File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / trafshow / session.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:55:18 2012 UTC (12 years, 3 months ago) by misho
Branches: trafshow, MAIN
CVS tags: v5_2_3p0, v5_2_3, HEAD
trafshow

    1: /*
    2:  *	Copyright (c) 1999-2003 Rinet Corp., Novosibirsk, Russia
    3:  *
    4:  * Redistribution and use in source forms, with and without modification,
    5:  * are permitted provided that this entire comment appears intact.
    6:  *
    7:  * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
    8:  */
    9: 
   10: #ifdef	HAVE_CONFIG_H
   11: #include <config.h>
   12: #endif
   13: 
   14: #include <sys/types.h>
   15: #include <sys/socket.h>
   16: #include <netinet/in.h>
   17: #include <fcntl.h>
   18: #include <stdlib.h>
   19: #include <string.h>
   20: #include <unistd.h>
   21: #include <errno.h>
   22: 
   23: #include "session.h"
   24: #include "events.h"	/* just for tv_sub() */
   25: 
   26: #define	dprintf(x)	/* nope */
   27: 
   28: #ifndef	BUF_SIZE
   29: #define	BUF_SIZE	8192
   30: #endif
   31: #ifndef	MAX_STR_LEN
   32: #define	MAX_STR_LEN	1500	/* must be vastly smaller then BUF_SIZE */
   33: #endif
   34: 
   35: #ifdef	O_NONBLOCK
   36: #define	ASYNC_MODE	O_NONBLOCK
   37: #elif	O_NDELAY
   38: #define	ASYNC_MODE	O_NDELAY
   39: #elif	FNDELAY
   40: #define	ASYNC_MODE	FNDELAY
   41: #elif	O_ASYNC
   42: #define	ASYNC_MODE	O_ASYNC
   43: #elif
   44: #error the fcntl argument to turn ON/OFF non-blocking I/O is unknown
   45: #endif
   46: 
   47: static int session_read(SESSION *sd);
   48: 
   49: static SESSION *first_session = 0;	/* first network session in table */
   50: 
   51: typedef	struct session_binder_ent {
   52: 	void (*notify)(void *arg);	/* call it before free */
   53: 	void *arg;
   54: 	struct session_binder_ent *next;
   55: } SESSION_BINDER;
   56: 
   57: 
   58: SESSION *
   59: session_open(sock, peer, type)
   60: 	int sock;
   61: 	const struct sockaddr *peer;
   62: 	SessionType type;
   63: {
   64: 	SESSION *sd, *prev = 0, *next = 0;
   65: 	static u_long sid = 0;
   66: 
   67: 	/*
   68: 	 * Search for first empty or last session slot.
   69: 	 */
   70: 	for (sd = first_session; sd; sd = sd->next) {
   71: 		if (!sd->sid) {
   72: 			next = sd->next;
   73: 			break;
   74: 		}
   75: 		prev = sd;
   76: 	}
   77: 	if (!sd && (sd = (SESSION *)malloc(sizeof(SESSION))) == 0)
   78: 		return 0;
   79: 	memset(sd, 0, sizeof(SESSION));
   80: 
   81: 	if (++sid == 0) sid++; /* prevent 0 sid */
   82: 	sd->sid = sid;
   83: 	sd->sock = sock;
   84: 	if (peer)
   85: 		memcpy(&sd->peer, peer, sizeof(struct sockaddr));
   86: 	else	memset(&sd->peer, 0, sizeof(sd->peer));
   87: 	memset(&sd->from, 0, sizeof(sd->from));
   88: 
   89: 	sd->type = type;
   90: 
   91: 	/* make chain */
   92: 	if (next) sd->next = next;
   93: 	else if (prev) prev->next = sd;
   94: 	if (!first_session) first_session = sd;
   95: 
   96: 	if (session_start(sd) < 0) {
   97: 		sd->sid = 0; /* this slot may be recycled later */
   98: 		sd = 0;
   99: 	}
  100: 	return sd;
  101: }
  102: 
  103: int
  104: session_start(sd)
  105: 	SESSION *sd;
  106: {
  107: 	int af;
  108: 
  109: 	/* sanity check */
  110: 	if (!sd) {
  111: 		errno = EINVAL;
  112: 		return -1;
  113: 	}
  114: 	errno = EBADF;
  115: 	if (sd->sock != -1 &&
  116: 	    (sd->type == PlainFile || socket_peer((struct sockaddr *)&sd->peer, sd->sock) != -1)) {
  117: 		/* already connected for example by accept() */
  118: 
  119: 		socket_nonblock(sd->sock, 0);
  120: 		if (sd->type == TextStream)
  121: 			socket_keepalive(sd->sock, 1);
  122: 		return 0;
  123: 	}
  124: 
  125: 	af = sd->peer.ss_family;
  126: 	if (!af) af = AF_INET; /* by default */
  127: 
  128: 	if (errno == EBADF || errno == ENOTSOCK) {
  129: 		switch (sd->type) {
  130: 		case PlainFile:
  131: 			sd->sock = -1;
  132: 			errno = EINVAL;
  133: 			break;
  134: 		case TextStream:
  135: 			sd->sock = socket(af, SOCK_STREAM, 0);
  136: 			break;
  137: 		case DataSequence:
  138: 			sd->sock = socket(af, SOCK_DGRAM, 0);
  139: 			break;
  140: 		/* XXX other session types would be added here */
  141: 		}
  142: 		if (sd->sock == -1)
  143: 			return -1;
  144: 
  145: 		errno = ENOTCONN;
  146: 	}
  147: 	if (errno == ENOTCONN) {
  148: 		/*
  149: 		 * Make socket `connected' for any type, so error on this
  150: 		 * socket will be returned asynchronously without timing out.
  151: 		 */
  152: 		socket_nonblock(sd->sock, 1);
  153: 
  154: 		if (!sd->peer.ss_family) {
  155: 			errno = 0;
  156: 			return 0;
  157: 		}
  158: 
  159: 		if (connect(sd->sock, (struct sockaddr *)&sd->peer, sizeof(struct sockaddr)) != -1 ||
  160: 		    errno == EINPROGRESS)
  161: 			return 0;
  162: 	}
  163: 	/* prevent lost of unused socket */
  164: 	session_stop(sd);
  165: 
  166: 	return -1;
  167: }
  168: 
  169: int
  170: session_sock(sd)
  171: 	SESSION *sd;
  172: {
  173: 	return (sd ? sd->sock : -1);
  174: }
  175: 
  176: unsigned
  177: session_settimeout(sd, timeout)
  178: 	SESSION *sd;
  179: 	unsigned timeout;
  180: {
  181: 	unsigned prev;
  182: 
  183: 	if (!sd || !sd->sid) return 0;
  184: 
  185: 	prev = sd->timeout;
  186: 	sd->timeout = timeout;
  187: 
  188: 	if (sd->timeout < 1)
  189: 		timerclear(&sd->expire);
  190: 
  191: 	return prev;
  192: }
  193: 
  194: void
  195: session_setcallback(sd, connected, read_error, read_data)
  196: 	SESSION *sd;
  197: 	void (*connected)(SESSION *sd);
  198: 	void (*read_error)(SESSION *sd, int error);
  199: 	void (*read_data)(SESSION *sd, const unsigned char *data, int len);
  200: {
  201: 	if (sd && sd->sid) {
  202: 		if (connected && sd->type == TextStream) {
  203: 			sd->connected = connected;
  204: 		}
  205: 		if (read_error)
  206: 			sd->read_error = read_error;
  207: 		if (read_data)
  208: 			sd->read_data = read_data;
  209: 	}
  210: }
  211: 
  212: void
  213: session_setcookie(sd, cookie)
  214: 	SESSION *sd;
  215: 	const void *cookie;
  216: {
  217: 	if (sd && sd->sid) sd->cookie = cookie;
  218: }
  219: 
  220: const void *
  221: session_cookie(sd)
  222: 	SESSION *sd;
  223: {
  224: 	return ((sd && sd->sid) ? sd->cookie : 0);
  225: }
  226: 
  227: void
  228: session_stop(sd)
  229: 	SESSION *sd;
  230: {
  231: 	if (!sd) return;
  232: 
  233: 	if (sd->sock != -1) {
  234: 		close(sd->sock);
  235: 		sd->sock = -1;
  236: 	}
  237: 	if (sd->buf) {
  238: 		free(sd->buf);
  239: 		sd->buf = 0;
  240: 	}
  241: 	timerclear(&sd->expire);
  242: }
  243: 
  244: int
  245: session_idle(sd)
  246: 	SESSION *sd;
  247: {
  248: 	if (!sd || !sd->sid) return -1;
  249: 	return (sd->sock != -1 ? 0 : 1);
  250: }
  251: 
  252: int
  253: session_bind(sd, notify, arg)
  254: 	SESSION *sd;
  255: 	void (*notify)(void *arg);
  256: 	void *arg;
  257: {
  258: 	SESSION_BINDER *curr, *last = 0;
  259: 
  260: 	if (!sd || !notify || !arg) {
  261: 		errno = EINVAL;
  262: 		return -1;
  263: 	}
  264: 	/* prevent dups and find last */
  265: 	for (curr = sd->sb; curr; curr = curr->next) {
  266: 		if (curr->notify == notify && curr->arg == arg)
  267: 			return 0;
  268: 		last = curr;
  269: 	}
  270: 	if ((curr = (SESSION_BINDER *)malloc(sizeof(SESSION_BINDER))) == 0)
  271: 		return -1;
  272: 	curr->notify = notify;
  273: 	curr->arg = arg;
  274: 	curr->next = 0;
  275: 	if (last)
  276: 		last->next = curr;
  277: 	else	sd->sb = curr;
  278: 	return 0;
  279: }
  280: 
  281: void
  282: session_unbind(sd, notify, arg)
  283: 	SESSION *sd;
  284: 	void (*notify)(void *arg);
  285: 	void *arg;
  286: {
  287: 	SESSION_BINDER *curr, *prev, *next;
  288: 
  289: 	curr = (sd ? sd->sb : 0);
  290: 	prev = 0;
  291: 	while (curr) {
  292: 		if ((!notify && !arg) ||
  293: 		    (curr->notify == notify && curr->arg == arg)) {
  294: 			next = curr->next;
  295: 			if (prev)
  296: 				prev->next = next;
  297: 			else	sd->sb = next;
  298: 			free(curr);
  299: 			curr = next;
  300: 		} else {
  301: 			prev = curr;
  302: 			curr = curr->next;
  303: 		}
  304: 	}
  305: }
  306: 
  307: /*
  308:  * This function free all memory only when free_sd = 0 else it just reset
  309:  * session id and does not free memory. The mean of this behaving is to
  310:  * reuse/recycle session slots without new malloc (avoiding it overhead).
  311:  */
  312: void
  313: session_free(free_sd)
  314: 	SESSION *free_sd;
  315: {
  316: 	SESSION *sd, *prev, *next;
  317: 	SESSION_BINDER *sb;
  318: 
  319: 	sd = first_session;
  320: 	prev = next = 0;
  321: 	while (sd) {
  322: 		if (!free_sd || sd == free_sd) {
  323: 			if (!free_sd) {
  324: 				next = sd->next;
  325: 				if (prev)
  326: 					prev->next = next;
  327: 				else	first_session = next;
  328: 			}
  329: 
  330: 			for (sb = sd->sb; sb; sb = sb->next) {
  331: 				if (sb->notify && sb->arg)
  332: 					(*sb->notify)(sb->arg);
  333: 			}
  334: 			session_stop(sd);
  335: 			session_unbind(sd, 0, 0); /* to free all */
  336: 
  337: 			if (!free_sd) {
  338: 				free(sd);
  339: 				sd = next;
  340: 				continue;
  341: 			}
  342: 			sd->sid = 0; /* this slot may be recycled later */
  343: 		}
  344: 		prev = sd;
  345: 		sd = sd->next;
  346: 	}
  347: }
  348: 
  349: SESSION *
  350: session_find(peer, type)
  351: 	const struct sockaddr *peer;
  352: 	SessionType type;
  353: {
  354: 	SESSION *sd;
  355: 
  356: 	/* sanity check */
  357: 	if (!peer) return 0;
  358: 
  359: 	for (sd = first_session; sd; sd = sd->next) {
  360: 		if (!sd->sid || sd->type != type ||
  361: 		   sd->peer.ss_family != peer->sa_family)
  362: 			continue;
  363: 
  364: 		if (peer->sa_family == AF_INET) {
  365: 			struct sockaddr_in *sin = (struct sockaddr_in *)&sd->peer;
  366: 			if (sin->sin_port == ((struct sockaddr_in *)peer)->sin_port &&
  367: 			    !memcmp(&sin->sin_addr,
  368: 				    &((struct sockaddr_in *)peer)->sin_addr,
  369: 				    sizeof(sin->sin_addr)))
  370: 				return sd;
  371: 		}
  372: #ifdef	INET6
  373: 		else if (peer->sa_family == AF_INET6) {
  374: 			struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&sd->peer;
  375: 			if (sin->sin6_port == ((struct sockaddr_in6 *)peer)->sin6_port &&
  376: 			    !memcmp(&sin->sin6_addr,
  377: 				    &((struct sockaddr_in6 *)peer)->sin6_addr,
  378: 				    sizeof(sin->sin6_addr)))
  379: 				return sd;
  380: 		}
  381: #endif
  382: 	}
  383: 	return 0;
  384: }
  385: 
  386: int
  387: session_send(sd, data, len)
  388: 	SESSION *sd;
  389: 	const unsigned char *data;
  390: 	int len;
  391: {
  392: 	int wlen = 0;
  393: 
  394: 	if (!sd || len < 0) {
  395: 		errno = EINVAL;
  396: 		return -1;
  397: 	}
  398: 	if (!sd->sid || sd->sock == -1) {
  399: 		errno = ENOTCONN;
  400: 		return -1;
  401: 	}
  402: 	if (data) {
  403: 		if (sd->type == PlainFile) {
  404: 			if (len) wlen = write(sd->sock, data, len);
  405: 
  406: 		} else if (sd->type == TextStream) {
  407: 			char buf[BUF_SIZE];
  408: 
  409: 			if (!sd->peer.ss_family) {
  410: 				errno = ENOTCONN;
  411: 				return -1;
  412: 			}
  413: 			if (len > sizeof(buf)-2) len = sizeof(buf)-2;
  414: 			if (len) memcpy(buf, data, len);
  415: 			if (!len || buf[len-1] != '\n') {
  416: 				buf[len++] = '\r';
  417: 				buf[len++] = '\n';
  418: 			}
  419: 			wlen = write(sd->sock, buf, len);
  420: 
  421: 		} else if (sd->type == DataSequence) {
  422: 
  423: 			if (!sd->peer.ss_family) {
  424: 				errno = ENOTCONN;
  425: 				return -1;
  426: 			}
  427: 			if (len) wlen = send(sd->sock, data, len, 0);
  428: 
  429: 		} else { /* XXX other session types must be added here */
  430: 			wlen = -1;
  431: 			errno = ESOCKTNOSUPPORT;
  432: 		}
  433: 	}
  434: 	if (wlen == -1) {
  435: 		if (errno == EAGAIN || errno == EINPROGRESS) {
  436: 			errno = 0;
  437: 			wlen = 0;
  438: 		} else if (sd->read_error) {
  439: 			(*sd->read_error)(sd, errno);
  440: 			return wlen;
  441: 		}
  442: 	}
  443: 	if (sd->timeout > 0) {
  444: 		gettimeofday(&sd->expire, 0);
  445: 		sd->expire.tv_sec += sd->timeout;
  446: 	}
  447: 	return wlen;
  448: }
  449: 
  450: static int
  451: session_read(sd)
  452: 	SESSION *sd;
  453: {
  454: 	int rlen = 0, rest = 0;
  455: 	char *cp, *line, buf[BUF_SIZE];
  456: 
  457: 	if (!sd) {
  458: 		errno = EINVAL;
  459: 		return -1;
  460: 	}
  461: 	if (!sd->sid || sd->sock == -1) {
  462: 		errno = ENOTCONN;
  463: 		return -1;
  464: 	}
  465: 	buf[0] = '\0';
  466: 
  467: 	if (sd->type == PlainFile) {
  468: 		rlen = read(sd->sock, buf, sizeof(buf));
  469: 
  470: 	} else if (sd->type == TextStream) {
  471: 		if (sd->buf) { /* previous line was truncated */
  472: 			rest = strlen(strcpy(buf, sd->buf));
  473: 			free(sd->buf);
  474: 			sd->buf = 0;
  475: 		}
  476: 		rlen = read(sd->sock, &buf[rest], (sizeof(buf)-1) - rest);
  477: 
  478: 	} else if (sd->type == DataSequence) {
  479: 		struct sockaddr from;
  480: 		socklen_t slen = sizeof(from);
  481: 
  482: 		rlen = recvfrom(sd->sock, buf, sizeof(buf), 0, &from, &slen);
  483: 		if (rlen != -1) {
  484: 			/* just for sanity */
  485: 			if (slen < sizeof(struct sockaddr_in) ||
  486: 			    slen > sizeof(struct sockaddr))
  487: 				return 0; /* should not happen */
  488: 
  489: 			if (sd->peer.ss_family &&
  490: 			    sd->peer.ss_family != from.sa_family)
  491: 				return 0; /* bad family */
  492: 
  493: 			/* save packet from */
  494: 			memcpy(&sd->from, &from, slen);
  495: 		} else	memset(&sd->from, 0, sizeof(sd->from));
  496: 
  497: 	} else { /* XXX other session types must be added here */
  498: 		errno = ESOCKTNOSUPPORT;
  499: 		return -1;
  500: 	}
  501: 
  502: 	if (rlen < 1) {
  503: 		if (!rlen || !errno)
  504: 			errno = ECONNRESET;
  505: 		return -1;
  506: 	}
  507: 
  508: 	if (sd->type == PlainFile || sd->type == DataSequence) {
  509: 		if (!sd->sid || sd->sock == -1)
  510: 			return 0;
  511: 		if (sd->read_data)
  512: 			(*sd->read_data)(sd, (u_char *)buf, rlen);
  513: 
  514: 	} else { /* TextStream */
  515: 		buf[rest + rlen] = '\0';
  516: 		for (cp = buf; (line = strchr(cp, '\n')) != 0; cp = line) {
  517: 			if (line > cp && line[-1] == '\r') line[-1] = '\0';
  518: 			*line++ = '\0';
  519: 			if (!sd->sid || sd->sock == -1)
  520: 				return 0;
  521: 			if (sd->read_data) {
  522: 				rest = strlen(cp);
  523: 				if (rest > MAX_STR_LEN) {
  524: 					errno = EMSGSIZE;
  525: 					return -1;
  526: 				}
  527: 				(*sd->read_data)(sd, (u_char *)cp, rest);
  528: 			}
  529: 		}
  530: 		if (cp && *cp) { /* truncated line, save it for next read */
  531: 			if (strlen(cp) > MAX_STR_LEN) {
  532: 				errno = EMSGSIZE;
  533: 				return -1;
  534: 			}
  535: 			sd->buf = strdup(cp);
  536: 		}
  537: 	}
  538: 	return rlen;
  539: }
  540: 
  541: int
  542: session_select(nfds, readfds, writefds, timeout, block)
  543: 	int *nfds;
  544: 	fd_set *readfds, *writefds;
  545: 	struct timeval *timeout;
  546: 	int *block;
  547: {
  548: 	SESSION *sd;
  549: 	struct timeval earliest, now;
  550: 	int active = 0, pending = 0;
  551: 
  552: 	timerclear(&earliest);
  553: 
  554: 	/*
  555: 	 * For each request outstanding, add it's socket to the readfds,
  556: 	 * and if it is the earliest timeout to expire, mark it as lowest.
  557: 	 */
  558: 	for (sd = first_session; sd; sd = sd->next) {
  559: 		if (!sd->sid || sd->sock == -1) {
  560: 			if (sd->sock != -1) /* lost session? free socket */
  561: 				session_stop(sd);
  562: 			continue;
  563: 		}
  564: 
  565: 		active++;
  566: 		if (sd->sock + 1 > *nfds)
  567: 			*nfds = sd->sock + 1;
  568: 
  569: 		if (!sd->connected) {
  570: 			FD_SET(sd->sock, readfds);
  571: 
  572: 			dprintf(("session_select: sock %d set for read", sd->sock));
  573: 		} else {
  574: 			FD_SET(sd->sock, writefds);
  575: 
  576: 			dprintf(("session_select: sock %d set for write", sd->sock));
  577: 		}
  578: 
  579: 		if (timerisset(&sd->expire)) {
  580: 			pending++;
  581: 			if (!timerisset(&earliest) ||
  582: 			    timercmp(&sd->expire, &earliest, <))
  583: 				earliest = sd->expire;
  584: 		}
  585: 	}
  586: 
  587: 	/*dprintf(("session_select: active=%d pending=%d", active, pending));*/
  588: 
  589: 	if (!pending)
  590: 		return active;
  591: 
  592: 	/*
  593: 	 * Transforms earliest from an absolute time into a delta time, the
  594: 	 * time left until the select should timeout.
  595: 	 */
  596: 	gettimeofday(&now, 0);
  597: 	tv_sub(&earliest, &now);
  598: 
  599: 	/* if it was blocking before or our delta time is less, reset timeout */
  600: 	if (*block || timercmp(&earliest, timeout, <)) {
  601: 		*timeout = earliest;
  602: 		*block = 0;
  603: 	}
  604: 	return active;
  605: }
  606: 
  607: /*
  608:  * Checks to see if any of the fd's set in the readfds belong to a session.
  609:  */
  610: void
  611: session_operate(readfds, writefds)
  612: 	fd_set *readfds, *writefds;
  613: {
  614: 	SESSION *sd;
  615: 	int try_conn, error;
  616: 
  617: 	for (sd = first_session; sd; sd = sd->next) {
  618: 		if (!sd->sid || sd->sock == -1)
  619: 			continue;
  620: 
  621: 		try_conn = (sd->connected != 0);
  622: 
  623: 		if (!try_conn && FD_ISSET(sd->sock, readfds)) {
  624: 
  625: 			dprintf(("session_operate: sock %d ready to read", sd->sock));
  626: 
  627: 			if (sd->type == PlainFile)
  628: 				error = 0;
  629: 			else	error = socket_error(sd->sock);
  630: 
  631: 			if (!error && session_read(sd) < 0)
  632: 				error = errno;
  633: 			if (error && sd->sid && sd->read_error)
  634: 				(*sd->read_error)(sd, error);
  635: 		}
  636: 
  637: 		if (try_conn && FD_ISSET(sd->sock, writefds)) {
  638: 
  639: 			dprintf(("session_operate: sock %d ready to write", sd->sock));
  640: 
  641: 			error = socket_error(sd->sock);
  642: 			if (!error) {
  643: 				socket_peer((struct sockaddr *)&sd->peer, sd->sock);
  644: 				socket_nonblock(sd->sock, 0);
  645: 				if (sd->type == TextStream)
  646: 					socket_keepalive(sd->sock, 1);
  647: 				if (sd->sid && sd->connected)
  648: 					(*sd->connected)(sd);
  649: 				sd->connected = 0; /* fire a shot only once! */
  650: 			} else if (sd->sid && sd->read_error)
  651: 				(*sd->read_error)(sd, error);
  652: 		}
  653: 	}
  654: }
  655: 
  656: /*
  657:  * Checks to see if any of the sessions have an outstanding request
  658:  * that has timed out.
  659:  */
  660: void
  661: session_timeout()
  662: {
  663: 	SESSION *sd;
  664: 	struct timeval now;
  665: 
  666: 	gettimeofday(&now, 0);
  667: 
  668: 	for (sd = first_session; sd; sd = sd->next) {
  669: 		if (!sd->sid || sd->sock == -1)
  670: 			continue;
  671: 
  672: 		if (timerisset(&sd->expire) && timercmp(&sd->expire, &now, <)) {
  673: 			if (sd->read_error) (*sd->read_error)(sd, ETIMEDOUT);
  674: 		}
  675: 	}
  676: }
  677: 
  678: /*
  679:  * Return session peer pointer.
  680:  */
  681: const struct sockaddr *
  682: session_peer(sd)
  683: 	SESSION *sd;
  684: {
  685: 	return ((sd && sd->peer.ss_family) ? (struct sockaddr *)&sd->peer : 0);
  686: }
  687: 
  688: /*
  689:  * Return session from pointer.
  690:  */
  691: const struct sockaddr *
  692: session_from(sd)
  693: 	SESSION *sd;
  694: {
  695: 	return ((sd && sd->from.ss_family) ? (struct sockaddr *)&sd->from : 0);
  696: }
  697: 
  698: /*
  699:  * Return connected socket peer ip address and port.
  700:  */
  701: int
  702: socket_peer(peer, sock)
  703: 	struct sockaddr *peer;
  704: 	int sock;
  705: {
  706: 	socklen_t arglen;
  707: 
  708: 	if (!peer) {
  709: 		errno = EINVAL;
  710: 		return -1;
  711: 	}
  712: 	arglen = sizeof(struct sockaddr);
  713: 	return getpeername(sock, peer, &arglen);
  714: }
  715: 
  716: /*
  717:  * Return socket name ip address and port.
  718:  */
  719: int
  720: socket_name(name, sock)
  721: 	struct sockaddr *name;
  722: 	int sock;
  723: {
  724: 	socklen_t arglen;
  725: 
  726: 	if (!name) {
  727: 		errno = EINVAL;
  728: 		return -1;
  729: 	}
  730: 	arglen = sizeof(*name);
  731: 	return getsockname(sock, name, &arglen);
  732: }
  733: 
  734: /*
  735:  * Return socket error (like errno) in the session or 0 if no errors.
  736:  */
  737: int
  738: socket_error(sock)
  739: 	int sock;
  740: {
  741: 	int argbuf;
  742: 	socklen_t arglen;
  743: 	struct sockaddr peer;
  744: 
  745: 	arglen = sizeof(argbuf);
  746: 	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &argbuf, &arglen) < 0)
  747: 		return errno;
  748: 	if (argbuf)
  749: 		return argbuf;
  750: 
  751: 	arglen = sizeof(argbuf);
  752: 	if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &argbuf, &arglen) < 0)
  753: 		return errno;
  754: 	if (argbuf == SOCK_STREAM) {
  755: 		arglen = sizeof(peer);
  756: 		if (getpeername(sock, &peer, &arglen) < 0)
  757: 			return errno;
  758: 	}
  759: 	return 0;
  760: }
  761: 
  762: /*
  763:  * Make socket blocked or non-blocked for sync/async I/O.
  764:  */
  765: int
  766: socket_nonblock(sock, on)
  767: 	int sock;
  768: 	int on; /* boolean */
  769: {
  770: 	int mode;
  771: 	int prev; /* boolean */
  772: 
  773: 	/* get current value of I/O mode */
  774: 	if ((mode = fcntl(sock, F_GETFL, 0)) < 0)
  775: 		return -1;
  776: 
  777: 	prev = (mode & ASYNC_MODE) != 0;
  778: 	if (on != prev) {
  779: 		if (on)	mode |= ASYNC_MODE;
  780: 		else	mode &= ~ASYNC_MODE;
  781: 		if (fcntl(sock, F_SETFL, mode))
  782: 			return -1;
  783: 	}
  784: 	return prev;
  785: }
  786: 
  787: int
  788: socket_keepalive(sock, on)
  789: 	int sock, on;
  790: {
  791: #ifdef  SO_KEEPALIVE
  792: 	int curr = 0;
  793: 	socklen_t slen = sizeof(curr);
  794: 	if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &curr, &slen) < 0)
  795: 		return -1;
  796: 
  797: 	curr = (curr != 0);
  798: 	if (on != curr) {
  799: 		if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
  800: 			return -1;
  801: 	}
  802: 	return 0;
  803: #else
  804: 	errno = ESOCKTNOSUPPORT;
  805: 	return -1;
  806: #endif
  807: }
  808: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>