LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/net - nr_socket_multi_tcp.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 268 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             : Copyright (c) 2007, Adobe Systems, Incorporated
       3             : Copyright (c) 2014, Mozilla
       4             : All rights reserved.
       5             : 
       6             : Redistribution and use in source and binary forms, with or without
       7             : modification, are permitted provided that the following conditions are
       8             : met:
       9             : 
      10             : * Redistributions of source code must retain the above copyright
      11             :   notice, this list of conditions and the following disclaimer.
      12             : 
      13             : * Redistributions in binary form must reproduce the above copyright
      14             :   notice, this list of conditions and the following disclaimer in the
      15             :   documentation and/or other materials provided with the distribution.
      16             : 
      17             : * Neither the name of Adobe Systems, Network Resonance nor the names of its
      18             :   contributors may be used to endorse or promote products derived from
      19             :   this software without specific prior written permission.
      20             : 
      21             : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      22             : "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      23             : LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      24             : A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      25             : OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      26             : SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      27             : LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      28             : DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      29             : THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      30             : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      31             : OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      32             : */
      33             : 
      34             : #include <assert.h>
      35             : #include <sys/types.h>
      36             : 
      37             : #include "nr_api.h"
      38             : #include "ice_ctx.h"
      39             : #include "nr_socket.h"
      40             : #include "nr_socket_local.h"
      41             : #include "nr_socket_multi_tcp.h"
      42             : #include "nr_socket_buffered_stun.h"
      43             : #include "async_timer.h"
      44             : 
      45             : typedef struct nr_tcp_socket_ctx_ {
      46             :      nr_socket * inner;
      47             :      nr_transport_addr remote_addr;
      48             :      int is_framed;
      49             : 
      50             :      TAILQ_ENTRY(nr_tcp_socket_ctx_) entry;
      51             : } nr_tcp_socket_ctx;
      52             : 
      53             : typedef TAILQ_HEAD(nr_tcp_socket_head_,nr_tcp_socket_ctx_) nr_tcp_socket_head;
      54             : 
      55             : static void nr_tcp_socket_readable_cb(NR_SOCKET s, int how, void *arg);
      56             : 
      57           0 : static int nr_tcp_socket_ctx_destroy(nr_tcp_socket_ctx **objp)
      58             :   {
      59             :     nr_tcp_socket_ctx *sock;
      60             : 
      61           0 :     if (!objp || !*objp)
      62           0 :       return(0);
      63             : 
      64           0 :     sock=*objp;
      65           0 :     *objp=0;
      66             : 
      67           0 :     nr_socket_destroy(&sock->inner);
      68             : 
      69           0 :     RFREE(sock);
      70             : 
      71           0 :     return(0);
      72             :   }
      73             : 
      74             : /* This takes ownership of nrsock whether it fails or not. */
      75           0 : static int nr_tcp_socket_ctx_create(nr_socket *nrsock, int is_framed,
      76             :   int max_pending, nr_tcp_socket_ctx **sockp)
      77             :   {
      78             :     int r, _status;
      79           0 :     nr_tcp_socket_ctx *sock = 0;
      80             :     nr_socket *tcpsock;
      81             : 
      82           0 :     if (!(sock = RCALLOC(sizeof(nr_tcp_socket_ctx)))) {
      83           0 :       nr_socket_destroy(&nrsock);
      84           0 :       ABORT(R_NO_MEMORY);
      85             :     }
      86             : 
      87           0 :     if ((r=nr_socket_buffered_stun_create(nrsock, max_pending, is_framed ? ICE_TCP_FRAMING : TURN_TCP_FRAMING, &tcpsock))){
      88           0 :       nr_socket_destroy(&nrsock);
      89           0 :       ABORT(r);
      90             :     }
      91             : 
      92           0 :     sock->inner=tcpsock;
      93           0 :     sock->is_framed=is_framed;
      94             : 
      95           0 :     if ((r=nr_ip4_port_to_transport_addr(ntohl(INADDR_ANY), 0, IPPROTO_TCP, &sock->remote_addr)))
      96           0 :       ABORT(r);
      97             : 
      98           0 :     *sockp=sock;
      99             : 
     100           0 :     _status=0;
     101             : abort:
     102           0 :     if (_status) {
     103           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s failed with error %d",__FILE__,__LINE__,__FUNCTION__,_status);
     104           0 :       nr_tcp_socket_ctx_destroy(&sock);
     105             :     }
     106           0 :     return(_status);
     107             :   }
     108             : 
     109           0 : static int nr_tcp_socket_ctx_initialize(nr_tcp_socket_ctx *tcpsock,
     110             :   nr_transport_addr *addr, void* cb_arg)
     111             :   {
     112             :     int r, _status;
     113             :     NR_SOCKET fd;
     114             : 
     115           0 :     if ((r=nr_transport_addr_copy(&tcpsock->remote_addr, addr)))
     116           0 :       ABORT(r);
     117           0 :     if ((r=nr_socket_getfd(tcpsock->inner, &fd)))
     118           0 :       ABORT(r);
     119           0 :     NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, nr_tcp_socket_readable_cb, cb_arg);
     120             : 
     121           0 :     _status=0;
     122             :   abort:
     123           0 :     if (_status)
     124           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
     125           0 :     return(_status);
     126             :   }
     127             : 
     128             : typedef struct nr_socket_multi_tcp_ {
     129             :   nr_ice_ctx *ctx;
     130             :   nr_socket *listen_socket;
     131             :   nr_tcp_socket_head sockets;
     132             :   nr_socket_tcp_type tcp_type;
     133             :   nr_transport_addr addr;
     134             :   NR_async_cb readable_cb;
     135             :   void *readable_cb_arg;
     136             :   int max_pending;
     137             : } nr_socket_multi_tcp;
     138             : 
     139             : static int nr_socket_multi_tcp_destroy(void **objp);
     140             : static int nr_socket_multi_tcp_sendto(void *obj,const void *msg, size_t len,
     141             :   int flags, nr_transport_addr *to);
     142             : static int nr_socket_multi_tcp_recvfrom(void *obj,void * restrict buf,
     143             :   size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
     144             : static int nr_socket_multi_tcp_getaddr(void *obj, nr_transport_addr *addrp);
     145             : static int nr_socket_multi_tcp_close(void *obj);
     146             : static int nr_socket_multi_tcp_connect(void *sock, nr_transport_addr *addr);
     147             : static int nr_socket_multi_tcp_listen(void *obj, int backlog);
     148             : 
     149             : static nr_socket_vtbl nr_socket_multi_tcp_vtbl={
     150             :   2,
     151             :   nr_socket_multi_tcp_destroy,
     152             :   nr_socket_multi_tcp_sendto,
     153             :   nr_socket_multi_tcp_recvfrom,
     154             :   0,
     155             :   nr_socket_multi_tcp_getaddr,
     156             :   nr_socket_multi_tcp_connect,
     157             :   0,
     158             :   0,
     159             :   nr_socket_multi_tcp_close,
     160             :   nr_socket_multi_tcp_listen,
     161             :   0
     162             : };
     163             : 
     164           0 : static int nr_socket_multi_tcp_create_stun_server_socket(
     165             :   nr_socket_multi_tcp *sock, nr_ice_stun_server * stun_server,
     166             :   nr_transport_addr *addr, int max_pending)
     167             :   {
     168             :     int r, _status;
     169           0 :     nr_tcp_socket_ctx *tcp_socket_ctx=0;
     170             :     nr_socket * nrsock;
     171             : 
     172           0 :     if (stun_server->transport!=IPPROTO_TCP) {
     173           0 :       r_log(LOG_ICE,LOG_INFO,"%s:%d function %s skipping UDP STUN server(addr:%s)",__FILE__,__LINE__,__FUNCTION__,stun_server->u.addr.as_string);
     174           0 :       ABORT(R_BAD_ARGS);
     175             :     }
     176             : 
     177           0 :     if (stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR &&
     178           0 :         nr_transport_addr_cmp(&stun_server->u.addr,addr,NR_TRANSPORT_ADDR_CMP_MODE_VERSION)) {
     179           0 :       r_log(LOG_ICE,LOG_INFO,"%s:%d function %s skipping STUN with different IP version (%u) than local socket (%u),",__FILE__,__LINE__,__FUNCTION__,stun_server->u.addr.ip_version,addr->ip_version);
     180           0 :       ABORT(R_BAD_ARGS);
     181             :     }
     182             : 
     183           0 :     if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory,addr, &nrsock)))
     184           0 :       ABORT(r);
     185             : 
     186             :     /* This takes ownership of nrsock whether it fails or not. */
     187           0 :     if ((r=nr_tcp_socket_ctx_create(nrsock, 0, max_pending, &tcp_socket_ctx)))
     188           0 :       ABORT(r);
     189             : 
     190           0 :     if (stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
     191             :       nr_transport_addr stun_server_addr;
     192             : 
     193           0 :       nr_transport_addr_copy(&stun_server_addr, &stun_server->u.addr);
     194           0 :       r=nr_socket_connect(tcp_socket_ctx->inner, &stun_server_addr);
     195           0 :       if (r && r!=R_WOULDBLOCK) {
     196           0 :         r_log(LOG_ICE,LOG_WARNING,"%s:%d function %s connect to STUN server(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,stun_server_addr.as_string,r);
     197           0 :         ABORT(r);
     198             :       }
     199             : 
     200           0 :       if ((r=nr_tcp_socket_ctx_initialize(tcp_socket_ctx, &stun_server_addr, sock)))
     201           0 :         ABORT(r);
     202             :     }
     203             : 
     204           0 :     TAILQ_INSERT_TAIL(&sock->sockets, tcp_socket_ctx, entry);
     205             : 
     206           0 :     _status=0;
     207             :   abort:
     208           0 :     if (_status) {
     209           0 :       nr_tcp_socket_ctx_destroy(&tcp_socket_ctx);
     210           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
     211             :     }
     212           0 :     return(_status);
     213             :   }
     214             : 
     215           0 : int nr_socket_multi_tcp_create(struct nr_ice_ctx_ *ctx,
     216             :     nr_transport_addr *addr, nr_socket_tcp_type tcp_type,
     217             :     int precreated_so_count, int max_pending, nr_socket **sockp)
     218             :   {
     219           0 :     int i=0;
     220             :     int r, _status;
     221           0 :     nr_socket_multi_tcp *sock=0;
     222             :     nr_tcp_socket_ctx *tcp_socket_ctx;
     223             :     nr_socket * nrsock;
     224             : 
     225           0 :     if (!(sock = RCALLOC(sizeof(nr_socket_multi_tcp))))
     226           0 :       ABORT(R_NO_MEMORY);
     227             : 
     228           0 :     TAILQ_INIT(&sock->sockets);
     229             : 
     230           0 :     sock->ctx=ctx;
     231           0 :     sock->max_pending=max_pending;
     232           0 :     sock->tcp_type=tcp_type;
     233           0 :     nr_transport_addr_copy(&sock->addr, addr);
     234             : 
     235           0 :     if((tcp_type==TCP_TYPE_PASSIVE) &&
     236           0 :       ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, addr, &sock->listen_socket))))
     237           0 :       ABORT(r);
     238             : 
     239           0 :     if (tcp_type!=TCP_TYPE_ACTIVE) {
     240           0 :       if (sock->ctx && sock->ctx->stun_servers) {
     241           0 :         for (i=0; i<sock->ctx->stun_server_ct; ++i) {
     242           0 :           if ((r=nr_socket_multi_tcp_create_stun_server_socket(sock,
     243           0 :               sock->ctx->stun_servers+i, addr, max_pending))) {
     244           0 :             if (r!=R_BAD_ARGS) {
     245           0 :               r_log(LOG_ICE,LOG_WARNING,"%s:%d function %s failed to connect STUN server from addr:%s with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,r);
     246             :             }
     247             :           }
     248             :         }
     249             :       }
     250           0 :       if (sock->ctx && sock->ctx->turn_servers) {
     251           0 :         for (i=0; i<sock->ctx->turn_server_ct; ++i) {
     252           0 :           if ((r=nr_socket_multi_tcp_create_stun_server_socket(sock,
     253           0 :               &(sock->ctx->turn_servers[i]).turn_server, addr, max_pending))) {
     254           0 :             if (r!=R_BAD_ARGS) {
     255           0 :               r_log(LOG_ICE,LOG_WARNING,"%s:%d function %s failed to connect TURN server from addr:%s with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,r);
     256             :             }
     257             :           }
     258             :         }
     259             :       }
     260             :     }
     261             : 
     262           0 :     if ((tcp_type==TCP_TYPE_SO)) {
     263           0 :       for (i=0; i<precreated_so_count; ++i) {
     264             : 
     265           0 :         if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, addr, &nrsock)))
     266           0 :           ABORT(r);
     267             : 
     268             :         /* This takes ownership of nrsock whether it fails or not. */
     269           0 :         if ((r=nr_tcp_socket_ctx_create(nrsock, 1, max_pending, &tcp_socket_ctx))){
     270           0 :           ABORT(r);
     271             :         }
     272           0 :         TAILQ_INSERT_TAIL(&sock->sockets, tcp_socket_ctx, entry);
     273             :       }
     274             :     }
     275             : 
     276           0 :     if((r=nr_socket_create_int(sock, &nr_socket_multi_tcp_vtbl, sockp)))
     277           0 :       ABORT(r);
     278             : 
     279           0 :     _status=0;
     280             :   abort:
     281           0 :     if (_status) {
     282           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
     283           0 :       nr_socket_multi_tcp_destroy((void**)&sock);
     284             :     }
     285           0 :     return(_status);
     286             :   }
     287             : 
     288           0 : int nr_socket_multi_tcp_set_readable_cb(nr_socket *sock,
     289             :   NR_async_cb readable_cb, void *readable_cb_arg)
     290             :   {
     291           0 :     nr_socket_multi_tcp *mtcp_sock = (nr_socket_multi_tcp *)sock->obj;
     292             : 
     293           0 :     mtcp_sock->readable_cb=readable_cb;
     294           0 :     mtcp_sock->readable_cb_arg=readable_cb_arg;
     295             : 
     296           0 :     return 0;
     297             :   }
     298             : 
     299             : #define PREALLOC_CONNECT_FRAMED          0
     300             : #define PREALLOC_CONNECT_NON_FRAMED      1
     301             : #define PREALLOC_DONT_CONNECT_UNLESS_SO  2
     302             : 
     303           0 : static int nr_socket_multi_tcp_get_sock_connected_to(nr_socket_multi_tcp *sock,
     304             :   nr_transport_addr *to, int preallocated_connect_mode, nr_socket **ret_sock)
     305             :   {
     306             :     int r, _status;
     307             :     nr_tcp_socket_ctx *tcp_sock_ctx;
     308             :     nr_socket * nrsock;
     309             : 
     310           0 :     to->protocol=IPPROTO_TCP;
     311             : 
     312           0 :     TAILQ_FOREACH(tcp_sock_ctx, &sock->sockets, entry) {
     313           0 :       if (!nr_transport_addr_is_wildcard(&tcp_sock_ctx->remote_addr)) {
     314           0 :         if (!nr_transport_addr_cmp(to, &tcp_sock_ctx->remote_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
     315           0 :           *ret_sock=tcp_sock_ctx->inner;
     316           0 :           return(0);
     317             :         }
     318             :       }
     319             :     }
     320             : 
     321           0 :     tcp_sock_ctx=NULL;
     322             :     /* not connected yet */
     323           0 :     if (sock->tcp_type != TCP_TYPE_ACTIVE) {
     324           0 :       if (preallocated_connect_mode == PREALLOC_DONT_CONNECT_UNLESS_SO && sock->tcp_type != TCP_TYPE_SO)
     325           0 :         ABORT(R_FAILED);
     326             : 
     327             :       /* find free preallocated socket and connect */
     328           0 :       TAILQ_FOREACH(tcp_sock_ctx, &sock->sockets, entry) {
     329           0 :         if (nr_transport_addr_is_wildcard(&tcp_sock_ctx->remote_addr)) {
     330           0 :           if (preallocated_connect_mode == PREALLOC_CONNECT_NON_FRAMED && tcp_sock_ctx->is_framed)
     331           0 :             continue;
     332           0 :           if (preallocated_connect_mode != PREALLOC_CONNECT_NON_FRAMED && !tcp_sock_ctx->is_framed)
     333           0 :             continue;
     334             : 
     335           0 :           if ((r=nr_socket_connect(tcp_sock_ctx->inner, to))){
     336           0 :             if (r!=R_WOULDBLOCK)
     337           0 :                ABORT(r);
     338             :           }
     339             : 
     340           0 :           if ((r=nr_tcp_socket_ctx_initialize(tcp_sock_ctx, to, sock)))
     341           0 :             ABORT(r);
     342             : 
     343           0 :           *ret_sock=tcp_sock_ctx->inner;
     344             : 
     345           0 :           return(0);
     346             :         }
     347             :       }
     348           0 :       tcp_sock_ctx=NULL;
     349           0 :       ABORT(R_FAILED);
     350             :     }
     351             : 
     352             :     /* if active type - create new socket for each new remote addr */
     353           0 :     assert(sock->tcp_type == TCP_TYPE_ACTIVE);
     354             : 
     355           0 :     if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, &sock->addr, &nrsock)))
     356           0 :       ABORT(r);
     357             : 
     358             :     /* This takes ownership of nrsock whether it fails or not. */
     359           0 :     if ((r=nr_tcp_socket_ctx_create(nrsock, 1, sock->max_pending, &tcp_sock_ctx))){
     360           0 :       ABORT(r);
     361             :     }
     362             : 
     363           0 :     TAILQ_INSERT_TAIL(&sock->sockets, tcp_sock_ctx, entry);
     364             : 
     365           0 :     if ((r=nr_socket_connect(tcp_sock_ctx->inner, to))){
     366           0 :       if (r!=R_WOULDBLOCK)
     367           0 :         ABORT(r);
     368             :     }
     369             : 
     370           0 :     if ((r=nr_tcp_socket_ctx_initialize(tcp_sock_ctx, to, sock)))
     371           0 :       ABORT(r);
     372             : 
     373           0 :     *ret_sock=tcp_sock_ctx->inner;
     374           0 :     tcp_sock_ctx=NULL;
     375             : 
     376           0 :     _status=0;
     377             :   abort:
     378           0 :     if (_status) {
     379           0 :       if (tcp_sock_ctx) {
     380           0 :         r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s failed with error %d, tcp_sock_ctx remote_addr: %s",__FILE__,__LINE__,__FUNCTION__,_status, tcp_sock_ctx->remote_addr.as_string);
     381           0 :         TAILQ_REMOVE(&sock->sockets, tcp_sock_ctx, entry);
     382           0 :         nr_tcp_socket_ctx_destroy(&tcp_sock_ctx);
     383             :       } else {
     384           0 :         r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s failed with error %d, tcp_sock_ctx=NULL",__FILE__,__LINE__,__FUNCTION__,_status);
     385             :       }
     386             :     }
     387             : 
     388           0 :     return(_status);
     389             :   }
     390             : 
     391           0 : int nr_socket_multi_tcp_stun_server_connect(nr_socket *sock,
     392             :   nr_transport_addr *addr)
     393             :   {
     394             :     int r, _status;
     395           0 :     nr_socket_multi_tcp *mtcp_sock = (nr_socket_multi_tcp *)sock->obj;
     396             :     nr_socket *nrsock;
     397             : 
     398           0 :     assert(mtcp_sock->tcp_type != TCP_TYPE_ACTIVE);
     399           0 :     if (mtcp_sock->tcp_type == TCP_TYPE_ACTIVE)
     400           0 :       ABORT(R_INTERNAL);
     401             : 
     402           0 :     if ((r=nr_socket_multi_tcp_get_sock_connected_to(mtcp_sock,addr,PREALLOC_CONNECT_NON_FRAMED,&nrsock)))
     403           0 :       ABORT(r);
     404             : 
     405           0 :     _status=0;
     406             :   abort:
     407           0 :     if (_status)
     408           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
     409           0 :     return(_status);
     410             :   }
     411             : 
     412           0 : static int nr_socket_multi_tcp_destroy(void **objp)
     413             :   {
     414             :     nr_socket_multi_tcp *sock;
     415             :     nr_tcp_socket_ctx *tcpsock;
     416             :     NR_SOCKET fd;
     417             : 
     418           0 :     if (!objp || !*objp)
     419           0 :       return 0;
     420             : 
     421           0 :     sock=(nr_socket_multi_tcp *)*objp;
     422           0 :     *objp=0;
     423             : 
     424             :     /* Cancel waiting on the socket */
     425           0 :     if (sock->listen_socket && !nr_socket_getfd(sock->listen_socket, &fd)) {
     426           0 :       NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
     427             :     }
     428             : 
     429           0 :     nr_socket_destroy(&sock->listen_socket);
     430             : 
     431           0 :     while (!TAILQ_EMPTY(&sock->sockets)) {
     432             : 
     433           0 :       tcpsock = TAILQ_FIRST(&sock->sockets);
     434           0 :       TAILQ_REMOVE(&sock->sockets, tcpsock, entry);
     435             : 
     436           0 :       if (!nr_socket_getfd(tcpsock->inner, &fd)) {
     437           0 :         NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
     438             :       }
     439             : 
     440           0 :       nr_tcp_socket_ctx_destroy(&tcpsock);
     441             :     }
     442             : 
     443           0 :     RFREE(sock);
     444             : 
     445           0 :     return 0;
     446             :   }
     447             : 
     448           0 : static int nr_socket_multi_tcp_sendto(void *obj, const void *msg, size_t len,
     449             :   int flags, nr_transport_addr *to)
     450             :   {
     451             :     int r, _status;
     452           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     453             :     nr_socket *nrsock;
     454             : 
     455           0 :     if ((r=nr_socket_multi_tcp_get_sock_connected_to(sock, to,
     456             :       PREALLOC_DONT_CONNECT_UNLESS_SO, &nrsock)))
     457           0 :       ABORT(r);
     458             : 
     459           0 :     if((r=nr_socket_sendto(nrsock, msg, len, flags, to)))
     460           0 :       ABORT(r);
     461             : 
     462           0 :     _status=0;
     463             :   abort:
     464           0 :     if (_status)
     465           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(to:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,to->as_string,_status);
     466             : 
     467           0 :     return(_status);
     468             : }
     469             : 
     470           0 : static int nr_socket_multi_tcp_recvfrom(void *obj,void * restrict buf,
     471             :   size_t maxlen, size_t *len, int flags, nr_transport_addr *from)
     472             :   {
     473           0 :     int r, _status = 0;
     474           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     475             :     nr_tcp_socket_ctx *tcpsock;
     476             : 
     477           0 :     if (TAILQ_EMPTY(&sock->sockets))
     478           0 :       ABORT(R_FAILED);
     479             : 
     480           0 :     TAILQ_FOREACH(tcpsock, &sock->sockets, entry) {
     481           0 :       if (nr_transport_addr_is_wildcard(&tcpsock->remote_addr))
     482           0 :         continue;
     483           0 :       r=nr_socket_recvfrom(tcpsock->inner, buf, maxlen, len, flags, from);
     484           0 :       if (!r)
     485           0 :         return 0;
     486             : 
     487           0 :       if (r!=R_WOULDBLOCK) {
     488             :         NR_SOCKET fd;
     489           0 :         r_log(LOG_ICE,LOG_DEBUG,
     490             :               "%s:%d function %s(to:%s) failed with error %d",__FILE__,
     491           0 :               __LINE__,__FUNCTION__,tcpsock->remote_addr.as_string,r);
     492           0 :         if (!nr_socket_getfd(tcpsock->inner, &fd)) {
     493           0 :           NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
     494           0 :           NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
     495             :         }
     496             : 
     497           0 :         TAILQ_REMOVE(&sock->sockets, tcpsock, entry);
     498           0 :         nr_tcp_socket_ctx_destroy(&tcpsock);
     499           0 :         ABORT(r);
     500             :       }
     501             :     }
     502             : 
     503             :     /* this also gets returned if all tcpsocks have wildcard remote_addr */
     504           0 :     _status=R_WOULDBLOCK;
     505             :   abort:
     506             : 
     507           0 :     return(_status);
     508             :   }
     509             : 
     510           0 : static int nr_socket_multi_tcp_getaddr(void *obj, nr_transport_addr *addrp)
     511             :   {
     512           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     513             : 
     514           0 :     return nr_transport_addr_copy(addrp,&sock->addr);
     515             :   }
     516             : 
     517           0 : static int nr_socket_multi_tcp_close(void *obj)
     518             :   {
     519           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     520             :     nr_tcp_socket_ctx *tcpsock;
     521             : 
     522           0 :     if(sock->listen_socket)
     523           0 :       nr_socket_close(sock->listen_socket);
     524             : 
     525           0 :     TAILQ_FOREACH(tcpsock, &sock->sockets, entry) {
     526           0 :       nr_socket_close(tcpsock->inner); //ignore errors
     527             :     }
     528             : 
     529           0 :     return 0;
     530             :   }
     531             : 
     532           0 : static void nr_tcp_socket_readable_cb(NR_SOCKET s, int how, void *arg)
     533             :   {
     534           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)arg;
     535             : 
     536             :     // rearm
     537           0 :     NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, nr_tcp_socket_readable_cb, arg);
     538             : 
     539           0 :     if (sock->readable_cb)
     540           0 :       sock->readable_cb(s, how, sock->readable_cb_arg);
     541           0 :   }
     542             : 
     543           0 : static int nr_socket_multi_tcp_connect(void *obj, nr_transport_addr *addr)
     544             :   {
     545             :     int r, _status;
     546           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     547             :     nr_socket *nrsock;
     548             : 
     549           0 :     if ((r=nr_socket_multi_tcp_get_sock_connected_to(sock,addr,PREALLOC_CONNECT_FRAMED,&nrsock)))
     550           0 :       ABORT(r);
     551             : 
     552           0 :     _status=0;
     553             : abort:
     554           0 :     if (_status)
     555           0 :       r_log(LOG_ICE,LOG_DEBUG,"%s:%d function %s(addr:%s) failed with error %d",__FILE__,__LINE__,__FUNCTION__,addr->as_string,_status);
     556             : 
     557           0 :     return(_status);
     558             :   }
     559             : 
     560           0 : static void nr_tcp_multi_lsocket_readable_cb(NR_SOCKET s, int how, void *arg)
     561             :   {
     562           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)arg;
     563             :     nr_socket *newsock;
     564             :     nr_transport_addr remote_addr;
     565             :     nr_tcp_socket_ctx *tcp_sock_ctx;
     566             :     int r, _status;
     567             : 
     568             :     // rearm
     569           0 :     NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, nr_tcp_multi_lsocket_readable_cb, arg);
     570             : 
     571             :     /* accept */
     572           0 :     if ((r=nr_socket_accept(sock->listen_socket, &remote_addr, &newsock)))
     573           0 :       ABORT(r);
     574             : 
     575             :     /* This takes ownership of newsock whether it fails or not. */
     576           0 :     if ((r=nr_tcp_socket_ctx_create(newsock, 1, sock->max_pending, &tcp_sock_ctx)))
     577           0 :       ABORT(r);
     578             : 
     579           0 :     nr_socket_buffered_set_connected_to(tcp_sock_ctx->inner, &remote_addr);
     580             : 
     581           0 :     if ((r=nr_tcp_socket_ctx_initialize(tcp_sock_ctx, &remote_addr, sock))) {
     582           0 :       nr_tcp_socket_ctx_destroy(&tcp_sock_ctx);
     583           0 :       ABORT(r);
     584             :     }
     585             : 
     586           0 :     TAILQ_INSERT_HEAD(&sock->sockets, tcp_sock_ctx, entry);
     587             : 
     588           0 :     _status=0;
     589             : abort:
     590           0 :     if (_status) {
     591           0 :       r_log(LOG_ICE,LOG_WARNING,"%s:%d %s failed to accept new TCP connection: %d",__FILE__,__LINE__,__FUNCTION__,_status);
     592             :     } else {
     593           0 :       r_log(LOG_ICE,LOG_INFO,"%s:%d %s accepted new TCP connection from %s",__FILE__,__LINE__,__FUNCTION__,remote_addr.as_string);
     594             :     }
     595           0 :   }
     596             : 
     597           0 : static int nr_socket_multi_tcp_listen(void *obj, int backlog)
     598             :   {
     599             :     int r, _status;
     600           0 :     nr_socket_multi_tcp *sock=(nr_socket_multi_tcp *)obj;
     601             :     NR_SOCKET fd;
     602             : 
     603           0 :     if(!sock->listen_socket)
     604           0 :       ABORT(R_FAILED);
     605             : 
     606           0 :     if ((r=nr_socket_listen(sock->listen_socket, backlog)))
     607           0 :       ABORT(r);
     608             : 
     609           0 :     if ((r=nr_socket_getfd(sock->listen_socket, &fd)))
     610           0 :       ABORT(r);
     611             : 
     612           0 :     NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, nr_tcp_multi_lsocket_readable_cb, sock);
     613             : 
     614           0 :     _status=0;
     615             :   abort:
     616           0 :     if (_status)
     617           0 :       r_log(LOG_ICE,LOG_WARNING,"%s:%d function %s failed with error %d",__FILE__,__LINE__,__FUNCTION__,_status);
     618             : 
     619           0 :     return(_status);
     620             :   }

Generated by: LCOV version 1.13