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 
uv__getaddrinfo_translate_error(int sys_err)42 int 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 
uv__getaddrinfo_work(struct uv__work * w)101 static 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 
uv__getaddrinfo_done(struct uv__work * w,int status)111 static 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 
uv_getaddrinfo(uv_loop_t * loop,uv_getaddrinfo_t * req,uv_getaddrinfo_cb cb,const char * hostname,const char * service,const struct addrinfo * hints)141 int 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 
uv_freeaddrinfo(struct addrinfo * ai)223 void uv_freeaddrinfo(struct addrinfo* ai) {
224   if (ai)
225     freeaddrinfo(ai);
226 }
227 
228 
uv_if_indextoname(unsigned int ifindex,char * buffer,size_t * size)229 int 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 
uv_if_indextoiid(unsigned int ifindex,char * buffer,size_t * size)253 int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
254   return uv_if_indextoname(ifindex, buffer, size);
255 }
256