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(&params.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(&params, &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