Annotation of libaitrpc/src/srv.c, revision 1.24.2.5

1.1       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.24.2.5! misho       6: * $Id: srv.c,v 1.24.2.4 2015/01/18 00:06:55 misho Exp $
1.1       misho       7: *
1.2       misho       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.24.2.2  misho      15: Copyright 2004 - 2015
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: */
1.1       misho      46: #include "global.h"
                     47: 
                     48: 
1.13      misho      49: /* SOCK_STREAM */
                     50: static void *acceptClients(sched_task_t *);
                     51: static void *closeClient(sched_task_t *);
                     52: static void *rxPacket(sched_task_t *);
                     53: static void *txPacket(sched_task_t *);
                     54: 
                     55: /* SOCK_DGRAM */
                     56: static void *freeClient(sched_task_t *);
                     57: static void *rxUDPPacket(sched_task_t *);
                     58: static void *txUDPPacket(sched_task_t *);
                     59: 
                     60: /* SOCK_RAW */
                     61: 
1.24      misho      62: /* SOCK_BPF */
                     63: static void *rxBPFPacket(sched_task_t *);
                     64: static void *txBPFPacket(sched_task_t *);
                     65: 
1.24.2.3  misho      66: /* SOCK_EXT */
1.24.2.5! misho      67: static void *rxEXTPacket(sched_task_t *);
        !            68: static void *txEXTPacket(sched_task_t *);
1.24.2.1  misho      69: 
                     70: static sched_task_func_t cbProto[SOCK_MAX_SUPPORT][4] = {
1.13      misho      71:        { acceptClients, closeClient, rxPacket, txPacket },     /* SOCK_STREAM */
                     72:        { acceptClients, closeClient, rxPacket, txPacket },     /* SOCK_STREAM */
                     73:        { rxUDPPacket, freeClient, rxUDPPacket, txUDPPacket },  /* SOCK_DGRAM */
1.24      misho      74:        { NULL, NULL, NULL, NULL },                             /* SOCK_RAW */
1.24.2.1  misho      75:        { rxBPFPacket, freeClient, rxBPFPacket, txBPFPacket },  /* SOCK_BPF */
1.24.2.5! misho      76:        { rxEXTPacket, freeClient, rxEXTPacket, txEXTPacket }   /* SOCK_EXT */
1.13      misho      77: };
                     78: 
1.23      misho      79: /* Global Signal Argument when kqueue support disabled */
                     80: 
                     81: static volatile uintptr_t _glSigArg = 0;
                     82: 
1.13      misho      83: 
1.16      misho      84: void
1.13      misho      85: rpc_freeCli(rpc_cli_t * __restrict c)
1.10      misho      86: {
                     87:        rpc_srv_t *s = c->cli_parent;
                     88: 
1.13      misho      89:        schedCancelby(s->srv_root, taskMAX, CRITERIA_ARG, c, NULL);
1.10      misho      90: 
                     91:        /* free buffer */
                     92:        AIT_FREE_VAL(&c->cli_buf);
                     93: 
1.14      misho      94:        array_Del(s->srv_clients, c->cli_id, 0);
1.10      misho      95:        if (c)
1.14      misho      96:                e_free(c);
1.13      misho      97: }
                     98: 
                     99: 
                    100: static inline int
1.14      misho     101: _check4freeslot(rpc_srv_t * __restrict srv, sockaddr_t * __restrict sa)
1.13      misho     102: {
                    103:        rpc_cli_t *c = NULL;
                    104:        register int i;
                    105: 
                    106:        /* check free slots for connect */
1.14      misho     107:        for (i = 0; i < array_Size(srv->srv_clients) && 
                    108:                        (c = array(srv->srv_clients, i, rpc_cli_t*)); i++)
1.13      misho     109:                /* check for duplicates */
1.14      misho     110:                if (sa && !e_addrcmp(&c->cli_sa, sa, 42))
1.13      misho     111:                        break;
1.14      misho     112:        if (i >= array_Size(srv->srv_clients))
1.13      misho     113:                return -1;      /* no more free slots! */
                    114: 
                    115:        return i;
                    116: }
                    117: 
                    118: static rpc_cli_t *
1.14      misho     119: _allocClient(rpc_srv_t * __restrict srv, sockaddr_t * __restrict sa)
1.13      misho     120: {
                    121:        rpc_cli_t *c = NULL;
                    122:        int n;
                    123: 
1.24.2.5! misho     124:        if (srv->srv_proto != SOCK_EXT)
        !           125:                n = _check4freeslot(srv, sa);
        !           126:        else
        !           127:                n = 0;
1.13      misho     128:        if (n == -1)
                    129:                return NULL;
                    130:        else
1.14      misho     131:                c = array(srv->srv_clients, n, rpc_cli_t*);
1.13      misho     132: 
                    133:        if (!c) {
1.14      misho     134:                c = e_malloc(sizeof(rpc_cli_t));
1.13      misho     135:                if (!c) {
                    136:                        LOGERR;
                    137:                        srv->srv_kill = 1;
                    138:                        return NULL;
                    139:                } else {
                    140:                        memset(c, 0, sizeof(rpc_cli_t));
1.14      misho     141:                        array_Set(srv->srv_clients, n, c);
1.13      misho     142:                        c->cli_id = n;
                    143:                        c->cli_parent = srv;
                    144:                }
                    145: 
                    146:                /* alloc empty buffer */
1.14      misho     147:                AIT_SET_BUFSIZ(&c->cli_buf, 0, srv->srv_netbuf);
1.13      misho     148:        }
                    149: 
                    150:        return c;
                    151: }
                    152: 
                    153: 
                    154: static void *
                    155: freeClient(sched_task_t *task)
                    156: {
                    157:        rpc_freeCli(TASK_ARG(task));
                    158: 
                    159:        return NULL;
                    160: }
                    161: 
                    162: static void *
                    163: closeClient(sched_task_t *task)
                    164: {
                    165:        int sock = ((rpc_cli_t*) TASK_ARG(task))->cli_sock;
                    166: 
                    167:        rpc_freeCli(TASK_ARG(task));
                    168: 
                    169:        /* close client socket */
                    170:        shutdown(sock, SHUT_RDWR);
                    171:        close(sock);
1.10      misho     172:        return NULL;
                    173: }
1.7       misho     174: 
                    175: static void *
                    176: txPacket(sched_task_t *task)
                    177: {
                    178:        rpc_cli_t *c = TASK_ARG(task);
                    179:        rpc_srv_t *s = c->cli_parent;
                    180:        rpc_func_t *f = NULL;
1.18      misho     181:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
1.7       misho     182:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
1.18      misho     183:        int ret, estlen, wlen = sizeof(struct tagRPCCall);
1.19      misho     184:        struct pollfd pfd;
1.21      misho     185: #ifdef TCP_SESSION_TIMEOUT
                    186:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
                    187: 
                    188:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, TASK_ARG(task), NULL);
                    189:        schedTimer(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    190:                         TASK_ARG(task), ts, TASK_ARG(task), 0);
                    191: #endif
1.7       misho     192: 
                    193:        if (rpc->call_argc) {
1.10      misho     194:                f = rpc_srv_getCall(s, ntohs(rpc->call_tag));
1.7       misho     195:                if (!f) {
1.10      misho     196:                        rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
1.18      misho     197: 
1.7       misho     198:                        rpc->call_argc ^= rpc->call_argc;
                    199:                        rpc->call_rep.ret = RPC_ERROR(-1);
                    200:                        rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    201:                } else {
1.18      misho     202:                        /* calc estimated length */
                    203:                        estlen = ait_resideVars(RPC_RETVARS(c)) + wlen;
                    204:                        if (estlen > AIT_LEN(&c->cli_buf))
                    205:                                AIT_RE_BUF(&c->cli_buf, estlen);
                    206:                        buf = AIT_GET_BUF(&c->cli_buf);
1.19      misho     207:                        rpc = (struct tagRPCCall*) buf;
1.18      misho     208: 
1.14      misho     209:                        rpc->call_argc = htons(array_Size(RPC_RETVARS(c)));
1.7       misho     210:                        /* Go Encapsulate variables */
1.18      misho     211:                        ret = ait_vars2buffer(buf + wlen, AIT_LEN(&c->cli_buf) - wlen, 
                    212:                                        RPC_RETVARS(c));
1.10      misho     213:                        /* Free return values */
1.14      misho     214:                        ait_freeVars(&c->cli_vars);
1.7       misho     215:                        if (ret == -1) {
                    216:                                rpc_SetErr(EBADRPC, "Prepare RPC packet failed");
1.19      misho     217: 
1.7       misho     218:                                rpc->call_argc ^= rpc->call_argc;
                    219:                                rpc->call_rep.ret = RPC_ERROR(-1);
                    220:                                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    221:                        } else
                    222:                                wlen += ret;
                    223:                }
                    224:        }
                    225: 
1.18      misho     226:        rpc->call_len = htonl(wlen);
1.8       misho     227: 
1.15      misho     228: #if 0
1.7       misho     229:        /* calculate CRC */
                    230:        rpc->call_crc ^= rpc->call_crc;
1.8       misho     231:        rpc->call_crc = htons(crcFletcher16((u_short*) buf, wlen / 2));
1.15      misho     232: #endif
1.7       misho     233: 
                    234:        /* send reply */
1.19      misho     235:        pfd.fd = TASK_FD(task);
                    236:        pfd.events = POLLOUT;
                    237:        for (; wlen > 0; wlen -= ret, buf += ret) {
                    238:                if ((ret = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
                    239:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
                    240:                        if (ret)
                    241:                                LOGERR;
                    242:                        else
1.22      misho     243:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
1.19      misho     244:                        /* close connection */
                    245:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    246:                                        TASK_ARG(task), 0, NULL, 0);
                    247:                        return NULL;
                    248:                }
                    249:                ret = send(TASK_FD(task), buf, MIN(wlen, s->srv_netbuf), MSG_NOSIGNAL);
                    250:                if (ret == -1) {
                    251:                        /* close connection */
                    252:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    253:                                        TASK_ARG(task), 0, NULL, 0);
                    254:                        return NULL;
                    255:                }
