Ignore:
File:
1 edited

Legend:

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

    r443a0bc rc0f3460  
    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);
     
    216186}
    217187
    218 /** Set IP link in association.
    219  *
    220  * @param assoc         Association
    221  * @param iplink        IP link
    222  */
    223 void 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;
     188/** Set foreign socket in association.
     189 *
     190 * @param assoc         Association
     191 * @param fsock         Foreign socket (deeply copied)
     192 */
     193void udp_assoc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
     194{
     195        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
     196        fibril_mutex_lock(&assoc->lock);
     197        assoc->ident.foreign = *fsock;
     198        fibril_mutex_unlock(&assoc->lock);
     199}
     200
     201/** Set local socket in association.
     202 *
     203 * @param assoc Association
     204 * @param lsock Local socket (deeply copied)
     205 *
     206 */
     207void udp_assoc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
     208{
     209        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
     210        fibril_mutex_lock(&assoc->lock);
     211        assoc->ident.local = *lsock;
     212        fibril_mutex_unlock(&assoc->lock);
     213}
     214
     215/** Set local port in association.
     216 *
     217 * @param assoc Association
     218 * @param lport Local port
     219 *
     220 */
     221void udp_assoc_set_local_port(udp_assoc_t *assoc, uint16_t lport)
     222{
     223        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %" PRIu16 ")", assoc, lport);
     224        fibril_mutex_lock(&assoc->lock);
     225        assoc->ident.local.port = lport;
    229226        fibril_mutex_unlock(&assoc->lock);
    230227}
     
    233230 *
    234231 * @param assoc         Association
    235  * @param remote        Remote endpoint or NULL not to override @a assoc
     232 * @param fsock         Foreign socket or NULL not to override @a assoc
    236233 * @param msg           Message
    237234 *
    238235 * @return              EOK on success
    239  *                      EINVAL if remote endpoint is not set
     236 *                      EINVAL if foreign socket is not set
    240237 *                      ENOMEM if out of resources
    241238 *                      EIO if no route to destination exists
    242239 */
    243 int udp_assoc_send(udp_assoc_t *assoc, inet_ep_t *remote, udp_msg_t *msg)
     240int udp_assoc_send(udp_assoc_t *assoc, udp_sock_t *fsock, udp_msg_t *msg)
    244241{
    245242        udp_pdu_t *pdu;
    246         inet_ep2_t epp;
     243        udp_sockpair_t sp;
    247244        int rc;
    248245
    249246        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))
     247            assoc, fsock, msg);
     248
     249        /* @a fsock can be used to override the foreign socket */
     250        sp = assoc->ident;
     251        if (fsock != NULL)
     252                sp.foreign = *fsock;
     253
     254        if ((inet_addr_is_any(&sp.foreign.addr)) ||
     255            (sp.foreign.port == UDP_PORT_ANY))
    261256                return EINVAL;
    262257
    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);
     258        rc = udp_pdu_encode(&sp, msg, &pdu);
    271259        if (rc != EOK)
    272260                return ENOMEM;
    273261
    274         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - transmit");
    275 
    276262        rc = udp_transmit_pdu(pdu);
    277         udp_pdu_delete(pdu);
    278 
    279263        if (rc != EOK)
    280264                return EIO;
    281265
    282         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send - success");
     266        udp_pdu_delete(pdu);
     267
    283268        return EOK;
    284269}
     
    288273 * Pull one message from the association's receive queue.
    289274 */
    290 int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, inet_ep_t *remote)
     275int udp_assoc_recv(udp_assoc_t *assoc, udp_msg_t **msg, udp_sock_t *fsock)
    291276{
    292277        link_t *link;
     
    304289                log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - association was reset");
    305290                fibril_mutex_unlock(&assoc->lock);
    306                 return ENXIO;
     291                return ECONNABORTED;
    307292        }
    308293
     
    314299
    315300        *msg = rqe->msg;
    316         *remote = rqe->epp.remote;
     301        *fsock = rqe->sp.foreign;
    317302        free(rqe);
    318303
     
    324309 * Find the association to which the message belongs and queue it.
    325310 */
    326 void udp_assoc_received(inet_ep2_t *repp, udp_msg_t *msg)
     311void udp_assoc_received(udp_sockpair_t *rsp, udp_msg_t *msg)
    327312{
    328313        udp_assoc_t *assoc;
    329314        int rc;
    330315
    331         log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", repp, msg);
    332 
    333         assoc = udp_assoc_find_ref(repp);
     316        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
     317
     318        assoc = udp_assoc_find_ref(rsp);
    334319        if (assoc == NULL) {
    335320                log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
    336321                /* XXX Generate ICMP error. */
    337322                /* XXX Might propagate error directly by error return. */
    338                 udp_msg_delete(msg);
    339323                return;
    340324        }
    341325
    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.");
     326        rc = udp_assoc_queue_msg(assoc, rsp, msg);
     327        if (rc != EOK) {
     328                log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
    346329                /* 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);
     330        }
    353331}
    354332
     
    366344}
    367345
    368 static int udp_assoc_queue_msg(udp_assoc_t *assoc, inet_ep2_t *epp,
     346static int udp_assoc_queue_msg(udp_assoc_t *assoc, udp_sockpair_t *sp,
    369347    udp_msg_t *msg)
    370348{
     
    372350
    373351        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
    374             assoc, epp, msg);
     352            assoc, sp, msg);
    375353
    376354        rqe = calloc(1, sizeof(udp_rcv_queue_entry_t));
     
    379357
    380358        link_initialize(&rqe->link);
    381         rqe->epp = *epp;
     359        rqe->sp = *sp;
    382360        rqe->msg = msg;
    383361
     
    391369}
    392370
    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.
     371/** Match socket with pattern. */
     372static bool udp_socket_match(udp_sock_t *sock, udp_sock_t *patt)
     373{
     374        log_msg(LOG_DEFAULT, LVL_DEBUG,
     375            "udp_socket_match(sock=(%u), pat=(%u))", sock->port, patt->port);
     376       
     377        if ((!inet_addr_is_any(&patt->addr)) &&
     378            (!inet_addr_compare(&patt->addr, &sock->addr)))
     379                return false;
     380       
     381        if ((patt->port != UDP_PORT_ANY) &&
     382            (patt->port != sock->port))
     383                return false;
     384       
     385        log_msg(LOG_DEFAULT, LVL_DEBUG, " -> match");
     386       
     387        return true;
     388}
     389
     390/** Match socket pair with pattern. */
     391static bool udp_sockpair_match(udp_sockpair_t *sp, udp_sockpair_t *pattern)
     392{
     393        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
     394
     395        if (!udp_socket_match(&sp->local, &pattern->local))
     396                return false;
     397
     398        if (!udp_socket_match(&sp->foreign, &pattern->foreign))
     399                return false;
     400
     401        log_msg(LOG_DEFAULT, LVL_DEBUG, "Socket pair matched.");
     402        return true;
     403}
     404
     405
     406/** Find association structure for specified socket pair.
     407 *
     408 * An association is uniquely identified by a socket pair. Look up our
     409 * association map and return association structure based on socket pair.
    397410 * The association reference count is bumped by one.
    398411 *
    399  * @param epp   Endpoint pair
     412 * @param sp    Socket pair
    400413 * @return      Association structure or NULL if not found.
    401414 */
    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);
     415static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *sp)
     416{
     417        log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
     418       
    409419        fibril_mutex_lock(&assoc_list_lock);
    410 
    411         rc = amap_find_match(amap, epp, &arg);
    412         if (rc != EOK) {
    413                 assert(rc == ENOENT);
    414                 fibril_mutex_unlock(&assoc_list_lock);
    415                 return NULL;
    416         }
    417 
    418         assoc = (udp_assoc_t *)arg;
    419         udp_assoc_addref(assoc);
    420 
     420       
     421        list_foreach(assoc_list, link) {
     422                udp_assoc_t *assoc = list_get_instance(link, udp_assoc_t, link);
     423                udp_sockpair_t *asp = &assoc->ident;
     424               
     425                /* Skip unbound associations */
     426                if (asp->local.port == UDP_PORT_ANY)
     427                        continue;
     428               
     429                if (udp_sockpair_match(sp, asp)) {
     430                        log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning assoc %p", assoc);
     431                        udp_assoc_addref(assoc);
     432                        fibril_mutex_unlock(&assoc_list_lock);
     433                        return assoc;
     434                }
     435        }
     436       
    421437        fibril_mutex_unlock(&assoc_list_lock);
    422         return assoc;
     438        return NULL;
    423439}
    424440
Note: See TracChangeset for help on using the changeset viewer.