Code

IPv6 patch from Jelmer Vernooij
authorKalle Wallin <kaw@linux.se>
Tue, 28 Mar 2006 09:50:50 +0000 (09:50 +0000)
committerKalle Wallin <kaw@linux.se>
Tue, 28 Mar 2006 09:50:50 +0000 (09:50 +0000)
git-svn-id: https://svn.musicpd.org/ncmpc/trunk@3963 09075e82-0dd4-0310-85a5-a0d7c8717e4f

ChangeLog
src/libmpdclient.c

index 13a46c7b6a3de964757894b51bdae505b18634d5..2a676ad7abb222c29d6a5f54d774a95ed81d6877 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,9 @@
        * configure.ac: check for recv/send/gethostbyname/socket/connect in 
                        -lsocket -lnsl (Tonnerre)
 
+2006-03-28  Jelmer Vernooij <jelmer@samba.org>
+       * libmpdclient.c: Fix ipv6 support
+
 2006-01-22  Kalle Wallin <kaw@linux.se>
        * configure.ac: use libcursesw by default
        * wreadln.c: use wget_wch (wide characters) when built with libcursesw
index a8bbabef7bd046a2b3bf0de1992c64e3764c9511..3bbef181d85a15b97403d02cf0402027be4b3002 100644 (file)
 #include <fcntl.h>
 #include <stdarg.h>
 
-#ifndef MPD_NO_IPV6
-#ifdef AF_INET6
-#define MPD_HAVE_IPV6
-#endif
-#endif
-
 #ifndef MSG_DONTWAIT
 #define MSG_DONTWAIT 0
 #endif
@@ -80,16 +74,6 @@ char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
 };
 
 
-#ifdef MPD_HAVE_IPV6        
-int mpd_ipv6Supported() {
-        int s;          
-        s = socket(AF_INET6,SOCK_STREAM,0);
-        if(s == -1) return 0;
-        close(s);       
-        return 1;                       
-}                       
-#endif  
-
 static char * mpd_sanitizeArg(const char * arg) {
        size_t i;
        char * ret;
@@ -146,22 +130,15 @@ void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
 
 mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
        int err;
-       struct hostent * he;
-       struct sockaddr * dest;
-#ifdef HAVE_SOCKLEN_T
-       socklen_t destlen;
-#else
-       int destlen;
-#endif
-       struct sockaddr_in sin;
+       int error;
        char * rt;
        char * output;
+       char service[20];
        mpd_Connection * connection = malloc(sizeof(mpd_Connection));
        struct timeval tv;
+       struct addrinfo hints, *res;
+       struct addrinfo *addrinfo = NULL;
        fd_set fds;
-#ifdef MPD_HAVE_IPV6
-       struct sockaddr_in6 sin6;
-#endif
        strcpy(connection->buffer,"");
        connection->buflen = 0;
        connection->bufstart = 0;
@@ -173,73 +150,65 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
        connection->doneListOk = 0;
        connection->returnElement = NULL;
 
-       if(!(he=gethostbyname(host))) {
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       snprintf(service, sizeof(service), "%d", port);
+
+       error = getaddrinfo(host, service, &hints, &addrinfo);
+
+       if (error) {
                snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
-                               "host \"%s\" not found",host);
+                               "host \"%s\" not found: %s",host, gai_strerror(error));
                connection->error = MPD_ERROR_UNKHOST;
                return connection;
        }
 
-       memset(&sin,0,sizeof(struct sockaddr_in));
-       /*dest.sin_family = he->h_addrtype;*/
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(port);
-#ifdef MPD_HAVE_IPV6
-       memset(&sin6,0,sizeof(struct sockaddr_in6));
-       sin6.sin6_family = AF_INET6;
-       sin6.sin6_port = htons(port);
-#endif
-       switch(he->h_addrtype) {
-       case AF_INET:
-               memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
-                               he->h_length);
-               dest = (struct sockaddr *)&sin;
-               destlen = sizeof(struct sockaddr_in);
-               break;
-#ifdef MPD_HAVE_IPV6
-       case AF_INET6:
-               if(!mpd_ipv6Supported()) {
-                       strcpy(connection->errorStr,"no IPv6 suuport but a "
-                                       "IPv6 address found\n");
+       for (res = addrinfo; res; res = res->ai_next) {
+               /* create socket */
+               
+               if((connection->sock = socket(res->ai_family,SOCK_STREAM,res->ai_protocol))<0) {
+                       strcpy(connection->errorStr,"problems creating socket");
                        connection->error = MPD_ERROR_SYSTEM;
+                       freeaddrinfo(addrinfo);
                        return connection;
                }
-               memcpy((char *)&sin6.sin6_addr.s6_addr,(char *)he->h_addr,
-                               he->h_length);
-               dest = (struct sockaddr *)&sin6;
-               destlen = sizeof(struct sockaddr_in6);
-               break;
+
+               mpd_setConnectionTimeout(connection,timeout);
+
+               /* connect stuff */
+               {
+#ifdef WIN32
+                       int iMode = 1; // 0 = blocking, else non-blocking
+                       ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
+                       if(connect(connection->sock,res->ai_addr,res->ai_addrlen) == SOCKET_ERROR
+                               && WSAGetLastError() != WSAEWOULDBLOCK)
+#else
+                               int flags = fcntl(connection->sock, F_GETFL, 0);
+                       fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
+
+                       if(connect(connection->sock,res->ai_addr,res->ai_addrlen)<0 && 
+                                       errno!=EINPROGRESS) 
 #endif
-       default:
-               strcpy(connection->errorStr,"address type is not IPv4 or "
-                               "IPv6\n");
-               connection->error = MPD_ERROR_SYSTEM;
-               return connection;
-               break;
-       }
-       
-       if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
-               strcpy(connection->errorStr,"problems creating socket");
-               connection->error = MPD_ERROR_SYSTEM;
-               return connection;
+                       {
+                               /* try the next address family */
+                               close(connection->sock);
+                               connection->sock = 0;
+                               continue;
+                       }
+               }
        }
 
-       mpd_setConnectionTimeout(connection,timeout);
+       freeaddrinfo(addrinfo);
 
-       /* connect stuff */
-       {
-               int flags = fcntl(connection->sock, F_GETFL, 0);
-               fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
+       if (connection->sock == 0) {
+               snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
+                               "problems connecting to \"%s\" on port"
+                               " %i: %s",host,port, strerror(errno));
+               connection->error = MPD_ERROR_CONNPORT;
 
-               if(connect(connection->sock,dest,destlen)<0 && 
-                               errno!=EINPROGRESS) 
-               {
-                       snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
-                                       "problems connecting to \"%s\" on port"
-                                       " %i",host,port);
-                       connection->error = MPD_ERROR_CONNPORT;
-                       return connection;
-               }
+               return connection;
        }
 
        while(!(rt = strstr(connection->buffer,"\n"))) {