1.10      misho     256:        }
1.7       misho     257: 
                    258:        return NULL;
                    259: }
                    260: 
                    261: static void *
                    262: execCall(sched_task_t *task)
                    263: {
                    264:        rpc_cli_t *c = TASK_ARG(task);
                    265:        rpc_srv_t *s = c->cli_parent;
                    266:        rpc_func_t *f = NULL;
                    267:        array_t *arr = NULL;
1.18      misho     268:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
1.7       misho     269:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
                    270:        int argc = ntohs(rpc->call_argc);
                    271: 
                    272:        /* Go decapsulate variables ... */
1.8       misho     273:        if (argc) {
1.14      misho     274:                arr = ait_buffer2vars(buf + sizeof(struct tagRPCCall), 
1.18      misho     275:                                AIT_LEN(&c->cli_buf) - sizeof(struct tagRPCCall), argc, 42);
1.7       misho     276:                if (!arr) {
1.14      misho     277:                        rpc_SetErr(ERPCMISMATCH, "#%d - %s", elwix_GetErrno(), elwix_GetError());
1.18      misho     278: 
1.7       misho     279:                        rpc->call_argc ^= rpc->call_argc;
                    280:                        rpc->call_rep.ret = RPC_ERROR(-1);
                    281:                        rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    282:                        return NULL;
                    283:                }
1.10      misho     284:        } else
                    285:                arr = NULL;
1.7       misho     286: 
1.10      misho     287:        if (!(f = rpc_srv_getCall(s, ntohs(rpc->call_tag)))) {
1.7       misho     288:                rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
1.18      misho     289: 
1.7       misho     290:                rpc->call_argc ^= rpc->call_argc;
                    291:                rpc->call_rep.ret = RPC_ERROR(-1);
                    292:                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    293:        } else {
1.8       misho     294:                /* if client doesn't want reply */
1.10      misho     295:                argc = RPC_CHK_NOREPLY(rpc);
                    296:                rpc->call_rep.ret = RPC_ERROR(rpc_srv_execCall(c, rpc, f->func_name, arr));
1.7       misho     297:                if (rpc->call_rep.ret == htonl(-1)) {
1.20      misho     298:                        if (!rpc->call_rep.eno) {
                    299:                                LOGERR;
                    300:                                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    301:                        }
1.7       misho     302:                        rpc->call_argc ^= rpc->call_argc;
                    303:                } else {
                    304:                        rpc->call_rep.eno ^= rpc->call_rep.eno;
1.8       misho     305:                        if (argc) {
                    306:                                /* without reply */
1.14      misho     307:                                ait_freeVars(&c->cli_vars);
1.8       misho     308:                                rpc->call_argc ^= rpc->call_argc;
1.10      misho     309:                        } else {
                    310:                                /* reply */
1.14      misho     311:                                rpc->call_argc = htons(array_Size(RPC_RETVARS(c)));
1.10      misho     312:                        }
1.7       misho     313:                }
                    314:        }
                    315: 
1.14      misho     316:        array_Destroy(&arr);
1.7       misho     317:        return NULL;
                    318: }
                    319: 
                    320: static void *
                    321: rxPacket(sched_task_t *task)
                    322: {
                    323:        rpc_cli_t *c = TASK_ARG(task);
                    324:        rpc_srv_t *s = c->cli_parent;
1.18      misho     325:        int len, rlen, noreply, estlen;
1.15      misho     326: #if 0
                    327:        u_short crc;
                    328: #endif
1.10      misho     329:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
1.18      misho     330:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
1.19      misho     331:        struct pollfd pfd;
1.21      misho     332: #ifdef TCP_SESSION_TIMEOUT
                    333:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
                    334: 
                    335:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, TASK_ARG(task), NULL);
                    336:        schedTimer(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    337:                         TASK_ARG(task), ts, TASK_ARG(task), 0);
                    338: #endif
1.7       misho     339: 
1.18      misho     340:        memset(buf, 0, sizeof(struct tagRPCCall));
1.19      misho     341:        rlen = recv(TASK_FD(task), rpc, sizeof(struct tagRPCCall), MSG_PEEK);
1.18      misho     342:        if (rlen < sizeof(struct tagRPCCall)) {
1.10      misho     343:                /* close connection */
1.13      misho     344:                schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    345:                                TASK_ARG(task), 0, NULL, 0);
1.7       misho     346:                return NULL;
1.10      misho     347:        } else {
1.18      misho     348:                estlen = ntohl(rpc->call_len);
                    349:                if (estlen > AIT_LEN(&c->cli_buf))
                    350:                        AIT_RE_BUF(&c->cli_buf, estlen);
                    351:                rpc = (struct tagRPCCall*) AIT_GET_BUF(&c->cli_buf);
1.19      misho     352:                buf = AIT_GET_BUF(&c->cli_buf);
                    353:                len = estlen;
1.18      misho     354:        }
                    355: 
1.19      misho     356:        /* get next part of packet */
                    357:        memset(buf, 0, len);
                    358:        pfd.fd = TASK_FD(task);
                    359:        pfd.events = POLLIN | POLLPRI;
                    360:        for (; len > 0; len -= rlen, buf += rlen) {
                    361:                if ((rlen = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
                    362:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
                    363:                        if (rlen)
                    364:                                LOGERR;
                    365:                        else
1.22      misho     366:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
1.19      misho     367:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    368:                                        TASK_ARG(task), 0, NULL, 0);
                    369:                        return NULL;
                    370:                }
1.18      misho     371:                rlen = recv(TASK_FD(task), buf, len, 0);
                    372:                if (rlen == -1) {
                    373:                        /* close connection */
                    374:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    375:                                        TASK_ARG(task), 0, NULL, 0);
1.8       misho     376:                        return NULL;
1.10      misho     377:                }
1.18      misho     378:        }
1.22      misho     379:        len = estlen;
1.8       misho     380: 
1.15      misho     381: #if 0
1.18      misho     382:        /* check integrity of packet */
                    383:        crc = ntohs(rpc->call_crc);
                    384:        rpc->call_crc ^= rpc->call_crc;
                    385:        if (crc != crcFletcher16((u_short*) rpc, len / 2)) {
                    386:                rpc_SetErr(ERPCMISMATCH, "Bad CRC RPC packet");
                    387:                return NULL;
                    388:        }
1.15      misho     389: #endif
1.7       misho     390: 
1.18      misho     391:        noreply = RPC_CHK_NOREPLY(rpc);
1.7       misho     392: 
1.18      misho     393:        /* check RPC packet session info */
                    394:        if (rpc_chkPktSession(&rpc->call_session, &s->srv_session)) {
                    395:                rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
1.7       misho     396: 
1.18      misho     397:                rpc->call_argc ^= rpc->call_argc;
                    398:                rpc->call_rep.ret = RPC_ERROR(-1);
                    399:                rpc->call_rep.eno = RPC_ERROR(errno);
                    400:        } else {
                    401:                /* execute RPC call */
                    402:                schedEvent(TASK_ROOT(task), execCall, TASK_ARG(task), (int) noreply, rpc, len);
                    403:        }
1.7       misho     404: 
1.18      misho     405:        /* send RPC reply */
                    406:        if (!noreply)
                    407:                schedWrite(TASK_ROOT(task), cbProto[s->srv_proto][CB_TXPACKET], 
                    408:                                TASK_ARG(task), TASK_FD(task), rpc, len);
1.7       misho     409: 
                    410:        /* lets get next packet */
1.18      misho     411:        schedReadSelf(task);
1.7       misho     412:        return NULL;
                    413: }
                    414: 
1.1       misho     415: static void *
1.10      misho     416: acceptClients(sched_task_t *task)
1.1       misho     417: {
1.10      misho     418:        rpc_srv_t *srv = TASK_ARG(task);
                    419:        rpc_cli_t *c = NULL;
1.14      misho     420:        socklen_t salen = sizeof(sockaddr_t);
1.21      misho     421:        int sock;
                    422: #ifdef TCP_SESSION_TIMEOUT
                    423:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
                    424: #endif
1.7       misho     425: 
1.13      misho     426:        c = _allocClient(srv, NULL);
1.21      misho     427:        if (!c) {
                    428:                EVERBOSE(1, "RPC client quota exceeded! Connection will be shutdown!\n");
                    429:                if ((sock = accept(TASK_FD(task), NULL, NULL)) != -1) {
                    430:                        shutdown(sock, SHUT_RDWR);
                    431:                        close(sock);
                    432:                }
1.10      misho     433:                goto end;
1.21      misho     434:        }
1.10      misho     435: 
                    436:        /* accept client */
                    437:        c->cli_sock = accept(TASK_FD(task), &c->cli_sa.sa, &salen);
                    438:        if (c->cli_sock == -1) {
                    439:                LOGERR;
                    440:                AIT_FREE_VAL(&c->cli_buf);
1.14      misho     441:                array_Del(srv->srv_clients, c->cli_id, 42);
1.10      misho     442:                goto end;
1.1       misho     443:        } else
1.10      misho     444:                fcntl(c->cli_sock, F_SETFL, fcntl(c->cli_sock, F_GETFL) | O_NONBLOCK);
1.1       misho     445: 
1.21      misho     446: #ifdef TCP_SESSION_TIMEOUT
                    447:        /* armed timer for close stateless connection */
                    448:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, c, NULL);
                    449:        schedTimer(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], c, 
                    450:                        ts, c, 0);
                    451: #endif
1.13      misho     452:        schedRead(TASK_ROOT(task), cbProto[srv->srv_proto][CB_RXPACKET], c, 
                    453:                        c->cli_sock, NULL, 0);
1.10      misho     454: end:
                    455:        schedReadSelf(task);
                    456:        return NULL;
                    457: }
1.5       misho     458: 
1.7       misho     459: 
1.10      misho     460: static void *
1.13      misho     461: txUDPPacket(sched_task_t *task)
1.10      misho     462: {
                    463:        rpc_cli_t *c = TASK_ARG(task);
                    464:        rpc_srv_t *s = c->cli_parent;
1.13      misho     465:        rpc_func_t *f = NULL;
1.18      misho     466:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
1.13      misho     467:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
1.22      misho     468:        int ret, estlen, wlen = sizeof(struct tagRPCCall);
1.13      misho     469:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
1.22      misho     470:        struct pollfd pfd;
1.13      misho     471: 
                    472:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, TASK_ARG(task), NULL);
                    473:        schedTimer(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    474:                         TASK_ARG(task), ts, TASK_ARG(task), 0);
                    475: 
                    476:        if (rpc->call_argc) {
                    477:                f = rpc_srv_getCall(s, ntohs(rpc->call_tag));
                    478:                if (!f) {
                    479:                        rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
                    480:                        rpc->call_argc ^= rpc->call_argc;
                    481:                        rpc->call_rep.ret = RPC_ERROR(-1);
                    482:                        rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    483:                } else {
1.22      misho     484:                        /* calc estimated length */
                    485:                        estlen = ait_resideVars(RPC_RETVARS(c)) + wlen;
                    486:                        if (estlen > AIT_LEN(&c->cli_buf))
                    487:                                AIT_RE_BUF(&c->cli_buf, estlen);
                    488:                        buf = AIT_GET_BUF(&c->cli_buf);
                    489:                        rpc = (struct tagRPCCall*) buf;
                    490: 
1.14      misho     491:                        rpc->call_argc = htons(array_Size(RPC_RETVARS(c)));
1.13      misho     492:                        /* Go Encapsulate variables */
1.18      misho     493:                        ret = ait_vars2buffer(buf + wlen, AIT_LEN(&c->cli_buf) - wlen, 
                    494:                                        RPC_RETVARS(c));
1.13      misho     495:                        /* Free return values */
1.14      misho     496:                        ait_freeVars(&c->cli_vars);
1.13      misho     497:                        if (ret == -1) {
                    498:                                rpc_SetErr(EBADRPC, "Prepare RPC packet failed");
                    499:                                rpc->call_argc ^= rpc->call_argc;
                    500:                                rpc->call_rep.ret = RPC_ERROR(-1);
                    501:                                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    502:                        } else
                    503:                                wlen += ret;
                    504:                }
                    505:        }
1.7       misho     506: 
1.18      misho     507:        rpc->call_len = htonl(wlen);
1.7       misho     508: 
1.13      misho     509:        /* calculate CRC */
                    510:        rpc->call_crc ^= rpc->call_crc;
                    511:        rpc->call_crc = htons(crcFletcher16((u_short*) buf, wlen / 2));
                    512: 
                    513:        /* send reply */
