1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21 
22 #include <assert.h>
23 #include <stdio.h>
24 
25 #include "uv.h"
26 #include "internal.h"
27 #include "req-inl.h"
28 
29 #ifndef GetNameInfo
30 int WSAAPI GetNameInfoW(
31   const SOCKADDR *pSockaddr,
32   socklen_t SockaddrLength,
33   PWCHAR pNodeBuffer,
34   DWORD NodeBufferSize,
35   PWCHAR pServiceBuffer,
36   DWORD ServiceBufferSize,
37   INT Flags
38 );
39 #endif
40 
uv__getnameinfo_work(struct uv__work * w)41 static void uv__getnameinfo_work(struct uv__work* w) {
42   uv_getnameinfo_t* req;
43   WCHAR host[NI_MAXHOST];
44   WCHAR service[NI_MAXSERV];
45   int ret;
46 
47   req = container_of(w, uv_getnameinfo_t, work_req);
48   if (GetNameInfoW((struct sockaddr*)&req->storage,
49                    sizeof(req->storage),
50                    host,
51                    ARRAY_SIZE(host),
52                    service,
53                    ARRAY_SIZE(service),
54                    req->flags)) {
55     ret = WSAGetLastError();
56     req->retcode = uv__getaddrinfo_translate_error(ret);
57     return;
58   }
59 
60   ret = WideCharToMultiByte(CP_UTF8,
61                             0,
62                             host,
63                             -1,
64                             req->host,
65                             sizeof(req->host),
66                             NULL,
67                             NULL);
68   if (ret == 0) {
69     req->retcode = uv_translate_sys_error(GetLastError());
70     return;
71   }
72 
73   ret = WideCharToMultiByte(CP_UTF8,
74                             0,
75                             service,
76                             -1,
77                             req->service,
78                             sizeof(req->service),
79                             NULL,
80                             NULL);
81   if (ret == 0) {
82     req->retcode = uv_translate_sys_error(GetLastError());
83   }
84 }
85 
86 
87 /*
88 * Called from uv_run when complete.
89 */
uv__getnameinfo_done(struct uv__work * w,int status)90 static void uv__getnameinfo_done(struct uv__work* w, int status) {
91   uv_getnameinfo_t* req;
92   char* host;
93   char* service;
94 
95   req = container_of(w, uv_getnameinfo_t, work_req);
96   uv__req_unregister(req->loop, req);
97   host = service = NULL;
98 
99   if (status == UV_ECANCELED) {
100     assert(req->retcode == 0);
101     req->retcode = UV_EAI_CANCELED;
102   } else if (req->retcode == 0) {
103     host = req->host;
104     service = req->service;
105   }
106 
107   if (req->getnameinfo_cb)
108     req->getnameinfo_cb(req, req->retcode, host, service);
109 }
110 
111 
112 /*
113 * Entry point for getnameinfo
114 * return 0 if a callback will be made
115 * return error code if validation fails
116 */
uv_getnameinfo(uv_loop_t * loop,uv_getnameinfo_t * req,uv_getnameinfo_cb getnameinfo_cb,const struct sockaddr * addr,int flags)117 int uv_getnameinfo(uv_loop_t* loop,
118                    uv_getnameinfo_t* req,
119                    uv_getnameinfo_cb getnameinfo_cb,
120                    const struct sockaddr* addr,
121                    int flags) {
122   if (req == NULL || addr == NULL)
123     return UV_EINVAL;
124 
125   if (addr->sa_family == AF_INET) {
126     memcpy(&req->storage,
127            addr,
128            sizeof(struct sockaddr_in));
129   } else if (addr->sa_family == AF_INET6) {
130     memcpy(&req->storage,
131            addr,
132            sizeof(struct sockaddr_in6));
133   } else {
134     return UV_EINVAL;
135   }
136 
137   UV_REQ_INIT(req, UV_GETNAMEINFO);
138   uv__req_register(loop, req);
139 
140   req->getnameinfo_cb = getnameinfo_cb;
141   req->flags = flags;
142   req->loop = loop;
143   req->retcode = 0;
144 
145   if (getnameinfo_cb) {
146     uv__work_submit(loop,
147                     &req->work_req,
148                     UV__WORK_SLOW_IO,
149                     uv__getnameinfo_work,
150                     uv__getnameinfo_done);
151     return 0;
152   } else {
153     uv__getnameinfo_work(&req->work_req);
154     uv__getnameinfo_done(&req->work_req, 0);
155     return req->retcode;
156   }
157 }
158