File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgt_sock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:42:02 2012 UTC (12 years, 5 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20111008, HEAD
istgt

    1: /*
    2:  * Copyright (C) 2008-2010 Daisuke Aoyama <aoyama@peach.ne.jp>.
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  */
   27: 
   28: #ifdef HAVE_CONFIG_H
   29: #include "config.h"
   30: #endif
   31: 
   32: #include <errno.h>
   33: #include <stdio.h>
   34: #include <string.h>
   35: #include <unistd.h>
   36: #include <poll.h>
   37: #include <sys/types.h>
   38: #include <sys/socket.h>
   39: #include <netdb.h>
   40: #include <netinet/in.h>
   41: #include <netinet/tcp.h>
   42: 
   43: #include "istgt.h"
   44: #include "istgt_sock.h"
   45: #include "istgt_misc.h"
   46: 
   47: //#define USE_POLLWAIT
   48: #undef USE_POLLWAIT
   49: #define TIMEOUT_RW 60
   50: #define POLLWAIT 1000
   51: #define PORTNUMLEN 32
   52: 
   53: #ifndef AI_NUMERICSERV
   54: #define AI_NUMERICSERV 0
   55: #endif
   56: 
   57: int
   58: istgt_getaddr(int sock, char *saddr, int slen, char *caddr, int clen)
   59: {
   60: 	struct sockaddr_storage sa;
   61: 	socklen_t salen;
   62: 	int rc;
   63: 
   64: 	memset(&sa, 0, sizeof sa);
   65: 	salen = sizeof sa;
   66: 	rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
   67: 	if (rc != 0) {
   68: 		return -1;
   69: 	}
   70: 	rc = getnameinfo((struct sockaddr *) &sa, salen,
   71: 					 saddr, slen, NULL, 0, NI_NUMERICHOST);
   72: 	if (rc != 0) {
   73: 		return -1;
   74: 	}
   75: 
   76: 	memset(&sa, 0, sizeof sa);
   77: 	salen = sizeof sa;
   78: 	rc = getpeername(sock, (struct sockaddr *) &sa, &salen);
   79: 	if (rc != 0) {
   80: 		return -1;
   81: 	}
   82: 	rc = getnameinfo((struct sockaddr *) &sa, salen,
   83: 					 caddr, clen, NULL, 0, NI_NUMERICHOST);
   84: 	if (rc != 0) {
   85: 		return -1;
   86: 	}
   87: 
   88: 	return 0;
   89: }
   90: 
   91: int
   92: istgt_listen(const char *ip, int port)
   93: {
   94: 	char buf[MAX_TMPBUF];
   95: 	char portnum[PORTNUMLEN];
   96: 	char *p;
   97: 	struct addrinfo hints, *res, *res0;
   98: 	int sock;
   99: 	int val = 1;
  100: 	int rc;
  101: 
  102: 	if (ip == NULL)
  103: 		return -1;
  104: 	if (ip[0] == '[') {
  105: 		strlcpy(buf, ip + 1, sizeof buf);
  106: 		p = strchr(buf, ']');
  107: 		if (p != NULL)
  108: 			*p = '\0';
  109: 		ip = (const char *) &buf[0];
  110: 		if (strcasecmp(ip, "*") == 0) {
  111: 			strlcpy(buf, "::", sizeof buf);
  112: 			ip = (const char *) &buf[0];
  113: 		}
  114: 	} else {
  115: 		if (strcasecmp(ip, "*") == 0) {
  116: 			strlcpy(buf, "0.0.0.0", sizeof buf);
  117: 			ip = (const char *) &buf[0];
  118: 		}
  119: 	}
  120: 	snprintf(portnum, sizeof portnum, "%d", port);
  121: 	memset(&hints, 0, sizeof hints);
  122: 	hints.ai_family = PF_UNSPEC;
  123: 	hints.ai_socktype = SOCK_STREAM;
  124: 	hints.ai_flags = AI_NUMERICSERV;
  125: 	hints.ai_flags |= AI_PASSIVE;
  126: 	hints.ai_flags |= AI_NUMERICHOST;
  127: 	rc = getaddrinfo(ip, portnum, &hints, &res0);
  128: 	if (rc != 0) {
  129: 		return -1;
  130: 	}
  131: 
  132: 	/* try listen */
  133: 	sock = -1;
  134: 	for (res = res0; res != NULL; res = res->ai_next) {
  135: 	retry:
  136: 		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  137: 		if (sock < 0) {
  138: 			/* error */
  139: 			continue;
  140: 		}
  141: 		rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
  142: 		if (rc != 0) {
  143: 			/* error */
  144: 			continue;
  145: 		}
  146: 		rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
  147: 		if (rc != 0) {
  148: 			/* error */
  149: 			continue;
  150: 		}
  151: 		rc = bind(sock, res->ai_addr, res->ai_addrlen);
  152: 		if (rc == -1 && errno == EINTR) {
  153: 			/* interrupted? */
  154: 			close(sock);
  155: 			sock = -1;
  156: 			goto retry;
  157: 		}
  158: 		if (rc != 0) {
  159: 			/* try next family */
  160: 			close(sock);
  161: 			sock = -1;
  162: 			continue;
  163: 		}
  164: 		/* bind OK */
  165: 		rc = listen(sock, 2);
  166: 		if (rc != 0) {
  167: 			close(sock);
  168: 			sock = -1;
  169: 			break;
  170: 		}
  171: 		break;
  172: 	}
  173: 	freeaddrinfo(res0);
  174: 
  175: 	if (sock < 0) {
  176: 		return -1;
  177: 	}
  178: 	return sock;
  179: }
  180: 
  181: int
  182: istgt_connect(const char *host, int port)
  183: {
  184: 	char buf[MAX_TMPBUF];
  185: 	char portnum[PORTNUMLEN];
  186: 	char *p;
  187: 	struct addrinfo hints, *res, *res0;
  188: 	int sock;
  189: 	int val = 1;
  190: 	int rc;
  191: 
  192: 	if (host == NULL)
  193: 		return -1;
  194: 	if (host[0] == '[') {
  195: 		strlcpy(buf, host + 1, sizeof buf);
  196: 		p = strchr(buf, ']');
  197: 		if (p != NULL)
  198: 			*p = '\0';
  199: 		host = (const char *) &buf[0];
  200: 		if (strcasecmp(host, "*") == 0) {
  201: 			strlcpy(buf, "::", sizeof buf);
  202: 			host = (const char *) &buf[0];
  203: 		}
  204: 	} else {
  205: 		if (strcasecmp(host, "*") == 0) {
  206: 			strlcpy(buf, "0.0.0.0", sizeof buf);
  207: 			host = (const char *) &buf[0];
  208: 		}
  209: 	}
  210: 	snprintf(portnum, sizeof portnum, "%d", port);
  211: 	memset(&hints, 0, sizeof hints);
  212: 	hints.ai_family = PF_UNSPEC;
  213: 	hints.ai_socktype = SOCK_STREAM;
  214: 	hints.ai_flags = AI_NUMERICSERV;
  215: 	rc = getaddrinfo(host, portnum, &hints, &res0);
  216: 	if (rc != 0) {
  217: 		return -1;
  218: 	}
  219: 
  220: 	/* try connect */
  221: 	sock = -1;
  222: 	for (res = res0; res != NULL; res = res->ai_next) {
  223: 	retry:
  224: 		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  225: 		if (sock < 0) {
  226: 			/* error */
  227: 			continue;
  228: 		}
  229: 		rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
  230: 		if (rc != 0) {
  231: 			/* error */
  232: 			continue;
  233: 		}
  234: 		rc = connect(sock, res->ai_addr, res->ai_addrlen);
  235: 		if (rc == -1 && errno == EINTR) {
  236: 			/* interrupted? */
  237: 			close(sock);
  238: 			sock = -1;
  239: 			goto retry;
  240: 		}
  241: 		if (rc != 0) {
  242: 			/* try next family */
  243: 			close(sock);
  244: 			sock = -1;
  245: 			continue;
  246: 		}
  247: 		/* connect OK */
  248: 		break;
  249: 	}
  250: 	freeaddrinfo(res0);
  251: 
  252: 	if (sock < 0) {
  253: 		return -1;
  254: 	}
  255: 	return sock;
  256: }
  257: 
  258: int
  259: istgt_set_recvtimeout(int s, int msec)
  260: {
  261: 	struct timeval tv;
  262: 	int rc;
  263: 
  264: 	memset(&tv, 0, sizeof tv);
  265: 	tv.tv_sec = msec / 1000;
  266: 	tv.tv_usec = (msec % 1000) * 1000;
  267: 	rc = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
  268: 	if (rc != 0)
  269: 		return -1;
  270: 	return 0;
  271: }
  272: 
  273: int
  274: istgt_set_sendtimeout(int s, int msec)
  275: {
  276: 	struct timeval tv;
  277: 	int rc;
  278: 
  279: 	memset(&tv, 0, sizeof tv);
  280: 	tv.tv_sec = msec / 1000;
  281: 	tv.tv_usec = (msec % 1000) * 1000;
  282: 	rc = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  283: 	if (rc != 0)
  284: 		return -1;
  285: 	return 0;
  286: }
  287: 
  288: #ifdef USE_POLLWAIT
  289: static int
  290: can_read_socket(int s, int msec)
  291: {
  292: 	struct pollfd fds[1];
  293: 	int rc;
  294: 
  295: 	fds[0].fd = s;
  296: 	fds[0].events = POLLIN;
  297:  retry:
  298: 	do {
  299: 		rc = poll(fds, 1, msec);
  300: 	} while (rc == -1 && errno == EINTR);
  301: 	if (rc == -1 && errno == EAGAIN) {
  302: 		goto retry;
  303: 	}
  304: 	if (rc < 0) {
  305: 		/* error */
  306: 		return -1;
  307: 	}
  308: 	if (fds[0].revents & POLLIN) {
  309: 		/* read OK */
  310: 		return 1;
  311: 	}
  312: 	return 0;
  313: }
  314: 
  315: static int
  316: can_write_socket(int s, int msec)
  317: {
  318: 	struct pollfd fds[1];
  319: 	int rc;
  320: 
  321: 	fds[0].fd = s;
  322: 	fds[0].events = POLLOUT;
  323:  retry:
  324: 	do {
  325: 		rc = poll(fds, 1, msec);
  326: 	} while (rc == -1 && errno == EINTR);
  327: 	if (rc == -1 && errno == EAGAIN) {
  328: 		goto retry;
  329: 	}
  330: 	if (rc < 0) {
  331: 		/* error */
  332: 		return -1;
  333: 	}
  334: 	if (fds[0].revents & POLLOUT) {
  335: 		/* write OK */
  336: 		return 1;
  337: 	}
  338: 	return 0;
  339: }
  340: #endif /* USE_POLLWAIT */
  341: 
  342: ssize_t
  343: istgt_read_socket(int s, void *buf, size_t nbytes, int timeout)
  344: {
  345: 	ssize_t n;
  346: #ifdef USE_POLLWAIT
  347: 	int msec = POLLWAIT;
  348: 	int rc;
  349: #endif /* USE_POLLWAIT */
  350: 
  351: 	if (nbytes == 0)
  352: 		return 0;
  353: 
  354: #ifdef USE_POLLWAIT
  355: 	msec = timeout * 1000;
  356: 	rc = can_read_socket(s, msec);
  357: 	if (rc < 0) {
  358: 		return -1;
  359: 	}
  360: 	if (rc == 0) {
  361: 		/* TIMEOUT */
  362: 		return -2;
  363: 	}
  364:  retry:
  365: 	do {
  366: 		n = read(s, buf, nbytes);
  367: 	} while (n == -1 && errno == EINTR);
  368: 	if (n == -1 && errno == EAGAIN) {
  369: 		goto retry;
  370: 	}
  371: 	if (n < 0) {
  372: 		return -1;
  373: 	}
  374: #else
  375: 	do {
  376: 		n = recv(s, buf, nbytes, 0);
  377: 	} while (n == -1 && errno == EINTR);
  378: 	if (n == -1 && errno == EAGAIN) {
  379: 		/* TIMEOUT */
  380: 		return -2;
  381: 	}
  382: 	if (n == -1) {
  383: 		return -1;
  384: 	}
  385: #endif /* USE_POLLWAIT */
  386: 	return n;
  387: }
  388: 
  389: ssize_t
  390: istgt_write_socket(int s, const void *buf, size_t nbytes, int timeout)
  391: {
  392: 	ssize_t n;
  393: #ifdef USE_POLLWAIT
  394: 	int msec = POLLWAIT;
  395: 	int rc;
  396: #endif /* USE_POLLWAIT */
  397: 
  398: 	if (nbytes == 0)
  399: 		return 0;
  400: 
  401: #ifdef USE_POLLWAIT
  402: 	msec = timeout * 1000;
  403: 	rc = can_write_socket(s, msec);
  404: 	if (rc < 0) {
  405: 		return -1;
  406: 	}
  407: 	if (rc == 0) {
  408: 		/* TIMEOUT */
  409: 		return -2;
  410: 	}
  411:  retry:
  412: 	do {
  413: 		n = write(s, buf, nbytes);
  414: 	} while (n == -1 && errno == EINTR);
  415: 	if (n == -1 && errno == EAGAIN) {
  416: 		goto retry;
  417: 	}
  418: 	if (n < 0) {
  419: 		return -1;
  420: 	}
  421: #else
  422: 	do {
  423: 		n = send(s, buf, nbytes, 0);
  424: 	} while (n == -1 && (errno == EINTR || errno == EAGAIN));
  425: 	if (n == -1) {
  426: 		return -1;
  427: 	}
  428: #endif /* USE_POLLWAIT */
  429: 	return n;
  430: }
  431: 
  432: ssize_t
  433: istgt_readline_socket(int sock, char *buf, size_t size, char *tmp, size_t tmpsize, int *tmpidx, int *tmpcnt, int timeout)
  434: {
  435: 	unsigned char *up, *utp;
  436: 	ssize_t maxsize;
  437: 	ssize_t total;
  438: 	ssize_t n;
  439: 	int got_cr;
  440: 	int idx, cnt;
  441: 	int ch;
  442: 
  443: 	if (size < 2) {
  444: 		return -1;
  445: 	}
  446: 
  447: 	up = (unsigned char *) buf;
  448: 	utp = (unsigned char *) tmp;
  449: 	maxsize = size - 2; /* LF + NUL */
  450: 	total = 0;
  451: 	idx = *tmpidx;
  452: 	cnt = *tmpcnt;
  453: 	got_cr = 0;
  454: 
  455: 	/* receive with LF */
  456: 	while (total < maxsize) {
  457: 		/* fill temporary buffer */
  458: 		if (idx == cnt) {
  459: 			*tmpidx = idx;
  460: 			up[total] = '\0';
  461: 			n = istgt_read_socket(sock, tmp, tmpsize, timeout);
  462: 			if (n < 0) {
  463: 				if (total != 0) {
  464: 					up[total] = '\0';
  465: 					return total;
  466: 				}
  467: 				return -1;
  468: 			}
  469: 			if (n == 0) {
  470: 				/* EOF */
  471: 				up[total] = '\0';
  472: 				return total;
  473: 			}
  474: 			/* got n bytes */
  475: 			cnt = *tmpcnt = n;
  476: 			idx = 0;
  477: 		}
  478: 
  479: 		/* copy from temporary until LF */
  480: 		ch = utp[idx++];
  481: 		if (got_cr && ch != '\n') {
  482: 			/* CR only */
  483: 			/* back to temporary */
  484: 			idx--;
  485: 			/* remove CR */
  486: 			total--;
  487: 			break;
  488: 		} else if (ch == '\n') {
  489: 			if (got_cr) {
  490: 				/* CRLF */
  491: 				/* remove CR */
  492: 				total--;
  493: 			} else {
  494: 				/* LF only */
  495: 			}
  496: 			break;
  497: 		} else if (ch == '\r') {
  498: 			got_cr = 1;
  499: 		}
  500: 		up[total++] = ch;
  501: 	}
  502: 	*tmpidx = idx;
  503: 	/* always append LF + NUL */
  504: 	up[total++] = '\n';
  505: 	up[total] = '\0';
  506: 	return total;
  507: }
  508: 
  509: static ssize_t
  510: istgt_allwrite_socket(int s, const void *buf, size_t nbytes, int timeout)
  511: {
  512: 	const uint8_t *cp;
  513: 	size_t total;
  514: 	ssize_t n;
  515: 
  516: 	total = 0;
  517: 	cp = (const uint8_t *) buf;
  518: 	do {
  519: 		n = istgt_write_socket(s, cp + total, (nbytes - total), timeout);
  520: 		if (n < 0) {
  521: 			return n;
  522: 		}
  523: 		total += n;
  524: 	} while (total < nbytes);
  525: 	return total;
  526: }
  527: 
  528: ssize_t
  529: istgt_writeline_socket(int sock, const char *buf, int timeout)
  530: {
  531: 	const unsigned char *up;
  532: 	ssize_t total;
  533: 	ssize_t n;
  534: 	int idx;
  535: 	int ch;
  536: 
  537: 	up = (const unsigned char *) buf;
  538: 	total = 0;
  539: 	idx = 0;
  540: 
  541: 	if (up[0] == '\0') {
  542: 		/* empty string */
  543: 		n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  544: 		if (n < 0) {
  545: 			return -1;
  546: 		}
  547: 		if (n != 2) {
  548: 			return -1;
  549: 		}
  550: 		total = n;
  551: 		return total;
  552: 	}
  553: 
  554: 	/* send with CRLF */
  555: 	while ((ch = up[idx]) != '\0') {
  556: 		if (ch == '\r') {
  557: 			if (up[idx + 1] == '\n') {
  558: 				/* CRLF */
  559: 				n = istgt_allwrite_socket(sock, up, idx + 2, timeout);
  560: 				if (n < 0) {
  561: 					return -1;
  562: 				}
  563: 				if (n != idx + 2) {
  564: 					return -1;
  565: 				}
  566: 				idx += 2;
  567: 			} else {
  568: 				/* CR Only */
  569: 				n = istgt_allwrite_socket(sock, up, idx, timeout);
  570: 				if (n < 0) {
  571: 					return -1;
  572: 				}
  573: 				if (n != idx) {
  574: 					return -1;
  575: 				}
  576: 				idx += 1;
  577: 				n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  578: 				if (n < 0) {
  579: 					return -1;
  580: 				}
  581: 				if (n != 2) {
  582: 					return -1;
  583: 				}
  584: 			}
  585: 		} else if (ch == '\n') {
  586: 			/* LF Only */
  587: 			n = istgt_allwrite_socket(sock, up, idx, timeout);
  588: 			if (n < 0) {
  589: 				return -1;
  590: 			}
  591: 			if (n != idx) {
  592: 				return -1;
  593: 			}
  594: 			idx += 1;
  595: 			n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  596: 			if (n < 0) {
  597: 				return -1;
  598: 			}
  599: 			if (n != 2) {
  600: 				return -1;
  601: 			}
  602: 		} else {
  603: 			idx++;
  604: 			continue;
  605: 		}
  606: 		up += idx;
  607: 		total += idx;
  608: 		idx = 0;
  609: 	}
  610: 
  611: 	if (idx != 0) {
  612: 		/* no CRLF string */
  613: 		n = istgt_allwrite_socket(sock, up, idx, timeout);
  614: 		if (n < 0) {
  615: 			return -1;
  616: 		}
  617: 		if (n != idx) {
  618: 			return -1;
  619: 		}
  620: 		n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  621: 		if (n < 0) {
  622: 			return -1;
  623: 		}
  624: 		if (n != 2) {
  625: 			return -1;
  626: 		}
  627: 		up += idx;
  628: 		total += idx + 2;
  629: 		idx = 0;
  630: 	}
  631: 
  632: 	return total;
  633: }

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