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>