Ticket #1930: tcp-getaddrinfo.patch

File tcp-getaddrinfo.patch, 8.4 KB (added by fcr@…, 15 years ago)

Patch fixing link-local IPv6 support

  • stream/tcp.c

     
    7777connect2Server_with_af(char *host, int port, int af,int verb) {
    7878        int socket_server_fd;
    7979        int err;
    80         socklen_t err_len;
     80        socklen_t err_len;
    8181        int ret,count = 0;
    8282        fd_set set;
    8383        struct timeval tv;
    84         union {
    85                 struct sockaddr_in four;
    86 #ifdef HAVE_AF_INET6
    87                 struct sockaddr_in6 six;
    88 #endif
    89         } server_address;
    90         size_t server_address_size;
    91         void *our_s_addr;       // Pointer to sin_addr or sin6_addr
    92         struct hostent *hp=NULL;
    9384        char buf[255];
     85        struct addrinfo hints, *res, *rp;
     86        char portstr[6];
    9487
    9588#if HAVE_WINSOCK2_H
    9689        unsigned long val;
     
    107100        }
    108101#endif
    109102
    110         socket_server_fd = socket(af, SOCK_STREAM, 0);
     103        snprintf(portstr, 6, "%d", port);
     104        portstr[5] = 0;
     105        memset(&hints, 0, sizeof hints);
     106        hints.ai_family = af;
     107        err = getaddrinfo(host, portstr, &hints, &res);
    111108
    112 
    113         if( socket_server_fd==-1 ) {
    114 //              mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
     109        if (err != 0 || !res) {
     110                snprintf(buf, 255, "%s: %s", host, gai_strerror(err));
     111                mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), buf);
    115112                return TCP_ERROR_FATAL;
    116113        }
    117114
    118 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
    119 #if HAVE_WINSOCK2_H
    120         /* timeout in milliseconds */
    121         to = 10 * 1000;
    122 #else
    123         to.tv_sec = 10;
    124         to.tv_usec = 0;
    125 #endif
    126         setsockopt(socket_server_fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
    127         setsockopt(socket_server_fd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
    128 #endif
     115        rp = res;
     116        while (rp) {
    129117
    130         switch (af) {
    131                 case AF_INET:  our_s_addr = (void *) &server_address.four.sin_addr; break;
    132 #ifdef HAVE_AF_INET6
    133                 case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break;
    134 #endif
    135                 default:
    136                         mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
    137                         return TCP_ERROR_FATAL;
    138         }
     118                socket_server_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
    139119
    140 
    141         memset(&server_address, 0, sizeof(server_address));
    142 
    143 #if HAVE_INET_PTON
    144         if (inet_pton(af, host, our_s_addr)!=1)
    145 #elif HAVE_INET_ATON
    146         if (inet_aton(host, our_s_addr)!=1)
    147 #elif HAVE_WINSOCK2_H
    148         if ( inet_addr(host)==INADDR_NONE )
    149 #endif
    150         {
    151                 if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af));
    152 
    153 #ifdef HAVE_GETHOSTBYNAME2
    154                 hp=(struct hostent*)gethostbyname2( host, af );
    155 #else
    156                 hp=(struct hostent*)gethostbyname( host );
    157 #endif
    158                 if( hp==NULL ) {
    159                         if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host);
    160                         return TCP_ERROR_FATAL;
     120                if( socket_server_fd==-1 ) {
     121//                      mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
     122                        err = TCP_ERROR_FATAL;
     123                        goto retry_next_host1;
    161124                }
    162125
    163                 memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length );
    164         }
     126#if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
    165127#if HAVE_WINSOCK2_H
    166         else {
    167                 unsigned long addr = inet_addr(host);
    168                 memcpy( our_s_addr, (void*)&addr, sizeof(addr) );
    169         }
     128                /* timeout in milliseconds */
     129                to = 10 * 1000;
     130#else
     131                to.tv_sec = 10;
     132                to.tv_usec = 0;
    170133#endif
    171 
    172         switch (af) {
    173                 case AF_INET:
    174                         server_address.four.sin_family=af;
    175                         server_address.four.sin_port=htons(port);
    176                         server_address_size = sizeof(server_address.four);
    177                         break;
    178 #ifdef HAVE_AF_INET6
    179                 case AF_INET6:
    180                         server_address.six.sin6_family=af;
    181                         server_address.six.sin6_port=htons(port);
    182                         server_address_size = sizeof(server_address.six);
    183                         break;
     134                setsockopt(socket_server_fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
     135                setsockopt(socket_server_fd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
    184136#endif
    185                 default:
    186                         mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
    187                         return TCP_ERROR_FATAL;
    188         }
    189137
    190 #if HAVE_INET_PTON
    191         inet_ntop(af, our_s_addr, buf, 255);
    192 #elif HAVE_INET_ATON || defined(HAVE_WINSOCK2_H)
    193         av_strlcpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);
    194 #endif
    195         if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port );
     138                getnameinfo(rp->ai_addr, rp->ai_addrlen, buf, 255, NULL, 0, NI_NUMERICHOST);
    196139
    197         // Turn the socket as non blocking so we can timeout on the connection
     140                if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port );
     141
     142                // Turn the socket as non blocking so we can timeout on the connection
    198143#if !HAVE_WINSOCK2_H
    199         fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
     144                fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
    200145#else
    201         val = 1;
    202         ioctlsocket( socket_server_fd, FIONBIO, &val );
     146                val = 1;
     147                ioctlsocket( socket_server_fd, FIONBIO, &val );
    203148#endif
    204         if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) {
     149
     150                if( connect( socket_server_fd, rp->ai_addr, rp->ai_addrlen )==-1 ) {
    205151#if !HAVE_WINSOCK2_H
    206                 if( errno!=EINPROGRESS ) {
     152                        if( errno!=EINPROGRESS ) {
    207153#else
    208                 if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
     154                        if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
    209155#endif
    210                         if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af));
    211                         closesocket(socket_server_fd);
    212                         return TCP_ERROR_PORT;
     156                                if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af));
     157                                closesocket(socket_server_fd);
     158                                err = TCP_ERROR_PORT;
     159                                goto retry_next_host2;
     160                        }
    213161                }
    214         }
    215         tv.tv_sec = 0;
    216         tv.tv_usec = 500000;
    217         FD_ZERO( &set );
    218         FD_SET( socket_server_fd, &set );
    219         // When the connection will be made, we will have a writeable fd
    220         while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
    221               if(count > 30 || stream_check_interrupt(500)) {
    222                 if(count > 30)
    223                   mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout);
    224                 else
    225                   mp_msg(MSGT_NETWORK,MSGL_V,"Connection interrupted by user\n");
    226                 return TCP_ERROR_TIMEOUT;
    227               }
    228               count++;
    229               FD_ZERO( &set );
    230               FD_SET( socket_server_fd, &set );
    231               tv.tv_sec = 0;
    232               tv.tv_usec = 500000;
    233         }
    234         if (ret < 0) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed);
     162                tv.tv_sec = 0;
     163                tv.tv_usec = 500000;
     164                FD_ZERO( &set );
     165                FD_SET( socket_server_fd, &set );
     166                // When the connection will be made, we will have a writeable fd
     167                while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
     168                        if(count > 30 || stream_check_interrupt(500)) {
     169                          if(count > 30)
     170                            mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout);
     171                          else
     172                            mp_msg(MSGT_NETWORK,MSGL_V,"Connection interrupted by user\n");
     173                          err = TCP_ERROR_TIMEOUT;
     174                          goto retry_next_host2;
     175                        }
     176                        count++;
     177                        FD_ZERO( &set );
     178                        FD_SET( socket_server_fd, &set );
     179                        tv.tv_sec = 0;
     180                        tv.tv_usec = 500000;
     181                }
     182                if (ret < 0) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed);
    235183
    236         // Turn back the socket as blocking
     184                // Turn back the socket as blocking
    237185#if !HAVE_WINSOCK2_H
    238         fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );
     186                fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );
    239187#else
    240         val = 0;
    241         ioctlsocket( socket_server_fd, FIONBIO, &val );
     188                val = 0;
     189                ioctlsocket( socket_server_fd, FIONBIO, &val );
    242190#endif
    243         // Check if there were any errors
    244         err_len = sizeof(int);
    245         ret =  getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
    246         if(ret < 0) {
    247                 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno));
    248                 return TCP_ERROR_FATAL;
    249         }
    250         if(err > 0) {
    251                 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err));
    252                 return TCP_ERROR_PORT;
    253         }
     191                // Check if there were any errors
     192                err_len = sizeof(int);
     193                ret =  getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
     194                if(ret < 0) {
     195                        mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno));
     196                        err = TCP_ERROR_FATAL;
     197                        goto retry_next_host2;
     198                }
     199                if(err > 0) {
     200                        mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err));
     201                        err = TCP_ERROR_PORT;
     202                        goto retry_next_host2;
     203                }
    254204
    255         return socket_server_fd;
     205                freeaddrinfo(res);
     206                return socket_server_fd;
     207
     208retry_next_host2:
     209                closesocket(socket_server_fd);
     210retry_next_host1:
     211                rp = rp->ai_next;
     212        }
     213        freeaddrinfo(res);
     214        return err;
    256215}
    257216
    258217// Connect to a server using a TCP connection