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 "resolver.h"
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
40 #ifdef WIN32
41 # include <ws2tcpip.h>
42 # include <winsock.h>
43 #else
44 # include <netinet/in.h>
45 # include <arpa/inet.h>
46 # include <sys/socket.h>
47 # include <sys/un.h>
48 # include <netdb.h>
49 #endif
51 #ifndef MPD_NO_GAI
52 # ifdef AI_ADDRCONFIG
53 # define MPD_HAVE_GAI
54 # endif
55 #endif
57 struct resolver {
58 enum {
59 TYPE_ZERO, TYPE_ONE, TYPE_ANY
60 } type;
62 #ifdef MPD_HAVE_GAI
63 struct addrinfo *ai;
64 const struct addrinfo *next;
65 #else
66 struct sockaddr_in sin;
67 #endif
69 struct resolver_address current;
71 #ifndef WIN32
72 struct sockaddr_un sun;
73 #endif
74 };
76 struct resolver *
77 resolver_new(const char *host, int port)
78 {
79 struct resolver *resolver;
81 resolver = malloc(sizeof(*resolver));
82 if (resolver == NULL)
83 return NULL;
85 #ifndef WIN32
86 if (host[0] == '/') {
87 size_t path_length = strlen(host);
88 if (path_length >= sizeof(resolver->sun.sun_path)) {
89 free(resolver);
90 return NULL;
91 }
93 resolver->sun.sun_family = AF_UNIX;
94 memcpy(resolver->sun.sun_path, host, path_length + 1);
96 resolver->current.family = PF_UNIX;
97 resolver->current.protocol = 0;
98 resolver->current.addrlen = sizeof(resolver->sun);
99 resolver->current.addr = (const struct sockaddr *)&resolver->sun;
100 resolver->type = TYPE_ONE;
101 } else {
102 #endif
103 #ifdef MPD_HAVE_GAI
104 struct addrinfo hints;
105 char service[20];
106 int ret;
108 memset(&hints, 0, sizeof(hints));
109 hints.ai_flags = AI_ADDRCONFIG;
110 hints.ai_family = PF_UNSPEC;
111 hints.ai_socktype = SOCK_STREAM;
112 hints.ai_protocol = IPPROTO_TCP;
114 snprintf(service, sizeof(service), "%d", port);
116 ret = getaddrinfo(host, service, &hints, &resolver->ai);
117 if (ret != 0) {
118 free(resolver);
119 return NULL;
120 }
122 resolver->next = resolver->ai;
123 resolver->type = TYPE_ANY;
124 #else
125 const struct hostent *he;
127 he = gethostbyname(host);
128 if (he == NULL) {
129 free(resolver);
130 return NULL;
131 }
133 if (he->h_addrtype != AF_INET) {
134 free(resolver);
135 return NULL;
136 }
139 memset(&resolver->sin, 0, sizeof(resolver->sin));
140 resolver->sin.sin_family = AF_INET;
141 resolver->sin.sin_port = htons(port);
142 memcpy((char *)&resolver->sin.sin_addr.s_addr,
143 (char *)he->h_addr, he->h_length);
145 resolver->current.family = PF_INET;
146 resolver->current.protocol = 0;
147 resolver->current.addrlen = sizeof(resolver->sin);
148 resolver->current.addr = (const struct sockaddr *)&resolver->sin;
150 resolver->type = TYPE_ONE;
151 #endif
152 #ifndef WIN32
153 }
154 #endif
156 return resolver;
157 }
159 void
160 resolver_free(struct resolver *resolver)
161 {
162 #ifdef MPD_HAVE_GAI
163 if (resolver->type == TYPE_ANY)
164 freeaddrinfo(resolver->ai);
165 #endif
166 free(resolver);
167 }
169 const struct resolver_address *
170 resolver_next(struct resolver *resolver)
171 {
172 if (resolver->type == TYPE_ZERO)
173 return NULL;
175 if (resolver->type == TYPE_ONE) {
176 resolver->type = TYPE_ZERO;
177 return &resolver->current;
178 }
180 #ifdef MPD_HAVE_GAI
181 if (resolver->next == NULL)
182 return NULL;
184 resolver->current.family = resolver->next->ai_family;
185 resolver->current.protocol = resolver->next->ai_protocol;
186 resolver->current.addrlen = resolver->next->ai_addrlen;
187 resolver->current.addr = resolver->next->ai_addr;
189 resolver->next = resolver->next->ai_next;
191 return &resolver->current;
192 #else
193 return NULL;
194 #endif
195 }