Annotation of embedaddon/istgt/src/istgt_sock.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
1.1 misho 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"
1.1.1.3 ! misho 44: #include "istgt_log.h"
1.1 misho 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:
1.1.1.2 misho 58: #if !defined(__GNUC__)
59: #undef __attribute__
60: #define __attribute__(x)
61: #endif
62:
1.1 misho 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) {
1.1.1.3 ! misho 74: ISTGT_ERRLOG("getsockname() failed (errno=%d)\n", errno);
1.1 misho 75: return -1;
76: }
77: rc = getnameinfo((struct sockaddr *) &sa, salen,
1.1.1.2 misho 78: saddr, slen, NULL, 0, NI_NUMERICHOST);
1.1 misho 79: if (rc != 0) {
1.1.1.3 ! misho 80: ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
1.1 misho 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) {
1.1.1.3 ! misho 88: ISTGT_ERRLOG("getpeername() failed (errno=%d)\n", errno);
1.1 misho 89: return -1;
90: }
91: rc = getnameinfo((struct sockaddr *) &sa, salen,
1.1.1.2 misho 92: caddr, clen, NULL, 0, NI_NUMERICHOST);
1.1 misho 93: if (rc != 0) {
1.1.1.3 ! misho 94: ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
1.1 misho 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) {
1.1.1.3 ! misho 139: ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
1.1 misho 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) {
1.1.1.3 ! misho 228: ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
1.1 misho 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:
1.1.1.3 ! misho 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:
1.1 misho 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:
1.1.1.2 misho 367: #ifdef USE_POLLWAIT
368: #define UNUSED_POLLWAIT(x) x
369: #else
370: #define UNUSED_POLLWAIT(x) x __attribute__((__unused__))
371: #endif
372:
1.1 misho 373: ssize_t
1.1.1.2 misho 374: istgt_read_socket(int s, void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
1.1 misho 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
1.1.1.2 misho 421: istgt_write_socket(int s, const void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
1.1 misho 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>