libuv-svace-build

Форк
0
/
getaddrinfo.c 
383 строки · 11.8 Кб
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

24
#include "uv.h"
25
#include "internal.h"
26
#include "req-inl.h"
27
#include "idna.h"
28

29
/* EAI_* constants. */
30
#include <winsock2.h>
31

32
/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
33
#include <iphlpapi.h>
34

35
int uv__getaddrinfo_translate_error(int sys_err) {
36
  switch (sys_err) {
37
    case 0:                       return 0;
38
    case WSATRY_AGAIN:            return UV_EAI_AGAIN;
39
    case WSAEINVAL:               return UV_EAI_BADFLAGS;
40
    case WSANO_RECOVERY:          return UV_EAI_FAIL;
41
    case WSAEAFNOSUPPORT:         return UV_EAI_FAMILY;
42
    case WSA_NOT_ENOUGH_MEMORY:   return UV_EAI_MEMORY;
43
    case WSAHOST_NOT_FOUND:       return UV_EAI_NONAME;
44
    case WSATYPE_NOT_FOUND:       return UV_EAI_SERVICE;
45
    case WSAESOCKTNOSUPPORT:      return UV_EAI_SOCKTYPE;
46
    default:                      return uv_translate_sys_error(sys_err);
47
  }
48
}
49

50

51
/*
52
 * MinGW is missing this
53
 */
54
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
55
  typedef struct addrinfoW {
56
    int ai_flags;
57
    int ai_family;
58
    int ai_socktype;
59
    int ai_protocol;
60
    size_t ai_addrlen;
61
    WCHAR* ai_canonname;
62
    struct sockaddr* ai_addr;
63
    struct addrinfoW* ai_next;
64
  } ADDRINFOW, *PADDRINFOW;
65

66
  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
67
                                          const WCHAR* service,
68
                                          const ADDRINFOW* hints,
69
                                          PADDRINFOW* result);
70

71
  DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
72
#endif
73

74

75
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
76
 * Do we need different versions of this for different architectures? */
77
#define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
78

79
#ifndef NDIS_IF_MAX_STRING_SIZE
80
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
81
#endif
82

83
static void uv__getaddrinfo_work(struct uv__work* w) {
84
  uv_getaddrinfo_t* req;
85
  struct addrinfoW* hints;
86
  int err;
87

88
  req = container_of(w, uv_getaddrinfo_t, work_req);
89
  hints = req->addrinfow;
90
  req->addrinfow = NULL;
91
  err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
92
  req->retcode = uv__getaddrinfo_translate_error(err);
93
}
94

95

96
/*
97
 * Called from uv_run when complete. Call user specified callback
98
 * then free returned addrinfo
99
 * Returned addrinfo strings are converted from UTF-16 to UTF-8.
100
 *
101
 * To minimize allocation we calculate total size required,
102
 * and copy all structs and referenced strings into the one block.
103
 * Each size calculation is adjusted to avoid unaligned pointers.
104
 */
105
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
106
  uv_getaddrinfo_t* req;
107
  size_t addrinfo_len = 0;
108
  ssize_t name_len = 0;
109
  size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
110
  struct addrinfoW* addrinfow_ptr;
111
  struct addrinfo* addrinfo_ptr;
112
  char* alloc_ptr = NULL;
113
  char* cur_ptr = NULL;
114
  int r;
115

116
  req = container_of(w, uv_getaddrinfo_t, work_req);
117

118
  /* release input parameter memory */
119
  uv__free(req->alloc);
120
  req->alloc = NULL;
121

122
  if (status == UV_ECANCELED) {
123
    assert(req->retcode == 0);
124
    req->retcode = UV_EAI_CANCELED;
125
    goto complete;
126
  }
127

128
  if (req->retcode == 0) {
129
    /* Convert addrinfoW to addrinfo. First calculate required length. */
130
    addrinfow_ptr = req->addrinfow;
131
    while (addrinfow_ptr != NULL) {
132
      addrinfo_len += addrinfo_struct_len +
133
          ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
134
      if (addrinfow_ptr->ai_canonname != NULL) {
135
        name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1);
136
        if (name_len < 0) {
137
          req->retcode = name_len;
138
          goto complete;
139
        }
140
        addrinfo_len += ALIGNED_SIZE(name_len + 1);
141
      }
142
      addrinfow_ptr = addrinfow_ptr->ai_next;
143
    }