1.22      misho     514:        pfd.fd = TASK_FD(task);
                    515:        pfd.events = POLLOUT;
                    516:        for (; wlen > 0; wlen -= ret, buf += ret) {
                    517:                if ((ret = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
                    518:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
                    519:                        if (ret)
                    520:                                LOGERR;
                    521:                        else
                    522:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
                    523:                        /* close connection */
                    524:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    525:                                        TASK_ARG(task), 0, NULL, 0);
                    526:                        return NULL;
                    527:                }
                    528:                ret = sendto(TASK_FD(task), buf, MIN(wlen, s->srv_netbuf), MSG_NOSIGNAL, 
                    529:                                &c->cli_sa.sa, c->cli_sa.sa.sa_len);
                    530:                if (ret == -1) {
                    531:                        /* close connection */
                    532:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    533:                                        TASK_ARG(task), 0, NULL, 0);
                    534:                        return NULL;
                    535:                }
1.13      misho     536:        }
                    537: 
                    538:        return NULL;
                    539: }
                    540: 
                    541: static void *
                    542: rxUDPPacket(sched_task_t *task)
                    543: {
                    544:        rpc_srv_t *srv = TASK_ARG(task);
                    545:        rpc_cli_t *c = NULL;
1.22      misho     546:        int len, rlen, noreply, estlen;
                    547:        u_short crc;
                    548:        u_char *buf, b[sizeof(struct tagRPCCall)];
                    549:        struct tagRPCCall *rpc = (struct tagRPCCall*) b;
1.14      misho     550:        sockaddr_t sa;
                    551:        socklen_t salen;
1.13      misho     552:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
1.22      misho     553:        struct pollfd pfd;
1.13      misho     554: 
                    555:        /* receive connect packet */
1.14      misho     556:        salen = sa.ss.ss_len = sizeof(sockaddr_t);
1.22      misho     557:        rlen = recvfrom(TASK_FD(task), b, sizeof b, MSG_PEEK, &sa.sa, &salen);
                    558:        if (rlen < sizeof(struct tagRPCCall)) {
                    559:                rpc_SetErr(ERPCMISMATCH, "Short RPC packet");
1.13      misho     560:                goto end;
1.22      misho     561:        }
1.13      misho     562: 
                    563:        c = _allocClient(srv, &sa);
1.22      misho     564:        if (!c) {
                    565:                EVERBOSE(1, "RPC client quota exceeded! Connection will be shutdown!\n");
                    566:                usleep(2000);   /* blocked client delay */
1.13      misho     567:                goto end;
1.22      misho     568:        } else {
                    569:                estlen = ntohl(rpc->call_len);
                    570:                if (estlen > AIT_LEN(&c->cli_buf))
                    571:                        AIT_RE_BUF(&c->cli_buf, estlen);
                    572:                rpc = (struct tagRPCCall*) AIT_GET_BUF(&c->cli_buf);
                    573:                buf = AIT_GET_BUF(&c->cli_buf);
                    574:                len = estlen;
                    575: 
1.13      misho     576:                c->cli_sock = TASK_FD(task);
                    577:                memcpy(&c->cli_sa, &sa, sizeof c->cli_sa);
1.22      misho     578: 
1.13      misho     579:                /* armed timer for close stateless connection */
                    580:                schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, c, NULL);
                    581:                schedTimer(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    582:                                c, ts, c, 0);
                    583:        }
                    584: 
1.22      misho     585:        /* get next part of packet */
                    586:        memset(buf, 0, len);
                    587:        pfd.fd = TASK_FD(task);
                    588:        pfd.events = POLLIN | POLLPRI;
                    589:        for (; len > 0; len -= rlen, buf += rlen) {
                    590:                if ((rlen = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
                    591:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
                    592:                        if (rlen)
                    593:                                LOGERR;
                    594:                        else
                    595:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
                    596:                        schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    597:                                        c, 0, NULL, 0);
1.24      misho     598:                        goto end;
1.13      misho     599:                }
1.22      misho     600:                salen = sa.ss.ss_len = sizeof(sockaddr_t);
                    601:                rlen = recvfrom(TASK_FD(task), buf, len, 0, &sa.sa, &salen);
                    602:                if (rlen == -1) {
                    603:                        /* close connection */
                    604:                        schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    605:                                        c, 0, NULL, 0);
1.24      misho     606:                        goto end;
1.13      misho     607:                }
1.22      misho     608:                if (e_addrcmp(&c->cli_sa, &sa, 42))
                    609:                        rlen ^= rlen;   /* skip if arrive from different address */
                    610:        }
                    611:        len = estlen;
1.13      misho     612: 
1.22      misho     613:        /* check integrity of packet */
                    614:        crc = ntohs(rpc->call_crc);
                    615:        rpc->call_crc ^= rpc->call_crc;
                    616:        if (crc != crcFletcher16((u_short*) rpc, len / 2)) {
                    617:                rpc_SetErr(ERPCMISMATCH, "Bad CRC RPC packet");
1.24      misho     618:                /* close connection */
                    619:                schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    620:                                c, 0, NULL, 0);
                    621:                goto end;
                    622:        }
                    623: 
                    624:        noreply = RPC_CHK_NOREPLY(rpc);
                    625: 
                    626:        /* check RPC packet session info */
                    627:        if (rpc_chkPktSession(&rpc->call_session, &srv->srv_session)) {
                    628:                rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
                    629: 
                    630:                rpc->call_argc ^= rpc->call_argc;
                    631:                rpc->call_rep.ret = RPC_ERROR(-1);
                    632:                rpc->call_rep.eno = RPC_ERROR(errno);
                    633:        } else {
                    634:                /* execute RPC call */
                    635:                schedEvent(TASK_ROOT(task), execCall, c, (int) noreply, rpc, len);
                    636:        }
                    637: 
                    638:        /* send RPC reply */
                    639:        if (!noreply)
                    640:                schedWrite(TASK_ROOT(task), cbProto[srv->srv_proto][CB_TXPACKET], 
                    641:                                c, TASK_FD(task), rpc, len);
                    642: end:
                    643:        schedReadSelf(task);
                    644:        return NULL;
                    645: }
                    646: 
                    647: 
                    648: static void *
                    649: txBPFPacket(sched_task_t *task)
                    650: {
                    651:        rpc_cli_t *c = TASK_ARG(task);
                    652:        rpc_srv_t *s = c->cli_parent;
                    653:        rpc_func_t *f = NULL;
                    654:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
                    655:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
                    656:        int ret, len, wlen = sizeof(struct tagRPCCall);
                    657:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
                    658:        struct ether_header *eh;
                    659:        ait_val_t b = AIT_VAL_INIT;
                    660: 
                    661:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, TASK_ARG(task), NULL);
                    662:        schedTimer(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    663:                         TASK_ARG(task), ts, TASK_ARG(task), 0);
                    664: 
                    665:        if (rpc->call_argc) {
                    666:                f = rpc_srv_getCall(s, ntohs(rpc->call_tag));
                    667:                if (!f) {
                    668:                        rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
                    669:                        rpc->call_argc ^= rpc->call_argc;
                    670:                        rpc->call_rep.ret = RPC_ERROR(-1);
                    671:                        rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    672:                } else {
                    673:                        /* calc estimated length */
                    674:                        len = ait_resideVars(RPC_RETVARS(c)) + wlen;
                    675:                        if (len > AIT_LEN(&c->cli_buf))
                    676:                                AIT_RE_BUF(&c->cli_buf, len);
                    677:                        buf = AIT_GET_BUF(&c->cli_buf);
                    678:                        rpc = (struct tagRPCCall*) buf;
                    679: 
                    680:                        rpc->call_argc = htons(array_Size(RPC_RETVARS(c)));
                    681:                        /* Go Encapsulate variables */
                    682:                        ret = ait_vars2buffer(buf + wlen, AIT_LEN(&c->cli_buf) - wlen, 
                    683:                                        RPC_RETVARS(c));
                    684:                        /* Free return values */
                    685:                        ait_freeVars(&RPC_RETVARS(c));
                    686:                        if (ret == -1) {
                    687:                                rpc_SetErr(EBADRPC, "Prepare RPC packet failed");
                    688:                                rpc->call_argc ^= rpc->call_argc;
                    689:                                rpc->call_rep.ret = RPC_ERROR(-1);
                    690:                                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
                    691:                        } else
                    692:                                wlen += ret;
                    693:                }
                    694:        }
                    695: 
                    696:        rpc->call_len = htonl(wlen);
                    697: 
                    698:        /* calculate CRC */
                    699:        rpc->call_crc ^= rpc->call_crc;
                    700:        rpc->call_crc = htons(crcFletcher16((u_short*) buf, wlen / 2));
                    701: 
                    702:        /* send reply */
                    703:        AIT_SET_BUF(&b, NULL, MIN(wlen, s->srv_netbuf) + ETHER_HDR_LEN);
                    704:        eh = (struct ether_header*) AIT_GET_BUF(&b);
                    705:        memcpy(eh->ether_dhost, LLADDR(&c->cli_sa.sdl), ETHER_ADDR_LEN);
                    706:        eh->ether_type = htons(RPC_DEFPORT);
                    707:        memcpy(eh + 1, buf, MIN(wlen, s->srv_netbuf));
                    708: 
                    709:        ret = write(TASK_FD(task), AIT_GET_BUF(&b), AIT_LEN(&b));
                    710:        AIT_FREE_VAL(&b);
                    711:        if (ret == -1) {
                    712:                /* close connection */
                    713:                schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
                    714:                                TASK_ARG(task), 0, NULL, 0);
1.22      misho     715:                return NULL;
                    716:        }
