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/resolver.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 'src/resolver.c')
-rw-r--r-- | src/resolver.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/resolver.c b/src/resolver.c new file mode 100644 index 000000000..e5df05ce5 --- /dev/null +++ b/src/resolver.c @@ -0,0 +1,195 @@ +/* libmpdclient + (c) 2008 Max Kellermann <max@duempel.org> + This project's homepage is: http://www.musicpd.org + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Music Player Daemon nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "resolver.h" + +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef WIN32 +# include <ws2tcpip.h> +# include <winsock.h> +#else +# include <netinet/in.h> +# include <arpa/inet.h> +# include <sys/socket.h> +# include <sys/un.h> +# include <netdb.h> +#endif + +#ifndef MPD_NO_GAI +# ifdef AI_ADDRCONFIG +# define MPD_HAVE_GAI +# endif +#endif + +struct resolver { + enum { + TYPE_ZERO, TYPE_ONE, TYPE_ANY + } type; + +#ifdef MPD_HAVE_GAI + struct addrinfo *ai; + const struct addrinfo *next; +#else + struct sockaddr_in sin; +#endif + + struct resolver_address current; + +#ifndef WIN32 + struct sockaddr_un sun; +#endif +}; + +struct resolver * +resolver_new(const char *host, int port) +{ + struct resolver *resolver; + + resolver = malloc(sizeof(*resolver)); + if (resolver == NULL) + return NULL; + +#ifndef WIN32 + if (host[0] == '/') { + size_t path_length = strlen(host); + if (path_length >= sizeof(resolver->sun.sun_path)) { + free(resolver); + return NULL; + } + + resolver->sun.sun_family = AF_UNIX; + memcpy(resolver->sun.sun_path, host, path_length + 1); + + resolver->current.family = PF_UNIX; + resolver->current.protocol = 0; + resolver->current.addrlen = sizeof(resolver->sun); + resolver->current.addr = (const struct sockaddr *)&resolver->sun; + resolver->type = TYPE_ONE; + } else { +#endif +#ifdef MPD_HAVE_GAI + struct addrinfo hints; + char service[20]; + int ret; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + snprintf(service, sizeof(service), "%d", port); + + ret = getaddrinfo(host, service, &hints, &resolver->ai); + if (ret != 0) { + free(resolver); + return NULL; + } + + resolver->next = resolver->ai; + resolver->type = TYPE_ANY; +#else + const struct hostent *he; + + he = gethostbyname(host); + if (he == NULL) { + free(resolver); + return NULL; + } + + if (he->h_addrtype != AF_INET) { + free(resolver); + return NULL; + } + + + memset(&resolver->sin, 0, sizeof(resolver->sin)); + resolver->sin.sin_family = AF_INET; + resolver->sin.sin_port = htons(port); + memcpy((char *)&resolver->sin.sin_addr.s_addr, + (char *)he->h_addr, he->h_length); + + resolver->current.family = PF_INET; + resolver->current.protocol = 0; + resolver->current.addrlen = sizeof(resolver->sin); + resolver->current.addr = (const struct sockaddr *)&resolver->sin; + + resolver->type = TYPE_ONE; +#endif +#ifndef WIN32 + } +#endif + + return resolver; +} + +void +resolver_free(struct resolver *resolver) +{ +#ifdef MPD_HAVE_GAI + if (resolver->type == TYPE_ANY) + freeaddrinfo(resolver->ai); +#endif + free(resolver); +} + +const struct resolver_address * +resolver_next(struct resolver *resolver) +{ + if (resolver->type == TYPE_ZERO) + return NULL; + + if (resolver->type == TYPE_ONE) { + resolver->type = TYPE_ZERO; + return &resolver->current; + } + +#ifdef MPD_HAVE_GAI + if (resolver->next == NULL) + return NULL; + + resolver->current.family = resolver->next->ai_family; + resolver->current.protocol = resolver->next->ai_protocol; + resolver->current.addrlen = resolver->next->ai_addrlen; + resolver->current.addr = resolver->next->ai_addr; + + resolver->next = resolver->next->ai_next; + + return &resolver->current; +#else + return NULL; +#endif +} |