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
25#include "uv.h"
26#include "internal.h"
27#include "idna.h"
28
29#include <errno.h>
30#include <stddef.h> /* NULL */
31#include <stdlib.h>
32#include <string.h>
33#include <net/if.h> /* if_indextoname() */
34
35/* EAI_* constants. */
36#include <netdb.h>
37
38
39int uv__getaddrinfo_translate_error(int sys_err) {
40  switch (sys_err) {
41  case 0: return 0;
42#if defined(EAI_ADDRFAMILY)
43  case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
44#endif
45#if defined(EAI_AGAIN)
46  case EAI_AGAIN: return UV_EAI_AGAIN;
47#endif
48#if defined(EAI_BADFLAGS)
49  case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
50#endif
51#if defined(EAI_BADHINTS)
52  case EAI_BADHINTS: return UV_EAI_BADHINTS;
53#endif
54#if defined(EAI_CANCELED)
55  case EAI_CANCELED: return UV_EAI_CANCELED;
56#endif
57#if defined(EAI_FAIL)
58  case EAI_FAIL: return UV_EAI_FAIL;
59#endif
60#if defined(EAI_FAMILY)
61  case EAI_FAMILY: return UV_EAI_FAMILY;
62#endif
63#if defined(EAI_MEMORY)
64  case EAI_MEMORY: return UV_EAI_MEMORY;
65#endif
66#if defined(EAI_NODATA)
67  case EAI_NODATA: return UV_EAI_NODATA;
68#endif
69#if defined(EAI_NONAME)
70# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
71  case EAI_NONAME: return UV_EAI_NONAME;
72# endif
73#endif
74#if defined(EAI_OVERFLOW)
75  case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
76#endif
77#if defined(EAI_PROTOCOL)
78  case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
79#endif
80#if defined(EAI_SERVICE)
81  case EAI_SERVICE: return UV_EAI_SERVICE;
82#endif
83#if defined(EAI_SOCKTYPE)
84  case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
85#endif
86#if defined(EAI_SYSTEM)
87  case EAI_SYSTEM: return UV__ERR(errno);
88#endif
89  }
90  assert(!"unknown EAI_* error code");
91  abort();
92#ifndef __SUNPRO_C
93  return 0;  /* Pacify compiler. */
94#endif
95}
96
97
98static void uv__getaddrinfo_work(struct uv__work* w) {
99  uv_getaddrinfo_t* req;
100  int err;
101
102  req = container_of(w, uv_getaddrinfo_t, work_req);
103  err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
104  req->retcode = uv__getaddrinfo_translate_error(err);
105}
106
107
108static void uv__getaddrinfo_done(struct uv__work* w, int status) {
109  uv_getaddrinfo_t* req;
110
111  req = container_of(w, uv_getaddrinfo_t, work_req);
112  uv__req_unregister(req->loop, req);
113
114  /* See initialization in uv_getaddrinfo(). */
115  if (req->hints)
116    uv__free(req->hints);
117  else if (req->service)
118    uv__free(req->service);
119  else if (req->hostname)
120    uv__free(req->hostname);
121  else
122    assert(0);
123
124  req->hints = NULL;
125  req->service = NULL;
126  req->hostname = NULL;
127
128  if (status == UV_ECANCELED) {
129    assert(req->retcode == 0);
130    req->retcode = UV_EAI_CANCELED;
131  }
132
133  if (req->cb)
134    req->cb(req, req->retcode, req->addrinfo);
135}
136
137
138int uv_getaddrinfo(uv_loop_t* loop,
139                   uv_getaddrinfo_t* req,
140                   uv_getaddrinfo_cb cb,
141                   const char* hostname,
142                   const char* service,
143                   const struct addrinfo* hints) {
144  char hostname_ascii[256];
145  size_t hostname_len;
146  size_t service_len;
147  size_t hints_len;
148  size_t len;
149  char* buf;
150  long rc;
151
152  if (req == NULL || (hostname == NULL && service == NULL))
153    return UV_EINVAL;
154
155  /* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
156   * probably because it uses EBCDIC rather than ASCII.
157   */
158#ifdef __MVS__
159  (void) &hostname_ascii;
160#else
161  if (hostname != NULL) {
162    rc = uv__idna_toascii(hostname,
163                          hostname + strlen(hostname),
164                          hostname_ascii,
165                          hostname_ascii + sizeof(hostname_ascii));
166    if (rc < 0)
167      return rc;
168    hostname = hostname_ascii;
169  }
170#endif
171
172  hostname_len = hostname ? strlen(hostname) + 1 : 0;
173  service_len = service ? strlen(service) + 1 : 0;
174  hints_len = hints ? sizeof(*hints) : 0;
175  buf = uv__malloc(hostname_len + service_len + hints_len);
176
177  if (buf == NULL)
178    return UV_ENOMEM;
179
180  uv__req_init(loop, req, UV_GETADDRINFO);
181  req->loop = loop;
182  req->cb = cb;
183  req->addrinfo = NULL;
184  req->hints = NULL;
185  req->service = NULL;
186  req->hostname = NULL;
187  req->retcode = 0;
188
189  /* order matters, see uv_getaddrinfo_done() */
190  len = 0;
191
192  if (hints) {
193    req->hints = memcpy(buf + len, hints, sizeof(*hints));
194    len += sizeof(*hints);
195  }
196
197  if (service) {
198    req->service = memcpy(buf + len, service, service_len);
199    len += service_len;
200  }
201
202  if (hostname)
203    req->hostname = memcpy(buf + len, hostname, hostname_len);
204
205  if (cb) {
206    uv__work_submit(loop,
207                    &req->work_req,
208                    UV__WORK_SLOW_IO,
209                    uv__getaddrinfo_work,
210                    uv__getaddrinfo_done);
211    return 0;
212  } else {
213    uv__getaddrinfo_work(&req->work_req);
214    uv__getaddrinfo_done(&req->work_req, 0);
215    return req->retcode;
216  }
217}
218
219
220void uv_freeaddrinfo(struct addrinfo* ai) {
221  if (ai)
222    freeaddrinfo(ai);
223}
224
225
226int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
227  char ifname_buf[UV_IF_NAMESIZE];
228  size_t len;
229
230  if (buffer == NULL || size == NULL || *size == 0)
231    return UV_EINVAL;
232
233  if (if_indextoname(ifindex, ifname_buf) == NULL)
234    return UV__ERR(errno);
235
236  len = strnlen(ifname_buf, sizeof(ifname_buf));
237
238  if (*size <= len) {
239    *size = len + 1;
240    return UV_ENOBUFS;
241  }
242
243  memcpy(buffer, ifname_buf, len);
244  buffer[len] = '\0';
245  *size = len;
246
247  return 0;
248}
249
250int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
251  return uv_if_indextoname(ifindex, buffer, size);
252}
253