1.13      misho     717: 
1.24      misho     718:        return NULL;
                    719: }
                    720: 
                    721: static void *
                    722: rxBPFPacket(sched_task_t *task)
                    723: {
                    724:        rpc_srv_t *srv = TASK_ARG(task);
                    725:        rpc_cli_t *c = NULL;
                    726:        int len, rlen, noreply;
                    727:        u_short crc;
                    728:        struct tagRPCCall *rpc;
                    729:        sockaddr_t sa;
                    730:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
                    731:        struct bpf_hdr *h;
                    732:        struct ether_header *eh;
                    733:        ait_val_t b = AIT_VAL_INIT;
                    734: 
                    735:        /* receive connect packet */
                    736:        AIT_SET_BUF(&b, NULL, srv->srv_netbuf);
                    737:        rlen = read(TASK_FD(task), AIT_GET_BUF(&b), AIT_LEN(&b));
                    738:        h = (struct bpf_hdr*) AIT_GET_BUF(&b);
                    739:        rlen -= h->bh_hdrlen;
                    740:        if (rlen < h->bh_datalen || h->bh_caplen != h->bh_datalen || 
                    741:                        rlen < ETHER_HDR_LEN + sizeof(struct tagRPCCall)) {
                    742:                rpc_SetErr(ERPCMISMATCH, "Short RPC packet");
                    743:                goto end;
                    744:        } else {
                    745:                rlen = h->bh_caplen;
                    746:                eh = (struct ether_header*) (AIT_GET_BUF(&b) + h->bh_hdrlen);
                    747:                rlen -= ETHER_HDR_LEN;
                    748:                rpc = (struct tagRPCCall*) (eh + 1);
                    749:                if (eh->ether_type != ntohs(RPC_DEFPORT))
                    750:                        goto end;
                    751:                else
                    752:                        e_getlinkbymac((const ether_addr_t*) eh->ether_shost, &sa);
                    753:        }
                    754: 
                    755:        c = _allocClient(srv, &sa);
                    756:        if (!c) {
                    757:                EVERBOSE(1, "RPC client quota exceeded! Connection will be shutdown!\n");
                    758:                usleep(2000);   /* blocked client delay */
                    759:                goto end;
                    760:        } else {
                    761:                len = ntohl(rpc->call_len);
                    762:                if (len > AIT_LEN(&c->cli_buf))
                    763:                        AIT_RE_BUF(&c->cli_buf, len);
                    764:                memcpy(AIT_GET_BUF(&c->cli_buf), rpc, AIT_LEN(&c->cli_buf));
                    765:                rpc = (struct tagRPCCall*) AIT_GET_BUF(&c->cli_buf);
                    766: 
                    767:                c->cli_sock = TASK_FD(task);
                    768:                memcpy(&c->cli_sa, &sa, sizeof c->cli_sa);
                    769: 
                    770:                /* armed timer for close stateless connection */
                    771:                schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, c, NULL);
                    772:                schedTimer(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    773:                                c, ts, c, 0);
                    774:        }
                    775: 
                    776:        /* check integrity of packet */
                    777:        crc = ntohs(rpc->call_crc);
                    778:        rpc->call_crc ^= rpc->call_crc;
                    779:        if (crc != crcFletcher16((u_short*) rpc, len / 2)) {
                    780:                rpc_SetErr(ERPCMISMATCH, "Bad CRC RPC packet");
                    781:                /* close connection */
                    782:                schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
                    783:                                c, 0, NULL, 0);
                    784:                goto end;
                    785:        }
                    786: 
1.22      misho     787:        noreply = RPC_CHK_NOREPLY(rpc);
1.18      misho     788: 
1.22      misho     789:        /* check RPC packet session info */
                    790:        if (rpc_chkPktSession(&rpc->call_session, &srv->srv_session)) {
                    791:                rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
1.13      misho     792: 
1.22      misho     793:                rpc->call_argc ^= rpc->call_argc;
                    794:                rpc->call_rep.ret = RPC_ERROR(-1);
                    795:                rpc->call_rep.eno = RPC_ERROR(errno);
                    796:        } else {
                    797:                /* execute RPC call */
                    798:                schedEvent(TASK_ROOT(task), execCall, c, (int) noreply, rpc, len);
                    799:        }
1.13      misho     800: 
1.22      misho     801:        /* send RPC reply */
                    802:        if (!noreply)
1.24      misho     803:                schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_TXPACKET], 
1.22      misho     804:                                c, TASK_FD(task), rpc, len);
1.13      misho     805: end:
1.24      misho     806:        AIT_FREE_VAL(&b);
1.13      misho     807:        schedReadSelf(task);
                    808:        return NULL;
                    809: }
                    810: 
1.24.2.5! misho     811: 
        !           812: static void *
        !           813: txEXTPacket(sched_task_t *task)
        !           814: {
        !           815:        rpc_cli_t *c = TASK_ARG(task);
        !           816:        rpc_srv_t *s = c->cli_parent;
        !           817:        rpc_func_t *f = NULL;
        !           818:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
        !           819:        struct tagRPCCall *rpc = (struct tagRPCCall*) buf;
        !           820:        int ret, estlen, wlen = sizeof(struct tagRPCCall);
        !           821:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
        !           822:        struct pollfd pfd;
        !           823: 
        !           824:        schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, TASK_ARG(task), NULL);
        !           825:        schedTimer(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
        !           826:                         TASK_ARG(task), ts, TASK_ARG(task), 0);
        !           827: 
        !           828:        if (rpc->call_argc) {
        !           829:                f = rpc_srv_getCall(s, ntohs(rpc->call_tag));
        !           830:                if (!f) {
        !           831:                        rpc_SetErr(EPROGUNAVAIL, "Function not found at RPC server");
        !           832:                        rpc->call_argc ^= rpc->call_argc;
        !           833:                        rpc->call_rep.ret = RPC_ERROR(-1);
        !           834:                        rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
        !           835:                } else {
        !           836:                        /* calc estimated length */
        !           837:                        estlen = ait_resideVars(RPC_RETVARS(c)) + wlen;
        !           838:                        if (estlen > AIT_LEN(&c->cli_buf))
        !           839:                                AIT_RE_BUF(&c->cli_buf, estlen);
        !           840:                        buf = AIT_GET_BUF(&c->cli_buf);
        !           841:                        rpc = (struct tagRPCCall*) buf;
        !           842: 
        !           843:                        rpc->call_argc = htons(array_Size(RPC_RETVARS(c)));
        !           844:                        /* Go Encapsulate variables */
        !           845:                        ret = ait_vars2buffer(buf + wlen, AIT_LEN(&c->cli_buf) - wlen, 
        !           846:                                        RPC_RETVARS(c));
        !           847:                        /* Free return values */
        !           848:                        ait_freeVars(&c->cli_vars);
        !           849:                        if (ret == -1) {
        !           850:                                rpc_SetErr(EBADRPC, "Prepare RPC packet failed");
        !           851:                                rpc->call_argc ^= rpc->call_argc;
        !           852:                                rpc->call_rep.ret = RPC_ERROR(-1);
        !           853:                                rpc->call_rep.eno = RPC_ERROR(rpc_Errno);
        !           854:                        } else
        !           855:                                wlen += ret;
        !           856:                }
        !           857:        }
        !           858: 
        !           859:        rpc->call_len = htonl(wlen);
        !           860: 
        !           861:        /* send reply */
        !           862:        pfd.fd = TASK_FD(task);
        !           863:        pfd.events = POLLOUT;
        !           864:        for (; wlen > 0; wlen -= ret, buf += ret) {
        !           865:                if ((ret = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
        !           866:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
        !           867:                        if (ret)
        !           868:                                LOGERR;
        !           869:                        else
        !           870:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
        !           871:                        /* close connection */
        !           872:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
        !           873:                                        TASK_ARG(task), 0, NULL, 0);
        !           874:                        return NULL;
        !           875:                }
        !           876:                ret = write(TASK_FD(task), buf, MIN(wlen, s->srv_netbuf));
        !           877:                if (ret == -1) {
        !           878:                        /* close connection */
        !           879:                        schedEvent(TASK_ROOT(task), cbProto[s->srv_proto][CB_CLOSECLIENT], 
        !           880:                                        TASK_ARG(task), 0, NULL, 0);
        !           881:                        return NULL;
        !           882:                }
        !           883:        }
        !           884: 
        !           885:        return NULL;
        !           886: }
        !           887: 
        !           888: static void *
        !           889: rxEXTPacket(sched_task_t *task)
        !           890: {
        !           891:        rpc_srv_t *srv = TASK_ARG(task);
        !           892:        rpc_cli_t *c = NULL;
        !           893:        int len, rlen, noreply, estlen;
        !           894:        u_char *buf, b[sizeof(struct tagRPCCall)];
        !           895:        struct tagRPCCall *rpc = (struct tagRPCCall*) b;
        !           896:        struct timespec ts = { DEF_RPC_TIMEOUT, 0 };
        !           897:        struct pollfd pfd;
        !           898: 
        !           899:        /* receive connect packet */
        !           900:        rlen = read(TASK_FD(task), b, sizeof b);
        !           901:        if (rlen < sizeof(struct tagRPCCall)) {
        !           902:                rpc_SetErr(ERPCMISMATCH, "Short RPC packet");
        !           903:                goto end;
        !           904:        }
        !           905: 
        !           906:        c = _allocClient(srv, (sockaddr_t*) -1);
        !           907:        if (!c) {
        !           908:                EVERBOSE(1, "RPC client quota exceeded! Connection will be shutdown!\n");
        !           909:                usleep(2000);   /* blocked client delay */
        !           910:                goto end;
        !           911:        } else {
        !           912:                estlen = ntohl(rpc->call_len);
        !           913:                if (estlen > AIT_LEN(&c->cli_buf))
        !           914:                        AIT_RE_BUF(&c->cli_buf, estlen);
        !           915:                rpc = (struct tagRPCCall*) AIT_GET_BUF(&c->cli_buf);
        !           916:                memcpy(rpc, b, sizeof b);
        !           917:                buf = (u_char*) (rpc + 1);
        !           918:                len = estlen;
        !           919: 
        !           920:                c->cli_sock = TASK_FD(task);
        !           921: 
        !           922:                /* armed timer for close stateless connection */
        !           923:                schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_DATA, c, NULL);
        !           924:                schedTimer(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
        !           925:                                c, ts, c, 0);
        !           926:        }
        !           927: 
        !           928:        /* get next part of packet */
        !           929:        memset(buf, 0, len);
        !           930:        pfd.fd = TASK_FD(task);
        !           931:        pfd.events = POLLIN | POLLPRI;
        !           932:        for (; len > 0; len -= rlen, buf += rlen) {
        !           933:                if ((rlen = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
        !           934:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
        !           935:                        if (rlen)
        !           936:                                LOGERR;
        !           937:                        else
        !           938:                                rpc_SetErr(ETIMEDOUT, "Timeout reached! Client not respond");
        !           939:                        schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
        !           940:                                        c, 0, NULL, 0);
        !           941:                        goto end;
        !           942:                }
        !           943:                rlen = read(TASK_FD(task), buf, len);
        !           944:                if (rlen == -1) {
        !           945:                        /* close connection */
        !           946:                        schedEvent(TASK_ROOT(task), cbProto[srv->srv_proto][CB_CLOSECLIENT], 
        !           947:                                        c, 0, NULL, 0);
        !           948:                        goto end;
        !           949:                }
        !           950:        }
        !           951:        len = estlen;
        !           952: 
        !           953:        noreply = RPC_CHK_NOREPLY(rpc);
        !           954: 
        !           955:        /* check RPC packet session info */
        !           956:        if (rpc_chkPktSession(&rpc->call_session, &srv->srv_session)) {
        !           957:                rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
        !           958: 
        !           959:                rpc->call_argc ^= rpc->call_argc;
        !           960:                rpc->call_rep.ret = RPC_ERROR(-1);
        !           961:                rpc->call_rep.eno = RPC_ERROR(errno);
        !           962:        } else {
        !           963:                /* execute RPC call */
        !           964:                schedEvent(TASK_ROOT(task), execCall, c, (int) noreply, rpc, len);
        !           965:        }
        !           966: 
        !           967:        /* send RPC reply */
        !           968:        if (!noreply)
        !           969:                schedWrite(TASK_ROOT(task), cbProto[srv->srv_proto][CB_TXPACKET], 
        !           970:                                c, TASK_FD(task), rpc, len);
        !           971: end:
        !           972:        schedReadSelf(task);
        !           973:        return NULL;
        !           974: }
        !           975: 
1.13      misho     976: /* ------------------------------------------------------ */
                    977: 
