/* 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. */ #include "uv.h" #include "uv-common.h" #include #include #include /* NULL */ #include /* malloc */ #include /* memset */ #if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) && !defined(_WIN32) # include /* if_nametoindex */ #endif /* EAI_* constants. */ #if !defined(_WIN32) # include # include # include #endif #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); size_t uv_handle_size(uv_handle_type type) { switch (type) { UV_HANDLE_TYPE_MAP(XX) default: return -1; } } size_t uv_req_size(uv_req_type type) { switch(type) { UV_REQ_TYPE_MAP(XX) default: return -1; } } #undef XX size_t uv_strlcpy(char* dst, const char* src, size_t size) { size_t n; if (size == 0) return 0; for (n = 0; n < (size - 1) && *src != '\0'; n++) *dst++ = *src++; *dst = '\0'; return n; } size_t uv_strlcat(char* dst, const char* src, size_t size) { size_t n; if (size == 0) return 0; for (n = 0; n < size && *dst != '\0'; n++, dst++); if (n == size) return n; while (n < (size - 1) && *src != '\0') n++, *dst++ = *src++; *dst = '\0'; return n; } uv_buf_t uv_buf_init(char* base, unsigned int len) { uv_buf_t buf; buf.base = base; buf.len = len; return buf; } #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; const char* uv_err_name(int err) { switch (err) { UV_ERRNO_MAP(UV_ERR_NAME_GEN) default: assert(0); return NULL; } } #undef UV_ERR_NAME_GEN #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; const char* uv_strerror(int err) { switch (err) { UV_ERRNO_MAP(UV_STRERROR_GEN) default: return "Unknown system error"; } } #undef UV_STRERROR_GEN struct sockaddr_in uv_ip4_addr(const char* ip, int port) { struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); return addr; } struct sockaddr_in6 uv_ip6_addr(const char* ip, int port) { struct sockaddr_in6 addr; #if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) char address_part[40]; size_t address_part_size; const char* zone_index; #endif memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(port); #if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) zone_index = strchr(ip, '%'); if (zone_index != NULL) { address_part_size = zone_index - ip; if (address_part_size >= sizeof(address_part)) address_part_size = sizeof(address_part) - 1; memcpy(address_part, ip, address_part_size); address_part[address_part_size] = '\0'; ip = address_part; zone_index++; /* skip '%' */ /* NOTE: unknown interface (id=0) is silently ignored */ #ifdef _WIN32 addr.sin6_scope_id = atoi(zone_index); #else addr.sin6_scope_id = if_nametoindex(zone_index); #endif } #endif /* result code is ignored - we assume ip is a valid IPv6 address */ uv_inet_pton(AF_INET6, ip, &addr.sin6_addr); return addr; } int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size); } int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); } int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) { if (handle->type != UV_TCP || addr.sin_family != AF_INET) return UV_EINVAL; else return uv__tcp_bind(handle, addr); } int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { if (handle->type != UV_TCP || addr.sin6_family != AF_INET6) return UV_EINVAL; else return uv__tcp_bind6(handle, addr); } int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned int flags) { if (handle->type != UV_UDP || addr.sin_family != AF_INET) return UV_EINVAL; else return uv__udp_bind(handle, addr, flags); } int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned int flags) { if (handle->type != UV_UDP || addr.sin6_family != AF_INET6) return UV_EINVAL; else return uv__udp_bind6(handle, addr, flags); } int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in address, uv_connect_cb cb) { if (handle->type != UV_TCP || address.sin_family != AF_INET) return UV_EINVAL; else return uv__tcp_connect(req, handle, address, cb); } int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in6 address, uv_connect_cb cb) { if (handle->type != UV_TCP || address.sin6_family != AF_INET6) return UV_EINVAL; else return uv__tcp_connect6(req, handle, address, cb); } int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr_in addr, uv_udp_send_cb send_cb) { if (handle->type != UV_UDP || addr.sin_family != AF_INET) return UV_EINVAL; else return uv__udp_send(req, handle, bufs, bufcnt, addr, send_cb); } int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb send_cb) { if (handle->type != UV_UDP || addr.sin6_family != AF_INET6) return UV_EINVAL; else return uv__udp_send6(req, handle, bufs, bufcnt, addr, send_cb); } int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) return UV_EINVAL; else return uv__udp_recv_start(handle, alloc_cb, recv_cb); } int uv_udp_recv_stop(uv_udp_t* handle) { if (handle->type != UV_UDP) return UV_EINVAL; else return uv__udp_recv_stop(handle); } struct thread_ctx { void (*entry)(void* arg); void* arg; }; #ifdef _WIN32 static UINT __stdcall uv__thread_start(void* arg) #else static void* uv__thread_start(void *arg) #endif { struct thread_ctx *ctx_p; struct thread_ctx ctx; ctx_p = arg; ctx = *ctx_p; free(ctx_p); ctx.entry(ctx.arg); return 0; } int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct thread_ctx* ctx; int err; ctx = malloc(sizeof(*ctx)); if (ctx == NULL) return UV_ENOMEM; ctx->entry = entry; ctx->arg = arg; #ifdef _WIN32 *tid = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, ctx, 0, NULL); err = *tid ? 0 : errno; #else err = pthread_create(tid, NULL, uv__thread_start, ctx); #endif if (err) free(ctx); return err ? -1 : 0; } unsigned long uv_thread_self(void) { #ifdef _WIN32 return (unsigned long) GetCurrentThreadId(); #else return (unsigned long) pthread_self(); #endif } void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { QUEUE* q; uv_handle_t* h; QUEUE_FOREACH(q, &loop->handle_queue) { h = QUEUE_DATA(q, uv_handle_t, handle_queue); if (h->flags & UV__HANDLE_INTERNAL) continue; walk_cb(h, arg); } } #ifndef NDEBUG static void uv__print_handles(uv_loop_t* loop, int only_active) { const char* type; QUEUE* q; uv_handle_t* h; if (loop == NULL) loop = uv_default_loop(); QUEUE_FOREACH(q, &loop->handle_queue) { h = QUEUE_DATA(q, uv_handle_t, handle_queue); if (only_active && !uv__is_active(h)) continue; switch (h->type) { #define X(uc, lc) case UV_##uc: type = #lc; break; UV_HANDLE_TYPE_MAP(X) #undef X default: type = ""; } fprintf(stderr, "[%c%c%c] %-8s %p\n", "R-"[!(h->flags & UV__HANDLE_REF)], "A-"[!(h->flags & UV__HANDLE_ACTIVE)], "I-"[!(h->flags & UV__HANDLE_INTERNAL)], type, (void*)h); } } void uv_print_all_handles(uv_loop_t* loop) { uv__print_handles(loop, 0); } void uv_print_active_handles(uv_loop_t* loop) { uv__print_handles(loop, 1); } #endif void uv_ref(uv_handle_t* handle) { uv__handle_ref(handle); } void uv_unref(uv_handle_t* handle) { uv__handle_unref(handle); } int uv_has_ref(const uv_handle_t* handle) { return uv__has_ref(handle); } void uv_stop(uv_loop_t* loop) { loop->stop_flag = 1; } uint64_t uv_now(uv_loop_t* loop) { return loop->time; } 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_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_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_EAI_SYSTEM; #endif } assert(!"unknown EAI_* error code"); abort(); return 0; /* Pacify compiler. */ }