Code

include "config.h" in all files using HAVE_* defines
[ncmpc.git] / src / resolver.c
1 /* libmpdclient
2    (c) 2008 Max Kellermann <max@duempel.org>
3    This project's homepage is: http://www.musicpd.org
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
16    - Neither the name of the Music Player Daemon nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
33 #include "config.h"
34 #include "resolver.h"
36 #include <netdb.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
41 #ifdef WIN32
42 #  include <ws2tcpip.h>
43 #  include <winsock.h>
44 #else
45 #  include <netinet/in.h>
46 #  include <arpa/inet.h>
47 #  include <sys/socket.h>
48 #  include <sys/un.h>
49 #  include <netdb.h>
50 #endif
52 #ifndef MPD_NO_GAI
53 #  ifdef AI_ADDRCONFIG
54 #    define MPD_HAVE_GAI
55 #  endif
56 #endif
58 struct resolver {
59         enum {
60                 TYPE_ZERO, TYPE_ONE, TYPE_ANY
61         } type;
63 #ifdef MPD_HAVE_GAI
64         struct addrinfo *ai;
65         const struct addrinfo *next;
66 #else
67         struct sockaddr_in sin;
68 #endif
70         struct resolver_address current;
72 #ifndef WIN32
73         struct sockaddr_un saun;
74 #endif
75 };
77 struct resolver *
78 resolver_new(const char *host, int port)
79 {
80         struct resolver *resolver;
82         resolver = malloc(sizeof(*resolver));
83         if (resolver == NULL)
84                 return NULL;
86 #ifndef WIN32
87         if (host[0] == '/') {
88                 size_t path_length = strlen(host);
89                 if (path_length >= sizeof(resolver->saun.sun_path)) {
90                         free(resolver);
91                         return NULL;
92                 }
94                 resolver->saun.sun_family = AF_UNIX;
95                 memcpy(resolver->saun.sun_path, host, path_length + 1);
97                 resolver->current.family = PF_UNIX;
98                 resolver->current.protocol = 0;
99                 resolver->current.addrlen = sizeof(resolver->saun);
100                 resolver->current.addr = (const struct sockaddr *)&resolver->saun;
101                 resolver->type = TYPE_ONE;
102         } else {
103 #endif
104 #ifdef MPD_HAVE_GAI
105                 struct addrinfo hints;
106                 char service[20];
107                 int ret;
109                 memset(&hints, 0, sizeof(hints));
110                 hints.ai_flags = AI_ADDRCONFIG;
111                 hints.ai_family = PF_UNSPEC;
112                 hints.ai_socktype = SOCK_STREAM;
113                 hints.ai_protocol = IPPROTO_TCP;
115                 snprintf(service, sizeof(service), "%d", port);
117                 ret = getaddrinfo(host, service, &hints, &resolver->ai);
118                 if (ret != 0) {
119                         free(resolver);
120                         return NULL;
121                 }
123                 resolver->next = resolver->ai;
124                 resolver->type = TYPE_ANY;
125 #else
126                 const struct hostent *he;
128                 he = gethostbyname(host);
129                 if (he == NULL) {
130                         free(resolver);
131                         return NULL;
132                 }
134                 if (he->h_addrtype != AF_INET) {
135                         free(resolver);
136                         return NULL;
137                 }
140                 memset(&resolver->sin, 0, sizeof(resolver->sin));
141                 resolver->sin.sin_family = AF_INET;
142                 resolver->sin.sin_port = htons(port);
143                 memcpy((char *)&resolver->sin.sin_addr.s_addr,
144                        (char *)he->h_addr, he->h_length);
146                 resolver->current.family = PF_INET;
147                 resolver->current.protocol = 0;
148                 resolver->current.addrlen = sizeof(resolver->sin);
149                 resolver->current.addr = (const struct sockaddr *)&resolver->sin;
151                 resolver->type = TYPE_ONE;
152 #endif
153 #ifndef WIN32
154         }
155 #endif
157         return resolver;
160 void
161 resolver_free(struct resolver *resolver)
163 #ifdef MPD_HAVE_GAI
164         if (resolver->type == TYPE_ANY)
165                 freeaddrinfo(resolver->ai);
166 #endif
167         free(resolver);
170 const struct resolver_address *
171 resolver_next(struct resolver *resolver)
173         if (resolver->type == TYPE_ZERO)
174                 return NULL;
176         if (resolver->type == TYPE_ONE) {
177                 resolver->type = TYPE_ZERO;
178                 return &resolver->current;
179         }
181 #ifdef MPD_HAVE_GAI
182         if (resolver->next == NULL)
183                 return NULL;
185         resolver->current.family = resolver->next->ai_family;
186         resolver->current.protocol = resolver->next->ai_protocol;
187         resolver->current.addrlen = resolver->next->ai_addrlen;
188         resolver->current.addr = resolver->next->ai_addr;
190         resolver->next = resolver->next->ai_next;
192         return &resolver->current;
193 #else
194         return NULL;
195 #endif