Annotation of embedaddon/miniupnpd/miniupnpc/src/connecthostport.c, revision 1.1

1.1     ! misho       1: /* $Id: connecthostport.c,v 1.24 2020/11/09 19:26:53 nanard Exp $ */
        !             2: /* vim: tabstop=4 shiftwidth=4 noexpandtab
        !             3:  * Project : miniupnp
        !             4:  * Author : Thomas Bernard
        !             5:  * Copyright (c) 2010-2020 Thomas Bernard
        !             6:  * This software is subject to the conditions detailed in the
        !             7:  * LICENCE file provided in this distribution. */
        !             8: 
        !             9: /* use getaddrinfo() or gethostbyname()
        !            10:  * uncomment the following line in order to use gethostbyname() */
        !            11: #ifdef NO_GETADDRINFO
        !            12: #define USE_GETHOSTBYNAME
        !            13: #endif
        !            14: 
        !            15: #include <string.h>
        !            16: #include <stdio.h>
        !            17: #ifdef _WIN32
        !            18: #include <winsock2.h>
        !            19: #include <ws2tcpip.h>
        !            20: #include <io.h>
        !            21: #define MAXHOSTNAMELEN 64
        !            22: #include "win32_snprintf.h"
        !            23: #define herror
        !            24: #define socklen_t int
        !            25: #else /* #ifdef _WIN32 */
        !            26: #include <unistd.h>
        !            27: #include <sys/types.h>
        !            28: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !            29: #include <sys/time.h>
        !            30: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
        !            31: #include <sys/param.h>
        !            32: #include <sys/select.h>
        !            33: #include <errno.h>
        !            34: #define closesocket close
        !            35: #include <netdb.h>
        !            36: #include <netinet/in.h>
        !            37: /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
        !            38:  * during the connect() call */
        !            39: #define MINIUPNPC_IGNORE_EINTR
        !            40: #include <sys/socket.h>
        !            41: #include <sys/select.h>
        !            42: #endif /* #else _WIN32 */
        !            43: 
        !            44: #if defined(__amigaos__) || defined(__amigaos4__)
        !            45: #define herror(A) printf("%s\n", A)
        !            46: #endif
        !            47: 
        !            48: #include "connecthostport.h"
        !            49: 
        !            50: #ifndef MAXHOSTNAMELEN
        !            51: #define MAXHOSTNAMELEN 64
        !            52: #endif
        !            53: 
        !            54: /* connecthostport()
        !            55:  * return a socket connected (TCP) to the host and port
        !            56:  * or -1 in case of error */
        !            57: SOCKET connecthostport(const char * host, unsigned short port,
        !            58:                        unsigned int scope_id)
        !            59: {
        !            60:    SOCKET s;
        !            61:    int n;
        !            62: #ifdef USE_GETHOSTBYNAME
        !            63:    struct sockaddr_in dest;
        !            64:    struct hostent *hp;
        !            65: #else /* #ifdef USE_GETHOSTBYNAME */
        !            66:    char tmp_host[MAXHOSTNAMELEN+1];
        !            67:    char port_str[8];
        !            68:    struct addrinfo *ai, *p;
        !            69:    struct addrinfo hints;
        !            70: #endif /* #ifdef USE_GETHOSTBYNAME */
        !            71: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !            72:    struct timeval timeout;
        !            73: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
        !            74: 
        !            75: #ifdef USE_GETHOSTBYNAME
        !            76:    hp = gethostbyname(host);
        !            77:    if(hp == NULL)
        !            78:    {
        !            79:        herror(host);
        !            80:        return INVALID_SOCKET;
        !            81:    }
        !            82:    memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
        !            83:    memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
        !            84:    s = socket(PF_INET, SOCK_STREAM, 0);
        !            85:    if(ISINVALID(s))
        !            86:    {
        !            87:        PRINT_SOCKET_ERROR("socket");
        !            88:        return INVALID_SOCKET;
        !            89:    }
        !            90: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !            91:    /* setting a 3 seconds timeout for the connect() call */
        !            92:    timeout.tv_sec = 3;
        !            93:    timeout.tv_usec = 0;
        !            94:    if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
        !            95:    {
        !            96:        PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO");
        !            97:    }
        !            98:    timeout.tv_sec = 3;
        !            99:    timeout.tv_usec = 0;
        !           100:    if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
        !           101:    {
        !           102:        PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO");
        !           103:    }
        !           104: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
        !           105:    dest.sin_family = AF_INET;
        !           106:    dest.sin_port = htons(port);
        !           107:    n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
        !           108: #ifdef MINIUPNPC_IGNORE_EINTR
        !           109:    /* EINTR The system call was interrupted by a signal that was caught
        !           110:     * EINPROGRESS The socket is nonblocking and the connection cannot
        !           111:     *             be completed immediately. */
        !           112:    while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
        !           113:    {
        !           114:        socklen_t len;
        !           115:        fd_set wset;
        !           116:        int err;
        !           117:        FD_ZERO(&wset);
        !           118:        FD_SET(s, &wset);
        !           119: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !           120:        timeout.tv_sec = 3;
        !           121:        timeout.tv_usec = 0;
        !           122:        n = select(s + 1, NULL, &wset, NULL, &timeout);
        !           123: #else
        !           124:        n = select(s + 1, NULL, &wset, NULL, NULL);
        !           125: #endif
        !           126:        if(n == -1 && errno == EINTR)
        !           127:            continue;
        !           128: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !           129:        if(n == 0) {
        !           130:            errno = ETIMEDOUT;
        !           131:            n = -1;
        !           132:            break;
        !           133:        }
        !           134: #endif
        !           135:        /*len = 0;*/
        !           136:        /*n = getpeername(s, NULL, &len);*/
        !           137:        len = sizeof(err);
        !           138:        if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
        !           139:            PRINT_SOCKET_ERROR("getsockopt");
        !           140:            closesocket(s);
        !           141:            return INVALID_SOCKET;
        !           142:        }
        !           143:        if(err != 0) {
        !           144:            errno = err;
        !           145:            n = -1;
        !           146:        }
        !           147:    }
        !           148: #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
        !           149:    if(n<0)
        !           150:    {
        !           151:        PRINT_SOCKET_ERROR("connect");
        !           152:        closesocket(s);
        !           153:        return INVALID_SOCKET;
        !           154:    }
        !           155: #else /* #ifdef USE_GETHOSTBYNAME */
        !           156:    /* use getaddrinfo() instead of gethostbyname() */
        !           157:    memset(&hints, 0, sizeof(hints));
        !           158:    /* hints.ai_flags = AI_ADDRCONFIG; */
        !           159: #ifdef AI_NUMERICSERV
        !           160:    hints.ai_flags = AI_NUMERICSERV;
        !           161: #endif
        !           162:    hints.ai_socktype = SOCK_STREAM;
        !           163:    hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
        !           164:    /* hints.ai_protocol = IPPROTO_TCP; */
        !           165:    snprintf(port_str, sizeof(port_str), "%hu", port);
        !           166:    if(host[0] == '[')
        !           167:    {
        !           168:        /* literal ip v6 address */
        !           169:        int i, j;
        !           170:        for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
        !           171:        {
        !           172:            tmp_host[i] = host[j];
        !           173:            if(0 == strncmp(host+j, "%25", 3))  /* %25 is just url encoding for '%' */
        !           174:                j+=2;                           /* skip "25" */
        !           175:        }
        !           176:        tmp_host[i] = '\0';
        !           177:    }
        !           178:    else
        !           179:    {
        !           180:        strncpy(tmp_host, host, MAXHOSTNAMELEN);
        !           181:    }
        !           182:    tmp_host[MAXHOSTNAMELEN] = '\0';
        !           183:    n = getaddrinfo(tmp_host, port_str, &hints, &ai);
        !           184:    if(n != 0)
        !           185:    {
        !           186: #ifdef _WIN32
        !           187:        fprintf(stderr, "getaddrinfo() error : %d\n", n);
        !           188: #else
        !           189:        fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
        !           190: #endif
        !           191:        return INVALID_SOCKET;
        !           192:    }
        !           193:    s = INVALID_SOCKET;
        !           194:    for(p = ai; p; p = p->ai_next)
        !           195:    {
        !           196:        if(!ISINVALID(s))
        !           197:            closesocket(s);
        !           198: #ifdef DEBUG
        !           199:        printf("ai_family=%d ai_socktype=%d ai_protocol=%d (PF_INET=%d, PF_INET6=%d)\n",
        !           200:               p->ai_family, p->ai_socktype, p->ai_protocol, PF_INET, PF_INET6);
        !           201: #endif
        !           202:        s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        !           203:        if(ISINVALID(s))
        !           204:            continue;
        !           205:        if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
        !           206:            struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
        !           207:            addr6->sin6_scope_id = scope_id;
        !           208:        }
        !           209: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !           210:        /* setting a 3 seconds timeout for the connect() call */
        !           211:        timeout.tv_sec = 3;
        !           212:        timeout.tv_usec = 0;
        !           213:        if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
        !           214:        {
        !           215:            PRINT_SOCKET_ERROR("setsockopt");
        !           216:        }
        !           217:        timeout.tv_sec = 3;
        !           218:        timeout.tv_usec = 0;
        !           219:        if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
        !           220:        {
        !           221:            PRINT_SOCKET_ERROR("setsockopt");
        !           222:        }
        !           223: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
        !           224:        n = connect(s, p->ai_addr, MSC_CAST_INT p->ai_addrlen);
        !           225: #ifdef MINIUPNPC_IGNORE_EINTR
        !           226:        /* EINTR The system call was interrupted by a signal that was caught
        !           227:         * EINPROGRESS The socket is nonblocking and the connection cannot
        !           228:         *             be completed immediately. */
        !           229:        while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
        !           230:        {
        !           231:            socklen_t len;
        !           232:            fd_set wset;
        !           233:            int err;
        !           234:            FD_ZERO(&wset);
        !           235:            FD_SET(s, &wset);
        !           236: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !           237:            timeout.tv_sec = 3;
        !           238:            timeout.tv_usec = 0;
        !           239:            n = select(s + 1, NULL, &wset, NULL, &timeout);
        !           240: #else
        !           241:            n = select(s + 1, NULL, &wset, NULL, NULL);
        !           242: #endif
        !           243:            if(n == -1 && errno == EINTR)
        !           244:                continue;
        !           245: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
        !           246:            if(n == 0) {
        !           247:                errno = ETIMEDOUT;
        !           248:                n = -1;
        !           249:                break;
        !           250:            }
        !           251: #endif
        !           252:            /*len = 0;*/
        !           253:            /*n = getpeername(s, NULL, &len);*/
        !           254:            len = sizeof(err);
        !           255:            if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
        !           256:                PRINT_SOCKET_ERROR("getsockopt");
        !           257:                closesocket(s);
        !           258:                freeaddrinfo(ai);
        !           259:                return INVALID_SOCKET;
        !           260:            }
        !           261:            if(err != 0) {
        !           262:                errno = err;
        !           263:                n = -1;
        !           264:            }
        !           265:        }
        !           266: #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
        !           267:        if(n >= 0)  /* connect() was successful */
        !           268:            break;
        !           269:    }
        !           270:    freeaddrinfo(ai);
        !           271:    if(ISINVALID(s))
        !           272:    {
        !           273:        PRINT_SOCKET_ERROR("socket");
        !           274:        return INVALID_SOCKET;
        !           275:    }
        !           276:    if(n < 0)
        !           277:    {
        !           278:        PRINT_SOCKET_ERROR("connect");
        !           279:        closesocket(s);
        !           280:        return INVALID_SOCKET;
        !           281:    }
        !           282: #endif /* #ifdef USE_GETHOSTBYNAME */
        !           283:    return s;
        !           284: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>