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
istgt_getaddr(int sock,char * saddr,int slen,char * caddr,int clen)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
istgt_listen(const char * ip,int port)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, 1);
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
istgt_connect(const char * host,int port)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
istgt_set_recvtimeout(int s,int msec)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
istgt_set_sendtimeout(int s,int msec)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
istgt_set_recvlowat(int s,int nbytes)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
can_read_socket(int s,int msec)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
can_write_socket(int s,int msec)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
istgt_read_socket(int s,void * buf,size_t nbytes,int UNUSED_POLLWAIT (timeout))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
istgt_write_socket(int s,const void * buf,size_t nbytes,int UNUSED_POLLWAIT (timeout))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
istgt_readline_socket(int sock,char * buf,size_t size,char * tmp,size_t tmpsize,int * tmpidx,int * tmpcnt,int timeout)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
istgt_allwrite_socket(int s,const void * buf,size_t nbytes,int timeout)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
istgt_writeline_socket(int sock,const char * buf,int timeout)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 }
665