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