1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 Copyright (c) 2013, Mozilla
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 * Neither the name of Adobe Systems, Network Resonance, Mozilla nor
19 the names of its contributors may be used to endorse or promote
20 products derived from this software without specific prior written
21 permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #ifdef USE_TURN
37
38 #include <assert.h>
39 #include <string.h>
40
41 #include "nr_api.h"
42 #include "r_time.h"
43 #include "async_timer.h"
44 #include "nr_socket_buffered_stun.h"
45 #include "stun.h"
46 #include "turn_client_ctx.h"
47 #include "ice_ctx.h"
48
49 int NR_LOG_TURN = 0;
50
51 #define TURN_MAX_PENDING_BYTES 32000
52
53 #define TURN_RTO 100 /* Hardcoded RTO estimate */
54 #define TURN_LIFETIME_REQUEST_SECONDS 3600 /* One hour */
55 #define TURN_USECS_PER_S 1000000
56 #define TURN_REFRESH_SLACK_SECONDS 10 /* How long before expiry to refresh
57 allocations/permissions. The RFC 5766
58 Section 7 recommendation if 60 seconds,
59 but this is silly since the transaction
60 times out after about 5. */
61 #define TURN_PERMISSION_LIFETIME_SECONDS 300 /* 5 minutes. From RFC 5766 2.3 */
62
63 // Set to enable a temporary fix that will run the TURN reservation keep-alive
64 // logic when data is received via a TURN relayed path: a DATA_INDICATION packet is received.
65 // TODO(pkerr@mozilla.com) This should be replace/removed when bug 935806 is implemented.
66 #define REFRESH_RESERVATION_ON_RECV 1
67
68 static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int type,
69 NR_async_cb success_cb,
70 NR_async_cb failure_cb,
71 nr_turn_stun_ctx **ctxp);
72 static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp);
73 static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg);
74 static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
75 char *realm, char *nonce);
76 static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg);
77 static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
78 nr_turn_stun_ctx **sctx);
79 static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *ctx,
80 nr_turn_stun_ctx *sctx,
81 UINT4 lifetime);
82 static int nr_turn_permission_create(nr_turn_client_ctx *ctx,
83 const nr_transport_addr *addr,
84 nr_turn_permission **permp);
85 static int nr_turn_permission_find(nr_turn_client_ctx *ctx,
86 const nr_transport_addr *addr,
87 nr_turn_permission **permp);
88 static int nr_turn_permission_destroy(nr_turn_permission **permp);
89 static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg);
90 static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *cb);
91 static int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
92 nr_stun_message *req,
93 int flags);
94
nr_transport_addr_listnode_create(const nr_transport_addr * addr,nr_transport_addr_listnode ** listnodep)95 int nr_transport_addr_listnode_create(const nr_transport_addr *addr, nr_transport_addr_listnode **listnodep)
96 {
97 nr_transport_addr_listnode *listnode = 0;
98 int r,_status;
99
100 if (!(listnode=RCALLOC(sizeof(nr_transport_addr_listnode)))) {
101 ABORT(R_NO_MEMORY);
102 }
103
104 if ((r = nr_transport_addr_copy(&listnode->value, addr))) {
105 ABORT(r);
106 }
107
108 *listnodep = listnode;
109 listnode = 0;
110 _status = 0;
111
112 abort:
113 nr_transport_addr_listnode_destroy(&listnode);
114 return(_status);
115 }
116
nr_transport_addr_listnode_destroy(nr_transport_addr_listnode ** listnode)117 void nr_transport_addr_listnode_destroy(nr_transport_addr_listnode **listnode)
118 {
119 RFREE(*listnode);
120 *listnode = 0;
121 }
122
123 /* nr_turn_stun_ctx functions */
nr_turn_stun_ctx_create(nr_turn_client_ctx * tctx,int mode,NR_async_cb success_cb,NR_async_cb error_cb,nr_turn_stun_ctx ** ctxp)124 static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int mode,
125 NR_async_cb success_cb,
126 NR_async_cb error_cb,
127 nr_turn_stun_ctx **ctxp)
128 {
129 nr_turn_stun_ctx *sctx = 0;
130 int r,_status;
131 char label[256];
132
133 if (!(sctx=RCALLOC(sizeof(nr_turn_stun_ctx))))
134 ABORT(R_NO_MEMORY);
135
136 /* TODO(ekr@rtfm.com): label by phase */
137 snprintf(label, sizeof(label), "%s:%s", tctx->label, ":TURN");
138
139 if ((r=nr_stun_client_ctx_create(label, tctx->sock, &tctx->turn_server_addr,
140 TURN_RTO, &sctx->stun))) {
141 ABORT(r);
142 }
143
144 /* Set the STUN auth parameters, but don't set authentication on.
145 For that we need the nonce, set in nr_turn_stun_set_auth_params.
146 */
147 sctx->stun->auth_params.username=tctx->username;
148 INIT_DATA(sctx->stun->auth_params.password,
149 tctx->password->data, tctx->password->len);
150
151 sctx->tctx=tctx;
152 sctx->success_cb=success_cb;
153 sctx->error_cb=error_cb;
154 sctx->mode=mode;
155 sctx->last_error_code=0;
156 STAILQ_INIT(&sctx->addresses_tried);
157
158 /* Add ourselves to the tctx's list */
159 STAILQ_INSERT_TAIL(&tctx->stun_ctxs, sctx, entry);
160 *ctxp=sctx;
161
162 _status=0;
163 abort:
164 if (_status) {
165 nr_turn_stun_ctx_destroy(&sctx);
166 }
167 return(_status);
168 }
169
170 /* Note: this function does not pull us off the tctx's list. */
nr_turn_stun_ctx_destroy(nr_turn_stun_ctx ** ctxp)171 static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp)
172 {
173 nr_turn_stun_ctx *ctx;
174
175 if (!ctxp || !*ctxp)
176 return 0;
177
178 ctx = *ctxp;
179 *ctxp = 0;
180
181 nr_stun_client_ctx_destroy(&ctx->stun);
182 RFREE(ctx->realm);
183 RFREE(ctx->nonce);
184
185 while (!STAILQ_EMPTY(&ctx->addresses_tried)) {
186 nr_transport_addr_listnode *listnode = STAILQ_FIRST(&ctx->addresses_tried);
187 STAILQ_REMOVE_HEAD(&ctx->addresses_tried, entry);
188 nr_transport_addr_listnode_destroy(&listnode);
189 }
190
191 RFREE(ctx);
192
193 return 0;
194 }
195
nr_turn_stun_set_auth_params(nr_turn_stun_ctx * ctx,char * realm,char * nonce)196 static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
197 char *realm, char *nonce)
198 {
199 int _status;
200
201 RFREE(ctx->realm);
202 RFREE(ctx->nonce);
203
204 assert(realm);
205 if (!realm)
206 ABORT(R_BAD_ARGS);
207 ctx->realm=r_strdup(realm);
208 if (!ctx->realm)
209 ABORT(R_NO_MEMORY);
210
211 assert(nonce);
212 if (!nonce)
213 ABORT(R_BAD_ARGS);
214 ctx->nonce=r_strdup(nonce);
215 if (!ctx->nonce)
216 ABORT(R_NO_MEMORY);
217
218 RFREE(ctx->stun->realm);
219 ctx->stun->realm = r_strdup(ctx->realm);
220 if (!ctx->stun->realm)
221 ABORT(R_NO_MEMORY);
222
223 ctx->stun->auth_params.realm = ctx->realm;
224 ctx->stun->auth_params.nonce = ctx->nonce;
225 ctx->stun->auth_params.authenticate = 1; /* May already be 1 */
226
227 _status=0;
228 abort:
229 return(_status);
230 }
231
nr_turn_stun_ctx_start(nr_turn_stun_ctx * ctx)232 static int nr_turn_stun_ctx_start(nr_turn_stun_ctx *ctx)
233 {
234 int r, _status;
235 nr_turn_client_ctx *tctx = ctx->tctx;
236 nr_transport_addr_listnode *address_tried = 0;
237
238 if ((r=nr_stun_client_reset(ctx->stun))) {
239 r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't reset STUN",
240 tctx->label);
241 ABORT(r);
242 }
243
244 if ((r=nr_stun_client_start(ctx->stun, ctx->mode, nr_turn_stun_ctx_cb, ctx))) {
245 r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN",
246 tctx->label);
247 ABORT(r);
248 }
249
250 if ((r=nr_transport_addr_listnode_create(&ctx->stun->peer_addr, &address_tried))) {
251 ABORT(r);
252 }
253
254 STAILQ_INSERT_TAIL(&ctx->addresses_tried, address_tried, entry);
255
256 _status=0;
257 abort:
258 return _status;
259 }
260
nr_turn_stun_ctx_handle_redirect(nr_turn_stun_ctx * ctx)261 static int nr_turn_stun_ctx_handle_redirect(nr_turn_stun_ctx *ctx)
262 {
263 int r, _status;
264 nr_turn_client_ctx *tctx = ctx->tctx;
265 nr_stun_message_attribute *ec;
266 nr_stun_message_attribute *attr;
267 nr_transport_addr *alternate_addr = 0;
268 int index = 0;
269
270 if (!tctx->ctx) {
271 /* If we were to require TCP nr_sockets to allow multiple connect calls by
272 * disconnecting and re-connecting, we could avoid this requirement. */
273 r_log(NR_LOG_TURN, LOG_ERR,
274 "TURN(%s): nr_turn_stun_ctx_handle_redirect is not supported when "
275 "there is no ICE ctx, and by extension no socket factory, since we "
276 "need that to create new sockets in the TCP case",
277 tctx->label);
278 ABORT(R_BAD_ARGS);
279 }
280
281 if (ctx->stun->response->header.type != NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE) {
282 r_log(NR_LOG_TURN, LOG_ERR,
283 "TURN(%s): nr_turn_stun_ctx_handle_redirect called for something "
284 "other than an Allocate error response (type=%d)",
285 tctx->label, ctx->stun->response->header.type);
286 ABORT(R_BAD_ARGS);
287 }
288
289 if (!nr_stun_message_has_attribute(ctx->stun->response,
290 NR_STUN_ATTR_ERROR_CODE, &ec) ||
291 (ec->u.error_code.number != 300)) {
292 r_log(NR_LOG_TURN, LOG_ERR,
293 "TURN(%s): nr_turn_stun_ctx_handle_redirect called without a "
294 "300 response",
295 tctx->label);
296 ABORT(R_BAD_ARGS);
297 }
298
299 while (!alternate_addr && !nr_stun_message_get_attribute(
300 ctx->stun->response, NR_STUN_ATTR_ALTERNATE_SERVER, index++, &attr)) {
301 alternate_addr = &attr->u.alternate_server;
302
303 // TODO: Someday we may need to handle IP version switching, but it is
304 // unclear how that is supposed to work with ICE when the IP version of
305 // the candidate's base address is fixed...
306 if (alternate_addr->ip_version != tctx->turn_server_addr.ip_version) {
307 r_log(NR_LOG_TURN, LOG_INFO,
308 "TURN(%s): nr_turn_stun_ctx_handle_redirect not trying %s, since it is a different IP version",
309 tctx->label, alternate_addr->as_string);
310 alternate_addr = 0;
311 continue;
312 }
313
314 /* Check if we've already tried this, and ignore if we have */
315 nr_transport_addr_listnode *address_tried = 0;
316 STAILQ_FOREACH(address_tried, &ctx->addresses_tried, entry) {
317 /* Ignore protocol */
318 alternate_addr->protocol = address_tried->value.protocol;
319 if (!nr_transport_addr_cmp(alternate_addr, &address_tried->value, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
320 r_log(NR_LOG_TURN, LOG_INFO,
321 "TURN(%s): nr_turn_stun_ctx_handle_redirect already tried %s, ignoring",
322 tctx->label, alternate_addr->as_string);
323 alternate_addr = 0;
324 break;
325 }
326 }
327 }
328
329 if (!alternate_addr) {
330 /* Should we use a different error code depending on why we didn't find
331 * one? (eg; no ALTERNATE-SERVERS at all, none that we have not tried
332 * already, none that are of a compatible IP version?) */
333 r_log(NR_LOG_TURN, LOG_ERR,
334 "TURN(%s): nr_turn_stun_ctx_handle_redirect did not find a viable "
335 "ALTERNATE-SERVER",
336 tctx->label);
337 ABORT(R_FAILED);
338 }
339
340 r_log(NR_LOG_TURN, LOG_INFO,
341 "TURN(%s): nr_turn_stun_ctx_handle_redirect trying %s",
342 tctx->label, alternate_addr->as_string);
343
344 /* This also handles the call to nr_transport_addr_fmt_addr_string */
345 if ((r = nr_transport_addr_copy_addrport(&tctx->turn_server_addr,
346 alternate_addr))) {
347 r_log(NR_LOG_TURN, LOG_ERR,
348 "TURN(%s): nr_turn_stun_ctx_handle_redirect copying ALTERNATE-SERVER "
349 "failed(%d)!",
350 tctx->label, r);
351 assert(0);
352 ABORT(r);
353 }
354
355 /* TURN server address is now updated. Restart the STUN Allocate ctx. Note
356 * that we do not attempt to update the local address; if the TURN server
357 * redirects to something that is not best reached from the already-selected
358 * local address, oh well. */
359
360 if (tctx->turn_server_addr.protocol == IPPROTO_TCP) {
361 /* For TCP, we need to replace the underlying nr_socket, since we cannot
362 * un-connect it from the old server. */
363 /* If we were to require TCP nr_sockets to allow multiple connect calls by
364 * disconnecting and re-connecting, we could avoid this stuff, and just
365 * call nr_socket_connect. */
366 nr_transport_addr old_local_addr;
367 nr_socket* new_socket;
368 if ((r = nr_socket_getaddr(tctx->sock, &old_local_addr))) {
369 r_log(NR_LOG_TURN, LOG_ERR,
370 "TURN(%s): nr_turn_stun_ctx_handle_redirect "
371 "failed to get old local address (%d)!",
372 tctx->label, r);
373 assert(0);
374 ABORT(r);
375 }
376
377 if ((r = nr_socket_factory_create_socket(tctx->ctx->socket_factory,
378 &old_local_addr, &new_socket))) {
379 r_log(NR_LOG_TURN, LOG_ERR,
380 "TURN(%s): nr_turn_stun_ctx_handle_redirect "
381 "failed to create new raw TCP socket for redirect (%d)!",
382 tctx->label, r);
383 assert(0);
384 ABORT(r);
385 }
386
387 if ((r = nr_socket_buffered_stun_reset(tctx->sock, new_socket))) {
388 /* nr_socket_buffered_stun_reset always takes ownership of |new_socket| */
389 r_log(NR_LOG_TURN, LOG_ERR,
390 "TURN(%s): nr_turn_stun_ctx_handle_redirect "
391 "failed to update raw TCP socket (%d)!",
392 tctx->label, r);
393 assert(0);
394 ABORT(r);
395 }
396
397 if ((r = nr_socket_connect(tctx->sock, &tctx->turn_server_addr))) {
398 if (r != R_WOULDBLOCK) {
399 r_log(NR_LOG_TURN, LOG_ERR,
400 "TURN(%s): nr_turn_stun_ctx_handle_redirect nr_socket_connect "
401 "failed(%d)!",
402 tctx->label, r);
403 assert(0);
404 ABORT(r);
405 }
406 }
407 }
408
409 nr_transport_addr_copy(&ctx->stun->peer_addr, &tctx->turn_server_addr);
410
411 if ((r = nr_turn_stun_ctx_start(ctx))) {
412 r_log(NR_LOG_TURN, LOG_ERR,
413 "TURN(%s): nr_turn_stun_ctx_handle_redirect nr_turn_stun_ctx_start "
414 "failed(%d)!",
415 tctx->label, r);
416 assert(0);
417 ABORT(r);
418 }
419
420 _status = 0;
421 abort:
422 return _status;
423 }
424
nr_turn_stun_ctx_cb(NR_SOCKET s,int how,void * arg)425 static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg)
426 {
427 int r, _status;
428 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
429
430 ctx->last_error_code = ctx->stun->error_code;
431
432 switch (ctx->stun->state) {
433 case NR_STUN_CLIENT_STATE_DONE:
434 /* Save the realm and nonce */
435 if (ctx->stun->realm && (!ctx->tctx->realm || strcmp(ctx->stun->realm,
436 ctx->tctx->realm))) {
437 RFREE(ctx->tctx->realm);
438 ctx->tctx->realm = r_strdup(ctx->stun->realm);
439 if (!ctx->tctx->realm)
440 ABORT(R_NO_MEMORY);
441 }
442 if (ctx->stun->nonce && (!ctx->tctx->nonce || strcmp(ctx->stun->nonce,
443 ctx->tctx->nonce))) {
444 RFREE(ctx->tctx->nonce);
445 ctx->tctx->nonce = r_strdup(ctx->stun->nonce);
446 if (!ctx->tctx->nonce)
447 ABORT(R_NO_MEMORY);
448 }
449
450 ctx->retry_ct=0;
451 ctx->success_cb(0, 0, ctx);
452 break;
453
454 case NR_STUN_CLIENT_STATE_FAILED:
455 /* Special case: if this is an authentication error,
456 we retry once. This allows the 401/438 nonce retry
457 paradigm. After that, we fail */
458 /* TODO(ekr@rtfm.com): 401 needs a #define */
459 /* TODO(ekr@rtfm.com): Add alternate-server (Mozilla bug 857688) */
460 if (ctx->stun->error_code == 438) {
461 // track 438s for ice telemetry
462 nr_accumulate_count(&(ctx->tctx->cnt_438s), 1);
463 }
464 if (ctx->stun->error_code == 401 || ctx->stun->error_code == 438) {
465 if (ctx->retry_ct > 0) {
466 if (ctx->stun->error_code == 401) {
467 // track 401s for ice telemetry
468 nr_accumulate_count(&(ctx->tctx->cnt_401s), 1);
469 }
470 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Exceeded the number of retries", ctx->tctx->label);
471 ABORT(R_FAILED);
472 }
473
474 if (!ctx->stun->nonce) {
475 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no nonce", ctx->tctx->label);
476 ABORT(R_FAILED);
477 }
478 if (!ctx->stun->realm) {
479 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no realm", ctx->tctx->label);
480 ABORT(R_FAILED);
481 }
482
483 /* Try to retry */
484 if ((r=nr_turn_stun_set_auth_params(ctx, ctx->stun->realm,
485 ctx->stun->nonce)))
486 ABORT(r);
487
488 ctx->stun->error_code = 0; /* Reset to avoid inf-looping */
489
490 if ((r=nr_turn_stun_ctx_start(ctx))) {
491 r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN", ctx->tctx->label);
492 ABORT(r);
493 }
494
495 ctx->retry_ct++;
496 } else if (ctx->stun->error_code == 300) {
497 r_log(NR_LOG_TURN, LOG_INFO,
498 "TURN(%s): Redirect received, restarting TURN", ctx->tctx->label);
499 /* We don't limit this with a retry counter, we limit redirects by
500 * checking whether we've tried the ALTERNATE-SERVER yet. */
501 ctx->retry_ct = 0;
502 if ((r = nr_turn_stun_ctx_handle_redirect(ctx))) {
503 ABORT(r);
504 }
505 } else {
506 ABORT(R_FAILED);
507 }
508 break;
509
510 case NR_STUN_CLIENT_STATE_TIMED_OUT:
511 ABORT(R_FAILED);
512 break;
513
514 case NR_STUN_CLIENT_STATE_CANCELLED:
515 assert(0); /* Shouldn't happen */
516 return;
517 break;
518
519 default:
520 assert(0); /* Shouldn't happen */
521 return;
522 }
523
524 _status=0;
525 abort:
526 if (_status) {
527 ctx->error_cb(0, 0, ctx);
528 }
529 }
530
531 /* nr_turn_client_ctx functions */
nr_turn_client_ctx_create(const char * label,nr_socket * sock,const char * username,Data * password,nr_transport_addr * addr,nr_ice_ctx * ice_ctx,nr_turn_client_ctx ** ctxp)532 int nr_turn_client_ctx_create(const char* label, nr_socket* sock,
533 const char* username, Data* password,
534 nr_transport_addr* addr, nr_ice_ctx* ice_ctx,
535 nr_turn_client_ctx** ctxp) {
536 nr_turn_client_ctx *ctx=0;
537 int r,_status;
538
539 if ((r=r_log_register("turn", &NR_LOG_TURN)))
540 ABORT(r);
541
542 if(!(ctx=RCALLOC(sizeof(nr_turn_client_ctx))))
543 ABORT(R_NO_MEMORY);
544
545 STAILQ_INIT(&ctx->stun_ctxs);
546 STAILQ_INIT(&ctx->permissions);
547
548 if(!(ctx->label=r_strdup(label)))
549 ABORT(R_NO_MEMORY);
550
551 ctx->sock=sock;
552 ctx->username = r_strdup(username);
553 if (!ctx->username)
554 ABORT(R_NO_MEMORY);
555
556 if ((r=r_data_create(&ctx->password, password->data, password->len)))
557 ABORT(r);
558 if ((r=nr_transport_addr_copy(&ctx->turn_server_addr, addr)))
559 ABORT(r);
560
561 ctx->state = NR_TURN_CLIENT_STATE_INITTED;
562 if (addr->protocol == IPPROTO_TCP) {
563 if ((r=nr_socket_connect(ctx->sock, &ctx->turn_server_addr))) {
564 if (r != R_WOULDBLOCK)
565 ABORT(r);
566 }
567 }
568
569 ctx->ctx = ice_ctx;
570
571 *ctxp=ctx;
572
573 _status=0;
574 abort:
575 if(_status){
576 nr_turn_client_ctx_destroy(&ctx);
577 }
578 return(_status);
579 }
580
581 int
nr_turn_client_ctx_destroy(nr_turn_client_ctx ** ctxp)582 nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
583 {
584 nr_turn_client_ctx *ctx;
585
586 if(!ctxp || !*ctxp)
587 return(0);
588
589 ctx=*ctxp;
590 *ctxp = 0;
591
592 if (ctx->label)
593 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): destroy", ctx->label);
594
595 nr_turn_client_deallocate(ctx);
596
597 /* Cancel frees the rest of our data */
598 RFREE(ctx->label);
599 ctx->label = 0;
600
601 nr_turn_client_cancel(ctx);
602
603 RFREE(ctx->username);
604 ctx->username = 0;
605 r_data_destroy(&ctx->password);
606 RFREE(ctx->nonce);
607 ctx->nonce = 0;
608 RFREE(ctx->realm);
609 ctx->realm = 0;
610
611 /* Destroy the STUN client ctxs */
612 while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
613 nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
614 STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
615 nr_turn_stun_ctx_destroy(&stun);
616 }
617
618 /* Destroy the permissions */
619 while (!STAILQ_EMPTY(&ctx->permissions)) {
620 nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
621 STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
622 nr_turn_permission_destroy(&perm);
623 }
624
625 RFREE(ctx);
626
627 return(0);
628 }
629
nr_turn_client_cancel(nr_turn_client_ctx * ctx)630 int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
631 {
632 nr_turn_stun_ctx *stun = 0;
633
634 if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
635 ctx->state == NR_TURN_CLIENT_STATE_FAILED)
636 return(0);
637
638 if (ctx->label)
639 r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): cancelling", ctx->label);
640
641 /* Cancel the STUN client ctxs */
642 stun = STAILQ_FIRST(&ctx->stun_ctxs);
643 while (stun) {
644 nr_stun_client_cancel(stun->stun);
645 stun = STAILQ_NEXT(stun, entry);
646 }
647
648 /* Cancel the timers, if not already cancelled */
649 NR_async_timer_cancel(ctx->connected_timer_handle);
650 NR_async_timer_cancel(ctx->refresh_timer_handle);
651
652 ctx->state = NR_TURN_CLIENT_STATE_CANCELLED;
653
654 return(0);
655 }
656
nr_turn_client_send_stun_request(nr_turn_client_ctx * ctx,nr_stun_message * req,int flags)657 int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
658 nr_stun_message *req,
659 int flags)
660 {
661 int r,_status;
662
663 if ((r=nr_stun_encode_message(req)))
664 ABORT(r);
665
666 if ((r=nr_socket_sendto(ctx->sock,
667 req->buffer, req->length, flags,
668 &ctx->turn_server_addr))) {
669 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Failed sending request",
670 ctx->label);
671 ABORT(r);
672 }
673
674 _status=0;
675 abort:
676 return(_status);
677 }
678
nr_turn_client_deallocate(nr_turn_client_ctx * ctx)679 int nr_turn_client_deallocate(nr_turn_client_ctx *ctx)
680 {
681 int r,_status;
682 nr_stun_message *aloc = 0;
683 nr_stun_client_auth_params auth;
684 nr_stun_client_refresh_request_params refresh;
685
686 if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
687 return(0);
688
689 r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): deallocating", ctx->label);
690
691 refresh.lifetime_secs = 0;
692
693 auth.username = ctx->username;
694 INIT_DATA(auth.password, ctx->password->data, ctx->password->len);
695
696 auth.realm = ctx->realm;
697 auth.nonce = ctx->nonce;
698
699 auth.authenticate = 1;
700
701 if ((r=nr_stun_build_refresh_request(&auth, &refresh, &aloc)))
702 ABORT(r);
703
704 // We are only sending a single request here because we are in the process of
705 // shutting everything down. Theoretically we should probably start a seperate
706 // STUN transaction which outlives the TURN context.
707 if ((r=nr_turn_client_send_stun_request(ctx, aloc, 0)))
708 ABORT(r);
709
710 ctx->state = NR_TURN_CLIENT_STATE_DEALLOCATING;
711
712 _status=0;
713 abort:
714 nr_stun_message_destroy(&aloc);
715 return(_status);
716 }
717
nr_turn_client_fire_finished_cb(nr_turn_client_ctx * ctx)718 static void nr_turn_client_fire_finished_cb(nr_turn_client_ctx *ctx)
719 {
720 if (ctx->finished_cb) {
721 NR_async_cb finished_cb=ctx->finished_cb;
722 ctx->finished_cb=0;
723 finished_cb(0, 0, ctx->cb_arg);
724 }
725 }
726
nr_turn_client_failed(nr_turn_client_ctx * ctx)727 int nr_turn_client_failed(nr_turn_client_ctx *ctx)
728 {
729 if (ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
730 ctx->state == NR_TURN_CLIENT_STATE_CANCELLED)
731 return(0);
732
733 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s) failed", ctx->label);
734 nr_turn_client_cancel(ctx);
735 ctx->state = NR_TURN_CLIENT_STATE_FAILED;
736 nr_turn_client_fire_finished_cb(ctx);
737
738 return(0);
739 }
740
nr_turn_client_get_relayed_address(nr_turn_client_ctx * ctx,nr_transport_addr * relayed_address)741 int nr_turn_client_get_relayed_address(nr_turn_client_ctx *ctx,
742 nr_transport_addr *relayed_address)
743 {
744 int r, _status;
745
746 if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
747 ABORT(R_FAILED);
748
749 if (r=nr_transport_addr_copy(relayed_address, &ctx->relay_addr))
750 ABORT(r);
751
752 _status=0;
753 abort:
754 return(_status);
755 }
756
nr_turn_client_get_mapped_address(nr_turn_client_ctx * ctx,nr_transport_addr * mapped_address)757 int nr_turn_client_get_mapped_address(nr_turn_client_ctx *ctx,
758 nr_transport_addr *mapped_address)
759 {
760 int r, _status;
761
762 if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
763 ABORT(R_FAILED);
764
765 if (r=nr_transport_addr_copy(mapped_address, &ctx->mapped_addr))
766 ABORT(r);
767
768 _status=0;
769 abort:
770 return(_status);
771 }
772
nr_turn_client_allocate_cb(NR_SOCKET s,int how,void * arg)773 static void nr_turn_client_allocate_cb(NR_SOCKET s, int how, void *arg)
774 {
775 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
776 nr_turn_stun_ctx *refresh_ctx;
777 int r,_status;
778
779 ctx->tctx->state = NR_TURN_CLIENT_STATE_ALLOCATED;
780
781 if ((r=nr_transport_addr_copy(
782 &ctx->tctx->relay_addr,
783 &ctx->stun->results.allocate_response.relay_addr)))
784 ABORT(r);
785
786 if ((r=nr_transport_addr_copy(
787 &ctx->tctx->mapped_addr,
788 &ctx->stun->results.allocate_response.mapped_addr)))
789 ABORT(r);
790
791 if ((r=nr_turn_client_refresh_setup(ctx->tctx, &refresh_ctx)))
792 ABORT(r);
793
794 if ((r=nr_turn_client_start_refresh_timer(
795 ctx->tctx, refresh_ctx,
796 ctx->stun->results.allocate_response.lifetime_secs)))
797 ABORT(r);
798
799 r_log(NR_LOG_TURN, LOG_INFO,
800 "TURN(%s): Succesfully allocated addr %s lifetime=%u",
801 ctx->tctx->label,
802 ctx->tctx->relay_addr.as_string,
803 ctx->stun->results.allocate_response.lifetime_secs);
804
805 nr_turn_client_fire_finished_cb(ctx->tctx);
806 _status=0;
807 abort:
808 if (_status) {
809 nr_turn_client_failed(ctx->tctx);
810 }
811 }
812
nr_turn_client_error_cb(NR_SOCKET s,int how,void * arg)813 static void nr_turn_client_error_cb(NR_SOCKET s, int how, void *arg)
814 {
815 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
816
817 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, %s",
818 ctx->tctx->label, ctx->mode, __FUNCTION__);
819
820 nr_turn_client_failed(ctx->tctx);
821 }
822
nr_turn_client_permission_error_cb(NR_SOCKET s,int how,void * arg)823 static void nr_turn_client_permission_error_cb(NR_SOCKET s, int how, void *arg)
824 {
825 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
826
827 if (ctx->last_error_code == 403) {
828 // track 403s for ice telemetry
829 nr_accumulate_count(&(ctx->tctx->cnt_403s), 1);
830 r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, permission denied",
831 ctx->tctx->label, ctx->mode);
832
833 } else{
834 nr_turn_client_error_cb(0, 0, ctx);
835 }
836 }
837
nr_turn_client_allocate(nr_turn_client_ctx * ctx,NR_async_cb finished_cb,void * cb_arg)838 int nr_turn_client_allocate(nr_turn_client_ctx *ctx,
839 NR_async_cb finished_cb, void *cb_arg)
840 {
841 nr_turn_stun_ctx *stun = 0;
842 int r,_status;
843
844 if(ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
845 ctx->state == NR_TURN_CLIENT_STATE_CANCELLED){
846 /* TURN TCP contexts can fail before we ever try to form an allocation,
847 * since the TCP connection can fail. It is also conceivable that a TURN
848 * TCP context could be cancelled before we are done forming all
849 * allocations (although we do not do this at the time this code was
850 * written) */
851 assert(ctx->turn_server_addr.protocol == IPPROTO_TCP);
852 ABORT(R_NOT_FOUND);
853 }
854
855 assert(ctx->state == NR_TURN_CLIENT_STATE_INITTED);
856
857 ctx->finished_cb=finished_cb;
858 ctx->cb_arg=cb_arg;
859
860 if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST,
861 nr_turn_client_allocate_cb,
862 nr_turn_client_error_cb,
863 &stun)))
864 ABORT(r);
865 stun->stun->params.allocate_request.lifetime_secs =
866 TURN_LIFETIME_REQUEST_SECONDS;
867
868 if (ctx->state == NR_TURN_CLIENT_STATE_INITTED) {
869 if ((r=nr_turn_stun_ctx_start(stun)))
870 ABORT(r);
871 ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING;
872 } else {
873 ABORT(R_ALREADY);
874 }
875
876 _status=0;
877 abort:
878 if (_status) {
879 nr_turn_client_failed(ctx);
880 }
881
882 return(_status);
883 }
884
nr_turn_client_process_response(nr_turn_client_ctx * ctx,UCHAR * msg,int len,nr_transport_addr * turn_server_addr)885 int nr_turn_client_process_response(nr_turn_client_ctx *ctx,
886 UCHAR *msg, int len,
887 nr_transport_addr *turn_server_addr)
888 {
889 int r, _status;
890 nr_turn_stun_ctx *sc1;
891
892 switch (ctx->state) {
893 case NR_TURN_CLIENT_STATE_ALLOCATING:
894 case NR_TURN_CLIENT_STATE_ALLOCATED:
895 break;
896 default:
897 ABORT(R_FAILED);
898 }
899
900 sc1 = STAILQ_FIRST(&ctx->stun_ctxs);
901 while (sc1) {
902 r = nr_stun_client_process_response(sc1->stun, msg, len, turn_server_addr);
903 if (!r)
904 break;
905 if (r==R_RETRY) /* Likely a 401 and we will retry */
906 break;
907 if (r != R_REJECTED)
908 ABORT(r);
909 sc1 = STAILQ_NEXT(sc1, entry);
910 }
911 if (!sc1)
912 ABORT(R_REJECTED);
913
914 _status=0;
915 abort:
916 return(_status);
917 }
918
nr_turn_client_refresh_setup(nr_turn_client_ctx * ctx,nr_turn_stun_ctx ** sctx)919 static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
920 nr_turn_stun_ctx **sctx)
921 {
922 nr_turn_stun_ctx *stun = 0;
923 int r,_status;
924
925 assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
926 if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
927 ABORT(R_NOT_PERMITTED);
928
929 if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_REFRESH_REQUEST,
930 nr_turn_client_refresh_cb,
931 nr_turn_client_error_cb,
932 &stun)))
933 ABORT(r);
934
935 if ((r=nr_turn_stun_set_auth_params(stun, ctx->realm, ctx->nonce)))
936 ABORT(r);
937
938 stun->stun->params.refresh_request.lifetime_secs =
939 TURN_LIFETIME_REQUEST_SECONDS;
940
941
942 *sctx=stun;
943
944 _status=0;
945 abort:
946 return(_status);
947 }
948
nr_turn_client_start_refresh_timer(nr_turn_client_ctx * tctx,nr_turn_stun_ctx * sctx,UINT4 lifetime)949 static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *tctx,
950 nr_turn_stun_ctx *sctx,
951 UINT4 lifetime)
952 {
953 int _status;
954
955 assert(!tctx->refresh_timer_handle);
956
957 if (lifetime <= TURN_REFRESH_SLACK_SECONDS) {
958 r_log(NR_LOG_TURN, LOG_ERR, "Too short lifetime specified for turn %u", lifetime);
959 ABORT(R_BAD_DATA);
960 }
961
962 if (lifetime > 3600)
963 lifetime = 3600;
964
965 lifetime -= TURN_REFRESH_SLACK_SECONDS;
966
967 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Setting refresh timer for %u seconds",
968 tctx->label, lifetime);
969 NR_ASYNC_TIMER_SET(lifetime * 1000, nr_turn_client_refresh_timer_cb, sctx,
970 &tctx->refresh_timer_handle);
971
972 _status=0;
973 abort:
974 if (_status) {
975 nr_turn_client_failed(tctx);
976 }
977 return _status;
978 }
979
nr_turn_client_refresh_timer_cb(NR_SOCKET s,int how,void * arg)980 static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg)
981 {
982 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
983 int r,_status;
984
985 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh timer fired",
986 ctx->tctx->label);
987
988 ctx->tctx->refresh_timer_handle=0;
989 if ((r=nr_turn_stun_ctx_start(ctx))) {
990 ABORT(r);
991 }
992
993 _status=0;
994 abort:
995 if (_status) {
996 nr_turn_client_failed(ctx->tctx);
997 }
998 return;
999 }
1000
nr_turn_client_refresh_cb(NR_SOCKET s,int how,void * arg)1001 static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg)
1002 {
1003 int r, _status;
1004 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
1005 /* Save lifetime from the reset */
1006 UINT4 lifetime = ctx->stun->results.refresh_response.lifetime_secs;
1007
1008 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh succeeded. lifetime=%u",
1009 ctx->tctx->label, lifetime);
1010
1011 if ((r=nr_turn_client_start_refresh_timer(
1012 ctx->tctx, ctx, lifetime)))
1013 ABORT(r);
1014
1015 _status=0;
1016
1017 abort:
1018 if (_status) {
1019 nr_turn_client_failed(ctx->tctx);
1020 }
1021 }
1022
1023 /* TODO(ekr@rtfm.com): We currently don't support channels.
1024 We might in the future. Mozilla bug 857736 */
nr_turn_client_send_indication(nr_turn_client_ctx * ctx,const UCHAR * msg,size_t len,int flags,const nr_transport_addr * remote_addr)1025 int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
1026 const UCHAR *msg, size_t len,
1027 int flags, const nr_transport_addr *remote_addr)
1028 {
1029 int r,_status;
1030 nr_stun_client_send_indication_params params = { { 0 } };
1031 nr_stun_message *ind = 0;
1032
1033 if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
1034 ABORT(R_FAILED);
1035
1036 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Send indication len=%zu",
1037 ctx->label, len);
1038
1039 if ((r=nr_turn_client_ensure_perm(ctx, remote_addr)))
1040 ABORT(r);
1041
1042 if ((r=nr_transport_addr_copy(¶ms.remote_addr, remote_addr)))
1043 ABORT(r);
1044
1045 params.data.data = (UCHAR*)msg;
1046 params.data.len = len;
1047
1048 if ((r=nr_stun_build_send_indication(¶ms, &ind)))
1049 ABORT(r);
1050
1051 if ((r=nr_turn_client_send_stun_request(ctx, ind, flags)))
1052 ABORT(r);
1053
1054 _status=0;
1055 abort:
1056 nr_stun_message_destroy(&ind);
1057 return(_status);
1058 }
1059
nr_turn_client_parse_data_indication(nr_turn_client_ctx * ctx,nr_transport_addr * source_addr,UCHAR * msg,size_t len,UCHAR * newmsg,size_t * newlen,size_t newsize,nr_transport_addr * remote_addr)1060 int nr_turn_client_parse_data_indication(nr_turn_client_ctx *ctx,
1061 nr_transport_addr *source_addr,
1062 UCHAR *msg, size_t len,
1063 UCHAR *newmsg, size_t *newlen,
1064 size_t newsize,
1065 nr_transport_addr *remote_addr)
1066 {
1067 int r,_status;
1068 nr_stun_message *ind=0;
1069 nr_stun_message_attribute *attr;
1070 nr_turn_permission *perm;
1071
1072 if (nr_transport_addr_cmp(&ctx->turn_server_addr, source_addr,
1073 NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
1074 r_log(NR_LOG_TURN, LOG_WARNING,
1075 "TURN(%s): Indication from unexpected source addr %s (expected %s)",
1076 ctx->label, source_addr->as_string, ctx->turn_server_addr.as_string);
1077 ABORT(R_REJECTED);
1078 }
1079
1080 if ((r=nr_stun_message_create2(&ind, msg, len)))
1081 ABORT(r);
1082 if ((r=nr_stun_decode_message(ind, 0, 0)))
1083 ABORT(r);
1084
1085 if (ind->header.type != NR_STUN_MSG_DATA_INDICATION)
1086 ABORT(R_BAD_ARGS);
1087
1088 if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_XOR_PEER_ADDRESS, &attr))
1089 ABORT(R_BAD_ARGS);
1090
1091 if ((r=nr_turn_permission_find(ctx, &attr->u.xor_mapped_address.unmasked,
1092 &perm))) {
1093 if (r == R_NOT_FOUND) {
1094 r_log(NR_LOG_TURN, LOG_WARNING,
1095 "TURN(%s): Indication from peer addr %s with no permission",
1096 ctx->label, attr->u.xor_mapped_address.unmasked.as_string);
1097 }
1098 ABORT(r);
1099 }
1100
1101 if ((r=nr_transport_addr_copy(remote_addr,
1102 &attr->u.xor_mapped_address.unmasked)))
1103 ABORT(r);
1104
1105 #if REFRESH_RESERVATION_ON_RECV
1106 if ((r=nr_turn_client_ensure_perm(ctx, remote_addr))) {
1107 ABORT(r);
1108 }
1109 #endif
1110
1111 if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_DATA, &attr)) {
1112 ABORT(R_BAD_DATA);
1113 }
1114
1115 assert(newsize >= attr->u.data.length);
1116 if (newsize < attr->u.data.length)
1117 ABORT(R_BAD_ARGS);
1118
1119 memcpy(newmsg, attr->u.data.data, attr->u.data.length);
1120 *newlen = attr->u.data.length;
1121
1122 _status=0;
1123 abort:
1124 nr_stun_message_destroy(&ind);
1125 return(_status);
1126 }
1127
1128
1129
1130 /* The permissions model is as follows:
1131
1132 - We keep a list of all the permissions we have ever requested
1133 along with when they were last established.
1134 - Whenever someone sends a packet, we automatically create/
1135 refresh the permission.
1136
1137 This means that permissions automatically time out if
1138 unused.
1139
1140 */
nr_turn_client_ensure_perm(nr_turn_client_ctx * ctx,const nr_transport_addr * addr)1141 int nr_turn_client_ensure_perm(nr_turn_client_ctx *ctx, const nr_transport_addr *addr)
1142 {
1143 int r, _status;
1144 nr_turn_permission *perm = 0;
1145 UINT8 now;
1146 UINT8 turn_permission_refresh = (TURN_PERMISSION_LIFETIME_SECONDS -
1147 TURN_REFRESH_SLACK_SECONDS) * TURN_USECS_PER_S;
1148
1149 if ((r=nr_turn_permission_find(ctx, addr, &perm))) {
1150 if (r == R_NOT_FOUND) {
1151 if ((r=nr_turn_permission_create(ctx, addr, &perm)))
1152 ABORT(r);
1153 }
1154 else {
1155 ABORT(r);
1156 }
1157 }
1158
1159 assert(perm);
1160
1161 /* Now check that the permission is up-to-date */
1162 now = r_gettimeint();
1163
1164 if ((now - perm->last_used) > turn_permission_refresh) {
1165 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Permission for %s requires refresh",
1166 ctx->label, perm->addr.as_string);
1167
1168 if ((r=nr_turn_stun_ctx_start(perm->stun)))
1169 ABORT(r);
1170
1171 perm->last_used = now; /* Update the time now so we don't retry on
1172 next packet */
1173 }
1174
1175 _status=0;
1176 abort:
1177 return(_status);
1178 }
1179
nr_turn_permission_create(nr_turn_client_ctx * ctx,const nr_transport_addr * addr,nr_turn_permission ** permp)1180 static int nr_turn_permission_create(nr_turn_client_ctx *ctx, const nr_transport_addr *addr,
1181 nr_turn_permission **permp)
1182 {
1183 int r, _status;
1184 nr_turn_permission *perm = 0;
1185
1186 assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
1187
1188 r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): Creating permission for %s",
1189 ctx->label, addr->as_string);
1190
1191 if (!(perm = RCALLOC(sizeof(nr_turn_permission))))
1192 ABORT(R_NO_MEMORY);
1193
1194 if ((r=nr_transport_addr_copy(&perm->addr, addr)))
1195 ABORT(r);
1196
1197 perm->last_used = 0;
1198
1199 if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_PERMISSION_REQUEST,
1200 nr_turn_client_permissions_cb,
1201 nr_turn_client_permission_error_cb,
1202 &perm->stun)))
1203 ABORT(r);
1204
1205 /* We want to authenticate on the first packet */
1206 if ((r=nr_turn_stun_set_auth_params(perm->stun, ctx->realm, ctx->nonce)))
1207 ABORT(r);
1208
1209 if ((r=nr_transport_addr_copy(
1210 &perm->stun->stun->params.permission_request.remote_addr, addr)))
1211 ABORT(r);
1212 STAILQ_INSERT_TAIL(&ctx->permissions, perm, entry);
1213
1214 *permp = perm;
1215
1216 _status=0;
1217 abort:
1218 if (_status) {
1219 nr_turn_permission_destroy(&perm);
1220 }
1221 return(_status);
1222 }
1223
1224
nr_turn_permission_find(nr_turn_client_ctx * ctx,const nr_transport_addr * addr,nr_turn_permission ** permp)1225 static int nr_turn_permission_find(nr_turn_client_ctx *ctx, const nr_transport_addr *addr,
1226 nr_turn_permission **permp)
1227 {
1228 nr_turn_permission *perm;
1229 int _status;
1230
1231 perm = STAILQ_FIRST(&ctx->permissions);
1232 while (perm) {
1233 if (!nr_transport_addr_cmp(&perm->addr, addr,
1234 NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
1235 break;
1236
1237 perm = STAILQ_NEXT(perm, entry);
1238 }
1239
1240 if (!perm) {
1241 ABORT(R_NOT_FOUND);
1242 }
1243 if (perm->stun->last_error_code == 403) {
1244 ABORT(R_NOT_PERMITTED);
1245 }
1246 *permp = perm;
1247
1248 _status=0;
1249 abort:
1250 return(_status);
1251 }
1252
nr_turn_client_permissions_cb(NR_SOCKET s,int how,void * arg)1253 static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *arg)
1254 {
1255 nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
1256 r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Successfully refreshed permission",
1257 ctx->tctx->label);
1258 }
1259
1260 /* Note that we don't destroy the nr_turn_stun_ctx. That is owned by the
1261 nr_turn_client_ctx. */
nr_turn_permission_destroy(nr_turn_permission ** permp)1262 static int nr_turn_permission_destroy(nr_turn_permission **permp)
1263 {
1264 nr_turn_permission *perm;
1265
1266 if (!permp || !*permp)
1267 return(0);
1268
1269 perm = *permp;
1270 *permp = 0;
1271
1272 RFREE(perm);
1273
1274 return(0);
1275 }
1276
1277 #endif /* USE_TURN */
1278