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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 659ebd86 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
RevLine 
[ee603c4]1/*
[2f19103]2 * Copyright (c) 2015 Jiri Svoboda
[ee603c4]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>
[fab2746]38#include <errno.h>
[3e6a98c5]39#include <stdbool.h>
[ee603c4]40#include <fibril_synch.h>
[58e9dec]41#include <inet/endpoint.h>
[ee603c4]42#include <io/log.h>
[2989c7e]43#include <nettl/amap.h>
[ee603c4]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
[2989c7e]52static LIST_INITIALIZE(assoc_list);
53static FIBRIL_MUTEX_INITIALIZE(assoc_list_lock);
54static amap_t *amap;
[ee603c4]55
[2f19103]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 *);
[92b42442]58
[2989c7e]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
[ee603c4]73/** Create new association structure.
74 *
[2f19103]75 * @param epp Endpoint pair (will be copied)
76 * @param cb Callbacks
77 * @param cb_arg Callback argument
[ee603c4]78 * @return New association or NULL
79 */
[2f19103]80udp_assoc_t *udp_assoc_new(inet_ep2_t *epp, udp_assoc_cb_t *cb, void *cb_arg)
[ee603c4]81{
82 udp_assoc_t *assoc = NULL;
83
[92b42442]84 /* Allocate association structure */
[ee603c4]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
[2f19103]98 if (epp != NULL)
99 assoc->ident = *epp;
[ee603c4]100
[fab2746]101 assoc->cb = cb;
102 assoc->cb_arg = cb_arg;
[ee603c4]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 *
[92b42442]118 * @param assoc Association
[ee603c4]119 */
120static void udp_assoc_free(udp_assoc_t *assoc)
121{
[a1a101d]122 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
[ee603c4]123
124 while (!list_empty(&assoc->rcv_queue)) {
125 link_t *link = list_first(&assoc->rcv_queue);
[92b42442]126 udp_rcv_queue_entry_t *rqe = list_get_instance(link,
127 udp_rcv_queue_entry_t, link);
[ee603c4]128 list_remove(link);
[92b42442]129
130 udp_msg_delete(rqe->msg);
131 free(rqe);
[ee603c4]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{
[a1a101d]145 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
[ee603c4]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{
[a1a101d]157 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
[ee603c4]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{
[a1a101d]172 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
[ee603c4]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 */
[2989c7e]183int udp_assoc_add(udp_assoc_t *assoc)
[ee603c4]184{
[2989c7e]185 inet_ep2_t aepp;
186 int rc;
187
[ee603c4]188 udp_assoc_addref(assoc);
189 fibril_mutex_lock(&assoc_list_lock);
[2989c7e]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;
[ee603c4]199 list_append(&assoc->link, &assoc_list);
200 fibril_mutex_unlock(&assoc_list_lock);
[2989c7e]201
202 return EOK;
[ee603c4]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);
[2989c7e]212 amap_remove(amap, &assoc->ident);
[ee603c4]213 list_remove(&assoc->link);
214 fibril_mutex_unlock(&assoc_list_lock);
215 udp_assoc_delref(assoc);
216}
217
[695b6ff]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);
[2f19103]228 assoc->ident.local_link = iplink;
[695b6ff]229 fibril_mutex_unlock(&assoc->lock);
230}
231
[ee603c4]232/** Send message to association.
233 *
234 * @param assoc Association
[2f19103]235 * @param remote Remote endpoint or NULL not to override @a assoc
[ee603c4]236 * @param msg Message
237 *
238 * @return EOK on success
[2f19103]239 * EINVAL if remote endpoint is not set
[ee603c4]240 * ENOMEM if out of resources
241 * EIO if no route to destination exists
242 */
[2f19103]243int udp_assoc_send(udp_assoc_t *assoc, inet_ep_t *remote, udp_msg_t *msg)
[ee603c4]244{
245 udp_pdu_t *pdu;
[2f19103]246 inet_ep2_t epp;
[ee603c4]247 int rc;
248
[c3f7d37]249 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
[2f19103]250 assoc, remote, msg);
[92b42442]251
[2f19103]252 /* @a remote can be used to override the remote endpoint */
253 epp = assoc->ident;
254 if (remote != NULL)
255 epp.remote = *remote;
[ee603c4]256
[c3f7d37]257 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - check addr any");
[fab2746]258
[2f19103]259 if ((inet_addr_is_any(&epp.remote.addr)) ||
[58e9dec]260 (epp.remote.port == inet_port_any))
[ee603c4]261 return EINVAL;
262
[c3f7d37]263 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - check version");
[fab2746]264
[2f19103]265 if (epp.remote.addr.version != epp.local.addr.version)
[fab2746]266 return EINVAL;
267
[c3f7d37]268 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - encode pdu");
[fab2746]269
[2f19103]270 rc = udp_pdu_encode(&epp, msg, &pdu);
[ee603c4]271 if (rc != EOK)
272 return ENOMEM;
273
[c3f7d37]274 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - transmit");
[fab2746]275
[ee603c4]276 rc = udp_transmit_pdu(pdu);
[071a2c60]277 udp_pdu_delete(pdu);
278
[ee603c4]279 if (rc != EOK)
280 return EIO;
281
[c3f7d37]282 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - success");
[ee603c4]283 return EOK;
284}
285
[92b42442]286/** Get a received message.
287 *
288 * Pull one message from the association's receive queue.
289 */
[2f19103]290int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, inet_ep_t *remote)
[92b42442]291{
292 link_t *link;
293 udp_rcv_queue_entry_t *rqe;
294
[c3f7d37]295 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv()");
[92b42442]296
297 fibril_mutex_lock(&assoc->lock);
[141a20d]298 while (list_empty(&assoc->rcv_queue) && !assoc->reset) {
[a1a101d]299 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - waiting");
[92b42442]300 fibril_condvar_wait(&assoc->rcv_queue_cv, &assoc->lock);
301 }
302
[141a20d]303 if (assoc->reset) {
[a1e2df13]304 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - association was reset");
[141a20d]305 fibril_mutex_unlock(&assoc->lock);
[fab2746]306 return ENXIO;
[141a20d]307 }
308
[c3f7d37]309 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - got a message");
[92b42442]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;
[2f19103]316 *remote = rqe->epp.remote;
[7094e196]317 free(rqe);
[92b42442]318
319 return EOK;
320}
321
322/** Message received.
323 *
324 * Find the association to which the message belongs and queue it.
325 */
[2f19103]326void udp_assoc_received(inet_ep2_t *repp, udp_msg_t *msg)
[92b42442]327{
328 udp_assoc_t *assoc;
329 int rc;
330
[c3f7d37]331 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", repp, msg);
[92b42442]332
[2f19103]333 assoc = udp_assoc_find_ref(repp);
[92b42442]334 if (assoc == NULL) {
[c3f7d37]335 log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
[92b42442]336 /* XXX Generate ICMP error. */
337 /* XXX Might propagate error directly by error return. */
[071a2c60]338 udp_msg_delete(msg);
[92b42442]339 return;
340 }
341
[fab2746]342 if (0) {
[2f19103]343 rc = udp_assoc_queue_msg(assoc, repp, msg);
[fab2746]344 if (rc != EOK) {
345 log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
[92b42442]346 /* XXX Generate ICMP error? */
[fab2746]347 }
[92b42442]348 }
[fab2746]349
[c3f7d37]350 log_msg(LOG_DEFAULT, LVL_DEBUG, "call assoc->cb->recv_msg");
[2f19103]351 assoc->cb->recv_msg(assoc->cb_arg, repp, msg);
[99ea91b2]352 udp_assoc_delref(assoc);
[92b42442]353}
354
[141a20d]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
[2f19103]368static int udp_assoc_queue_msg(udp_assoc_t *assoc, inet_ep2_t *epp,
[92b42442]369 udp_msg_t *msg)
370{
371 udp_rcv_queue_entry_t *rqe;
372
[a1a101d]373 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
[2f19103]374 assoc, epp, msg);
[92b42442]375
376 rqe = calloc(1, sizeof(udp_rcv_queue_entry_t));
377 if (rqe == NULL)
378 return ENOMEM;
379
380 link_initialize(&rqe->link);
[2f19103]381 rqe->epp = *epp;
[92b42442]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
[2f19103]393/** Find association structure for specified endpoint pair.
[92b42442]394 *
[2f19103]395 * An association is uniquely identified by an endpoint pair. Look up our
396 * association map and return association structure based on endpoint pair.
[92b42442]397 * The association reference count is bumped by one.
398 *
[2f19103]399 * @param epp Endpoint pair
[92b42442]400 * @return Association structure or NULL if not found.
401 */
[2f19103]402static udp_assoc_t *udp_assoc_find_ref(inet_ep2_t *epp)
[92b42442]403{
[8d48c7e]404 int rc;
405 void *arg;
406 udp_assoc_t *assoc;
[fab2746]407
[c3f7d37]408 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", epp);
[92b42442]409 fibril_mutex_lock(&assoc_list_lock);
[2f19103]410
[8d48c7e]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;
[92b42442]416 }
[2f19103]417
[8d48c7e]418 assoc = (udp_assoc_t *)arg;
419 udp_assoc_addref(assoc);
420
[92b42442]421 fibril_mutex_unlock(&assoc_list_lock);
[8d48c7e]422 return assoc;
[92b42442]423}
424
[ee603c4]425/**
426 * @}
427 */
Note: See TracBrowser for help on using the repository browser.