libdns: Convert dns_udp_request to 0/errno
[Samba.git] / libcli / dns / dns.c
blobcc3f90d298a6c003ea55a7ed3181eaf19759bda5
1 /*
2 Unix SMB/CIFS implementation.
4 Small async DNS library for Samba with socketwrapper support
6 Copyright (C) 2010 Kai Blin <kai@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "replace.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/dns/libdns.h"
27 #include "lib/util/tevent_unix.h"
28 #include "lib/util/samba_util.h"
29 #include "libcli/util/error.h"
30 #include "librpc/gen_ndr/dns.h"
32 struct dns_udp_request_state {
33 struct tevent_context *ev;
34 struct tdgram_context *dgram;
35 size_t query_len;
36 uint8_t *reply;
37 size_t reply_len;
40 #define DNS_REQUEST_TIMEOUT 2
42 /* Declare callback functions used below. */
43 static void dns_udp_request_get_reply(struct tevent_req *subreq);
44 static void dns_udp_request_done(struct tevent_req *subreq);
46 struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
47 struct tevent_context *ev,
48 const char *server_addr_string,
49 const uint8_t *query,
50 size_t query_len)
52 struct tevent_req *req, *subreq;
53 struct dns_udp_request_state *state;
54 struct tsocket_address *local_addr, *server_addr;
55 struct tdgram_context *dgram;
56 int ret;
58 req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
59 if (req == NULL) {
60 return NULL;
63 state->ev = ev;
65 /* Use connected UDP sockets */
66 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
67 &local_addr);
68 if (ret != 0) {
69 tevent_req_error(req, errno);
70 return tevent_req_post(req, ev);
73 ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
74 DNS_SERVICE_PORT, &server_addr);
75 if (ret != 0) {
76 tevent_req_error(req, errno);
77 return tevent_req_post(req, ev);
80 ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
81 if (ret != 0) {
82 tevent_req_error(req, errno);
83 return tevent_req_post(req, ev);
86 state->dgram = dgram;
87 state->query_len = query_len;
89 dump_data(10, query, query_len);
91 subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
92 if (tevent_req_nomem(subreq, req)) {
93 return tevent_req_post(req, ev);
96 if (!tevent_req_set_endtime(req, ev,
97 timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
98 tevent_req_oom(req);
99 return tevent_req_post(req, ev);
103 tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
104 return req;
107 static void dns_udp_request_get_reply(struct tevent_req *subreq)
109 struct tevent_req *req = tevent_req_callback_data(subreq,
110 struct tevent_req);
111 struct dns_udp_request_state *state = tevent_req_data(req,
112 struct dns_udp_request_state);
113 ssize_t len;
114 int err = 0;
116 len = tdgram_sendto_recv(subreq, &err);
117 TALLOC_FREE(subreq);
119 if (len == -1 && err != 0) {
120 tevent_req_error(req, err);
121 return;
124 if (len != state->query_len) {
125 tevent_req_error(req, EIO);
126 return;
129 subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
130 if (tevent_req_nomem(subreq, req)) {
131 return;
134 tevent_req_set_callback(subreq, dns_udp_request_done, req);
135 return;
138 static void dns_udp_request_done(struct tevent_req *subreq)
140 struct tevent_req *req = tevent_req_callback_data(subreq,
141 struct tevent_req);
142 struct dns_udp_request_state *state = tevent_req_data(req,
143 struct dns_udp_request_state);
145 ssize_t len;
146 int err = 0;
148 len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
149 TALLOC_FREE(subreq);
151 if (len == -1 && err != 0) {
152 tevent_req_error(req, err);
153 return;
156 state->reply_len = len;
157 dump_data(10, state->reply, state->reply_len);
158 tevent_req_done(req);
161 int dns_udp_request_recv(struct tevent_req *req,
162 TALLOC_CTX *mem_ctx,
163 uint8_t **reply,
164 size_t *reply_len)
166 struct dns_udp_request_state *state = tevent_req_data(req,
167 struct dns_udp_request_state);
168 int err;
170 if (tevent_req_is_unix_error(req, &err)) {
171 tevent_req_received(req);
172 return err;
175 *reply = talloc_move(mem_ctx, &state->reply);
176 *reply_len = state->reply_len;
177 tevent_req_received(req);
179 return 0;