source: mainline/uspace/lib/nettl/src/amap.c@ 99c23405

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

Remove excessive debugging output.

  • Property mode set to 100644
File size: 13.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 libnettl
30 * @{
31 */
32
33/**
34 * @file Association map
35 *
36 * Manages allocations of endpoints / endpoint pairs (corresponding to
37 * UDP associations, TCP listeners and TCP connections)
38 */
39
40#include <adt/list.h>
41#include <errno.h>
42#include <inet/addr.h>
43#include <inet/inet.h>
44#include <io/log.h>
45#include <nettl/amap.h>
46#include <stdint.h>
47#include <stdlib.h>
48
49int amap_create(amap_t **rmap)
50{
51 amap_t *map;
52 int rc;
53
54 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_create()");
55
56 map = calloc(1, sizeof(amap_t));
57 if (map == NULL)
58 return ENOMEM;
59
60 rc = portrng_create(&map->unspec);
61 if (rc != EOK) {
62 assert(rc == ENOMEM);
63 free(map);
64 return ENOMEM;
65 }
66
67 list_initialize(&map->repla);
68 list_initialize(&map->laddr);
69 list_initialize(&map->llink);
70
71 *rmap = map;
72 return EOK;
73}
74
75void amap_destroy(amap_t *map)
76{
77 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_destroy()");
78 free(map);
79}
80
81/** Find exact repla */
82static int amap_repla_find(amap_t *map, inet_ep_t *rep, inet_addr_t *la,
83 amap_repla_t **rrepla)
84{
85 char *sraddr, *sladdr;
86
87 (void) inet_addr_format(&rep->addr, &sraddr);
88 (void) inet_addr_format(la, &sladdr);
89
90 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_repla_find(): rep=(%s,%" PRIu16
91 ") la=%s", sraddr, rep->port, sladdr);
92 free(sraddr);
93 free(sladdr);
94
95 list_foreach(map->repla, lamap, amap_repla_t, repla) {
96 (void) inet_addr_format(&repla->rep.addr, &sraddr);
97 (void) inet_addr_format(&repla->laddr, &sladdr);
98 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_repla_find(): "
99 "compare to rep=(%s, %" PRIu16 ") la=%s",
100 sraddr, repla->rep.port, sladdr);
101 free(sraddr);
102 free(sladdr);
103 if (inet_addr_compare(&repla->rep.addr, &rep->addr) &&
104 repla->rep.port == rep->port &&
105 inet_addr_compare(&repla->laddr, la)) {
106 *rrepla = repla;
107 return EOK;
108 }
109 }
110
111 *rrepla = NULL;
112 return ENOENT;
113}
114
115static int amap_repla_insert(amap_t *map, inet_ep_t *rep, inet_addr_t *la,
116 amap_repla_t **rrepla)
117{
118 amap_repla_t *repla;
119 int rc;
120
121 repla = calloc(1, sizeof(amap_repla_t));
122 if (repla == NULL) {
123 *rrepla = NULL;
124 return ENOMEM;
125 }
126
127 rc = portrng_create(&repla->portrng);
128 if (rc != EOK) {
129 free(repla);
130 return ENOMEM;
131 }
132
133 repla->rep = *rep;
134 repla->laddr = *la;
135 list_append(&repla->lamap, &map->repla);
136
137 *rrepla = repla;
138 return EOK;
139}
140
141static void amap_repla_remove(amap_t *map, amap_repla_t *repla)
142{
143 list_remove(&repla->lamap);
144 portrng_destroy(repla->portrng);
145 free(repla);
146}
147
148/** Find exact laddr */
149static int amap_laddr_find(amap_t *map, inet_addr_t *addr,
150 amap_laddr_t **rladdr)
151{
152 list_foreach(map->laddr, lamap, amap_laddr_t, laddr) {
153 if (inet_addr_compare(&laddr->laddr, addr)) {
154 *rladdr = laddr;
155 return EOK;
156 }
157 }
158
159 *rladdr = NULL;
160 return ENOENT;
161}
162
163static int amap_laddr_insert(amap_t *map, inet_addr_t *addr,
164 amap_laddr_t **rladdr)
165{
166 amap_laddr_t *laddr;
167 int rc;
168
169 laddr = calloc(1, sizeof(amap_laddr_t));
170 if (laddr == NULL) {
171 *rladdr = NULL;
172 return ENOMEM;
173 }
174
175 rc = portrng_create(&laddr->portrng);
176 if (rc != EOK) {
177 free(laddr);
178 return ENOMEM;
179 }
180
181 laddr->laddr = *addr;
182 list_append(&laddr->lamap, &map->laddr);
183
184 *rladdr = laddr;
185 return EOK;
186}
187
188static void amap_laddr_remove(amap_t *map, amap_laddr_t *laddr)
189{
190 list_remove(&laddr->lamap);
191 portrng_destroy(laddr->portrng);
192 free(laddr);
193}
194
195/** Find exact llink */
196static int amap_llink_find(amap_t *map, sysarg_t link_id,
197 amap_llink_t **rllink)
198{
199 list_foreach(map->llink, lamap, amap_llink_t, llink) {
200 if (llink->llink == link_id) {
201 *rllink = llink;
202 return EOK;
203 }
204 }
205
206 *rllink = NULL;
207 return ENOENT;
208}
209
210static int amap_llink_insert(amap_t *map, sysarg_t link_id,
211 amap_llink_t **rllink)
212{
213 amap_llink_t *llink;
214 int rc;
215
216 llink = calloc(1, sizeof(amap_llink_t));
217 if (llink == NULL) {
218 *rllink = NULL;
219 return ENOMEM;
220 }
221
222 rc = portrng_create(&llink->portrng);
223 if (rc != EOK) {
224 free(llink);
225 return ENOMEM;
226 }
227
228 llink->llink = link_id;
229 list_append(&llink->lamap, &map->llink);
230
231 *rllink = llink;
232 return EOK;
233}
234
235static void amap_llink_remove(amap_t *map, amap_llink_t *llink)
236{
237 list_remove(&llink->lamap);
238 portrng_destroy(llink->portrng);
239 free(llink);
240}
241
242static int amap_insert_repla(amap_t *map, inet_ep2_t *epp, void *arg,
243 amap_flags_t flags, inet_ep2_t *aepp)
244{
245 amap_repla_t *repla;
246 inet_ep2_t mepp;
247 int rc;
248
249 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_repla()");
250
251 rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
252 if (rc != EOK) {
253 /* New repla */
254 rc = amap_repla_insert(map, &epp->remote, &epp->local.addr,
255 &repla);
256 if (rc != EOK) {
257 assert(rc == ENOMEM);
258 return rc;
259 }
260 }
261
262 mepp = *epp;
263
264 rc = portrng_alloc(repla->portrng, epp->local.port, arg, flags,
265 &mepp.local.port);
266 if (rc != EOK) {
267 return rc;
268 }
269
270 *aepp = mepp;
271 return EOK;
272}
273
274static int amap_insert_laddr(amap_t *map, inet_ep2_t *epp, void *arg,
275 amap_flags_t flags, inet_ep2_t *aepp)
276{
277 amap_laddr_t *laddr;
278 inet_ep2_t mepp;
279 int rc;
280
281 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_laddr()");
282
283 rc = amap_laddr_find(map, &epp->local.addr, &laddr);
284 if (rc != EOK) {
285 /* New laddr */
286 rc = amap_laddr_insert(map, &epp->local.addr, &laddr);
287 if (rc != EOK) {
288 assert(rc == ENOMEM);
289 return rc;
290 }
291 }
292
293 mepp = *epp;
294
295 rc = portrng_alloc(laddr->portrng, epp->local.port, arg, flags,
296 &mepp.local.port);
297 if (rc != EOK) {
298 return rc;
299 }
300
301 *aepp = mepp;
302 return EOK;
303}
304
305static int amap_insert_llink(amap_t *map, inet_ep2_t *epp, void *arg,
306 amap_flags_t flags, inet_ep2_t *aepp)
307{
308 amap_llink_t *llink;
309 inet_ep2_t mepp;
310 int rc;
311
312 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_llink()");
313
314 rc = amap_llink_find(map, epp->local_link, &llink);
315 if (rc != EOK) {
316 /* New llink */
317 rc = amap_llink_insert(map, epp->local_link, &llink);
318 if (rc != EOK) {
319 assert(rc == ENOMEM);
320 return rc;
321 }
322 }
323
324 mepp = *epp;
325
326 rc = portrng_alloc(llink->portrng, epp->local.port, arg, flags,
327 &mepp.local.port);
328 if (rc != EOK) {
329 return rc;
330 }
331
332 *aepp = mepp;
333 return EOK;
334}
335
336static int amap_insert_unspec(amap_t *map, inet_ep2_t *epp, void *arg,
337 amap_flags_t flags, inet_ep2_t *aepp)
338{
339 inet_ep2_t mepp;
340 int rc;
341
342 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_unspec()");
343 mepp = *epp;
344
345 rc = portrng_alloc(map->unspec, epp->local.port, arg, flags,
346 &mepp.local.port);
347 if (rc != EOK) {
348 return rc;
349 }
350
351 *aepp = mepp;
352 return EOK;
353}
354
355/** Insert endpoint pair into map.
356 *
357 * If local endpoint is not fully specified, it is filled in (determine
358 * source address, allocate port number). Checks for conflicting endpoint pair.
359 *
360 * @param map Association map
361 * @param epp Endpoint pair, possibly with local port inet_port_any
362 * @param arg arg User value
363 * @param flags Flags
364 * @param aepp Place to store actual endpoint pair, possibly with allocated port
365 *
366 * @return EOK on success, EEXISTS if conflicting epp exists,
367 * ENOMEM if out of memory
368 */
369int amap_insert(amap_t *map, inet_ep2_t *epp, void *arg, amap_flags_t flags,
370 inet_ep2_t *aepp)
371{
372 bool raddr, rport, laddr, llink;
373 inet_ep2_t mepp;
374 int rc;
375
376 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert()");
377
378 mepp = *epp;
379
380 /* Fill in local address? */
381 if (!inet_addr_is_any(&epp->remote.addr) &&
382 inet_addr_is_any(&epp->local.addr)) {
383 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
384 "determine local address");
385 rc = inet_get_srcaddr(&epp->remote.addr, 0, &mepp.local.addr);
386 if (rc != EOK) {
387 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
388 "cannot determine local address");
389 return rc;
390 }
391 } else {
392 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
393 "local address specified or remote address not specified");
394 }
395
396 raddr = !inet_addr_is_any(&mepp.remote.addr);
397 rport = mepp.remote.port != inet_port_any;
398 laddr = !inet_addr_is_any(&mepp.local.addr);
399 llink = mepp.local_link != 0;
400
401 if (raddr && rport && laddr && !llink) {
402 return amap_insert_repla(map, &mepp, arg, flags, aepp);
403 } else if (!raddr && !rport && laddr && !llink) {
404 return amap_insert_laddr(map, &mepp, arg, flags, aepp);
405 } else if (!raddr && !rport && !laddr && llink) {
406 return amap_insert_llink(map, &mepp, arg, flags, aepp);
407 } else if (!raddr && !rport && !laddr && !llink) {
408 return amap_insert_unspec(map, &mepp, arg, flags, aepp);
409 } else {
410 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: invalid "
411 "combination of raddr=%d rport=%d laddr=%d llink=%d",
412 raddr, rport, laddr, llink);
413 return EINVAL;
414 }
415
416 return EOK;
417}
418
419static void amap_remove_repla(amap_t *map, inet_ep2_t *epp)
420{
421 amap_repla_t *repla;
422 int rc;
423
424 rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
425 if (rc != EOK) {
426 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_repla: not found");
427 return;
428 }
429
430 portrng_free_port(repla->portrng, epp->local.port);
431
432 if (portrng_empty(repla->portrng))
433 amap_repla_remove(map, repla);
434}
435
436static void amap_remove_laddr(amap_t *map, inet_ep2_t *epp)
437{
438 amap_laddr_t *laddr;
439 int rc;
440
441 rc = amap_laddr_find(map, &epp->local.addr, &laddr);
442 if (rc != EOK) {
443 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_laddr: not found");
444 return;
445 }
446
447 portrng_free_port(laddr->portrng, epp->local.port);
448
449 if (portrng_empty(laddr->portrng))
450 amap_laddr_remove(map, laddr);
451}
452
453static void amap_remove_llink(amap_t *map, inet_ep2_t *epp)
454{
455 amap_llink_t *llink;
456 int rc;
457
458 rc = amap_llink_find(map, epp->local_link, &llink);
459 if (rc != EOK) {
460 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_llink: not found");
461 return;
462 }
463
464 portrng_free_port(llink->portrng, epp->local.port);
465
466 if (portrng_empty(llink->portrng))
467 amap_llink_remove(map, llink);
468}
469
470static void amap_remove_unspec(amap_t *map, inet_ep2_t *epp)
471{
472 portrng_free_port(map->unspec, epp->local.port);
473}
474
475void amap_remove(amap_t *map, inet_ep2_t *epp)
476{
477 bool raddr, rport, laddr, llink;
478
479 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove()");
480
481 raddr = !inet_addr_is_any(&epp->remote.addr);
482 rport = epp->remote.port != inet_port_any;
483 laddr = !inet_addr_is_any(&epp->local.addr);
484 llink = epp->local_link != 0;
485
486 if (raddr && rport && laddr && !llink) {
487 amap_remove_repla(map, epp);
488 } else if (!raddr && !rport && laddr && !llink) {
489 amap_remove_laddr(map, epp);
490 } else if (!raddr && !rport && !laddr && llink) {
491 amap_remove_llink(map, epp);
492 } else if (!raddr && !rport && !laddr && !llink) {
493 amap_remove_unspec(map, epp);
494 } else {
495 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove: invalid "
496 "combination of raddr=%d rport=%d laddr=%d llink=%d",
497 raddr, rport, laddr, llink);
498 return;
499 }
500}
501
502/** Find association matching an endpoint pair.
503 *
504 * Used to find which association to deliver a datagram to.
505 *
506 * @param map Association map
507 * @param epp Endpoint pair
508 * @param rarg Place to store user argument for the matching association.
509 *
510 * @return EOK on success, ENOENT if not found.
511 */
512int amap_find_match(amap_t *map, inet_ep2_t *epp, void **rarg)
513{
514 int rc;
515 amap_repla_t *repla;
516 amap_laddr_t *laddr;
517 amap_llink_t *llink;
518
519 log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_find_match(llink=%zu)",
520 epp->local_link);
521
522 /* Remode endpoint, local address */
523 rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
524 if (rc == EOK) {
525 rc = portrng_find_port(repla->portrng, epp->local.port,
526 rarg);
527 if (rc == EOK) {
528 log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched repla / "
529 "port %" PRIu16, epp->local.port);
530 return EOK;
531 }
532 }
533
534 /* Local address */
535 rc = amap_laddr_find(map, &epp->local.addr, &laddr);
536 if (rc == EOK) {
537 rc = portrng_find_port(laddr->portrng, epp->local.port,
538 rarg);
539 if (rc == EOK) {
540 log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched laddr / "
541 "port %" PRIu16, epp->local.port);
542 return EOK;
543 }
544 }
545
546 /* Local link */
547 rc = amap_llink_find(map, epp->local_link, &llink);
548 if (epp->local_link != 0 && rc == EOK) {
549 rc = portrng_find_port(llink->portrng, epp->local.port,
550 rarg);
551 if (rc == EOK) {
552 log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched llink / "
553 "port %" PRIu16, epp->local.port);
554 return EOK;
555 }
556 }
557
558 /* Unspecified */
559 rc = portrng_find_port(map->unspec, epp->local.port, rarg);
560 if (rc == EOK) {
561 log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched unspec / port %" PRIu16,
562 epp->local.port);
563 return EOK;
564 }
565
566 log_msg(LOG_DEFAULT, LVL_DEBUG2, "No match.");
567 return ENOENT;
568}
569
570/**
571 * @}
572 */
Note: See TracBrowser for help on using the repository browser.