source: mainline/uspace/srv/net/udp/assoc.c@ b688fd8

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

Remove excessive debugging output.

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2015 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 udp
30 * @{
31 */
32
33/**
34 * @file UDP associations
35 */
36
37#include <adt/list.h>
38#include <errno.h>
39#include <stdbool.h>
40#include <fibril_synch.h>
41#include <inet/endpoint.h>
42#include <io/log.h>
43#include <nettl/amap.h>
44#include <stdlib.h>
45
46#include "assoc.h"
47#include "msg.h"
48#include "pdu.h"
49#include "udp_inet.h"
50#include "udp_type.h"
51
52static LIST_INITIALIZE(assoc_list);
53static FIBRIL_MUTEX_INITIALIZE(assoc_list_lock);
54static amap_t *amap;
55
56static udp_assoc_t *udp_assoc_find_ref(inet_ep2_t *);
57static int udp_assoc_queue_msg(udp_assoc_t *, inet_ep2_t *, udp_msg_t *);
58
59/** Initialize associations. */
60int udp_assocs_init(void)
61{
62 int rc;
63
64 rc = amap_create(&amap);
65 if (rc != EOK) {
66 assert(rc == ENOMEM);
67 return ENOMEM;
68 }
69
70 return EOK;
71}
72
73/** Create new association structure.
74 *
75 * @param epp Endpoint pair (will be copied)
76 * @param cb Callbacks
77 * @param cb_arg Callback argument
78 * @return New association or NULL
79 */
80udp_assoc_t *udp_assoc_new(inet_ep2_t *epp, udp_assoc_cb_t *cb, void *cb_arg)
81{
82 udp_assoc_t *assoc = NULL;
83
84 /* Allocate association structure */
85 assoc = calloc(1, sizeof(udp_assoc_t));
86 if (assoc == NULL)
87 goto error;
88
89 fibril_mutex_initialize(&assoc->lock);
90
91 /* One for the user */
92 atomic_set(&assoc->refcnt, 1);
93
94 /* Initialize receive queue */
95 list_initialize(&assoc->rcv_queue);
96 fibril_condvar_initialize(&assoc->rcv_queue_cv);
97
98 if (epp != NULL)
99 assoc->ident = *epp;
100
101 assoc->cb = cb;
102 assoc->cb_arg = cb_arg;
103 return assoc;
104error:
105 return NULL;
106}
107
108/** Destroy association structure.
109 *
110 * Association structure should be destroyed when the folowing conditions
111 * are met:
112 * (1) user has deleted the association
113 * (2) nobody is holding references to the association
114 *
115 * This happens when @a assoc->refcnt is zero as we count (1)
116 * as an extra reference.
117 *
118 * @param assoc Association
119 */
120static void udp_assoc_free(udp_assoc_t *assoc)
121{
122 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
123
124 while (!list_empty(&assoc->rcv_queue)) {
125 link_t *link = list_first(&assoc->rcv_queue);
126 udp_rcv_queue_entry_t *rqe = list_get_instance(link,
127 udp_rcv_queue_entry_t, link);
128 list_remove(link);
129
130 udp_msg_delete(rqe->msg);
131 free(rqe);
132 }
133
134 free(assoc);
135}
136
137/** Add reference to association.
138 *
139 * Increase association reference count by one.
140 *
141 * @param assoc Association
142 */
143void udp_assoc_addref(udp_assoc_t *assoc)
144{
145 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
146 atomic_inc(&assoc->refcnt);
147}
148
149/** Remove reference from association.
150 *
151 * Decrease association reference count by one.
152 *
153 * @param assoc Association
154 */
155void udp_assoc_delref(udp_assoc_t *assoc)
156{
157 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
158
159 if (atomic_predec(&assoc->refcnt) == 0)
160 udp_assoc_free(assoc);
161}
162
163/** Delete association.
164 *
165 * The caller promises not make no further references to @a assoc.
166 * UDP will free @a assoc eventually.
167 *
168 * @param assoc Association
169 */
170void udp_assoc_delete(udp_assoc_t *assoc)
171{
172 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
173
174 assert(assoc->deleted == false);
175 udp_assoc_delref(assoc);
176 assoc->deleted = true;
177}
178
179/** Enlist association.
180 *
181 * Add association to the association map.
182 */
183int udp_assoc_add(udp_assoc_t *assoc)
184{
185 inet_ep2_t aepp;
186 int rc;
187
188 udp_assoc_addref(assoc);
189 fibril_mutex_lock(&assoc_list_lock);
190
191 rc = amap_insert(amap, &assoc->ident, assoc, af_allow_system, &aepp);
192 if (rc != EOK) {
193 udp_assoc_delref(assoc);
194 fibril_mutex_unlock(&assoc_list_lock);
195 return rc;
196 }
197
198 assoc->ident = aepp;
199 list_append(&assoc->link, &assoc_list);
200 fibril_mutex_unlock(&assoc_list_lock);
201
202 return EOK;
203}
204
205/** Delist association.
206 *
207 * Remove association from the association map.
208 */
209void udp_assoc_remove(udp_assoc_t *assoc)
210{
211 fibril_mutex_lock(&assoc_list_lock);
212 amap_remove(amap, &assoc->ident);
213 list_remove(&assoc->link);
214 fibril_mutex_unlock(&assoc_list_lock);
215 udp_assoc_delref(assoc);
216}
217
218/** Set IP link in association.
219 *
220 * @param assoc Association
221 * @param iplink IP link
222 */
223void udp_assoc_set_iplink(udp_assoc_t *assoc, service_id_t iplink)
224{
225 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_iplink(%p, %zu)",
226 assoc, iplink);
227 fibril_mutex_lock(&assoc->lock);
228 assoc->ident.local_link = iplink;
229 fibril_mutex_unlock(&assoc->lock);
230}
231
232/** Send message to association.
233 *
234 * @param assoc Association
235 * @param remote Remote endpoint or NULL not to override @a assoc
236 * @param msg Message
237 *
238 * @return EOK on success
239 * EINVAL if remote endpoint is not set
240 * ENOMEM if out of resources
241 * EIO if no route to destination exists
242 */
243int udp_assoc_send(udp_assoc_t *assoc, inet_ep_t *remote, udp_msg_t *msg)
244{
245 udp_pdu_t *pdu;
246 inet_ep2_t epp;
247 int rc;
248
249 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
250 assoc, remote, msg);
251
252 /* @a remote can be used to override the remote endpoint */
253 epp = assoc->ident;
254 if (remote != NULL)
255 epp.remote = *remote;
256
257 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - check addr any");
258
259 if ((inet_addr_is_any(&epp.remote.addr)) ||
260 (epp.remote.port == inet_port_any))
261 return EINVAL;
262
263 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - check version");
264
265 if (epp.remote.addr.version != epp.local.addr.version)
266 return EINVAL;
267
268 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - encode pdu");
269
270 rc = udp_pdu_encode(&epp, msg, &pdu);
271 if (rc != EOK)
272 return ENOMEM;
273
274 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - transmit");
275
276 rc = udp_transmit_pdu(pdu);
277 udp_pdu_delete(pdu);
278
279 if (rc != EOK)
280 return EIO;
281
282 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - success");
283 return EOK;
284}
285
286/** Get a received message.
287 *
288 * Pull one message from the association's receive queue.
289 */
290int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, inet_ep_t *remote)
291{
292 link_t *link;
293 udp_rcv_queue_entry_t *rqe;
294
295 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv()");
296
297 fibril_mutex_lock(&assoc->lock);
298 while (list_empty(&assoc->rcv_queue) && !assoc->reset) {
299 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - waiting");
300 fibril_condvar_wait(&assoc->rcv_queue_cv, &assoc->lock);
301 }
302
303 if (assoc->reset) {
304 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - association was reset");
305 fibril_mutex_unlock(&assoc->lock);
306 return ENXIO;
307 }
308
309 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - got a message");
310 link = list_first(&assoc->rcv_queue);
311 rqe = list_get_instance(link, udp_rcv_queue_entry_t, link);
312 list_remove(link);
313 fibril_mutex_unlock(&assoc->lock);
314
315 *msg = rqe->msg;
316 *remote = rqe->epp.remote;
317 free(rqe);
318
319 return EOK;
320}
321
322/** Message received.
323 *
324 * Find the association to which the message belongs and queue it.
325 */
326void udp_assoc_received(inet_ep2_t *repp, udp_msg_t *msg)
327{
328 udp_assoc_t *assoc;
329 int rc;
330
331 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", repp, msg);
332
333 assoc = udp_assoc_find_ref(repp);
334 if (assoc == NULL) {
335 log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
336 /* XXX Generate ICMP error. */
337 /* XXX Might propagate error directly by error return. */
338 udp_msg_delete(msg);
339 return;
340 }
341
342 if (0) {
343 rc = udp_assoc_queue_msg(assoc, repp, msg);
344 if (rc != EOK) {
345 log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
346 /* XXX Generate ICMP error? */
347 }
348 }
349
350 log_msg(LOG_DEFAULT, LVL_DEBUG, "call assoc->cb->recv_msg");
351 assoc->cb->recv_msg(assoc->cb_arg, repp, msg);
352 udp_assoc_delref(assoc);
353}
354
355/** Reset association.
356 *
357 * This causes any pendingreceive operations to return immediately with
358 * UDP_ERESET.
359 */
360void udp_assoc_reset(udp_assoc_t *assoc)
361{
362 fibril_mutex_lock(&assoc->lock);
363 assoc->reset = true;
364 fibril_condvar_broadcast(&assoc->rcv_queue_cv);
365 fibril_mutex_unlock(&assoc->lock);
366}
367
368static int udp_assoc_queue_msg(udp_assoc_t *assoc, inet_ep2_t *epp,
369 udp_msg_t *msg)
370{
371 udp_rcv_queue_entry_t *rqe;
372
373 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
374 assoc, epp, msg);
375
376 rqe = calloc(1, sizeof(udp_rcv_queue_entry_t));
377 if (rqe == NULL)
378 return ENOMEM;
379
380 link_initialize(&rqe->link);
381 rqe->epp = *epp;
382 rqe->msg = msg;
383
384 fibril_mutex_lock(&assoc->lock);
385 list_append(&rqe->link, &assoc->rcv_queue);
386 fibril_mutex_unlock(&assoc->lock);
387
388 fibril_condvar_broadcast(&assoc->rcv_queue_cv);
389
390 return EOK;
391}
392
393/** Find association structure for specified endpoint pair.
394 *
395 * An association is uniquely identified by an endpoint pair. Look up our
396 * association map and return association structure based on endpoint pair.
397 * The association reference count is bumped by one.
398 *
399 * @param epp Endpoint pair
400 * @return Association structure or NULL if not found.
401 */
402static udp_assoc_t *udp_assoc_find_ref(inet_ep2_t *epp)
403{
404 int rc;
405 void *arg;
406 udp_assoc_t *assoc;
407
408 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", epp);
409 fibril_mutex_lock(&assoc_list_lock);
410
411 rc = amap_find_match(amap, epp, &arg);
412 if (rc != EOK) {
413 assert(rc == ENOMEM);
414 fibril_mutex_unlock(&assoc_list_lock);
415 return NULL;
416 }
417
418 assoc = (udp_assoc_t *)arg;
419 udp_assoc_addref(assoc);
420
421 fibril_mutex_unlock(&assoc_list_lock);
422 return assoc;
423}
424
425/**
426 * @}
427 */
Note: See TracBrowser for help on using the repository browser.