Annotation of embedaddon/istgt/src/istgt_sock.c, revision 1.1.1.2
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"
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:
1.1.1.2 ! misho 57: #if !defined(__GNUC__)
! 58: #undef __attribute__
! 59: #define __attribute__(x)
! 60: #endif
! 61:
1.1 misho 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,
1.1.1.2 ! misho 76: saddr, slen, NULL, 0, NI_NUMERICHOST);
1.1 misho 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,
1.1.1.2 ! misho 88: caddr, clen, NULL, 0, NI_NUMERICHOST);
1.1 misho 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:
1.1.1.2 ! misho 347: #ifdef USE_POLLWAIT
! 348: #define UNUSED_POLLWAIT(x) x
! 349: #else
! 350: #define UNUSED_POLLWAIT(x) x __attribute__((__unused__))
! 351: #endif
! 352:
1.1 misho 353: ssize_t
1.1.1.2 ! misho 354: istgt_read_socket(int s, void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
1.1 misho 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
1.1.1.2 ! misho 401: istgt_write_socket(int s, const void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout))
1.1 misho 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>