blob: 42fa635828c97a794131ce94f63e0fdff01af4fa [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjnath/turn_session.h>
21#include <pjnath/errno.h>
22#include <pjlib-util/srv_resolver.h>
23#include <pj/addr_resolv.h>
24#include <pj/assert.h>
25#include <pj/errno.h>
26#include <pj/hash.h>
27#include <pj/lock.h>
28#include <pj/log.h>
29#include <pj/os.h>
30#include <pj/pool.h>
31#include <pj/rand.h>
32#include <pj/sock.h>
33
34#define PJ_TURN_CHANNEL_MIN 0x4000
35#define PJ_TURN_CHANNEL_MAX 0x7FFF /* inclusive */
36#define PJ_TURN_CHANNEL_HTABLE_SIZE 8
37#define PJ_TURN_PERM_HTABLE_SIZE 8
38
39static const char *state_names[] =
40{
41 "Null",
42 "Resolving",
43 "Resolved",
44 "Allocating",
45 "Ready",
46 "Deallocating",
47 "Deallocated",
48 "Destroying"
49};
50
51enum timer_id_t
52{
53 TIMER_NONE,
54 TIMER_KEEP_ALIVE,
55 TIMER_DESTROY
56};
57
58/* This structure describes a channel binding. A channel binding is index by
59 * the channel number or IP address and port number of the peer.
60 */
61struct ch_t
62{
63 /* The channel number */
64 pj_uint16_t num;
65
66 /* PJ_TRUE if we've received successful response to ChannelBind request
67 * for this channel.
68 */
69 pj_bool_t bound;
70
71 /* The peer IP address and port */
72 pj_sockaddr addr;
73
74 /* The channel binding expiration */
75 pj_time_val expiry;
76};
77
78
79/* This structure describes a permission. A permission is identified by the
80 * IP address only.
81 */
82struct perm_t
83{
84 /* Cache of hash value to speed-up lookup */
85 pj_uint32_t hval;
86
87 /* The permission IP address. The port number MUST be zero */
88 pj_sockaddr addr;
89
90 /* Number of peers that uses this permission. */
91 unsigned peer_cnt;
92
93 /* Automatically renew this permission once it expires? */
94 pj_bool_t renew;
95
96 /* The permission expiration */
97 pj_time_val expiry;
98
99 /* Arbitrary/random pointer value (token) to map this perm with the
100 * request to create it. It is used to invalidate this perm when the
101 * request fails.
102 */
103 void *req_token;
104};
105
106
107/* The TURN client session structure */
108struct pj_turn_session
109{
110 pj_pool_t *pool;
111 const char *obj_name;
112 pj_turn_session_cb cb;
113 void *user_data;
114 pj_stun_config stun_cfg;
115 pj_bool_t is_destroying;
116
117 pj_grp_lock_t *grp_lock;
118 int busy;
119
120 pj_turn_state_t state;
121 pj_status_t last_status;
122 pj_bool_t pending_destroy;
123
124 pj_stun_session *stun;
125
126 unsigned lifetime;
127 int ka_interval;
128 pj_time_val expiry;
129
130 pj_timer_heap_t *timer_heap;
131 pj_timer_entry timer;
132
133 pj_uint16_t default_port;
134
135 pj_uint16_t af;
136 pj_turn_tp_type conn_type;
137 pj_uint16_t srv_addr_cnt;
138 pj_sockaddr *srv_addr_list;
139 pj_sockaddr *srv_addr;
140
141 pj_bool_t pending_alloc;
142 pj_turn_alloc_param alloc_param;
143
144 pj_sockaddr mapped_addr;
145 pj_sockaddr relay_addr;
146
147 pj_hash_table_t *ch_table;
148 pj_hash_table_t *perm_table;
149
150 pj_uint32_t send_ind_tsx_id[3];
151 /* tx_pkt must be 16bit aligned */
152 pj_uint8_t tx_pkt[PJ_TURN_MAX_PKT_LEN];
153
154 pj_uint16_t next_ch;
155};
156
157
158/*
159 * Prototypes.
160 */
161static void sess_shutdown(pj_turn_session *sess,
162 pj_status_t status);
163static void turn_sess_on_destroy(void *comp);
164static void do_destroy(pj_turn_session *sess);
165static void send_refresh(pj_turn_session *sess, int lifetime);
166static pj_status_t stun_on_send_msg(pj_stun_session *sess,
167 void *token,
168 const void *pkt,
169 pj_size_t pkt_size,
170 const pj_sockaddr_t *dst_addr,
171 unsigned addr_len);
172static void stun_on_request_complete(pj_stun_session *sess,
173 pj_status_t status,
174 void *token,
175 pj_stun_tx_data *tdata,
176 const pj_stun_msg *response,
177 const pj_sockaddr_t *src_addr,
178 unsigned src_addr_len);
179static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
180 const pj_uint8_t *pkt,
181 unsigned pkt_len,
182 const pj_stun_msg *msg,
183 void *token,
184 const pj_sockaddr_t *src_addr,
185 unsigned src_addr_len);
186static void dns_srv_resolver_cb(void *user_data,
187 pj_status_t status,
188 const pj_dns_srv_record *rec);
189static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
190 const pj_sockaddr_t *addr,
191 unsigned addr_len,
192 pj_bool_t update,
193 pj_bool_t bind_channel);
194static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
195 pj_uint16_t chnum);
196static struct perm_t *lookup_perm(pj_turn_session *sess,
197 const pj_sockaddr_t *addr,
198 unsigned addr_len,
199 pj_bool_t update);
200static void invalidate_perm(pj_turn_session *sess,
201 struct perm_t *perm);
202static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e);
203
204
205/*
206 * Create default pj_turn_alloc_param.
207 */
208PJ_DEF(void) pj_turn_alloc_param_default(pj_turn_alloc_param *prm)
209{
210 pj_bzero(prm, sizeof(*prm));
211}
212
213/*
214 * Duplicate pj_turn_alloc_param.
215 */
216PJ_DEF(void) pj_turn_alloc_param_copy( pj_pool_t *pool,
217 pj_turn_alloc_param *dst,
218 const pj_turn_alloc_param *src)
219{
220 PJ_UNUSED_ARG(pool);
221 pj_memcpy(dst, src, sizeof(*dst));
222}
223
224/*
225 * Get TURN state name.
226 */
227PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state)
228{
229 return state_names[state];
230}
231
232/*
233 * Create TURN client session.
234 */
235PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
236 const char *name,
237 int af,
238 pj_turn_tp_type conn_type,
239 pj_grp_lock_t *grp_lock,
240 const pj_turn_session_cb *cb,
241 unsigned options,
242 void *user_data,
243 pj_turn_session **p_sess)
244{
245 pj_pool_t *pool;
246 pj_turn_session *sess;
247 pj_stun_session_cb stun_cb;
248 pj_status_t status;
249
250 PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL);
251 PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL);
252
253 PJ_UNUSED_ARG(options);
254
255 if (name == NULL)
256 name = "turn%p";
257
258 /* Allocate and create TURN session */
259 pool = pj_pool_create(cfg->pf, name, PJNATH_POOL_LEN_TURN_SESS,
260 PJNATH_POOL_INC_TURN_SESS, NULL);
261 sess = PJ_POOL_ZALLOC_T(pool, pj_turn_session);
262 sess->pool = pool;
263 sess->obj_name = pool->obj_name;
264 sess->timer_heap = cfg->timer_heap;
265 sess->af = (pj_uint16_t)af;
266 sess->conn_type = conn_type;
267 sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
268 sess->user_data = user_data;
269 sess->next_ch = PJ_TURN_CHANNEL_MIN;
270
271 /* Copy STUN session */
272 pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config));
273
274 /* Copy callback */
275 pj_memcpy(&sess->cb, cb, sizeof(*cb));
276
277 /* Peer hash table */
278 sess->ch_table = pj_hash_create(pool, PJ_TURN_CHANNEL_HTABLE_SIZE);
279
280 /* Permission hash table */
281 sess->perm_table = pj_hash_create(pool, PJ_TURN_PERM_HTABLE_SIZE);
282
283 /* Session lock */
284 if (grp_lock) {
285 sess->grp_lock = grp_lock;
286 } else {
287 status = pj_grp_lock_create(pool, NULL, &sess->grp_lock);
288 if (status != PJ_SUCCESS) {
289 pj_pool_release(pool);
290 return status;
291 }
292 }
293
294 pj_grp_lock_add_ref(sess->grp_lock);
295 pj_grp_lock_add_handler(sess->grp_lock, pool, sess,
296 &turn_sess_on_destroy);
297
298 /* Timer */
299 pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event);
300
301 /* Create STUN session */
302 pj_bzero(&stun_cb, sizeof(stun_cb));
303 stun_cb.on_send_msg = &stun_on_send_msg;
304 stun_cb.on_request_complete = &stun_on_request_complete;
305 stun_cb.on_rx_indication = &stun_on_rx_indication;
306 status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb,
307 PJ_FALSE, sess->grp_lock, &sess->stun);
308 if (status != PJ_SUCCESS) {
309 do_destroy(sess);
310 return status;
311 }
312
313 /* Attach ourself to STUN session */
314 pj_stun_session_set_user_data(sess->stun, sess);
315
316 /* Done */
317
318 PJ_LOG(4,(sess->obj_name, "TURN client session created"));
319
320 *p_sess = sess;
321 return PJ_SUCCESS;
322}
323
324
325static void turn_sess_on_destroy(void *comp)
326{
327 pj_turn_session *sess = (pj_turn_session*) comp;
328
329 /* Destroy pool */
330 if (sess->pool) {
331 pj_pool_t *pool = sess->pool;
332
333 PJ_LOG(4,(sess->obj_name, "TURN client session destroyed"));
334
335 sess->pool = NULL;
336 pj_pool_release(pool);
337 }
338}
339
340/* Destroy */
341static void do_destroy(pj_turn_session *sess)
342{
343 PJ_LOG(4,(sess->obj_name, "TURN session destroy request, ref_cnt=%d",
344 pj_grp_lock_get_ref(sess->grp_lock)));
345
346 pj_grp_lock_acquire(sess->grp_lock);
347 if (sess->is_destroying) {
348 pj_grp_lock_release(sess->grp_lock);
349 return;
350 }
351
352 sess->is_destroying = PJ_TRUE;
353 pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, TIMER_NONE);
354 pj_stun_session_destroy(sess->stun);
355
356 pj_grp_lock_dec_ref(sess->grp_lock);
357 pj_grp_lock_release(sess->grp_lock);
358}
359
360
361/* Set session state */
362static void set_state(pj_turn_session *sess, enum pj_turn_state_t state)
363{
364 pj_turn_state_t old_state = sess->state;
365
366 if (state==sess->state)
367 return;
368
369 PJ_LOG(4,(sess->obj_name, "State changed %s --> %s",
370 state_names[old_state], state_names[state]));
371 sess->state = state;
372
373 if (sess->cb.on_state) {
374 (*sess->cb.on_state)(sess, old_state, state);
375 }
376}
377
378/*
379 * Notify application and shutdown the TURN session.
380 */
381static void sess_shutdown(pj_turn_session *sess,
382 pj_status_t status)
383{
384 pj_bool_t can_destroy = PJ_TRUE;
385
386 PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d",
387 state_names[sess->state], status));
388
389 if (sess->last_status == PJ_SUCCESS && status != PJ_SUCCESS)
390 sess->last_status = status;
391
392 switch (sess->state) {
393 case PJ_TURN_STATE_NULL:
394 break;
395 case PJ_TURN_STATE_RESOLVING:
396 /* Wait for DNS callback invoked, it will call the this function
397 * again. If the callback happens to get pending_destroy==FALSE,
398 * the TURN allocation will call this function again.
399 */
400 sess->pending_destroy = PJ_TRUE;
401 can_destroy = PJ_FALSE;
402 break;
403 case PJ_TURN_STATE_RESOLVED:
404 break;
405 case PJ_TURN_STATE_ALLOCATING:
406 /* We need to wait until allocation complete */
407 sess->pending_destroy = PJ_TRUE;
408 can_destroy = PJ_FALSE;
409 break;
410 case PJ_TURN_STATE_READY:
411 /* Send REFRESH with LIFETIME=0 */
412 can_destroy = PJ_FALSE;
413 send_refresh(sess, 0);
414 break;
415 case PJ_TURN_STATE_DEALLOCATING:
416 can_destroy = PJ_FALSE;
417 /* This may recursively call this function again with
418 * state==PJ_TURN_STATE_DEALLOCATED.
419 */
420 /* No need to deallocate as we're already deallocating!
421 * See https://trac.pjsip.org/repos/ticket/1551
422 send_refresh(sess, 0);
423 */
424 break;
425 case PJ_TURN_STATE_DEALLOCATED:
426 case PJ_TURN_STATE_DESTROYING:
427 break;
428 }
429
430 if (can_destroy) {
431 /* Schedule destroy */
432 pj_time_val delay = {0, 0};
433
434 set_state(sess, PJ_TURN_STATE_DESTROYING);
435
436 pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
437 TIMER_NONE);
438 pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
439 &delay, TIMER_DESTROY,
440 sess->grp_lock);
441 }
442}
443
444
445/*
446 * Public API to destroy TURN client session.
447 */
448PJ_DEF(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess)
449{
450 PJ_ASSERT_RETURN(sess, PJ_EINVAL);
451
452 pj_grp_lock_acquire(sess->grp_lock);
453
454 sess_shutdown(sess, PJ_SUCCESS);
455
456 pj_grp_lock_release(sess->grp_lock);
457
458 return PJ_SUCCESS;
459}
460
461
462/**
463 * Forcefully destroy the TURN session.
464 */
465PJ_DEF(pj_status_t) pj_turn_session_destroy( pj_turn_session *sess,
466 pj_status_t last_err)
467{
468 PJ_ASSERT_RETURN(sess, PJ_EINVAL);
469
470 if (last_err != PJ_SUCCESS && sess->last_status == PJ_SUCCESS)
471 sess->last_status = last_err;
472 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
473 sess_shutdown(sess, PJ_SUCCESS);
474 return PJ_SUCCESS;
475}
476
477
478/*
479 * Get TURN session info.
480 */
481PJ_DEF(pj_status_t) pj_turn_session_get_info( pj_turn_session *sess,
482 pj_turn_session_info *info)
483{
484 pj_time_val now;
485
486 PJ_ASSERT_RETURN(sess && info, PJ_EINVAL);
487
488 pj_gettimeofday(&now);
489
490 info->state = sess->state;
491 info->conn_type = sess->conn_type;
492 info->lifetime = sess->expiry.sec - now.sec;
493 info->last_status = sess->last_status;
494
495 if (sess->srv_addr)
496 pj_memcpy(&info->server, sess->srv_addr, sizeof(info->server));
497 else
498 pj_bzero(&info->server, sizeof(info->server));
499
500 pj_memcpy(&info->mapped_addr, &sess->mapped_addr,
501 sizeof(sess->mapped_addr));
502 pj_memcpy(&info->relay_addr, &sess->relay_addr,
503 sizeof(sess->relay_addr));
504
505 return PJ_SUCCESS;
506}
507
508
509/*
510 * Re-assign user data.
511 */
512PJ_DEF(pj_status_t) pj_turn_session_set_user_data( pj_turn_session *sess,
513 void *user_data)
514{
515 sess->user_data = user_data;
516 return PJ_SUCCESS;
517}
518
519
520/**
521 * Retrieve user data.
522 */
523PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess)
524{
525 return sess->user_data;
526}
527
528
529/*
530 * Configure message logging. By default all flags are enabled.
531 *
532 * @param sess The TURN client session.
533 * @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
534 */
535PJ_DEF(void) pj_turn_session_set_log( pj_turn_session *sess,
536 unsigned flags)
537{
538 pj_stun_session_set_log(sess->stun, flags);
539}
540
541
542/*
543 * Set software name
544 */
545PJ_DEF(pj_status_t) pj_turn_session_set_software_name( pj_turn_session *sess,
546 const pj_str_t *sw)
547{
548 pj_status_t status;
549
550 pj_grp_lock_acquire(sess->grp_lock);
551 status = pj_stun_session_set_software_name(sess->stun, sw);
552 pj_grp_lock_release(sess->grp_lock);
553
554 return status;
555}
556
557
558/**
559 * Set the server or domain name of the server.
560 */
561PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
562 const pj_str_t *domain,
563 int default_port,
564 pj_dns_resolver *resolver)
565{
566 pj_sockaddr tmp_addr;
567 pj_bool_t is_ip_addr;
568 pj_status_t status;
569
570 PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
571 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP);
572
573 pj_grp_lock_acquire(sess->grp_lock);
574
575 /* See if "domain" contains just IP address */
576 tmp_addr.addr.sa_family = sess->af;
577 status = pj_inet_pton(sess->af, domain,
578 pj_sockaddr_get_addr(&tmp_addr));
579 is_ip_addr = (status == PJ_SUCCESS);
580
581 if (!is_ip_addr && resolver) {
582 /* Resolve with DNS SRV resolution, and fallback to DNS A resolution
583 * if default_port is specified.
584 */
585 unsigned opt = 0;
586 pj_str_t res_name;
587
588 switch (sess->conn_type) {
589 case PJ_TURN_TP_UDP:
590 res_name = pj_str("_turn._udp.");
591 break;
592 case PJ_TURN_TP_TCP:
593 res_name = pj_str("_turn._tcp.");
594 break;
595 case PJ_TURN_TP_TLS:
596 res_name = pj_str("_turns._tcp.");
597 break;
598 default:
599 status = PJNATH_ETURNINTP;
600 goto on_return;
601 }
602
603 /* Fallback to DNS A only if default port is specified */
604 if (default_port>0 && default_port<65536) {
605 opt = PJ_DNS_SRV_FALLBACK_A;
606 sess->default_port = (pj_uint16_t)default_port;
607 }
608
609 PJ_LOG(5,(sess->obj_name, "Resolving %.*s%.*s with DNS SRV",
610 (int)res_name.slen, res_name.ptr,
611 (int)domain->slen, domain->ptr));
612 set_state(sess, PJ_TURN_STATE_RESOLVING);
613
614 /* User may have destroyed us in the callback */
615 if (sess->state != PJ_TURN_STATE_RESOLVING) {
616 status = PJ_ECANCELLED;
617 goto on_return;
618 }
619
620 status = pj_dns_srv_resolve(domain, &res_name, default_port,
621 sess->pool, resolver, opt, sess,
622 &dns_srv_resolver_cb, NULL);
623 if (status != PJ_SUCCESS) {
624 set_state(sess, PJ_TURN_STATE_NULL);
625 goto on_return;
626 }
627
628 } else {
629 /* Resolver is not specified, resolve with standard gethostbyname().
630 * The default_port MUST be specified in this case.
631 */
632 pj_addrinfo *ai;
633 unsigned i, cnt;
634
635 /* Default port must be specified */
636 PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
637 sess->default_port = (pj_uint16_t)default_port;
638
639 cnt = PJ_TURN_MAX_DNS_SRV_CNT;
640 ai = (pj_addrinfo*)
641 pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));
642
643 PJ_LOG(5,(sess->obj_name, "Resolving %.*s with DNS A",
644 (int)domain->slen, domain->ptr));
645 set_state(sess, PJ_TURN_STATE_RESOLVING);
646
647 /* User may have destroyed us in the callback */
648 if (sess->state != PJ_TURN_STATE_RESOLVING) {
649 status = PJ_ECANCELLED;
650 goto on_return;
651 }
652
653 status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
654 if (status != PJ_SUCCESS)
655 goto on_return;
656
657 sess->srv_addr_cnt = (pj_uint16_t)cnt;
658 sess->srv_addr_list = (pj_sockaddr*)
659 pj_pool_calloc(sess->pool, cnt,
660 sizeof(pj_sockaddr));
661 for (i=0; i<cnt; ++i) {
662 pj_sockaddr *addr = &sess->srv_addr_list[i];
663 pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
664 addr->addr.sa_family = sess->af;
665 addr->ipv4.sin_port = pj_htons(sess->default_port);
666 }
667
668 sess->srv_addr = &sess->srv_addr_list[0];
669 set_state(sess, PJ_TURN_STATE_RESOLVED);
670 }
671
672on_return:
673 pj_grp_lock_release(sess->grp_lock);
674 return status;
675}
676
677
678/**
679 * Set credential to be used by the session.
680 */
681PJ_DEF(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
682 const pj_stun_auth_cred *cred)
683{
684 PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
685 PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);
686
687 pj_grp_lock_acquire(sess->grp_lock);
688
689 pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);
690
691 pj_grp_lock_release(sess->grp_lock);
692
693 return PJ_SUCCESS;
694}
695
696
697/**
698 * Create TURN allocation.
699 */
700PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
701 const pj_turn_alloc_param *param)
702{
703 pj_stun_tx_data *tdata;
704 pj_bool_t retransmit;
705 pj_status_t status;
706
707 PJ_ASSERT_RETURN(sess, PJ_EINVAL);
708 PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL &&
709 sess->state<=PJ_TURN_STATE_RESOLVED,
710 PJ_EINVALIDOP);
711
712 pj_grp_lock_acquire(sess->grp_lock);
713
714 if (param && param != &sess->alloc_param)
715 pj_turn_alloc_param_copy(sess->pool, &sess->alloc_param, param);
716
717 if (sess->state < PJ_TURN_STATE_RESOLVED) {
718 sess->pending_alloc = PJ_TRUE;
719
720 PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s",
721 state_names[sess->state]));
722
723 pj_grp_lock_release(sess->grp_lock);
724 return PJ_SUCCESS;
725
726 }
727
728 /* Ready to allocate */
729 pj_assert(sess->state == PJ_TURN_STATE_RESOLVED);
730
731 /* Create a bare request */
732 status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST,
733 PJ_STUN_MAGIC, NULL, &tdata);
734 if (status != PJ_SUCCESS) {
735 pj_grp_lock_release(sess->grp_lock);
736 return status;
737 }
738
739 /* MUST include REQUESTED-TRANSPORT attribute */
740 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
741 PJ_STUN_ATTR_REQ_TRANSPORT,
742 PJ_STUN_SET_RT_PROTO(PJ_TURN_TP_UDP));
743
744 /* Include BANDWIDTH if requested */
745 if (sess->alloc_param.bandwidth > 0) {
746 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
747 PJ_STUN_ATTR_BANDWIDTH,
748 sess->alloc_param.bandwidth);
749 }
750
751 /* Include LIFETIME if requested */
752 if (sess->alloc_param.lifetime > 0) {
753 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
754 PJ_STUN_ATTR_LIFETIME,
755 sess->alloc_param.lifetime);
756 }
757
758 /* Server address must be set */
759 pj_assert(sess->srv_addr != NULL);
760
761 /* Send request */
762 set_state(sess, PJ_TURN_STATE_ALLOCATING);
763 retransmit = (sess->conn_type == PJ_TURN_TP_UDP);
764 status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
765 retransmit, sess->srv_addr,
766 pj_sockaddr_get_len(sess->srv_addr),
767 tdata);
768 if (status != PJ_SUCCESS) {
769 /* Set state back to RESOLVED. We don't want to destroy session now,
770 * let the application do it if it wants to.
771 */
772 set_state(sess, PJ_TURN_STATE_RESOLVED);
773 }
774
775 pj_grp_lock_release(sess->grp_lock);
776 return status;
777}
778
779
780/*
781 * Install or renew permissions
782 */
783PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
784 unsigned addr_cnt,
785 const pj_sockaddr addr[],
786 unsigned options)
787{
788 pj_stun_tx_data *tdata;
789 pj_hash_iterator_t it_buf, *it;
790 void *req_token;
791 unsigned i, attr_added=0;
792 pj_status_t status;
793
794 PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL);
795
796 pj_grp_lock_acquire(sess->grp_lock);
797
798 /* Create a bare CreatePermission request */
799 status = pj_stun_session_create_req(sess->stun,
800 PJ_STUN_CREATE_PERM_REQUEST,
801 PJ_STUN_MAGIC, NULL, &tdata);
802 if (status != PJ_SUCCESS) {
803 pj_grp_lock_release(sess->grp_lock);
804 return status;
805 }
806
807 /* Create request token to map the request to the perm structures
808 * which the request belongs.
809 */
810 req_token = (void*)(pj_ssize_t)pj_rand();
811
812 /* Process the addresses */
813 for (i=0; i<addr_cnt; ++i) {
814 struct perm_t *perm;
815
816 /* Lookup the perm structure and create if it doesn't exist */
817 perm = lookup_perm(sess, &addr[i], pj_sockaddr_get_len(&addr[i]),
818 PJ_TRUE);
819 perm->renew = (options & 0x01);
820
821 /* Only add to the request if the request doesn't contain this
822 * address yet.
823 */
824 if (perm->req_token != req_token) {
825 perm->req_token = req_token;
826
827 /* Add XOR-PEER-ADDRESS */
828 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
829 PJ_STUN_ATTR_XOR_PEER_ADDR,
830 PJ_TRUE,
831 &addr[i],
832 sizeof(addr[i]));
833 if (status != PJ_SUCCESS)
834 goto on_error;
835
836 ++attr_added;
837 }
838 }
839
840 pj_assert(attr_added != 0);
841
842 /* Send the request */
843 status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE,
844 (sess->conn_type==PJ_TURN_TP_UDP),
845 sess->srv_addr,
846 pj_sockaddr_get_len(sess->srv_addr),
847 tdata);
848 if (status != PJ_SUCCESS) {
849 /* tdata is already destroyed */
850 tdata = NULL;
851 goto on_error;
852 }
853
854 pj_grp_lock_release(sess->grp_lock);
855 return PJ_SUCCESS;
856
857on_error:
858 /* destroy tdata */
859 if (tdata) {
860 pj_stun_msg_destroy_tdata(sess->stun, tdata);
861 }
862 /* invalidate perm structures associated with this request */
863 it = pj_hash_first(sess->perm_table, &it_buf);
864 while (it) {
865 struct perm_t *perm = (struct perm_t*)
866 pj_hash_this(sess->perm_table, it);
867 it = pj_hash_next(sess->perm_table, it);
868 if (perm->req_token == req_token)
869 invalidate_perm(sess, perm);
870 }
871 pj_grp_lock_release(sess->grp_lock);
872 return status;
873}
874
875/*
876 * Send REFRESH
877 */
878static void send_refresh(pj_turn_session *sess, int lifetime)
879{
880 pj_stun_tx_data *tdata;
881 pj_status_t status;
882
883 PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return);
884
885 /* Create a bare REFRESH request */
886 status = pj_stun_session_create_req(sess->stun, PJ_STUN_REFRESH_REQUEST,
887 PJ_STUN_MAGIC, NULL, &tdata);
888 if (status != PJ_SUCCESS)
889 goto on_error;
890
891 /* Add LIFETIME */
892 if (lifetime >= 0) {
893 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
894 PJ_STUN_ATTR_LIFETIME, lifetime);
895 }
896
897 /* Send request */
898 if (lifetime == 0) {
899 set_state(sess, PJ_TURN_STATE_DEALLOCATING);
900 }
901
902 status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
903 (sess->conn_type==PJ_TURN_TP_UDP),
904 sess->srv_addr,
905 pj_sockaddr_get_len(sess->srv_addr),
906 tdata);
907 if (status != PJ_SUCCESS)
908 goto on_error;
909
910 return;
911
912on_error:
913 if (lifetime == 0) {
914 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
915 sess_shutdown(sess, status);
916 }
917}
918
919
920/**
921 * Relay data to the specified peer through the session.
922 */
923PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
924 const pj_uint8_t *pkt,
925 unsigned pkt_len,
926 const pj_sockaddr_t *addr,
927 unsigned addr_len)
928{
929 struct ch_t *ch;
930 struct perm_t *perm;
931 pj_status_t status;
932
933 PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len,
934 PJ_EINVAL);
935
936 /* Return error if we're not ready */
937 if (sess->state != PJ_TURN_STATE_READY) {
938 return PJ_EIGNORED;
939 }
940
941 /* Lock session now */
942 pj_grp_lock_acquire(sess->grp_lock);
943
944 /* Lookup permission first */
945 perm = lookup_perm(sess, addr, pj_sockaddr_get_len(addr), PJ_FALSE);
946 if (perm == NULL) {
947 /* Permission doesn't exist, install it first */
948 char ipstr[PJ_INET6_ADDRSTRLEN+2];
949
950 PJ_LOG(4,(sess->obj_name,
951 "sendto(): IP %s has no permission, requesting it first..",
952 pj_sockaddr_print(addr, ipstr, sizeof(ipstr), 2)));
953
954 status = pj_turn_session_set_perm(sess, 1, (const pj_sockaddr*)addr,
955 0);
956 if (status != PJ_SUCCESS) {
957 pj_grp_lock_release(sess->grp_lock);
958 return status;
959 }
960 }
961
962 /* See if the peer is bound to a channel number */
963 ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr),
964 PJ_FALSE, PJ_FALSE);
965 if (ch && ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound) {
966 unsigned total_len;
967
968 /* Peer is assigned a channel number, we can use ChannelData */
969 pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt;
970
971 pj_assert(sizeof(*cd)==4);
972
973 /* Calculate total length, including paddings */
974 total_len = (pkt_len + sizeof(*cd) + 3) & (~3);
975 if (total_len > sizeof(sess->tx_pkt)) {
976 status = PJ_ETOOBIG;
977 goto on_return;
978 }
979
980 cd->ch_number = pj_htons((pj_uint16_t)ch->num);
981 cd->length = pj_htons((pj_uint16_t)pkt_len);
982 pj_memcpy(cd+1, pkt, pkt_len);
983
984 pj_assert(sess->srv_addr != NULL);
985
986 status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len,
987 sess->srv_addr,
988 pj_sockaddr_get_len(sess->srv_addr));
989
990 } else {
991 /* Use Send Indication. */
992 pj_stun_sockaddr_attr peer_attr;
993 pj_stun_binary_attr data_attr;
994 pj_stun_msg send_ind;
995 pj_size_t send_ind_len;
996
997 /* Increment counter */
998 ++sess->send_ind_tsx_id[2];
999
1000 /* Create blank SEND-INDICATION */
1001 status = pj_stun_msg_init(&send_ind, PJ_STUN_SEND_INDICATION,
1002 PJ_STUN_MAGIC,
1003 (const pj_uint8_t*)sess->send_ind_tsx_id);
1004 if (status != PJ_SUCCESS)
1005 goto on_return;
1006
1007 /* Add XOR-PEER-ADDRESS */
1008 pj_stun_sockaddr_attr_init(&peer_attr, PJ_STUN_ATTR_XOR_PEER_ADDR,
1009 PJ_TRUE, addr, addr_len);
1010 pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&peer_attr);
1011
1012 /* Add DATA attribute */
1013 pj_stun_binary_attr_init(&data_attr, NULL, PJ_STUN_ATTR_DATA, NULL, 0);
1014 data_attr.data = (pj_uint8_t*)pkt;
1015 data_attr.length = pkt_len;
1016 pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&data_attr);
1017
1018 /* Encode the message */
1019 status = pj_stun_msg_encode(&send_ind, sess->tx_pkt,
1020 sizeof(sess->tx_pkt), 0,
1021 NULL, &send_ind_len);
1022 if (status != PJ_SUCCESS)
1023 goto on_return;
1024
1025 /* Send the Send Indication */
1026 status = sess->cb.on_send_pkt(sess, sess->tx_pkt,
1027 (unsigned)send_ind_len,
1028 sess->srv_addr,
1029 pj_sockaddr_get_len(sess->srv_addr));
1030 }
1031
1032on_return:
1033 pj_grp_lock_release(sess->grp_lock);
1034 return status;
1035}
1036
1037
1038/**
1039 * Bind a peer address to a channel number.
1040 */
1041PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
1042 const pj_sockaddr_t *peer_adr,
1043 unsigned addr_len)
1044{
1045 struct ch_t *ch;
1046 pj_stun_tx_data *tdata;
1047 pj_uint16_t ch_num;
1048 pj_status_t status;
1049
1050 PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL);
1051 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP);
1052
1053 pj_grp_lock_acquire(sess->grp_lock);
1054
1055 /* Create blank ChannelBind request */
1056 status = pj_stun_session_create_req(sess->stun,
1057 PJ_STUN_CHANNEL_BIND_REQUEST,
1058 PJ_STUN_MAGIC, NULL, &tdata);
1059 if (status != PJ_SUCCESS)
1060 goto on_return;
1061
1062 /* Lookup if this peer has already been assigned a number */
1063 ch = lookup_ch_by_addr(sess, peer_adr, pj_sockaddr_get_len(peer_adr),
1064 PJ_TRUE, PJ_FALSE);
1065 pj_assert(ch);
1066
1067 if (ch->num != PJ_TURN_INVALID_CHANNEL) {
1068 /* Channel is already bound. This is a refresh request. */
1069 ch_num = ch->num;
1070 } else {
1071 PJ_ASSERT_ON_FAIL(sess->next_ch <= PJ_TURN_CHANNEL_MAX,
1072 {status=PJ_ETOOMANY; goto on_return;});
1073 ch->num = ch_num = sess->next_ch++;
1074 }
1075
1076 /* Add CHANNEL-NUMBER attribute */
1077 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
1078 PJ_STUN_ATTR_CHANNEL_NUMBER,
1079 PJ_STUN_SET_CH_NB(ch_num));
1080
1081 /* Add XOR-PEER-ADDRESS attribute */
1082 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
1083 PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
1084 peer_adr, addr_len);
1085
1086 /* Send the request, associate peer data structure with tdata
1087 * for future reference when we receive the ChannelBind response.
1088 */
1089 status = pj_stun_session_send_msg(sess->stun, ch, PJ_FALSE,
1090 (sess->conn_type==PJ_TURN_TP_UDP),
1091 sess->srv_addr,
1092 pj_sockaddr_get_len(sess->srv_addr),
1093 tdata);
1094
1095on_return:
1096 pj_grp_lock_release(sess->grp_lock);
1097 return status;
1098}
1099
1100
1101/**
1102 * Notify TURN client session upon receiving a packet from server.
1103 * The packet maybe a STUN packet or ChannelData packet.
1104 */
1105PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
1106 void *pkt,
1107 pj_size_t pkt_len,
1108 pj_size_t *parsed_len)
1109{
1110 pj_bool_t is_stun;
1111 pj_status_t status;
1112 pj_bool_t is_datagram;
1113
1114 /* Packet could be ChannelData or STUN message (response or
1115 * indication).
1116 */
1117
1118 /* Start locking the session */
1119 pj_grp_lock_acquire(sess->grp_lock);
1120
1121 is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
1122
1123 /* Quickly check if this is STUN message */
1124 is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
1125
1126 if (is_stun) {
1127 /* This looks like STUN, give it to the STUN session */
1128 unsigned options;
1129
1130 options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
1131 if (is_datagram)
1132 options |= PJ_STUN_IS_DATAGRAM;
1133 status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
1134 options, NULL, parsed_len,
1135 sess->srv_addr,
1136 pj_sockaddr_get_len(sess->srv_addr));
1137
1138 } else {
1139 /* This must be ChannelData. */
1140 pj_turn_channel_data cd;
1141 struct ch_t *ch;
1142
1143 if (pkt_len < 4) {
1144 if (parsed_len) *parsed_len = 0;
1145 return PJ_ETOOSMALL;
1146 }
1147
1148 /* Decode ChannelData packet */
1149 pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data));
1150 cd.ch_number = pj_ntohs(cd.ch_number);
1151 cd.length = pj_ntohs(cd.length);
1152
1153 /* Check that size is sane */
1154 if (pkt_len < cd.length+sizeof(cd)) {
1155 if (parsed_len) {
1156 if (is_datagram) {
1157 /* Discard the datagram */
1158 *parsed_len = pkt_len;
1159 } else {
1160 /* Insufficient fragment */
1161 *parsed_len = 0;
1162 }
1163 }
1164 status = PJ_ETOOSMALL;
1165 goto on_return;
1166 } else {
1167 if (parsed_len) {
1168 /* Apply padding too */
1169 *parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd);
1170 }
1171 }
1172
1173 /* Lookup channel */
1174 ch = lookup_ch_by_chnum(sess, cd.ch_number);
1175 if (!ch || !ch->bound) {
1176 status = PJ_ENOTFOUND;
1177 goto on_return;
1178 }
1179
1180 /* Notify application */
1181 if (sess->cb.on_rx_data) {
1182 (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd),
1183 cd.length, &ch->addr,
1184 pj_sockaddr_get_len(&ch->addr));
1185 }
1186
1187 status = PJ_SUCCESS;
1188 }
1189
1190on_return:
1191 pj_grp_lock_release(sess->grp_lock);
1192 return status;
1193}
1194
1195
1196/*
1197 * This is a callback from STUN session to send outgoing packet.
1198 */
1199static pj_status_t stun_on_send_msg(pj_stun_session *stun,
1200 void *token,
1201 const void *pkt,
1202 pj_size_t pkt_size,
1203 const pj_sockaddr_t *dst_addr,
1204 unsigned addr_len)
1205{
1206 pj_turn_session *sess;
1207
1208 PJ_UNUSED_ARG(token);
1209
1210 sess = (pj_turn_session*) pj_stun_session_get_user_data(stun);
1211 return (*sess->cb.on_send_pkt)(sess, (const pj_uint8_t*)pkt,
1212 (unsigned)pkt_size,
1213 dst_addr, addr_len);
1214}
1215
1216
1217/*
1218 * Handle failed ALLOCATE or REFRESH request. This may switch to alternate
1219 * server if we have one.
1220 */
1221static void on_session_fail( pj_turn_session *sess,
1222 enum pj_stun_method_e method,
1223 pj_status_t status,
1224 const pj_str_t *reason)
1225{
1226 sess->last_status = status;
1227
1228 do {
1229 pj_str_t reason1;
1230 char err_msg[PJ_ERR_MSG_SIZE];
1231
1232 if (reason == NULL) {
1233 pj_strerror(status, err_msg, sizeof(err_msg));
1234 reason1 = pj_str(err_msg);
1235 reason = &reason1;
1236 }
1237
1238 PJ_LOG(4,(sess->obj_name, "%s error: %.*s",
1239 pj_stun_get_method_name(method),
1240 (int)reason->slen, reason->ptr));
1241
1242 /* If this is ALLOCATE response and we don't have more server
1243 * addresses to try, notify application and destroy the TURN
1244 * session.
1245 */
1246 if (method==PJ_STUN_ALLOCATE_METHOD &&
1247 sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1])
1248 {
1249
1250 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1251 sess_shutdown(sess, status);
1252 return;
1253 }
1254
1255 /* Otherwise if this is not ALLOCATE response, notify application
1256 * that session has been TERMINATED.
1257 */
1258 if (method!=PJ_STUN_ALLOCATE_METHOD) {
1259 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1260 sess_shutdown(sess, status);
1261 return;
1262 }
1263
1264 /* Try next server */
1265 ++sess->srv_addr;
1266 reason = NULL;
1267
1268 PJ_LOG(4,(sess->obj_name, "Trying next server"));
1269 set_state(sess, PJ_TURN_STATE_RESOLVED);
1270
1271 } while (0);
1272}
1273
1274
1275/*
1276 * Handle successful response to ALLOCATE or REFRESH request.
1277 */
1278static void on_allocate_success(pj_turn_session *sess,
1279 enum pj_stun_method_e method,
1280 const pj_stun_msg *msg)
1281{
1282 const pj_stun_lifetime_attr *lf_attr;
1283 const pj_stun_xor_relayed_addr_attr *raddr_attr;
1284 const pj_stun_sockaddr_attr *mapped_attr;
1285 pj_str_t s;
1286 pj_time_val timeout;
1287
1288 /* Must have LIFETIME attribute */
1289 lf_attr = (const pj_stun_lifetime_attr*)
1290 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1291 if (lf_attr == NULL) {
1292 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1293 pj_cstr(&s, "Error: Missing LIFETIME attribute"));
1294 return;
1295 }
1296
1297 /* If LIFETIME is zero, this is a deallocation */
1298 if (lf_attr->value == 0) {
1299 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1300 sess_shutdown(sess, PJ_SUCCESS);
1301 return;
1302 }
1303
1304 /* Update lifetime and keep-alive interval */
1305 sess->lifetime = lf_attr->value;
1306 pj_gettimeofday(&sess->expiry);
1307
1308 if (sess->lifetime < PJ_TURN_KEEP_ALIVE_SEC) {
1309 if (sess->lifetime <= 2) {
1310 on_session_fail(sess, method, PJ_ETOOSMALL,
1311 pj_cstr(&s, "Error: LIFETIME too small"));
1312 return;
1313 }
1314 sess->ka_interval = sess->lifetime - 2;
1315 sess->expiry.sec += (sess->ka_interval-1);
1316 } else {
1317 int timeout;
1318
1319 sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
1320
1321 timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE;
1322 if (timeout < sess->ka_interval)
1323 timeout = sess->ka_interval - 1;
1324
1325 sess->expiry.sec += timeout;
1326 }
1327
1328 /* Check that relayed transport address contains correct
1329 * address family.
1330 */
1331 raddr_attr = (const pj_stun_xor_relayed_addr_attr*)
1332 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_RELAYED_ADDR, 0);
1333 if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) {
1334 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1335 pj_cstr(&s, "Error: Received ALLOCATE without "
1336 "RELAY-ADDRESS attribute"));
1337 return;
1338 }
1339 if (raddr_attr && raddr_attr->sockaddr.addr.sa_family != sess->af) {
1340 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1341 pj_cstr(&s, "Error: RELAY-ADDRESS with non IPv4"
1342 " address family is not supported "
1343 "for now"));
1344 return;
1345 }
1346 if (raddr_attr && !pj_sockaddr_has_addr(&raddr_attr->sockaddr)) {
1347 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1348 pj_cstr(&s, "Error: Invalid IP address in "
1349 "RELAY-ADDRESS attribute"));
1350 return;
1351 }
1352
1353 /* Save relayed address */
1354 if (raddr_attr) {
1355 /* If we already have relay address, check if the relay address
1356 * in the response matches our relay address.
1357 */
1358 if (pj_sockaddr_has_addr(&sess->relay_addr)) {
1359 if (pj_sockaddr_cmp(&sess->relay_addr, &raddr_attr->sockaddr)) {
1360 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1361 pj_cstr(&s, "Error: different RELAY-ADDRESS is"
1362 "returned by server"));
1363 return;
1364 }
1365 } else {
1366 /* Otherwise save the relayed address */
1367 pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr,
1368 sizeof(pj_sockaddr));
1369 }
1370 }
1371
1372 /* Get mapped address */
1373 mapped_attr = (const pj_stun_sockaddr_attr*)
1374 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0);
1375 if (mapped_attr) {
1376 pj_memcpy(&sess->mapped_addr, &mapped_attr->sockaddr,
1377 sizeof(mapped_attr->sockaddr));
1378 }
1379
1380 /* Success */
1381
1382 /* Cancel existing keep-alive timer, if any */
1383 pj_assert(sess->timer.id != TIMER_DESTROY);
1384 if (sess->timer.id == TIMER_KEEP_ALIVE) {
1385 pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
1386 TIMER_NONE);
1387 }
1388
1389 /* Start keep-alive timer once allocation succeeds */
1390 if (sess->state < PJ_TURN_STATE_DEALLOCATING) {
1391 timeout.sec = sess->ka_interval;
1392 timeout.msec = 0;
1393
1394 pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
1395 &timeout, TIMER_KEEP_ALIVE,
1396 sess->grp_lock);
1397
1398 set_state(sess, PJ_TURN_STATE_READY);
1399 }
1400}
1401
1402/*
1403 * Notification from STUN session on request completion.
1404 */
1405static void stun_on_request_complete(pj_stun_session *stun,
1406 pj_status_t status,
1407 void *token,
1408 pj_stun_tx_data *tdata,
1409 const pj_stun_msg *response,
1410 const pj_sockaddr_t *src_addr,
1411 unsigned src_addr_len)
1412{
1413 pj_turn_session *sess;
1414 enum pj_stun_method_e method = (enum pj_stun_method_e)
1415 PJ_STUN_GET_METHOD(tdata->msg->hdr.type);
1416
1417 PJ_UNUSED_ARG(src_addr);
1418 PJ_UNUSED_ARG(src_addr_len);
1419
1420 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
1421
1422 if (method == PJ_STUN_ALLOCATE_METHOD) {
1423
1424 /* Destroy if we have pending destroy request */
1425 if (sess->pending_destroy) {
1426 if (status == PJ_SUCCESS)
1427 sess->state = PJ_TURN_STATE_READY;
1428 else
1429 sess->state = PJ_TURN_STATE_DEALLOCATED;
1430 sess_shutdown(sess, PJ_SUCCESS);
1431 return;
1432 }
1433
1434 /* Handle ALLOCATE response */
1435 if (status==PJ_SUCCESS &&
1436 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1437 {
1438
1439 /* Successful Allocate response */
1440 on_allocate_success(sess, method, response);
1441
1442 } else {
1443 /* Failed Allocate request */
1444 const pj_str_t *err_msg = NULL;
1445
1446 if (status == PJ_SUCCESS) {
1447 const pj_stun_errcode_attr *err_attr;
1448 err_attr = (const pj_stun_errcode_attr*)
1449 pj_stun_msg_find_attr(response,
1450 PJ_STUN_ATTR_ERROR_CODE, 0);
1451 if (err_attr) {
1452 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1453 err_msg = &err_attr->reason;
1454 } else {
1455 status = PJNATH_EINSTUNMSG;
1456 }
1457 }
1458
1459 on_session_fail(sess, method, status, err_msg);
1460 }
1461
1462 } else if (method == PJ_STUN_REFRESH_METHOD) {
1463 /* Handle Refresh response */
1464 if (status==PJ_SUCCESS &&
1465 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1466 {
1467 /* Success, schedule next refresh. */
1468 on_allocate_success(sess, method, response);
1469
1470 } else {
1471 /* Failed Refresh request */
1472 const pj_str_t *err_msg = NULL;
1473
1474 pj_assert(status != PJ_SUCCESS);
1475
1476 if (response) {
1477 const pj_stun_errcode_attr *err_attr;
1478 err_attr = (const pj_stun_errcode_attr*)
1479 pj_stun_msg_find_attr(response,
1480 PJ_STUN_ATTR_ERROR_CODE, 0);
1481 if (err_attr) {
1482 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1483 err_msg = &err_attr->reason;
1484 }
1485 }
1486
1487 /* Notify and destroy */
1488 on_session_fail(sess, method, status, err_msg);
1489 }
1490
1491 } else if (method == PJ_STUN_CHANNEL_BIND_METHOD) {
1492 /* Handle ChannelBind response */
1493 if (status==PJ_SUCCESS &&
1494 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1495 {
1496 /* Successful ChannelBind response */
1497 struct ch_t *ch = (struct ch_t*)token;
1498
1499 pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL);
1500 ch->bound = PJ_TRUE;
1501
1502 /* Update hash table */
1503 lookup_ch_by_addr(sess, &ch->addr,
1504 pj_sockaddr_get_len(&ch->addr),
1505 PJ_TRUE, PJ_TRUE);
1506
1507 } else {
1508 /* Failed ChannelBind response */
1509 pj_str_t reason = {"", 0};
1510 int err_code = 0;
1511 char errbuf[PJ_ERR_MSG_SIZE];
1512
1513 pj_assert(status != PJ_SUCCESS);
1514
1515 if (response) {
1516 const pj_stun_errcode_attr *err_attr;
1517 err_attr = (const pj_stun_errcode_attr*)
1518 pj_stun_msg_find_attr(response,
1519 PJ_STUN_ATTR_ERROR_CODE, 0);
1520 if (err_attr) {
1521 err_code = err_attr->err_code;
1522 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1523 reason = err_attr->reason;
1524 }
1525 } else {
1526 err_code = status;
1527 reason = pj_strerror(status, errbuf, sizeof(errbuf));
1528 }
1529
1530 PJ_LOG(1,(sess->obj_name, "ChannelBind failed: %d/%.*s",
1531 err_code, (int)reason.slen, reason.ptr));
1532
1533 if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
1534 /* Allocation mismatch means allocation no longer exists */
1535 on_session_fail(sess, PJ_STUN_CHANNEL_BIND_METHOD,
1536 status, &reason);
1537 return;
1538 }
1539 }
1540
1541 } else if (method == PJ_STUN_CREATE_PERM_METHOD) {
1542 /* Handle CreatePermission response */
1543 if (status==PJ_SUCCESS &&
1544 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1545 {
1546 /* No special handling when the request is successful. */
1547 } else {
1548 /* Iterate the permission table and invalidate all permissions
1549 * that are related to this request.
1550 */
1551 pj_hash_iterator_t it_buf, *it;
1552 char ipstr[PJ_INET6_ADDRSTRLEN+10];
1553 int err_code;
1554 char errbuf[PJ_ERR_MSG_SIZE];
1555 pj_str_t reason;
1556
1557 pj_assert(status != PJ_SUCCESS);
1558
1559 if (response) {
1560 const pj_stun_errcode_attr *eattr;
1561
1562 eattr = (const pj_stun_errcode_attr*)
1563 pj_stun_msg_find_attr(response,
1564 PJ_STUN_ATTR_ERROR_CODE, 0);
1565 if (eattr) {
1566 err_code = eattr->err_code;
1567 reason = eattr->reason;
1568 } else {
1569 err_code = -1;
1570 reason = pj_str("?");
1571 }
1572 } else {
1573 err_code = status;
1574 reason = pj_strerror(status, errbuf, sizeof(errbuf));
1575 }
1576
1577 it = pj_hash_first(sess->perm_table, &it_buf);
1578 while (it) {
1579 struct perm_t *perm = (struct perm_t*)
1580 pj_hash_this(sess->perm_table, it);
1581 it = pj_hash_next(sess->perm_table, it);
1582
1583 if (perm->req_token == token) {
1584 PJ_LOG(1,(sess->obj_name,
1585 "CreatePermission failed for IP %s: %d/%.*s",
1586 pj_sockaddr_print(&perm->addr, ipstr,
1587 sizeof(ipstr), 2),
1588 err_code, (int)reason.slen, reason.ptr));
1589
1590 invalidate_perm(sess, perm);
1591 }
1592 }
1593
1594 if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
1595 /* Allocation mismatch means allocation no longer exists */
1596 on_session_fail(sess, PJ_STUN_CREATE_PERM_METHOD,
1597 status, &reason);
1598 return;
1599 }
1600 }
1601
1602 } else {
1603 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response",
1604 pj_stun_get_method_name(response->hdr.type)));
1605 }
1606}
1607
1608
1609/*
1610 * Notification from STUN session on incoming STUN Indication
1611 * message.
1612 */
1613static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
1614 const pj_uint8_t *pkt,
1615 unsigned pkt_len,
1616 const pj_stun_msg *msg,
1617 void *token,
1618 const pj_sockaddr_t *src_addr,
1619 unsigned src_addr_len)
1620{
1621 pj_turn_session *sess;
1622 pj_stun_xor_peer_addr_attr *peer_attr;
1623 pj_stun_icmp_attr *icmp;
1624 pj_stun_data_attr *data_attr;
1625
1626 PJ_UNUSED_ARG(token);
1627 PJ_UNUSED_ARG(pkt);
1628 PJ_UNUSED_ARG(pkt_len);
1629 PJ_UNUSED_ARG(src_addr);
1630 PJ_UNUSED_ARG(src_addr_len);
1631
1632 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
1633
1634 /* Expecting Data Indication only */
1635 if (msg->hdr.type != PJ_STUN_DATA_INDICATION) {
1636 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication",
1637 pj_stun_get_method_name(msg->hdr.type)));
1638 return PJ_EINVALIDOP;
1639 }
1640
1641 /* Check if there is ICMP attribute in the message */
1642 icmp = (pj_stun_icmp_attr*)
1643 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICMP, 0);
1644 if (icmp != NULL) {
1645 /* This is a forwarded ICMP packet. Ignore it for now */
1646 return PJ_SUCCESS;
1647 }
1648
1649 /* Get XOR-PEER-ADDRESS attribute */
1650 peer_attr = (pj_stun_xor_peer_addr_attr*)
1651 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1652
1653 /* Get DATA attribute */
1654 data_attr = (pj_stun_data_attr*)
1655 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1656
1657 /* Must have both XOR-PEER-ADDRESS and DATA attributes */
1658 if (!peer_attr || !data_attr) {
1659 PJ_LOG(4,(sess->obj_name,
1660 "Received Data indication with missing attributes"));
1661 return PJ_EINVALIDOP;
1662 }
1663
1664 /* Notify application */
1665 if (sess->cb.on_rx_data) {
1666 (*sess->cb.on_rx_data)(sess, data_attr->data, data_attr->length,
1667 &peer_attr->sockaddr,
1668 pj_sockaddr_get_len(&peer_attr->sockaddr));
1669 }
1670
1671 return PJ_SUCCESS;
1672}
1673
1674
1675/*
1676 * Notification on completion of DNS SRV resolution.
1677 */
1678static void dns_srv_resolver_cb(void *user_data,
1679 pj_status_t status,
1680 const pj_dns_srv_record *rec)
1681{
1682 pj_turn_session *sess = (pj_turn_session*) user_data;
1683 unsigned i, cnt, tot_cnt;
1684
1685 /* Check failure */
1686 if (status != PJ_SUCCESS || sess->pending_destroy) {
1687 set_state(sess, PJ_TURN_STATE_DESTROYING);
1688 sess_shutdown(sess, status);
1689 return;
1690 }
1691
1692 /* Calculate total number of server entries in the response */
1693 tot_cnt = 0;
1694 for (i=0; i<rec->count; ++i) {
1695 tot_cnt += rec->entry[i].server.addr_count;
1696 }
1697
1698 if (tot_cnt > PJ_TURN_MAX_DNS_SRV_CNT)
1699 tot_cnt = PJ_TURN_MAX_DNS_SRV_CNT;
1700
1701 /* Allocate server entries */
1702 sess->srv_addr_list = (pj_sockaddr*)
1703 pj_pool_calloc(sess->pool, tot_cnt,
1704 sizeof(pj_sockaddr));
1705
1706 /* Copy results to server entries */
1707 for (i=0, cnt=0; i<rec->count && cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++i) {
1708 unsigned j;
1709
1710 for (j=0; j<rec->entry[i].server.addr_count &&
1711 cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++j)
1712 {
1713 pj_sockaddr_in *addr = &sess->srv_addr_list[cnt].ipv4;
1714
1715 addr->sin_family = sess->af;
1716 addr->sin_port = pj_htons(rec->entry[i].port);
1717 addr->sin_addr.s_addr = rec->entry[i].server.addr[j].s_addr;
1718
1719 ++cnt;
1720 }
1721 }
1722 sess->srv_addr_cnt = (pj_uint16_t)cnt;
1723
1724 /* Set current server */
1725 sess->srv_addr = &sess->srv_addr_list[0];
1726
1727 /* Set state to PJ_TURN_STATE_RESOLVED */
1728 set_state(sess, PJ_TURN_STATE_RESOLVED);
1729
1730 /* Run pending allocation */
1731 if (sess->pending_alloc) {
1732 pj_turn_session_alloc(sess, NULL);
1733 }
1734}
1735
1736
1737/*
1738 * Lookup peer descriptor from its address.
1739 */
1740static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
1741 const pj_sockaddr_t *addr,
1742 unsigned addr_len,
1743 pj_bool_t update,
1744 pj_bool_t bind_channel)
1745{
1746 pj_uint32_t hval = 0;
1747 struct ch_t *ch;
1748
1749 ch = (struct ch_t*)
1750 pj_hash_get(sess->ch_table, addr, addr_len, &hval);
1751 if (ch == NULL && update) {
1752 ch = PJ_POOL_ZALLOC_T(sess->pool, struct ch_t);
1753 ch->num = PJ_TURN_INVALID_CHANNEL;
1754 pj_memcpy(&ch->addr, addr, addr_len);
1755
1756 /* Register by peer address */
1757 pj_hash_set(sess->pool, sess->ch_table, &ch->addr, addr_len,
1758 hval, ch);
1759 }
1760
1761 if (ch && update) {
1762 pj_gettimeofday(&ch->expiry);
1763 ch->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1764
1765 if (bind_channel) {
1766 pj_uint32_t hval = 0;
1767 /* Register by channel number */
1768 pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound);
1769
1770 if (pj_hash_get(sess->ch_table, &ch->num,
1771 sizeof(ch->num), &hval)==0) {
1772 pj_hash_set(sess->pool, sess->ch_table, &ch->num,
1773 sizeof(ch->num), hval, ch);
1774 }
1775 }
1776 }
1777
1778 /* Also create/update permission for this destination. Ideally we
1779 * should update this when we receive the successful response,
1780 * but that would cause duplicate CreatePermission to be sent
1781 * during refreshing.
1782 */
1783 if (ch && update) {
1784 lookup_perm(sess, &ch->addr, pj_sockaddr_get_len(&ch->addr), PJ_TRUE);
1785 }
1786
1787 return ch;
1788}
1789
1790
1791/*
1792 * Lookup channel descriptor from its channel number.
1793 */
1794static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
1795 pj_uint16_t chnum)
1796{
1797 return (struct ch_t*) pj_hash_get(sess->ch_table, &chnum,
1798 sizeof(chnum), NULL);
1799}
1800
1801
1802/*
1803 * Lookup permission and optionally create if it doesn't exist.
1804 */
1805static struct perm_t *lookup_perm(pj_turn_session *sess,
1806 const pj_sockaddr_t *addr,
1807 unsigned addr_len,
1808 pj_bool_t update)
1809{
1810 pj_uint32_t hval = 0;
1811 pj_sockaddr perm_addr;
1812 struct perm_t *perm;
1813
1814 /* make sure port number if zero */
1815 if (pj_sockaddr_get_port(addr) != 0) {
1816 pj_memcpy(&perm_addr, addr, addr_len);
1817 pj_sockaddr_set_port(&perm_addr, 0);
1818 addr = &perm_addr;
1819 }
1820
1821 /* lookup and create if it doesn't exist and wanted */
1822 perm = (struct perm_t*)
1823 pj_hash_get(sess->perm_table, addr, addr_len, &hval);
1824 if (perm == NULL && update) {
1825 perm = PJ_POOL_ZALLOC_T(sess->pool, struct perm_t);
1826 pj_memcpy(&perm->addr, addr, addr_len);
1827 perm->hval = hval;
1828
1829 pj_hash_set(sess->pool, sess->perm_table, &perm->addr, addr_len,
1830 perm->hval, perm);
1831 }
1832
1833 if (perm && update) {
1834 pj_gettimeofday(&perm->expiry);
1835 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1836
1837 }
1838
1839 return perm;
1840}
1841
1842/*
1843 * Delete permission
1844 */
1845static void invalidate_perm(pj_turn_session *sess,
1846 struct perm_t *perm)
1847{
1848 pj_hash_set(NULL, sess->perm_table, &perm->addr,
1849 pj_sockaddr_get_len(&perm->addr), perm->hval, NULL);
1850}
1851
1852/*
1853 * Scan permission's hash table to refresh the permission.
1854 */
1855static unsigned refresh_permissions(pj_turn_session *sess,
1856 const pj_time_val *now)
1857{
1858 pj_stun_tx_data *tdata = NULL;
1859 unsigned count = 0;
1860 void *req_token = NULL;
1861 pj_hash_iterator_t *it, itbuf;
1862 pj_status_t status;
1863
1864 it = pj_hash_first(sess->perm_table, &itbuf);
1865 while (it) {
1866 struct perm_t *perm = (struct perm_t*)
1867 pj_hash_this(sess->perm_table, it);
1868
1869 it = pj_hash_next(sess->perm_table, it);
1870
1871 if (perm->expiry.sec-1 <= now->sec) {
1872 if (perm->renew) {
1873 /* Renew this permission */
1874 if (tdata == NULL) {
1875 /* Create a bare CreatePermission request */
1876 status = pj_stun_session_create_req(
1877 sess->stun,
1878 PJ_STUN_CREATE_PERM_REQUEST,
1879 PJ_STUN_MAGIC, NULL, &tdata);
1880 if (status != PJ_SUCCESS) {
1881 PJ_LOG(1,(sess->obj_name,
1882 "Error creating CreatePermission request: %d",
1883 status));
1884 return 0;
1885 }
1886
1887 /* Create request token to map the request to the perm
1888 * structures which the request belongs.
1889 */
1890 req_token = (void*)(pj_ssize_t)pj_rand();
1891 }
1892
1893 status = pj_stun_msg_add_sockaddr_attr(
1894 tdata->pool,
1895 tdata->msg,
1896 PJ_STUN_ATTR_XOR_PEER_ADDR,
1897 PJ_TRUE,
1898 &perm->addr,
1899 sizeof(perm->addr));
1900 if (status != PJ_SUCCESS) {
1901 pj_stun_msg_destroy_tdata(sess->stun, tdata);
1902 return 0;
1903 }
1904
1905 perm->expiry = *now;
1906 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT-sess->ka_interval-1;
1907 perm->req_token = req_token;
1908 ++count;
1909
1910 } else {
1911 /* This permission has expired and app doesn't want
1912 * us to renew, so delete it from the hash table.
1913 */
1914 invalidate_perm(sess, perm);
1915 }
1916 }
1917 }
1918
1919 if (tdata) {
1920 status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE,
1921 (sess->conn_type==PJ_TURN_TP_UDP),
1922 sess->srv_addr,
1923 pj_sockaddr_get_len(sess->srv_addr),
1924 tdata);
1925 if (status != PJ_SUCCESS) {
1926 PJ_LOG(1,(sess->obj_name,
1927 "Error sending CreatePermission request: %d",
1928 status));
1929 count = 0;
1930 }
1931
1932 }
1933
1934 return count;
1935}
1936
1937/*
1938 * Timer event.
1939 */
1940static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
1941{
1942 pj_turn_session *sess = (pj_turn_session*)e->user_data;
1943 enum timer_id_t eid;
1944
1945 PJ_UNUSED_ARG(th);
1946
1947 pj_grp_lock_acquire(sess->grp_lock);
1948
1949 eid = (enum timer_id_t) e->id;
1950 e->id = TIMER_NONE;
1951
1952 if (eid == TIMER_KEEP_ALIVE) {
1953 pj_time_val now;
1954 pj_hash_iterator_t itbuf, *it;
1955 pj_bool_t resched = PJ_TRUE;
1956 pj_bool_t pkt_sent = PJ_FALSE;
1957
1958 if (sess->state >= PJ_TURN_STATE_DEALLOCATING) {
1959 /* Ignore if we're deallocating */
1960 goto on_return;
1961 }
1962
1963 pj_gettimeofday(&now);
1964
1965 /* Refresh allocation if it's time to do so */
1966 if (PJ_TIME_VAL_LTE(sess->expiry, now)) {
1967 int lifetime = sess->alloc_param.lifetime;
1968
1969 if (lifetime == 0)
1970 lifetime = -1;
1971
1972 send_refresh(sess, lifetime);
1973 resched = PJ_FALSE;
1974 pkt_sent = PJ_TRUE;
1975 }
1976
1977 /* Scan hash table to refresh bound channels */
1978 it = pj_hash_first(sess->ch_table, &itbuf);
1979 while (it) {
1980 struct ch_t *ch = (struct ch_t*)
1981 pj_hash_this(sess->ch_table, it);
1982 if (ch->bound && PJ_TIME_VAL_LTE(ch->expiry, now)) {
1983
1984 /* Send ChannelBind to refresh channel binding and
1985 * permission.
1986 */
1987 pj_turn_session_bind_channel(sess, &ch->addr,
1988 pj_sockaddr_get_len(&ch->addr));
1989 pkt_sent = PJ_TRUE;
1990 }
1991
1992 it = pj_hash_next(sess->ch_table, it);
1993 }
1994
1995 /* Scan permission table to refresh permissions */
1996 if (refresh_permissions(sess, &now))
1997 pkt_sent = PJ_TRUE;
1998
1999 /* If no packet is sent, send a blank Send indication to
2000 * refresh local NAT.
2001 */
2002 if (!pkt_sent && sess->alloc_param.ka_interval > 0) {
2003 pj_stun_tx_data *tdata;
2004 pj_status_t rc;
2005
2006 /* Create blank SEND-INDICATION */
2007 rc = pj_stun_session_create_ind(sess->stun,
2008 PJ_STUN_SEND_INDICATION, &tdata);
2009 if (rc == PJ_SUCCESS) {
2010 /* Add DATA attribute with zero length */
2011 pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
2012 PJ_STUN_ATTR_DATA, NULL, 0);
2013
2014 /* Send the indication */
2015 pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
2016 PJ_FALSE, sess->srv_addr,
2017 pj_sockaddr_get_len(sess->srv_addr),
2018 tdata);
2019 }
2020 }
2021
2022 /* Reshcedule timer */
2023 if (resched) {
2024 pj_time_val delay;
2025
2026 delay.sec = sess->ka_interval;
2027 delay.msec = 0;
2028
2029 pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
2030 &delay, TIMER_KEEP_ALIVE,
2031 sess->grp_lock);
2032 }
2033
2034 } else if (eid == TIMER_DESTROY) {
2035 /* Time to destroy */
2036 do_destroy(sess);
2037 } else {
2038 pj_assert(!"Unknown timer event");
2039 }
2040
2041on_return:
2042 pj_grp_lock_release(sess->grp_lock);
2043}
2044