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