Annotation of embedaddon/mpd/src/tcp.c, revision 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>