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 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 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 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 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 223 void uv_freeaddrinfo(struct addrinfo* ai) { 224 if (ai) 225 freeaddrinfo(ai); 226 } 227 228 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 253 int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { 254 return uv_if_indextoname(ifindex, buffer, size); 255 } 256