blob: c51527db51157b538995c454cefee5848d3205a9 [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/stun_sock.h>
21#include <pjnath/errno.h>
22#include <pjnath/stun_transaction.h>
23#include <pjnath/stun_session.h>
24#include <pjlib-util/srv_resolver.h>
25#include <pj/activesock.h>
26#include <pj/addr_resolv.h>
27#include <pj/array.h>
28#include <pj/assert.h>
29#include <pj/ip_helper.h>
30#include <pj/log.h>
31#include <pj/os.h>
32#include <pj/pool.h>
33#include <pj/rand.h>
34
35#if 1
36# define TRACE_(x) PJ_LOG(5,x)
37#else
38# define TRACE_(x)
39#endif
40
41enum { MAX_BIND_RETRY = 100 };
42
43struct pj_stun_sock
44{
45 char *obj_name; /* Log identification */
46 pj_pool_t *pool; /* Pool */
47 void *user_data; /* Application user data */
48 pj_bool_t is_destroying; /* Destroy already called */
49 int af; /* Address family */
50 pj_stun_config stun_cfg; /* STUN config (ioqueue etc)*/
51 pj_stun_sock_cb cb; /* Application callbacks */
52
53 int ka_interval; /* Keep alive interval */
54 pj_timer_entry ka_timer; /* Keep alive timer. */
55
56 pj_sockaddr srv_addr; /* Resolved server addr */
57 pj_sockaddr mapped_addr; /* Our public address */
58
59 pj_dns_srv_async_query *q; /* Pending DNS query */
60 pj_sock_t sock_fd; /* Socket descriptor */
61 pj_activesock_t *active_sock; /* Active socket object */
62 pj_ioqueue_op_key_t send_key; /* Default send key for app */
63 pj_ioqueue_op_key_t int_send_key; /* Send key for internal */
64
65 pj_uint16_t tsx_id[6]; /* .. to match STUN msg */
66 pj_stun_session *stun_sess; /* STUN session */
67 pj_grp_lock_t *grp_lock; /* Session group lock */
68};
69
70/*
71 * Prototypes for static functions
72 */
73
74/* Destructor for group lock */
75static void stun_sock_destructor(void *obj);
76
77/* This callback is called by the STUN session to send packet */
78static pj_status_t sess_on_send_msg(pj_stun_session *sess,
79 void *token,
80 const void *pkt,
81 pj_size_t pkt_size,
82 const pj_sockaddr_t *dst_addr,
83 unsigned addr_len);
84
85/* This callback is called by the STUN session when outgoing transaction
86 * is complete
87 */
88static void sess_on_request_complete(pj_stun_session *sess,
89 pj_status_t status,
90 void *token,
91 pj_stun_tx_data *tdata,
92 const pj_stun_msg *response,
93 const pj_sockaddr_t *src_addr,
94 unsigned src_addr_len);
95/* DNS resolver callback */
96static void dns_srv_resolver_cb(void *user_data,
97 pj_status_t status,
98 const pj_dns_srv_record *rec);
99
100/* Start sending STUN Binding request */
101static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock);
102
103/* Callback from active socket when incoming packet is received */
104static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
105 void *data,
106 pj_size_t size,
107 const pj_sockaddr_t *src_addr,
108 int addr_len,
109 pj_status_t status);
110
111/* Callback from active socket about send status */
112static pj_bool_t on_data_sent(pj_activesock_t *asock,
113 pj_ioqueue_op_key_t *send_key,
114 pj_ssize_t sent);
115
116/* Schedule keep-alive timer */
117static void start_ka_timer(pj_stun_sock *stun_sock);
118
119/* Keep-alive timer callback */
120static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
121
122#define INTERNAL_MSG_TOKEN (void*)(pj_ssize_t)1
123
124
125/*
126 * Retrieve the name representing the specified operation.
127 */
128PJ_DEF(const char*) pj_stun_sock_op_name(pj_stun_sock_op op)
129{
130 const char *names[] = {
131 "?",
132 "DNS resolution",
133 "STUN Binding request",
134 "Keep-alive",
135 "Mapped addr. changed"
136 };
137
138 return op < PJ_ARRAY_SIZE(names) ? names[op] : "???";
139};
140
141
142/*
143 * Initialize the STUN transport setting with its default values.
144 */
145PJ_DEF(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg)
146{
147 pj_bzero(cfg, sizeof(*cfg));
148 cfg->max_pkt_size = PJ_STUN_SOCK_PKT_LEN;
149 cfg->async_cnt = 1;
150 cfg->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
151 cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT;
152 cfg->qos_ignore_error = PJ_TRUE;
153}
154
155
156/* Check that configuration setting is valid */
157static pj_bool_t pj_stun_sock_cfg_is_valid(const pj_stun_sock_cfg *cfg)
158{
159 return cfg->max_pkt_size > 1 && cfg->async_cnt >= 1;
160}
161
162/*
163 * Create the STUN transport using the specified configuration.
164 */
165PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
166 const char *name,
167 int af,
168 const pj_stun_sock_cb *cb,
169 const pj_stun_sock_cfg *cfg,
170 void *user_data,
171 pj_stun_sock **p_stun_sock)
172{
173 pj_pool_t *pool;
174 pj_stun_sock *stun_sock;
175 pj_stun_sock_cfg default_cfg;
176 pj_sockaddr bound_addr;
177 unsigned i;
178 pj_uint16_t max_bind_retry;
179 pj_status_t status;
180
181 PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL);
182 PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP);
183 PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL);
184 PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL);
185
186 status = pj_stun_config_check_valid(stun_cfg);
187 if (status != PJ_SUCCESS)
188 return status;
189
190 if (name == NULL)
191 name = "stuntp%p";
192
193 if (cfg == NULL) {
194 pj_stun_sock_cfg_default(&default_cfg);
195 cfg = &default_cfg;
196 }
197
198
199 /* Create structure */
200 pool = pj_pool_create(stun_cfg->pf, name, 256, 512, NULL);
201 stun_sock = PJ_POOL_ZALLOC_T(pool, pj_stun_sock);
202 stun_sock->pool = pool;
203 stun_sock->obj_name = pool->obj_name;
204 stun_sock->user_data = user_data;
205 stun_sock->af = af;
206 stun_sock->sock_fd = PJ_INVALID_SOCKET;
207 pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg));
208 pj_memcpy(&stun_sock->cb, cb, sizeof(*cb));
209
210 stun_sock->ka_interval = cfg->ka_interval;
211 if (stun_sock->ka_interval == 0)
212 stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
213
214 if (cfg->grp_lock) {
215 stun_sock->grp_lock = cfg->grp_lock;
216 } else {
217 status = pj_grp_lock_create(pool, NULL, &stun_sock->grp_lock);
218 if (status != PJ_SUCCESS) {
219 pj_pool_release(pool);
220 return status;
221 }
222 }
223
224 pj_grp_lock_add_ref(stun_sock->grp_lock);
225 pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock,
226 &stun_sock_destructor);
227
228 /* Create socket and bind socket */
229 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd);
230 if (status != PJ_SUCCESS)
231 goto on_error;
232
233 /* Apply QoS, if specified */
234 status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type,
235 &cfg->qos_params, 2, stun_sock->obj_name,
236 NULL);
237 if (status != PJ_SUCCESS && !cfg->qos_ignore_error)
238 goto on_error;
239
240 /* Apply socket buffer size */
241 if (cfg->so_rcvbuf_size > 0) {
242 unsigned sobuf_size = cfg->so_rcvbuf_size;
243 status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_RCVBUF(),
244 PJ_TRUE, &sobuf_size);
245 if (status != PJ_SUCCESS) {
246 pj_perror(3, stun_sock->obj_name, status,
247 "Failed setting SO_RCVBUF");
248 } else {
249 if (sobuf_size < cfg->so_rcvbuf_size) {
250 PJ_LOG(4, (stun_sock->obj_name,
251 "Warning! Cannot set SO_RCVBUF as configured, "
252 "now=%d, configured=%d",
253 sobuf_size, cfg->so_rcvbuf_size));
254 } else {
255 PJ_LOG(5, (stun_sock->obj_name, "SO_RCVBUF set to %d",
256 sobuf_size));
257 }
258 }
259 }
260 if (cfg->so_sndbuf_size > 0) {
261 unsigned sobuf_size = cfg->so_sndbuf_size;
262 status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(),
263 PJ_TRUE, &sobuf_size);
264 if (status != PJ_SUCCESS) {
265 pj_perror(3, stun_sock->obj_name, status,
266 "Failed setting SO_SNDBUF");
267 } else {
268 if (sobuf_size < cfg->so_sndbuf_size) {
269 PJ_LOG(4, (stun_sock->obj_name,
270 "Warning! Cannot set SO_SNDBUF as configured, "
271 "now=%d, configured=%d",
272 sobuf_size, cfg->so_sndbuf_size));
273 } else {
274 PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d",
275 sobuf_size));
276 }
277 }
278 }
279
280 /* Bind socket */
281 max_bind_retry = MAX_BIND_RETRY;
282 if (cfg->port_range && cfg->port_range < max_bind_retry)
283 max_bind_retry = cfg->port_range;
284 pj_sockaddr_init(af, &bound_addr, NULL, 0);
285 if (cfg->bound_addr.addr.sa_family == pj_AF_INET() ||
286 cfg->bound_addr.addr.sa_family == pj_AF_INET6())
287 {
288 pj_sockaddr_cp(&bound_addr, &cfg->bound_addr);
289 }
290 status = pj_sock_bind_random(stun_sock->sock_fd, &bound_addr,
291 cfg->port_range, max_bind_retry);
292 if (status != PJ_SUCCESS)
293 goto on_error;
294
295 /* Create more useful information string about this transport */
296#if 0
297 {
298 pj_sockaddr bound_addr;
299 int addr_len = sizeof(bound_addr);
300
301 status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr,
302 &addr_len);
303 if (status != PJ_SUCCESS)
304 goto on_error;
305
306 stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10);
307 pj_sockaddr_print(&bound_addr, stun_sock->info,
308 PJ_INET6_ADDRSTRLEN, 3);
309 }
310#endif
311
312 /* Init active socket configuration */
313 {
314 pj_activesock_cfg activesock_cfg;
315 pj_activesock_cb activesock_cb;
316
317 pj_activesock_cfg_default(&activesock_cfg);
318 activesock_cfg.grp_lock = stun_sock->grp_lock;
319 activesock_cfg.async_cnt = cfg->async_cnt;
320 activesock_cfg.concurrency = 0;
321
322 /* Create the active socket */
323 pj_bzero(&activesock_cb, sizeof(activesock_cb));
324 activesock_cb.on_data_recvfrom = &on_data_recvfrom;
325 activesock_cb.on_data_sent = &on_data_sent;
326 status = pj_activesock_create(pool, stun_sock->sock_fd,
327 pj_SOCK_DGRAM(),
328 &activesock_cfg, stun_cfg->ioqueue,
329 &activesock_cb, stun_sock,
330 &stun_sock->active_sock);
331 if (status != PJ_SUCCESS)
332 goto on_error;
333
334 /* Start asynchronous read operations */
335 status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool,
336 cfg->max_pkt_size, 0);
337 if (status != PJ_SUCCESS)
338 goto on_error;
339
340 /* Init send keys */
341 pj_ioqueue_op_key_init(&stun_sock->send_key,
342 sizeof(stun_sock->send_key));
343 pj_ioqueue_op_key_init(&stun_sock->int_send_key,
344 sizeof(stun_sock->int_send_key));
345 }
346
347 /* Create STUN session */
348 {
349 pj_stun_session_cb sess_cb;
350
351 pj_bzero(&sess_cb, sizeof(sess_cb));
352 sess_cb.on_request_complete = &sess_on_request_complete;
353 sess_cb.on_send_msg = &sess_on_send_msg;
354 status = pj_stun_session_create(&stun_sock->stun_cfg,
355 stun_sock->obj_name,
356 &sess_cb, PJ_FALSE,
357 stun_sock->grp_lock,
358 &stun_sock->stun_sess);
359 if (status != PJ_SUCCESS)
360 goto on_error;
361 }
362
363 /* Associate us with the STUN session */
364 pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock);
365
366 /* Initialize random numbers to be used as STUN transaction ID for
367 * outgoing Binding request. We use the 80bit number to distinguish
368 * STUN messages we sent with STUN messages that the application sends.
369 * The last 16bit value in the array is a counter.
370 */
371 for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) {
372 stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand();
373 }
374 stun_sock->tsx_id[5] = 0;
375
376
377 /* Init timer entry */
378 stun_sock->ka_timer.cb = &ka_timer_cb;
379 stun_sock->ka_timer.user_data = stun_sock;
380
381 /* Done */
382 *p_stun_sock = stun_sock;
383 return PJ_SUCCESS;
384
385on_error:
386 pj_stun_sock_destroy(stun_sock);
387 return status;
388}
389
390/* Start socket. */
391PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
392 const pj_str_t *domain,
393 pj_uint16_t default_port,
394 pj_dns_resolver *resolver)
395{
396 pj_status_t status;
397
398 PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL);
399
400 pj_grp_lock_acquire(stun_sock->grp_lock);
401
402 /* Check whether the domain contains IP address */
403 stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af;
404 status = pj_inet_pton(stun_sock->af, domain,
405 pj_sockaddr_get_addr(&stun_sock->srv_addr));
406 if (status != PJ_SUCCESS) {
407 stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)0;
408 }
409
410 /* If resolver is set, try to resolve with DNS SRV first. It
411 * will fallback to DNS A/AAAA when no SRV record is found.
412 */
413 if (status != PJ_SUCCESS && resolver) {
414 const pj_str_t res_name = pj_str("_stun._udp.");
415 unsigned opt;
416
417 pj_assert(stun_sock->q == NULL);
418
419 opt = PJ_DNS_SRV_FALLBACK_A;
420 if (stun_sock->af == pj_AF_INET6()) {
421 opt |= (PJ_DNS_SRV_RESOLVE_AAAA | PJ_DNS_SRV_FALLBACK_AAAA);
422 }
423
424 status = pj_dns_srv_resolve(domain, &res_name, default_port,
425 stun_sock->pool, resolver, opt,
426 stun_sock, &dns_srv_resolver_cb,
427 &stun_sock->q);
428
429 /* Processing will resume when the DNS SRV callback is called */
430
431 } else {
432
433 if (status != PJ_SUCCESS) {
434 pj_addrinfo ai;
435 unsigned cnt = 1;
436
437 status = pj_getaddrinfo(stun_sock->af, domain, &cnt, &ai);
438 if (status != PJ_SUCCESS)
439 return status;
440
441 pj_sockaddr_cp(&stun_sock->srv_addr, &ai.ai_addr);
442 }
443
444 pj_sockaddr_set_port(&stun_sock->srv_addr, (pj_uint16_t)default_port);
445
446 /* Start sending Binding request */
447 status = get_mapped_addr(stun_sock);
448 }
449
450 pj_grp_lock_release(stun_sock->grp_lock);
451 return status;
452}
453
454/* Destructor */
455static void stun_sock_destructor(void *obj)
456{
457 pj_stun_sock *stun_sock = (pj_stun_sock*)obj;
458
459 if (stun_sock->q) {
460 pj_dns_srv_cancel_query(stun_sock->q, PJ_FALSE);
461 stun_sock->q = NULL;
462 }
463
464 /*
465 if (stun_sock->stun_sess) {
466 pj_stun_session_destroy(stun_sock->stun_sess);
467 stun_sock->stun_sess = NULL;
468 }
469 */
470
471 if (stun_sock->pool) {
472 pj_pool_t *pool = stun_sock->pool;
473 stun_sock->pool = NULL;
474 pj_pool_release(pool);
475 }
476
477 TRACE_(("", "STUN sock %p destroyed", stun_sock));
478
479}
480
481/* Destroy */
482PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock)
483{
484 TRACE_((stun_sock->obj_name, "STUN sock %p request, ref_cnt=%d",
485 stun_sock, pj_grp_lock_get_ref(stun_sock->grp_lock)));
486
487 pj_grp_lock_acquire(stun_sock->grp_lock);
488 if (stun_sock->is_destroying) {
489 /* Destroy already called */
490 pj_grp_lock_release(stun_sock->grp_lock);
491 return PJ_EINVALIDOP;
492 }
493
494 stun_sock->is_destroying = PJ_TRUE;
495 pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap,
496 &stun_sock->ka_timer, 0);
497
498 if (stun_sock->active_sock != NULL) {
499 stun_sock->sock_fd = PJ_INVALID_SOCKET;
500 pj_activesock_close(stun_sock->active_sock);
501 } else if (stun_sock->sock_fd != PJ_INVALID_SOCKET) {
502 pj_sock_close(stun_sock->sock_fd);
503 stun_sock->sock_fd = PJ_INVALID_SOCKET;
504 }
505
506 if (stun_sock->stun_sess) {
507 pj_stun_session_destroy(stun_sock->stun_sess);
508 }
509 pj_grp_lock_dec_ref(stun_sock->grp_lock);
510 pj_grp_lock_release(stun_sock->grp_lock);
511 return PJ_SUCCESS;
512}
513
514/* Associate user data */
515PJ_DEF(pj_status_t) pj_stun_sock_set_user_data( pj_stun_sock *stun_sock,
516 void *user_data)
517{
518 PJ_ASSERT_RETURN(stun_sock, PJ_EINVAL);
519 stun_sock->user_data = user_data;
520 return PJ_SUCCESS;
521}
522
523
524/* Get user data */
525PJ_DEF(void*) pj_stun_sock_get_user_data(pj_stun_sock *stun_sock)
526{
527 PJ_ASSERT_RETURN(stun_sock, NULL);
528 return stun_sock->user_data;
529}
530
531/* Get group lock */
532PJ_DECL(pj_grp_lock_t *) pj_stun_sock_get_grp_lock(pj_stun_sock *stun_sock)
533{
534 PJ_ASSERT_RETURN(stun_sock, NULL);
535 return stun_sock->grp_lock;
536}
537
538/* Notify application that session has failed */
539static pj_bool_t sess_fail(pj_stun_sock *stun_sock,
540 pj_stun_sock_op op,
541 pj_status_t status)
542{
543 pj_bool_t ret;
544
545 PJ_PERROR(4,(stun_sock->obj_name, status,
546 "Session failed because %s failed",
547 pj_stun_sock_op_name(op)));
548
549 ret = (*stun_sock->cb.on_status)(stun_sock, op, status);
550
551 return ret;
552}
553
554/* DNS resolver callback */
555static void dns_srv_resolver_cb(void *user_data,
556 pj_status_t status,
557 const pj_dns_srv_record *rec)
558{
559 pj_stun_sock *stun_sock = (pj_stun_sock*) user_data;
560
561 pj_grp_lock_acquire(stun_sock->grp_lock);
562
563 /* Clear query */
564 stun_sock->q = NULL;
565
566 /* Handle error */
567 if (status != PJ_SUCCESS) {
568 sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status);
569 pj_grp_lock_release(stun_sock->grp_lock);
570 return;
571 }
572
573 pj_assert(rec->count);
574 pj_assert(rec->entry[0].server.addr_count);
575
576 PJ_TODO(SUPPORT_IPV6_IN_RESOLVER);
577 pj_assert(stun_sock->af == pj_AF_INET());
578
579 /* Set the address */
580 pj_sockaddr_in_init(&stun_sock->srv_addr.ipv4, NULL,
581 rec->entry[0].port);
582 stun_sock->srv_addr.ipv4.sin_addr = rec->entry[0].server.addr[0];
583
584 /* Start sending Binding request */
585 get_mapped_addr(stun_sock);
586
587 pj_grp_lock_release(stun_sock->grp_lock);
588}
589
590
591/* Start sending STUN Binding request */
592static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock)
593{
594 pj_stun_tx_data *tdata;
595 pj_status_t status;
596
597 /* Increment request counter and create STUN Binding request */
598 ++stun_sock->tsx_id[5];
599 status = pj_stun_session_create_req(stun_sock->stun_sess,
600 PJ_STUN_BINDING_REQUEST,
601 PJ_STUN_MAGIC,
602 (const pj_uint8_t*)stun_sock->tsx_id,
603 &tdata);
604 if (status != PJ_SUCCESS)
605 goto on_error;
606
607 /* Send request */
608 status=pj_stun_session_send_msg(stun_sock->stun_sess, INTERNAL_MSG_TOKEN,
609 PJ_FALSE, PJ_TRUE, &stun_sock->srv_addr,
610 pj_sockaddr_get_len(&stun_sock->srv_addr),
611 tdata);
612 if (status != PJ_SUCCESS && status != PJ_EPENDING)
613 goto on_error;
614
615 return PJ_SUCCESS;
616
617on_error:
618 sess_fail(stun_sock, PJ_STUN_SOCK_BINDING_OP, status);
619 return status;
620}
621
622/* Get info */
623PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
624 pj_stun_sock_info *info)
625{
626 int addr_len;
627 pj_status_t status;
628
629 PJ_ASSERT_RETURN(stun_sock && info, PJ_EINVAL);
630
631 pj_grp_lock_acquire(stun_sock->grp_lock);
632
633 /* Copy STUN server address and mapped address */
634 pj_memcpy(&info->srv_addr, &stun_sock->srv_addr,
635 sizeof(pj_sockaddr));
636 pj_memcpy(&info->mapped_addr, &stun_sock->mapped_addr,
637 sizeof(pj_sockaddr));
638
639 /* Retrieve bound address */
640 addr_len = sizeof(info->bound_addr);
641 status = pj_sock_getsockname(stun_sock->sock_fd, &info->bound_addr,
642 &addr_len);
643 if (status != PJ_SUCCESS) {
644 pj_grp_lock_release(stun_sock->grp_lock);
645 return status;
646 }
647
648 /* If socket is bound to a specific interface, then only put that
649 * interface in the alias list. Otherwise query all the interfaces
650 * in the host.
651 */
652 if (pj_sockaddr_has_addr(&info->bound_addr)) {
653 info->alias_cnt = 1;
654 pj_sockaddr_cp(&info->aliases[0], &info->bound_addr);
655 } else {
656 pj_sockaddr def_addr;
657 pj_uint16_t port = pj_sockaddr_get_port(&info->bound_addr);
658 unsigned i;
659
660 /* Get the default address */
661 status = pj_gethostip(stun_sock->af, &def_addr);
662 if (status != PJ_SUCCESS) {
663 pj_grp_lock_release(stun_sock->grp_lock);
664 return status;
665 }
666
667 pj_sockaddr_set_port(&def_addr, port);
668
669 /* Enum all IP interfaces in the host */
670 info->alias_cnt = PJ_ARRAY_SIZE(info->aliases);
671 status = pj_enum_ip_interface(stun_sock->af, &info->alias_cnt,
672 info->aliases);
673 if (status != PJ_SUCCESS) {
674 pj_grp_lock_release(stun_sock->grp_lock);
675 return status;
676 }
677
678 /* Set the port number for each address.
679 */
680 for (i=0; i<info->alias_cnt; ++i) {
681 pj_sockaddr_set_port(&info->aliases[i], port);
682 }
683
684 /* Put the default IP in the first slot */
685 for (i=0; i<info->alias_cnt; ++i) {
686 if (pj_sockaddr_cmp(&info->aliases[i], &def_addr)==0) {
687 if (i!=0) {
688 pj_sockaddr_cp(&info->aliases[i], &info->aliases[0]);
689 pj_sockaddr_cp(&info->aliases[0], &def_addr);
690 }
691 break;
692 }
693 }
694 }
695
696 pj_grp_lock_release(stun_sock->grp_lock);
697 return PJ_SUCCESS;
698}
699
700/* Send application data */
701PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock,
702 pj_ioqueue_op_key_t *send_key,
703 const void *pkt,
704 unsigned pkt_len,
705 unsigned flag,
706 const pj_sockaddr_t *dst_addr,
707 unsigned addr_len)
708{
709 pj_ssize_t size;
710 pj_status_t status;
711
712 PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL);
713
714 pj_grp_lock_acquire(stun_sock->grp_lock);
715
716 if (!stun_sock->active_sock) {
717 /* We have been shutdown, but this callback may still get called
718 * by retransmit timer.
719 */
720 pj_grp_lock_release(stun_sock->grp_lock);
721 return PJ_EINVALIDOP;
722 }
723
724 if (send_key==NULL)
725 send_key = &stun_sock->send_key;
726
727 size = pkt_len;
728 status = pj_activesock_sendto(stun_sock->active_sock, send_key,
729 pkt, &size, flag, dst_addr, addr_len);
730
731 pj_grp_lock_release(stun_sock->grp_lock);
732 return status;
733}
734
735/* This callback is called by the STUN session to send packet */
736static pj_status_t sess_on_send_msg(pj_stun_session *sess,
737 void *token,
738 const void *pkt,
739 pj_size_t pkt_size,
740 const pj_sockaddr_t *dst_addr,
741 unsigned addr_len)
742{
743 pj_stun_sock *stun_sock;
744 pj_ssize_t size;
745
746 stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
747 if (!stun_sock || !stun_sock->active_sock) {
748 /* We have been shutdown, but this callback may still get called
749 * by retransmit timer.
750 */
751 return PJ_EINVALIDOP;
752 }
753
754 pj_assert(token==INTERNAL_MSG_TOKEN);
755 PJ_UNUSED_ARG(token);
756
757 size = pkt_size;
758 return pj_activesock_sendto(stun_sock->active_sock,
759 &stun_sock->int_send_key,
760 pkt, &size, 0, dst_addr, addr_len);
761}
762
763/* This callback is called by the STUN session when outgoing transaction
764 * is complete
765 */
766static void sess_on_request_complete(pj_stun_session *sess,
767 pj_status_t status,
768 void *token,
769 pj_stun_tx_data *tdata,
770 const pj_stun_msg *response,
771 const pj_sockaddr_t *src_addr,
772 unsigned src_addr_len)
773{
774 pj_stun_sock *stun_sock;
775 const pj_stun_sockaddr_attr *mapped_attr;
776 pj_stun_sock_op op;
777 pj_bool_t mapped_changed;
778 pj_bool_t resched = PJ_TRUE;
779
780 stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
781 if (!stun_sock)
782 return;
783
784 PJ_UNUSED_ARG(tdata);
785 PJ_UNUSED_ARG(token);
786 PJ_UNUSED_ARG(src_addr);
787 PJ_UNUSED_ARG(src_addr_len);
788
789 /* Check if this is a keep-alive or the first Binding request */
790 if (pj_sockaddr_has_addr(&stun_sock->mapped_addr))
791 op = PJ_STUN_SOCK_KEEP_ALIVE_OP;
792 else
793 op = PJ_STUN_SOCK_BINDING_OP;
794
795 /* Handle failure */
796 if (status != PJ_SUCCESS) {
797 resched = sess_fail(stun_sock, op, status);
798 goto on_return;
799 }
800
801 /* Get XOR-MAPPED-ADDRESS, or MAPPED-ADDRESS when XOR-MAPPED-ADDRESS
802 * doesn't exist.
803 */
804 mapped_attr = (const pj_stun_sockaddr_attr*)
805 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
806 0);
807 if (mapped_attr==NULL) {
808 mapped_attr = (const pj_stun_sockaddr_attr*)
809 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR,
810 0);
811 }
812
813 if (mapped_attr == NULL) {
814 resched = sess_fail(stun_sock, op, PJNATH_ESTUNNOMAPPEDADDR);
815 goto on_return;
816 }
817
818 /* Determine if mapped address has changed, and save the new mapped
819 * address and call callback if so
820 */
821 mapped_changed = !pj_sockaddr_has_addr(&stun_sock->mapped_addr) ||
822 pj_sockaddr_cmp(&stun_sock->mapped_addr,
823 &mapped_attr->sockaddr) != 0;
824 if (mapped_changed) {
825 /* Print mapped adress */
826 {
827 char addrinfo[PJ_INET6_ADDRSTRLEN+10];
828 PJ_LOG(4,(stun_sock->obj_name,
829 "STUN mapped address found/changed: %s",
830 pj_sockaddr_print(&mapped_attr->sockaddr,
831 addrinfo, sizeof(addrinfo), 3)));
832 }
833
834 pj_sockaddr_cp(&stun_sock->mapped_addr, &mapped_attr->sockaddr);
835
836 if (op==PJ_STUN_SOCK_KEEP_ALIVE_OP)
837 op = PJ_STUN_SOCK_MAPPED_ADDR_CHANGE;
838 }
839
840 /* Notify user */
841 resched = (*stun_sock->cb.on_status)(stun_sock, op, PJ_SUCCESS);
842
843on_return:
844 /* Start/restart keep-alive timer */
845 if (resched)
846 start_ka_timer(stun_sock);
847}
848
849/* Schedule keep-alive timer */
850static void start_ka_timer(pj_stun_sock *stun_sock)
851{
852 pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap,
853 &stun_sock->ka_timer, 0);
854
855 pj_assert(stun_sock->ka_interval != 0);
856 if (stun_sock->ka_interval > 0 && !stun_sock->is_destroying) {
857 pj_time_val delay;
858
859 delay.sec = stun_sock->ka_interval;
860 delay.msec = 0;
861
862 pj_timer_heap_schedule_w_grp_lock(stun_sock->stun_cfg.timer_heap,
863 &stun_sock->ka_timer,
864 &delay, PJ_TRUE,
865 stun_sock->grp_lock);
866 }
867}
868
869/* Keep-alive timer callback */
870static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
871{
872 pj_stun_sock *stun_sock;
873
874 stun_sock = (pj_stun_sock *) te->user_data;
875
876 PJ_UNUSED_ARG(th);
877 pj_grp_lock_acquire(stun_sock->grp_lock);
878
879 /* Time to send STUN Binding request */
880 if (get_mapped_addr(stun_sock) != PJ_SUCCESS) {
881 pj_grp_lock_release(stun_sock->grp_lock);
882 return;
883 }
884
885 /* Next keep-alive timer will be scheduled once the request
886 * is complete.
887 */
888 pj_grp_lock_release(stun_sock->grp_lock);
889}
890
891/* Callback from active socket when incoming packet is received */
892static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
893 void *data,
894 pj_size_t size,
895 const pj_sockaddr_t *src_addr,
896 int addr_len,
897 pj_status_t status)
898{
899 pj_stun_sock *stun_sock;
900 pj_stun_msg_hdr *hdr;
901 pj_uint16_t type;
902
903 stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);
904 if (!stun_sock)
905 return PJ_FALSE;
906
907 /* Log socket error */
908 if (status != PJ_SUCCESS) {
909 PJ_PERROR(2,(stun_sock->obj_name, status, "recvfrom() error"));
910 return PJ_TRUE;
911 }
912
913 pj_grp_lock_acquire(stun_sock->grp_lock);
914
915 /* Check that this is STUN message */
916 status = pj_stun_msg_check((const pj_uint8_t*)data, size,
917 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET);
918 if (status != PJ_SUCCESS) {
919 /* Not STUN -- give it to application */
920 goto process_app_data;
921 }
922
923 /* Treat packet as STUN header and copy the STUN message type.
924 * We don't want to access the type directly from the header
925 * since it may not be properly aligned.
926 */
927 hdr = (pj_stun_msg_hdr*) data;
928 pj_memcpy(&type, &hdr->type, 2);
929 type = pj_ntohs(type);
930
931 /* If the packet is a STUN Binding response and part of the
932 * transaction ID matches our internal ID, then this is
933 * our internal STUN message (Binding request or keep alive).
934 * Give it to our STUN session.
935 */
936 if (!PJ_STUN_IS_RESPONSE(type) ||
937 PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD ||
938 pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0)
939 {
940 /* Not STUN Binding response, or STUN transaction ID mismatch.
941 * This is not our message too -- give it to application.
942 */
943 goto process_app_data;
944 }
945
946 /* This is our STUN Binding response. Give it to the STUN session */
947 status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, data, size,
948 PJ_STUN_IS_DATAGRAM, NULL, NULL,
949 src_addr, addr_len);
950
951 status = pj_grp_lock_release(stun_sock->grp_lock);
952
953 return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
954
955process_app_data:
956 if (stun_sock->cb.on_rx_data) {
957 pj_bool_t ret;
958
959 ret = (*stun_sock->cb.on_rx_data)(stun_sock, data, (unsigned)size,
960 src_addr, addr_len);
961 status = pj_grp_lock_release(stun_sock->grp_lock);
962 return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
963 }
964
965 status = pj_grp_lock_release(stun_sock->grp_lock);
966 return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
967}
968
969/* Callback from active socket about send status */
970static pj_bool_t on_data_sent(pj_activesock_t *asock,
971 pj_ioqueue_op_key_t *send_key,
972 pj_ssize_t sent)
973{
974 pj_stun_sock *stun_sock;
975
976 stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);
977 if (!stun_sock)
978 return PJ_FALSE;
979
980 /* Don't report to callback if this is internal message */
981 if (send_key == &stun_sock->int_send_key) {
982 return PJ_TRUE;
983 }
984
985 /* Report to callback */
986 if (stun_sock->cb.on_data_sent) {
987 pj_bool_t ret;
988
989 pj_grp_lock_acquire(stun_sock->grp_lock);
990
991 /* If app gives NULL send_key in sendto() function, then give
992 * NULL in the callback too
993 */
994 if (send_key == &stun_sock->send_key)
995 send_key = NULL;
996
997 /* Call callback */
998 ret = (*stun_sock->cb.on_data_sent)(stun_sock, send_key, sent);
999
1000 pj_grp_lock_release(stun_sock->grp_lock);
1001 return ret;
1002 }
1003
1004 return PJ_TRUE;
1005}
1006