1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18 * IN THE SOFTWARE.
19 */
20
21/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
22 * include any headers.
23 */
24#ifndef _GNU_SOURCE
25# define _GNU_SOURCE
26#endif
27
28#include "uv.h"
29#include "internal.h"
30#include "idna.h"
31
32#include <errno.h>
33#include <stddef.h> /* NULL */
34#include <stdlib.h>
35#include <string.h>
36#include <net/if.h> /* if_indextoname() */
37
38/* EAI_* constants. */
39#include <netdb.h>
40
41
42int uv__getaddrinfo_translate_error(int sys_err) {
43 switch (sys_err) {
44 case 0: return 0;
45#if defined(EAI_ADDRFAMILY)
46 case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
47#endif
48#if defined(EAI_AGAIN)
49 case EAI_AGAIN: return UV_EAI_AGAIN;
50#endif
51#if defined(EAI_BADFLAGS)
52 case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
53#endif
54#if defined(EAI_BADHINTS)
55 case EAI_BADHINTS: return UV_EAI_BADHINTS;
56#endif
57#if defined(EAI_CANCELED)
58 case EAI_CANCELED: return UV_EAI_CANCELED;
59#endif
60#if defined(EAI_FAIL)
61 case EAI_FAIL: return UV_EAI_FAIL;
62#endif
63#if defined(EAI_FAMILY)
64 case EAI_FAMILY: return UV_EAI_FAMILY;
65#endif
66#if defined(EAI_MEMORY)
67 case EAI_MEMORY: return UV_EAI_MEMORY;
68#endif
69#if defined(EAI_NODATA)
70 case EAI_NODATA: return UV_EAI_NODATA;
71#endif
72#if defined(EAI_NONAME)
73# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
74 case EAI_NONAME: return UV_EAI_NONAME;
75# endif
76#endif
77#if defined(EAI_OVERFLOW)
78 case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
79#endif
80#if defined(EAI_PROTOCOL)
81 case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
82#endif
83#if defined(EAI_SERVICE)
84 case EAI_SERVICE: return UV_EAI_SERVICE;
85#endif
86#if defined(EAI_SOCKTYPE)
87 case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
88#endif
89#if defined(EAI_SYSTEM)
90 case EAI_SYSTEM: return UV__ERR(errno);
91#endif
92 }
93 assert(!"unknown EAI_* error code");
94 abort();
95#ifndef __SUNPRO_C
96 return 0; /* Pacify compiler. */
97#endif
98}
99
100
101static void uv__getaddrinfo_work(struct uv__work* w) {
102 uv_getaddrinfo_t* req;
103 int err;
104
105 req = container_of(w, uv_getaddrinfo_t, work_req);
106 err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
107 req->retcode = uv__getaddrinfo_translate_error(err);
108}
109
110
111static void uv__getaddrinfo_done(struct uv__work* w, int status) {
112 uv_getaddrinfo_t* req;
113
114 req = container_of(w, uv_getaddrinfo_t, work_req);
115 uv__req_unregister(req->loop, req);
116
117 /* See initialization in uv_getaddrinfo(). */
118 if (req->hints)
119 uv__free(req->hints);
120 else if (req->service)
121 uv__free(req->service);
122 else if (req->hostname)
123 uv__free(req->hostname);
124 else
125 assert(0);
126
127 req->hints = NULL;
128 req->service = NULL;
129 req->hostname = NULL;
130
131 if (status == UV_ECANCELED) {
132 assert(req->retcode == 0);
133 req->retcode = UV_EAI_CANCELED;
134 }
135
136 if (req->cb)
137 req->cb(req, req->retcode, req->addrinfo);
138}
139
140
141int uv_getaddrinfo(uv_loop_t* loop,
142 uv_getaddrinfo_t* req,
143 uv_getaddrinfo_cb cb,
144 const char* hostname,
145 const char* service,
146 const struct addrinfo* hints) {
147 char hostname_ascii[256];
148 size_t hostname_len;
149 size_t service_len;
150 size_t hints_len;
151 size_t len;
152 char* buf;
153 long rc;
154
155 if (req == NULL || (hostname == NULL && service == NULL))
156 return UV_EINVAL;
157
158 /* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
159 * probably because it uses EBCDIC rather than ASCII.
160 */
161#ifdef __MVS__
162 (void) &hostname_ascii;
163#else
164 if (hostname != NULL) {
165 rc = uv__idna_toascii(hostname,
166 hostname + strlen(hostname),
167 hostname_ascii,
168 hostname_ascii + sizeof(hostname_ascii));
169 if (rc < 0)
170 return rc;
171 hostname = hostname_ascii;
172 }
173#endif
174
175 hostname_len = hostname ? strlen(hostname) + 1 : 0;
176 service_len = service ? strlen(service) + 1 : 0;
177 hints_len = hints ? sizeof(*hints) : 0;
178 buf = uv__malloc(hostname_len + service_len + hints_len);
179
180 if (buf == NULL)
181 return UV_ENOMEM;
182
183 uv__req_init(loop, req, UV_GETADDRINFO);
184 req->loop = loop;
185 req->cb = cb;
186 req->addrinfo = NULL;
187 req->hints = NULL;
188 req->service = NULL;
189 req->hostname = NULL;
190 req->retcode = 0;
191
192 /* order matters, see uv_getaddrinfo_done() */
193 len = 0;
194
195 if (hints) {
196 req->hints = memcpy(buf + len, hints, sizeof(*hints));
197 len += sizeof(*hints);
198 }
199
200 if (service) {
201 req->service = memcpy(buf + len, service, service_len);
202 len += service_len;
203 }
204
205 if (hostname)
206 req->hostname = memcpy(buf + len, hostname, hostname_len);
207
208 if (cb) {
209 uv__work_submit(loop,
210 &req->work_req,
211 UV__WORK_SLOW_IO,
212 uv__getaddrinfo_work,
213 uv__getaddrinfo_done);
214 return 0;
215 } else {
216 uv__getaddrinfo_work(&req->work_req);
217 uv__getaddrinfo_done(&req->work_req, 0);
218 return req->retcode;
219 }
220}
221
222
223void uv_freeaddrinfo(struct addrinfo* ai) {
224 if (ai)
225 freeaddrinfo(ai);
226}
227
228
229int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
230 char ifname_buf[UV_IF_NAMESIZE];
231 size_t len;
232
233 if (buffer == NULL || size == NULL || *size == 0)
234 return UV_EINVAL;
235
236 if (if_indextoname(ifindex, ifname_buf) == NULL)
237 return UV__ERR(errno);
238
239 len = strnlen(ifname_buf, sizeof(ifname_buf));
240
241 if (*size <= len) {
242 *size = len + 1;
243 return UV_ENOBUFS;
244 }
245
246 memcpy(buffer, ifname_buf, len);
247 buffer[len] = '\0';
248 *size = len;
249
250 return 0;
251}
252
253int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
254 return uv_if_indextoname(ifindex, buffer, size);
255}
256