/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /* Expose glibc-specific EAI_* error codes. Needs to be defined before we * include any headers. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include "uv.h" #include "internal.h" #include "idna.h" #include <errno.h> #include <stddef.h> /* NULL */ #include <stdlib.h> #include <string.h> #include <net/if.h> /* if_indextoname() */ /* EAI_* constants. */ #include <netdb.h> int uv__getaddrinfo_translate_error(int sys_err) { switch (sys_err) { case 0: return 0; #if defined(EAI_ADDRFAMILY) case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; #endif #if defined(EAI_AGAIN) case EAI_AGAIN: return UV_EAI_AGAIN; #endif #if defined(EAI_BADFLAGS) case EAI_BADFLAGS: return UV_EAI_BADFLAGS; #endif #if defined(EAI_BADHINTS) case EAI_BADHINTS: return UV_EAI_BADHINTS; #endif #if defined(EAI_CANCELED) case EAI_CANCELED: return UV_EAI_CANCELED; #endif #if defined(EAI_FAIL) case EAI_FAIL: return UV_EAI_FAIL; #endif #if defined(EAI_FAMILY) case EAI_FAMILY: return UV_EAI_FAMILY; #endif #if defined(EAI_MEMORY) case EAI_MEMORY: return UV_EAI_MEMORY; #endif #if defined(EAI_NODATA) case EAI_NODATA: return UV_EAI_NODATA; #endif #if defined(EAI_NONAME) # if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME case EAI_NONAME: return UV_EAI_NONAME; # endif #endif #if defined(EAI_OVERFLOW) case EAI_OVERFLOW: return UV_EAI_OVERFLOW; #endif #if defined(EAI_PROTOCOL) case EAI_PROTOCOL: return UV_EAI_PROTOCOL; #endif #if defined(EAI_SERVICE) case EAI_SERVICE: return UV_EAI_SERVICE; #endif #if defined(EAI_SOCKTYPE) case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; #endif #if defined(EAI_SYSTEM) case EAI_SYSTEM: return UV__ERR(errno); #endif } assert(!"unknown EAI_* error code"); abort(); #ifndef __SUNPRO_C return 0; /* Pacify compiler. */ #endif } static void uv__getaddrinfo_work(struct uv__work* w) { uv_getaddrinfo_t* req; int err; req = container_of(w, uv_getaddrinfo_t, work_req); err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo); req->retcode = uv__getaddrinfo_translate_error(err); } static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; req = container_of(w, uv_getaddrinfo_t, work_req); uv__req_unregister(req->loop, req); /* See initialization in uv_getaddrinfo(). */ if (req->hints) uv__free(req->hints); else if (req->service) uv__free(req->service); else if (req->hostname) uv__free(req->hostname); else assert(0); req->hints = NULL; req->service = NULL; req->hostname = NULL; if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } if (req->cb) req->cb(req, req->retcode, req->addrinfo); } int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb cb, const char* hostname, const char* service, const struct addrinfo* hints) { char hostname_ascii[256]; size_t hostname_len; size_t service_len; size_t hints_len; size_t len; char* buf; long rc; if (req == NULL || (hostname == NULL && service == NULL)) return UV_EINVAL; /* FIXME(bnoordhuis) IDNA does not seem to work z/OS, * probably because it uses EBCDIC rather than ASCII. */ #ifdef __MVS__ (void) &hostname_ascii; #else if (hostname != NULL) { rc = uv__idna_toascii(hostname, hostname + strlen(hostname), hostname_ascii, hostname_ascii + sizeof(hostname_ascii)); if (rc < 0) return rc; hostname = hostname_ascii; } #endif hostname_len = hostname ? strlen(hostname) + 1 : 0; service_len = service ? strlen(service) + 1 : 0; hints_len = hints ? sizeof(*hints) : 0; buf = uv__malloc(hostname_len + service_len + hints_len); if (buf == NULL) return UV_ENOMEM; uv__req_init(loop, req, UV_GETADDRINFO); req->loop = loop; req->cb = cb; req->addrinfo = NULL; req->hints = NULL; req->service = NULL; req->hostname = NULL; req->retcode = 0; /* order matters, see uv_getaddrinfo_done() */ len = 0; if (hints) { req->hints = memcpy(buf + len, hints, sizeof(*hints)); len += sizeof(*hints); } if (service) { req->service = memcpy(buf + len, service, service_len); len += service_len; } if (hostname) req->hostname = memcpy(buf + len, hostname, hostname_len); if (cb) { uv__work_submit(loop, &req->work_req, UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; } else { uv__getaddrinfo_work(&req->work_req); uv__getaddrinfo_done(&req->work_req, 0); return req->retcode; } } void uv_freeaddrinfo(struct addrinfo* ai) { if (ai) freeaddrinfo(ai); } int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { char ifname_buf[UV_IF_NAMESIZE]; size_t len; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; if (if_indextoname(ifindex, ifname_buf) == NULL) return UV__ERR(errno); len = strnlen(ifname_buf, sizeof(ifname_buf)); if (*size <= len) { *size = len + 1; return UV_ENOBUFS; } memcpy(buffer, ifname_buf, len); buffer[len] = '\0'; *size = len; return 0; } int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { return uv_if_indextoname(ifindex, buffer, size); }