File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgt_sock.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:13:23 2012 UTC (11 years, 9 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20120901, HEAD
dhcp 4.1 r7

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

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