Annotation of embedaddon/mpd/src/tcp.c, revision 1.1.1.2
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:
95: static int TcpSetCommand(Context ctx, int ac, char *av[], void *arg);
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 },
135: { NULL },
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: };
145: struct TcpIf TcpIfs[TCP_MAXPARENTIFS];
146:
147: /*
148: * INTERNAL VARIABLES
149: */
150:
151: static struct confinfo gConfList[] = {
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: {
365: struct {
366: struct ng_mesg resp;
367: int32_t rval;
368: } cn;
369: Link l;
370: TcpInfo pi;
371: char path[NG_PATHSIZ];
372:
373: /* Restore context. */
374: l = (Link)cookie;
375: pi = (TcpInfo)l->info;
376:
377: assert(type == EVENT_READ);
378:
379: /* Check whether the connection was successful or not. */
380: if (NgRecvMsg(pi->csock, &cn.resp, sizeof(cn), path) < 0) {
381: Perror("[%s] error reading message from \"%s\"", l->name, path);
382: goto failed;
383: }
384:
385: assert(cn.resp.header.typecookie == NGM_KSOCKET_COOKIE);
386: assert(cn.resp.header.cmd == NGM_KSOCKET_CONNECT);
387:
388: if (cn.rval != 0) {
389: Log(LG_PHYS, ("[%s] failed to connect: %s", l->name,
390: strerror(cn.rval)));
391: goto failed;
392: }
393:
394: /* Report connected. */
395: Log(LG_PHYS, ("[%s] connection established", l->name));
396:
397: l->state = PHYS_STATE_UP;
398: PhysUp(l);
399:
400: return;
401: failed:
402: l->state = PHYS_STATE_DOWN;
403: TcpDoClose(l);
404: PhysDown(l, STR_ERROR, NULL);
405:
406: }
407:
408: /*
409: * TcpAcceptEvent() triggers when we accept incoming connection.
410: */
411: static void
412: TcpAcceptEvent(int type, void *cookie)
413: {
414: struct {
415: struct ng_mesg resp;
416: uint32_t id;
417: struct sockaddr_storage sin;
418: } ac;
419: struct ngm_name nm;
420: char path[NG_PATHSIZ];
421: struct u_addr addr;
422: in_port_t port;
423: char buf[48];
424: int k;
425: struct TcpIf *If=(struct TcpIf *)(cookie);
426: Link l = NULL;
427: TcpInfo pi = NULL;
428:
429: assert(type == EVENT_READ);
430:
431: /* Accept cloned ng_ksocket(4). */
432: if (NgRecvMsg(If->csock, &ac.resp, sizeof(ac), NULL) < 0) {
433: Perror("TCP: error reading message from \"%s\"", path);
434: goto failed;
435: }
436: sockaddrtou_addr(&ac.sin, &addr, &port);
437:
438: Log(LG_PHYS, ("Incoming TCP connection from %s %u",
439: u_addrtoa(&addr, buf, sizeof(buf)), port));
440:
441: if (gShutdownInProgress) {
442: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
443: return;
444: }
445:
446: if (OVERLOAD()) {
447: Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
448: return;
449: }
450:
451: /* Examine all TCP links. */
452: for (k = 0; k < gNumLinks; k++) {
453: Link l2;
454: TcpInfo pi2;
455:
456: if (!gLinks[k] || gLinks[k]->type != &gTcpPhysType)
457: continue;
458:
459: l2 = gLinks[k];
460: pi2 = (TcpInfo)l2->info;
461:
462: if ((!PhysIsBusy(l2)) &&
463: Enabled(&l2->conf.options, LINK_CONF_INCOMING) &&
464: (pi2->If == If) &&
465: IpAddrInRange(&pi2->conf.peer_addr, &addr) &&
466: (pi2->conf.peer_port == 0 || pi2->conf.peer_port == port)) {
467:
468: if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
469: l = l2;
470: pi = pi2;
471: if (u_rangehost(&pi->conf.peer_addr)) {
472: break; /* Nothing could be better */
473: }
474: }
475: }
476: }
477: if (l != NULL && l->tmpl)
478: l = LinkInst(l, NULL, 0, 0);
479:
480: if (l != NULL) {
481: pi = (TcpInfo)l->info;
482: Log(LG_PHYS, ("[%s] Accepting TCP connection from %s %u",
483: l->name, u_addrtoa(&addr, buf, sizeof(buf)), port));
484:
485: sockaddrtou_addr(&ac.sin, &pi->peer_addr, &pi->peer_port);
486:
487: pi->node_id = ac.id;
488:
489: /* Give it a name */
490: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", gPid, l->name);
491: snprintf(path, sizeof(path), "[%x]:", ac.id);
492: if (NgSendMsg(If->csock, path,
493: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
494: Perror("[%s] can't name %s node",
495: l->name, NG_KSOCKET_NODE_TYPE);
496: }
497:
498: pi->incoming=1;
499: l->state = PHYS_STATE_READY;
500:
501: PhysIncoming(l);
502: } else {
503: Log(LG_PHYS, ("No free TCP link with requested parameters "
504: "was found"));
505: snprintf(path, sizeof(path), "[%x]:", ac.id);
506: NgFuncShutdownNode(If->csock, "", path);
507: }
508:
509: failed:
510: /* Tell that we are willing to receive accept message. */
511: if (NgSendMsg(If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
512: NGM_KSOCKET_ACCEPT, NULL, 0) < 0) {
513: Perror("TCP: can't accept on %s node", NG_KSOCKET_NODE_TYPE);
514: }
515: EventRegister(&If->ctrlEvent, EVENT_READ, If->csock,
516: 0, TcpAcceptEvent, If);
517: }
518:
519: /*
520: * TcpClose()
521: */
522:
523: static void
524: TcpClose(Link l)
525: {
526: TcpInfo const pi = (TcpInfo) l->info;
527:
528: TcpDoClose(l);
529:
530: if (l->state != PHYS_STATE_DOWN) {
531: pi->incoming=0;
532: l->state = PHYS_STATE_DOWN;
533:
534: u_addrclear(&pi->peer_addr);
535: pi->peer_port=0;
536:
537: PhysDown(l, STR_MANUALLY, NULL);
538: }
539: }
540:
541: /*
542: * TcpShutdown()
543: */
544:
545: static void
546: TcpShutdown(Link l)
547: {
548: TcpInfo const pi = (TcpInfo) l->info;
549:
550: if (pi->conf.fqdn_peer_addr)
551: Freee(pi->conf.fqdn_peer_addr);
552:
553: TcpDoClose(l);
554: TcpUnListen(l);
555: Freee(l->info);
556: }
557:
558: /*
559: * TcpDoClose()
560: */
561:
562: static void
563: TcpDoClose(Link l)
564: {
565: char path[NG_PATHSIZ];
566: TcpInfo const pi = (TcpInfo) l->info;
567:
568: EventUnRegister(&pi->ev_connect);
569:
570: if (pi->csock<=0) {
571: return;
572: };
573:
574: if (pi->node_id != 0) {
575: snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->node_id);
576: NgFuncShutdownNode(pi->csock, l->name, path);
577: pi->node_id = 0;
578: }
579:
580: if (pi->async_node_id != 0) {
581: snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->async_node_id);
582: NgFuncShutdownNode(pi->csock, l->name, path);
583: pi->async_node_id = 0;
584: }
585:
586: close(pi->csock);
587: pi->csock = -1;
588: pi->node_id = 0;
589: }
590:
591: /*
592: * TcpOriginate()
593: */
594:
595: static int
596: TcpOriginate(Link l)
597: {
598: TcpInfo const pi = (TcpInfo) l->info;
599:
600: return (pi->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
601: }
602:
603: /*
604: * TcpIsSync()
605: */
606:
607: static int
608: TcpIsSync(Link l)
609: {
610: return (1);
611: }
612:
613: static int
614: TcpSelfAddr(Link l, void *buf, size_t buf_len)
615: {
616: TcpInfo const pi = (TcpInfo) l->info;
617:
618: if (!u_addrempty(&pi->conf.self_addr)) {
619: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
620: return (0);
621: else {
622: ((char*)buf)[0]=0;
623: return (-1);
624: }
625: }
626: ((char*)buf)[0]=0;
627: return (0);
628: }
629:
630: static int
631: TcpPeerAddr(Link l, void *buf, size_t buf_len)
632: {
633: TcpInfo const pi = (TcpInfo) l->info;
634:
635: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
636: return (0);
637: else
638: return (-1);
639: }
640:
641: static int
642: TcpPeerPort(Link l, void *buf, size_t buf_len)
643: {
644: TcpInfo const pi = (TcpInfo) l->info;
645:
646: if (snprintf( buf, buf_len, "%u", pi->peer_port))
647: return (0);
648: else
649: return (-1);
650: }
651:
652: static int
653: TcpCallingNum(Link l, void *buf, size_t buf_len)
654: {
655: TcpInfo const pi = (TcpInfo) l->info;
656:
657: if (pi->incoming) {
658: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
659: return (0);
660: else
661: return (-1);
662: } else {
663: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
664: return (0);
665: else
666: return (-1);
667: }
668: }
669:
670: static int
671: TcpCalledNum(Link l, void *buf, size_t buf_len)
672: {
673: TcpInfo const pi = (TcpInfo) l->info;
674:
675: if (!pi->incoming) {
676: if (u_addrtoa(&pi->peer_addr, buf, buf_len))
677: return (0);
678: else
679: return (-1);
680: } else {
681: if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
682: return (0);
683: else
684: return (-1);
685: }
686: }
687:
688: /*
689: * TcpStat()
690: */
691:
692: void
693: TcpStat(Context ctx)
694: {
695: TcpInfo const pi = (TcpInfo) ctx->lnk->info;
696: char buf[48];
697:
698: Printf("TCP configuration:\r\n");
699: Printf("\tPeer FQDN : %s\r\n", pi->conf.fqdn_peer_addr);
700: Printf("\tSelf address : %s, port %u\r\n",
701: u_addrtoa(&pi->conf.self_addr, buf, sizeof(buf)), pi->conf.self_port);
702: Printf("\tPeer address : %s, port %u\r\n",
703: u_rangetoa(&pi->conf.peer_addr, buf, sizeof(buf)), pi->conf.peer_port);
704: Printf("TCP state:\r\n");
705: if (ctx->lnk->state != PHYS_STATE_DOWN) {
706: Printf("\tIncoming : %s\r\n", (pi->incoming?"YES":"NO"));
707: Printf("\tCurrent peer : %s, port %u\r\n",
708: u_addrtoa(&pi->peer_addr, buf, sizeof(buf)), pi->peer_port);
709: }
710: }
711:
712: static int
713: TcpListen(Link l)
714: {
715: TcpInfo const pi = (TcpInfo) l->info;
716: struct ngm_mkpeer mkp;
717: struct sockaddr_storage addr;
718: int32_t backlog = 1;
719: char buf[48];
720: union {
721: u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
722: struct ng_ksocket_sockopt ksso;
723: } u;
724: struct ng_ksocket_sockopt *const ksso = &u.ksso;
725: int i, j = -1, free = -1;
726:
727: if (pi->If)
728: return(1);
729:
730: for (i = 0; i < TCP_MAXPARENTIFS; i++) {
731: if (TcpIfs[i].self_port == 0)
732: free = i;
733: else if ((u_addrcompare(&TcpIfs[i].self_addr, &pi->conf.self_addr) == 0) &&
734: (TcpIfs[i].self_port == pi->conf.self_port)) {
735: j = i;
736: break;
737: }
738: }
739:
740: if (j >= 0) {
741: TcpIfs[j].refs++;
742: pi->If=&TcpIfs[j];
743: return(1);
744: }
745:
746: if (free < 0) {
747: Log(LG_ERR, ("[%s] TCP: Too many different listening ports! ",
748: l->name));
749: return (0);
750: }
751:
752: TcpIfs[free].refs = 1;
753: pi->If=&TcpIfs[free];
754:
755: u_addrcopy(&pi->conf.self_addr,&pi->If->self_addr);
756: pi->If->self_port=pi->conf.self_port;
757:
758: /* Create a new netgraph node */
759: if (NgMkSockNode(NULL, &pi->If->csock, NULL) < 0) {
760: Perror("TCP: can't create ctrl socket");
761: return(0);
762: }
763: (void)fcntl(pi->If->csock, F_SETFD, 1);
764:
765: /* Make listening TCP ksocket node. */
766: strcpy(mkp.type, NG_KSOCKET_NODE_TYPE);
767: strcpy(mkp.ourhook, LISTENHOOK);
768: if (pi->If->self_addr.family==AF_INET6) {
769: snprintf(mkp.peerhook, sizeof(mkp.peerhook), "%d/%d/%d", PF_INET6, SOCK_STREAM, IPPROTO_TCP);
770: } else {
771: snprintf(mkp.peerhook, sizeof(mkp.peerhook), "inet/stream/tcp");
772: }
773: if (NgSendMsg(pi->If->csock, ".:", NGM_GENERIC_COOKIE, NGM_MKPEER,
774: &mkp, sizeof(mkp)) < 0) {
775: Perror("TCP: can't attach %s node", NG_KSOCKET_NODE_TYPE);
776: goto fail2;
777: }
778:
779: /* Setsockopt socket. */
780: ksso->level=SOL_SOCKET;
781: ksso->name=SO_REUSEPORT;
782: ((int *)(ksso->value))[0]=1;
783: if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
784: NGM_KSOCKET_SETOPT, &u, sizeof(u)) < 0) {
785: Perror("TCP: can't setsockopt() %s node", NG_KSOCKET_NODE_TYPE);
786: goto fail2;
787: }
788:
789: /* Bind socket. */
790: u_addrtosockaddr(&pi->If->self_addr, pi->If->self_port, &addr);
791: if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
792: NGM_KSOCKET_BIND, &addr, addr.ss_len) < 0) {
793: Perror("TCP: can't bind() %s node", NG_KSOCKET_NODE_TYPE);
794: goto fail2;
795: }
796:
797: /* Listen. */
798: if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
799: NGM_KSOCKET_LISTEN, &backlog, sizeof(backlog)) < 0) {
800: Perror("TCP: can't listen() on %s node", NG_KSOCKET_NODE_TYPE);
801: goto fail2;
802: }
803:
804: /* Tell that we are willing to receive accept message. */
805: if (NgSendMsg(pi->If->csock, LISTENHOOK, NGM_KSOCKET_COOKIE,
806: NGM_KSOCKET_ACCEPT, NULL, 0) < 0) {
807: Perror("TCP: can't accept() on %s node", NG_KSOCKET_NODE_TYPE);
808: goto fail2;
809: }
810:
811: Log(LG_PHYS, ("TCP: waiting for connection on %s %u",
812: u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
813: EventRegister(&pi->If->ctrlEvent, EVENT_READ, pi->If->csock,
814: 0, TcpAcceptEvent, pi->If);
815:
816: return (1);
817: fail2:
818: NgSendMsg(pi->If->csock, LISTENHOOK, NGM_GENERIC_COOKIE, NGM_SHUTDOWN,
819: NULL, 0);
820: return (0);
821: }
822:
823: static void
824: TcpUnListen(Link l)
825: {
826: TcpInfo const pi = (TcpInfo) l->info;
827: char buf[48];
828:
829: if (!pi->If)
830: return;
831:
832: pi->If->refs--;
833: if (pi->If->refs == 0) {
834: Log(LG_PHYS, ("TCP: stop waiting for connection on %s %u",
835: u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
836: EventUnRegister(&pi->If->ctrlEvent);
837: close(pi->If->csock);
838: pi->If->csock = -1;
839: pi->If->self_port = 0;
840: pi->If = NULL;
841: }
842: }
843:
844: /*
845: * TcpNodeUpdate()
846: */
847:
848: static void
849: TcpNodeUpdate(Link l)
850: {
851: TcpInfo const pi = (TcpInfo) l->info;
852: if (!pi->If) {
853: if (Enabled(&l->conf.options, LINK_CONF_INCOMING))
854: TcpListen(l);
855: } else {
856: if (!Enabled(&l->conf.options, LINK_CONF_INCOMING))
857: TcpUnListen(l);
858: }
859: }
860:
861: /*
862: * TcpSetCommand()
863: */
864:
865: static int
866: TcpSetCommand(Context ctx, int ac, char *av[], void *arg)
867: {
868: TcpInfo const pi = (TcpInfo) ctx->lnk->info;
869: char **fqdn_peer_addr = &pi->conf.fqdn_peer_addr;
870: struct u_range rng;
871: int port;
872:
873: switch ((intptr_t)arg) {
874: case SET_PEERADDR:
875: case SET_SELFADDR:
876: if ((ac == 1 || ac == 2) && (intptr_t)arg == SET_PEERADDR) {
877: if (*fqdn_peer_addr)
878: Freee(*fqdn_peer_addr);
879: *fqdn_peer_addr = Mstrdup(MB_PHYS, av[0]);
880: }
881: if (ac < 1 || ac > 2 || !ParseRange(av[0], &rng, ALLOW_IPV4|ALLOW_IPV6))
882: return(-1);
883: if (ac > 1) {
884: if ((port = atoi(av[1])) < 0 || port > 0xffff)
885: return(-1);
886: } else {
887: port = 0;
888: }
889: if ((intptr_t)arg == SET_SELFADDR) {
890: pi->conf.self_addr = rng.addr;
891: pi->conf.self_port = port;
892: } else {
893: pi->conf.peer_addr = rng;
894: pi->conf.peer_port = port;
895: }
896: if (pi->If) {
897: TcpUnListen(ctx->lnk);
898: TcpListen(ctx->lnk);
899: }
900: break;
901: case SET_ENABLE:
902: EnableCommand(ac, av, &pi->conf.options, gConfList);
903: TcpNodeUpdate(ctx->lnk);
904: break;
905: case SET_DISABLE:
906: DisableCommand(ac, av, &pi->conf.options, gConfList);
907: TcpNodeUpdate(ctx->lnk);
908: break;
909: default:
910: assert(0);
911: }
912:
913: return (0);
914: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>