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: srv.c,v 1.6.2.9 2012/03/15 00:44:24 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: static void *rxPacket(sched_task_t*);
50: static void *rxBLOB(sched_task_t*);
51:
52: static void *
53: txPacket(sched_task_t *task)
54: {
55: rpc_cli_t *c = TASK_ARG(task);
56: rpc_srv_t *s = c->cli_parent;
57: rpc_func_t *f = NULL;
58: u_char *buf = TASK_DATA(task);
59: struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
60: int ret, wlen = sizeof(struct tagRPCCall);
61: array_t *arr = NULL;
62:
63: FTRACE();
64:
65: if (rpc->call_argc) {
66: f = rpc_srv_getCall(s, ntohs(rpc->call_tag), ntohl(rpc->call_hash));
67: if (!f) {
68: rpc->call_argc ^= rpc->call_argc;
69: rpc->call_rep.ret = RPC_ERROR(-1);
70: rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
71: } else {
72: rpc->call_argc = htons(rpc_srv_getVars(f, &arr));
73: /* Go Encapsulate variables */
74: ret = io_vars2buffer(buf + wlen, TASK_DATLEN(task) - wlen, arr);
75: io_clrVars(f->func_vars);
76: if (ret == -1) {
77: rpc_SetErr(EBADRPC, "Prepare RPC packet failed");
78: rpc->call_argc ^= rpc->call_argc;
79: rpc->call_rep.ret = RPC_ERROR(-1);
80: rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
81: } else
82: wlen += ret;
83: }
84: }
85:
86: /* calculate CRC */
87: rpc->call_crc ^= rpc->call_crc;
88: rpc->call_crc = htons(crcFletcher16((u_short*) buf, io_align(wlen, 1) / 2));
89:
90: /* send reply */
91: ret = send(TASK_FD(task), buf, wlen, 0);
92: if (ret == -1)
93: LOGERR;
94: else if (ret != wlen)
95: rpc_SetErr(EPROCUNAVAIL, "RPC reply, should be send %d bytes, "
96: "really sended %d bytes", wlen, ret);
97: else
98: LOGGER("Sended %d bytes", ret);
99:
100: return NULL;
101: }
102:
103: static void *
104: execCall(sched_task_t *task)
105: {
106: rpc_cli_t *c = TASK_ARG(task);
107: rpc_srv_t *s = c->cli_parent;
108: rpc_func_t *f = NULL;
109: array_t *arr = NULL;
110: u_char *buf = TASK_DATA(task);
111: struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
112: int argc = ntohs(rpc->call_argc);
113:
114: FTRACE();
115:
116: /* Go decapsulate variables ... */
117: if (!(rpc->call_req.flags & RPC_NOREPLY) && argc) {
118: arr = io_buffer2vars(buf + sizeof(struct tagRPCCall),
119: TASK_DATLEN(task) - sizeof(struct tagRPCCall), argc, 1);
120: if (!arr) {
121: rpc_SetErr(ERPCMISMATCH, "#%d - %s", io_GetErrno(), io_GetError());
122: rpc->call_argc ^= rpc->call_argc;
123: rpc->call_rep.ret = RPC_ERROR(-1);
124: rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
125: return NULL;
126: }
127: }
128:
129: if (!(f = rpc_srv_getCall(s, ntohs(rpc->call_tag), ntohl(rpc->call_hash)))) {
130: rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
131: rpc->call_argc ^= rpc->call_argc;
132: rpc->call_rep.ret = RPC_ERROR(-1);
133: rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
134: } else {
135: LOGGER("RPC function %s from module %s", AIT_GET_STR(&f->func_name),
136: AIT_GET_LIKE(&f->func_file, char*));
137:
138: rpc->call_rep.ret = RPC_ERROR(rpc_srv_execCall(f, rpc, arr));
139: if (rpc->call_rep.ret == htonl(-1)) {
140: rpc->call_rep.eno = RPC_ERROR(errno);
141: rpc->call_argc ^= rpc->call_argc;
142: } else {
143: rpc->call_rep.eno ^= rpc->call_rep.eno;
144: rpc->call_argc = htons(rpc_srv_getVars(f, NULL));
145: }
146: }
147:
148: if (arr)
149: io_arrayDestroy(&arr);
150: return NULL;
151: }
152:
153: static void *
154: rxPacket(sched_task_t *task)
155: {
156: rpc_cli_t *c = TASK_ARG(task);
157: rpc_srv_t *s = c->cli_parent;
158: u_char *buf = TASK_DATA(task);
159: int rlen;
160: u_short crc;
161: struct tagRPCCall *rpc;
162: struct timespec ts;
163:
164: FTRACE();
165:
166: memset(buf, 0, TASK_DATLEN(task));
167: rlen = recv(TASK_FD(task), buf, TASK_DATLEN(task), 0);
168: if (rlen == -1) {
169: LOGERR;
170: s->srv_kill = s->srv_blob.state = kill;
171: return NULL;
172: } else if (!rlen) { /* receive EOF */
173: s->srv_kill = s->srv_blob.state = kill;
174: return NULL;
175: } else
176: LOGGER("Readed %d bytes", rlen);
177:
178: if (rlen < sizeof(struct tagRPCCall)) {
179: rpc_SetErr(ERPCMISMATCH, "Too short RPC packet");
180:
181: schedRead(TASK_ROOT(task), rxPacket, TASK_ARG(task), TASK_FD(task),
182: TASK_DATA(task), TASK_DATLEN(task));
183: return NULL;
184: } else
185: rpc = (struct tagRPCCall*) buf;
186:
187: /* check integrity of packet */
188: crc = ntohs(rpc->call_crc);
189: rpc->call_crc ^= rpc->call_crc;
190: if (crc != crcFletcher16((u_short*) buf, io_align(rlen, 1) / 2)) {
191: rpc_SetErr(ERPCMISMATCH, "Bad CRC RPC packet");
192:
193: schedRead(TASK_ROOT(task), rxPacket, TASK_ARG(task), TASK_FD(task),
194: TASK_DATA(task), TASK_DATLEN(task));
195: return NULL;
196: }
197:
198: /* check RPC packet session info */
199: if (rpc_chkPktSession(&rpc->call_session, &s->srv_session)) {
200: rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
201: rpc->call_argc ^= rpc->call_argc;
202: rpc->call_rep.ret = RPC_ERROR(-1);
203: rpc->call_rep.eno = RPC_ERROR(errno);
204: goto end;
205: } else {
206: /* change socket timeout from last packet */
207: ts.tv_sec = rpc->call_session.sess_timeout;
208: ts.tv_nsec = 0;
209: schedPolling(TASK_ROOT(task), &ts, NULL);
210: }
211:
212: /* execute RPC call */
213: schedEvent(TASK_ROOT(task), execCall, TASK_ARG(task), 0,
214: TASK_DATA(task), TASK_DATLEN(task));
215:
216: end:
217: /* send RPC reply */
218: if (!(rpc->call_req.flags & RPC_NOREPLY))
219: schedWrite(TASK_ROOT(task), txPacket, TASK_ARG(task), TASK_FD(task),
220: TASK_DATA(task), TASK_DATLEN(task));
221: /* lets get next packet */
222: schedRead(TASK_ROOT(task), rxPacket, TASK_ARG(task), TASK_FD(task),
223: TASK_DATA(task), TASK_DATLEN(task));
224: return NULL;
225: }
226:
227: static void *
228: rpc_srv_dispatchCall(void *arg)
229: {
230: rpc_cli_t *c = arg;
231: rpc_srv_t *s;
232: u_char *buf;
233: sched_root_task_t *root;
234: struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
235:
236: FTRACE();
237:
238: if (!arg) {
239: rpc_SetErr(EINVAL, "Invalid parameter can`t procced RPC client");
240: return NULL;
241: } else
242: s = c->cli_parent;
243:
244: /* allocate net buffer */
245: buf = malloc(s->srv_netbuf);
246: if (!buf) {
247: LOGERR;
248: return NULL;
249: }
250:
251: root = schedBegin();
252: if (!root) {
253: rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
254: free(buf);
255: return NULL;
256: } else {
257: schedTermCondition(root, kill);
258: schedPolling(root, &ts, NULL);
259: }
260:
261: schedRead(root, rxPacket, c, c->cli_sock, buf, s->srv_netbuf);
262:
263: schedRun(root, (void*) &s->srv_kill);
264: schedEnd(&root);
265:
266: shutdown(c->cli_sock, SHUT_RDWR);
267: close(c->cli_sock);
268: memset(c, 0, sizeof(rpc_cli_t));
269: free(buf);
270: return NULL;
271: }
272:
273:
274: static void *
275: txBLOB(sched_task_t *task)
276: {
277: u_char *buf = TASK_DATA(task);
278: struct tagBLOBHdr *blob = (struct tagBLOBHdr *) buf;
279: int wlen = sizeof(struct tagBLOBHdr);
280:
281: FTRACE();
282:
283: /* calculate CRC */
284: blob->hdr_crc ^= blob->hdr_crc;
285: blob->hdr_crc = htons(crcFletcher16((u_short*) buf, io_align(wlen, 1) / 2));
286:
287: /* send reply */
288: wlen = send(TASK_FD(task), buf, wlen, 0);
289: if (wlen == -1)
290: LOGERR;
291: else if (wlen != sizeof(struct tagBLOBHdr))
292: rpc_SetErr(EPROCUNAVAIL, "RPC reply, should be send %d bytes, "
293: "really sended %d bytes", sizeof(struct tagBLOBHdr), wlen);
294: else
295: LOGGER("Sended %d bytes", wlen);
296:
297: return NULL;
298: }
299:
300: static void *
301: rxBLOB(sched_task_t *task)
302: {
303: rpc_cli_t *c = TASK_ARG(task);
304: rpc_srv_t *s = c->cli_parent;
305: rpc_blob_t *b;
306: u_char *buf = TASK_DATA(task);
307: struct tagBLOBHdr *blob = (struct tagBLOBHdr *) buf;
308: int rlen;
309: u_short crc;
310: struct timespec ts;
311:
312: FTRACE();
313:
314: /* check for disable service at this moment? */
315: if (s->srv_blob.state == disable) {
316: usleep(100000);
317: #ifdef HAVE_PTHREAD_YIELD
318: pthread_yield();
319: #endif
320: schedRead(TASK_ROOT(task), rxBLOB, TASK_ARG(task), TASK_FD(task),
321: TASK_DATA(task), TASK_DATLEN(task));
322: return NULL;
323: }
324:
325: memset(buf, 0, TASK_DATLEN(task));
326: rlen = recv(TASK_FD(task), buf, TASK_DATLEN(task), 0);
327: if (rlen == -1) {
328: LOGERR;
329: s->srv_blob.state = kill;
330: return NULL;
331: } else if (!rlen || s->srv_kill == kill) { /* receive EOF */
332: s->srv_blob.state = kill;
333: return NULL;
334: } else
335: LOGGER("Readed %d bytes", rlen);
336:
337: if (rlen < sizeof(struct tagBLOBHdr)) {
338: rpc_SetErr(ERPCMISMATCH, "Too short BLOB packet");
339: schedRead(TASK_ROOT(task), rxBLOB, TASK_ARG(task), TASK_FD(task),
340: TASK_DATA(task), TASK_DATLEN(task));
341: return NULL;
342: }
343:
344: /* check integrity of packet */
345: crc = ntohs(blob->hdr_crc);
346: blob->hdr_crc ^= blob->hdr_crc;
347: if (crc != crcFletcher16((u_short*) buf, io_align(rlen, 1) / 2)) {
348: rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
349: schedRead(TASK_ROOT(task), rxBLOB, TASK_ARG(task), TASK_FD(task),
350: TASK_DATA(task), TASK_DATLEN(task));
351: return NULL;
352: }
353:
354: /* check RPC packet session info */
355: if ((crc = rpc_chkPktSession(&blob->hdr_session, &s->srv_session))) {
356: rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
357: blob->hdr_cmd = error;
358: goto end;
359: } else {
360: /* change socket timeout from last packet */
361: ts.tv_sec = blob->hdr_session.sess_timeout;
362: ts.tv_nsec = 0;
363: schedPolling(TASK_ROOT(task), &ts, NULL);
364: }
365:
366: /* Go to proceed packet ... */
367: switch (blob->hdr_cmd) {
368: case get:
369: if (!(b = rpc_srv_getBLOB(s, ntohl(blob->hdr_var)))) {
370: rpc_SetErr(EINVAL, "Var=%x not found", ntohl(blob->hdr_var));
371: blob->hdr_cmd = no;
372: blob->hdr_ret = RPC_ERROR(-1);
373: break;
374: } else
375: blob->hdr_len = htonl(b->blob_len);
376:
377: if (rpc_srv_blobMap(s, b) != -1) {
378: /* deliver BLOB variable to client */
379: blob->hdr_ret = htonl(rpc_srv_sendBLOB(c, b));
380: rpc_srv_blobUnmap(b);
381: } else {
382: blob->hdr_cmd = error;
383: blob->hdr_ret = RPC_ERROR(-1);
384: }
385: break;
386: case set:
387: if ((b = rpc_srv_registerBLOB(s, ntohl(blob->hdr_len)))) {
388: /* set new BLOB variable for reply :) */
389: blob->hdr_var = htonl(b->blob_var);
390:
391: /* receive BLOB from client */
392: blob->hdr_ret = htonl(rpc_srv_recvBLOB(c, b));
393: rpc_srv_blobUnmap(b);
394: } else {
395: blob->hdr_cmd = error;
396: blob->hdr_ret = RPC_ERROR(-1);
397: }
398: break;
399: case unset:
400: if (rpc_srv_unregisterBLOB(s, blob->hdr_var) == -1) {
401: blob->hdr_cmd = error;
402: blob->hdr_ret = RPC_ERROR(-1);
403: }
404: break;
405: default:
406: rpc_SetErr(EPROCUNAVAIL, "Unsupported BLOB command %d", blob->hdr_cmd);
407: blob->hdr_cmd = error;
408: blob->hdr_ret = RPC_ERROR(-1);
409: }
410:
411: end:
412: schedWrite(TASK_ROOT(task), txBLOB, TASK_ARG(task), TASK_FD(task),
413: TASK_DATA(task), TASK_DATLEN(task));
414: schedRead(TASK_ROOT(task), rxBLOB, TASK_ARG(task), TASK_FD(task),
415: TASK_DATA(task), TASK_DATLEN(task));
416: return NULL;
417: }
418:
419: static void *
420: rpc_srv_dispatchVars(void *arg)
421: {
422: rpc_cli_t *c = arg;
423: rpc_srv_t *s;
424: sched_root_task_t *root;
425: u_char *buf;
426: struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
427:
428: FTRACE();
429:
430: if (!arg) {
431: rpc_SetErr(EINVAL, "Invalid parameter can`t procced BLOB");
432: return NULL;
433: } else
434: s = c->cli_parent;
435:
436: /* allocate net buffer */
437: buf = malloc(sizeof(struct tagBLOBHdr));
438: if (!buf) {
439: LOGERR;
440: return NULL;
441: }
442:
443: root = schedBegin();
444: if (!root) {
445: rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
446: free(buf);
447: return NULL;
448: } else {
449: schedTermCondition(root, kill);
450: schedPolling(root, &ts, NULL);
451: }
452:
453: schedRead(root, rxBLOB, c, c->cli_sock, buf, sizeof(struct tagBLOBHdr));
454:
455: schedRun(root, (void*) &s->srv_blob.state);
456: schedEnd(&root);
457:
458: shutdown(c->cli_sock, SHUT_RDWR);
459: close(c->cli_sock);
460: memset(c, 0, sizeof(rpc_cli_t));
461: free(buf);
462: return NULL;
463: }
464:
465: // -------------------------------------------------
466:
467: /*
468: * rpc_srv_initBLOBServer() - Init & create BLOB Server
469: *
470: * @srv = RPC server instance
471: * @Port = Port for bind server, if Port == 0 default port is selected
472: * @diskDir = Disk place for BLOB file objects
473: * return: -1 == error or 0 bind and created BLOB server instance
474: */
475: int
476: rpc_srv_initBLOBServer(rpc_srv_t * __restrict srv, u_short Port, const char *diskDir)
477: {
478: int n = 1;
479: io_sockaddr_t sa;
480:
481: FTRACE();
482:
483: if (!srv) {
484: rpc_SetErr(EINVAL, "Invalid parameters can`t init BLOB server");
485: return -1;
486: }
487: if (srv->srv_blob.state) {
488: rpc_SetErr(EPERM, "Already started BLOB server!");
489: return 0;
490: }
491:
492: memset(&srv->srv_blob, 0, sizeof srv->srv_blob);
493: if (access(diskDir, R_OK | W_OK) == -1) {
494: LOGERR;
495: return -1;
496: } else
497: AIT_SET_STR(&srv->srv_blob.dir, diskDir);
498:
499: srv->srv_blob.server.cli_tid = pthread_self();
500: srv->srv_blob.server.cli_parent = srv;
501:
502: memcpy(&sa, &srv->srv_server.cli_sa, sizeof sa);
503: switch (sa.sa.sa_family) {
504: case AF_INET:
505: sa.sin.sin_port = htons(Port ? Port : ntohs(sa.sin.sin_port) + 1);
506: break;
507: case AF_INET6:
508: sa.sin6.sin6_port = htons(Port ? Port : ntohs(sa.sin6.sin6_port) + 1);
509: break;
510: case AF_LOCAL:
511: strlcat(sa.sun.sun_path, ".blob", sizeof sa.sun.sun_path);
512: break;
513: default:
514: AIT_FREE_VAL(&srv->srv_blob.dir);
515: return -1;
516: }
517: memcpy(&srv->srv_blob.server.cli_sa, &sa, sizeof sa);
518:
519: /* create BLOB server socket */
520: srv->srv_blob.server.cli_sock = socket(srv->srv_server.cli_sa.sa.sa_family, SOCK_STREAM, 0);
521: if (srv->srv_blob.server.cli_sock == -1) {
522: LOGERR;
523: AIT_FREE_VAL(&srv->srv_blob.dir);
524: return -1;
525: }
526: if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
527: LOGERR;
528: close(srv->srv_blob.server.cli_sock);
529: AIT_FREE_VAL(&srv->srv_blob.dir);
530: return -1;
531: }
532: n = srv->srv_netbuf;
533: if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof n) == -1) {
534: LOGERR;
535: close(srv->srv_blob.server.cli_sock);
536: AIT_FREE_VAL(&srv->srv_blob.dir);
537: return -1;
538: }
539: if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof n) == -1) {
540: LOGERR;
541: close(srv->srv_blob.server.cli_sock);
542: AIT_FREE_VAL(&srv->srv_blob.dir);
543: return -1;
544: }
545: if (bind(srv->srv_blob.server.cli_sock, &srv->srv_blob.server.cli_sa.sa,
546: srv->srv_blob.server.cli_sa.sa.sa_len) == -1) {
547: LOGERR;
548: close(srv->srv_blob.server.cli_sock);
549: AIT_FREE_VAL(&srv->srv_blob.dir);
550: return -1;
551: }
552:
553: /* allocate pool for concurent clients */
554: srv->srv_blob.clients = calloc(srv->srv_numcli, sizeof(rpc_cli_t));
555: if (!srv->srv_blob.clients) {
556: LOGERR;
557: close(srv->srv_blob.server.cli_sock);
558: AIT_FREE_VAL(&srv->srv_blob.dir);
559: return -1;
560: } else
561: memset(srv->srv_blob.clients, 0, srv->srv_numcli * sizeof(rpc_cli_t));
562:
563: pthread_mutex_init(&srv->srv_blob.mtx, NULL);
564:
565: rpc_srv_registerCall(srv, NULL, CALL_BLOBSHUTDOWN, 0);
566: rpc_srv_registerCall(srv, NULL, CALL_BLOBCLIENTS, 1);
567: rpc_srv_registerCall(srv, NULL, CALL_BLOBVARS, 1);
568: rpc_srv_registerCall(srv, NULL, CALL_BLOBSTATE, 0);
569:
570: srv->srv_blob.state = enable; /* enable BLOB */
571: return 0;
572: }
573:
574: /*
575: * rpc_srv_endBLOBServer() - Destroy BLOB server, close all opened sockets and free resources
576: *
577: * @srv = RPC Server instance
578: * return: none
579: */
580: void
581: rpc_srv_endBLOBServer(rpc_srv_t * __restrict srv)
582: {
583: rpc_cli_t *c;
584: register int i;
585: rpc_blob_t *f;
586:
587: FTRACE();
588:
589: if (!srv) {
590: rpc_SetErr(EINVAL, "Can`t destroy server because parameter is null!");
591: return;
592: } else
593: srv->srv_blob.state = kill;
594:
595: rpc_srv_unregisterCall(srv, NULL, CALL_BLOBSHUTDOWN);
596: rpc_srv_unregisterCall(srv, NULL, CALL_BLOBCLIENTS);
597: rpc_srv_unregisterCall(srv, NULL, CALL_BLOBVARS);
598: rpc_srv_unregisterCall(srv, NULL, CALL_BLOBSTATE);
599:
600: AIT_FREE_VAL(&srv->srv_blob.dir);
601:
602: /* close all clients connections & server socket */
603: for (i = 0, c = srv->srv_blob.clients; i < srv->srv_numcli && c; i++, c++)
604: if (c->cli_sa.sa.sa_family)
605: shutdown(c->cli_sock, SHUT_RDWR);
606: close(srv->srv_blob.server.cli_sock);
607:
608: pthread_mutex_lock(&srv->srv_blob.mtx);
609: if (srv->srv_blob.clients) {
610: free(srv->srv_blob.clients);
611: srv->srv_blob.clients = NULL;
612: }
613:
614: /* detach blobs */
615: while ((f = srv->srv_blob.blobs)) {
616: srv->srv_blob.blobs = f->blob_next;
617: rpc_srv_blobFree(srv, f);
618: free(f);
619: }
620: pthread_mutex_unlock(&srv->srv_blob.mtx);
621:
622: while (pthread_mutex_trylock(&srv->srv_blob.mtx) == EBUSY);
623: pthread_mutex_destroy(&srv->srv_blob.mtx);
624: }
625:
626: /*
627: * rpc_srv_loopBLOB() - Execute Main BLOB server loop and wait for clients requests
628: *
629: * @srv = RPC Server instance
630: * return: -1 error or 0 ok, infinite loop ...
631: */
632: int
633: rpc_srv_loopBLOB(rpc_srv_t * __restrict srv)
634: {
635: socklen_t salen = sizeof(io_sockaddr_t);
636: register int i;
637: rpc_cli_t *c;
638: fd_set fds;
639: int ret;
640: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
641: pthread_attr_t attr;
642:
643: FTRACE();
644:
645: if (!srv || srv->srv_blob.state == kill) {
646: rpc_SetErr(EINVAL, "Invalid parameter can`t start BLOB server");
647: return -1;
648: }
649:
650: tv.tv_sec = srv->srv_session.sess_timeout;
651:
652: if (listen(srv->srv_blob.server.cli_sock, SOMAXCONN) == -1) {
653: LOGERR;
654: return -1;
655: }
656:
657: pthread_attr_init(&attr);
658: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
659:
660: /* main BLOB loop */
661: while (srv->srv_blob.state != kill && srv->srv_kill != kill) {
662: for (c = srv->srv_blob.clients, i = 0; i < srv->srv_numcli && c; i++, c++)
663: if (!c->cli_sa.sa.sa_family)
664: break;
665: if (i >= srv->srv_numcli) {
666: #ifdef HAVE_PTHREAD_YIELD
667: pthread_yield();
668: #else
669: usleep(1000000);
670: #endif
671: continue;
672: }
673:
674: FD_ZERO(&fds);
675: FD_SET(srv->srv_blob.server.cli_sock, &fds);
676: ret = select(srv->srv_blob.server.cli_sock + 1, &fds, NULL, NULL, &tv);
677: if (ret == -1) {
678: LOGERR;
679: ret = 1;
680: break;
681: }
682: if (!ret)
683: continue;
684:
685: c->cli_sock = accept(srv->srv_blob.server.cli_sock, &c->cli_sa.sa, &salen);
686: if (c->cli_sock == -1) {
687: LOGERR;
688: continue;
689: } else
690: c->cli_parent = srv;
691:
692: /* spawn dispatch thread for BLOB client */
693: if (pthread_create(&c->cli_tid, &attr, rpc_srv_dispatchVars, c)) {
694: LOGERR;
695: continue;
696: }
697: }
698:
699: srv->srv_blob.state = kill;
700:
701: pthread_attr_destroy(&attr);
702: return 0;
703: }
704:
705:
706: /*
707: * rpc_srv_initServer() - Init & create RPC Server
708: *
709: * @regProgID = ProgramID for authentication & recognition
710: * @regProcID = ProcessID for authentication & recognition
711: * @concurentClients = Concurent clients at same time to this server
712: * @netBuf = Network buffer length, if =0 == BUFSIZ (also meaning max RPC packet)
713: * @family = Family type, AF_INET, AF_INET6 or AF_LOCAL
714: * @csHost = Host name or address for bind server, if NULL any address
715: * @Port = Port for bind server, if Port == 0 default port is selected
716: * return: NULL == error or !=NULL bind and created RPC server instance
717: */
718: rpc_srv_t *
719: rpc_srv_initServer(u_int regProgID, u_int regProcID, int concurentClients,
720: int netBuf, u_short family, const char *csHost, u_short Port)
721: {
722: rpc_srv_t *srv = NULL;
723: int n = 1;
724: struct hostent *host = NULL;
725: io_sockaddr_t sa;
726:
727: FTRACE();
728:
729: if (!concurentClients || !regProgID ||
730: (family != AF_INET && family != AF_INET6 && family != AF_LOCAL)) {
731: rpc_SetErr(EINVAL, "Error:: Invalid parameters can`t init RPC server ...\n");
732: return NULL;
733: }
734: if (!Port)
735: Port = RPC_DEFPORT;
736: if (!netBuf)
737: netBuf = BUFSIZ;
738: else
739: netBuf = io_align(netBuf, 1); /* align netBuf length */
740: if (csHost && family != AF_LOCAL) {
741: host = gethostbyname2(csHost, family);
742: if (!host) {
743: rpc_SetErr(h_errno, "Error:: %s\n", hstrerror(h_errno));
744: return NULL;
745: }
746: }
747: memset(&sa, 0, sizeof sa);
748: sa.sa.sa_family = family;
749: switch (family) {
750: case AF_INET:
751: sa.sin.sin_len = sizeof(struct sockaddr_in);
752: sa.sin.sin_port = htons(Port);
753: if (csHost)
754: memcpy(&sa.sin.sin_addr, host->h_addr, host->h_length);
755: break;
756: case AF_INET6:
757: sa.sin6.sin6_len = sizeof(struct sockaddr_in6);
758: sa.sin6.sin6_port = htons(Port);
759: if (csHost)
760: memcpy(&sa.sin6.sin6_addr, host->h_addr, host->h_length);
761: break;
762: case AF_LOCAL:
763: sa.sun.sun_len = sizeof(struct sockaddr_un);
764: if (csHost)
765: strlcpy(sa.sun.sun_path, csHost, sizeof sa.sun.sun_path);
766: unlink(sa.sun.sun_path);
767: break;
768: default:
769: rpc_SetErr(EINVAL, "Error:: Invalid parameters can`t start RPC server ...\n");
770: return NULL;
771: }
772:
773: srv = malloc(sizeof(rpc_srv_t));
774: if (!srv) {
775: LOGERR;
776: return NULL;
777: } else
778: memset(srv, 0, sizeof(rpc_srv_t));
779:
780: srv->srv_netbuf = netBuf;
781: srv->srv_numcli = concurentClients;
782: srv->srv_session.sess_version = RPC_VERSION;
783: srv->srv_session.sess_timeout = DEF_RPC_TIMEOUT;
784: srv->srv_session.sess_program = regProgID;
785: srv->srv_session.sess_process = regProcID;
786:
787: srv->srv_server.cli_tid = pthread_self();
788: srv->srv_server.cli_parent = srv;
789: memcpy(&srv->srv_server.cli_sa, &sa, sizeof sa);
790:
791: /* create server socket */
792: srv->srv_server.cli_sock = socket(family, SOCK_STREAM, 0);
793: if (srv->srv_server.cli_sock == -1) {
794: LOGERR;
795: free(srv);
796: return NULL;
797: }
798: if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
799: LOGERR;
800: close(srv->srv_server.cli_sock);
801: free(srv);
802: return NULL;
803: }
804: n = srv->srv_netbuf;
805: if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof n) == -1) {
806: LOGERR;
807: close(srv->srv_server.cli_sock);
808: free(srv);
809: return NULL;
810: }
811: if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof n) == -1) {
812: LOGERR;
813: close(srv->srv_server.cli_sock);
814: free(srv);
815: return NULL;
816: }
817: if (bind(srv->srv_server.cli_sock, &srv->srv_server.cli_sa.sa,
818: srv->srv_server.cli_sa.sa.sa_len) == -1) {
819: LOGERR;
820: close(srv->srv_server.cli_sock);
821: free(srv);
822: return NULL;
823: }
824:
825: /* allocate pool for concurent clients */
826: srv->srv_clients = calloc(srv->srv_numcli, sizeof(rpc_cli_t));
827: if (!srv->srv_clients) {
828: LOGERR;
829: close(srv->srv_server.cli_sock);
830: free(srv);
831: return NULL;
832: } else
833: memset(srv->srv_clients, 0, srv->srv_numcli * sizeof(rpc_cli_t));
834:
835: pthread_mutex_init(&srv->srv_mtx, NULL);
836:
837: rpc_srv_registerCall(srv, NULL, CALL_SRVSHUTDOWN, 0);
838: rpc_srv_registerCall(srv, NULL, CALL_SRVCLIENTS, 1);
839: rpc_srv_registerCall(srv, NULL, CALL_SRVSESSIONS, 4);
840: rpc_srv_registerCall(srv, NULL, CALL_SRVCALLS, 1);
841: return srv;
842: }
843:
844: /*
845: * rpc_srv_endServer() - Destroy RPC server, close all opened sockets and free resources
846: *
847: * @psrv = RPC Server instance
848: * return: none
849: */
850: void
851: rpc_srv_endServer(rpc_srv_t ** __restrict psrv)
852: {
853: rpc_cli_t *c;
854: register int i;
855: rpc_func_t *f;
856:
857: FTRACE();
858:
859: if (!psrv || !*psrv) {
860: rpc_SetErr(EINVAL, "Error:: Can`t destroy server because parameter is null!\n");
861: return;
862: }
863:
864: rpc_srv_endBLOBServer(*psrv);
865:
866: /* close all clients connections & server socket */
867: for (i = 0, c = (*psrv)->srv_clients; i < (*psrv)->srv_numcli && c; i++, c++)
868: if (c->cli_sa.sa.sa_family) {
869: shutdown(c->cli_sock, SHUT_RDWR);
870: close(c->cli_sock);
871: }
872: close((*psrv)->srv_server.cli_sock);
873:
874: if ((*psrv)->srv_clients) {
875: free((*psrv)->srv_clients);
876: (*psrv)->srv_clients = NULL;
877: (*psrv)->srv_numcli = 0;
878: }
879:
880: /* detach exported calls */
881: pthread_mutex_lock(&(*psrv)->srv_mtx);
882: while ((f = (*psrv)->srv_funcs)) {
883: (*psrv)->srv_funcs = f->func_next;
884: io_freeVars(&f->func_vars);
885: AIT_FREE_VAL(&f->func_name);
886: AIT_FREE_VAL(&f->func_file);
887: free(f);
888: }
889: pthread_mutex_unlock(&(*psrv)->srv_mtx);
890:
891: while (pthread_mutex_trylock(&(*psrv)->srv_mtx) == EBUSY);
892: pthread_mutex_destroy(&(*psrv)->srv_mtx);
893:
894: free(*psrv);
895: *psrv = NULL;
896: }
897:
898: /*
899: * rpc_srv_loopServer() - Execute Main server loop and wait for clients requests
900: *
901: * @srv = RPC Server instance
902: * return: -1 error or 0 ok, infinite loop ...
903: */
904: int
905: rpc_srv_loopServer(rpc_srv_t * __restrict srv)
906: {
907: socklen_t salen = sizeof(io_sockaddr_t);
908: register int i;
909: rpc_cli_t *c;
910: fd_set fds;
911: int ret;
912: struct timeval tv = { DEF_RPC_TIMEOUT, 0 };
913: pthread_attr_t attr;
914:
915: FTRACE();
916:
917: if (!srv) {
918: rpc_SetErr(EINVAL, "Error:: Invalid parameter can`t start RPC server ...\n");
919: return -1;
920: }
921:
922: tv.tv_sec = srv->srv_session.sess_timeout;
923:
924: /* activate BLOB server worker if srv->srv_blob.state == enable */
925: rpc_srv_execBLOBServer(srv);
926:
927: if (listen(srv->srv_server.cli_sock, SOMAXCONN) == -1) {
928: LOGERR;
929: return -1;
930: }
931:
932: pthread_attr_init(&attr);
933: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
934:
935: /* main rpc loop */
936: while (srv->srv_kill != kill) {
937: for (c = srv->srv_clients, i = 0; i < srv->srv_numcli && c; i++, c++)
938: if (!c->cli_sa.sa.sa_family)
939: break;
940: if (i >= srv->srv_numcli) {
941: #ifdef HAVE_PTHREAD_YIELD
942: pthread_yield();
943: #else
944: usleep(1000000);
945: #endif
946: continue;
947: }
948:
949: FD_ZERO(&fds);
950: FD_SET(srv->srv_server.cli_sock, &fds);
951: ret = select(srv->srv_server.cli_sock + 1, &fds, NULL, NULL, &tv);
952: if (ret == -1) {
953: LOGERR;
954: ret = 1;
955: break;
956: }
957: if (!ret)
958: continue;
959:
960: c->cli_sock = accept(srv->srv_server.cli_sock, &c->cli_sa.sa, &salen);
961: if (c->cli_sock == -1) {
962: LOGERR;
963: continue;
964: } else
965: c->cli_parent = srv;
966:
967: /* spawn rpc client dispatcher */
968: if (pthread_create(&c->cli_tid, &attr, rpc_srv_dispatchCall, c)) {
969: LOGERR;
970: continue;
971: }
972: }
973:
974: pthread_attr_destroy(&attr);
975: return 0;
976: }
977:
978: // ---------------------------------------------------------
979:
980: /*
981: * rpc_srv_execCall() Execute registered call from RPC server
982: *
983: * @call = Register RPC call
984: * @rpc = IN RPC call structure
985: * @args = IN RPC calling arguments from RPC client
986: * return: -1 error, !=-1 ok
987: */
988: int
989: rpc_srv_execCall(rpc_func_t * __restrict call, struct tagRPCCall * __restrict rpc,
990: array_t * __restrict args)
991: {
992: void *dl;
993: rpc_callback_t func;
994: int ret;
995:
996: FTRACE();
997:
998: if (!call || !rpc || !call->func_parent) {
999: rpc_SetErr(EINVAL, "Invalid parameter can`t exec function");
1000: return -1;
1001: }
1002:
1003: dl = dlopen(AIT_VOID(&call->func_file), RTLD_NOW);
1004: if (!dl) {
1005: rpc_SetErr(ENOENT, "Can`t attach module %s!", dlerror());
1006: return -1;
1007: }
1008:
1009: func = dlsym(dl, (const char*) AIT_GET_STR(&call->func_name));
1010: if (func)
1011: ret = func(call, ntohs(rpc->call_argc), args);
1012: else {
1013: rpc_SetErr(ENOEXEC, "Can`t find function %s!", dlerror());
1014: ret = -1;
1015: }
1016:
1017: dlclose(dl);
1018: return ret;
1019: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>