blob: 8ab3e3155340980453e49c0370e8fd98858d504e [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $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 * Get group lock.
530 */
531PJ_DEF(pj_grp_lock_t *) pj_turn_session_get_grp_lock(pj_turn_session *sess)
532{
533 PJ_ASSERT_RETURN(sess, NULL);
534 return sess->grp_lock;
535}
536
537/*
538 * Configure message logging. By default all flags are enabled.
539 *
540 * @param sess The TURN client session.
541 * @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
542 */
543PJ_DEF(void) pj_turn_session_set_log( pj_turn_session *sess,
544 unsigned flags)
545{
546 pj_stun_session_set_log(sess->stun, flags);
547}
548
549
550/*
551 * Set software name
552 */
553PJ_DEF(pj_status_t) pj_turn_session_set_software_name( pj_turn_session *sess,
554 const pj_str_t *sw)
555{
556 pj_status_t status;
557
558 pj_grp_lock_acquire(sess->grp_lock);
559 status = pj_stun_session_set_software_name(sess->stun, sw);
560 pj_grp_lock_release(sess->grp_lock);
561
562 return status;
563}
564
565
566/**
567 * Set the server or domain name of the server.
568 */
569PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
570 const pj_str_t *domain,
571 int default_port,
572 pj_dns_resolver *resolver)
573{
574 pj_sockaddr tmp_addr;
575 pj_bool_t is_ip_addr;
576 pj_status_t status;
577
578 PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
579 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP);
580
581 pj_grp_lock_acquire(sess->grp_lock);
582
583 /* See if "domain" contains just IP address */
584 tmp_addr.addr.sa_family = sess->af;
585 status = pj_inet_pton(sess->af, domain,
586 pj_sockaddr_get_addr(&tmp_addr));
587 is_ip_addr = (status == PJ_SUCCESS);
588
589 if (!is_ip_addr && resolver) {
590 /* Resolve with DNS SRV resolution, and fallback to DNS A resolution
591 * if default_port is specified.
592 */
593 unsigned opt = 0;
594 pj_str_t res_name;
595
596 switch (sess->conn_type) {
597 case PJ_TURN_TP_UDP:
598 res_name = pj_str("_turn._udp.");
599 break;
600 case PJ_TURN_TP_TCP:
601 res_name = pj_str("_turn._tcp.");
602 break;
603 case PJ_TURN_TP_TLS:
604 res_name = pj_str("_turns._tcp.");
605 break;
606 default:
607 status = PJNATH_ETURNINTP;
608 goto on_return;
609 }
610
611 /* Fallback to DNS A only if default port is specified */
612 if (default_port>0 && default_port<65536) {
613 opt = PJ_DNS_SRV_FALLBACK_A;
614 sess->default_port = (pj_uint16_t)default_port;
615 }
616
617 PJ_LOG(5,(sess->obj_name, "Resolving %.*s%.*s with DNS SRV",
618 (int)res_name.slen, res_name.ptr,
619 (int)domain->slen, domain->ptr));
620 set_state(sess, PJ_TURN_STATE_RESOLVING);
621
622 /* User may have destroyed us in the callback */
623 if (sess->state != PJ_TURN_STATE_RESOLVING) {
624 status = PJ_ECANCELLED;
625 goto on_return;
626 }
627
628 status = pj_dns_srv_resolve(domain, &res_name, default_port,
629 sess->pool, resolver, opt, sess,
630 &dns_srv_resolver_cb, NULL);
631 if (status != PJ_SUCCESS) {
632 set_state(sess, PJ_TURN_STATE_NULL);
633 goto on_return;
634 }
635
636 } else {
637 /* Resolver is not specified, resolve with standard gethostbyname().
638 * The default_port MUST be specified in this case.
639 */
640 pj_addrinfo *ai;
641 unsigned i, cnt;
642
643 /* Default port must be specified */
644 PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
645 sess->default_port = (pj_uint16_t)default_port;
646
647 cnt = PJ_TURN_MAX_DNS_SRV_CNT;
648 ai = (pj_addrinfo*)
649 pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));
650
651 PJ_LOG(5,(sess->obj_name, "Resolving %.*s with DNS A",
652 (int)domain->slen, domain->ptr));
653 set_state(sess, PJ_TURN_STATE_RESOLVING);
654
655 /* User may have destroyed us in the callback */
656 if (sess->state != PJ_TURN_STATE_RESOLVING) {
657 status = PJ_ECANCELLED;
658 goto on_return;
659 }
660
661 status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
662 if (status != PJ_SUCCESS)
663 goto on_return;
664
665 sess->srv_addr_cnt = (pj_uint16_t)cnt;
666 sess->srv_addr_list = (pj_sockaddr*)
667 pj_pool_calloc(sess->pool, cnt,
668 sizeof(pj_sockaddr));
669 for (i=0; i<cnt; ++i) {
670 pj_sockaddr *addr = &sess->srv_addr_list[i];
671 pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
672 addr->addr.sa_family = sess->af;
673 addr->ipv4.sin_port = pj_htons(sess->default_port);
674 }
675
676 sess->srv_addr = &sess->srv_addr_list[0];
677 set_state(sess, PJ_TURN_STATE_RESOLVED);
678 }
679
680on_return:
681 pj_grp_lock_release(sess->grp_lock);
682 return status;
683}
684
685
686/**
687 * Set credential to be used by the session.
688 */
689PJ_DEF(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
690 const pj_stun_auth_cred *cred)
691{
692 PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
693 PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);
694
695 pj_grp_lock_acquire(sess->grp_lock);
696
697 pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);
698
699 pj_grp_lock_release(sess->grp_lock);
700
701 return PJ_SUCCESS;
702}
703
704
705/**
706 * Create TURN allocation.
707 */
708PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
709 const pj_turn_alloc_param *param)
710{
711 pj_stun_tx_data *tdata;
712 pj_bool_t retransmit;
713 pj_status_t status;
714
715 PJ_ASSERT_RETURN(sess, PJ_EINVAL);
716 PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL &&
717 sess->state<=PJ_TURN_STATE_RESOLVED,
718 PJ_EINVALIDOP);
719
720 pj_grp_lock_acquire(sess->grp_lock);
721
722 if (param && param != &sess->alloc_param)
723 pj_turn_alloc_param_copy(sess->pool, &sess->alloc_param, param);
724
725 if (sess->state < PJ_TURN_STATE_RESOLVED) {
726 sess->pending_alloc = PJ_TRUE;
727
728 PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s",
729 state_names[sess->state]));
730
731 pj_grp_lock_release(sess->grp_lock);
732 return PJ_SUCCESS;
733
734 }
735
736 /* Ready to allocate */
737 pj_assert(sess->state == PJ_TURN_STATE_RESOLVED);
738
739 /* Create a bare request */
740 status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST,
741 PJ_STUN_MAGIC, NULL, &tdata);
742 if (status != PJ_SUCCESS) {
743 pj_grp_lock_release(sess->grp_lock);
744 return status;
745 }
746
747 /* MUST include REQUESTED-TRANSPORT attribute */
748 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
749 PJ_STUN_ATTR_REQ_TRANSPORT,
750 PJ_STUN_SET_RT_PROTO(PJ_TURN_TP_UDP));
751
752 /* Include BANDWIDTH if requested */
753 if (sess->alloc_param.bandwidth > 0) {
754 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
755 PJ_STUN_ATTR_BANDWIDTH,
756 sess->alloc_param.bandwidth);
757 }
758
759 /* Include LIFETIME if requested */
760 if (sess->alloc_param.lifetime > 0) {
761 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
762 PJ_STUN_ATTR_LIFETIME,
763 sess->alloc_param.lifetime);
764 }
765
766 /* Server address must be set */
767 pj_assert(sess->srv_addr != NULL);
768
769 /* Send request */
770 set_state(sess, PJ_TURN_STATE_ALLOCATING);
771 retransmit = (sess->conn_type == PJ_TURN_TP_UDP);
772 status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
773 retransmit, sess->srv_addr,
774 pj_sockaddr_get_len(sess->srv_addr),
775 tdata);
776 if (status != PJ_SUCCESS) {
777 /* Set state back to RESOLVED. We don't want to destroy session now,
778 * let the application do it if it wants to.
779 */
780 set_state(sess, PJ_TURN_STATE_RESOLVED);
781 }
782
783 pj_grp_lock_release(sess->grp_lock);
784 return status;
785}
786
787
788/*
789 * Install or renew permissions
790 */
791PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
792 unsigned addr_cnt,
793 const pj_sockaddr addr[],
794 unsigned options)
795{
796 pj_stun_tx_data *tdata;
797 pj_hash_iterator_t it_buf, *it;
798 void *req_token;
799 unsigned i, attr_added=0;
800 pj_status_t status;
801
802 PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL);
803
804 pj_grp_lock_acquire(sess->grp_lock);
805
806 /* Create a bare CreatePermission request */
807 status = pj_stun_session_create_req(sess->stun,
808 PJ_STUN_CREATE_PERM_REQUEST,
809 PJ_STUN_MAGIC, NULL, &tdata);
810 if (status != PJ_SUCCESS) {
811 pj_grp_lock_release(sess->grp_lock);
812 return status;
813 }
814
815 /* Create request token to map the request to the perm structures
816 * which the request belongs.
817 */
818 req_token = (void*)(pj_ssize_t)pj_rand();
819
820 /* Process the addresses */
821 for (i=0; i<addr_cnt; ++i) {
822 struct perm_t *perm;
823
824 /* Lookup the perm structure and create if it doesn't exist */
825 perm = lookup_perm(sess, &addr[i], pj_sockaddr_get_len(&addr[i]),
826 PJ_TRUE);
827 perm->renew = (options & 0x01);
828
829 /* Only add to the request if the request doesn't contain this
830 * address yet.
831 */
832 if (perm->req_token != req_token) {
833 perm->req_token = req_token;
834
835 /* Add XOR-PEER-ADDRESS */
836 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
837 PJ_STUN_ATTR_XOR_PEER_ADDR,
838 PJ_TRUE,
839 &addr[i],
840 sizeof(addr[i]));
841 if (status != PJ_SUCCESS)
842 goto on_error;
843
844 ++attr_added;
845 }
846 }
847
848 pj_assert(attr_added != 0);
849
850 /* Send the request */
851 status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE,
852 (sess->conn_type==PJ_TURN_TP_UDP),
853 sess->srv_addr,
854 pj_sockaddr_get_len(sess->srv_addr),
855 tdata);
856 if (status != PJ_SUCCESS) {
857 /* tdata is already destroyed */
858 tdata = NULL;
859 goto on_error;
860 }
861
862 pj_grp_lock_release(sess->grp_lock);
863 return PJ_SUCCESS;
864
865on_error:
866 /* destroy tdata */
867 if (tdata) {
868 pj_stun_msg_destroy_tdata(sess->stun, tdata);
869 }
870 /* invalidate perm structures associated with this request */
871 it = pj_hash_first(sess->perm_table, &it_buf);
872 while (it) {
873 struct perm_t *perm = (struct perm_t*)
874 pj_hash_this(sess->perm_table, it);
875 it = pj_hash_next(sess->perm_table, it);
876 if (perm->req_token == req_token)
877 invalidate_perm(sess, perm);
878 }
879 pj_grp_lock_release(sess->grp_lock);
880 return status;
881}
882
883/*
884 * Send REFRESH
885 */
886static void send_refresh(pj_turn_session *sess, int lifetime)
887{
888 pj_stun_tx_data *tdata;
889 pj_status_t status;
890
891 PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return);
892
893 /* Create a bare REFRESH request */
894 status = pj_stun_session_create_req(sess->stun, PJ_STUN_REFRESH_REQUEST,
895 PJ_STUN_MAGIC, NULL, &tdata);
896 if (status != PJ_SUCCESS)
897 goto on_error;
898
899 /* Add LIFETIME */
900 if (lifetime >= 0) {
901 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
902 PJ_STUN_ATTR_LIFETIME, lifetime);
903 }
904
905 /* Send request */
906 if (lifetime == 0) {
907 set_state(sess, PJ_TURN_STATE_DEALLOCATING);
908 }
909
910 status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
911 (sess->conn_type==PJ_TURN_TP_UDP),
912 sess->srv_addr,
913 pj_sockaddr_get_len(sess->srv_addr),
914 tdata);
915 if (status != PJ_SUCCESS)
916 goto on_error;
917
918 return;
919
920on_error:
921 if (lifetime == 0) {
922 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
923 sess_shutdown(sess, status);
924 }
925}
926
927
928/**
929 * Relay data to the specified peer through the session.
930 */
931PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
932 const pj_uint8_t *pkt,
933 unsigned pkt_len,
934 const pj_sockaddr_t *addr,
935 unsigned addr_len)
936{
937 struct ch_t *ch;
938 struct perm_t *perm;
939 pj_status_t status;
940
941 PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len,
942 PJ_EINVAL);
943
944 /* Return error if we're not ready */
945 if (sess->state != PJ_TURN_STATE_READY) {
946 return PJ_EIGNORED;
947 }
948
949 /* Lock session now */
950 pj_grp_lock_acquire(sess->grp_lock);
951
952 /* Lookup permission first */
953 perm = lookup_perm(sess, addr, pj_sockaddr_get_len(addr), PJ_FALSE);
954 if (perm == NULL) {
955 /* Permission doesn't exist, install it first */
956 char ipstr[PJ_INET6_ADDRSTRLEN+2];
957
958 PJ_LOG(4,(sess->obj_name,
959 "sendto(): IP %s has no permission, requesting it first..",
960 pj_sockaddr_print(addr, ipstr, sizeof(ipstr), 2)));
961
962 status = pj_turn_session_set_perm(sess, 1, (const pj_sockaddr*)addr,
963 0);
964 if (status != PJ_SUCCESS) {
965 pj_grp_lock_release(sess->grp_lock);
966 return status;
967 }
968 }
969
970 /* See if the peer is bound to a channel number */
971 ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr),
972 PJ_FALSE, PJ_FALSE);
973 if (ch && ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound) {
974 unsigned total_len;
975
976 /* Peer is assigned a channel number, we can use ChannelData */
977 pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt;
978
979 pj_assert(sizeof(*cd)==4);
980
981 /* Calculate total length, including paddings */
982 total_len = (pkt_len + sizeof(*cd) + 3) & (~3);
983 if (total_len > sizeof(sess->tx_pkt)) {
984 status = PJ_ETOOBIG;
985 goto on_return;
986 }
987
988 cd->ch_number = pj_htons((pj_uint16_t)ch->num);
989 cd->length = pj_htons((pj_uint16_t)pkt_len);
990 pj_memcpy(cd+1, pkt, pkt_len);
991
992 pj_assert(sess->srv_addr != NULL);
993
994 status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len,
995 sess->srv_addr,
996 pj_sockaddr_get_len(sess->srv_addr));
997
998 } else {
999 /* Use Send Indication. */
1000 pj_stun_sockaddr_attr peer_attr;
1001 pj_stun_binary_attr data_attr;
1002 pj_stun_msg send_ind;
1003 pj_size_t send_ind_len;
1004
1005 /* Increment counter */
1006 ++sess->send_ind_tsx_id[2];
1007
1008 /* Create blank SEND-INDICATION */
1009 status = pj_stun_msg_init(&send_ind, PJ_STUN_SEND_INDICATION,
1010 PJ_STUN_MAGIC,
1011 (const pj_uint8_t*)sess->send_ind_tsx_id);
1012 if (status != PJ_SUCCESS)
1013 goto on_return;
1014
1015 /* Add XOR-PEER-ADDRESS */
1016 pj_stun_sockaddr_attr_init(&peer_attr, PJ_STUN_ATTR_XOR_PEER_ADDR,
1017 PJ_TRUE, addr, addr_len);
1018 pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&peer_attr);
1019
1020 /* Add DATA attribute */
1021 pj_stun_binary_attr_init(&data_attr, NULL, PJ_STUN_ATTR_DATA, NULL, 0);
1022 data_attr.data = (pj_uint8_t*)pkt;
1023 data_attr.length = pkt_len;
1024 pj_stun_msg_add_attr(&send_ind, (pj_stun_attr_hdr*)&data_attr);
1025
1026 /* Encode the message */
1027 status = pj_stun_msg_encode(&send_ind, sess->tx_pkt,
1028 sizeof(sess->tx_pkt), 0,
1029 NULL, &send_ind_len);
1030 if (status != PJ_SUCCESS)
1031 goto on_return;
1032
1033 /* Send the Send Indication */
1034 status = sess->cb.on_send_pkt(sess, sess->tx_pkt,
1035 (unsigned)send_ind_len,
1036 sess->srv_addr,
1037 pj_sockaddr_get_len(sess->srv_addr));
1038 }
1039
1040on_return:
1041 pj_grp_lock_release(sess->grp_lock);
1042 return status;
1043}
1044
1045
1046/**
1047 * Bind a peer address to a channel number.
1048 */
1049PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
1050 const pj_sockaddr_t *peer_adr,
1051 unsigned addr_len)
1052{
1053 struct ch_t *ch;
1054 pj_stun_tx_data *tdata;
1055 pj_uint16_t ch_num;
1056 pj_status_t status;
1057
1058 PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL);
1059 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP);
1060
1061 pj_grp_lock_acquire(sess->grp_lock);
1062
1063 /* Create blank ChannelBind request */
1064 status = pj_stun_session_create_req(sess->stun,
1065 PJ_STUN_CHANNEL_BIND_REQUEST,
1066 PJ_STUN_MAGIC, NULL, &tdata);
1067 if (status != PJ_SUCCESS)
1068 goto on_return;
1069
1070 /* Lookup if this peer has already been assigned a number */
1071 ch = lookup_ch_by_addr(sess, peer_adr, pj_sockaddr_get_len(peer_adr),
1072 PJ_TRUE, PJ_FALSE);
1073 pj_assert(ch);
1074
1075 if (ch->num != PJ_TURN_INVALID_CHANNEL) {
1076 /* Channel is already bound. This is a refresh request. */
1077 ch_num = ch->num;
1078 } else {
1079 PJ_ASSERT_ON_FAIL(sess->next_ch <= PJ_TURN_CHANNEL_MAX,
1080 {status=PJ_ETOOMANY; goto on_return;});
1081 ch->num = ch_num = sess->next_ch++;
1082 }
1083
1084 /* Add CHANNEL-NUMBER attribute */
1085 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
1086 PJ_STUN_ATTR_CHANNEL_NUMBER,
1087 PJ_STUN_SET_CH_NB(ch_num));
1088
1089 /* Add XOR-PEER-ADDRESS attribute */
1090 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
1091 PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
1092 peer_adr, addr_len);
1093
1094 /* Send the request, associate peer data structure with tdata
1095 * for future reference when we receive the ChannelBind response.
1096 */
1097 status = pj_stun_session_send_msg(sess->stun, ch, PJ_FALSE,
1098 (sess->conn_type==PJ_TURN_TP_UDP),
1099 sess->srv_addr,
1100 pj_sockaddr_get_len(sess->srv_addr),
1101 tdata);
1102
1103on_return:
1104 pj_grp_lock_release(sess->grp_lock);
1105 return status;
1106}
1107
1108
1109/**
1110 * Notify TURN client session upon receiving a packet from server.
1111 * The packet maybe a STUN packet or ChannelData packet.
1112 */
1113PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
1114 void *pkt,
1115 pj_size_t pkt_len,
1116 pj_size_t *parsed_len)
1117{
1118 pj_bool_t is_stun;
1119 pj_status_t status;
1120 pj_bool_t is_datagram;
1121
1122 /* Packet could be ChannelData or STUN message (response or
1123 * indication).
1124 */
1125
1126 /* Start locking the session */
1127 pj_grp_lock_acquire(sess->grp_lock);
1128
1129 is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
1130
1131 /* Quickly check if this is STUN message */
1132 is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
1133
1134 if (is_stun) {
1135 /* This looks like STUN, give it to the STUN session */
1136 unsigned options;
1137
1138 options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
1139 if (is_datagram)
1140 options |= PJ_STUN_IS_DATAGRAM;
1141 status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
1142 options, NULL, parsed_len,
1143 sess->srv_addr,
1144 pj_sockaddr_get_len(sess->srv_addr));
1145
1146 } else {
1147 /* This must be ChannelData. */
1148 pj_turn_channel_data cd;
1149 struct ch_t *ch;
1150
1151 if (pkt_len < 4) {
1152 if (parsed_len) *parsed_len = 0;
1153 return PJ_ETOOSMALL;
1154 }
1155
1156 /* Decode ChannelData packet */
1157 pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data));
1158 cd.ch_number = pj_ntohs(cd.ch_number);
1159 cd.length = pj_ntohs(cd.length);
1160
1161 /* Check that size is sane */
1162 if (pkt_len < cd.length+sizeof(cd)) {
1163 if (parsed_len) {
1164 if (is_datagram) {
1165 /* Discard the datagram */
1166 *parsed_len = pkt_len;
1167 } else {
1168 /* Insufficient fragment */
1169 *parsed_len = 0;
1170 }
1171 }
1172 status = PJ_ETOOSMALL;
1173 goto on_return;
1174 } else {
1175 if (parsed_len) {
1176 /* Apply padding too */
1177 *parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd);
1178 }
1179 }
1180
1181 /* Lookup channel */
1182 ch = lookup_ch_by_chnum(sess, cd.ch_number);
1183 if (!ch || !ch->bound) {
1184 status = PJ_ENOTFOUND;
1185 goto on_return;
1186 }
1187
1188 /* Notify application */
1189 if (sess->cb.on_rx_data) {
1190 (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd),
1191 cd.length, &ch->addr,
1192 pj_sockaddr_get_len(&ch->addr));
1193 }
1194
1195 status = PJ_SUCCESS;
1196 }
1197
1198on_return:
1199 pj_grp_lock_release(sess->grp_lock);
1200 return status;
1201}
1202
1203
1204/*
1205 * This is a callback from STUN session to send outgoing packet.
1206 */
1207static pj_status_t stun_on_send_msg(pj_stun_session *stun,
1208 void *token,
1209 const void *pkt,
1210 pj_size_t pkt_size,
1211 const pj_sockaddr_t *dst_addr,
1212 unsigned addr_len)
1213{
1214 pj_turn_session *sess;
1215
1216 PJ_UNUSED_ARG(token);
1217
1218 sess = (pj_turn_session*) pj_stun_session_get_user_data(stun);
1219 return (*sess->cb.on_send_pkt)(sess, (const pj_uint8_t*)pkt,
1220 (unsigned)pkt_size,
1221 dst_addr, addr_len);
1222}
1223
1224
1225/*
1226 * Handle failed ALLOCATE or REFRESH request. This may switch to alternate
1227 * server if we have one.
1228 */
1229static void on_session_fail( pj_turn_session *sess,
1230 enum pj_stun_method_e method,
1231 pj_status_t status,
1232 const pj_str_t *reason)
1233{
1234 sess->last_status = status;
1235
1236 do {
1237 pj_str_t reason1;
1238 char err_msg[PJ_ERR_MSG_SIZE];
1239
1240 if (reason == NULL) {
1241 pj_strerror(status, err_msg, sizeof(err_msg));
1242 reason1 = pj_str(err_msg);
1243 reason = &reason1;
1244 }
1245
1246 PJ_LOG(4,(sess->obj_name, "%s error: %.*s",
1247 pj_stun_get_method_name(method),
1248 (int)reason->slen, reason->ptr));
1249
1250 /* If this is ALLOCATE response and we don't have more server
1251 * addresses to try, notify application and destroy the TURN
1252 * session.
1253 */
1254 if (method==PJ_STUN_ALLOCATE_METHOD &&
1255 sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1])
1256 {
1257
1258 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1259 sess_shutdown(sess, status);
1260 return;
1261 }
1262
1263 /* Otherwise if this is not ALLOCATE response, notify application
1264 * that session has been TERMINATED.
1265 */
1266 if (method!=PJ_STUN_ALLOCATE_METHOD) {
1267 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1268 sess_shutdown(sess, status);
1269 return;
1270 }
1271
1272 /* Try next server */
1273 ++sess->srv_addr;
1274 reason = NULL;
1275
1276 PJ_LOG(4,(sess->obj_name, "Trying next server"));
1277 set_state(sess, PJ_TURN_STATE_RESOLVED);
1278
1279 } while (0);
1280}
1281
1282
1283/*
1284 * Handle successful response to ALLOCATE or REFRESH request.
1285 */
1286static void on_allocate_success(pj_turn_session *sess,
1287 enum pj_stun_method_e method,
1288 const pj_stun_msg *msg)
1289{
1290 const pj_stun_lifetime_attr *lf_attr;
1291 const pj_stun_xor_relayed_addr_attr *raddr_attr;
1292 const pj_stun_sockaddr_attr *mapped_attr;
1293 pj_str_t s;
1294 pj_time_val timeout;
1295
1296 /* Must have LIFETIME attribute */
1297 lf_attr = (const pj_stun_lifetime_attr*)
1298 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1299 if (lf_attr == NULL) {
1300 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1301 pj_cstr(&s, "Error: Missing LIFETIME attribute"));
1302 return;
1303 }
1304
1305 /* If LIFETIME is zero, this is a deallocation */
1306 if (lf_attr->value == 0) {
1307 set_state(sess, PJ_TURN_STATE_DEALLOCATED);
1308 sess_shutdown(sess, PJ_SUCCESS);
1309 return;
1310 }
1311
1312 /* Update lifetime and keep-alive interval */
1313 sess->lifetime = lf_attr->value;
1314 pj_gettimeofday(&sess->expiry);
1315
1316 if (sess->lifetime < PJ_TURN_KEEP_ALIVE_SEC) {
1317 if (sess->lifetime <= 2) {
1318 on_session_fail(sess, method, PJ_ETOOSMALL,
1319 pj_cstr(&s, "Error: LIFETIME too small"));
1320 return;
1321 }
1322 sess->ka_interval = sess->lifetime - 2;
1323 sess->expiry.sec += (sess->ka_interval-1);
1324 } else {
1325 int timeout;
1326
1327 sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
1328
1329 timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE;
1330 if (timeout < sess->ka_interval)
1331 timeout = sess->ka_interval - 1;
1332
1333 sess->expiry.sec += timeout;
1334 }
1335
1336 /* Check that relayed transport address contains correct
1337 * address family.
1338 */
1339 raddr_attr = (const pj_stun_xor_relayed_addr_attr*)
1340 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_RELAYED_ADDR, 0);
1341 if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) {
1342 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1343 pj_cstr(&s, "Error: Received ALLOCATE without "
1344 "RELAY-ADDRESS attribute"));
1345 return;
1346 }
1347 if (raddr_attr && raddr_attr->sockaddr.addr.sa_family != sess->af) {
1348 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1349 pj_cstr(&s, "Error: RELAY-ADDRESS with non IPv4"
1350 " address family is not supported "
1351 "for now"));
1352 return;
1353 }
1354 if (raddr_attr && !pj_sockaddr_has_addr(&raddr_attr->sockaddr)) {
1355 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1356 pj_cstr(&s, "Error: Invalid IP address in "
1357 "RELAY-ADDRESS attribute"));
1358 return;
1359 }
1360
1361 /* Save relayed address */
1362 if (raddr_attr) {
1363 /* If we already have relay address, check if the relay address
1364 * in the response matches our relay address.
1365 */
1366 if (pj_sockaddr_has_addr(&sess->relay_addr)) {
1367 if (pj_sockaddr_cmp(&sess->relay_addr, &raddr_attr->sockaddr)) {
1368 on_session_fail(sess, method, PJNATH_EINSTUNMSG,
1369 pj_cstr(&s, "Error: different RELAY-ADDRESS is"
1370 "returned by server"));
1371 return;
1372 }
1373 } else {
1374 /* Otherwise save the relayed address */
1375 pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr,
1376 sizeof(pj_sockaddr));
1377 }
1378 }
1379
1380 /* Get mapped address */
1381 mapped_attr = (const pj_stun_sockaddr_attr*)
1382 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0);
1383 if (mapped_attr) {
1384 pj_memcpy(&sess->mapped_addr, &mapped_attr->sockaddr,
1385 sizeof(mapped_attr->sockaddr));
1386 }
1387
1388 /* Success */
1389
1390 /* Cancel existing keep-alive timer, if any */
1391 pj_assert(sess->timer.id != TIMER_DESTROY);
1392 if (sess->timer.id == TIMER_KEEP_ALIVE) {
1393 pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
1394 TIMER_NONE);
1395 }
1396
1397 /* Start keep-alive timer once allocation succeeds */
1398 if (sess->state < PJ_TURN_STATE_DEALLOCATING) {
1399 timeout.sec = sess->ka_interval;
1400 timeout.msec = 0;
1401
1402 pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
1403 &timeout, TIMER_KEEP_ALIVE,
1404 sess->grp_lock);
1405
1406 set_state(sess, PJ_TURN_STATE_READY);
1407 }
1408}
1409
1410/*
1411 * Notification from STUN session on request completion.
1412 */
1413static void stun_on_request_complete(pj_stun_session *stun,
1414 pj_status_t status,
1415 void *token,
1416 pj_stun_tx_data *tdata,
1417 const pj_stun_msg *response,
1418 const pj_sockaddr_t *src_addr,
1419 unsigned src_addr_len)
1420{
1421 pj_turn_session *sess;
1422 enum pj_stun_method_e method = (enum pj_stun_method_e)
1423 PJ_STUN_GET_METHOD(tdata->msg->hdr.type);
1424
1425 PJ_UNUSED_ARG(src_addr);
1426 PJ_UNUSED_ARG(src_addr_len);
1427
1428 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
1429
1430 if (method == PJ_STUN_ALLOCATE_METHOD) {
1431
1432 /* Destroy if we have pending destroy request */
1433 if (sess->pending_destroy) {
1434 if (status == PJ_SUCCESS)
1435 sess->state = PJ_TURN_STATE_READY;
1436 else
1437 sess->state = PJ_TURN_STATE_DEALLOCATED;
1438 sess_shutdown(sess, PJ_SUCCESS);
1439 return;
1440 }
1441
1442 /* Handle ALLOCATE response */
1443 if (status==PJ_SUCCESS &&
1444 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1445 {
1446
1447 /* Successful Allocate response */
1448 on_allocate_success(sess, method, response);
1449
1450 } else {
1451 /* Failed Allocate request */
1452 const pj_str_t *err_msg = NULL;
1453
1454 if (status == PJ_SUCCESS) {
1455 const pj_stun_errcode_attr *err_attr;
1456 err_attr = (const pj_stun_errcode_attr*)
1457 pj_stun_msg_find_attr(response,
1458 PJ_STUN_ATTR_ERROR_CODE, 0);
1459 if (err_attr) {
1460 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1461 err_msg = &err_attr->reason;
1462 } else {
1463 status = PJNATH_EINSTUNMSG;
1464 }
1465 }
1466
1467 on_session_fail(sess, method, status, err_msg);
1468 }
1469
1470 } else if (method == PJ_STUN_REFRESH_METHOD) {
1471 /* Handle Refresh response */
1472 if (status==PJ_SUCCESS &&
1473 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1474 {
1475 /* Success, schedule next refresh. */
1476 on_allocate_success(sess, method, response);
1477
1478 } else {
1479 /* Failed Refresh request */
1480 const pj_str_t *err_msg = NULL;
1481
1482 pj_assert(status != PJ_SUCCESS);
1483
1484 if (response) {
1485 const pj_stun_errcode_attr *err_attr;
1486 err_attr = (const pj_stun_errcode_attr*)
1487 pj_stun_msg_find_attr(response,
1488 PJ_STUN_ATTR_ERROR_CODE, 0);
1489 if (err_attr) {
1490 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1491 err_msg = &err_attr->reason;
1492 }
1493 }
1494
1495 /* Notify and destroy */
1496 on_session_fail(sess, method, status, err_msg);
1497 }
1498
1499 } else if (method == PJ_STUN_CHANNEL_BIND_METHOD) {
1500 /* Handle ChannelBind response */
1501 if (status==PJ_SUCCESS &&
1502 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1503 {
1504 /* Successful ChannelBind response */
1505 struct ch_t *ch = (struct ch_t*)token;
1506
1507 pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL);
1508 ch->bound = PJ_TRUE;
1509
1510 /* Update hash table */
1511 lookup_ch_by_addr(sess, &ch->addr,
1512 pj_sockaddr_get_len(&ch->addr),
1513 PJ_TRUE, PJ_TRUE);
1514
1515 } else {
1516 /* Failed ChannelBind response */
1517 pj_str_t reason = {"", 0};
1518 int err_code = 0;
1519 char errbuf[PJ_ERR_MSG_SIZE];
1520
1521 pj_assert(status != PJ_SUCCESS);
1522
1523 if (response) {
1524 const pj_stun_errcode_attr *err_attr;
1525 err_attr = (const pj_stun_errcode_attr*)
1526 pj_stun_msg_find_attr(response,
1527 PJ_STUN_ATTR_ERROR_CODE, 0);
1528 if (err_attr) {
1529 err_code = err_attr->err_code;
1530 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
1531 reason = err_attr->reason;
1532 }
1533 } else {
1534 err_code = status;
1535 reason = pj_strerror(status, errbuf, sizeof(errbuf));
1536 }
1537
1538 PJ_LOG(1,(sess->obj_name, "ChannelBind failed: %d/%.*s",
1539 err_code, (int)reason.slen, reason.ptr));
1540
1541 if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
1542 /* Allocation mismatch means allocation no longer exists */
1543 on_session_fail(sess, PJ_STUN_CHANNEL_BIND_METHOD,
1544 status, &reason);
1545 return;
1546 }
1547 }
1548
1549 } else if (method == PJ_STUN_CREATE_PERM_METHOD) {
1550 /* Handle CreatePermission response */
1551 if (status==PJ_SUCCESS &&
1552 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
1553 {
1554 /* No special handling when the request is successful. */
1555 } else {
1556 /* Iterate the permission table and invalidate all permissions
1557 * that are related to this request.
1558 */
1559 pj_hash_iterator_t it_buf, *it;
1560 char ipstr[PJ_INET6_ADDRSTRLEN+10];
1561 int err_code;
1562 char errbuf[PJ_ERR_MSG_SIZE];
1563 pj_str_t reason;
1564
1565 pj_assert(status != PJ_SUCCESS);
1566
1567 if (response) {
1568 const pj_stun_errcode_attr *eattr;
1569
1570 eattr = (const pj_stun_errcode_attr*)
1571 pj_stun_msg_find_attr(response,
1572 PJ_STUN_ATTR_ERROR_CODE, 0);
1573 if (eattr) {
1574 err_code = eattr->err_code;
1575 reason = eattr->reason;
1576 } else {
1577 err_code = -1;
1578 reason = pj_str("?");
1579 }
1580 } else {
1581 err_code = status;
1582 reason = pj_strerror(status, errbuf, sizeof(errbuf));
1583 }
1584
1585 it = pj_hash_first(sess->perm_table, &it_buf);
1586 while (it) {
1587 struct perm_t *perm = (struct perm_t*)
1588 pj_hash_this(sess->perm_table, it);
1589 it = pj_hash_next(sess->perm_table, it);
1590
1591 if (perm->req_token == token) {
1592 PJ_LOG(1,(sess->obj_name,
1593 "CreatePermission failed for IP %s: %d/%.*s",
1594 pj_sockaddr_print(&perm->addr, ipstr,
1595 sizeof(ipstr), 2),
1596 err_code, (int)reason.slen, reason.ptr));
1597
1598 invalidate_perm(sess, perm);
1599 }
1600 }
1601
1602 if (err_code == PJ_STUN_SC_ALLOCATION_MISMATCH) {
1603 /* Allocation mismatch means allocation no longer exists */
1604 on_session_fail(sess, PJ_STUN_CREATE_PERM_METHOD,
1605 status, &reason);
1606 return;
1607 }
1608 }
1609
1610 } else {
1611 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response",
1612 pj_stun_get_method_name(response->hdr.type)));
1613 }
1614}
1615
1616
1617/*
1618 * Notification from STUN session on incoming STUN Indication
1619 * message.
1620 */
1621static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
1622 const pj_uint8_t *pkt,
1623 unsigned pkt_len,
1624 const pj_stun_msg *msg,
1625 void *token,
1626 const pj_sockaddr_t *src_addr,
1627 unsigned src_addr_len)
1628{
1629 pj_turn_session *sess;
1630 pj_stun_xor_peer_addr_attr *peer_attr;
1631 pj_stun_icmp_attr *icmp;
1632 pj_stun_data_attr *data_attr;
1633
1634 PJ_UNUSED_ARG(token);
1635 PJ_UNUSED_ARG(pkt);
1636 PJ_UNUSED_ARG(pkt_len);
1637 PJ_UNUSED_ARG(src_addr);
1638 PJ_UNUSED_ARG(src_addr_len);
1639
1640 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
1641
1642 /* Expecting Data Indication only */
1643 if (msg->hdr.type != PJ_STUN_DATA_INDICATION) {
1644 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication",
1645 pj_stun_get_method_name(msg->hdr.type)));
1646 return PJ_EINVALIDOP;
1647 }
1648
1649 /* Check if there is ICMP attribute in the message */
1650 icmp = (pj_stun_icmp_attr*)
1651 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICMP, 0);
1652 if (icmp != NULL) {
1653 /* This is a forwarded ICMP packet. Ignore it for now */
1654 return PJ_SUCCESS;
1655 }
1656
1657 /* Get XOR-PEER-ADDRESS attribute */
1658 peer_attr = (pj_stun_xor_peer_addr_attr*)
1659 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1660
1661 /* Get DATA attribute */
1662 data_attr = (pj_stun_data_attr*)
1663 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1664
1665 /* Must have both XOR-PEER-ADDRESS and DATA attributes */
1666 if (!peer_attr || !data_attr) {
1667 PJ_LOG(4,(sess->obj_name,
1668 "Received Data indication with missing attributes"));
1669 return PJ_EINVALIDOP;
1670 }
1671
1672 /* Notify application */
1673 if (sess->cb.on_rx_data) {
1674 (*sess->cb.on_rx_data)(sess, data_attr->data, data_attr->length,
1675 &peer_attr->sockaddr,
1676 pj_sockaddr_get_len(&peer_attr->sockaddr));
1677 }
1678
1679 return PJ_SUCCESS;
1680}
1681
1682
1683/*
1684 * Notification on completion of DNS SRV resolution.
1685 */
1686static void dns_srv_resolver_cb(void *user_data,
1687 pj_status_t status,
1688 const pj_dns_srv_record *rec)
1689{
1690 pj_turn_session *sess = (pj_turn_session*) user_data;
1691 unsigned i, cnt, tot_cnt;
1692
1693 /* Check failure */
1694 if (status != PJ_SUCCESS || sess->pending_destroy) {
1695 set_state(sess, PJ_TURN_STATE_DESTROYING);
1696 sess_shutdown(sess, status);
1697 return;
1698 }
1699
1700 /* Calculate total number of server entries in the response */
1701 tot_cnt = 0;
1702 for (i=0; i<rec->count; ++i) {
1703 tot_cnt += rec->entry[i].server.addr_count;
1704 }
1705
1706 if (tot_cnt > PJ_TURN_MAX_DNS_SRV_CNT)
1707 tot_cnt = PJ_TURN_MAX_DNS_SRV_CNT;
1708
1709 /* Allocate server entries */
1710 sess->srv_addr_list = (pj_sockaddr*)
1711 pj_pool_calloc(sess->pool, tot_cnt,
1712 sizeof(pj_sockaddr));
1713
1714 /* Copy results to server entries */
1715 for (i=0, cnt=0; i<rec->count && cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++i) {
1716 unsigned j;
1717
1718 for (j=0; j<rec->entry[i].server.addr_count &&
1719 cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++j)
1720 {
1721 pj_sockaddr_in *addr = &sess->srv_addr_list[cnt].ipv4;
1722
1723 addr->sin_family = sess->af;
1724 addr->sin_port = pj_htons(rec->entry[i].port);
1725 addr->sin_addr.s_addr = rec->entry[i].server.addr[j].s_addr;
1726
1727 ++cnt;
1728 }
1729 }
1730 sess->srv_addr_cnt = (pj_uint16_t)cnt;
1731
1732 /* Set current server */
1733 sess->srv_addr = &sess->srv_addr_list[0];
1734
1735 /* Set state to PJ_TURN_STATE_RESOLVED */
1736 set_state(sess, PJ_TURN_STATE_RESOLVED);
1737
1738 /* Run pending allocation */
1739 if (sess->pending_alloc) {
1740 pj_turn_session_alloc(sess, NULL);
1741 }
1742}
1743
1744
1745/*
1746 * Lookup peer descriptor from its address.
1747 */
1748static struct ch_t *lookup_ch_by_addr(pj_turn_session *sess,
1749 const pj_sockaddr_t *addr,
1750 unsigned addr_len,
1751 pj_bool_t update,
1752 pj_bool_t bind_channel)
1753{
1754 pj_uint32_t hval = 0;
1755 struct ch_t *ch;
1756
1757 ch = (struct ch_t*)
1758 pj_hash_get(sess->ch_table, addr, addr_len, &hval);
1759 if (ch == NULL && update) {
1760 ch = PJ_POOL_ZALLOC_T(sess->pool, struct ch_t);
1761 ch->num = PJ_TURN_INVALID_CHANNEL;
1762 pj_memcpy(&ch->addr, addr, addr_len);
1763
1764 /* Register by peer address */
1765 pj_hash_set(sess->pool, sess->ch_table, &ch->addr, addr_len,
1766 hval, ch);
1767 }
1768
1769 if (ch && update) {
1770 pj_gettimeofday(&ch->expiry);
1771 ch->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1772
1773 if (bind_channel) {
1774 pj_uint32_t hval = 0;
1775 /* Register by channel number */
1776 pj_assert(ch->num != PJ_TURN_INVALID_CHANNEL && ch->bound);
1777
1778 if (pj_hash_get(sess->ch_table, &ch->num,
1779 sizeof(ch->num), &hval)==0) {
1780 pj_hash_set(sess->pool, sess->ch_table, &ch->num,
1781 sizeof(ch->num), hval, ch);
1782 }
1783 }
1784 }
1785
1786 /* Also create/update permission for this destination. Ideally we
1787 * should update this when we receive the successful response,
1788 * but that would cause duplicate CreatePermission to be sent
1789 * during refreshing.
1790 */
1791 if (ch && update) {
1792 lookup_perm(sess, &ch->addr, pj_sockaddr_get_len(&ch->addr), PJ_TRUE);
1793 }
1794
1795 return ch;
1796}
1797
1798
1799/*
1800 * Lookup channel descriptor from its channel number.
1801 */
1802static struct ch_t *lookup_ch_by_chnum(pj_turn_session *sess,
1803 pj_uint16_t chnum)
1804{
1805 return (struct ch_t*) pj_hash_get(sess->ch_table, &chnum,
1806 sizeof(chnum), NULL);
1807}
1808
1809
1810/*
1811 * Lookup permission and optionally create if it doesn't exist.
1812 */
1813static struct perm_t *lookup_perm(pj_turn_session *sess,
1814 const pj_sockaddr_t *addr,
1815 unsigned addr_len,
1816 pj_bool_t update)
1817{
1818 pj_uint32_t hval = 0;
1819 pj_sockaddr perm_addr;
1820 struct perm_t *perm;
1821
1822 /* make sure port number if zero */
1823 if (pj_sockaddr_get_port(addr) != 0) {
1824 pj_memcpy(&perm_addr, addr, addr_len);
1825 pj_sockaddr_set_port(&perm_addr, 0);
1826 addr = &perm_addr;
1827 }
1828
1829 /* lookup and create if it doesn't exist and wanted */
1830 perm = (struct perm_t*)
1831 pj_hash_get(sess->perm_table, addr, addr_len, &hval);
1832 if (perm == NULL && update) {
1833 perm = PJ_POOL_ZALLOC_T(sess->pool, struct perm_t);
1834 pj_memcpy(&perm->addr, addr, addr_len);
1835 perm->hval = hval;
1836
1837 pj_hash_set(sess->pool, sess->perm_table, &perm->addr, addr_len,
1838 perm->hval, perm);
1839 }
1840
1841 if (perm && update) {
1842 pj_gettimeofday(&perm->expiry);
1843 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT - sess->ka_interval - 1;
1844
1845 }
1846
1847 return perm;
1848}
1849
1850/*
1851 * Delete permission
1852 */
1853static void invalidate_perm(pj_turn_session *sess,
1854 struct perm_t *perm)
1855{
1856 pj_hash_set(NULL, sess->perm_table, &perm->addr,
1857 pj_sockaddr_get_len(&perm->addr), perm->hval, NULL);
1858}
1859
1860/*
1861 * Scan permission's hash table to refresh the permission.
1862 */
1863static unsigned refresh_permissions(pj_turn_session *sess,
1864 const pj_time_val *now)
1865{
1866 pj_stun_tx_data *tdata = NULL;
1867 unsigned count = 0;
1868 void *req_token = NULL;
1869 pj_hash_iterator_t *it, itbuf;
1870 pj_status_t status;
1871
1872 it = pj_hash_first(sess->perm_table, &itbuf);
1873 while (it) {
1874 struct perm_t *perm = (struct perm_t*)
1875 pj_hash_this(sess->perm_table, it);
1876
1877 it = pj_hash_next(sess->perm_table, it);
1878
1879 if (perm->expiry.sec-1 <= now->sec) {
1880 if (perm->renew) {
1881 /* Renew this permission */
1882 if (tdata == NULL) {
1883 /* Create a bare CreatePermission request */
1884 status = pj_stun_session_create_req(
1885 sess->stun,
1886 PJ_STUN_CREATE_PERM_REQUEST,
1887 PJ_STUN_MAGIC, NULL, &tdata);
1888 if (status != PJ_SUCCESS) {
1889 PJ_LOG(1,(sess->obj_name,
1890 "Error creating CreatePermission request: %d",
1891 status));
1892 return 0;
1893 }
1894
1895 /* Create request token to map the request to the perm
1896 * structures which the request belongs.
1897 */
1898 req_token = (void*)(pj_ssize_t)pj_rand();
1899 }
1900
1901 status = pj_stun_msg_add_sockaddr_attr(
1902 tdata->pool,
1903 tdata->msg,
1904 PJ_STUN_ATTR_XOR_PEER_ADDR,
1905 PJ_TRUE,
1906 &perm->addr,
1907 sizeof(perm->addr));
1908 if (status != PJ_SUCCESS) {
1909 pj_stun_msg_destroy_tdata(sess->stun, tdata);
1910 return 0;
1911 }
1912
1913 perm->expiry = *now;
1914 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT-sess->ka_interval-1;
1915 perm->req_token = req_token;
1916 ++count;
1917
1918 } else {
1919 /* This permission has expired and app doesn't want
1920 * us to renew, so delete it from the hash table.
1921 */
1922 invalidate_perm(sess, perm);
1923 }
1924 }
1925 }
1926
1927 if (tdata) {
1928 status = pj_stun_session_send_msg(sess->stun, req_token, PJ_FALSE,
1929 (sess->conn_type==PJ_TURN_TP_UDP),
1930 sess->srv_addr,
1931 pj_sockaddr_get_len(sess->srv_addr),
1932 tdata);
1933 if (status != PJ_SUCCESS) {
1934 PJ_LOG(1,(sess->obj_name,
1935 "Error sending CreatePermission request: %d",
1936 status));
1937 count = 0;
1938 }
1939
1940 }
1941
1942 return count;
1943}
1944
1945/*
1946 * Timer event.
1947 */
1948static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
1949{
1950 pj_turn_session *sess = (pj_turn_session*)e->user_data;
1951 enum timer_id_t eid;
1952
1953 PJ_UNUSED_ARG(th);
1954
1955 pj_grp_lock_acquire(sess->grp_lock);
1956
1957 eid = (enum timer_id_t) e->id;
1958 e->id = TIMER_NONE;
1959
1960 if (eid == TIMER_KEEP_ALIVE) {
1961 pj_time_val now;
1962 pj_hash_iterator_t itbuf, *it;
1963 pj_bool_t resched = PJ_TRUE;
1964 pj_bool_t pkt_sent = PJ_FALSE;
1965
1966 if (sess->state >= PJ_TURN_STATE_DEALLOCATING) {
1967 /* Ignore if we're deallocating */
1968 goto on_return;
1969 }
1970
1971 pj_gettimeofday(&now);
1972
1973 /* Refresh allocation if it's time to do so */
1974 if (PJ_TIME_VAL_LTE(sess->expiry, now)) {
1975 int lifetime = sess->alloc_param.lifetime;
1976
1977 if (lifetime == 0)
1978 lifetime = -1;
1979
1980 send_refresh(sess, lifetime);
1981 resched = PJ_FALSE;
1982 pkt_sent = PJ_TRUE;
1983 }
1984
1985 /* Scan hash table to refresh bound channels */
1986 it = pj_hash_first(sess->ch_table, &itbuf);
1987 while (it) {
1988 struct ch_t *ch = (struct ch_t*)
1989 pj_hash_this(sess->ch_table, it);
1990 if (ch->bound && PJ_TIME_VAL_LTE(ch->expiry, now)) {
1991
1992 /* Send ChannelBind to refresh channel binding and
1993 * permission.
1994 */
1995 pj_turn_session_bind_channel(sess, &ch->addr,
1996 pj_sockaddr_get_len(&ch->addr));
1997 pkt_sent = PJ_TRUE;
1998 }
1999
2000 it = pj_hash_next(sess->ch_table, it);
2001 }
2002
2003 /* Scan permission table to refresh permissions */
2004 if (refresh_permissions(sess, &now))
2005 pkt_sent = PJ_TRUE;
2006
2007 /* If no packet is sent, send a blank Send indication to
2008 * refresh local NAT.
2009 */
2010 if (!pkt_sent && sess->alloc_param.ka_interval > 0) {
2011 pj_stun_tx_data *tdata;
2012 pj_status_t rc;
2013
2014 /* Create blank SEND-INDICATION */
2015 rc = pj_stun_session_create_ind(sess->stun,
2016 PJ_STUN_SEND_INDICATION, &tdata);
2017 if (rc == PJ_SUCCESS) {
2018 /* Add DATA attribute with zero length */
2019 pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
2020 PJ_STUN_ATTR_DATA, NULL, 0);
2021
2022 /* Send the indication */
2023 pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
2024 PJ_FALSE, sess->srv_addr,
2025 pj_sockaddr_get_len(sess->srv_addr),
2026 tdata);
2027 }
2028 }
2029
2030 /* Reshcedule timer */
2031 if (resched) {
2032 pj_time_val delay;
2033
2034 delay.sec = sess->ka_interval;
2035 delay.msec = 0;
2036
2037 pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
2038 &delay, TIMER_KEEP_ALIVE,
2039 sess->grp_lock);
2040 }
2041
2042 } else if (eid == TIMER_DESTROY) {
2043 /* Time to destroy */
2044 do_destroy(sess);
2045 } else {
2046 pj_assert(!"Unknown timer event");
2047 }
2048
2049on_return:
2050 pj_grp_lock_release(sess->grp_lock);
2051}
2052