HelenOS sources
This source file includes following definitions.
- aflags_to_pflags
- amap_create
- amap_destroy
- amap_repla_find
- amap_repla_insert
- amap_repla_remove
- amap_laddr_find
- amap_laddr_insert
- amap_laddr_remove
- amap_llink_find
- amap_llink_insert
- amap_llink_remove
- amap_insert_repla
- amap_insert_laddr
- amap_insert_llink
- amap_insert_unspec
- amap_insert
- amap_remove_repla
- amap_remove_laddr
- amap_remove_llink
- amap_remove_unspec
- amap_remove
- amap_find_match
#include <adt/list.h>
#include <errno.h>
#include <inet/addr.h>
#include <inet/inet.h>
#include <io/log.h>
#include <nettl/amap.h>
#include <stdint.h>
#include <stdlib.h>
static portrng_flags_t aflags_to_pflags(amap_flags_t flags)
{
portrng_flags_t pflags;
pflags = 0;
if ((flags & af_allow_system) != 0)
pflags |= pf_allow_system;
return pflags;
}
errno_t amap_create(amap_t **rmap)
{
amap_t *map;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_create()");
map = calloc(1, sizeof(amap_t));
if (map == NULL)
return ENOMEM;
rc = portrng_create(&map->unspec);
if (rc != EOK) {
assert(rc == ENOMEM);
free(map);
return ENOMEM;
}
list_initialize(&map->repla);
list_initialize(&map->laddr);
list_initialize(&map->llink);
*rmap = map;
return EOK;
}
void amap_destroy(amap_t *map)
{
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_destroy()");
assert(list_empty(&map->repla));
assert(list_empty(&map->laddr));
assert(list_empty(&map->llink));
free(map);
}
static errno_t amap_repla_find(amap_t *map, inet_ep_t *rep, inet_addr_t *la,
amap_repla_t **rrepla)
{
char *sraddr, *sladdr;
(void) inet_addr_format(&rep->addr, &sraddr);
(void) inet_addr_format(la, &sladdr);
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_repla_find(): rep=(%s,%" PRIu16
") la=%s", sraddr, rep->port, sladdr);
free(sraddr);
free(sladdr);
list_foreach(map->repla, lamap, amap_repla_t, repla) {
(void) inet_addr_format(&repla->rep.addr, &sraddr);
(void) inet_addr_format(&repla->laddr, &sladdr);
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_repla_find(): "
"compare to rep=(%s, %" PRIu16 ") la=%s",
sraddr, repla->rep.port, sladdr);
free(sraddr);
free(sladdr);
if (inet_addr_compare(&repla->rep.addr, &rep->addr) &&
repla->rep.port == rep->port &&
inet_addr_compare(&repla->laddr, la)) {
*rrepla = repla;
return EOK;
}
}
*rrepla = NULL;
return ENOENT;
}
static errno_t amap_repla_insert(amap_t *map, inet_ep_t *rep, inet_addr_t *la,
amap_repla_t **rrepla)
{
amap_repla_t *repla;
errno_t rc;
repla = calloc(1, sizeof(amap_repla_t));
if (repla == NULL) {
*rrepla = NULL;
return ENOMEM;
}
rc = portrng_create(&repla->portrng);
if (rc != EOK) {
free(repla);
return ENOMEM;
}
repla->rep = *rep;
repla->laddr = *la;
list_append(&repla->lamap, &map->repla);
*rrepla = repla;
return EOK;
}
static void amap_repla_remove(amap_t *map, amap_repla_t *repla)
{
list_remove(&repla->lamap);
portrng_destroy(repla->portrng);
free(repla);
}
static errno_t amap_laddr_find(amap_t *map, inet_addr_t *addr,
amap_laddr_t **rladdr)
{
list_foreach(map->laddr, lamap, amap_laddr_t, laddr) {
if (inet_addr_compare(&laddr->laddr, addr)) {
*rladdr = laddr;
return EOK;
}
}
*rladdr = NULL;
return ENOENT;
}
static errno_t amap_laddr_insert(amap_t *map, inet_addr_t *addr,
amap_laddr_t **rladdr)
{
amap_laddr_t *laddr;
errno_t rc;
laddr = calloc(1, sizeof(amap_laddr_t));
if (laddr == NULL) {
*rladdr = NULL;
return ENOMEM;
}
rc = portrng_create(&laddr->portrng);
if (rc != EOK) {
free(laddr);
return ENOMEM;
}
laddr->laddr = *addr;
list_append(&laddr->lamap, &map->laddr);
*rladdr = laddr;
return EOK;
}
static void amap_laddr_remove(amap_t *map, amap_laddr_t *laddr)
{
list_remove(&laddr->lamap);
portrng_destroy(laddr->portrng);
free(laddr);
}
static errno_t amap_llink_find(amap_t *map, sysarg_t link_id,
amap_llink_t **rllink)
{
list_foreach(map->llink, lamap, amap_llink_t, llink) {
if (llink->llink == link_id) {
*rllink = llink;
return EOK;
}
}
*rllink = NULL;
return ENOENT;
}
static errno_t amap_llink_insert(amap_t *map, sysarg_t link_id,
amap_llink_t **rllink)
{
amap_llink_t *llink;
errno_t rc;
llink = calloc(1, sizeof(amap_llink_t));
if (llink == NULL) {
*rllink = NULL;
return ENOMEM;
}
rc = portrng_create(&llink->portrng);
if (rc != EOK) {
free(llink);
return ENOMEM;
}
llink->llink = link_id;
list_append(&llink->lamap, &map->llink);
*rllink = llink;
return EOK;
}
static void amap_llink_remove(amap_t *map, amap_llink_t *llink)
{
list_remove(&llink->lamap);
portrng_destroy(llink->portrng);
free(llink);
}
static errno_t amap_insert_repla(amap_t *map, inet_ep2_t *epp, void *arg,
amap_flags_t flags, inet_ep2_t *aepp)
{
amap_repla_t *repla;
inet_ep2_t mepp;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_repla()");
rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
if (rc != EOK) {
rc = amap_repla_insert(map, &epp->remote, &epp->local.addr,
&repla);
if (rc != EOK) {
assert(rc == ENOMEM);
return rc;
}
}
mepp = *epp;
rc = portrng_alloc(repla->portrng, epp->local.port, arg, aflags_to_pflags(flags),
&mepp.local.port);
if (rc != EOK) {
return rc;
}
*aepp = mepp;
return EOK;
}
static errno_t amap_insert_laddr(amap_t *map, inet_ep2_t *epp, void *arg,
amap_flags_t flags, inet_ep2_t *aepp)
{
amap_laddr_t *laddr;
inet_ep2_t mepp;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_laddr()");
rc = amap_laddr_find(map, &epp->local.addr, &laddr);
if (rc != EOK) {
rc = amap_laddr_insert(map, &epp->local.addr, &laddr);
if (rc != EOK) {
assert(rc == ENOMEM);
return rc;
}
}
mepp = *epp;
rc = portrng_alloc(laddr->portrng, epp->local.port, arg, aflags_to_pflags(flags),
&mepp.local.port);
if (rc != EOK) {
return rc;
}
*aepp = mepp;
return EOK;
}
static errno_t amap_insert_llink(amap_t *map, inet_ep2_t *epp, void *arg,
amap_flags_t flags, inet_ep2_t *aepp)
{
amap_llink_t *llink;
inet_ep2_t mepp;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_llink()");
rc = amap_llink_find(map, epp->local_link, &llink);
if (rc != EOK) {
rc = amap_llink_insert(map, epp->local_link, &llink);
if (rc != EOK) {
assert(rc == ENOMEM);
return rc;
}
}
mepp = *epp;
rc = portrng_alloc(llink->portrng, epp->local.port, arg, aflags_to_pflags(flags),
&mepp.local.port);
if (rc != EOK) {
return rc;
}
*aepp = mepp;
return EOK;
}
static errno_t amap_insert_unspec(amap_t *map, inet_ep2_t *epp, void *arg,
amap_flags_t flags, inet_ep2_t *aepp)
{
inet_ep2_t mepp;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert_unspec()");
mepp = *epp;
rc = portrng_alloc(map->unspec, epp->local.port, arg, aflags_to_pflags(flags),
&mepp.local.port);
if (rc != EOK) {
return rc;
}
*aepp = mepp;
return EOK;
}
errno_t amap_insert(amap_t *map, inet_ep2_t *epp, void *arg, amap_flags_t flags,
inet_ep2_t *aepp)
{
bool raddr, rport, laddr, llink;
inet_ep2_t mepp;
errno_t rc;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert()");
mepp = *epp;
if (!inet_addr_is_any(&epp->remote.addr) &&
inet_addr_is_any(&epp->local.addr)) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
"determine local address");
rc = inet_get_srcaddr(&epp->remote.addr, 0, &mepp.local.addr);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
"cannot determine local address");
return rc;
}
} else {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: "
"local address specified or remote address not specified");
}
raddr = !inet_addr_is_any(&mepp.remote.addr);
rport = mepp.remote.port != inet_port_any;
laddr = !inet_addr_is_any(&mepp.local.addr);
llink = mepp.local_link != 0;
if (raddr && rport && laddr && !llink) {
return amap_insert_repla(map, &mepp, arg, flags, aepp);
} else if (!raddr && !rport && laddr && !llink) {
return amap_insert_laddr(map, &mepp, arg, flags, aepp);
} else if (!raddr && !rport && !laddr && llink) {
return amap_insert_llink(map, &mepp, arg, flags, aepp);
} else if (!raddr && !rport && !laddr && !llink) {
return amap_insert_unspec(map, &mepp, arg, flags, aepp);
} else {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_insert: invalid "
"combination of raddr=%d rport=%d laddr=%d llink=%d",
raddr, rport, laddr, llink);
return EINVAL;
}
return EOK;
}
static void amap_remove_repla(amap_t *map, inet_ep2_t *epp)
{
amap_repla_t *repla;
errno_t rc;
rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_repla: not found");
return;
}
portrng_free_port(repla->portrng, epp->local.port);
if (portrng_empty(repla->portrng))
amap_repla_remove(map, repla);
}
static void amap_remove_laddr(amap_t *map, inet_ep2_t *epp)
{
amap_laddr_t *laddr;
errno_t rc;
rc = amap_laddr_find(map, &epp->local.addr, &laddr);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_laddr: not found");
return;
}
portrng_free_port(laddr->portrng, epp->local.port);
if (portrng_empty(laddr->portrng))
amap_laddr_remove(map, laddr);
}
static void amap_remove_llink(amap_t *map, inet_ep2_t *epp)
{
amap_llink_t *llink;
errno_t rc;
rc = amap_llink_find(map, epp->local_link, &llink);
if (rc != EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove_llink: not found");
return;
}
portrng_free_port(llink->portrng, epp->local.port);
if (portrng_empty(llink->portrng))
amap_llink_remove(map, llink);
}
static void amap_remove_unspec(amap_t *map, inet_ep2_t *epp)
{
portrng_free_port(map->unspec, epp->local.port);
}
void amap_remove(amap_t *map, inet_ep2_t *epp)
{
bool raddr, rport, laddr, llink;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove()");
raddr = !inet_addr_is_any(&epp->remote.addr);
rport = epp->remote.port != inet_port_any;
laddr = !inet_addr_is_any(&epp->local.addr);
llink = epp->local_link != 0;
if (raddr && rport && laddr && !llink) {
amap_remove_repla(map, epp);
} else if (!raddr && !rport && laddr && !llink) {
amap_remove_laddr(map, epp);
} else if (!raddr && !rport && !laddr && llink) {
amap_remove_llink(map, epp);
} else if (!raddr && !rport && !laddr && !llink) {
amap_remove_unspec(map, epp);
} else {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_remove: invalid "
"combination of raddr=%d rport=%d laddr=%d llink=%d",
raddr, rport, laddr, llink);
return;
}
}
errno_t amap_find_match(amap_t *map, inet_ep2_t *epp, void **rarg)
{
errno_t rc;
amap_repla_t *repla;
amap_laddr_t *laddr;
amap_llink_t *llink;
log_msg(LOG_DEFAULT, LVL_DEBUG2, "amap_find_match(llink=%zu)",
epp->local_link);
rc = amap_repla_find(map, &epp->remote, &epp->local.addr, &repla);
if (rc == EOK) {
rc = portrng_find_port(repla->portrng, epp->local.port,
rarg);
if (rc == EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched repla / "
"port %" PRIu16, epp->local.port);
return EOK;
}
}
rc = amap_laddr_find(map, &epp->local.addr, &laddr);
if (rc == EOK) {
rc = portrng_find_port(laddr->portrng, epp->local.port,
rarg);
if (rc == EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched laddr / "
"port %" PRIu16, epp->local.port);
return EOK;
}
}
rc = amap_llink_find(map, epp->local_link, &llink);
if (epp->local_link != 0 && rc == EOK) {
rc = portrng_find_port(llink->portrng, epp->local.port,
rarg);
if (rc == EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched llink / "
"port %" PRIu16, epp->local.port);
return EOK;
}
}
rc = portrng_find_port(map->unspec, epp->local.port, rarg);
if (rc == EOK) {
log_msg(LOG_DEFAULT, LVL_DEBUG2, "Matched unspec / port %" PRIu16,
epp->local.port);
return EOK;
}
log_msg(LOG_DEFAULT, LVL_DEBUG2, "No match.");
return ENOENT;
}
HelenOS homepage, sources at GitHub