/* 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 #include #include "uv.h" #include "internal.h" #include "req-inl.h" #ifndef GetNameInfo int WSAAPI GetNameInfoW( const SOCKADDR *pSockaddr, socklen_t SockaddrLength, PWCHAR pNodeBuffer, DWORD NodeBufferSize, PWCHAR pServiceBuffer, DWORD ServiceBufferSize, INT Flags ); #endif static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; int ret; req = container_of(w, uv_getnameinfo_t, work_req); if (GetNameInfoW((struct sockaddr*)&req->storage, sizeof(req->storage), host, ARRAY_SIZE(host), service, ARRAY_SIZE(service), req->flags)) { ret = WSAGetLastError(); req->retcode = uv__getaddrinfo_translate_error(ret); return; } ret = WideCharToMultiByte(CP_UTF8, 0, host, -1, req->host, sizeof(req->host), NULL, NULL); if (ret == 0) { req->retcode = uv_translate_sys_error(GetLastError()); return; } ret = WideCharToMultiByte(CP_UTF8, 0, service, -1, req->service, sizeof(req->service), NULL, NULL); if (ret == 0) { req->retcode = uv_translate_sys_error(GetLastError()); } } /* * Called from uv_run when complete. */ static void uv__getnameinfo_done(struct uv__work* w, int status) { uv_getnameinfo_t* req; char* host; char* service; req = container_of(w, uv_getnameinfo_t, work_req); uv__req_unregister(req->loop, req); host = service = NULL; if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } else if (req->retcode == 0) { host = req->host; service = req->service; } if (req->getnameinfo_cb) req->getnameinfo_cb(req, req->retcode, host, service); } /* * Entry point for getnameinfo * return 0 if a callback will be made * return error code if validation fails */ int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags) { if (req == NULL || addr == NULL) return UV_EINVAL; if (addr->sa_family == AF_INET) { memcpy(&req->storage, addr, sizeof(struct sockaddr_in)); } else if (addr->sa_family == AF_INET6) { memcpy(&req->storage, addr, sizeof(struct sockaddr_in6)); } else { return UV_EINVAL; } UV_REQ_INIT(req, UV_GETNAMEINFO); uv__req_register(loop, req); req->getnameinfo_cb = getnameinfo_cb; req->flags = flags; req->loop = loop; req->retcode = 0; if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; } else { uv__getnameinfo_work(&req->work_req); uv__getnameinfo_done(&req->work_req, 0); return req->retcode; } }