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

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

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