Code

952c2c930005ced9e169fa926feea3533c71cd93
[ncmpc.git] / src / net / resolver.c
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;
164 void
165 resolver_free(struct resolver *resolver)
167 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
168         if (resolver->type == TYPE_ANY)
169                 freeaddrinfo(resolver->ai);
170 #endif
171         free(resolver);
174 const struct resolver_address *
175 resolver_next(struct resolver *resolver)
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