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

Last change on this file was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 6.7 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 dnsrsrv
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <adt/list.h>
37#include <errno.h>
38#include <str_error.h>
39#include <fibril_synch.h>
40#include <inet/addr.h>
41#include <inet/endpoint.h>
42#include <inet/udp.h>
43#include <io/log.h>
44#include <stdbool.h>
45#include <stdlib.h>
46
47#include "dns_msg.h"
48#include "dns_type.h"
49#include "transport.h"
50
51#define RECV_BUF_SIZE 4096
52#define DNS_SERVER_PORT 53
53
54/** Request timeout (microseconds) */
55#define REQ_TIMEOUT (5 * 1000 * 1000)
56
57/** Maximum number of retries */
58#define REQ_RETRY_MAX 3
59
60inet_addr_t dns_server_addr;
61
62typedef struct {
63 link_t lreq;
64 dns_message_t *req;
65 dns_message_t *resp;
66
67 bool done;
68 fibril_condvar_t done_cv;
69 fibril_mutex_t done_lock;
70
71 errno_t status;
72} trans_req_t;
73
74static uint8_t recv_buf[RECV_BUF_SIZE];
75static udp_t *transport_udp;
76static udp_assoc_t *transport_assoc;
77
78/** Outstanding requests */
79static LIST_INITIALIZE(treq_list);
80static FIBRIL_MUTEX_INITIALIZE(treq_lock);
81
82static void transport_recv_msg(udp_assoc_t *, udp_rmsg_t *);
83static void transport_recv_err(udp_assoc_t *, udp_rerr_t *);
84static void transport_link_state(udp_assoc_t *, udp_link_state_t);
85
86static udp_cb_t transport_cb = {
87 .recv_msg = transport_recv_msg,
88 .recv_err = transport_recv_err,
89 .link_state = transport_link_state
90};
91
92errno_t transport_init(void)
93{
94 inet_ep2_t epp;
95 errno_t rc;
96
97 inet_ep2_init(&epp);
98
99 rc = udp_create(&transport_udp);
100 if (rc != EOK) {
101 rc = EIO;
102 goto error;
103 }
104
105 rc = udp_assoc_create(transport_udp, &epp, &transport_cb, NULL,
106 &transport_assoc);
107 if (rc != EOK) {
108 rc = EIO;
109 goto error;
110 }
111
112 return EOK;
113error:
114 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing network.");
115 udp_assoc_destroy(transport_assoc);
116 udp_destroy(transport_udp);
117 return rc;
118}
119
120void transport_fini(void)
121{
122 udp_assoc_destroy(transport_assoc);
123 udp_destroy(transport_udp);
124}
125
126static trans_req_t *treq_create(dns_message_t *req)
127{
128 trans_req_t *treq;
129
130 treq = calloc(1, sizeof(trans_req_t));
131 if (treq == NULL)
132 return NULL;
133
134 treq->req = req;
135 treq->resp = NULL;
136 treq->done = false;
137 fibril_condvar_initialize(&treq->done_cv);
138 fibril_mutex_initialize(&treq->done_lock);
139
140 fibril_mutex_lock(&treq_lock);
141 list_append(&treq->lreq, &treq_list);
142 fibril_mutex_unlock(&treq_lock);
143
144 return treq;
145}
146
147static void treq_destroy(trans_req_t *treq)
148{
149 if (link_in_use(&treq->lreq))
150 list_remove(&treq->lreq);
151 free(treq);
152}
153
154static trans_req_t *treq_match_resp(dns_message_t *resp)
155{
156 assert(fibril_mutex_is_locked(&treq_lock));
157
158 list_foreach(treq_list, lreq, trans_req_t, treq) {
159 if (treq->req->id == resp->id) {
160 /* Match */
161 return treq;
162 }
163 }
164
165 return NULL;
166}
167
168static void treq_complete(trans_req_t *treq, dns_message_t *resp)
169{
170 fibril_mutex_lock(&treq->done_lock);
171 treq->done = true;
172 treq->status = EOK;
173 treq->resp = resp;
174 fibril_mutex_unlock(&treq->done_lock);
175
176 fibril_condvar_broadcast(&treq->done_cv);
177}
178
179errno_t dns_request(dns_message_t *req, dns_message_t **rresp)
180{
181 trans_req_t *treq = NULL;
182 inet_ep_t ep;
183
184 void *req_data;
185 size_t req_size;
186 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_request: Encode dns message");
187 errno_t rc = dns_message_encode(req, &req_data, &req_size);
188 if (rc != EOK)
189 goto error;
190
191 inet_ep_init(&ep);
192 ep.addr = dns_server_addr;
193 ep.port = DNS_SERVER_PORT;
194
195 size_t ntry = 0;
196
197 while (ntry < REQ_RETRY_MAX) {
198 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_request: Send DNS message");
199 rc = udp_assoc_send_msg(transport_assoc, &ep, req_data,
200 req_size);
201 if (rc != EOK) {
202 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending message: %s", str_error(rc));
203 goto error;
204 }
205
206 treq = treq_create(req);
207 if (treq == NULL) {
208 rc = ENOMEM;
209 goto error;
210 }
211
212 fibril_mutex_lock(&treq->done_lock);
213 while (treq->done != true) {
214 rc = fibril_condvar_wait_timeout(&treq->done_cv, &treq->done_lock,
215 REQ_TIMEOUT);
216 if (rc == ETIMEOUT) {
217 ++ntry;
218 break;
219 }
220 }
221
222 fibril_mutex_unlock(&treq->done_lock);
223
224 if (rc != ETIMEOUT)
225 break;
226 }
227
228 if (ntry >= REQ_RETRY_MAX) {
229 rc = EIO;
230 goto error;
231 }
232
233 if (treq->status != EOK) {
234 rc = treq->status;
235 goto error;
236 }
237
238 *rresp = treq->resp;
239 treq_destroy(treq);
240 free(req_data);
241 return EOK;
242
243error:
244 if (treq != NULL)
245 treq_destroy(treq);
246
247 free(req_data);
248 return rc;
249}
250
251static void transport_recv_msg(udp_assoc_t *assoc, udp_rmsg_t *rmsg)
252{
253 dns_message_t *resp = NULL;
254 trans_req_t *treq;
255 size_t size;
256 inet_ep_t remote_ep;
257 errno_t rc;
258
259 size = udp_rmsg_size(rmsg);
260 if (size > RECV_BUF_SIZE)
261 size = RECV_BUF_SIZE; /* XXX */
262
263 rc = udp_rmsg_read(rmsg, 0, recv_buf, size);
264 if (rc != EOK) {
265 log_msg(LOG_DEFAULT, LVL_ERROR, "Error reading message.");
266 return;
267 }
268
269 udp_rmsg_remote_ep(rmsg, &remote_ep);
270 /* XXX */
271
272 rc = dns_message_decode(recv_buf, size, &resp);
273 if (rc != EOK) {
274 log_msg(LOG_DEFAULT, LVL_ERROR, "Error decoding message.");
275 return;
276 }
277
278 assert(resp != NULL);
279
280 fibril_mutex_lock(&treq_lock);
281 treq = treq_match_resp(resp);
282 if (treq == NULL) {
283 fibril_mutex_unlock(&treq_lock);
284 return;
285 }
286
287 list_remove(&treq->lreq);
288 fibril_mutex_unlock(&treq_lock);
289
290 treq_complete(treq, resp);
291}
292
293static void transport_recv_err(udp_assoc_t *assoc, udp_rerr_t *rerr)
294{
295 log_msg(LOG_DEFAULT, LVL_WARN, "Ignoring ICMP error");
296}
297
298static void transport_link_state(udp_assoc_t *assoc, udp_link_state_t ls)
299{
300 log_msg(LOG_DEFAULT, LVL_NOTE, "Link state change");
301}
302
303/** @}
304 */
Note: See TracBrowser for help on using the repository browser.