Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/udp/assoc.c

    rc3f7d37 r071a2c60  
    11/*
    2  * Copyright (c) 2015 Jiri Svoboda
     2 * Copyright (c) 2012 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3636
    3737#include <adt/list.h>
    38 #include <errno.h>
    3938#include <stdbool.h>
    4039#include <fibril_synch.h>
    41 #include <inet/endpoint.h>
    4240#include <io/log.h>
    43 #include <nettl/amap.h>
    4441#include <stdlib.h>
    4542
     
    4744#include "msg.h"
    4845#include "pdu.h"
     46#include "ucall.h"
    4947#include "udp_inet.h"
    5048#include "udp_type.h"
    5149
    52 static LIST_INITIALIZE(assoc_list);
    53 static FIBRIL_MUTEX_INITIALIZE(assoc_list_lock);
    54 static amap_t *amap;
    55 
    56 static udp_assoc_t *udp_assoc_find_ref(inet_ep2_t *);
    57 static int udp_assoc_queue_msg(udp_assoc_t *, inet_ep2_t *, udp_msg_t *);
    58 
    59 /** Initialize associations. */
    60 int 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 }
     50LIST_INITIALIZE(assoc_list);
     51FIBRIL_MUTEX_INITIALIZE(assoc_list_lock);
     52
     53static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *);
     54static int udp_assoc_queue_msg(udp_assoc_t *, udp_sockpair_t *, udp_msg_t *);
     55static bool udp_socket_match(udp_sock_t *, udp_sock_t *);
     56static bool udp_sockpair_match(udp_sockpair_t *, udp_sockpair_t *);
    7257
    7358/** Create new association structure.
    7459 *
    75  * @param epp           Endpoint pair (will be copied)
    76  * @param cb            Callbacks
    77  * @param cb_arg        Callback argument
     60 * @param lsock         Local socket (will be deeply copied)
     61 * @param fsock         Foreign socket (will be deeply copied)
    7862 * @return              New association or NULL
    7963 */
    80 udp_assoc_t *udp_assoc_new(inet_ep2_t *epp, udp_assoc_cb_t *cb, void *cb_arg)
     64udp_assoc_t *udp_assoc_new(udp_sock_t *lsock, udp_sock_t *fsock)
    8165{
    8266        udp_assoc_t *assoc = NULL;
     
    9680        fibril_condvar_initialize(&assoc->rcv_queue_cv);
    9781
    98         if (epp != NULL)
    99                 assoc->ident = *epp;
    100 
    101         assoc->cb = cb;
    102         assoc->cb_arg = cb_arg;
     82        if (lsock != NULL)
     83                assoc->ident.local = *lsock;
     84       
     85        if (fsock != NULL)
     86                assoc->ident.foreign = *fsock;
     87
    10388        return assoc;
    10489error:
     
    181166 * Add association to the association map.
    182167 */
    183 int udp_assoc_add(udp_assoc_t *assoc)
    184 {
    185         inet_ep2_t aepp;
    186         int rc;
    187 
     168void udp_assoc_add(udp_assoc_t *assoc)
     169{
    188170        udp_assoc_addref(assoc);
    189171        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;
    199172        list_append(&assoc->link, &assoc_list);
    200173        fibril_mutex_unlock(&assoc_list_lock);
    201 
    202         return EOK;
    203174}
    204175
     
    210181{
    211182        fibril_mutex_lock(&assoc_list_lock);
    212         amap_remove(amap, &assoc->ident);
    213183        list_remove(&assoc->link);
    214184        fibril_mutex_unlock(&assoc_list_lock);
     
    226196            assoc, iplink);
    227197        fibril_mutex_lock(&assoc->lock);
    228         assoc->ident.local_link = iplink;
     198        assoc->ident.iplink = iplink;
     199        fibril_mutex_unlock(&assoc->lock);
     200}
     201
     202/** Set foreign socket in association.
     203 *
     204 * @param assoc         Association
     205 * @param fsock         Foreign socket (deeply copied)
     206 */
     207void udp_assoc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
     208{
     209        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
     210        fibril_mutex_lock(&assoc->lock);
     211        assoc->ident.foreign = *fsock;
     212        fibril_mutex_unlock(&assoc->lock);
     213}
     214
     215/** Set local socket in association.
     216 *
     217 * @param assoc Association
     218 * @param lsock Local socket (deeply copied)
     219 *
     220 */
     221void udp_assoc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
     222{
     223        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
     224        fibril_mutex_lock(&assoc->lock);
     225        assoc->ident.local = *lsock;
     226        fibril_mutex_unlock(&assoc->lock);
     227}
     228
     229/** Set local port in association.
     230 *
     231 * @param assoc Association
     232 * @param lport Local port
     233 *
     234 */
     235void udp_assoc_set_local_port(udp_assoc_t *assoc, uint16_t lport)
     236{
     237        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %" PRIu16 ")", assoc, lport);
     238        fibril_mutex_lock(&assoc->lock);
     239        assoc->ident.local.port = lport;
    229240        fibril_mutex_unlock(&assoc->lock);
    230241}
     
    233244 *
    234245 * @param assoc         Association
    235  * @param remote        Remote endpoint or NULL not to override @a assoc
     246 * @param fsock         Foreign socket or NULL not to override @a assoc
    236247 * @param msg           Message
    237248 *
    238249 * @return              EOK on success
    239  *                      EINVAL if remote endpoint is not set
     250 *                      EINVAL if foreign socket is not set
    240251 *                      ENOMEM if out of resources
    241252 *                      EIO if no route to destination exists
    242253 */
    243 int udp_assoc_send(udp_assoc_t *assoc, inet_ep_t *remote, udp_msg_t *msg)
     254int udp_assoc_send(udp_assoc_t *assoc, udp_sock_t *fsock, udp_msg_t *msg)
    244255{
    245256        udp_pdu_t *pdu;
    246         inet_ep2_t epp;
     257        udp_sockpair_t sp;
    247258        int rc;
    248259
    249260        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            assoc, fsock, msg);
     262
     263        /* @a fsock can be used to override the foreign socket */
     264        sp = assoc->ident;
     265        if (fsock != NULL)
     266                sp.foreign = *fsock;
     267
     268        if ((inet_addr_is_any(&sp.foreign.addr)) ||
     269            (sp.foreign.port == UDP_PORT_ANY))
    261270                return EINVAL;
    262271
    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);
     272        rc = udp_pdu_encode(&sp, msg, &pdu);
    271273        if (rc != EOK)
    272274                return ENOMEM;
    273275
    274         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - transmit");
    275 
    276276        rc = udp_transmit_pdu(pdu);
    277277        udp_pdu_delete(pdu);
     
    280280                return EIO;
    281281
    282         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - success");
    283282        return EOK;
    284283}
     
    288287 * Pull one message from the association's receive queue.
    289288 */
    290 int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, inet_ep_t *remote)
     289int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, udp_sock_t *fsock)
    291290{
    292291        link_t *link;
     
    304303                log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - association was reset");
    305304                fibril_mutex_unlock(&assoc->lock);
    306                 return ENXIO;
     305                return ECONNABORTED;
    307306        }
    308307
     
    314313
    315314        *msg = rqe->msg;
    316         *remote = rqe->epp.remote;
     315        *fsock = rqe->sp.foreign;
    317316        free(rqe);
    318317
     
    324323 * Find the association to which the message belongs and queue it.
    325324 */
    326 void udp_assoc_received(inet_ep2_t *repp, udp_msg_t *msg)
     325void udp_assoc_received(udp_sockpair_t *rsp, udp_msg_t *msg)
    327326{
    328327        udp_assoc_t *assoc;
    329328        int rc;
    330329
    331         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", repp, msg);
    332 
    333         assoc = udp_assoc_find_ref(repp);
     330        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
     331
     332        assoc = udp_assoc_find_ref(rsp);
    334333        if (assoc == NULL) {
    335334                log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
     
    340339        }
    341340
    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.");
     341        rc = udp_assoc_queue_msg(assoc, rsp, msg);
     342        if (rc != EOK) {
     343                log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
    346344                /* 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);
     345        }
    353346}
    354347
     
    366359}
    367360
    368 static int udp_assoc_queue_msg(udp_assoc_t *assoc, inet_ep2_t *epp,
     361static int udp_assoc_queue_msg(udp_assoc_t *assoc, udp_sockpair_t *sp,
    369362    udp_msg_t *msg)
    370363{
     
    372365
    373366        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
    374             assoc, epp, msg);
     367            assoc, sp, msg);
    375368
    376369        rqe = calloc(1, sizeof(udp_rcv_queue_entry_t));
     
    379372
    380373        link_initialize(&rqe->link);
    381         rqe->epp = *epp;
     374        rqe->sp = *sp;
    382375        rqe->msg = msg;
    383376
     
    391384}
    392385
    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.
     386/** Match socket with pattern. */
     387static bool udp_socket_match(udp_sock_t *sock, udp_sock_t *patt)
     388{
     389        log_msg(LOG_DEFAULT, LVL_DEBUG,
     390            "udp_socket_match(sock=(%u), pat=(%u))", sock->port, patt->port);
     391       
     392        if ((!inet_addr_is_any(&patt->addr)) &&
     393            (!inet_addr_compare(&patt->addr, &sock->addr)))
     394                return false;
     395       
     396        if ((patt->port != UDP_PORT_ANY) &&
     397            (patt->port != sock->port))
     398                return false;
     399       
     400        log_msg(LOG_DEFAULT, LVL_DEBUG, " -> match");
     401       
     402        return true;
     403}
     404
     405/** Match socket pair with pattern. */
     406static bool udp_sockpair_match(udp_sockpair_t *sp, udp_sockpair_t *pattern)
     407{
     408        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
     409
     410        if (!udp_socket_match(&sp->local, &pattern->local))
     411                return false;
     412
     413        if (!udp_socket_match(&sp->foreign, &pattern->foreign))
     414                return false;
     415
     416        log_msg(LOG_DEFAULT, LVL_DEBUG, "Socket pair matched.");
     417        return true;
     418}
     419
     420
     421/** Find association structure for specified socket pair.
     422 *
     423 * An association is uniquely identified by a socket pair. Look up our
     424 * association map and return association structure based on socket pair.
    397425 * The association reference count is bumped by one.
    398426 *
    399  * @param epp   Endpoint pair
     427 * @param sp    Socket pair
    400428 * @return      Association structure or NULL if not found.
    401429 */
    402 static 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);
     430static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *sp)
     431{
     432        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
     433       
    409434        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 
     435       
     436        list_foreach(assoc_list, link, udp_assoc_t, assoc) {
     437                udp_sockpair_t *asp = &assoc->ident;
     438               
     439                /* Skip unbound associations */
     440                if (asp->local.port == UDP_PORT_ANY)
     441                        continue;
     442               
     443                if (udp_sockpair_match(sp, asp)) {
     444                        log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning assoc %p", assoc);
     445                        udp_assoc_addref(assoc);
     446                        fibril_mutex_unlock(&assoc_list_lock);
     447                        return assoc;
     448                }
     449        }
     450       
    421451        fibril_mutex_unlock(&assoc_list_lock);
    422         return assoc;
     452        return NULL;
    423453}
    424454
Note: See TracChangeset for help on using the changeset viewer.