1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: blob.c,v 1.7.2.6 2012/05/16 14:46:29 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * rpc_srv_blobCreate() - Create and map blob to memory region and return object
51: *
52: * @srv = RPC Server instance
53: * @len = BLOB length object
54: * return: NULL error or !=NULL allocated BLOB object
55: */
56: inline rpc_blob_t *
57: rpc_srv_blobCreate(rpc_srv_t * __restrict srv, int len)
58: {
59: rpc_blob_t *blob = NULL;
60: char szFName[MAXPATHLEN];
61: int f;
62: u_int rnd;
63:
64: again:
65: rnd = random() % UINT_MAX;
66:
67: memset(szFName, 0, sizeof szFName);
68: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), rnd);
69: f = open(szFName, O_CREAT | O_EXCL | O_RDWR, 0600);
70: if (f == -1) {
71: if (errno == EEXIST)
72: goto again;
73:
74: LOGERR;
75: return NULL;
76: }
77: if (ftruncate(f, len) == -1) {
78: LOGERR;
79: close(f);
80: unlink(szFName);
81: return NULL;
82: }
83:
84: blob = malloc(sizeof(rpc_blob_t));
85: if (!blob) {
86: LOGERR;
87: close(f);
88: unlink(szFName);
89: return NULL;
90: }
91:
92: blob->blob_data = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
93: if (blob->blob_data == MAP_FAILED) {
94: LOGERR;
95: free(blob);
96: close(f);
97: unlink(szFName);
98: return NULL;
99: } else
100: close(f);
101:
102: blob->blob_len = len;
103: blob->blob_var = rnd;
104: return blob;
105: }
106:
107: /*
108: * rpc_srv_blobMap() - Map blob to memory region
109: *
110: * @srv = RPC Server instance
111: * @blob = Map to this BLOB element
112: * return: -1 error or 0 ok
113: */
114: inline int
115: rpc_srv_blobMap(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
116: {
117: int f;
118: char szFName[MAXPATHLEN];
119:
120: if (!blob) {
121: rpc_SetErr(EINVAL, "Invalid argument BLOB");
122: return -1;
123: }
124: if (blob->blob_data) {
125: rpc_SetErr(EPERM, "Already mmapped object found!");
126: return -1;
127: }
128:
129: memset(szFName, 0, sizeof szFName);
130: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
131: f = open(szFName, O_RDWR);
132: if (f == -1) {
133: LOGERR;
134: return -1;
135: }
136:
137: blob->blob_data = mmap(NULL, blob->blob_len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
138: if (blob->blob_data == MAP_FAILED) {
139: LOGERR;
140: close(f);
141: blob->blob_data = NULL;
142: return -1;
143: } else {
144: close(f);
145:
146: madvise(blob->blob_data, blob->blob_len, MADV_SEQUENTIAL);
147: }
148:
149: return 0;
150: }
151:
152: /*
153: * rpc_srv_blobUnmap() - Unmap blob memory region
154: *
155: * @blob = Mapped BLOB element
156: * return: none
157: */
158: inline void
159: rpc_srv_blobUnmap(rpc_blob_t * __restrict blob)
160: {
161: if (blob && blob->blob_data) {
162: munmap(blob->blob_data, blob->blob_len);
163: blob->blob_data = NULL;
164: }
165: }
166:
167: /*
168: * rpc_srv_blobFree() - Free blob from disk & memory
169: *
170: * @srv = RPC Server instance
171: * @blob = Mapped BLOB element
172: * return: -1 error or 0 ok
173: */
174: inline int
175: rpc_srv_blobFree(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
176: {
177: char szFName[MAXPATHLEN];
178:
179: if (!blob) {
180: rpc_SetErr(EINVAL, "Invalid argument BLOB");
181: return -1;
182: } else
183: rpc_srv_blobUnmap(blob);
184:
185: memset(szFName, 0, sizeof szFName);
186: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
187: if (unlink(szFName) == -1) {
188: LOGERR;
189: return -1;
190: }
191:
192: return 0;
193: }
194:
195: /* ------------------------------------------------------------ */
196:
197: /*
198: * rpc_srv_sendBLOB() - Send mapped BLOB to client
199: *
200: * @cli = Client instance
201: * @blob = Mapped BLOB element
202: * return: -1 error, 0 ok
203: */
204: int
205: rpc_srv_sendBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
206: {
207: int ret, len;
208: uint8_t *pos;
209:
210: if (!cli || !blob || !blob->blob_data) {
211: rpc_SetErr(EINVAL, "Invalid arguments");
212: return -1;
213: }
214:
215: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
216: len = send(cli->cli_sock, pos, ret, MSG_NOSIGNAL);
217: if (len == -1) {
218: LOGERR;
219: return -1;
220: }
221: }
222:
223: return ret;
224: }
225:
226: /*
227: * rpc_srv_recvBLOB() - Receive BLOB from client
228: *
229: * @cli = Client instance
230: * @blob = Mapped BLOB element
231: * return: -1 error, 0 ok, >0 unreceived data from client, may be error?
232: */
233: int
234: rpc_srv_recvBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
235: {
236: int ret, len;
237: uint8_t *pos;
238: struct pollfd pfd;
239:
240: if (!cli || !blob || !blob->blob_data) {
241: rpc_SetErr(EINVAL, "Invalid arguments");
242: return -1;
243: }
244:
245: pfd.fd = cli->cli_sock;
246: pfd.events = POLLIN | POLLPRI;
247: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
248: if ((len = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 ||
249: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
250: LOGERR;
251: return -1;
252: }
253:
254: len = recv(cli->cli_sock, pos, ret, 0);
255: if (len == -1) {
256: LOGERR;
257: return -1;
258: }
259: }
260:
261: return ret;
262: }
263:
264: /* ------------------------------------------------------------ */
265:
266: /*
267: * rpc_cli_sendBLOB() - Send BLOB to server
268: *
269: * @cli = Client instance
270: * @var = BLOB variable
271: * @data = BLOB data
272: * return: -1 error, 0 ok, 1 remote error
273: */
274: int
275: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void * __restrict data)
276: {
277: int ret, len;
278: uint8_t *pos;
279: struct tagBLOBHdr hdr;
280: struct pollfd pfd;
281:
282: if (!cli || !var || !data) {
283: rpc_SetErr(EINVAL, "Invalid arguments");
284: return -1;
285: } else
286: memset(&hdr, 0, sizeof hdr);
287:
288: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
289: hdr.hdr_cmd = set;
290: hdr.hdr_var = 0;
291: hdr.hdr_ret = 0;
292: hdr.hdr_len = htonl(AIT_LEN(var));
293: /* calculate CRC */
294: hdr.hdr_crc ^= hdr.hdr_crc;
295: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
296:
297: /* send SET request */
298: if (send(cli->cli_sock, &hdr, sizeof hdr, MSG_NOSIGNAL) == -1) {
299: LOGERR;
300: return -1;
301: }
302:
303: /* send BLOB to server */
304: for (ret = AIT_LEN(var), pos = data; ret > 0; ret -= len, pos += len)
305: if ((len = send(cli->cli_sock, pos, ret, MSG_NOSIGNAL)) == -1) {
306: LOGERR;
307: return -1;
308: }
309:
310: /* wait for reply */
311: pfd.fd = cli->cli_sock;
312: pfd.events = POLLIN | POLLPRI;
313: if ((ret = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 ||
314: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
315: if (ret)
316: LOGERR;
317: else
318: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
319: return -1;
320: }
321: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
322: LOGERR;
323: return 1;
324: }
325: /* check CRC */
326: ret = ntohs(hdr.hdr_crc);
327: hdr.hdr_crc ^= hdr.hdr_crc;
328: if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
329: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
330: return 1;
331: }
332:
333: if (hdr.hdr_cmd != error) {
334: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
335: rpc_SetErr(ECANCELED, "Bad return length packet");
336: return 1;
337: }
338:
339: AIT_SET_BLOB(var, ntohl(hdr.hdr_var), ntohl(hdr.hdr_len));
340: }
341:
342: return hdr.hdr_cmd == error;
343: }
344:
345: /*
346: * rpc_cli_recvBLOB() - Receive BLOB from server
347: *
348: * @cli = Client instance
349: * @var = BLOB variable
350: * @data = BLOB data, must be free after use!
351: * return: -1 error, 0 ok, 1 remote error
352: */
353: int
354: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
355: {
356: int ret, len;
357: uint8_t *pos;
358: struct pollfd pfd;
359: struct tagBLOBHdr hdr;
360:
361: if (!cli || !var || !data) {
362: rpc_SetErr(EINVAL, "Invalid arguments");
363: return -1;
364: }
365:
366: *data = malloc(AIT_LEN(var));
367: if (!*data) {
368: LOGERR;
369: return -1;
370: } else {
371: memset(&hdr, 0, sizeof hdr);
372: memset(*data, 0, AIT_LEN(var));
373: }
374:
375: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
376: hdr.hdr_cmd = get;
377: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
378: hdr.hdr_ret = 0;
379: hdr.hdr_len = 0;
380: /* calculate CRC */
381: hdr.hdr_crc ^= hdr.hdr_crc;
382: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
383:
384: /* send GET request */
385: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
386: LOGERR;
387: free(*data);
388: *data = NULL;
389: return -1;
390: }
391:
392: /* receive BLOB from server */
393: pfd.fd = cli->cli_sock;
394: pfd.events = POLLIN | POLLPRI;
395: for (ret = AIT_LEN(var), pos = *data; ret > 0; ret -= len, pos += len) {
396: if ((len = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 ||
397: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
398: LOGERR;
399: free(*data);
400: *data = NULL;
401: return -1;
402: }
403:
404: if ((len = recv(cli->cli_sock, pos, ret, 0)) == -1) {
405: LOGERR;
406: free(*data);
407: *data = NULL;
408: return -1;
409: }
410: }
411:
412: /* wait for reply */
413: if ((len = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 ||
414: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
415: if (len)
416: LOGERR;
417: else
418: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
419: free(*data);
420: *data = NULL;
421: return 1;
422: }
423: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
424: LOGERR;
425: free(*data);
426: *data = NULL;
427: return 1;
428: }
429: /* check CRC */
430: ret = ntohs(hdr.hdr_crc);
431: hdr.hdr_crc ^= hdr.hdr_crc;
432: if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
433: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
434: free(*data);
435: *data = NULL;
436: return 1;
437: }
438: if (hdr.hdr_cmd != error) {
439: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
440: rpc_SetErr(ECANCELED, "Bad return length packet");
441: free(*data);
442: *data = NULL;
443: return 1;
444: }
445: }
446:
447: return hdr.hdr_cmd == error;
448: }
449:
450: /*
451: * rpc_cli_delBLOB() - Delete BLOB from server
452: *
453: * @cli = Client instance
454: * @var = BLOB variable
455: * return: -1 error, 0 ok, 1 remote error
456: */
457: int
458: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var)
459: {
460: struct tagBLOBHdr hdr;
461: struct pollfd pfd;
462: int ret;
463:
464: if (!cli || !var) {
465: rpc_SetErr(EINVAL, "Invalid arguments");
466: return -1;
467: } else
468: memset(&hdr, 0, sizeof hdr);
469:
470: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
471: hdr.hdr_cmd = unset;
472: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
473: hdr.hdr_ret = 0;
474: hdr.hdr_len = 0;
475: /* calculate CRC */
476: hdr.hdr_crc ^= hdr.hdr_crc;
477: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
478:
479: /* send UNSET request */
480: if (send(cli->cli_sock, &hdr, sizeof hdr, MSG_NOSIGNAL) == -1) {
481: LOGERR;
482: return -1;
483: }
484:
485: /* wait for reply */
486: pfd.fd = cli->cli_sock;
487: pfd.events = POLLIN | POLLPRI;
488: if ((ret = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 ||
489: pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
490: if (ret)
491: LOGERR;
492: else
493: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
494: return 1;
495: }
496: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
497: LOGERR;
498: return 1;
499: }
500: /* check CRC */
501: ret = ntohs(hdr.hdr_crc);
502: hdr.hdr_crc ^= hdr.hdr_crc;
503: if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
504: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
505: return 1;
506: }
507:
508: return hdr.hdr_cmd == error;
509: }
510:
511: /*
512: * rpc_cli_getBLOB() - Receive BLOB from server and Delete after that
513: *
514: * @cli = Client instance
515: * @var = BLOB variable
516: * @data = BLOB data, must be free after use!
517: * return: -1 error, 0 ok, 1 remote error
518: */
519: inline int
520: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
521: {
522: int ret;
523:
524: ret = rpc_cli_recvBLOB(cli, var, data);
525: ret |= rpc_cli_delBLOB(cli, var) > 0 ? 2 : 0;
526:
527: return ret;
528: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>