Annotation of embedaddon/mpd/src/udp.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * udp.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 "udp.h"
! 12: #include "ngfunc.h"
! 13: #include "util.h"
! 14: #include "log.h"
! 15:
! 16: #include <netgraph/ng_message.h>
! 17: #include <netgraph/ng_socket.h>
! 18: #include <netgraph/ng_ksocket.h>
! 19: #include <netgraph.h>
! 20:
! 21: /*
! 22: * XXX this device type not completely correct,
! 23: * as it can deliver out-of-order frames. This can make problems
! 24: * for different compression and encryption protocols.
! 25: */
! 26:
! 27: /*
! 28: * DEFINITIONS
! 29: */
! 30:
! 31: #define UDP_MTU 2048
! 32: #define UDP_MRU 2048
! 33:
! 34: #define UDP_MAXPARENTIFS 256
! 35:
! 36: struct udpinfo {
! 37: struct {
! 38: struct optinfo options;
! 39: struct u_addr self_addr; /* Configured local IP address */
! 40: struct u_range peer_addr; /* Configured peer IP address */
! 41: in_port_t self_port; /* Configured local port */
! 42: in_port_t peer_port; /* Configured peer port */
! 43: char *fqdn_peer_addr; /* FQDN Peer address */
! 44: } conf;
! 45:
! 46: /* State */
! 47: u_char incoming; /* incoming vs. outgoing */
! 48: struct UdpIf *If;
! 49: struct u_addr peer_addr;
! 50: in_port_t peer_port;
! 51: ng_ID_t node_id;
! 52: };
! 53: typedef struct udpinfo *UdpInfo;
! 54:
! 55: /* Set menu options */
! 56:
! 57: enum {
! 58: SET_PEERADDR,
! 59: SET_SELFADDR,
! 60: SET_ENABLE,
! 61: SET_DISABLE
! 62: };
! 63:
! 64: /* Binary options */
! 65: enum {
! 66: UDP_CONF_RESOLVE_ONCE /* Only once resolve peer_addr */
! 67: };
! 68:
! 69: /*
! 70: * INTERNAL FUNCTIONS
! 71: */
! 72:
! 73: static int UdpInit(Link l);
! 74: static int UdpInst(Link l, Link lt);
! 75: static void UdpOpen(Link l);
! 76: static void UdpClose(Link l);
! 77: static void UdpStat(Context ctx);
! 78: static int UdpOrigination(Link l);
! 79: static int UdpIsSync(Link l);
! 80: static int UdpSelfAddr(Link l, void *buf, size_t buf_len);
! 81: static int UdpPeerAddr(Link l, void *buf, size_t buf_len);
! 82: static int UdpPeerPort(Link l, void *buf, size_t buf_len);
! 83: static int UdpCallingNum(Link l, void *buf, size_t buf_len);
! 84: static int UdpCalledNum(Link l, void *buf, size_t buf_len);
! 85:
! 86: static void UdpDoClose(Link l);
! 87: static void UdpShutdown(Link l);
! 88: static int UdpSetCommand(Context ctx, int ac, char *av[], void *arg);
! 89: static void UdpNodeUpdate(Link l);
! 90: static int UdpListen(Link l);
! 91: static int UdpUnListen(Link l);
! 92:
! 93: /*
! 94: * GLOBAL VARIABLES
! 95: */
! 96:
! 97: const struct phystype gUdpPhysType = {
! 98: .name = "udp",
! 99: .descr = "PPP over UDP",
! 100: .mtu = UDP_MTU,
! 101: .mru = UDP_MRU,
! 102: .tmpl = 1,
! 103: .init = UdpInit,
! 104: .inst = UdpInst,
! 105: .open = UdpOpen,
! 106: .close = UdpClose,
! 107: .update = UdpNodeUpdate,
! 108: .shutdown = UdpShutdown,
! 109: .showstat = UdpStat,
! 110: .originate = UdpOrigination,
! 111: .issync = UdpIsSync,
! 112: .selfaddr = UdpSelfAddr,
! 113: .peeraddr = UdpPeerAddr,
! 114: .peerport = UdpPeerPort,
! 115: .callingnum = UdpCallingNum,
! 116: .callednum = UdpCalledNum,
! 117: };
! 118:
! 119: const struct cmdtab UdpSetCmds[] = {
! 120: { "self {ip} [{port}]", "Set local IP address",
! 121: UdpSetCommand, NULL, 2, (void *) SET_SELFADDR },
! 122: { "peer {ip} [{port}]", "Set remote IP address",
! 123: UdpSetCommand, NULL, 2, (void *) SET_PEERADDR },
! 124: { "enable [opt ...]", "Enable option",
! 125: UdpSetCommand, NULL, 2, (void *) SET_ENABLE },
! 126: { "disable [opt ...]", "Disable option",
! 127: UdpSetCommand, NULL, 2, (void *) SET_DISABLE },
! 128: { NULL },
! 129: };
! 130:
! 131: struct UdpIf {
! 132: struct u_addr self_addr;
! 133: in_port_t self_port;
! 134: int refs;
! 135: int csock; /* netgraph Control socket */
! 136: EventRef ctrlEvent; /* listen for ctrl messages */
! 137: };
! 138: struct UdpIf UdpIfs[UDP_MAXPARENTIFS];
! 139:
! 140: int UdpListenUpdateSheduled=0;
! 141: struct pppTimer UdpListenUpdateTimer;
! 142:
! 143: /*
! 144: * INTERNAL VARIABLES
! 145: */
! 146:
! 147: static struct confinfo gConfList[] = {
! 148: { 0, UDP_CONF_RESOLVE_ONCE, "resolve-once" },
! 149: { 0, 0, NULL },
! 150: };
! 151:
! 152:
! 153: /*
! 154: * UdpInit()
! 155: */
! 156:
! 157: static int
! 158: UdpInit(Link l)
! 159: {
! 160: UdpInfo pi;
! 161:
! 162: pi = (UdpInfo) (l->info = Malloc(MB_PHYS, sizeof(*pi)));
! 163:
! 164: u_addrclear(&pi->conf.self_addr);
! 165: u_rangeclear(&pi->conf.peer_addr);
! 166: pi->conf.self_port=0;
! 167: pi->conf.peer_port=0;
! 168:
! 169: pi->incoming = 0;
! 170: pi->If = NULL;
! 171:
! 172: u_addrclear(&pi->peer_addr);
! 173: pi->peer_port=0;
! 174: pi->conf.fqdn_peer_addr = NULL;
! 175: Enable(&pi->conf.options, UDP_CONF_RESOLVE_ONCE);
! 176:
! 177: return(0);
! 178: }
! 179:
! 180: /*
! 181: * UdpInst()
! 182: */
! 183:
! 184: static int
! 185: UdpInst(Link l, Link lt)
! 186: {
! 187: UdpInfo pi;
! 188: UdpInfo const pit = (UdpInfo) lt->info;
! 189:
! 190: /* Initialize this link */
! 191: pi = (UdpInfo) (l->info = Mdup(MB_PHYS, lt->info, sizeof(*pi)));
! 192: if (pit->conf.fqdn_peer_addr != NULL)
! 193: pi->conf.fqdn_peer_addr =
! 194: Mstrdup(MB_PHYS, pit->conf.fqdn_peer_addr);
! 195:
! 196: if (pi->If)
! 197: pi->If->refs++;
! 198:
! 199: return(0);
! 200: }
! 201:
! 202: /*
! 203: * UdpOpen()
! 204: */
! 205:
! 206: static void
! 207: UdpOpen(Link l)
! 208: {
! 209: UdpInfo const pi = (UdpInfo) l->info;
! 210: char path[NG_PATHSIZ];
! 211: char hook[NG_HOOKSIZ];
! 212: struct ngm_mkpeer mkp;
! 213: struct ngm_name nm;
! 214: struct sockaddr_storage addr;
! 215: union {
! 216: u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
! 217: struct ng_ksocket_sockopt ksso;
! 218: } u;
! 219: struct ng_ksocket_sockopt *const ksso = &u.ksso;
! 220: int csock;
! 221:
! 222: /* Create a new netgraph node to control TCP ksocket node. */
! 223: if (NgMkSockNode(NULL, &csock, NULL) < 0) {
! 224: Perror("[%s] TCP can't create control socket", l->name);
! 225: goto fail;
! 226: }
! 227: (void)fcntl(csock, F_SETFD, 1);
! 228:
! 229: if (!PhysGetUpperHook(l, path, hook)) {
! 230: Log(LG_PHYS, ("[%s] UDP: can't get upper hook", l->name));
! 231: goto fail;
! 232: }
! 233:
! 234: /* Attach ksocket node to PPP node */
! 235: memset(&mkp, 0, sizeof(mkp));
! 236: strcpy(mkp.type, NG_KSOCKET_NODE_TYPE);
! 237: strlcpy(mkp.ourhook, hook, sizeof(mkp.ourhook));
! 238: if ((pi->conf.self_addr.family==AF_INET6) ||
! 239: (pi->conf.self_addr.family==AF_UNSPEC && pi->conf.peer_addr.addr.family==AF_INET6)) {
! 240: snprintf(mkp.peerhook, sizeof(mkp.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
! 241: } else {
! 242: snprintf(mkp.peerhook, sizeof(mkp.peerhook), "inet/dgram/udp");
! 243: }
! 244: if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
! 245: NGM_MKPEER, &mkp, sizeof(mkp)) < 0) {
! 246: Perror("[%s] can't attach %s node",
! 247: l->name, NG_KSOCKET_NODE_TYPE);
! 248: goto fail;
! 249: }
! 250:
! 251: strlcat(path, ".", sizeof(path));
! 252: strlcat(path, hook, sizeof(path));
! 253:
! 254: /* Give it a name */
! 255: memset(&nm, 0, sizeof(nm));
! 256: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-kso", gPid, l->name);
! 257: if (NgSendMsg(csock, path,
! 258: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
! 259: Perror("[%s] can't name %s node", l->name, NG_KSOCKET_NODE_TYPE);
! 260: }
! 261:
! 262: if ((pi->node_id = NgGetNodeID(csock, path)) == 0) {
! 263: Perror("[%s] Cannot get %s node id", l->name, NG_KSOCKET_NODE_TYPE);
! 264: goto fail;
! 265: };
! 266:
! 267: if ((pi->incoming) || (pi->conf.self_port != 0)) {
! 268: /* Setsockopt socket. */
! 269: ksso->level=SOL_SOCKET;
! 270: ksso->name=SO_REUSEPORT;
! 271: ((int *)(ksso->value))[0]=1;
! 272: if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
! 273: NGM_KSOCKET_SETOPT, &u, sizeof(u)) < 0) {
! 274: Perror("[%s] can't setsockopt() %s node",
! 275: l->name, NG_KSOCKET_NODE_TYPE);
! 276: goto fail;
! 277: }
! 278:
! 279: if ((!Enabled(&pi->conf.options, UDP_CONF_RESOLVE_ONCE)) &&
! 280: (pi->conf.fqdn_peer_addr != NULL)) {
! 281: struct u_range rng;
! 282: if (ParseRange(pi->conf.fqdn_peer_addr, &rng, ALLOW_IPV4|ALLOW_IPV6))
! 283: pi->conf.peer_addr = rng;
! 284: }
! 285:
! 286: /* Bind socket */
! 287: u_addrtosockaddr(&pi->conf.self_addr, pi->conf.self_port, &addr);
! 288: if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
! 289: NGM_KSOCKET_BIND, &addr, addr.ss_len) < 0) {
! 290: Perror("[%s] can't bind() %s node", l->name, NG_KSOCKET_NODE_TYPE);
! 291: goto fail;
! 292: }
! 293: }
! 294:
! 295: if (!pi->incoming) {
! 296: if ((!u_rangeempty(&pi->conf.peer_addr)) && (pi->conf.peer_port != 0)) {
! 297: u_addrcopy(&pi->conf.peer_addr.addr,&pi->peer_addr);
! 298: pi->peer_port = pi->conf.peer_port;
! 299: } else {
! 300: Log(LG_ERR, ("[%s] Can't connect without peer specified", l->name));
! 301: goto fail;
! 302: }
! 303: }
! 304: u_addrtosockaddr(&pi->peer_addr, pi->peer_port, &addr);
! 305:
! 306: /* Connect socket if peer address and port is specified */
! 307: if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
! 308: NGM_KSOCKET_CONNECT, &addr, addr.ss_len) < 0) {
! 309: Perror("[%s] can't connect() %s node", l->name, NG_KSOCKET_NODE_TYPE);
! 310: goto fail;
! 311: }
! 312:
! 313: close(csock);
! 314:
! 315: /* OK */
! 316: l->state = PHYS_STATE_UP;
! 317: PhysUp(l);
! 318: return;
! 319:
! 320: fail:
! 321: UdpDoClose(l);
! 322: pi->incoming=0;
! 323: l->state = PHYS_STATE_DOWN;
! 324: u_addrclear(&pi->peer_addr);
! 325: pi->peer_port=0;
! 326: if (csock>0)
! 327: close(csock);
! 328:
! 329: PhysDown(l, STR_ERROR, NULL);
! 330: }
! 331:
! 332: /*
! 333: * UdpClose()
! 334: */
! 335:
! 336: static void
! 337: UdpClose(Link l)
! 338: {
! 339: UdpInfo const pi = (UdpInfo) l->info;
! 340: if (l->state != PHYS_STATE_DOWN) {
! 341: UdpDoClose(l);
! 342: pi->incoming=0;
! 343: l->state = PHYS_STATE_DOWN;
! 344: u_addrclear(&pi->peer_addr);
! 345: pi->peer_port=0;
! 346: PhysDown(l, STR_MANUALLY, NULL);
! 347: }
! 348: }
! 349:
! 350: /*
! 351: * UdpShutdown()
! 352: */
! 353:
! 354: static void
! 355: UdpShutdown(Link l)
! 356: {
! 357: UdpInfo const pi = (UdpInfo) l->info;
! 358:
! 359: if (pi->conf.fqdn_peer_addr)
! 360: Freee(pi->conf.fqdn_peer_addr);
! 361:
! 362: UdpDoClose(l);
! 363: UdpUnListen(l);
! 364: Freee(l->info);
! 365: }
! 366:
! 367: /*
! 368: * UdpDoClose()
! 369: */
! 370:
! 371: static void
! 372: UdpDoClose(Link l)
! 373: {
! 374: UdpInfo const pi = (UdpInfo) l->info;
! 375: char path[NG_PATHSIZ];
! 376: int csock;
! 377:
! 378: if (pi->node_id == 0)
! 379: return;
! 380:
! 381: /* Get a temporary netgraph socket node */
! 382: if (NgMkSockNode(NULL, &csock, NULL) == -1) {
! 383: Perror("UDP: NgMkSockNode");
! 384: return;
! 385: }
! 386:
! 387: /* Disconnect session hook. */
! 388: snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->node_id);
! 389: NgFuncShutdownNode(csock, l->name, path);
! 390:
! 391: close(csock);
! 392:
! 393: pi->node_id = 0;
! 394: }
! 395:
! 396: /*
! 397: * UdpOrigination()
! 398: */
! 399:
! 400: static int
! 401: UdpOrigination(Link l)
! 402: {
! 403: UdpInfo const pi = (UdpInfo) l->info;
! 404:
! 405: return (pi->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
! 406: }
! 407:
! 408: /*
! 409: * UdpIsSync()
! 410: */
! 411:
! 412: static int
! 413: UdpIsSync(Link l)
! 414: {
! 415: return (1);
! 416: }
! 417:
! 418: static int
! 419: UdpSelfAddr(Link l, void *buf, size_t buf_len)
! 420: {
! 421: UdpInfo const pi = (UdpInfo) l->info;
! 422:
! 423: if (!u_addrempty(&pi->conf.self_addr)) {
! 424: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
! 425: return (0);
! 426: else {
! 427: ((char*)buf)[0]=0;
! 428: return (-1);
! 429: }
! 430: }
! 431: ((char*)buf)[0]=0;
! 432: return (0);
! 433: }
! 434:
! 435: static int
! 436: UdpPeerAddr(Link l, void *buf, size_t buf_len)
! 437: {
! 438: UdpInfo const pi = (UdpInfo) l->info;
! 439:
! 440: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
! 441: return(0);
! 442: else
! 443: return(-1);
! 444: }
! 445:
! 446: static int
! 447: UdpPeerPort(Link l, void *buf, size_t buf_len)
! 448: {
! 449: UdpInfo const pi = (UdpInfo) l->info;
! 450:
! 451: if (snprintf(buf, buf_len, "%d", pi->peer_port))
! 452: return(0);
! 453: else
! 454: return(-1);
! 455: }
! 456:
! 457: static int
! 458: UdpCallingNum(Link l, void *buf, size_t buf_len)
! 459: {
! 460: UdpInfo const pi = (UdpInfo) l->info;
! 461:
! 462: if (pi->incoming) {
! 463: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
! 464: return (0);
! 465: else
! 466: return (-1);
! 467: } else {
! 468: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
! 469: return (0);
! 470: else
! 471: return (-1);
! 472: }
! 473: }
! 474:
! 475: static int
! 476: UdpCalledNum(Link l, void *buf, size_t buf_len)
! 477: {
! 478: UdpInfo const pi = (UdpInfo) l->info;
! 479:
! 480: if (!pi->incoming) {
! 481: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
! 482: return (0);
! 483: else
! 484: return (-1);
! 485: } else {
! 486: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
! 487: return (0);
! 488: else
! 489: return (-1);
! 490: }
! 491: }
! 492:
! 493: /*
! 494: * UdpStat()
! 495: */
! 496:
! 497: void
! 498: UdpStat(Context ctx)
! 499: {
! 500: UdpInfo const pi = (UdpInfo) ctx->lnk->info;
! 501: char buf[48];
! 502:
! 503: Printf("UDP configuration:\r\n");
! 504: Printf("\tPeer FQDN : %s\r\n", pi->conf.fqdn_peer_addr);
! 505: Printf("\tSelf address : %s, port %u\r\n",
! 506: u_addrtoa(&pi->conf.self_addr, buf, sizeof(buf)), pi->conf.self_port);
! 507: Printf("\tPeer address : %s, port %u\r\n",
! 508: u_rangetoa(&pi->conf.peer_addr, buf, sizeof(buf)), pi->conf.peer_port);
! 509: Printf("UDP state:\r\n");
! 510: if (ctx->lnk->state != PHYS_STATE_DOWN) {
! 511: Printf("\tIncoming : %s\r\n", (pi->incoming?"YES":"NO"));
! 512: Printf("\tCurrent peer : %s, port %u\r\n",
! 513: u_addrtoa(&pi->peer_addr, buf, sizeof(buf)), pi->peer_port);
! 514: }
! 515: }
! 516:
! 517: /*
! 518: * UdpAcceptEvent() triggers when we accept incoming connection.
! 519: */
! 520:
! 521: static void
! 522: UdpAcceptEvent(int type, void *cookie)
! 523: {
! 524: struct sockaddr_storage saddr;
! 525: socklen_t saddrlen;
! 526: struct u_addr addr;
! 527: in_port_t port;
! 528: char buf[48];
! 529: char buf1[48];
! 530: int k;
! 531: struct UdpIf *If=(struct UdpIf *)(cookie);
! 532: Link l = NULL;
! 533: UdpInfo pi = NULL;
! 534:
! 535: char pktbuf[UDP_MRU+100];
! 536: ssize_t pktlen;
! 537:
! 538: assert(type == EVENT_READ);
! 539:
! 540: saddrlen = sizeof(saddr);
! 541: if ((pktlen = recvfrom(If->csock, pktbuf, sizeof(pktbuf), MSG_DONTWAIT, (struct sockaddr *)(&saddr), &saddrlen)) < 0) {
! 542: Log(LG_PHYS, ("recvfrom() error: %s", strerror(errno)));
! 543: }
! 544:
! 545: sockaddrtou_addr(&saddr, &addr, &port);
! 546:
! 547: Log(LG_PHYS, ("Incoming UDP connection from %s %u to %s %u",
! 548: u_addrtoa(&addr, buf, sizeof(buf)), port,
! 549: u_addrtoa(&If->self_addr, buf1, sizeof(buf1)), If->self_port));
! 550:
! 551: if (gShutdownInProgress) {
! 552: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
! 553: goto failed;
! 554: }
! 555:
! 556: if (OVERLOAD()) {
! 557: Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
! 558: goto failed;
! 559: }
! 560:
! 561: /* Examine all UDP links. */
! 562: for (k = 0; k < gNumLinks; k++) {
! 563: Link l2;
! 564: UdpInfo pi2;
! 565:
! 566: if (!gLinks[k] || gLinks[k]->type != &gUdpPhysType)
! 567: continue;
! 568:
! 569: l2 = gLinks[k];
! 570: pi2 = (UdpInfo)l2->info;
! 571:
! 572: if ((!PhysIsBusy(l2)) &&
! 573: Enabled(&l2->conf.options, LINK_CONF_INCOMING) &&
! 574: (pi2->If == If) &&
! 575: IpAddrInRange(&pi2->conf.peer_addr, &addr) &&
! 576: (pi2->conf.peer_port == 0 || pi2->conf.peer_port == port)) {
! 577:
! 578: if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
! 579: l = l2;
! 580: pi = pi2;
! 581: if (u_rangehost(&pi->conf.peer_addr)) {
! 582: break; /* Nothing could be better */
! 583: }
! 584: }
! 585: }
! 586: }
! 587: if (l != NULL && l->tmpl)
! 588: l = LinkInst(l, NULL, 0, 0);
! 589:
! 590: if (l != NULL) {
! 591: pi = (UdpInfo)l->info;
! 592: Log(LG_PHYS, ("[%s] Accepting UDP connection from %s %u to %s %u",
! 593: l->name, u_addrtoa(&addr, buf, sizeof(buf)), port,
! 594: u_addrtoa(&If->self_addr, buf1, sizeof(buf1)), If->self_port));
! 595:
! 596: sockaddrtou_addr(&saddr, &pi->peer_addr, &pi->peer_port);
! 597:
! 598: pi->incoming=1;
! 599: l->state = PHYS_STATE_READY;
! 600:
! 601: PhysIncoming(l);
! 602: } else {
! 603: Log(LG_PHYS, ("No free UDP link with requested parameters "
! 604: "was found"));
! 605: }
! 606:
! 607: failed:
! 608: EventRegister(&If->ctrlEvent, EVENT_READ, If->csock,
! 609: 0, UdpAcceptEvent, If);
! 610: }
! 611:
! 612: static int
! 613: UdpListen(Link l)
! 614: {
! 615: UdpInfo const pi = (UdpInfo) l->info;
! 616: struct sockaddr_storage addr;
! 617: char buf[48];
! 618: int opt, i, j = -1, free = -1;
! 619:
! 620: if (pi->If)
! 621: return(1);
! 622:
! 623: for (i = 0; i < UDP_MAXPARENTIFS; i++) {
! 624: if (UdpIfs[i].self_port == 0)
! 625: free = i;
! 626: else if ((u_addrcompare(&UdpIfs[i].self_addr, &pi->conf.self_addr) == 0) &&
! 627: (UdpIfs[i].self_port == pi->conf.self_port)) {
! 628: j = i;
! 629: break;
! 630: }
! 631: }
! 632:
! 633: if (j >= 0) {
! 634: UdpIfs[j].refs++;
! 635: pi->If=&UdpIfs[j];
! 636: return(1);
! 637: }
! 638:
! 639: if (free < 0) {
! 640: Log(LG_ERR, ("[%s] UDP: Too many different listening ports! ",
! 641: l->name));
! 642: return (0);
! 643: }
! 644:
! 645: UdpIfs[free].refs = 1;
! 646: pi->If=&UdpIfs[free];
! 647:
! 648: u_addrcopy(&pi->conf.self_addr,&pi->If->self_addr);
! 649: pi->If->self_port=pi->conf.self_port;
! 650:
! 651: /* Make listening UDP socket. */
! 652: if (pi->If->self_addr.family==AF_INET6) {
! 653: pi->If->csock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
! 654: } else {
! 655: pi->If->csock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
! 656: }
! 657: (void)fcntl(pi->If->csock, F_SETFD, 1);
! 658:
! 659: /* Setsockopt socket. */
! 660: opt = 1;
! 661: if (setsockopt(pi->If->csock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) {
! 662: Perror("UDP: can't setsockopt socket");
! 663: goto fail2;
! 664: };
! 665:
! 666: /* Bind socket. */
! 667: u_addrtosockaddr(&pi->If->self_addr, pi->If->self_port, &addr);
! 668: if (bind(pi->If->csock, (struct sockaddr *)(&addr), addr.ss_len)) {
! 669: Perror("UDP: can't bind socket");
! 670: goto fail2;
! 671: }
! 672:
! 673: Log(LG_PHYS, ("UDP: waiting for connection on %s %u",
! 674: u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
! 675: EventRegister(&pi->If->ctrlEvent, EVENT_READ, pi->If->csock,
! 676: 0, UdpAcceptEvent, pi->If);
! 677:
! 678: return (1);
! 679: fail2:
! 680: close(pi->If->csock);
! 681: pi->If->csock = -1;
! 682: pi->If->self_port = 0;
! 683: pi->If = NULL;
! 684: return (0);
! 685: }
! 686:
! 687:
! 688: static int
! 689: UdpUnListen(Link l)
! 690: {
! 691: UdpInfo const pi = (UdpInfo) l->info;
! 692: char buf[48];
! 693:
! 694: if (!pi->If)
! 695: return(1);
! 696:
! 697: pi->If->refs--;
! 698: if (pi->If->refs == 0) {
! 699: Log(LG_PHYS, ("UDP: stop waiting for connection on %s %u",
! 700: u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
! 701: EventUnRegister(&pi->If->ctrlEvent);
! 702: close(pi->If->csock);
! 703: pi->If->csock = -1;
! 704: pi->If->self_port = 0;
! 705: pi->If = NULL;
! 706: }
! 707:
! 708: return (1);
! 709: }
! 710:
! 711: /*
! 712: * UdpNodeUpdate()
! 713: */
! 714:
! 715: static void
! 716: UdpNodeUpdate(Link l)
! 717: {
! 718: UdpInfo const pi = (UdpInfo) l->info;
! 719: if (!pi->If) {
! 720: if (Enabled(&l->conf.options, LINK_CONF_INCOMING))
! 721: UdpListen(l);
! 722: } else {
! 723: if (!Enabled(&l->conf.options, LINK_CONF_INCOMING))
! 724: UdpUnListen(l);
! 725: }
! 726: }
! 727:
! 728: /*
! 729: * UdpSetCommand()
! 730: */
! 731:
! 732: static int
! 733: UdpSetCommand(Context ctx, int ac, char *av[], void *arg)
! 734: {
! 735: UdpInfo const pi = (UdpInfo) ctx->lnk->info;
! 736: char **fqdn_peer_addr = &pi->conf.fqdn_peer_addr;
! 737: struct u_range rng;
! 738: int port;
! 739:
! 740: switch ((intptr_t)arg) {
! 741: case SET_PEERADDR:
! 742: case SET_SELFADDR:
! 743: if ((ac == 1 || ac == 2) && (intptr_t)arg == SET_PEERADDR) {
! 744: if (*fqdn_peer_addr)
! 745: Freee(*fqdn_peer_addr);
! 746: *fqdn_peer_addr = Mstrdup(MB_PHYS, av[0]);
! 747: }
! 748: if (ac < 1 || ac > 2 || !ParseRange(av[0], &rng, ALLOW_IPV4|ALLOW_IPV6))
! 749: return(-1);
! 750: if (ac > 1) {
! 751: if ((port = atoi(av[1])) < 0 || port > 0xffff)
! 752: return(-1);
! 753: } else {
! 754: port = 0;
! 755: }
! 756: if ((intptr_t)arg == SET_SELFADDR) {
! 757: pi->conf.self_addr = rng.addr;
! 758: pi->conf.self_port = port;
! 759: } else {
! 760: pi->conf.peer_addr = rng;
! 761: pi->conf.peer_port = port;
! 762: }
! 763: if (pi->If) {
! 764: UdpUnListen(ctx->lnk);
! 765: UdpListen(ctx->lnk);
! 766: }
! 767: break;
! 768: case SET_ENABLE:
! 769: EnableCommand(ac, av, &pi->conf.options, gConfList);
! 770: UdpNodeUpdate(ctx->lnk);
! 771: break;
! 772: case SET_DISABLE:
! 773: DisableCommand(ac, av, &pi->conf.options, gConfList);
! 774: UdpNodeUpdate(ctx->lnk);
! 775: break;
! 776: default:
! 777: assert(0);
! 778: }
! 779: return(0);
! 780: }
! 781:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>