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