File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgt_sock.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:49:22 2013 UTC (11 years, 8 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20121028, HEAD
20121028

    1: /*
    2:  * Copyright (C) 2008-2012 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_log.h"
   45: #include "istgt_sock.h"
   46: #include "istgt_misc.h"
   47: 
   48: //#define USE_POLLWAIT
   49: #undef USE_POLLWAIT
   50: #define TIMEOUT_RW 60
   51: #define POLLWAIT 1000
   52: #define PORTNUMLEN 32
   53: 
   54: #ifndef AI_NUMERICSERV
   55: #define AI_NUMERICSERV 0
   56: #endif
   57: 
   58: #if !defined(__GNUC__)
   59: #undef __attribute__
   60: #define __attribute__(x)
   61: #endif
   62: 
   63: int
   64: istgt_getaddr(int sock, char *saddr, int slen, char *caddr, int clen)
   65: {
   66: 	struct sockaddr_storage sa;
   67: 	socklen_t salen;
   68: 	int rc;
   69: 
   70: 	memset(&sa, 0, sizeof sa);
   71: 	salen = sizeof sa;
   72: 	rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
   73: 	if (rc != 0) {
   74: 		ISTGT_ERRLOG("getsockname() failed (errno=%d)\n", errno);
   75: 		return -1;
   76: 	}
   77: 	rc = getnameinfo((struct sockaddr *) &sa, salen,
   78: 	    saddr, slen, NULL, 0, NI_NUMERICHOST);
   79: 	if (rc != 0) {
   80: 		ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
   81: 		return -1;
   82: 	}
   83: 
   84: 	memset(&sa, 0, sizeof sa);
   85: 	salen = sizeof sa;
   86: 	rc = getpeername(sock, (struct sockaddr *) &sa, &salen);
   87: 	if (rc != 0) {
   88: 		ISTGT_ERRLOG("getpeername() failed (errno=%d)\n", errno);
   89: 		return -1;
   90: 	}
   91: 	rc = getnameinfo((struct sockaddr *) &sa, salen,
   92: 	    caddr, clen, NULL, 0, NI_NUMERICHOST);
   93: 	if (rc != 0) {
   94: 		ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
   95: 		return -1;
   96: 	}
   97: 
   98: 	return 0;
   99: }
  100: 
  101: int
  102: istgt_listen(const char *ip, int port)
  103: {
  104: 	char buf[MAX_TMPBUF];
  105: 	char portnum[PORTNUMLEN];
  106: 	char *p;
  107: 	struct addrinfo hints, *res, *res0;
  108: 	int sock;
  109: 	int val = 1;
  110: 	int rc;
  111: 
  112: 	if (ip == NULL)
  113: 		return -1;
  114: 	if (ip[0] == '[') {
  115: 		strlcpy(buf, ip + 1, sizeof buf);
  116: 		p = strchr(buf, ']');
  117: 		if (p != NULL)
  118: 			*p = '\0';
  119: 		ip = (const char *) &buf[0];
  120: 		if (strcasecmp(ip, "*") == 0) {
  121: 			strlcpy(buf, "::", sizeof buf);
  122: 			ip = (const char *) &buf[0];
  123: 		}
  124: 	} else {
  125: 		if (strcasecmp(ip, "*") == 0) {
  126: 			strlcpy(buf, "0.0.0.0", sizeof buf);
  127: 			ip = (const char *) &buf[0];
  128: 		}
  129: 	}
  130: 	snprintf(portnum, sizeof portnum, "%d", port);
  131: 	memset(&hints, 0, sizeof hints);
  132: 	hints.ai_family = PF_UNSPEC;
  133: 	hints.ai_socktype = SOCK_STREAM;
  134: 	hints.ai_flags = AI_NUMERICSERV;
  135: 	hints.ai_flags |= AI_PASSIVE;
  136: 	hints.ai_flags |= AI_NUMERICHOST;
  137: 	rc = getaddrinfo(ip, portnum, &hints, &res0);
  138: 	if (rc != 0) {
  139: 		ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
  140: 		return -1;
  141: 	}
  142: 
  143: 	/* try listen */
  144: 	sock = -1;
  145: 	for (res = res0; res != NULL; res = res->ai_next) {
  146: 	retry:
  147: 		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  148: 		if (sock < 0) {
  149: 			/* error */
  150: 			continue;
  151: 		}
  152: 		rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
  153: 		if (rc != 0) {
  154: 			/* error */
  155: 			continue;
  156: 		}
  157: 		rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
  158: 		if (rc != 0) {
  159: 			/* error */
  160: 			continue;
  161: 		}
  162: 		rc = bind(sock, res->ai_addr, res->ai_addrlen);
  163: 		if (rc == -1 && errno == EINTR) {
  164: 			/* interrupted? */
  165: 			close(sock);
  166: 			sock = -1;
  167: 			goto retry;
  168: 		}
  169: 		if (rc != 0) {
  170: 			/* try next family */
  171: 			close(sock);
  172: 			sock = -1;
  173: 			continue;
  174: 		}
  175: 		/* bind OK */
  176: 		rc = listen(sock, 2);
  177: 		if (rc != 0) {
  178: 			close(sock);
  179: 			sock = -1;
  180: 			break;
  181: 		}
  182: 		break;
  183: 	}
  184: 	freeaddrinfo(res0);
  185: 
  186: 	if (sock < 0) {
  187: 		return -1;
  188: 	}
  189: 	return sock;
  190: }
  191: 
  192: int
  193: istgt_connect(const char *host, int port)
  194: {
  195: 	char buf[MAX_TMPBUF];
  196: 	char portnum[PORTNUMLEN];
  197: 	char *p;
  198: 	struct addrinfo hints, *res, *res0;
  199: 	int sock;
  200: 	int val = 1;
  201: 	int rc;
  202: 
  203: 	if (host == NULL)
  204: 		return -1;
  205: 	if (host[0] == '[') {
  206: 		strlcpy(buf, host + 1, sizeof buf);
  207: 		p = strchr(buf, ']');
  208: 		if (p != NULL)
  209: 			*p = '\0';
  210: 		host = (const char *) &buf[0];
  211: 		if (strcasecmp(host, "*") == 0) {
  212: 			strlcpy(buf, "::", sizeof buf);
  213: 			host = (const char *) &buf[0];
  214: 		}
  215: 	} else {
  216: 		if (strcasecmp(host, "*") == 0) {
  217: 			strlcpy(buf, "0.0.0.0", sizeof buf);
  218: 			host = (const char *) &buf[0];
  219: 		}
  220: 	}
  221: 	snprintf(portnum, sizeof portnum, "%d", port);
  222: 	memset(&hints, 0, sizeof hints);
  223: 	hints.ai_family = PF_UNSPEC;
  224: 	hints.ai_socktype = SOCK_STREAM;
  225: 	hints.ai_flags = AI_NUMERICSERV;
  226: 	rc = getaddrinfo(host, portnum, &hints, &res0);
  227: 	if (rc != 0) {
  228: 		ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
  229: 		return -1;
  230: 	}
  231: 
  232: 	/* try connect */
  233: 	sock = -1;
  234: 	for (res = res0; res != NULL; res = res->ai_next) {
  235: 	retry:
  236: 		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  237: 		if (sock < 0) {
  238: 			/* error */
  239: 			continue;
  240: 		}
  241: 		rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
  242: 		if (rc != 0) {
  243: 			/* error */
  244: 			continue;
  245: 		}
  246: 		rc = connect(sock, res->ai_addr, res->ai_addrlen);
  247: 		if (rc == -1 && errno == EINTR) {
  248: 			/* interrupted? */
  249: 			close(sock);
  250: 			sock = -1;
  251: 			goto retry;
  252: 		}
  253: 		if (rc != 0) {
  254: 			/* try next family */
  255: 			close(sock);
  256: 			sock = -1;
  257: 			continue;
  258: 		}
  259: 		/* connect OK */
  260: 		break;
  261: 	}
  262: 	freeaddrinfo(res0);
  263: 
  264: 	if (sock < 0) {
  265: 		return -1;
  266: 	}
  267: 	return sock;
  268: }
  269: 
  270: int
  271: istgt_set_recvtimeout(int s, int msec)
  272: {
  273: 	struct timeval tv;
  274: 	int rc;
  275: 
  276: 	memset(&tv, 0, sizeof tv);
  277: 	tv.tv_sec = msec / 1000;
  278: 	tv.tv_usec = (msec % 1000) * 1000;
  279: 	rc = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
  280: 	if (rc != 0)
  281: 		return -1;
  282: 	return 0;
  283: }
  284: 
  285: int
  286: istgt_set_sendtimeout(int s, int msec)
  287: {
  288: 	struct timeval tv;
  289: 	int rc;
  290: 
  291: 	memset(&tv, 0, sizeof tv);
  292: 	tv.tv_sec = msec / 1000;
  293: 	tv.tv_usec = (msec % 1000) * 1000;
  294: 	rc = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  295: 	if (rc != 0)
  296: 		return -1;
  297: 	return 0;
  298: }
  299: 
  300: int
  301: istgt_set_recvlowat(int s, int nbytes)
  302: {
  303: 	int val;
  304: 	int rc;
  305: 
  306: 	val = nbytes;
  307: 	rc = setsockopt(s, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
  308: 	if (rc != 0)
  309: 		return -1;
  310: 	return 0;
  311: }
  312: 
  313: #ifdef USE_POLLWAIT
  314: static int
  315: can_read_socket(int s, int msec)
  316: {
  317: 	struct pollfd fds[1];
  318: 	int rc;
  319: 
  320: 	fds[0].fd = s;
  321: 	fds[0].events = POLLIN;
  322:  retry:
  323: 	do {
  324: 		rc = poll(fds, 1, msec);
  325: 	} while (rc == -1 && errno == EINTR);
  326: 	if (rc == -1 && errno == EAGAIN) {
  327: 		goto retry;
  328: 	}
  329: 	if (rc < 0) {
  330: 		/* error */
  331: 		return -1;
  332: 	}
  333: 	if (fds[0].revents & POLLIN) {
  334: 		/* read OK */
  335: 		return 1;
  336: 	}
  337: 	return 0;
  338: }
  339: 
  340: static int
  341: can_write_socket(int s, int msec)
  342: {
  343: 	struct pollfd fds[1];
  344: 	int rc;
  345: 
  346: 	fds[0].fd = s;
  347: 	fds[0].events = POLLOUT;
  348:  retry:
  349: 	do {
  350: 		rc = poll(fds, 1, msec);
  351: 	} while (rc == -1 && errno == EINTR);
  352: 	if (rc == -1 && errno == EAGAIN) {
  353: 		goto retry;
  354: 	}
  355: 	if (rc < 0) {
  356: 		/* error */
  357: 		return -1;
  358: 	}
  359: 	if (fds[0].revents & POLLOUT) {
  360: 		/* write OK */
  361: 		return 1;
  362: 	}
  363: 	return 0;
  364: }
  365: #endif /* USE_POLLWAIT */
  366: 
  367: #ifdef USE_POLLWAIT
  368: #define UNUSED_POLLWAIT(x) x
  369: #else
  370: #define UNUSED_POLLWAIT(x) x __attribute__((__unused__))
  371: #endif
  372: 
  373: ssize_t
  374: istgt_read_socket(int s, void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
  375: {
  376: 	ssize_t n;
  377: #ifdef USE_POLLWAIT
  378: 	int msec = POLLWAIT;
  379: 	int rc;
  380: #endif /* USE_POLLWAIT */
  381: 
  382: 	if (nbytes == 0)
  383: 		return 0;
  384: 
  385: #ifdef USE_POLLWAIT
  386: 	msec = timeout * 1000;
  387: 	rc = can_read_socket(s, msec);
  388: 	if (rc < 0) {
  389: 		return -1;
  390: 	}
  391: 	if (rc == 0) {
  392: 		/* TIMEOUT */
  393: 		return -2;
  394: 	}
  395:  retry:
  396: 	do {
  397: 		n = read(s, buf, nbytes);
  398: 	} while (n == -1 && errno == EINTR);
  399: 	if (n == -1 && errno == EAGAIN) {
  400: 		goto retry;
  401: 	}
  402: 	if (n < 0) {
  403: 		return -1;
  404: 	}
  405: #else
  406: 	do {
  407: 		n = recv(s, buf, nbytes, 0);
  408: 	} while (n == -1 && errno == EINTR);
  409: 	if (n == -1 && errno == EAGAIN) {
  410: 		/* TIMEOUT */
  411: 		return -2;
  412: 	}
  413: 	if (n == -1) {
  414: 		return -1;
  415: 	}
  416: #endif /* USE_POLLWAIT */
  417: 	return n;
  418: }
  419: 
  420: ssize_t
  421: istgt_write_socket(int s, const void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
  422: {
  423: 	ssize_t n;
  424: #ifdef USE_POLLWAIT
  425: 	int msec = POLLWAIT;
  426: 	int rc;
  427: #endif /* USE_POLLWAIT */
  428: 
  429: 	if (nbytes == 0)
  430: 		return 0;
  431: 
  432: #ifdef USE_POLLWAIT
  433: 	msec = timeout * 1000;
  434: 	rc = can_write_socket(s, msec);
  435: 	if (rc < 0) {
  436: 		return -1;
  437: 	}
  438: 	if (rc == 0) {
  439: 		/* TIMEOUT */
  440: 		return -2;
  441: 	}
  442:  retry:
  443: 	do {
  444: 		n = write(s, buf, nbytes);
  445: 	} while (n == -1 && errno == EINTR);
  446: 	if (n == -1 && errno == EAGAIN) {
  447: 		goto retry;
  448: 	}
  449: 	if (n < 0) {
  450: 		return -1;
  451: 	}
  452: #else
  453: 	do {
  454: 		n = send(s, buf, nbytes, 0);
  455: 	} while (n == -1 && (errno == EINTR || errno == EAGAIN));
  456: 	if (n == -1) {
  457: 		return -1;
  458: 	}
  459: #endif /* USE_POLLWAIT */
  460: 	return n;
  461: }
  462: 
  463: ssize_t
  464: istgt_readline_socket(int sock, char *buf, size_t size, char *tmp, size_t tmpsize, int *tmpidx, int *tmpcnt, int timeout)
  465: {
  466: 	unsigned char *up, *utp;
  467: 	ssize_t maxsize;
  468: 	ssize_t total;
  469: 	ssize_t n;
  470: 	int got_cr;
  471: 	int idx, cnt;
  472: 	int ch;
  473: 
  474: 	if (size < 2) {
  475: 		return -1;
  476: 	}
  477: 
  478: 	up = (unsigned char *) buf;
  479: 	utp = (unsigned char *) tmp;
  480: 	maxsize = size - 2; /* LF + NUL */
  481: 	total = 0;
  482: 	idx = *tmpidx;
  483: 	cnt = *tmpcnt;
  484: 	got_cr = 0;
  485: 
  486: 	/* receive with LF */
  487: 	while (total < maxsize) {
  488: 		/* fill temporary buffer */
  489: 		if (idx == cnt) {
  490: 			*tmpidx = idx;
  491: 			up[total] = '\0';
  492: 			n = istgt_read_socket(sock, tmp, tmpsize, timeout);
  493: 			if (n < 0) {
  494: 				if (total != 0) {
  495: 					up[total] = '\0';
  496: 					return total;
  497: 				}
  498: 				return -1;
  499: 			}
  500: 			if (n == 0) {
  501: 				/* EOF */
  502: 				up[total] = '\0';
  503: 				return total;
  504: 			}
  505: 			/* got n bytes */
  506: 			cnt = *tmpcnt = n;
  507: 			idx = 0;
  508: 		}
  509: 
  510: 		/* copy from temporary until LF */
  511: 		ch = utp[idx++];
  512: 		if (got_cr && ch != '\n') {
  513: 			/* CR only */
  514: 			/* back to temporary */
  515: 			idx--;
  516: 			/* remove CR */
  517: 			total--;
  518: 			break;
  519: 		} else if (ch == '\n') {
  520: 			if (got_cr) {
  521: 				/* CRLF */
  522: 				/* remove CR */
  523: 				total--;
  524: 			} else {
  525: 				/* LF only */
  526: 			}
  527: 			break;
  528: 		} else if (ch == '\r') {
  529: 			got_cr = 1;
  530: 		}
  531: 		up[total++] = ch;
  532: 	}
  533: 	*tmpidx = idx;
  534: 	/* always append LF + NUL */
  535: 	up[total++] = '\n';
  536: 	up[total] = '\0';
  537: 	return total;
  538: }
  539: 
  540: static ssize_t
  541: istgt_allwrite_socket(int s, const void *buf, size_t nbytes, int timeout)
  542: {
  543: 	const uint8_t *cp;
  544: 	size_t total;
  545: 	ssize_t n;
  546: 
  547: 	total = 0;
  548: 	cp = (const uint8_t *) buf;
  549: 	do {
  550: 		n = istgt_write_socket(s, cp + total, (nbytes - total), timeout);
  551: 		if (n < 0) {
  552: 			return n;
  553: 		}
  554: 		total += n;
  555: 	} while (total < nbytes);
  556: 	return total;
  557: }
  558: 
  559: ssize_t
  560: istgt_writeline_socket(int sock, const char *buf, int timeout)
  561: {
  562: 	const unsigned char *up;
  563: 	ssize_t total;
  564: 	ssize_t n;
  565: 	int idx;
  566: 	int ch;
  567: 
  568: 	up = (const unsigned char *) buf;
  569: 	total = 0;
  570: 	idx = 0;
  571: 
  572: 	if (up[0] == '\0') {
  573: 		/* empty string */
  574: 		n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  575: 		if (n < 0) {
  576: 			return -1;
  577: 		}
  578: 		if (n != 2) {
  579: 			return -1;
  580: 		}
  581: 		total = n;
  582: 		return total;
  583: 	}
  584: 
  585: 	/* send with CRLF */
  586: 	while ((ch = up[idx]) != '\0') {
  587: 		if (ch == '\r') {
  588: 			if (up[idx + 1] == '\n') {
  589: 				/* CRLF */
  590: 				n = istgt_allwrite_socket(sock, up, idx + 2, timeout);
  591: 				if (n < 0) {
  592: 					return -1;
  593: 				}
  594: 				if (n != idx + 2) {
  595: 					return -1;
  596: 				}
  597: 				idx += 2;
  598: 			} else {
  599: 				/* CR Only */
  600: 				n = istgt_allwrite_socket(sock, up, idx, timeout);
  601: 				if (n < 0) {
  602: 					return -1;
  603: 				}
  604: 				if (n != idx) {
  605: 					return -1;
  606: 				}
  607: 				idx += 1;
  608: 				n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  609: 				if (n < 0) {
  610: 					return -1;
  611: 				}
  612: 				if (n != 2) {
  613: 					return -1;
  614: 				}
  615: 			}
  616: 		} else if (ch == '\n') {
  617: 			/* LF Only */
  618: 			n = istgt_allwrite_socket(sock, up, idx, timeout);
  619: 			if (n < 0) {
  620: 				return -1;
  621: 			}
  622: 			if (n != idx) {
  623: 				return -1;
  624: 			}
  625: 			idx += 1;
  626: 			n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  627: 			if (n < 0) {
  628: 				return -1;
  629: 			}
  630: 			if (n != 2) {
  631: 				return -1;
  632: 			}
  633: 		} else {
  634: 			idx++;
  635: 			continue;
  636: 		}
  637: 		up += idx;
  638: 		total += idx;
  639: 		idx = 0;
  640: 	}
  641: 
  642: 	if (idx != 0) {
  643: 		/* no CRLF string */
  644: 		n = istgt_allwrite_socket(sock, up, idx, timeout);
  645: 		if (n < 0) {
  646: 			return -1;
  647: 		}
  648: 		if (n != idx) {
  649: 			return -1;
  650: 		}
  651: 		n = istgt_allwrite_socket(sock, "\r\n", 2, timeout);
  652: 		if (n < 0) {
  653: 			return -1;
  654: 		}
  655: 		if (n != 2) {
  656: 			return -1;
  657: 		}
  658: 		up += idx;
  659: 		total += idx + 2;
  660: 		idx = 0;
  661: 	}
  662: 
  663: 	return total;
  664: }

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