144

145
    /* allocate memory for addrinfo results */
146
    alloc_ptr = (char*)uv__malloc(addrinfo_len);
147

148
    /* do conversions */
149
    if (alloc_ptr != NULL) {
150
      cur_ptr = alloc_ptr;
151
      addrinfow_ptr = req->addrinfow;
152

153
      while (addrinfow_ptr != NULL) {
154
        /* copy addrinfo struct data */
155
        assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
156
        addrinfo_ptr = (struct addrinfo*)cur_ptr;
157
        addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
158
        addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
159
        addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
160
        addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
161
        addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
162
        addrinfo_ptr->ai_canonname = NULL;
163
        addrinfo_ptr->ai_addr = NULL;
164
        addrinfo_ptr->ai_next = NULL;
165

166
        cur_ptr += addrinfo_struct_len;
167

168
        /* copy sockaddr */
169
        if (addrinfo_ptr->ai_addrlen > 0) {
170
          assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
171
                 alloc_ptr + addrinfo_len);
172
          memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
173
          addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
174
          cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
175
        }
176

177
        /* convert canonical name to UTF-8 */
178
        if (addrinfow_ptr->ai_canonname != NULL) {
179
          name_len = alloc_ptr + addrinfo_len - cur_ptr;
180
          r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
181
                                     -1,
182
                                     cur_ptr,
183
                                     (size_t*)&name_len);
184
          assert(r == 0);
185
          addrinfo_ptr->ai_canonname = cur_ptr;
186
          cur_ptr += ALIGNED_SIZE(name_len + 1);
187
        }
188
        assert(cur_ptr <= alloc_ptr + addrinfo_len);
189

190
        /* set next ptr */
191
        addrinfow_ptr = addrinfow_ptr->ai_next;
192
        if (addrinfow_ptr != NULL) {
193
          addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
194
        }
195
      }
196
      req->addrinfo = (struct addrinfo*)alloc_ptr;
197
    } else {
198
      req->retcode = UV_EAI_MEMORY;
199
    }
200
  }
201

202
  /* return memory to system */
203
  if (req->addrinfow != NULL) {
204
    FreeAddrInfoW(req->addrinfow);
205
    req->addrinfow = NULL;
206
  }
207

208
complete:
209
  uv__req_unregister(req->loop, req);
210

211
  /* finally do callback with converted result */
212
  if (req->getaddrinfo_cb)
213
    req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
214
}
215

216

217
void uv_freeaddrinfo(struct addrinfo* ai) {
218
  char* alloc_ptr = (char*)ai;
219

220
  /* release copied result memory */
221
  uv__free(alloc_ptr);
222
}
223

224

225
/*
226
 * Entry point for getaddrinfo
227
 * we convert the UTF-8 strings to UNICODE
228
 * and save the UNICODE string pointers in the req
229
 * We also copy hints so that caller does not need to keep memory until the
230
 * callback.
231
 * return 0 if a callback will be made
232
 * return error code if validation fails
233
 *
234
 * To minimize allocation we calculate total size required,
235
 * and copy all structs and referenced strings into the one block.
236
 * Each size calculation is adjusted to avoid unaligned pointers.
237
 */
