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

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

New transport layer API. Only UDP implemented.

  • Property mode set to 100644
File size: 6.4 KB
RevLine 
[adae30d]1/*
[dc95342]2 * Copyright (c) 2013 Jiri Svoboda
[adae30d]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
[48171fc4]36#include <adt/list.h>
[adae30d]37#include <errno.h>
[48171fc4]38#include <fibril_synch.h>
[fab2746]39#include <inet/addr.h>
40#include <inet/endpoint.h>
41#include <inet/udp.h>
[48171fc4]42#include <io/log.h>
43#include <stdbool.h>
[08a6382]44#include <stdlib.h>
[adae30d]45
46#include "dns_msg.h"
47#include "dns_type.h"
48#include "transport.h"
49
[ccb5165]50#define RECV_BUF_SIZE 4096
[5d1cb8a]51#define DNS_SERVER_PORT 53
[ccb5165]52
[48171fc4]53/** Request timeout (microseconds) */
[3e66428]54#define REQ_TIMEOUT (5 * 1000 * 1000)
[48171fc4]55
[06fe3b6]56/** Maximum number of retries */
57#define REQ_RETRY_MAX 3
58
[a2e3ee6]59inet_addr_t dns_server_addr;
[3e66428]60
[48171fc4]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
[ccb5165]73static uint8_t recv_buf[RECV_BUF_SIZE];
[fab2746]74static udp_t *transport_udp;
75static udp_assoc_t *transport_assoc;
[ccb5165]76
[48171fc4]77/** Outstanding requests */
78static LIST_INITIALIZE(treq_list);
79static FIBRIL_MUTEX_INITIALIZE(treq_lock);
80
[fab2746]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};
[48171fc4]90
91int transport_init(void)
[adae30d]92{
[fab2746]93 inet_ep2_t epp;
[48171fc4]94 int rc;
[141a20d]95
[fab2746]96 inet_ep2_init(&epp);
[adae30d]97
[fab2746]98 rc = udp_create(&transport_udp);
99 if (rc != EOK) {
[08a6382]100 rc = EIO;
101 goto error;
102 }
103
[fab2746]104 rc = udp_assoc_create(transport_udp, &epp, &transport_cb, NULL,
105 &transport_assoc);
106 if (rc != EOK) {
107 rc = EIO;
[48171fc4]108 goto error;
[fab2746]109 }
[48171fc4]110
111 return EOK;
112error:
[fab2746]113 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing network.");
114 udp_assoc_destroy(transport_assoc);
115 udp_destroy(transport_udp);
[48171fc4]116 return rc;
117}
118
119void transport_fini(void)
120{
[fab2746]121 udp_assoc_destroy(transport_assoc);
122 udp_destroy(transport_udp);
[48171fc4]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
[feeac0d]157 list_foreach(treq_list, lreq, trans_req_t, treq) {
[48171fc4]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{
[02a09ed]180 trans_req_t *treq = NULL;
[fab2746]181 inet_ep_t ep;
182
[48171fc4]183 void *req_data;
184 size_t req_size;
[02a09ed]185 int rc = dns_message_encode(req, &req_data, &req_size);
[48171fc4]186 if (rc != EOK)
187 goto error;
[fab2746]188
189 inet_ep_init(&ep);
190 ep.addr = dns_server_addr;
191 ep.port = DNS_SERVER_PORT;
192
[02a09ed]193 size_t ntry = 0;
[fab2746]194
[06fe3b6]195 while (ntry < REQ_RETRY_MAX) {
[fab2746]196 rc = udp_assoc_send_msg(transport_assoc, &ep, req_data,
197 req_size);
[06fe3b6]198 if (rc != EOK)
199 goto error;
[fab2746]200
[06fe3b6]201 treq = treq_create(req);
202 if (treq == NULL) {
203 rc = ENOMEM;
[48171fc4]204 goto error;
205 }
[fab2746]206
[06fe3b6]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 }
[fab2746]216
[06fe3b6]217 fibril_mutex_unlock(&treq->done_lock);
[fab2746]218
[06fe3b6]219 if (rc != ETIMEOUT)
220 break;
[48171fc4]221 }
[fab2746]222
[06fe3b6]223 if (ntry >= REQ_RETRY_MAX) {
224 rc = EIO;
225 goto error;
226 }
[fab2746]227
[48171fc4]228 if (treq->status != EOK) {
229 rc = treq->status;
230 goto error;
[0041cd6d]231 }
[fab2746]232
[48171fc4]233 *rresp = treq->resp;
234 treq_destroy(treq);
[141a20d]235 free(req_data);
[48171fc4]236 return EOK;
[fab2746]237
[48171fc4]238error:
239 if (treq != NULL)
240 treq_destroy(treq);
[fab2746]241
[48171fc4]242 free(req_data);
243 return rc;
244}
245
[fab2746]246static void transport_recv_msg(udp_assoc_t *assoc, udp_rmsg_t *rmsg)
[48171fc4]247{
[fab2746]248 dns_message_t *resp = NULL;
249 trans_req_t *treq;
250 size_t size;
251 inet_ep_t remote_ep;
[48171fc4]252 int rc;
253
[fab2746]254 size = udp_rmsg_size(rmsg);
255 if (size > RECV_BUF_SIZE)
256 size = RECV_BUF_SIZE; /* XXX */
[141a20d]257
[fab2746]258 rc = udp_rmsg_read(rmsg, 0, recv_buf, size);
[dc95342]259 if (rc != EOK) {
[fab2746]260 log_msg(LOG_DEFAULT, LVL_ERROR, "Error reading message.");
261 return;
[dc95342]262 }
[0041cd6d]263
[fab2746]264 udp_rmsg_remote_ep(rmsg, &remote_ep);
265 /* XXX */
[08a6382]266
[fab2746]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 }
[48171fc4]272
[fab2746]273 assert(resp != NULL);
[48171fc4]274
[fab2746]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 }
[b5f716b]281
[fab2746]282 list_remove(&treq->lreq);
283 fibril_mutex_unlock(&treq_lock);
[48171fc4]284
[fab2746]285 treq_complete(treq, resp);
286}
[48171fc4]287
[fab2746]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}
[48171fc4]292
[fab2746]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");
[48171fc4]296}
297
[fab2746]298
[adae30d]299/** @}
300 */
Note: See TracBrowser for help on using the repository browser.