File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / tcp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    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: #ifndef SMALL_SYSTEM
   30: #define TCP_MAXPARENTIFS	256
   31: #else
   32: #define TCP_MAXPARENTIFS	64
   33: #endif
   34: 
   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>