Annotation of embedaddon/istgt/src/istgt_sock.c, revision 1.1.1.1
1.1 misho 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>