1 /* libmpdclient
2 (c) 2003-2017 The Music Player Daemon Project
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 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
20 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
29 #include "resolver.h"
30 #include "config.h"
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #ifdef WIN32
38 # include <winsock2.h>
39 # include <ws2tcpip.h>
40 #else
41 # include <sys/socket.h>
42 # include <sys/un.h>
43 #ifdef ENABLE_TCP
44 # include <netinet/in.h>
45 # include <arpa/inet.h>
46 # include <netdb.h>
47 #endif
48 #endif
50 struct resolver {
51 enum {
52 TYPE_ZERO, TYPE_ONE, TYPE_ANY
53 } type;
55 #ifdef ENABLE_TCP
56 #ifdef HAVE_GETADDRINFO
57 struct addrinfo *ai;
58 const struct addrinfo *next;
59 #else
60 struct sockaddr_in sin;
61 #endif
62 #endif
64 struct resolver_address current;
66 #ifndef WIN32
67 struct sockaddr_un saun;
68 #endif
69 };
71 struct resolver *
72 resolver_new(const char *host, unsigned port)
73 {
74 struct resolver *resolver;
76 resolver = malloc(sizeof(*resolver));
77 if (resolver == NULL)
78 return NULL;
80 if (host[0] == '/' || host[0] == '@') {
81 #ifndef WIN32
82 const bool is_abstract = *host == '@';
83 /* sun_path must be null-terminated unless it's an abstract
84 socket */
85 const size_t path_length = strlen(host) + !is_abstract;
86 if (path_length > sizeof(resolver->saun.sun_path)) {
87 free(resolver);
88 return NULL;
89 }
91 resolver->saun.sun_family = AF_UNIX;
92 memcpy(resolver->saun.sun_path, host, path_length);
94 if (host[0] == '@')
95 /* abstract socket */
96 resolver->saun.sun_path[0] = 0;
98 resolver->current.family = PF_UNIX;
99 resolver->current.protocol = 0;
100 resolver->current.addrlen = sizeof(resolver->saun)
101 - sizeof(resolver->saun.sun_path) + path_length;
102 resolver->current.addr = (const struct sockaddr *)&resolver->saun;
103 resolver->type = TYPE_ONE;
104 #else /* WIN32 */
105 /* there are no UNIX domain sockets on Windows */
106 free(resolver);
107 return NULL;
108 #endif /* WIN32 */
109 } else {
110 #ifdef ENABLE_TCP
111 #ifdef HAVE_GETADDRINFO
112 struct addrinfo hints;
113 char service[20];
114 int ret;
116 memset(&hints, 0, sizeof(hints));
117 hints.ai_family = PF_UNSPEC;
118 hints.ai_socktype = SOCK_STREAM;
119 hints.ai_protocol = IPPROTO_TCP;
121 snprintf(service, sizeof(service), "%d", port);
123 ret = getaddrinfo(host, service, &hints, &resolver->ai);
124 if (ret != 0) {
125 free(resolver);
126 return NULL;
127 }
129 resolver->next = resolver->ai;
130 resolver->type = TYPE_ANY;
131 #else
132 const struct hostent *he;
134 he = gethostbyname(host);
135 if (he == NULL) {
136 free(resolver);
137 return NULL;
138 }
140 if (he->h_addrtype != AF_INET) {
141 free(resolver);
142 return NULL;
143 }
146 memset(&resolver->sin, 0, sizeof(resolver->sin));
147 resolver->sin.sin_family = AF_INET;
148 resolver->sin.sin_port = htons(port);
149 memcpy((char *)&resolver->sin.sin_addr.s_addr,
150 (char *)he->h_addr, he->h_length);
152 resolver->current.family = PF_INET;
153 resolver->current.protocol = 0;
154 resolver->current.addrlen = sizeof(resolver->sin);
155 resolver->current.addr = (const struct sockaddr *)&resolver->sin;
157 resolver->type = TYPE_ONE;
158 #endif
159 #else /* !ENABLE_TCP */
160 (void)port;
161 free(resolver);
162 return NULL;
163 #endif
164 }
166 return resolver;
167 }
169 void
170 resolver_free(struct resolver *resolver)
171 {
172 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
173 if (resolver->type == TYPE_ANY)
174 freeaddrinfo(resolver->ai);
175 #endif
176 free(resolver);
177 }
179 const struct resolver_address *
180 resolver_next(struct resolver *resolver)
181 {
182 if (resolver->type == TYPE_ZERO)
183 return NULL;
185 if (resolver->type == TYPE_ONE) {
186 resolver->type = TYPE_ZERO;
187 return &resolver->current;
188 }
190 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
191 if (resolver->next == NULL)
192 return NULL;
194 resolver->current.family = resolver->next->ai_family;
195 resolver->current.protocol = resolver->next->ai_protocol;
196 resolver->current.addrlen = resolver->next->ai_addrlen;
197 resolver->current.addr = resolver->next->ai_addr;
199 resolver->next = resolver->next->ai_next;
201 return &resolver->current;
202 #else
203 return NULL;
204 #endif
205 }