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