1.16      misho     978: void
1.13      misho     979: rpc_freeBLOBCli(rpc_cli_t * __restrict c)
                    980: {
                    981:        rpc_srv_t *s = c->cli_parent;
                    982: 
                    983:        schedCancelby(s->srv_blob.root, taskMAX, CRITERIA_ARG, c, NULL);
1.10      misho     984: 
                    985:        /* free buffer */
                    986:        AIT_FREE_VAL(&c->cli_buf);
                    987: 
1.14      misho     988:        array_Del(s->srv_blob.clients, c->cli_id, 0);
1.10      misho     989:        if (c)
1.14      misho     990:                e_free(c);
1.13      misho     991: }
                    992: 
                    993: 
                    994: static void *
                    995: closeBLOBClient(sched_task_t *task)
                    996: {
                    997:        int sock = ((rpc_cli_t*) TASK_ARG(task))->cli_sock;
                    998: 
                    999:        rpc_freeBLOBCli(TASK_ARG(task));
                   1000: 
                   1001:        /* close client socket */
                   1002:        shutdown(sock, SHUT_RDWR);
                   1003:        close(sock);
1.7       misho    1004:        return NULL;
                   1005: }
                   1006: 
                   1007: static void *
                   1008: txBLOB(sched_task_t *task)
                   1009: {
1.10      misho    1010:        rpc_cli_t *c = TASK_ARG(task);
                   1011:        u_char *buf = AIT_GET_BUF(&c->cli_buf);
1.7       misho    1012:        int wlen = sizeof(struct tagBLOBHdr);
                   1013: 
                   1014:        /* send reply */
1.10      misho    1015:        wlen = send(TASK_FD(task), buf, wlen, MSG_NOSIGNAL);
                   1016:        if (wlen == -1 || wlen != sizeof(struct tagBLOBHdr)) {
                   1017:                /* close blob connection */
                   1018:                schedEvent(TASK_ROOT(task), closeBLOBClient, c, 42, NULL, 0);
                   1019:        }
1.7       misho    1020: 
                   1021:        return NULL;
                   1022: }
1.4       misho    1023: 
1.7       misho    1024: static void *
                   1025: rxBLOB(sched_task_t *task)
                   1026: {
                   1027:        rpc_cli_t *c = TASK_ARG(task);
                   1028:        rpc_srv_t *s = c->cli_parent;
                   1029:        rpc_blob_t *b;
1.10      misho    1030:        struct tagBLOBHdr blob;
1.7       misho    1031:        int rlen;
                   1032: 
1.10      misho    1033:        memset(&blob, 0, sizeof blob);
                   1034:        rlen = recv(TASK_FD(task), &blob, sizeof blob, 0);
                   1035:        if (rlen < 1) {
                   1036:                /* close blob connection */
                   1037:                schedEvent(TASK_ROOT(task), closeBLOBClient, c, 42, NULL, 0);
1.7       misho    1038:                return NULL;
                   1039:        }
1.5       misho    1040: 
1.10      misho    1041:        /* check BLOB packet */
                   1042:        if (rlen < sizeof(struct tagBLOBHdr)) {
                   1043:                rpc_SetErr(ERPCMISMATCH, "Short BLOB packet");
1.6       misho    1044: 
1.10      misho    1045:                schedReadSelf(task);
1.7       misho    1046:                return NULL;
                   1047:        }
1.1       misho    1048: 
1.7       misho    1049:        /* check RPC packet session info */
1.15      misho    1050:        if (rpc_chkPktSession(&blob.hdr_session, &s->srv_session)) {
1.7       misho    1051:                rpc_SetErr(ERPCMISMATCH, "Get invalid RPC session");
1.10      misho    1052:                blob.hdr_cmd = error;
1.7       misho    1053:                goto end;
                   1054:        }
                   1055: 
                   1056:        /* Go to proceed packet ... */
1.10      misho    1057:        switch (blob.hdr_cmd) {
1.7       misho    1058:                case get:
1.10      misho    1059:                        if (!(b = rpc_srv_getBLOB(s, ntohl(blob.hdr_var)))) {
                   1060:                                rpc_SetErr(EINVAL, "Var=%x not found", ntohl(blob.hdr_var));
                   1061:                                blob.hdr_cmd = no;
                   1062:                                blob.hdr_ret = RPC_ERROR(-1);
1.7       misho    1063:                                break;
                   1064:                        } else
1.10      misho    1065:                                blob.hdr_len = htonl(b->blob_len);
1.5       misho    1066: 
1.7       misho    1067:                        if (rpc_srv_blobMap(s, b) != -1) {
                   1068:                                /* deliver BLOB variable to client */
1.10      misho    1069:                                blob.hdr_ret = htonl(rpc_srv_sendBLOB(c, b));
1.7       misho    1070:                                rpc_srv_blobUnmap(b);
                   1071:                        } else {
1.10      misho    1072:                                blob.hdr_cmd = error;
                   1073:                                blob.hdr_ret = RPC_ERROR(-1);
1.7       misho    1074:                        }
                   1075:                        break;
                   1076:                case set:
1.17      misho    1077:                        if ((b = rpc_srv_registerBLOB(s, ntohl(blob.hdr_len), 
                   1078:                                                        ntohl(blob.hdr_ret)))) {
1.7       misho    1079:                                /* set new BLOB variable for reply :) */
1.10      misho    1080:                                blob.hdr_var = htonl(b->blob_var);
1.7       misho    1081: 
                   1082:                                /* receive BLOB from client */
1.10      misho    1083:                                blob.hdr_ret = htonl(rpc_srv_recvBLOB(c, b));
1.7       misho    1084:                                rpc_srv_blobUnmap(b);
1.5       misho    1085:                        } else {
1.10      misho    1086:                                blob.hdr_cmd = error;
                   1087:                                blob.hdr_ret = RPC_ERROR(-1);
1.7       misho    1088:                        }
                   1089:                        break;
                   1090:                case unset:
1.11      misho    1091:                        if (rpc_srv_unregisterBLOB(s, ntohl(blob.hdr_var)) == -1) {
1.10      misho    1092:                                blob.hdr_cmd = error;
                   1093:                                blob.hdr_ret = RPC_ERROR(-1);
1.1       misho    1094:                        }
                   1095:                        break;
1.7       misho    1096:                default:
1.10      misho    1097:                        rpc_SetErr(EPROCUNAVAIL, "Unsupported BLOB command %d", blob.hdr_cmd);
                   1098:                        blob.hdr_cmd = error;
                   1099:                        blob.hdr_ret = RPC_ERROR(-1);
1.7       misho    1100:        }
1.1       misho    1101: 
1.7       misho    1102: end:
1.10      misho    1103:        memcpy(AIT_ADDR(&c->cli_buf), &blob, sizeof blob);
                   1104:        schedWrite(TASK_ROOT(task), txBLOB, TASK_ARG(task), TASK_FD(task), NULL, 0);
                   1105:        schedReadSelf(task);
1.7       misho    1106:        return NULL;
1.2       misho    1107: }
                   1108: 
                   1109: static void *
1.17      misho    1110: flushBLOB(sched_task_t *task)
                   1111: {
1.23      misho    1112:        uintptr_t sigArg = atomic_load_acq_ptr(&_glSigArg);
                   1113:        rpc_srv_t *srv = sigArg ? (void*) sigArg : TASK_ARG(task);
1.17      misho    1114:        rpc_blob_t *b, *tmp;
                   1115: 
                   1116:        TAILQ_FOREACH_SAFE(b, &srv->srv_blob.blobs, blob_node, tmp) {
                   1117:                TAILQ_REMOVE(&srv->srv_blob.blobs, b, blob_node);
                   1118: 
                   1119:                rpc_srv_blobFree(srv, b);
                   1120:                e_free(b);
                   1121:        }
                   1122: 
1.23      misho    1123:        if (!schedSignalSelf(task)) {
                   1124:                /* disabled kqueue support in libaitsched */
                   1125:                struct sigaction sa;
                   1126: 
                   1127:                memset(&sa, 0, sizeof sa);
                   1128:                sigemptyset(&sa.sa_mask);
                   1129:                sa.sa_handler = (void (*)(int)) flushBLOB;
                   1130:                sa.sa_flags = SA_RESTART | SA_RESETHAND;
                   1131:                sigaction(SIGFBLOB, &sa, NULL);
                   1132:        }
                   1133: 
1.17      misho    1134:        return NULL;
                   1135: }
                   1136: 
                   1137: static void *
1.10      misho    1138: acceptBLOBClients(sched_task_t *task)
1.2       misho    1139: {
1.10      misho    1140:        rpc_srv_t *srv = TASK_ARG(task);
                   1141:        rpc_cli_t *c = NULL;
                   1142:        register int i;
1.14      misho    1143:        socklen_t salen = sizeof(sockaddr_t);
1.21      misho    1144:        int sock;
1.12      misho    1145: #ifdef TCP_NOPUSH
                   1146:        int n = 1;
                   1147: #endif
1.7       misho    1148: 
1.10      misho    1149:        /* check free slots for connect */
1.14      misho    1150:        for (i = 0; i < array_Size(srv->srv_blob.clients) && 
                   1151:                        (c = array(srv->srv_blob.clients, i, rpc_cli_t*)); i++);
1.21      misho    1152:        if (c) {        /* no more free slots! */
                   1153:                EVERBOSE(1, "BLOB client quota exceeded! Connection will be shutdown!\n");
                   1154:                if ((sock = accept(TASK_FD(task), NULL, NULL)) != -1) {
                   1155:                        shutdown(sock, SHUT_RDWR);
                   1156:                        close(sock);
                   1157:                }
1.10      misho    1158:                goto end;
1.21      misho    1159:        }
                   1160: 
1.14      misho    1161:        c = e_malloc(sizeof(rpc_cli_t));
1.10      misho    1162:        if (!c) {
1.7       misho    1163:                LOGERR;
1.10      misho    1164:                srv->srv_kill = srv->srv_blob.kill = 1;
1.7       misho    1165:                return NULL;
                   1166:        } else {
1.10      misho    1167:                memset(c, 0, sizeof(rpc_cli_t));
1.14      misho    1168:                array_Set(srv->srv_blob.clients, i, c);
1.10      misho    1169:                c->cli_id = i;
                   1170:                c->cli_parent = srv;
1.7       misho    1171:        }
1.4       misho    1172: 
1.10      misho    1173:        /* alloc empty buffer */
1.14      misho    1174:        AIT_SET_BUFSIZ(&c->cli_buf, 0, srv->srv_netbuf);
1.2       misho    1175: 
1.10      misho    1176:        /* accept client */
                   1177:        c->cli_sock = accept(TASK_FD(task), &c->cli_sa.sa, &salen);
                   1178:        if (c->cli_sock == -1) {
                   1179:                LOGERR;
                   1180:                AIT_FREE_VAL(&c->cli_buf);
1.14      misho    1181:                array_Del(srv->srv_blob.clients, i, 42);
1.10      misho    1182:                goto end;
1.12      misho    1183:        } else {
                   1184: #ifdef TCP_NOPUSH
                   1185:                setsockopt(c->cli_sock, IPPROTO_TCP, TCP_NOPUSH, &n, sizeof n);
                   1186: #endif
1.10      misho    1187:                fcntl(c->cli_sock, F_SETFL, fcntl(c->cli_sock, F_GETFL) | O_NONBLOCK);
1.12      misho    1188:        }
1.2       misho    1189: 
1.10      misho    1190:        schedRead(TASK_ROOT(task), rxBLOB, c, c->cli_sock, NULL, 0);
                   1191: end:
                   1192:        schedReadSelf(task);
1.7       misho    1193:        return NULL;
1.1       misho    1194: }
                   1195: 
