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 <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "uv.h"
28#include "internal.h"
29
30
31static void uv__getnameinfo_work(struct uv__work* w) {
32  uv_getnameinfo_t* req;
33  int err;
34  socklen_t salen;
35
36  req = container_of(w, uv_getnameinfo_t, work_req);
37
38  if (req->storage.ss_family == AF_INET)
39    salen = sizeof(struct sockaddr_in);
40  else if (req->storage.ss_family == AF_INET6)
41    salen = sizeof(struct sockaddr_in6);
42  else
43    abort();
44
45  err = getnameinfo((struct sockaddr*) &req->storage,
46                    salen,
47                    req->host,
48                    sizeof(req->host),
49                    req->service,
50                    sizeof(req->service),
51                    req->flags);
52  req->retcode = uv__getaddrinfo_translate_error(err);
53}
54
55static void uv__getnameinfo_done(struct uv__work* w, int status) {
56  uv_getnameinfo_t* req;
57  char* host;
58  char* service;
59
60  req = container_of(w, uv_getnameinfo_t, work_req);
61  uv__req_unregister(req->loop, req);
62  host = service = NULL;
63
64  if (status == UV_ECANCELED) {
65    assert(req->retcode == 0);
66    req->retcode = UV_EAI_CANCELED;
67  } else if (req->retcode == 0) {
68    host = req->host;
69    service = req->service;
70  }
71
72  if (req->getnameinfo_cb)
73    req->getnameinfo_cb(req, req->retcode, host, service);
74}
75
76/*
77* Entry point for getnameinfo
78* return 0 if a callback will be made
79* return error code if validation fails
80*/
81int uv_getnameinfo(uv_loop_t* loop,
82                   uv_getnameinfo_t* req,
83                   uv_getnameinfo_cb getnameinfo_cb,
84                   const struct sockaddr* addr,
85                   int flags) {
86  if (req == NULL || addr == NULL)
87    return UV_EINVAL;
88
89  if (addr->sa_family == AF_INET) {
90    memcpy(&req->storage,
91           addr,
92           sizeof(struct sockaddr_in));
93  } else if (addr->sa_family == AF_INET6) {
94    memcpy(&req->storage,
95           addr,
96           sizeof(struct sockaddr_in6));
97  } else {
98    return UV_EINVAL;
99  }
100
101  uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
102
103  req->getnameinfo_cb = getnameinfo_cb;
104  req->flags = flags;
105  req->type = UV_GETNAMEINFO;
106  req->loop = loop;
107  req->retcode = 0;
108
109  if (getnameinfo_cb) {
110    uv__work_submit(loop,
111                    &req->work_req,
112                    UV__WORK_SLOW_IO,
113                    uv__getnameinfo_work,
114                    uv__getnameinfo_done);
115    return 0;
116  } else {
117    uv__getnameinfo_work(&req->work_req);
118    uv__getnameinfo_done(&req->work_req, 0);
119    return req->retcode;
120  }
121}
122