Annotation of libaitrpc/src/blob.c, revision 1.5
1.2 misho 1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.5 ! misho 6: * $Id: blob.c,v 1.4.4.5 2012/03/15 01:24:34 misho Exp $
1.2 misho 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:
1.5 ! misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.2 misho 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: /*
1.5 ! misho 50: * rpc_srv_blobCreate() - Create map blob to memory region and return object
! 51: *
1.2 misho 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:
1.3 misho 74: memset(szFName, 0, sizeof szFName);
1.5 ! misho 75: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), rnd);
1.2 misho 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: /*
1.5 ! misho 116: * rpc_srv_blobMap() - Map blob to memory region
! 117: *
1.2 misho 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) {
1.5 ! misho 129: rpc_SetErr(EINVAL, "Invalid argument BLOB");
1.2 misho 130: return -1;
131: }
1.4 misho 132: if (blob->blob_data) {
1.5 ! misho 133: rpc_SetErr(EPERM, "Already mmapped object found!");
1.4 misho 134: return -1;
135: }
1.2 misho 136:
1.3 misho 137: memset(szFName, 0, sizeof szFName);
1.5 ! misho 138: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
1.2 misho 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: /*
1.5 ! misho 161: * rpc_srv_blobUnmap() - Unmap blob memory region
! 162: *
1.2 misho 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)
1.5 ! misho 170: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 171: else {
172: munmap(blob->blob_data, blob->blob_len);
173: blob->blob_data = NULL;
174: }
175: }
176:
177: /*
1.5 ! misho 178: * rpc_srv_blobFree() - Free blob from disk & memory
! 179: *
1.2 misho 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) {
1.5 ! misho 190: rpc_SetErr(EINVAL, "Invalid argument BLOB");
1.2 misho 191: return -1;
192: }
193:
194: if (blob->blob_data)
195: rpc_srv_blobUnmap(blob);
196:
1.3 misho 197: memset(szFName, 0, sizeof szFName);
1.5 ! misho 198: snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
1.3 misho 199: if (unlink(szFName) == -1) {
1.2 misho 200: LOGERR;
201: return -1;
202: }
203:
204: return 0;
205: }
206:
207: // ------------------------------------------------------------
208:
209: /*
1.5 ! misho 210: * rpc_srv_sendBLOB() - Send mapped BLOB to client
! 211: *
1.2 misho 212: * @cli = Client instance
213: * @blob = Mapped BLOB element
214: * return: -1 error, 0 ok
215: */
216: int
217: rpc_srv_sendBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
218: {
219: int ret, len;
220: uint8_t *pos;
221:
222: if (!cli || !blob || !blob->blob_data) {
1.5 ! misho 223: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 224: return -1;
225: }
226:
1.3 misho 227: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
228: len = send(cli->cli_sock, pos, ret, 0);
229: if (len == -1) {
1.2 misho 230: LOGERR;
231: return -1;
232: }
1.3 misho 233: }
1.2 misho 234:
235: return ret;
236: }
237:
238: /*
1.5 ! misho 239: * rpc_srv_recvBLOB() - Receive BLOB from client
! 240: *
1.2 misho 241: * @cli = Client instance
242: * @blob = Mapped BLOB element
243: * return: -1 error, 0 ok, >0 unreceived data from client, may be error?
244: */
245: int
246: rpc_srv_recvBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
247: {
248: int ret, len;
249: uint8_t *pos;
250: fd_set fds;
251: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
252:
253: if (!cli || !blob || !blob->blob_data) {
1.5 ! misho 254: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 255: return -1;
1.5 ! misho 256: } else
! 257: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
1.2 misho 258:
259: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
260: FD_ZERO(&fds);
261: FD_SET(cli->cli_sock, &fds);
262: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
263: if (len < 1) {
264: LOGERR;
265: return -1;
266: }
267:
1.3 misho 268: len = recv(cli->cli_sock, pos, ret, 0);
269: if (len == -1) {
1.2 misho 270: LOGERR;
271: return -1;
272: }
273: }
274:
275: return ret;
276: }
277:
278: // ------------------------------------------------------------
279:
280: /*
1.5 ! misho 281: * rpc_cli_sendBLOB() - Send BLOB to server
! 282: *
1.2 misho 283: * @cli = Client instance
284: * @var = BLOB variable
285: * @data = BLOB data
286: * return: -1 error, 0 ok, 1 remote error
287: */
288: int
1.4 misho 289: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void * __restrict data)
1.2 misho 290: {
291: int ret, len;
292: uint8_t *pos;
293: struct tagBLOBHdr hdr;
294: fd_set fds;
295: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
296:
297: if (!cli || !var || !data) {
1.5 ! misho 298: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 299: return -1;
1.5 ! misho 300: } else
! 301: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
1.2 misho 302:
1.5 ! misho 303: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2 misho 304: hdr.hdr_cmd = set;
305: hdr.hdr_var = 0;
306: hdr.hdr_ret = 0;
1.5 ! misho 307: hdr.hdr_len = htonl(AIT_LEN(var));
! 308: /* calculate CRC */
! 309: hdr.hdr_crc ^= hdr.hdr_crc;
! 310: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
! 311:
! 312: /* send SET request */
1.2 misho 313: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
314: LOGERR;
315: return -1;
316: }
317:
1.4 misho 318: /* send BLOB to server */
319: for (ret = AIT_LEN(var), pos = data; ret > 0; ret -= len, pos += len)
1.3 misho 320: if ((len = send(cli->cli_sock, pos, ret, 0)) == -1) {
1.2 misho 321: LOGERR;
322: return -1;
323: }
324:
1.5 ! misho 325: /* wait for reply */
1.2 misho 326: FD_ZERO(&fds);
327: FD_SET(cli->cli_sock, &fds);
328: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
329: case -1:
330: LOGERR;
1.5 ! misho 331: return 1;
1.2 misho 332: case 0:
1.5 ! misho 333: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
! 334: return 1;
1.2 misho 335: }
336: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
337: LOGERR;
1.5 ! misho 338: return 1;
! 339: }
! 340: /* check CRC */
! 341: ret = ntohs(hdr.hdr_crc);
! 342: hdr.hdr_crc ^= hdr.hdr_crc;
! 343: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
! 344: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
! 345: return 1;
1.2 misho 346: }
1.5 ! misho 347:
1.2 misho 348: if (hdr.hdr_cmd != error) {
1.5 ! misho 349: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
! 350: rpc_SetErr(ECANCELED, "Bad return length packet");
! 351: return 1;
1.2 misho 352: }
353:
1.5 ! misho 354: var->val.blob = ntohl(hdr.hdr_var);
1.2 misho 355: }
356:
357: return hdr.hdr_cmd == error;
358: }
359:
360: /*
1.5 ! misho 361: * rpc_cli_recvBLOB() - Receive BLOB from server
! 362: *
1.2 misho 363: * @cli = Client instance
364: * @var = BLOB variable
365: * @data = BLOB data, must be free after use!
366: * return: -1 error, 0 ok, 1 remote error
367: */
368: int
1.4 misho 369: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
1.2 misho 370: {
371: int ret, len;
372: uint8_t *pos;
373: fd_set fds;
374: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
375: struct tagBLOBHdr hdr;
376:
377: if (!cli || !var || !data) {
1.5 ! misho 378: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 379: return -1;
1.5 ! misho 380: } else
! 381: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
1.2 misho 382:
1.4 misho 383: *data = malloc(AIT_LEN(var));
1.2 misho 384: if (!*data) {
385: LOGERR;
386: return -1;
387: } else
1.4 misho 388: memset(*data, 0, AIT_LEN(var));
1.2 misho 389:
1.5 ! misho 390: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2 misho 391: hdr.hdr_cmd = get;
1.5 ! misho 392: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
1.2 misho 393: hdr.hdr_ret = 0;
394: hdr.hdr_len = 0;
1.5 ! misho 395: /* calculate CRC */
! 396: hdr.hdr_crc ^= hdr.hdr_crc;
! 397: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
! 398:
! 399: /* send GET request */
1.2 misho 400: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
401: LOGERR;
402: free(*data);
403: *data = NULL;
404: return -1;
405: }
406:
1.4 misho 407: /* receive BLOB from server */
408: for (ret = AIT_LEN(var), pos = *data; ret > 0; ret -= len, pos += len) {
1.2 misho 409: FD_ZERO(&fds);
410: FD_SET(cli->cli_sock, &fds);
411: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
412: if (len < 1) {
413: LOGERR;
414: free(*data);
415: *data = NULL;
416: return -1;
417: }
418:
1.3 misho 419: if ((len = recv(cli->cli_sock, pos, ret, 0)) == -1) {
1.2 misho 420: LOGERR;
421: free(*data);
422: *data = NULL;
423: return -1;
424: }
425: }
426:
1.5 ! misho 427: /* wait for reply */
1.2 misho 428: FD_ZERO(&fds);
429: FD_SET(cli->cli_sock, &fds);
430: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
431: case -1:
432: LOGERR;
433: free(*data);
434: *data = NULL;
1.5 ! misho 435: return 1;
1.2 misho 436: case 0:
1.5 ! misho 437: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
1.2 misho 438: free(*data);
439: *data = NULL;
1.5 ! misho 440: return 1;
1.2 misho 441: }
442: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
443: LOGERR;
444: free(*data);
445: *data = NULL;
1.5 ! misho 446: return 1;
! 447: }
! 448: /* check CRC */
! 449: ret = ntohs(hdr.hdr_crc);
! 450: hdr.hdr_crc ^= hdr.hdr_crc;
! 451: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
! 452: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
! 453: free(*data);
! 454: *data = NULL;
! 455: return 1;
1.2 misho 456: }
457: if (hdr.hdr_cmd != error) {
1.5 ! misho 458: if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
! 459: rpc_SetErr(ECANCELED, "Bad return length packet");
1.2 misho 460: free(*data);
461: *data = NULL;
1.5 ! misho 462: return 1;
1.2 misho 463: }
464: }
465:
466: return hdr.hdr_cmd == error;
467: }
468:
469: /*
1.5 ! misho 470: * rpc_cli_delBLOB() - Delete BLOB from server
! 471: *
1.2 misho 472: * @cli = Client instance
473: * @var = BLOB variable
474: * return: -1 error, 0 ok, 1 remote error
475: */
476: int
1.4 misho 477: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var)
1.2 misho 478: {
479: struct tagBLOBHdr hdr;
480: fd_set fds;
481: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
1.5 ! misho 482: int ret;
1.2 misho 483:
484: if (!cli || !var) {
1.5 ! misho 485: rpc_SetErr(EINVAL, "Invalid arguments");
1.2 misho 486: return -1;
1.5 ! misho 487: } else
! 488: tv.tv_sec = ((rpc_sess_t*) cli->cli_parent)->sess_timeout;
1.2 misho 489:
1.5 ! misho 490: rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2 misho 491: hdr.hdr_cmd = unset;
1.5 ! misho 492: hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
1.2 misho 493: hdr.hdr_ret = 0;
494: hdr.hdr_len = 0;
1.5 ! misho 495: /* calculate CRC */
! 496: hdr.hdr_crc ^= hdr.hdr_crc;
! 497: hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2));
! 498:
! 499: /* send UNSET request */
1.2 misho 500: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
501: LOGERR;
502: return -1;
503: }
504:
1.5 ! misho 505: /* wait for reply */
1.2 misho 506: FD_ZERO(&fds);
507: FD_SET(cli->cli_sock, &fds);
508: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
509: case -1:
510: LOGERR;
1.5 ! misho 511: return 1;
1.2 misho 512: case 0:
1.5 ! misho 513: rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not responde");
! 514: return 1;
1.2 misho 515: }
516: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
517: LOGERR;
1.5 ! misho 518: return 1;
! 519: }
! 520: /* check CRC */
! 521: ret = ntohs(hdr.hdr_crc);
! 522: hdr.hdr_crc ^= hdr.hdr_crc;
! 523: if (ret != crcFletcher16((u_short*) &hdr, io_align(sizeof hdr, 1) / 2)) {
! 524: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
! 525: return 1;
1.2 misho 526: }
527:
528: return hdr.hdr_cmd == error;
529: }
530:
531: /*
1.5 ! misho 532: * rpc_cli_getBLOB() - Receive BLOB from server and Delete after that
! 533: *
1.2 misho 534: * @cli = Client instance
535: * @var = BLOB variable
536: * @data = BLOB data, must be free after use!
537: * return: -1 error, 0 ok, 1 remote error
538: */
539: inline int
1.4 misho 540: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
1.2 misho 541: {
542: int ret;
543:
544: ret = rpc_cli_recvBLOB(cli, var, data);
545: ret |= rpc_cli_delBLOB(cli, var) > 0 ? 2 : 0;
546:
547: return ret;
548: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>