diff options
author | Max Kellermann <max@duempel.org> | 2008-09-18 11:17:17 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-09-18 11:17:17 +0200 |
commit | dcb67250b34dc92aced026516e162a42000f1857 (patch) | |
tree | 6314bf5b1353347ce2b3973274513e2b78491aba /src/libmpdclient.c | |
parent | 919cebb0bcd44170a7dd773717eefa1e515d628c (diff) | |
download | mpd-dcb67250b34dc92aced026516e162a42000f1857.tar.gz mpd-dcb67250b34dc92aced026516e162a42000f1857.tar.xz mpd-dcb67250b34dc92aced026516e162a42000f1857.zip |
libmpdclient: added resolver library
The resolver library provides unified access to all resolvers
(getaddrinfo(), gethostbyname(), Unix domain sockets). Like
getaddrinfo(), it can return more than one address for a host name.
This fixes bug 1517 (http://www.musicpd.org/mantis/view.php?id=1517).
Diffstat (limited to '')
-rw-r--r-- | src/libmpdclient.c | 273 |
1 files changed, 74 insertions, 199 deletions
diff --git a/src/libmpdclient.c b/src/libmpdclient.c index b2c907b49..0f2b1b503 100644 --- a/src/libmpdclient.c +++ b/src/libmpdclient.c @@ -31,6 +31,7 @@ */ #include "libmpdclient.h" +#include "resolver.h" #include "str_pool.h" #include <assert.h> @@ -61,12 +62,6 @@ # define MSG_DONTWAIT 0 #endif -#ifndef MPD_NO_GAI -# ifdef AI_ADDRCONFIG -# define MPD_HAVE_GAI -# endif -#endif - #define COMMAND_LIST 1 #define COMMAND_LIST_OK 2 @@ -115,130 +110,6 @@ static int do_connect_fail(mpd_Connection *connection, } #endif /* !WIN32 */ -#ifdef MPD_HAVE_GAI -static int mpd_connect(mpd_Connection * connection, const char * host, int port, - float timeout) -{ - int error; - char service[20]; - struct addrinfo hints; - struct addrinfo *res = NULL; - struct addrinfo *addrinfo = NULL; - - /** - * Setup hints - */ - hints.ai_flags = AI_ADDRCONFIG; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; - - snprintf(service, sizeof(service), "%d", port); - - error = getaddrinfo(host, service, &hints, &addrinfo); - - if (error) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "host \"%s\" not found: %s",host, gai_strerror(error)); - connection->error = MPD_ERROR_UNKHOST; - return -1; - } - - for (res = addrinfo; res; res = res->ai_next) { - /* create socket */ - connection->sock = socket(res->ai_family, SOCK_STREAM, res->ai_protocol); - if (connection->sock < 0) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "problems creating socket: %s", - strerror(errno)); - connection->error = MPD_ERROR_SYSTEM; - freeaddrinfo(addrinfo); - return -1; - } - - mpd_setConnectionTimeout(connection,timeout); - - /* connect stuff */ - if (do_connect_fail(connection, res->ai_addr, res->ai_addrlen)) { - /* try the next address family */ - closesocket(connection->sock); - connection->sock = -1; - continue; - } - } - freeaddrinfo(addrinfo); - - if (connection->sock < 0) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "problems connecting to \"%s\" on port" - " %i: %s",host,port, strerror(errno)); - connection->error = MPD_ERROR_CONNPORT; - - return -1; - } - - return 0; -} -#else /* !MPD_HAVE_GAI */ -static int mpd_connect(mpd_Connection * connection, const char * host, int port, - float timeout) -{ - struct hostent * he; - struct sockaddr * dest; - int destlen; - struct sockaddr_in sin; - - if(!(he=gethostbyname(host))) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "host \"%s\" not found",host); - connection->error = MPD_ERROR_UNKHOST; - return -1; - } - - memset(&sin,0,sizeof(struct sockaddr_in)); - /*dest.sin_family = he->h_addrtype;*/ - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - 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; - default: - strcpy(connection->errorStr,"address type is not IPv4\n"); - connection->error = MPD_ERROR_SYSTEM; - return -1; - break; - } - - if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) { - strcpy(connection->errorStr,"problems creating socket"); - connection->error = MPD_ERROR_SYSTEM; - return -1; - } - - mpd_setConnectionTimeout(connection,timeout); - - /* connect stuff */ - if (do_connect_fail(connection, dest, destlen)) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "problems connecting to \"%s\" on port" - " %i",host,port); - connection->error = MPD_ERROR_CONNPORT; - return -1; - } - - return 0; -} -#endif /* !MPD_HAVE_GAI */ - const char *const mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] = { "Artist", @@ -333,53 +204,6 @@ static int mpd_parseWelcome(mpd_Connection * connection, const char * host, int return 0; } -#ifndef WIN32 -static int mpd_connect_un(mpd_Connection * connection, - const char * host, float timeout) -{ - int error, flags; - size_t path_length; - struct sockaddr_un sun; - - path_length = strlen(host); - if (path_length >= sizeof(sun.sun_path)) { - strcpy(connection->errorStr, "unix socket path is too long"); - connection->error = MPD_ERROR_UNKHOST; - return -1; - } - - sun.sun_family = AF_UNIX; - memcpy(sun.sun_path, host, path_length + 1); - - connection->sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (connection->sock < 0) { - strcpy(connection->errorStr, "problems creating socket"); - connection->error = MPD_ERROR_SYSTEM; - return -1; - } - - mpd_setConnectionTimeout(connection, timeout); - - flags = fcntl(connection->sock, F_GETFL, 0); - fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK); - - error = connect(connection->sock, (struct sockaddr*)&sun, sizeof(sun)); - if (error < 0) { - /* try the next address family */ - close(connection->sock); - connection->sock = 0; - - snprintf(connection->errorStr, sizeof(connection->errorStr), - "problems connecting to \"%s\": %s", - host, strerror(errno)); - connection->error = MPD_ERROR_CONNPORT; - return -1; - } - - return 0; -} -#endif /* WIN32 */ - /** * Wait for the socket to become readable. */ @@ -486,6 +310,76 @@ static int mpd_recv(mpd_Connection *connection) } } +static int +mpd_connect(mpd_Connection *connection, const char * host, int port) +{ + struct resolver *resolver; + const struct resolver_address *address; + int ret; + + resolver = resolver_new(host, port); + if (resolver == NULL) { + snprintf(connection->errorStr, sizeof(connection->errorStr), + "host \"%s\" not found", host); + connection->error = MPD_ERROR_UNKHOST; + return -1; + } + + while ((address = resolver_next(resolver)) != NULL) { + connection->sock = socket(address->family, SOCK_STREAM, + address->protocol); + if (connection->sock < 0) { + snprintf(connection->errorStr, + sizeof(connection->errorStr), + "problems creating socket: %s", + strerror(errno)); + connection->error = MPD_ERROR_SYSTEM; + continue; + } + + ret = do_connect_fail(connection, + address->addr, address->addrlen); + if (ret != 0) { + snprintf(connection->errorStr, + sizeof(connection->errorStr), + "problems connecting to \"%s\" on port" + " %i: %s", host, port, strerror(errno)); + connection->error = MPD_ERROR_CONNPORT; + + closesocket(connection->sock); + connection->sock = -1; + continue; + } + + ret = mpd_wait_connected(connection); + if (ret > 0) { + resolver_free(resolver); + mpd_clearError(connection); + return 0; + } + + if (ret == 0) { + snprintf(connection->errorStr, + sizeof(connection->errorStr), + "timeout in attempting to get a response from" + " \"%s\" on port %i", host, port); + connection->error = MPD_ERROR_NORESPONSE; + } else if (ret < 0) { + snprintf(connection->errorStr, + sizeof(connection->errorStr), + "problems connecting to \"%s\" on port %i: %s", + host, port, strerror(-ret)); + connection->error = MPD_ERROR_CONNPORT; + } + + closesocket(connection->sock); + connection->sock = -1; + } + + resolver_free(resolver); + return -1; +} + mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) { int err; char * rt; @@ -504,30 +398,11 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) { if (winsock_dll_error(connection)) return connection; -#ifndef WIN32 - if (host[0] == '/') - err = mpd_connect_un(connection, host, timeout); - else -#endif - err = mpd_connect(connection, host, port, timeout); - if (err < 0) - return connection; + mpd_setConnectionTimeout(connection,timeout); - err = mpd_wait_connected(connection); - if (err == 0) { - snprintf(connection->errorStr, sizeof(connection->errorStr), - "timeout in attempting to get a response from" - " \"%s\" on port %i",host,port); - connection->error = MPD_ERROR_NORESPONSE; - return connection; - } else if (err < 0) { - snprintf(connection->errorStr, - sizeof(connection->errorStr), - "problems connecting to \"%s\" on port %i: %s", - host, port, strerror(-err)); - connection->error = MPD_ERROR_CONNPORT; + err = mpd_connect(connection, host, port); + if (err < 0) return connection; - } while(!(rt = memchr(connection->buffer, '\n', connection->buflen))) { err = mpd_recv(connection); |