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.1.2.16 2011/05/02 23:07: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
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: * @srv = RPC Server instance
52: * @len = BLOB length object
53: * return: NULL error or !=NULL allocated BLOB object
54: */
55: inline rpc_blob_t *
56: rpc_srv_blobCreate(rpc_srv_t * __restrict srv, int len)
57: {
58: rpc_blob_t *blob = NULL;
59: char szFName[MAXPATHLEN];
60: int f;
61: u_int rnd;
62:
63: srandomdev();
64: again:
65: rnd = random() % UINT_MAX;
66:
67: memset(szFName, 0, MAXPATHLEN);
68: snprintf(szFName, MAXPATHLEN, BLOB_FILE, 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 (lseek(f, len - 1, SEEK_SET) == -1) {
78: LOGERR;
79: close(f);
80: unlink(szFName);
81: return NULL;
82: } else
83: write(f, "", 1);
84:
85: blob = malloc(sizeof(rpc_blob_t));
86: if (!blob) {
87: LOGERR;
88: close(f);
89: unlink(szFName);
90: return NULL;
91: }
92:
93: blob->blob_data = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
94: if (blob->blob_data == MAP_FAILED) {
95: LOGERR;
96: free(blob);
97: close(f);
98: unlink(szFName);
99: return NULL;
100: } else
101: close(f);
102:
103: blob->blob_len = len;
104: blob->blob_var = rnd;
105: return blob;
106: }
107:
108: /*
109: * rpc_srv_blobMap() Map blob to memory region
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, "Error:: invalid arguments ...\n");
122: return -1;
123: }
124:
125: memset(szFName, 0, MAXPATHLEN);
126: snprintf(szFName, MAXPATHLEN, BLOB_FILE, srv->srv_blob.dir, blob->blob_var);
127: f = open(szFName, O_RDWR);
128: if (f == -1) {
129: LOGERR;
130: return -1;
131: }
132:
133: blob->blob_data = mmap(NULL, blob->blob_len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
134: if (blob->blob_data == MAP_FAILED) {
135: LOGERR;
136: close(f);
137: blob->blob_data = NULL;
138: return -1;
139: } else {
140: close(f);
141:
142: madvise(blob->blob_data, blob->blob_len, MADV_SEQUENTIAL);
143: }
144:
145: return 0;
146: }
147:
148: /*
149: * rpc_srv_blobUnmap() Unmap blob memory region
150: * @blob = Mapped BLOB element
151: * return: none
152: */
153: inline void
154: rpc_srv_blobUnmap(rpc_blob_t * __restrict blob)
155: {
156: if (!blob || !blob->blob_data)
157: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
158: else {
159: munmap(blob->blob_data, blob->blob_len);
160: blob->blob_data = NULL;
161: }
162: }
163:
164: /*
165: * rpc_srv_blobFree() Free blob from disk & memory
166: * @srv = RPC Server instance
167: * @blob = Mapped BLOB element
168: * return: -1 error or 0 ok
169: */
170: inline int
171: rpc_srv_blobFree(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
172: {
173: char szFName[MAXPATHLEN];
174:
175: if (!blob) {
176: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
177: return -1;
178: }
179:
180: if (blob->blob_data)
181: rpc_srv_blobUnmap(blob);
182:
183: memset(szFName, 0, MAXPATHLEN);
184: snprintf(szFName, MAXPATHLEN, BLOB_FILE, srv->srv_blob.dir, blob->blob_var);
185: if (remove(szFName) == -1) {
186: LOGERR;
187: return -1;
188: }
189:
190: return 0;
191: }
192:
193: // ------------------------------------------------------------
194:
195: /*
196: * rpc_srv_sendBLOB() Send mapped BLOB to client
197: * @cli = Client instance
198: * @blob = Mapped BLOB element
199: * return: -1 error, 0 ok
200: */
201: int
202: rpc_srv_sendBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
203: {
204: int ret, len;
205: uint8_t *pos;
206:
207: if (!cli || !blob || !blob->blob_data) {
208: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
209: return -1;
210: }
211:
212: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len)
213: if ((len = send(cli->cli_sock, pos, ret > BLOBSIZ ? BLOBSIZ : ret, 0)) == -1) {
214: LOGERR;
215: return -1;
216: }
217:
218: return ret;
219: }
220:
221: /*
222: * rpc_srv_recvBLOB() Receive BLOB from client
223: * @cli = Client instance
224: * @blob = Mapped BLOB element
225: * return: -1 error, 0 ok, >0 unreceived data from client, may be error?
226: */
227: int
228: rpc_srv_recvBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
229: {
230: int ret, len;
231: uint8_t *pos;
232: fd_set fds;
233: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
234:
235: if (!cli || !blob || !blob->blob_data) {
236: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
237: return -1;
238: }
239:
240: for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
241: FD_ZERO(&fds);
242: FD_SET(cli->cli_sock, &fds);
243: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
244: if (len < 1) {
245: LOGERR;
246: return -1;
247: }
248:
249: if ((len = recv(cli->cli_sock, pos, BLOBSIZ, 0)) == -1) {
250: LOGERR;
251: return -1;
252: }
253: }
254:
255: return ret;
256: }
257:
258: // ------------------------------------------------------------
259:
260: /*
261: * rpc_cli_sendBLOB() Send BLOB to server
262: * @cli = Client instance
263: * @var = BLOB variable
264: * @data = BLOB data
265: * return: -1 error, 0 ok, 1 remote error
266: */
267: int
268: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, rpc_val_t * __restrict var, void * __restrict data)
269: {
270: int ret, len;
271: uint8_t *pos;
272: struct tagBLOBHdr hdr;
273: fd_set fds;
274: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
275:
276: if (!cli || !var || !data) {
277: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
278: return -1;
279: }
280:
281: memcpy(&hdr.hdr_session, cli->cli_parent, sizeof(rpc_sess_t));
282: hdr.hdr_cmd = set;
283: hdr.hdr_var = 0;
284: hdr.hdr_ret = 0;
285: hdr.hdr_len = var->val_len;
286: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
287: LOGERR;
288: return -1;
289: }
290:
291: for (ret = var->val_len, pos = data; ret > 0; ret -= len, pos += len)
292: if ((len = send(cli->cli_sock, pos, ret > BLOBSIZ ? BLOBSIZ : ret, 0)) == -1) {
293: LOGERR;
294: return -1;
295: }
296:
297: FD_ZERO(&fds);
298: FD_SET(cli->cli_sock, &fds);
299: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
300: case -1:
301: LOGERR;
302: return -1;
303: case 0:
304: rpc_SetErr(ETIMEDOUT, "Error:: Timeout reached! Server not responde ...\n");
305: return -1;
306: }
307: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
308: LOGERR;
309: return -1;
310: }
311: if (hdr.hdr_cmd != error) {
312: if (hdr.hdr_len != var->val_len) {
313: rpc_SetErr(ECANCELED, "Error:: Bad return length packet ...\n");
314: return -1;
315: }
316:
317: var->val.blob = hdr.hdr_var;
318: }
319:
320: return hdr.hdr_cmd == error;
321: }
322:
323: /*
324: * rpc_cli_recvBLOB() Receive BLOB from server
325: * @cli = Client instance
326: * @var = BLOB variable
327: * @data = BLOB data, must be free after use!
328: * return: -1 error, 0 ok, 1 remote error
329: */
330: int
331: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, rpc_val_t * __restrict var, void ** data)
332: {
333: int ret, len;
334: uint8_t *pos;
335: fd_set fds;
336: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
337: struct tagBLOBHdr hdr;
338:
339: if (!cli || !var || !data) {
340: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
341: return -1;
342: }
343:
344: *data = malloc(var->val_len);
345: if (!*data) {
346: LOGERR;
347: return -1;
348: } else
349: memset(*data, 0, var->val_len);
350:
351: memcpy(&hdr.hdr_session, cli->cli_parent, sizeof(rpc_sess_t));
352: hdr.hdr_cmd = get;
353: hdr.hdr_var = (uint32_t) RPC_GET_BLOB(var);
354: hdr.hdr_ret = 0;
355: hdr.hdr_len = 0;
356: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
357: LOGERR;
358: free(*data);
359: *data = NULL;
360: return -1;
361: }
362:
363: for (ret = var->val_len, pos = *data; ret > 0; ret -= len, pos += len) {
364: FD_ZERO(&fds);
365: FD_SET(cli->cli_sock, &fds);
366: len = select(cli->cli_sock + 1, &fds, NULL, NULL, &tv);
367: if (len < 1) {
368: LOGERR;
369: free(*data);
370: *data = NULL;
371: return -1;
372: }
373:
374: if ((len = recv(cli->cli_sock, pos, BLOBSIZ, 0)) == -1) {
375: LOGERR;
376: free(*data);
377: *data = NULL;
378: return -1;
379: }
380: }
381:
382: FD_ZERO(&fds);
383: FD_SET(cli->cli_sock, &fds);
384: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
385: case -1:
386: LOGERR;
387: free(*data);
388: *data = NULL;
389: return -1;
390: case 0:
391: rpc_SetErr(ETIMEDOUT, "Error:: Timeout reached! Server not responde ...\n");
392: free(*data);
393: *data = NULL;
394: return -1;
395: }
396: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
397: LOGERR;
398: free(*data);
399: *data = NULL;
400: return -1;
401: }
402: if (hdr.hdr_cmd != error) {
403: if (hdr.hdr_len != var->val_len) {
404: rpc_SetErr(ECANCELED, "Error:: Bad return length packet ...\n");
405: free(*data);
406: *data = NULL;
407: return -1;
408: }
409: }
410:
411: return hdr.hdr_cmd == error;
412: }
413:
414: /*
415: * rpc_cli_delBLOB() Delete BLOB from server
416: * @cli = Client instance
417: * @var = BLOB variable
418: * return: -1 error, 0 ok, 1 remote error
419: */
420: int
421: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, rpc_val_t * __restrict var)
422: {
423: struct tagBLOBHdr hdr;
424: fd_set fds;
425: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
426:
427: if (!cli || !var) {
428: rpc_SetErr(EINVAL, "Error:: invalid arguments ...\n");
429: return -1;
430: }
431:
432: memcpy(&hdr.hdr_session, cli->cli_parent, sizeof(rpc_sess_t));
433: hdr.hdr_cmd = unset;
434: hdr.hdr_var = (uint32_t) RPC_GET_BLOB(var);
435: hdr.hdr_ret = 0;
436: hdr.hdr_len = 0;
437: if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
438: LOGERR;
439: return -1;
440: }
441:
442: FD_ZERO(&fds);
443: FD_SET(cli->cli_sock, &fds);
444: switch (select(cli->cli_sock + 1, &fds, NULL, NULL, &tv)) {
445: case -1:
446: LOGERR;
447: return -1;
448: case 0:
449: rpc_SetErr(ETIMEDOUT, "Error:: Timeout reached! Server not responde ...\n");
450: return -1;
451: }
452: if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
453: LOGERR;
454: return -1;
455: }
456:
457: return hdr.hdr_cmd == error;
458: }
459:
460: /*
461: * rpc_cli_getBLOB() Receive BLOB from server and Delete after that
462: * @cli = Client instance
463: * @var = BLOB variable
464: * @data = BLOB data, must be free after use!
465: * return: -1 error, 0 ok, 1 remote error
466: */
467: inline int
468: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, rpc_val_t * __restrict var, void ** data)
469: {
470: int ret;
471:
472: ret = rpc_cli_recvBLOB(cli, var, data);
473: ret |= rpc_cli_delBLOB(cli, var) > 0 ? 2 : 0;
474:
475: return ret;
476: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>