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