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

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

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