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

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

New transport layer API. Only UDP implemented.

  • Property mode set to 100644
File size: 6.4 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 int rc = dns_message_encode(req, &req_data, &req_size);
186 if (rc != EOK)
187 goto error;
188
189 inet_ep_init(&ep);
190 ep.addr = dns_server_addr;
191 ep.port = DNS_SERVER_PORT;
192
193 size_t ntry = 0;
194
195 while (ntry < REQ_RETRY_MAX) {
196 rc = udp_assoc_send_msg(transport_assoc, &ep, req_data,
197 req_size);
198 if (rc != EOK)
199 goto error;
200
201 treq = treq_create(req);
202 if (treq == NULL) {
203 rc = ENOMEM;
204 goto error;
205 }
206
207 fibril_mutex_lock(&treq->done_lock);
208 while (treq->done != true) {
209 rc = fibril_condvar_wait_timeout(&treq->done_cv, &treq->done_lock,
210 REQ_TIMEOUT);
211 if (rc == ETIMEOUT) {
212 ++ntry;
213 break;
214 }
215 }
216
217 fibril_mutex_unlock(&treq->done_lock);
218
219 if (rc != ETIMEOUT)
220 break;
221 }
222
223 if (ntry >= REQ_RETRY_MAX) {
224 rc = EIO;
225 goto error;
226 }
227
228 if (treq->status != EOK) {
229 rc = treq->status;
230 goto error;
231 }
232
233 *rresp = treq->resp;
234 treq_destroy(treq);
235 free(req_data);
236 return EOK;
237
238error:
239 if (treq != NULL)
240 treq_destroy(treq);
241
242 free(req_data);
243 return rc;
244}
245
246static void transport_recv_msg(udp_assoc_t *assoc, udp_rmsg_t *rmsg)
247{
248 dns_message_t *resp = NULL;
249 trans_req_t *treq;
250 size_t size;
251 inet_ep_t remote_ep;
252 int rc;
253
254 size = udp_rmsg_size(rmsg);
255 if (size > RECV_BUF_SIZE)
256 size = RECV_BUF_SIZE; /* XXX */
257
258 rc = udp_rmsg_read(rmsg, 0, recv_buf, size);
259 if (rc != EOK) {
260 log_msg(LOG_DEFAULT, LVL_ERROR, "Error reading message.");
261 return;
262 }
263
264 udp_rmsg_remote_ep(rmsg, &remote_ep);
265 /* XXX */
266
267 rc = dns_message_decode(recv_buf, size, &resp);
268 if (rc != EOK) {
269 log_msg(LOG_DEFAULT, LVL_ERROR, "Error decoding message.");
270 return;
271 }
272
273 assert(resp != NULL);
274
275 fibril_mutex_lock(&treq_lock);
276 treq = treq_match_resp(resp);
277 if (treq == NULL) {
278 fibril_mutex_unlock(&treq_lock);
279 return;
280 }
281
282 list_remove(&treq->lreq);
283 fibril_mutex_unlock(&treq_lock);
284
285 treq_complete(treq, resp);
286}
287
288static void transport_recv_err(udp_assoc_t *assoc, udp_rerr_t *rerr)
289{
290 log_msg(LOG_DEFAULT, LVL_WARN, "Ignoring ICMP error");
291}
292
293static void transport_link_state(udp_assoc_t *assoc, udp_link_state_t ls)
294{
295 log_msg(LOG_DEFAULT, LVL_NOTE, "Link state change");
296}
297
298
299/** @}
300 */
Note: See TracBrowser for help on using the repository browser.