1.10      misho    1196: /* ------------------------------------------------------ */
1.1       misho    1197: 
                   1198: /*
1.7       misho    1199:  * rpc_srv_initBLOBServer() - Init & create BLOB Server
                   1200:  *
1.4       misho    1201:  * @srv = RPC server instance
1.2       misho    1202:  * @Port = Port for bind server, if Port == 0 default port is selected
                   1203:  * @diskDir = Disk place for BLOB file objects
                   1204:  * return: -1 == error or 0 bind and created BLOB server instance
                   1205:  */
                   1206: int
                   1207: rpc_srv_initBLOBServer(rpc_srv_t * __restrict srv, u_short Port, const char *diskDir)
                   1208: {
                   1209:        int n = 1;
                   1210: 
1.10      misho    1211:        if (!srv || srv->srv_kill) {
1.7       misho    1212:                rpc_SetErr(EINVAL, "Invalid parameters can`t init BLOB server");
1.2       misho    1213:                return -1;
                   1214:        }
                   1215: 
                   1216:        memset(&srv->srv_blob, 0, sizeof srv->srv_blob);
                   1217:        if (access(diskDir, R_OK | W_OK) == -1) {
                   1218:                LOGERR;
                   1219:                return -1;
                   1220:        } else
1.7       misho    1221:                AIT_SET_STR(&srv->srv_blob.dir, diskDir);
1.2       misho    1222: 
1.10      misho    1223:        /* init blob list */
                   1224:        TAILQ_INIT(&srv->srv_blob.blobs);
                   1225: 
1.2       misho    1226:        srv->srv_blob.server.cli_parent = srv;
1.4       misho    1227: 
1.14      misho    1228:        memcpy(&srv->srv_blob.server.cli_sa, &srv->srv_server.cli_sa, sizeof(sockaddr_t));
1.10      misho    1229:        switch (srv->srv_blob.server.cli_sa.sa.sa_family) {
1.4       misho    1230:                case AF_INET:
1.10      misho    1231:                        srv->srv_blob.server.cli_sa.sin.sin_port = 
                   1232:                                htons(Port ? Port : ntohs(srv->srv_blob.server.cli_sa.sin.sin_port) + 1);
1.4       misho    1233:                        break;
                   1234:                case AF_INET6:
1.10      misho    1235:                        srv->srv_blob.server.cli_sa.sin6.sin6_port = 
                   1236:                                htons(Port ? Port : ntohs(srv->srv_blob.server.cli_sa.sin6.sin6_port) + 1);
1.4       misho    1237:                        break;
                   1238:                case AF_LOCAL:
1.10      misho    1239:                        strlcat(srv->srv_blob.server.cli_sa.sun.sun_path, ".blob", 
                   1240:                                        sizeof srv->srv_blob.server.cli_sa.sun.sun_path);
1.4       misho    1241:                        break;
                   1242:                default:
1.7       misho    1243:                        AIT_FREE_VAL(&srv->srv_blob.dir);
1.4       misho    1244:                        return -1;
1.2       misho    1245:        }
                   1246: 
1.4       misho    1247:        /* create BLOB server socket */
1.6       misho    1248:        srv->srv_blob.server.cli_sock = socket(srv->srv_server.cli_sa.sa.sa_family, SOCK_STREAM, 0);
1.2       misho    1249:        if (srv->srv_blob.server.cli_sock == -1) {
                   1250:                LOGERR;
1.7       misho    1251:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.2       misho    1252:                return -1;
                   1253:        }
                   1254:        if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
                   1255:                LOGERR;
                   1256:                close(srv->srv_blob.server.cli_sock);
1.7       misho    1257:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.2       misho    1258:                return -1;
                   1259:        }
1.5       misho    1260:        n = srv->srv_netbuf;
                   1261:        if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof n) == -1) {
                   1262:                LOGERR;
                   1263:                close(srv->srv_blob.server.cli_sock);
1.7       misho    1264:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.5       misho    1265:                return -1;
                   1266:        }
                   1267:        if (setsockopt(srv->srv_blob.server.cli_sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof n) == -1) {
                   1268:                LOGERR;
                   1269:                close(srv->srv_blob.server.cli_sock);
1.7       misho    1270:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.5       misho    1271:                return -1;
                   1272:        }
1.6       misho    1273:        if (bind(srv->srv_blob.server.cli_sock, &srv->srv_blob.server.cli_sa.sa, 
                   1274:                                srv->srv_blob.server.cli_sa.sa.sa_len) == -1) {
1.2       misho    1275:                LOGERR;
                   1276:                close(srv->srv_blob.server.cli_sock);
1.7       misho    1277:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.2       misho    1278:                return -1;
1.13      misho    1279:        } else
                   1280:                fcntl(srv->srv_blob.server.cli_sock, F_SETFL, 
                   1281:                                fcntl(srv->srv_blob.server.cli_sock, F_GETFL) | O_NONBLOCK);
                   1282: 
1.2       misho    1283: 
1.10      misho    1284:        /* allocate pool for concurent blob clients */
1.14      misho    1285:        srv->srv_blob.clients = array_Init(array_Size(srv->srv_clients));
1.2       misho    1286:        if (!srv->srv_blob.clients) {
1.14      misho    1287:                rpc_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.2       misho    1288:                close(srv->srv_blob.server.cli_sock);
1.7       misho    1289:                AIT_FREE_VAL(&srv->srv_blob.dir);
1.2       misho    1290:                return -1;
1.10      misho    1291:        }
1.2       misho    1292: 
1.10      misho    1293:        /* init blob scheduler */
                   1294:        srv->srv_blob.root = schedBegin();
                   1295:        if (!srv->srv_blob.root) {
                   1296:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
1.14      misho    1297:                array_Destroy(&srv->srv_blob.clients);
1.10      misho    1298:                close(srv->srv_blob.server.cli_sock);
                   1299:                AIT_FREE_VAL(&srv->srv_blob.dir);
                   1300:                return -1;
                   1301:        }
1.2       misho    1302: 
                   1303:        return 0;
                   1304: }
                   1305: 
                   1306: /*
1.7       misho    1307:  * rpc_srv_endBLOBServer() - Destroy BLOB server, close all opened sockets and free resources
                   1308:  *
1.2       misho    1309:  * @srv = RPC Server instance
                   1310:  * return: none
                   1311:  */
1.16      misho    1312: void
1.2       misho    1313: rpc_srv_endBLOBServer(rpc_srv_t * __restrict srv)
                   1314: {
1.10      misho    1315:        if (!srv)
1.2       misho    1316:                return;
                   1317: 
1.10      misho    1318:        srv->srv_blob.kill = 1;
1.17      misho    1319: 
                   1320:        schedEnd(&srv->srv_blob.root);
1.2       misho    1321: }
                   1322: 
                   1323: /*
1.10      misho    1324:  * rpc_srv_loopBLOBServer() - Execute Main BLOB server loop and wait for clients requests
1.7       misho    1325:  *
1.2       misho    1326:  * @srv = RPC Server instance
                   1327:  * return: -1 error or 0 ok, infinite loop ...
                   1328:  */
                   1329: int
1.10      misho    1330: rpc_srv_loopBLOBServer(rpc_srv_t * __restrict srv)
1.2       misho    1331: {
1.10      misho    1332:        rpc_cli_t *c;
1.2       misho    1333:        register int i;
1.10      misho    1334:        rpc_blob_t *b, *tmp;
                   1335:        struct timespec ts = { RPC_SCHED_POLLING, 0 };
1.2       misho    1336: 
1.10      misho    1337:        if (!srv || srv->srv_kill) {
1.7       misho    1338:                rpc_SetErr(EINVAL, "Invalid parameter can`t start BLOB server");
1.2       misho    1339:                return -1;
                   1340:        }
                   1341: 
1.14      misho    1342:        if (listen(srv->srv_blob.server.cli_sock, array_Size(srv->srv_blob.clients)) == -1) {
1.2       misho    1343:                LOGERR;
                   1344:                return -1;
1.10      misho    1345:        }
                   1346: 
1.23      misho    1347:        if (!schedSignal(srv->srv_blob.root, flushBLOB, srv, SIGFBLOB, NULL, 0)) {
                   1348:                /* disabled kqueue support in libaitsched */
                   1349:                struct sigaction sa;
                   1350: 
                   1351:                atomic_store_rel_ptr(&_glSigArg, (uintptr_t) srv);
                   1352: 
                   1353:                memset(&sa, 0, sizeof sa);
                   1354:                sigemptyset(&sa.sa_mask);
                   1355:                sa.sa_handler = (void (*)(int)) flushBLOB;
                   1356:                sa.sa_flags = SA_RESTART | SA_RESETHAND;
                   1357:                sigaction(SIGFBLOB, &sa, NULL);
                   1358:        }
                   1359: 
1.10      misho    1360:        if (!schedRead(srv->srv_blob.root, acceptBLOBClients, srv, 
                   1361:                                srv->srv_blob.server.cli_sock, NULL, 0)) {
                   1362:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
                   1363:                return -1;
                   1364:        }
1.2       misho    1365: 
1.10      misho    1366:        schedPolling(srv->srv_blob.root, &ts, NULL);
                   1367:        /* main rpc loop */
                   1368:        schedRun(srv->srv_blob.root, &srv->srv_blob.kill);
1.7       misho    1369: 
1.17      misho    1370:        /* detach blobs */
                   1371:        TAILQ_FOREACH_SAFE(b, &srv->srv_blob.blobs, blob_node, tmp) {
                   1372:                TAILQ_REMOVE(&srv->srv_blob.blobs, b, blob_node);
                   1373: 
                   1374:                rpc_srv_blobFree(srv, b);
                   1375:                e_free(b);
                   1376:        }
                   1377: 
1.10      misho    1378:        /* close all clients connections & server socket */
1.14      misho    1379:        for (i = 0; i < array_Size(srv->srv_blob.clients); i++) {
                   1380:                c = array(srv->srv_blob.clients, i, rpc_cli_t*);
1.10      misho    1381:                if (c) {
                   1382:                        shutdown(c->cli_sock, SHUT_RDWR);
                   1383:                        close(c->cli_sock);
                   1384: 
                   1385:                        schedCancelby(srv->srv_blob.root, taskMAX, CRITERIA_ARG, c, NULL);
                   1386:                        AIT_FREE_VAL(&c->cli_buf);
1.2       misho    1387:                }
1.14      misho    1388:                array_Del(srv->srv_blob.clients, i, 42);
1.10      misho    1389:        }
1.14      misho    1390:        array_Destroy(&srv->srv_blob.clients);
1.2       misho    1391: 
1.10      misho    1392:        close(srv->srv_blob.server.cli_sock);
1.2       misho    1393: 
1.10      misho    1394:        AIT_FREE_VAL(&srv->srv_blob.dir);
1.2       misho    1395:        return 0;
                   1396: }
                   1397: 
                   1398: 
                   1399: /*
1.7       misho    1400:  * rpc_srv_initServer() - Init & create RPC Server
                   1401:  *
1.15      misho    1402:  * @InstID = Instance for authentication & recognition
1.1       misho    1403:  * @concurentClients = Concurent clients at same time to this server
1.10      misho    1404:  * @netBuf = Network buffer length (min:512 bytes), if =0 == BUFSIZ (also meaning max RPC packet)
1.4       misho    1405:  * @csHost = Host name or address for bind server, if NULL any address
1.1       misho    1406:  * @Port = Port for bind server, if Port == 0 default port is selected
1.13      misho    1407:  * @proto = Protocol, if == 0 choose SOCK_STREAM
1.1       misho    1408:  * return: NULL == error or !=NULL bind and created RPC server instance
                   1409:  */
                   1410: rpc_srv_t *
