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 : }
|