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>