Code

resolver: set the correct address size for local/abstract sockets
[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 <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;
169 void
170 resolver_free(struct resolver *resolver)
172 #if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
173         if (resolver->type == TYPE_ANY)
174                 freeaddrinfo(resolver->ai);
175 #endif
176         free(resolver);
179 const struct resolver_address *
180 resolver_next(struct resolver *resolver)
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