1.15      misho    1411: rpc_srv_initServer(u_char InstID, int concurentClients, int netBuf, 
                   1412:                const char *csHost, u_short Port, int proto)
1.1       misho    1413: {
1.10      misho    1414:        int n = 1;
1.1       misho    1415:        rpc_srv_t *srv = NULL;
1.14      misho    1416:        sockaddr_t sa = E_SOCKADDR_INIT;
1.1       misho    1417: 
1.24.2.2  misho    1418:        if (!concurentClients || (proto < 0 || proto > SOCK_RAW)) {
1.10      misho    1419:                rpc_SetErr(EINVAL, "Invalid parameters can`t init RPC server");
1.1       misho    1420:                return NULL;
                   1421:        }
1.14      misho    1422:        if (!e_gethostbyname(csHost, Port, &sa))
1.10      misho    1423:                return NULL;
1.1       misho    1424:        if (!Port)
                   1425:                Port = RPC_DEFPORT;
1.13      misho    1426:        if (!proto)
                   1427:                proto = SOCK_STREAM;
1.10      misho    1428:        if (netBuf < RPC_MIN_BUFSIZ)
1.5       misho    1429:                netBuf = BUFSIZ;
1.7       misho    1430:        else
1.14      misho    1431:                netBuf = E_ALIGN(netBuf, 2);    /* align netBuf length */
1.10      misho    1432: 
                   1433: #ifdef HAVE_SRANDOMDEV
                   1434:        srandomdev();
                   1435: #else
                   1436:        time_t tim;
                   1437: 
                   1438:        srandom((time(&tim) ^ getpid()));
                   1439: #endif
1.1       misho    1440: 
1.14      misho    1441:        srv = e_malloc(sizeof(rpc_srv_t));
1.1       misho    1442:        if (!srv) {
                   1443:                LOGERR;
                   1444:                return NULL;
                   1445:        } else
                   1446:                memset(srv, 0, sizeof(rpc_srv_t));
                   1447: 
1.13      misho    1448:        srv->srv_proto = proto;
1.5       misho    1449:        srv->srv_netbuf = netBuf;
1.1       misho    1450:        srv->srv_session.sess_version = RPC_VERSION;
1.15      misho    1451:        srv->srv_session.sess_instance = InstID;
1.1       misho    1452: 
                   1453:        srv->srv_server.cli_parent = srv;
1.10      misho    1454:        memcpy(&srv->srv_server.cli_sa, &sa, sizeof srv->srv_server.cli_sa);
                   1455: 
1.12      misho    1456:        /* init functions */
                   1457:        pthread_mutex_init(&srv->srv_funcs.mtx, NULL);
                   1458:        SLIST_INIT(&srv->srv_funcs);
                   1459:        AVL_INIT(&srv->srv_funcs);
1.10      misho    1460: 
                   1461:        /* init scheduler */
                   1462:        srv->srv_root = schedBegin();
                   1463:        if (!srv->srv_root) {
                   1464:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
1.12      misho    1465:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
1.14      misho    1466:                e_free(srv);
1.10      misho    1467:                return NULL;
                   1468:        }
                   1469: 
                   1470:        /* init pool for clients */
1.14      misho    1471:        srv->srv_clients = array_Init(concurentClients);
1.10      misho    1472:        if (!srv->srv_clients) {
1.14      misho    1473:                rpc_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.10      misho    1474:                schedEnd(&srv->srv_root);
1.12      misho    1475:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
1.14      misho    1476:                e_free(srv);
1.10      misho    1477:                return NULL;
                   1478:        }
1.4       misho    1479: 
                   1480:        /* create server socket */
1.13      misho    1481:        srv->srv_server.cli_sock = socket(srv->srv_server.cli_sa.sa.sa_family, srv->srv_proto, 0);
1.1       misho    1482:        if (srv->srv_server.cli_sock == -1) {
                   1483:                LOGERR;
1.14      misho    1484:                array_Destroy(&srv->srv_clients);
1.10      misho    1485:                schedEnd(&srv->srv_root);
1.12      misho    1486:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
1.14      misho    1487:                e_free(srv);
1.1       misho    1488:                return NULL;
                   1489:        }
                   1490:        if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
                   1491:                LOGERR;
1.10      misho    1492:                goto err;
1.1       misho    1493:        }
1.5       misho    1494:        n = srv->srv_netbuf;
                   1495:        if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof n) == -1) {
                   1496:                LOGERR;
1.10      misho    1497:                goto err;
1.5       misho    1498:        }
                   1499:        if (setsockopt(srv->srv_server.cli_sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof n) == -1) {
                   1500:                LOGERR;
1.10      misho    1501:                goto err;
1.5       misho    1502:        }
1.6       misho    1503:        if (bind(srv->srv_server.cli_sock, &srv->srv_server.cli_sa.sa, 
                   1504:                                srv->srv_server.cli_sa.sa.sa_len) == -1) {
1.1       misho    1505:                LOGERR;
1.10      misho    1506:                goto err;
1.13      misho    1507:        } else
                   1508:                fcntl(srv->srv_server.cli_sock, F_SETFL, 
                   1509:                                fcntl(srv->srv_server.cli_sock, F_GETFL) | O_NONBLOCK);
1.1       misho    1510: 
1.10      misho    1511:        rpc_register_srvPing(srv);
1.8       misho    1512: 
1.1       misho    1513:        return srv;
1.10      misho    1514: err:   /* error condition */
                   1515:        close(srv->srv_server.cli_sock);
1.14      misho    1516:        array_Destroy(&srv->srv_clients);
1.10      misho    1517:        schedEnd(&srv->srv_root);
1.12      misho    1518:        pthread_mutex_destroy(&srv->srv_funcs.mtx);
1.14      misho    1519:        e_free(srv);
1.10      misho    1520:        return NULL;
1.1       misho    1521: }
                   1522: 
                   1523: /*
1.7       misho    1524:  * rpc_srv_endServer() - Destroy RPC server, close all opened sockets and free resources
                   1525:  *
1.6       misho    1526:  * @psrv = RPC Server instance
1.1       misho    1527:  * return: none
                   1528:  */
1.16      misho    1529: void
1.6       misho    1530: rpc_srv_endServer(rpc_srv_t ** __restrict psrv)
1.1       misho    1531: {
1.10      misho    1532:        if (!psrv || !*psrv)
1.1       misho    1533:                return;
                   1534: 
1.10      misho    1535:        /* if send kill to blob server */
1.17      misho    1536:        rpc_srv_endBLOBServer(*psrv);
1.1       misho    1537: 
1.10      misho    1538:        (*psrv)->srv_kill = 1;
                   1539:        sleep(RPC_SCHED_POLLING);
1.2       misho    1540: 
1.17      misho    1541:        schedEnd(&(*psrv)->srv_root);
                   1542: 
1.12      misho    1543:        pthread_mutex_destroy(&(*psrv)->srv_funcs.mtx);
1.14      misho    1544:        e_free(*psrv);
1.6       misho    1545:        *psrv = NULL;
1.1       misho    1546: }
                   1547: 
                   1548: /*
1.7       misho    1549:  * rpc_srv_loopServer() - Execute Main server loop and wait for clients requests
                   1550:  *
1.1       misho    1551:  * @srv = RPC Server instance
                   1552:  * return: -1 error or 0 ok, infinite loop ...
                   1553:  */
                   1554: int
1.5       misho    1555: rpc_srv_loopServer(rpc_srv_t * __restrict srv)
1.1       misho    1556: {
1.10      misho    1557:        rpc_cli_t *c;
1.1       misho    1558:        register int i;
1.12      misho    1559:        rpc_func_t *f;
1.10      misho    1560:        struct timespec ts = { RPC_SCHED_POLLING, 0 };
1.1       misho    1561: 
                   1562:        if (!srv) {
1.10      misho    1563:                rpc_SetErr(EINVAL, "Invalid parameter can`t start RPC server");
1.1       misho    1564:                return -1;
                   1565:        }
                   1566: 
1.13      misho    1567:        if (srv->srv_proto == SOCK_STREAM)
1.14      misho    1568:                if (listen(srv->srv_server.cli_sock, array_Size(srv->srv_clients)) == -1) {
1.13      misho    1569:                        LOGERR;
                   1570:                        return -1;
                   1571:                }
1.1       misho    1572: 
1.13      misho    1573:        if (!schedRead(srv->srv_root, cbProto[srv->srv_proto][CB_ACCEPTCLIENT], srv, 
                   1574:                                srv->srv_server.cli_sock, NULL, 0)) {
1.10      misho    1575:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
                   1576:                return -1;
                   1577:        }
1.7       misho    1578: 
1.10      misho    1579:        schedPolling(srv->srv_root, &ts, NULL);
1.7       misho    1580:        /* main rpc loop */
1.10      misho    1581:        schedRun(srv->srv_root, &srv->srv_kill);
                   1582: 
                   1583:        /* close all clients connections & server socket */
1.14      misho    1584:        for (i = 0; i < array_Size(srv->srv_clients); i++) {
                   1585:                c = array(srv->srv_clients, i, rpc_cli_t*);
1.10      misho    1586:                if (c) {
1.24      misho    1587:                        if (srv->srv_proto == SOCK_STREAM) {
                   1588:                                shutdown(c->cli_sock, SHUT_RDWR);
                   1589:                                close(c->cli_sock);
                   1590:                        }
1.10      misho    1591: 
                   1592:                        schedCancelby(srv->srv_root, taskMAX, CRITERIA_ARG, c, NULL);
1.14      misho    1593:                        ait_freeVars(&RPC_RETVARS(c));
1.10      misho    1594:                        AIT_FREE_VAL(&c->cli_buf);
1.1       misho    1595:                }
1.14      misho    1596:                array_Del(srv->srv_clients, i, 42);
1.10      misho    1597:        }
1.14      misho    1598:        array_Destroy(&srv->srv_clients);
1.2       misho    1599: 
1.24.2.4  misho    1600:        if (srv->srv_proto != SOCK_EXT)
                   1601:                close(srv->srv_server.cli_sock);
1.2       misho    1602: 
1.10      misho    1603:        /* detach exported calls */
1.12      misho    1604:        RPC_FUNCS_LOCK(&srv->srv_funcs);
                   1605:        while ((f = SLIST_FIRST(&srv->srv_funcs))) {
                   1606:                SLIST_REMOVE_HEAD(&srv->srv_funcs, func_next);
1.1       misho    1607: 
1.10      misho    1608:                AIT_FREE_VAL(&f->func_name);
1.14      misho    1609:                e_free(f);
1.1       misho    1610:        }
1.12      misho    1611:        srv->srv_funcs.avlh_root = NULL;
                   1612:        RPC_FUNCS_UNLOCK(&srv->srv_funcs);
1.1       misho    1613: 
                   1614:        return 0;
                   1615: }
                   1616: 
                   1617: 
                   1618: /*
                   1619:  * rpc_srv_execCall() Execute registered call from RPC server
1.7       misho    1620:  *
1.10      misho    1621:  * @cli = RPC client
1.1       misho    1622:  * @rpc = IN RPC call structure
1.10      misho    1623:  * @funcname = Execute RPC function
1.5       misho    1624:  * @args = IN RPC calling arguments from RPC client
1.1       misho    1625:  * return: -1 error, !=-1 ok
                   1626:  */
                   1627: int
