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.4.4.4 2012/03/15 01:22:55 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 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: #ifdef HAVE_SRANDOMDEV
65: srandomdev();
66: #else
67: time_t tim;
68:
69: srandom((time(&tim) ^ getpid()));
70: #endif
71: again:
72: rnd = random() % UINT_MAX;
73:
74: memset(szFName, 0, sizeof szFName);
75: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), rnd);
76: f = open(szFName, O_CREAT | O_EXCL | O_RDWR, 0600);
77: if (f == -1) {
78: if (errno == EEXIST)
79: goto again;
80:
81: LOGERR;
82: return NULL;
83: }
84: if (lseek(f, len - 1, SEEK_SET) == -1) {
85: LOGERR;
86: close(f);
87: unlink(szFName);
88: return NULL;
89: } else
90: write(f, "", 1);
91:
92: blob = malloc(sizeof(rpc_blob_t));
93: if (!blob) {
94: LOGERR;
95: close(f);
96: unlink(szFName);
97: return NULL;
98: }
99:
100: blob->blob_data = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
101: if (blob->blob_data == MAP_FAILED) {
102: LOGERR;
103: free(blob);
104: close(f);
105: unlink(szFName);
106: return NULL;
107: } else
108: close(f);
109:
110: blob->blob_len = len;
111: blob->blob_var = rnd;
112: return blob;
113: }
114:
115: /*
116: * rpc_srv_blobMap() - Map blob to memory region
117: *
118: * @srv = RPC Server instance
119: * @blob = Map to this BLOB element
120: * return: -1 error or 0 ok
121: */
122: inline int
123: rpc_srv_blobMap(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
124: {
125: int f;
126: char szFName[MAXPATHLEN];
127:
128: if (!blob) {
129: rpc_SetErr(EINVAL, "Invalid argument BLOB");
130: return -1;
131: }
132: if (blob->blob_data) {
133: rpc_SetErr(EPERM, "Already mmapped object found!");
134: return -1;
135: }
136:
137: memset(szFName, 0, sizeof szFName);
138: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
139: f = open(szFName, O_RDWR);
140: if (f == -1) {
141: LOGERR;
142: return -1;
143: }
144:
145: blob->blob_data = mmap(NULL, blob->blob_len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
146: if (blob->blob_data == MAP_FAILED) {
147: LOGERR;
148: close(f);
149: blob->blob_data = NULL;
150: return -1;
151: } else {
152: close(f);
153:
154: madvise(blob->blob_data, blob->blob_len, MADV_SEQUENTIAL);
155: }
156:
157: return 0;
158: }
159:
160: /*
161: * rpc_srv_blobUnmap() - Unmap blob memory region
162: *
163: * @blob = Mapped BLOB element
164: * return: none
165: */
166: inline void
167: rpc_srv_blobUnmap(rpc_blob_t * __restrict blob)
168: {
169: if (!blob || !blob->blob_data)
170: rpc_SetErr(EINVAL, "Invalid arguments");
171: else {
172: munmap(blob->blob_data, blob->blob_len);
173: blob->blob_data = NULL;
174: }
175: }
176:
177: /*
178: * rpc_srv_blobFree() - Free blob from disk & memory
179: *
180: * @srv = RPC Server instance
181: * @blob = Mapped BLOB element
182: * return: -1 error or 0 ok
183: */
184: inline int
185: rpc_srv_blobFree(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
186: {
187: char szFName[MAXPATHLEN];
188:
189: if (!blob) {
190: rpc_SetErr(EINVAL, "Invalid argument BLOB");
191: return -1;
192: }
193:
194: if (blob->blob_data)
195: rpc_srv_blobUnmap(blob);
196:
197: memset(szFName, 0, sizeof szFName);
198: LOGGER("dir=%s", AIT_GET_LIKE(&srv->srv_blob.dir, char*));
199: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
200: if (unlink(szFName) == -1) {
201: LOGERR;
202: return -1;
203: }
204:
205: return 0;
206: }
207:
208: // ------------------------------------------------------------
209:
210: /*
211: * rpc_srv_sendBLOB() - Send mapped BLOB to client
212: *
213: * @cli = Client instance
214: * @blob = Mapped BLOB element
215: * return: -1 error, 0 ok
216: */
217: int
218: rpc_srv_sendBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
219: {
220: int ret, len;
221: uint8_t *pos;
222:
223: if (!cli || !blob || !blob->blob_data) {
224: rpc_SetErr(EINVAL, "Invalid arguments");
225: return -1;
226: }
227:
228: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
229: len = send(cli->cli_sock, pos, ret, 0);
230: if (len == -1) {
231: LOGERR;
232: return -1;
233: }
234: }
235:
236: return ret;
237: }
238:
239: /*
240: * rpc_srv_recvBLOB() - Receive BLOB from client
241: *
242: * @cli = Client instance
243: * @blob = Mapped BLOB element
244: * return: -1 error, 0 ok, >0 unreceived data from client, may be error?
245: */
246: int
247: rpc_srv_recvBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
248: {
249: int ret, len;
250: uint8_t *pos;
251: fd_set fds;
252: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
253:
254: if (!cli || !blob || !blob->blob_data) {
255: rpc_SetErr(EINVAL, "Invalid arguments");
256: return -1;
257: } else
258: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
259:
260: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
261: FD_ZERO(&fds);
262: FD_SET(cli->cli_sock, &fds);
263: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
264: if (len < 1) {
265: LOGERR;
266: return -1;
267: }
268:
269: len = recv(cli->cli_sock, pos, ret, 0);
270: if (len == -1) {
271: LOGERR;
272: return -1;
273: }
274: }
275:
276: return ret;
277: }
278:
279: // ------------------------------------------------------------
280:
281: /*
282: * rpc_cli_sendBLOB() - Send BLOB to server
283: *
284: * @cli = Client instance
285: * @var = BLOB variable
286: * @data = BLOB data
287: * return: -1 error, 0 ok, 1 remote error
288: */
289: int
290: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void * __restrict data)
291: {
292: int ret, len;
293: uint8_t *pos;
294: struct tagBLOBHdr hdr;
295: fd_set fds;
296: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
297:
298: if (!cli || !var || !data) {
299: rpc_SetErr(EINVAL, "Invalid arguments");
300: return -1;
301: } else
302: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
303:
304: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
305: hdr.hdr_cmd = set;
306: hdr.hdr_var = 0;
307: hdr.hdr_ret = 0;
308: hdr.hdr_len = htonl(AIT_LEN(var));
309: /* calculate CRC */
310: hdr.hdr_crc ^= hdr.hdr_crc;
311: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
312:
313: /* send SET request */
314: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
315: LOGERR;
316: return -1;
317: }
318:
319: /* send BLOB to server */
320: for (ret = AIT_LEN(var), pos = data; ret > 0; ret -= len, pos += len)
321: if ((len = send(cli->cli_sock, pos, ret, 0)) == -1) {
322: LOGERR;
323: return -1;
324: }
325:
326: /* wait for reply */
327: FD_ZERO(&fds);
328: FD_SET(cli->cli_sock, &fds);
329: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
330: case -1:
331: LOGERR;
332: return 1;
333: case 0:
334: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
335: return 1;
336: }
337: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
338: LOGERR;
339: return 1;
340: }
341: /* check CRC */
342: ret = ntohs(hdr.hdr_crc);
343: hdr.hdr_crc ^= hdr.hdr_crc;
344: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
345: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
346: return 1;
347: }
348:
349: if (hdr.hdr_cmd != error) {
350: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
351: rpc_SetErr(ECANCELED, "Bad return length packet");
352: return 1;
353: }
354:
355: var->val.blob = ntohl(hdr.hdr_var);
356: }
357:
358: return hdr.hdr_cmd == error;
359: }
360:
361: /*
362: * rpc_cli_recvBLOB() - Receive BLOB from server
363: *
364: * @cli = Client instance
365: * @var = BLOB variable
366: * @data = BLOB data, must be free after use!
367: * return: -1 error, 0 ok, 1 remote error
368: */
369: int
370: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
371: {
372: int ret, len;
373: uint8_t *pos;
374: fd_set fds;
375: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
376: struct tagBLOBHdr hdr;
377:
378: if (!cli || !var || !data) {
379: rpc_SetErr(EINVAL, "Invalid arguments");
380: return -1;
381: } else
382: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
383:
384: *data = malloc(AIT_LEN(var));
385: if (!*data) {
386: LOGERR;
387: return -1;
388: } else
389: memset(*data, 0, AIT_LEN(var));
390:
391: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
392: hdr.hdr_cmd = get;
393: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
394: hdr.hdr_ret = 0;
395: hdr.hdr_len = 0;
396: /* calculate CRC */
397: hdr.hdr_crc ^= hdr.hdr_crc;
398: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
399:
400: /* send GET request */
401: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
402: LOGERR;
403: free(*data);
404: *data = NULL;
405: return -1;
406: }
407:
408: /* receive BLOB from server */
409: for (ret = AIT_LEN(var), pos = *data; ret > 0; ret -= len, pos += len) {
410: FD_ZERO(&fds);
411: FD_SET(cli->cli_sock, &fds);
412: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
413: if (len < 1) {
414: LOGERR;
415: free(*data);
416: *data = NULL;
417: return -1;
418: }
419:
420: if ((len = recv(cli->cli_sock, pos, ret, 0)) == -1) {
421: LOGERR;
422: free(*data);
423: *data = NULL;
424: return -1;
425: }
426: }
427:
428: /* wait for reply */
429: FD_ZERO(&fds);
430: FD_SET(cli->cli_sock, &fds);
431: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
432: case -1:
433: LOGERR;
434: free(*data);
435: *data = NULL;
436: return 1;
437: case 0:
438: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
439: free(*data);
440: *data = NULL;
441: return 1;
442: }
443: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
444: LOGERR;
445: free(*data);
446: *data = NULL;
447: return 1;
448: }
449: /* check CRC */
450: ret = ntohs(hdr.hdr_crc);
451: hdr.hdr_crc ^= hdr.hdr_crc;
452: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
453: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
454: free(*data);
455: *data = NULL;
456: return 1;
457: }
458: if (hdr.hdr_cmd != error) {
459: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
460: rpc_SetErr(ECANCELED, "Bad return length packet");
461: free(*data);
462: *data = NULL;
463: return 1;
464: }
465: }
466:
467: return hdr.hdr_cmd == error;
468: }
469:
470: /*
471: * rpc_cli_delBLOB() - Delete BLOB from server
472: *
473: * @cli = Client instance
474: * @var = BLOB variable
475: * return: -1 error, 0 ok, 1 remote error
476: */
477: int
478: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var)
479: {
480: struct tagBLOBHdr hdr;
481: fd_set fds;
482: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
483: int ret;
484:
485: if (!cli || !var) {
486: rpc_SetErr(EINVAL, "Invalid arguments");
487: return -1;
488: } else
489: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
490:
491: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
492: hdr.hdr_cmd = unset;
493: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
494: hdr.hdr_ret = 0;
495: hdr.hdr_len = 0;
496: /* calculate CRC */
497: hdr.hdr_crc ^= hdr.hdr_crc;
498: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
499:
500: /* send UNSET request */
501: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
502: LOGERR;
503: return -1;
504: }
505:
506: /* wait for reply */
507: FD_ZERO(&fds);
508: FD_SET(cli->cli_sock, &fds);
509: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
510: case -1:
511: LOGERR;
512: return 1;
513: case 0:
514: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
515: return 1;
516: }
517: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
518: LOGERR;
519: return 1;
520: }
521: /* check CRC */
522: ret = ntohs(hdr.hdr_crc);
523: hdr.hdr_crc ^= hdr.hdr_crc;
524: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
525: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
526: return 1;
527: }
528:
529: return hdr.hdr_cmd == error;
530: }
531:
532: /*
533: * rpc_cli_getBLOB() - Receive BLOB from server and Delete after that
534: *
535: * @cli = Client instance
536: * @var = BLOB variable
537: * @data = BLOB data, must be free after use!
538: * return: -1 error, 0 ok, 1 remote error
539: */
540: inline int
541: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
542: {
543: int ret;
544:
545: ret = rpc_cli_recvBLOB(cli, var, data);
546: ret |= rpc_cli_delBLOB(cli, var) > 0 ? 2 : 0;
547:
548: return ret;
549: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>