source: mainline/uspace/srv/net/dnsrsrv/transport.c@ e1b4ae0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e1b4ae0 was 58e8646, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fix DNS resolution not working due to missing local address.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2013 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup dnsres
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <adt/list.h>
37#include <errno.h>
38#include <fibril_synch.h>
39#include <inet/addr.h>
40#include <inet/endpoint.h>
41#include <inet/udp.h>
42#include <io/log.h>
43#include <stdbool.h>
44#include <stdlib.h>
45
46#include "dns_msg.h"
47#include "dns_type.h"
48#include "transport.h"
49
50#define RECV_BUF_SIZE 4096
51#define DNS_SERVER_PORT 53
52
53/** Request timeout (microseconds) */
54#define REQ_TIMEOUT (5 * 1000 * 1000)
55
56/** Maximum number of retries */
57#define REQ_RETRY_MAX 3
58
59inet_addr_t dns_server_addr;
60
61typedef struct {
62 link_t lreq;
63 dns_message_t *req;
64 dns_message_t *resp;
65
66 bool done;
67 fibril_condvar_t done_cv;
68 fibril_mutex_t done_lock;
69
70 int status;
71} trans_req_t;
72
73static uint8_t recv_buf[RECV_BUF_SIZE];
74static udp_t *transport_udp;
75static udp_assoc_t *transport_assoc;
76
77/** Outstanding requests */
78static LIST_INITIALIZE(treq_list);
79static FIBRIL_MUTEX_INITIALIZE(treq_lock);
80
81static void transport_recv_msg(udp_assoc_t *, udp_rmsg_t *);
82static void transport_recv_err(udp_assoc_t *, udp_rerr_t *);
83static void transport_link_state(udp_assoc_t *, udp_link_state_t);
84
85static udp_cb_t transport_cb = {
86 .recv_msg = transport_recv_msg,
87 .recv_err = transport_recv_err,
88 .link_state = transport_link_state
89};
90
91int transport_init(void)
92{
93 inet_ep2_t epp;
94 int rc;
95
96 inet_ep2_init(&epp);
97
98 rc = udp_create(&transport_udp);
99 if (rc != EOK) {
100 rc = EIO;
101 goto error;
102 }
103
104 rc = udp_assoc_create(transport_udp, &epp, &transport_cb, NULL,
105 &transport_assoc);
106 if (rc != EOK) {
107 rc = EIO;
108 goto error;
109 }
110
111 return EOK;
112error:
113 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing network.");
114 udp_assoc_destroy(transport_assoc);
115 udp_destroy(transport_udp);
116 return rc;
117}
118
119void transport_fini(void)
120{
121 udp_assoc_destroy(transport_assoc);
122 udp_destroy(transport_udp);
123}
124
125static trans_req_t *treq_create(dns_message_t *req)
126{
127 trans_req_t *treq;
128
129 treq = calloc(1, sizeof(trans_req_t));
130 if (treq == NULL)
131 return NULL;
132
133 treq->req = req;
134 treq->resp = NULL;
135 treq->done = false;
136 fibril_condvar_initialize(&treq->done_cv);
137 fibril_mutex_initialize(&treq->done_lock);
138
139 fibril_mutex_lock(&treq_lock);
140 list_append(&treq->lreq, &treq_list);
141 fibril_mutex_unlock(&treq_lock);
142
143 return treq;
144}
145
146static void treq_destroy(trans_req_t *treq)
147{
148 if (link_in_use(&treq->lreq))
149 list_remove(&treq->lreq);
150 free(treq);
151}
152
153static trans_req_t *treq_match_resp(dns_message_t *resp)
154{
155 assert(fibril_mutex_is_locked(&treq_lock));
156
157 list_foreach(treq_list, lreq, trans_req_t, treq) {
158 if (treq->req->id == resp->id) {
159 /* Match */
160 return treq;
161 }
162 }
163
164 return NULL;
165}
166
167static void treq_complete(trans_req_t *treq, dns_message_t *resp)
168{
169 fibril_mutex_lock(&treq->done_lock);
170 treq->done = true;
171 treq->status = EOK;
172 treq->resp = resp;
173 fibril_mutex_unlock(&treq->done_lock);
174
175 fibril_condvar_broadcast(&treq->done_cv);
176}
177
178int dns_request(dns_message_t *req, dns_message_t **rresp)
179{
180 trans_req_t *treq = NULL;
181 inet_ep_t ep;
182
183 void *req_data;
184 size_t req_size;
185 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_request: Encode dns message");
186 int rc = dns_message_encode(req, &req_data, &req_size);
187 if (rc != EOK)
188 goto error;
189
190 inet_ep_init(&ep);
191 ep.addr = dns_server_addr;
192 ep.port = DNS_SERVER_PORT;
193
194 size_t ntry = 0;
195
196 while (ntry < REQ_RETRY_MAX) {
197 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_request: Send DNS message");
198 rc = udp_assoc_send_msg(transport_assoc, &ep, req_data,
199 req_size);
200 if (rc != EOK) {
201 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error %d sending message", rc);
202 goto error;
203 }
204
205 treq = treq_create(req);
206 if (treq == NULL) {
207 rc = ENOMEM;
208 goto error;
209 }
210
211 fibril_mutex_lock(&treq->done_lock);
212 while (treq->done != true) {
213 rc = fibril_condvar_wait_timeout(&treq->done_cv, &treq->done_lock,
214 REQ_TIMEOUT);
215 if (rc == ETIMEOUT) {
216 ++ntry;
217 break;
218 }
219 }
220
221 fibril_mutex_unlock(&treq->done_lock);
222
223 if (rc != ETIMEOUT)
224 break;
225 }
226
227 if (ntry >= REQ_RETRY_MAX) {
228 rc = EIO;
229 goto error;
230 }
231
232 if (treq->status != EOK) {
233 rc = treq->status;
234 goto error;
235 }
236
237 *rresp = treq->resp;
238 treq_destroy(treq);
239 free(req_data);
240 return EOK;
241
242error:
243 if (treq != NULL)
244 treq_destroy(treq);
245
246 free(req_data);
247 return rc;
248}
249
250static void transport_recv_msg(udp_assoc_t *assoc, udp_rmsg_t *rmsg)
251{
252 dns_message_t *resp = NULL;
253 trans_req_t *treq;
254 size_t size;
255 inet_ep_t remote_ep;
256 int rc;
257
258 size = udp_rmsg_size(rmsg);
259 if (size > RECV_BUF_SIZE)
260 size = RECV_BUF_SIZE; /* XXX */
261
262 rc = udp_rmsg_read(rmsg, 0, recv_buf, size);
263 if (rc != EOK) {
264 log_msg(LOG_DEFAULT, LVL_ERROR, "Error reading message.");
265 return;
266 }
267
268 udp_rmsg_remote_ep(rmsg, &remote_ep);
269 /* XXX */
270
271 rc = dns_message_decode(recv_buf, size, &resp);
272 if (rc != EOK) {
273 log_msg(LOG_DEFAULT, LVL_ERROR, "Error decoding message.");
274 return;
275 }
276
277 assert(resp != NULL);
278
279 fibril_mutex_lock(&treq_lock);
280 treq = treq_match_resp(resp);
281 if (treq == NULL) {
282 fibril_mutex_unlock(&treq_lock);
283 return;
284 }
285
286 list_remove(&treq->lreq);
287 fibril_mutex_unlock(&treq_lock);
288
289 treq_complete(treq, resp);
290}
291
292static void transport_recv_err(udp_assoc_t *assoc, udp_rerr_t *rerr)
293{
294 log_msg(LOG_DEFAULT, LVL_WARN, "Ignoring ICMP error");
295}
296
297static void transport_link_state(udp_assoc_t *assoc, udp_link_state_t ls)
298{
299 log_msg(LOG_DEFAULT, LVL_NOTE, "Link state change");
300}
301
302
303/** @}
304 */
Note: See TracBrowser for help on using the repository browser.