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