238
int uv_getaddrinfo(uv_loop_t* loop,
239
                   uv_getaddrinfo_t* req,
240
                   uv_getaddrinfo_cb getaddrinfo_cb,
241
                   const char* node,
242
                   const char* service,
243
                   const struct addrinfo* hints) {
244
  char hostname_ascii[256];
245
  size_t nodesize = 0;
246
  size_t servicesize = 0;
247
  size_t hintssize = 0;
248
  char* alloc_ptr = NULL;
249
  ssize_t rc;
250

251
  if (req == NULL || (node == NULL && service == NULL)) {
252
    return UV_EINVAL;
253
  }
254

255
  UV_REQ_INIT(req, UV_GETADDRINFO);
256
  req->getaddrinfo_cb = getaddrinfo_cb;
257
  req->addrinfo = NULL;
258
  req->loop = loop;
259
  req->retcode = 0;
260

261
  /* calculate required memory size for all input values */
262
  if (node != NULL) {
263
    rc = uv__idna_toascii(node,
264
                          node + strlen(node),
265
                          hostname_ascii,
266
                          hostname_ascii + sizeof(hostname_ascii));
267
    if (rc < 0)
268
      return rc;
269
    nodesize = strlen(hostname_ascii) + 1;
270
    node = hostname_ascii;
271
  }
272

273
  if (service != NULL) {
274
    rc = uv_wtf8_length_as_utf16(service);
275
    if (rc < 0)
276
       return rc;
277
    servicesize = rc;
278
  }
279
  if (hints != NULL) {
280
    hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
281
  }
282

283
  /* allocate memory for inputs, and partition it as needed */
284
  alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) +
285
                         ALIGNED_SIZE(servicesize * sizeof(WCHAR)) +
286
                         hintssize);
287
  if (!alloc_ptr)
288
    return UV_ENOMEM;
289

290
  /* save alloc_ptr now so we can free if error */
291
  req->alloc = (void*) alloc_ptr;
292

293
  /* Convert node string to UTF16 into allocated memory and save pointer in the
294
   * request. The node here has been converted to ascii. */
295
  if (node != NULL) {
296
    req->node = (WCHAR*) alloc_ptr;
297
    uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize);
298
    alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR));
299
  } else {
300
    req->node = NULL;
301
  }
302

303
  /* Convert service string to UTF16 into allocated memory and save pointer in
304
   * the req. */
305
  if (service != NULL) {
306
    req->service = (WCHAR*) alloc_ptr;
307
    uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize);
308
    alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR));
309
  } else {
310
    req->service = NULL;
311
  }
312

313
  /* copy hints to allocated memory and save pointer in req */
314
  if (hints != NULL) {
315
    req->addrinfow = (struct addrinfoW*) alloc_ptr;
316
    req->addrinfow->ai_family = hints->ai_family;
317
    req->addrinfow->ai_socktype = hints->ai_socktype;
318
    req->addrinfow->ai_protocol = hints->ai_protocol;
319
    req->addrinfow->ai_flags = hints->ai_flags;
320
    req->addrinfow->ai_addrlen = 0;
321
    req->addrinfow->ai_canonname = NULL;
322
    req->addrinfow->ai_addr = NULL;
323
    req->addrinfow->ai_next = NULL;
324
  } else {
325
    req->addrinfow = NULL;
326
  }
327

328
  uv__req_register(loop, req);
329

330
  if (getaddrinfo_cb) {
331
    uv__work_submit(loop,
332
                    &req->work_req,
333
                    UV__WORK_SLOW_IO,
334
                    uv__getaddrinfo_work,
335
                    uv__getaddrinfo_done);
336
    return 0;
337
  } else {
338
    uv__getaddrinfo_work(&req->work_req);
339
    uv__getaddrinfo_done(&req->work_req, 0);
340
    return req->retcode;
341
  }
342
}
343

344
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
345
  NET_LUID luid;
346
  wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
347
  int r;
348

349
  if (buffer == NULL || size == NULL || *size == 0)
350
    return UV_EINVAL;
351

352
  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
353

354
  if (r != 0)
355
    return uv_translate_sys_error(r);
356

357
  r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
358

359
  if (r != 0)
360
    return uv_translate_sys_error(r);
361

362
  return uv__copy_utf16_to_utf8(wname, -1, buffer, size);
363
}
364

365
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
366
  int r;
367

368
  if (buffer == NULL || size == NULL || *size == 0)
369
    return UV_EINVAL;
370

371
  r = snprintf(buffer, *size, "%d", ifindex);
372

373
  if (r < 0)
374
    return uv_translate_sys_error(r);
375

376
  if (r >= (int) *size) {
377
    *size = r + 1;
378
    return UV_ENOBUFS;
379
  }
380

381
  *size = r;
382
  return 0;
383
}
384

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.