952c2c930005ced9e169fa926feea3533c71cd93
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 <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #ifdef WIN32
37 # include <winsock2.h>
38 # include <ws2tcpip.h>
39 #else
40 # include <sys/socket.h>
41 # include <sys/un.h>
42 #ifdef ENABLE_TCP
43 # include <netinet/in.h>
44 # include <arpa/inet.h>
45 # include <netdb.h>
46 #endif
47 #endif
49 struct resolver {
50 enum {
51 TYPE_ZERO, TYPE_ONE, TYPE_ANY
52 } type;
54 #ifdef ENABLE_TCP
55 #ifdef HAVE_GETADDRINFO
56 struct addrinfo *ai;
57 const struct addrinfo *next;
58 #else
59 struct sockaddr_in sin;
60 #endif
61 #endif
63 struct resolver_address current;
65 #ifndef WIN32
66 struct sockaddr_un saun;
67 #endif
68 };
70 struct resolver *
71 resolver_new(const char *host, unsigned port)
72 {
73 struct resolver *resolver;
75 resolver = malloc(sizeof(*resolver));
76 if (resolver == NULL)
77 return NULL;
79 if (host[0] == '/' || host[0] == '@') {
80 #ifndef WIN32
81 size_t path_length = strlen(host);
82 if (path_length >= sizeof(resolver->saun.sun_path)) {
83 free(resolver);
84 return NULL;
85 }
87 resolver->saun.sun_family = AF_UNIX;
88 memcpy(resolver->saun.sun_path, host, path_length + 1);
90 if (host[0] == '@')
91 /* abstract socket */
92 resolver->saun.sun_path[0] = 0;
94 resolver->current.family = PF_UNIX;
95 resolver->current.protocol = 0;
96 resolver->current.addrlen = sizeof(resolver->saun);
97 resolver->current.addr = (const struct sockaddr *)&resolver->saun;
98 resolver->type = TYPE_ONE;
99 #else /* WIN32 */
100 /* there are no UNIX domain sockets on Windows */
101 free(resolver);
102 return NULL;
103 #endif /* WIN32 */
104 } else {
105 #ifdef ENABLE_TCP
106 #ifdef HAVE_GETADDRINFO
107 struct addrinfo hints;
108 char service[20];
109 int ret;
111 memset(&hints, 0, sizeof(hints));
112 hints.ai_family = PF_UNSPEC;
113 hints.ai_socktype = SOCK_STREAM;
114 hints.ai_protocol = IPPROTO_TCP;
116 snprintf(service, sizeof(service), "%d", port);
118 ret = getaddrinfo(host, service, &hints, &resolver->ai);
119 if (ret != 0) {
120 free(resolver);
121 return NULL;
122 }
124 resolver->next = resolver->ai;
125 resolver->type = TYPE_ANY;
126 #else
127 const struct hostent *he;
129 he = gethostbyname(host);
130 if (he == NULL) {
131 free(resolver);
132 return NULL;
133 }
135 if (he->h_addrtype != AF_INET) {
136 free(resolver);
137 return NULL;
138 }
141 memset(&resolver->sin, 0, sizeof(resolver->sin));
142 resolver->sin.sin_family = AF_INET;
143 resolver->sin.sin_port = htons(port);
144 memcpy((char *)&resolver->sin.sin_addr.s_addr,
145 (char *)he->h_addr, he->h_length);
147 resolver->current.family = PF_INET;
148 resolver->current.protocol = 0;
149 resolver->current.addrlen = sizeof(resolver->sin);
150 resolver->current.addr = (const struct sockaddr *)&resolver->sin;
152 resolver->type = TYPE_ONE;
153 #endif
154 #else /* !ENABLE_TCP */
155 (void)port;
156 free(resolver);
157 return NULL;
158 #endif
159 }
161 return resolver;
162 }
164 void
165 resolver_free(struct resolver *resolver)
166 {
167 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
168 if (resolver->type == TYPE_ANY)
169 freeaddrinfo(resolver->ai);
170 #endif
171 free(resolver);
172 }
174 const struct resolver_address *
175 resolver_next(struct resolver *resolver)
176 {
177 if (resolver->type == TYPE_ZERO)
178 return NULL;
180 if (resolver->type == TYPE_ONE) {
181 resolver->type = TYPE_ZERO;
182 return &resolver->current;
183 }
185 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
186 if (resolver->next == NULL)
187 return NULL;
189 resolver->current.family = resolver->next->ai_family;
190 resolver->current.protocol = resolver->next->ai_protocol;
191 resolver->current.addrlen = resolver->next->ai_addrlen;
192 resolver->current.addr = resolver->next->ai_addr;
194 resolver->next = resolver->next->ai_next;
196 return &resolver->current;
197 #else
198 return NULL;
199 #endif
200 }