Annotation of embedaddon/mpd/src/tcp.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * tcp.c
                      4:  *
                      5:  * Written by Alexander Motin <mav@FreeBSD.org>
                      6:  */
                      7: 
                      8: #include "ppp.h"
                      9: #include "phys.h"
                     10: #include "mbuf.h"
                     11: #include "ngfunc.h"
                     12: #include "tcp.h"
                     13: #include "log.h"
                     14: 
                     15: #include <netgraph/ng_message.h>
                     16: #include <netgraph/ng_socket.h>
                     17: #include <netgraph/ng_async.h>
                     18: #include <netgraph/ng_ksocket.h>
                     19: #include <netgraph.h>
                     20: 
                     21: /*
                     22:  * DEFINITIONS
                     23:  */
                     24: 
                     25: #define TCP_MTU                2048
                     26: #define TCP_MRU                2048
                     27: #define LISTENHOOK             "listen"
                     28: 
                     29: #define TCP_MAXPARENTIFS       256
                     30: 
                     31: struct tcpinfo {
                     32:        /* Configuration */
                     33:        struct  {
                     34:            struct optinfo      options;
                     35:            struct u_addr       self_addr;
                     36:            struct u_range      peer_addr;
                     37:            in_port_t           self_port;
                     38:            in_port_t           peer_port;
                     39:            char                *fqdn_peer_addr; /* FQDN Peer address */
                     40:        } conf;
                     41: 
                     42:        /* State */
                     43:        u_char          incoming;               /* incoming vs. outgoing */
                     44:        struct TcpIf    *If;
                     45:        int             csock;
                     46:        struct u_addr   peer_addr;
                     47:        in_port_t       peer_port;
                     48:        EventRef        ev_connect;
                     49:        ng_ID_t         async_node_id;
                     50:        ng_ID_t         node_id;
                     51: };
                     52: 
                     53: typedef struct tcpinfo *TcpInfo;
                     54: 
                     55: /* Set menu options */
                     56: enum {
                     57:        SET_PEERADDR,
                     58:        SET_SELFADDR,
                     59:        SET_ENABLE,
                     60:        SET_DISABLE
                     61: };
                     62: 
                     63:   /* Binary options */
                     64:   enum {
                     65:     TCP_CONF_RESOLVE_ONCE      /* Only once resolve peer_addr */
                     66:   };
                     67: 
                     68: /*
                     69:  * INTERNAL FUNCTIONS
                     70:  */
                     71: 
                     72: static int     TcpInit(Link l);
                     73: static int     TcpInst(Link l, Link lt);
                     74: static void    TcpOpen(Link l);
                     75: static void    TcpClose(Link l);
                     76: static void    TcpShutdown(Link l);
                     77: static void    TcpStat(Context ctx);
                     78: static int     TcpOriginate(Link l);
                     79: static int     TcpIsSync(Link l);
                     80: static int     TcpSelfAddr(Link l, void *buf, size_t buf_len);
                     81: static int     TcpPeerAddr(Link l, void *buf, size_t buf_len);
                     82: static int     TcpPeerPort(Link l, void *buf, size_t buf_len);
                     83: static int     TcpCallingNum(Link l, void *buf, size_t buf_len);
                     84: static int     TcpCalledNum(Link l, void *buf, size_t buf_len);
                     85: 
                     86: static void    TcpDoClose(Link l);
                     87: static void    TcpAcceptEvent(int type, void *cookie);
                     88: static void    TcpConnectEvent(int type, void *cookie);
                     89: 
                     90: static int     TcpSetCommand(Context ctx, int ac, char *av[], void *arg);
                     91: static void    TcpNodeUpdate(Link l);
                     92: static int     TcpListen(Link l);
                     93: static void    TcpUnListen(Link l);
                     94: 
                     95: /*
                     96:  * GLOBAL VARIABLES
                     97:  */
                     98: 
                     99: const struct phystype gTcpPhysType = {
                    100:        .name           = "tcp",
                    101:        .descr          = "PPP over TCP",
                    102:        .mtu            = TCP_MTU,
                    103:        .mru            = TCP_MRU,
                    104:        .tmpl           = 1,
                    105:        .init           = TcpInit,
                    106:        .inst           = TcpInst,
                    107:        .open           = TcpOpen,
                    108:        .close          = TcpClose,
                    109:        .update         = TcpNodeUpdate,
                    110:        .shutdown       = TcpShutdown,
                    111:        .showstat       = TcpStat,
                    112:        .originate      = TcpOriginate,
                    113:        .issync         = TcpIsSync,
                    114:        .selfaddr       = TcpSelfAddr,
                    115:        .peeraddr       = TcpPeerAddr,
                    116:        .peerport       = TcpPeerPort,
                    117:        .callingnum     = TcpCallingNum,
                    118:        .callednum      = TcpCalledNum,
                    119: };
                    120: 
                    121: const struct cmdtab TcpSetCmds[] = {
                    122:     { "self {ip} [{port}]",            "Set local IP address",
                    123:        TcpSetCommand, NULL, 2, (void *) SET_SELFADDR },
                    124:     { "peer {ip} [{port}]",            "Set remote IP address",
                    125:        TcpSetCommand, NULL, 2, (void *) SET_PEERADDR },
                    126:     { "enable [opt ...]",              "Enable option",
                    127:        TcpSetCommand, NULL, 2, (void *) SET_ENABLE },
                    128:     { "disable [opt ...]",             "Disable option",
                    129:        TcpSetCommand, NULL, 2, (void *) SET_DISABLE },
                    130:     { NULL },
                    131: };
                    132: 
                    133: struct TcpIf {
                    134:     struct u_addr      self_addr;
                    135:     in_port_t  self_port;
                    136:     int                refs;
                    137:     int                csock;                  /* netgraph Control socket */
                    138:     EventRef   ctrlEvent;              /* listen for ctrl messages */
                    139: };
                    140: struct TcpIf TcpIfs[TCP_MAXPARENTIFS];
                    141: 
                    142:  /*
                    143:  * INTERNAL VARIABLES
                    144:  */
                    145: 
                    146:   static struct confinfo       gConfList[] = {
                    147:     { 0,       TCP_CONF_RESOLVE_ONCE,  "resolve-once"  },
                    148:     { 0,       0,                      NULL            },
                    149:   };
                    150: 
                    151: /*
                    152:  * TcpInit()
                    153:  */
                    154: 
                    155: static int
                    156: TcpInit(Link l)
                    157: {
                    158:        TcpInfo pi;
                    159: 
                    160:        pi = (TcpInfo) (l->info = Malloc(MB_PHYS, sizeof(*pi)));
                    161: 
                    162:        u_addrclear(&pi->conf.self_addr);
                    163:        u_rangeclear(&pi->conf.peer_addr);
                    164:        pi->conf.self_port=0;
                    165:        pi->conf.peer_port=0;
                    166: 
                    167:        pi->incoming = 0;
                    168:        pi->If = NULL;
                    169:        pi->csock = -1;
                    170: 
                    171:        u_addrclear(&pi->peer_addr);
                    172:        pi->peer_port=0;
                    173:        pi->conf.fqdn_peer_addr = NULL;
                    174:        Enable(&pi->conf.options, TCP_CONF_RESOLVE_ONCE);
                    175: 
                    176:        return (0);
                    177: }
                    178: 
                    179: /*
                    180:  * TcpInst()
                    181:  */
                    182: 
                    183: static int
                    184: TcpInst(Link l, Link lt)
                    185: {
                    186:        TcpInfo pi;
                    187:        TcpInfo const pit = (TcpInfo) lt->info;
                    188: 
                    189:        /* Initialize this link */
                    190:        pi = (TcpInfo) (l->info = Mdup(MB_PHYS, lt->info, sizeof(*pi)));
                    191:        if (pit->conf.fqdn_peer_addr != NULL)
                    192:            pi->conf.fqdn_peer_addr =
                    193:                Mstrdup(MB_PHYS, pit->conf.fqdn_peer_addr);
                    194:     
                    195:        if (pi->If)
                    196:            pi->If->refs++;
                    197: 
                    198:        return (0);
                    199: }
                    200: 
                    201: /*
                    202:  * TcpOpen()
                    203:  */
                    204: 
                    205: static void
                    206: TcpOpen(Link l)
                    207: {
                    208:        TcpInfo const           pi = (TcpInfo) l->info;
                    209:        struct ngm_mkpeer       mkp;
                    210:        struct ngm_connect      cn;
                    211:        struct ngm_name         nm;
                    212:        char                    path[NG_PATHSIZ];
                    213:        char                    hook[NG_HOOKSIZ];
                    214:        struct sockaddr_storage addr;
                    215:        struct ng_async_cfg     acfg;
                    216:        int                     rval;
                    217:        char                    buf[48];
                    218: 
                    219:        /* Create a new netgraph node to control TCP ksocket node. */
                    220:        if (NgMkSockNode(NULL, &pi->csock, NULL) < 0) {
                    221:                Perror("[%s] TCP can't create control socket", l->name);
                    222:                goto fail;
                    223:        }
                    224:        (void)fcntl(pi->csock, F_SETFD, 1);
                    225: 
                    226:         if (!PhysGetUpperHook(l, path, hook)) {
                    227:                Log(LG_PHYS, ("[%s] TCP: can't get upper hook", l->name));
                    228:                goto fail;
                    229:         }
                    230:     
                    231:        strcpy(mkp.type, NG_ASYNC_NODE_TYPE);
                    232:        strlcpy(mkp.ourhook, hook, sizeof(mkp.ourhook));
                    233:        strcpy(mkp.peerhook, NG_ASYNC_HOOK_SYNC);
                    234:        if (NgSendMsg(pi->csock, path, NGM_GENERIC_COOKIE,
                    235:            NGM_MKPEER, &mkp, sizeof(mkp)) < 0) {
                    236:                Perror("[%s] can't attach %s %s node",
                    237:                    l->name, NG_ASYNC_NODE_TYPE, mkp.ourhook);
                    238:                goto fail;
                    239:        }
                    240:        
                    241:        strlcat(path, ".", sizeof(path));
                    242:        strlcat(path, hook, sizeof(path));
                    243:        
                    244:        /* Give it a name */
                    245:        snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-as", gPid, l->name);
                    246:        if (NgSendMsg(pi->csock, path,
                    247:            NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
                    248:                Perror("[%s] can't name %s node", l->name, NG_ASYNC_NODE_TYPE);
                    249:        }
                    250: 
                    251:        /* Get async node ID */
                    252:        if ((pi->async_node_id = NgGetNodeID(pi->csock, path)) == 0) {
                    253:            Perror("[%s] Cannot get %s node id", l->name, NG_ASYNC_NODE_TYPE);
                    254:            goto fail;
                    255:        };
                    256: 
                    257:        /* Configure the async converter node. */
                    258:        memset(&acfg, 0, sizeof(acfg));
                    259:        acfg.enabled = TRUE;
                    260:        acfg.accm = 0;  /* we do not need thie on TCP */
                    261:        acfg.amru = TCP_MRU;
                    262:        acfg.smru = TCP_MTU;
                    263:        if (NgSendMsg(pi->csock, path, NGM_ASYNC_COOKIE,
                    264:            NGM_ASYNC_CMD_SET_CONFIG, &acfg, sizeof(acfg)) < 0) {
                    265:                Log(LG_ERR, ("[%s] can't config %s", l->name, path));
                    266:                goto fail;
                    267:        }
                    268: 
                    269:        if (pi->incoming) {
                    270:                Log(LG_PHYS2, ("[%s] %s() on incoming call", l->name,
                    271:                    __func__));
                    272: 
                    273:                /* Connect new born ksocket to our link. */
                    274:                snprintf(cn.path, sizeof(cn.path), "[%x]:", pi->node_id);
                    275:                snprintf(cn.ourhook, sizeof(cn.ourhook), NG_ASYNC_HOOK_ASYNC);
                    276:                snprintf(cn.peerhook, sizeof(cn.peerhook), "data");
                    277:                if (NgSendMsg(pi->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
                    278:                    &cn, sizeof(cn)) < 0) {
                    279:                        Perror("[%s] can't connect new born ksocket", l->name);
                    280:                        goto fail;
                    281:                }
                    282: 
                    283:                l->state = PHYS_STATE_UP;
                    284:                PhysUp(l);
                    285:                return;
                    286:        }
                    287:        if ((!Enabled(&pi->conf.options, TCP_CONF_RESOLVE_ONCE)) &&
                    288:            (pi->conf.fqdn_peer_addr != NULL)) {
                    289:            struct u_range      rng;
                    290:            if (ParseRange(pi->conf.fqdn_peer_addr, &rng, ALLOW_IPV4|ALLOW_IPV6))
                    291:                pi->conf.peer_addr = rng;
                    292:        }
                    293: 
                    294:        u_addrcopy(&pi->conf.peer_addr.addr,&pi->peer_addr);
                    295:        pi->peer_port = pi->conf.peer_port;
                    296: 
                    297:        /*
                    298:         * Attach fresh ksocket node next to async node.
                    299:         */
                    300:        strcpy(mkp.type, NG_KSOCKET_NODE_TYPE);
                    301:        strcpy(mkp.ourhook, NG_ASYNC_HOOK_ASYNC);
                    302:        if ((pi->conf.self_addr.family==AF_INET6) || 
                    303:            (pi->conf.self_addr.family==AF_UNSPEC && pi->conf.peer_addr.addr.family==AF_INET6)) {
                    304:            snprintf(mkp.peerhook, sizeof(mkp.peerhook), "%d/%d/%d", PF_INET6, SOCK_STREAM, IPPROTO_TCP);
                    305:        } else {
                    306:            snprintf(mkp.peerhook, sizeof(mkp.peerhook), "inet/stream/tcp");
                    307:        }
                    308:        if (NgSendMsg(pi->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mkp,
                    309:            sizeof(mkp)) < 0) {
                    310:                Perror("[%s] can't attach %s node", l->name, NG_KSOCKET_NODE_TYPE);
                    311:                goto fail;
                    312:        }
                    313: 
                    314:        strlcat(path, ".", sizeof(path));
                    315:        strlcat(path, NG_ASYNC_HOOK_ASYNC, sizeof(path));
                    316: 
                    317:        /* Give it a name */
                    318:        snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-kso", gPid, l->name);
                    319:        if (NgSendMsg(pi->csock, path,
                    320:            NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
                    321:                Perror("[%s] can't name %s node", l->name, NG_KSOCKET_NODE_TYPE);
                    322:        }
                    323: 
                    324:        /* Start connecting to peer. */
                    325:        u_addrtosockaddr(&pi->peer_addr, pi->peer_port, &addr);
                    326:        rval = NgSendMsg(pi->csock, path, NGM_KSOCKET_COOKIE,
                    327:            NGM_KSOCKET_CONNECT, &addr, addr.ss_len);
                    328:        if (rval < 0 && errno != EINPROGRESS) {
                    329:                Perror("[%s] can't connect() %s node", l->name,
                    330:                    NG_KSOCKET_NODE_TYPE);
                    331:                goto fail;
                    332:        }
                    333: 
                    334:        l->state = PHYS_STATE_CONNECTING;
                    335: 
                    336:        if (rval == 0)  /* Can happen when peer is local. */
                    337:                TcpConnectEvent(EVENT_READ, l);
                    338:        else {
                    339:                assert(errno == EINPROGRESS);
                    340:                EventRegister(&pi->ev_connect, EVENT_READ, pi->csock,
                    341:                    0, TcpConnectEvent, l);
                    342:                Log(LG_PHYS, ("[%s] connecting to %s %u", l->name,
                    343:                    u_addrtoa(&pi->conf.peer_addr.addr, buf, sizeof(buf)), pi->conf.peer_port));
                    344:        }
                    345: 
                    346:        return;
                    347: fail:
                    348:        l->state = PHYS_STATE_DOWN;
                    349:        TcpDoClose(l);
                    350:        PhysDown(l, STR_ERROR, NULL);
                    351: }
                    352: 
                    353: /*
                    354:  * TcpConnectEvent() triggers when outgoing connection succeeds/fails.
                    355:  */
                    356: 
                    357: static void
                    358: TcpConnectEvent(int type, void *cookie)
                    359: {
                    360:        struct {
                    361:                struct ng_mesg  resp;
                    362:                int32_t         rval;
                    363:        } cn;
                    364:        Link            l;
                    365:        TcpInfo         pi;
                    366:        char path[NG_PATHSIZ];
                    367: 
                    368:        /* Restore context. */
                    369:        l = (Link)cookie;
                    370:        pi = (TcpInfo)l->info;
                    371: 
                    372:        assert(type == EVENT_READ);
                    373: 
                    374:        /* Check whether the connection was successful or not. */
                    375:        if (NgRecvMsg(pi->csock, &cn.resp, sizeof(cn), path) < 0) {
                    376:                Perror("[%s] error reading message from \"%s\"", l->name, path);
                    377:                goto failed;
                    378:        }
                    379: 
                    380:        assert(cn.resp.header.typecookie == NGM_KSOCKET_COOKIE);
                    381:        assert(cn.resp.header.cmd == NGM_KSOCKET_CONNECT);
                    382: 
                    383:        if (cn.rval != 0) {
                    384:                Log(LG_PHYS, ("[%s] failed to connect: %s", l->name,
                    385:                    strerror(cn.rval)));
                    386:                goto failed;
                    387:        }
                    388: 
                    389:        /* Report connected. */
                    390:        Log(LG_PHYS, ("[%s] connection established", l->name));
                    391: 
                    392:        l->state = PHYS_STATE_UP;
                    393:        PhysUp(l);
                    394: 
                    395:        return;
                    396: failed:
                    397:        l->state = PHYS_STATE_DOWN;
                    398:        TcpDoClose(l);
                    399:        PhysDown(l, STR_ERROR, NULL);
                    400: 
                    401: }
                    402: 
                    403: /*
                    404:  * TcpAcceptEvent() triggers when we accept incoming connection.
                    405:  */
                    406: static void
                    407: TcpAcceptEvent(int type, void *cookie)
                    408: {
                    409:        struct {
                    410:                struct ng_mesg  resp;
                    411:                uint32_t        id;
                    412:                struct sockaddr_storage sin;
                    413:        } ac;
                    414:        struct ngm_name         nm;
                    415:        char path[NG_PATHSIZ];
                    416:        struct u_addr   addr;
                    417:        in_port_t       port;
                    418:        char            buf[48];
                    419:        int             k;
                    420:        struct TcpIf    *If=(struct TcpIf *)(cookie);
                    421:        Link            l = NULL;
                    422:        TcpInfo         pi = NULL;
                    423: 
                    424:        assert(type == EVENT_READ);
                    425: 
                    426:        /* Accept cloned ng_ksocket(4). */
                    427:        if (NgRecvMsg(If->csock, &ac.resp, sizeof(ac), NULL) < 0) {
                    428:                Perror("TCP: error reading message from \"%s\"", path);
                    429:                goto failed;
                    430:        }
                    431:        sockaddrtou_addr(&ac.sin, &addr, &port);
                    432: 
                    433:        Log(LG_PHYS, ("Incoming TCP connection from %s %u",
                    434:            u_addrtoa(&addr, buf, sizeof(buf)), port));
                    435: 
                    436:        if (gShutdownInProgress) {
                    437:                Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
                    438:                return;
                    439:        }
                    440: 
                    441:        if (OVERLOAD()) {
                    442:                Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
                    443:                return;
                    444:        }
                    445: 
                    446:        /* Examine all TCP links. */
                    447:        for (k = 0; k < gNumLinks; k++) {
                    448:                Link l2;
                    449:                TcpInfo pi2;
                    450: 
                    451:                if (!gLinks[k] || gLinks[k]->type != &gTcpPhysType)
                    452:                        continue;
                    453: 
                    454:                l2 = gLinks[k];
                    455:                pi2 = (TcpInfo)l2->info;
                    456: 
                    457:                if ((!PhysIsBusy(l2)) &&
                    458:                    Enabled(&l2->conf.options, LINK_CONF_INCOMING) &&
                    459:                    (pi2->If == If) &&
                    460:                    IpAddrInRange(&pi2->conf.peer_addr, &addr) &&
                    461:                    (pi2->conf.peer_port == 0 || pi2->conf.peer_port == port)) {
                    462: 
                    463:                        if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
                    464:                                l = l2;
                    465:                                pi = pi2;
                    466:                                if (u_rangehost(&pi->conf.peer_addr)) {
                    467:                                        break;  /* Nothing could be better */
                    468:                                }
                    469:                        }
                    470:                }
                    471:        }
                    472:        if (l != NULL && l->tmpl)
                    473:                l = LinkInst(l, NULL, 0, 0);
                    474: 
                    475:        if (l != NULL) {
                    476:                pi = (TcpInfo)l->info;
                    477:                Log(LG_PHYS, ("[%s] Accepting TCP connection from %s %u",
                    478:                    l->name, u_addrtoa(&addr, buf, sizeof(buf)), port));
                    479: 
                    480:                sockaddrtou_addr(&ac.sin, &pi->peer_addr, &pi->peer_port);
                    481: 
                    482:                pi->node_id = ac.id;
                    483: 
                    484:                /* Give it a name */
                    485:                snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", gPid, l->name);
                    486:                snprintf(path, sizeof(path), "[%x]:", ac.id);
                    487:                if (NgSendMsg(If->csock, path,
                    488:                    NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
                    489:                        Perror("[%s] can't name %s node",
                    490:                            l->name, NG_KSOCKET_NODE_TYPE);
                    491:                }
                    492: 
                    493:                pi->incoming=1;
                    494:                l->state = PHYS_STATE_READY;
                    495: 
                    496:                PhysIncoming(l);
                    497:        } else {
                    498:            Log(LG_PHYS, ("No free TCP link with requested parameters "
                    499:                "was found"));
                    500:            snprintf(path, sizeof(path), "[%x]:", ac.id);
                    501:            NgFuncShutdownNode(If->csock, "", path);
                    502:        }
                    503: 
                    504: failed:
                    505:        /* Tell that we are willing to receive accept message. */
                    506:        if (NgSendMsg(If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
                    507:            NGM_KSOCKET_ACCEPT, NULL, 0) < 0) {
                    508:                Perror("TCP: can't accept on %s node", NG_KSOCKET_NODE_TYPE);
                    509:        }
                    510:        EventRegister(&If->ctrlEvent, EVENT_READ, If->csock,
                    511:            0, TcpAcceptEvent, If);
                    512: }
                    513: 
                    514: /*
                    515:  * TcpClose()
                    516:  */
                    517: 
                    518: static void
                    519: TcpClose(Link l)
                    520: {
                    521:        TcpInfo const pi = (TcpInfo) l->info;
                    522: 
                    523:        TcpDoClose(l);
                    524: 
                    525:        if (l->state != PHYS_STATE_DOWN) {
                    526:            pi->incoming=0;
                    527:            l->state = PHYS_STATE_DOWN;
                    528: 
                    529:            u_addrclear(&pi->peer_addr);
                    530:            pi->peer_port=0;
                    531: 
                    532:            PhysDown(l, STR_MANUALLY, NULL);
                    533:        }
                    534: }
                    535: 
                    536: /*
                    537:  * TcpShutdown()
                    538:  */
                    539: 
                    540: static void
                    541: TcpShutdown(Link l)
                    542: {
                    543:     TcpInfo const pi = (TcpInfo) l->info;
                    544: 
                    545:     if (pi->conf.fqdn_peer_addr)
                    546:         Freee(pi->conf.fqdn_peer_addr);
                    547: 
                    548:        TcpDoClose(l);
                    549:        TcpUnListen(l);
                    550:        Freee(l->info);
                    551: }
                    552: 
                    553: /*
                    554:  * TcpDoClose()
                    555:  */
                    556: 
                    557: static void
                    558: TcpDoClose(Link l)
                    559: {
                    560:        char path[NG_PATHSIZ];
                    561:        TcpInfo const pi = (TcpInfo) l->info;
                    562: 
                    563:        EventUnRegister(&pi->ev_connect);
                    564: 
                    565:        if (pi->csock<=0) {
                    566:            return;
                    567:        };
                    568: 
                    569:        if (pi->node_id != 0) {
                    570:            snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->node_id);
                    571:            NgFuncShutdownNode(pi->csock, l->name, path);
                    572:            pi->node_id = 0;
                    573:        }
                    574:        
                    575:        if (pi->async_node_id != 0) {
                    576:            snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->async_node_id);
                    577:            NgFuncShutdownNode(pi->csock, l->name, path);
                    578:            pi->async_node_id = 0;
                    579:        }
                    580:        
                    581:        close(pi->csock);
                    582:        pi->csock = -1;
                    583:        pi->node_id = 0;
                    584: }
                    585: 
                    586: /*
                    587:  * TcpOriginate()
                    588:  */
                    589: 
                    590: static int
                    591: TcpOriginate(Link l)
                    592: {
                    593:        TcpInfo const pi = (TcpInfo) l->info;
                    594: 
                    595:        return (pi->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
                    596: }
                    597: 
                    598: /*
                    599:  * TcpIsSync()
                    600:  */
                    601: 
                    602: static int
                    603: TcpIsSync(Link l)
                    604: {
                    605:        return (1);
                    606: }
                    607: 
                    608: static int
                    609: TcpSelfAddr(Link l, void *buf, size_t buf_len)
                    610: {
                    611:     TcpInfo const pi = (TcpInfo) l->info;
                    612: 
                    613:     if (!u_addrempty(&pi->conf.self_addr)) {
                    614:        if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
                    615:            return (0);
                    616:        else {
                    617:            ((char*)buf)[0]=0;
                    618:            return (-1);
                    619:        }
                    620:     }
                    621:     ((char*)buf)[0]=0;
                    622:     return (0);
                    623: }
                    624: 
                    625: static int
                    626: TcpPeerAddr(Link l, void *buf, size_t buf_len)
                    627: {
                    628:        TcpInfo const pi = (TcpInfo) l->info;
                    629: 
                    630:        if (u_addrtoa(&pi->peer_addr, buf, buf_len))
                    631:                return (0);
                    632:        else
                    633:                return (-1);
                    634: }
                    635: 
                    636: static int
                    637: TcpPeerPort(Link l, void *buf, size_t buf_len)
                    638: {
                    639:        TcpInfo const pi = (TcpInfo) l->info;
                    640: 
                    641:        if (snprintf( buf, buf_len, "%u", pi->peer_port))
                    642:                return (0);
                    643:        else
                    644:                return (-1);
                    645: }
                    646: 
                    647: static int
                    648: TcpCallingNum(Link l, void *buf, size_t buf_len)
                    649: {
                    650:        TcpInfo const pi = (TcpInfo) l->info;
                    651: 
                    652:        if (pi->incoming) {
                    653:            if (u_addrtoa(&pi->peer_addr, buf, buf_len))
                    654:                return (0);
                    655:            else
                    656:                return (-1);
                    657:        } else {
                    658:            if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
                    659:                return (0);
                    660:            else
                    661:                return (-1);
                    662:        }
                    663: }
                    664: 
                    665: static int
                    666: TcpCalledNum(Link l, void *buf, size_t buf_len)
                    667: {
                    668:        TcpInfo const pi = (TcpInfo) l->info;
                    669: 
                    670:        if (!pi->incoming) {
                    671:            if (u_addrtoa(&pi->peer_addr, buf, buf_len))
                    672:                return (0);
                    673:            else
                    674:                return (-1);
                    675:        } else {
                    676:            if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
                    677:                return (0);
                    678:            else
                    679:                return (-1);
                    680:        }
                    681: }
                    682: 
                    683: /*
                    684:  * TcpStat()
                    685:  */
                    686: 
                    687: void
                    688: TcpStat(Context ctx)
                    689: {
                    690:        TcpInfo const pi = (TcpInfo) ctx->lnk->info;
                    691:        char    buf[48];
                    692: 
                    693:        Printf("TCP configuration:\r\n");
                    694:        Printf("\tPeer FQDN    : %s\r\n", pi->conf.fqdn_peer_addr);
                    695:        Printf("\tSelf address : %s, port %u\r\n",
                    696:            u_addrtoa(&pi->conf.self_addr, buf, sizeof(buf)), pi->conf.self_port);
                    697:        Printf("\tPeer address : %s, port %u\r\n",
                    698:            u_rangetoa(&pi->conf.peer_addr, buf, sizeof(buf)), pi->conf.peer_port);
                    699:        Printf("TCP state:\r\n");
                    700:        if (ctx->lnk->state != PHYS_STATE_DOWN) {
                    701:            Printf("\tIncoming     : %s\r\n", (pi->incoming?"YES":"NO"));
                    702:            Printf("\tCurrent peer : %s, port %u\r\n",
                    703:                u_addrtoa(&pi->peer_addr, buf, sizeof(buf)), pi->peer_port);
                    704:        }
                    705: }
                    706: 
                    707: static int 
                    708: TcpListen(Link l)
                    709: {
                    710:        TcpInfo const pi = (TcpInfo) l->info;
                    711:        struct ngm_mkpeer mkp;
                    712:        struct sockaddr_storage addr;
                    713:        int32_t backlog = 1;
                    714:        char buf[48];
                    715:        union {
                    716:            u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
                    717:            struct ng_ksocket_sockopt ksso;
                    718:        } u;
                    719:        struct ng_ksocket_sockopt *const ksso = &u.ksso;
                    720:        int i, j = -1, free = -1;
                    721:        
                    722:        if (pi->If)
                    723:            return(1);
                    724: 
                    725:        for (i = 0; i < TCP_MAXPARENTIFS; i++) {
                    726:            if (TcpIfs[i].self_port == 0)
                    727:                free = i;
                    728:            else if ((u_addrcompare(&TcpIfs[i].self_addr, &pi->conf.self_addr) == 0) &&
                    729:                (TcpIfs[i].self_port == pi->conf.self_port)) {
                    730:                    j = i;
                    731:                    break;
                    732:            }
                    733:        }
                    734: 
                    735:        if (j >= 0) {
                    736:            TcpIfs[j].refs++;
                    737:            pi->If=&TcpIfs[j];
                    738:            return(1);
                    739:        }
                    740: 
                    741:        if (free < 0) {
                    742:            Log(LG_ERR, ("[%s] TCP: Too many different listening ports! ", 
                    743:                l->name));
                    744:            return (0);
                    745:        }
                    746: 
                    747:        TcpIfs[free].refs = 1;
                    748:        pi->If=&TcpIfs[free];
                    749:        
                    750:        u_addrcopy(&pi->conf.self_addr,&pi->If->self_addr);
                    751:        pi->If->self_port=pi->conf.self_port;
                    752:        
                    753:        /* Create a new netgraph node */
                    754:        if (NgMkSockNode(NULL, &pi->If->csock, NULL) < 0) {
                    755:            Perror("TCP: can't create ctrl socket");
                    756:            return(0);
                    757:        }
                    758:        (void)fcntl(pi->If->csock, F_SETFD, 1);
                    759: 
                    760:        /* Make listening TCP ksocket node. */
                    761:        strcpy(mkp.type, NG_KSOCKET_NODE_TYPE);
                    762:        strcpy(mkp.ourhook, LISTENHOOK);
                    763:        if (pi->If->self_addr.family==AF_INET6) {
                    764:            snprintf(mkp.peerhook, sizeof(mkp.peerhook), "%d/%d/%d", PF_INET6, SOCK_STREAM, IPPROTO_TCP);
                    765:        } else {
                    766:            snprintf(mkp.peerhook, sizeof(mkp.peerhook), "inet/stream/tcp");
                    767:        }
                    768:        if (NgSendMsg(pi->If->csock, ".:", NGM_GENERIC_COOKIE, NGM_MKPEER,
                    769:            &mkp, sizeof(mkp)) < 0) {
                    770:                Perror("TCP: can't attach %s node", NG_KSOCKET_NODE_TYPE);
                    771:                goto fail2;
                    772:        }
                    773: 
                    774:        /* Setsockopt socket. */
                    775:        ksso->level=SOL_SOCKET;
                    776:        ksso->name=SO_REUSEPORT;
                    777:        ((int *)(ksso->value))[0]=1;
                    778:        if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
                    779:            NGM_KSOCKET_SETOPT, &u, sizeof(u)) < 0) {
                    780:                Perror("TCP: can't setsockopt() %s node", NG_KSOCKET_NODE_TYPE);
                    781:                goto fail2;
                    782:        }
                    783: 
                    784:        /* Bind socket. */
                    785:        u_addrtosockaddr(&pi->If->self_addr, pi->If->self_port, &addr);
                    786:        if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
                    787:            NGM_KSOCKET_BIND, &addr, addr.ss_len) < 0) {
                    788:                Perror("TCP: can't bind() %s node", NG_KSOCKET_NODE_TYPE);
                    789:                goto fail2;
                    790:        }
                    791: 
                    792:        /* Listen. */
                    793:        if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
                    794:            NGM_KSOCKET_LISTEN, &backlog, sizeof(backlog)) < 0) {
                    795:                Perror("TCP: can't listen() on %s node", NG_KSOCKET_NODE_TYPE);
                    796:                goto fail2;
                    797:        }
                    798: 
                    799:        /* Tell that we are willing to receive accept message. */
                    800:        if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
                    801:            NGM_KSOCKET_ACCEPT, NULL, 0) < 0) {
                    802:                Perror("TCP: can't accept() on %s node", NG_KSOCKET_NODE_TYPE);
                    803:                goto fail2;
                    804:        }
                    805: 
                    806:        Log(LG_PHYS, ("TCP: waiting for connection on %s %u",
                    807:            u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
                    808:        EventRegister(&pi->If->ctrlEvent, EVENT_READ, pi->If->csock,
                    809:            0, TcpAcceptEvent, pi->If);
                    810: 
                    811:        return (1);
                    812: fail2:
                    813:        NgSendMsg(pi->If->csock, LISTENHOOK, NGM_GENERIC_COOKIE, NGM_SHUTDOWN,
                    814:            NULL, 0);
                    815:        return (0);
                    816: }
                    817: 
                    818: static void
                    819: TcpUnListen(Link l)
                    820: {
                    821:        TcpInfo const pi = (TcpInfo) l->info;
                    822:        char buf[48];
                    823:        
                    824:        if (!pi->If)
                    825:            return;
                    826: 
                    827:        pi->If->refs--;
                    828:        if (pi->If->refs == 0) {
                    829:            Log(LG_PHYS, ("TCP: stop waiting for connection on %s %u",
                    830:                u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
                    831:            EventUnRegister(&pi->If->ctrlEvent);
                    832:            close(pi->If->csock);
                    833:            pi->If->csock = -1;
                    834:            pi->If->self_port = 0;
                    835:            pi->If = NULL;
                    836:        }
                    837: }
                    838: 
                    839: /*
                    840:  * TcpNodeUpdate()
                    841:  */
                    842: 
                    843: static void
                    844: TcpNodeUpdate(Link l)
                    845: {
                    846:     TcpInfo const pi = (TcpInfo) l->info;
                    847:     if (!pi->If) {
                    848:        if (Enabled(&l->conf.options, LINK_CONF_INCOMING))
                    849:            TcpListen(l);
                    850:     } else {
                    851:        if (!Enabled(&l->conf.options, LINK_CONF_INCOMING))
                    852:            TcpUnListen(l);
                    853:     }
                    854: }
                    855: 
                    856: /*
                    857:  * TcpSetCommand()
                    858:  */
                    859: 
                    860: static int
                    861: TcpSetCommand(Context ctx, int ac, char *av[], void *arg)
                    862: {
                    863:     TcpInfo            const pi = (TcpInfo) ctx->lnk->info;
                    864:     char               **fqdn_peer_addr = &pi->conf.fqdn_peer_addr;
                    865:     struct u_range     rng;
                    866:     int                        port;
                    867: 
                    868:     switch ((intptr_t)arg) {
                    869:        case SET_PEERADDR:
                    870:        case SET_SELFADDR:
                    871:            if ((ac == 1 || ac == 2) && (intptr_t)arg == SET_PEERADDR) {
                    872:                if (*fqdn_peer_addr)
                    873:                    Freee(*fqdn_peer_addr);
                    874:                *fqdn_peer_addr = Mstrdup(MB_PHYS, av[0]);
                    875:            }
                    876:            if (ac < 1 || ac > 2 || !ParseRange(av[0], &rng, ALLOW_IPV4|ALLOW_IPV6))
                    877:                return(-1);
                    878:            if (ac > 1) {
                    879:                if ((port = atoi(av[1])) < 0 || port > 0xffff)
                    880:                    return(-1);
                    881:            } else {
                    882:                port = 0;
                    883:            }
                    884:            if ((intptr_t)arg == SET_SELFADDR) {
                    885:                pi->conf.self_addr = rng.addr;
                    886:                pi->conf.self_port = port;
                    887:            } else {
                    888:                pi->conf.peer_addr = rng;
                    889:                pi->conf.peer_port = port;
                    890:            }
                    891:            if (pi->If) {
                    892:                TcpUnListen(ctx->lnk);
                    893:                TcpListen(ctx->lnk);
                    894:            }
                    895:            break;
                    896:        case SET_ENABLE:
                    897:            EnableCommand(ac, av, &pi->conf.options, gConfList);
                    898:            TcpNodeUpdate(ctx->lnk);
                    899:            break;
                    900:        case SET_DISABLE:
                    901:            DisableCommand(ac, av, &pi->conf.options, gConfList);
                    902:            TcpNodeUpdate(ctx->lnk);
                    903:            break;
                    904:        default:
                    905:                assert(0);
                    906:     }
                    907: 
                    908:     return (0);
                    909: }

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