1.10      misho    1628: rpc_srv_execCall(rpc_cli_t * __restrict cli, struct tagRPCCall * __restrict rpc, 
                   1629:                ait_val_t funcname, array_t * __restrict args)
1.1       misho    1630: {
                   1631:        rpc_callback_t func;
                   1632: 
1.10      misho    1633:        if (!cli || !rpc || !AIT_ADDR(&funcname)) {
1.7       misho    1634:                rpc_SetErr(EINVAL, "Invalid parameter can`t exec function");
1.1       misho    1635:                return -1;
                   1636:        }
                   1637: 
1.10      misho    1638:        func = AIT_GET_LIKE(&funcname, rpc_callback_t);
                   1639:        return func(cli, rpc, args);
1.1       misho    1640: }
1.24      misho    1641: 
                   1642: 
                   1643: /*
                   1644:  * rpc_srv_initServer2() - Init & create layer2 RPC Server
                   1645:  *
                   1646:  * @InstID = Instance for authentication & recognition
                   1647:  * @concurentClients = Concurent clients at same time to this server
                   1648:  * @netBuf = Network buffer length (min:512 bytes), if =0 == BUFSIZ (also meaning max RPC packet)
                   1649:  * @csIface = Interface name for bind server, if NULL first interface on host
                   1650:  * return: NULL == error or !=NULL bind and created RPC server instance
                   1651:  */
                   1652: rpc_srv_t *
                   1653: rpc_srv_initServer2(u_char InstID, int concurentClients, int netBuf, const char *csIface)
                   1654: {
                   1655:        int n = 1;
                   1656:        rpc_srv_t *srv = NULL;
                   1657:        sockaddr_t sa = E_SOCKADDR_INIT;
                   1658:        char szIface[64], szStr[STRSIZ];
                   1659:        register int i;
                   1660:        struct ifreq ifr;
                   1661:        struct bpf_insn insns[] = {
                   1662:                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
                   1663:                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, RPC_DEFPORT, 0, 1),
                   1664:                BPF_STMT(BPF_RET + BPF_K, -1),
                   1665:                BPF_STMT(BPF_RET + BPF_K, 0),
                   1666:        };
                   1667:        struct bpf_program fcode = { 
                   1668:                .bf_len = sizeof(insns) / sizeof(struct bpf_insn), 
                   1669:                        .bf_insns = insns
                   1670:        };
                   1671: 
                   1672:        if (!concurentClients) {
                   1673:                rpc_SetErr(EINVAL, "Invalid parameters can`t init RPC server");
                   1674:                return NULL;
                   1675:        }
                   1676:        if (!csIface) {
                   1677:                if (e_get1stiface(szIface, sizeof szIface))
                   1678:                        return NULL;
                   1679:        } else
                   1680:                strlcpy(szIface, csIface, sizeof szIface);
                   1681:        if (!e_getifacebyname(szIface, &sa))
                   1682:                return NULL;
                   1683: 
                   1684: #ifdef HAVE_SRANDOMDEV
                   1685:        srandomdev();
                   1686: #else
                   1687:        time_t tim;
                   1688: 
                   1689:        srandom((time(&tim) ^ getpid()));
                   1690: #endif
                   1691: 
                   1692:        srv = e_malloc(sizeof(rpc_srv_t));
                   1693:        if (!srv) {
                   1694:                LOGERR;
                   1695:                return NULL;
                   1696:        } else
                   1697:                memset(srv, 0, sizeof(rpc_srv_t));
                   1698: 
                   1699:        srv->srv_proto = SOCK_BPF;
                   1700:        srv->srv_netbuf = netBuf;
                   1701:        srv->srv_session.sess_version = RPC_VERSION;
                   1702:        srv->srv_session.sess_instance = InstID;
                   1703: 
                   1704:        srv->srv_server.cli_parent = srv;
                   1705:        memcpy(&srv->srv_server.cli_sa, &sa, sizeof srv->srv_server.cli_sa);
                   1706: 
                   1707:        /* init functions */
                   1708:        pthread_mutex_init(&srv->srv_funcs.mtx, NULL);
                   1709:        SLIST_INIT(&srv->srv_funcs);
                   1710:        AVL_INIT(&srv->srv_funcs);
                   1711: 
                   1712:        /* init scheduler */
                   1713:        srv->srv_root = schedBegin();
                   1714:        if (!srv->srv_root) {
                   1715:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
                   1716:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1717:                e_free(srv);
                   1718:                return NULL;
                   1719:        }
                   1720: 
                   1721:        /* init pool for clients */
                   1722:        srv->srv_clients = array_Init(concurentClients);
                   1723:        if (!srv->srv_clients) {
                   1724:                rpc_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                   1725:                schedEnd(&srv->srv_root);
                   1726:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1727:                e_free(srv);
                   1728:                return NULL;
                   1729:        }
                   1730: 
                   1731:        /* create server handler */
                   1732:        for (i = 0; i < 10; i++) {
                   1733:                memset(szStr, 0, sizeof szStr);
                   1734:                snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
                   1735:                srv->srv_server.cli_sock = open(szStr, O_RDWR);
                   1736:                if (srv->srv_server.cli_sock > STDERR_FILENO)
                   1737:                        break;
                   1738:        }
                   1739:        if (srv->srv_server.cli_sock < 3) {
                   1740:                LOGERR;
                   1741:                array_Destroy(&srv->srv_clients);
                   1742:                schedEnd(&srv->srv_root);
                   1743:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1744:                e_free(srv);
                   1745:                return NULL;
                   1746:        }
                   1747: 
                   1748:        if (ioctl(srv->srv_server.cli_sock, BIOCIMMEDIATE, &n) == -1) {
                   1749:                LOGERR;
                   1750:                goto err;
                   1751:        }
                   1752:        if (ioctl(srv->srv_server.cli_sock, BIOCSETF, &fcode) == -1) {
                   1753:                LOGERR;
                   1754:                goto err;
                   1755:        }
                   1756:        n = (netBuf < RPC_MIN_BUFSIZ) ? getpagesize() : E_ALIGN(netBuf, 2);
                   1757:        if (ioctl(srv->srv_server.cli_sock, BIOCSBLEN, &n) == -1) {
                   1758:                LOGERR;
                   1759:                goto err;
                   1760:        } else
                   1761:                srv->srv_netbuf = n;
                   1762: 
                   1763:        memset(&ifr, 0, sizeof ifr);
                   1764:        strlcpy(ifr.ifr_name, szIface, sizeof ifr.ifr_name);
                   1765:        if (ioctl(srv->srv_server.cli_sock, BIOCSETIF, &ifr) == -1) {
                   1766:                LOGERR;
                   1767:                goto err;
                   1768:        } else
                   1769:                fcntl(srv->srv_server.cli_sock, F_SETFL, 
                   1770:                                fcntl(srv->srv_server.cli_sock, F_GETFL) | O_NONBLOCK);
                   1771: 
                   1772:        rpc_register_srvPing(srv);
                   1773: 
                   1774:        return srv;
                   1775: err:   /* error condition */
                   1776:        close(srv->srv_server.cli_sock);
                   1777:        array_Destroy(&srv->srv_clients);
                   1778:        schedEnd(&srv->srv_root);
                   1779:        pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1780:        e_free(srv);
                   1781:        return NULL;
                   1782: }
1.24.2.3  misho    1783: 
                   1784: /*
                   1785:  * rpc_srv_initServerExt() - Init & create pipe RPC Server
                   1786:  *
                   1787:  * @InstID = Instance for authentication & recognition
                   1788:  * @netBuf = Network buffer length (min:512 bytes), if =0 == BUFSIZ (also meaning max RPC packet)
                   1789:  * @fd = File descriptor
                   1790:  * return: NULL == error or !=NULL bind and created RPC server instance
                   1791:  */
                   1792: rpc_srv_t *
                   1793: rpc_srv_initServerExt(u_char InstID, int netBuf, int fd)
                   1794: {
                   1795:        rpc_srv_t *srv = NULL;
                   1796: 
                   1797: #ifdef HAVE_SRANDOMDEV
                   1798:        srandomdev();
                   1799: #else
                   1800:        time_t tim;
                   1801: 
                   1802:        srandom((time(&tim) ^ getpid()));
                   1803: #endif
                   1804: 
                   1805:        srv = e_malloc(sizeof(rpc_srv_t));
                   1806:        if (!srv) {
                   1807:                LOGERR;
                   1808:                return NULL;
                   1809:        } else
                   1810:                memset(srv, 0, sizeof(rpc_srv_t));
                   1811: 
                   1812:        srv->srv_proto = SOCK_EXT;
                   1813:        srv->srv_netbuf = netBuf;
                   1814:        srv->srv_session.sess_version = RPC_VERSION;
                   1815:        srv->srv_session.sess_instance = InstID;
                   1816: 
                   1817:        srv->srv_server.cli_parent = srv;
                   1818:        srv->srv_server.cli_sock = fd;
                   1819: 
                   1820:        /* init functions */
                   1821:        pthread_mutex_init(&srv->srv_funcs.mtx, NULL);
                   1822:        SLIST_INIT(&srv->srv_funcs);
                   1823:        AVL_INIT(&srv->srv_funcs);
                   1824: 
                   1825:        /* init scheduler */
                   1826:        srv->srv_root = schedBegin();
                   1827:        if (!srv->srv_root) {
                   1828:                rpc_SetErr(sched_GetErrno(), "%s", sched_GetError());
                   1829:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1830:                e_free(srv);
                   1831:                return NULL;
                   1832:        }
                   1833: 
                   1834:        /* init pool for clients */
                   1835:        srv->srv_clients = array_Init(1);
                   1836:        if (!srv->srv_clients) {
                   1837:                rpc_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                   1838:                schedEnd(&srv->srv_root);
                   1839:                pthread_mutex_destroy(&srv->srv_funcs.mtx);
                   1840:                e_free(srv);
                   1841:                return NULL;
                   1842:        }
                   1843: 
                   1844:        fcntl(srv->srv_server.cli_sock, F_SETFL, 
                   1845:                        fcntl(srv->srv_server.cli_sock, F_GETFL) | O_NONBLOCK);
                   1846: 
                   1847:        rpc_register_srvPing(srv);
                   1848: 
                   1849:        return srv;
                   1850: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>