blob: f267bf80bdcac237ef21b458bcd105c338fc0a86 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: allocation.c 4360 2013-02-21 11:26:35Z bennylp $ */
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 "turn.h"
21#include "auth.h"
22
23
24#define THIS_FILE "allocation.c"
25
26
27enum {
28 TIMER_ID_NONE,
29 TIMER_ID_TIMEOUT,
30 TIMER_ID_DESTROY
31};
32
33#define DESTROY_DELAY {0, 500}
34#define PEER_TABLE_SIZE 32
35
36#define MAX_CLIENT_BANDWIDTH 128 /* In Kbps */
37#define DEFA_CLIENT_BANDWIDTH 64
38
39#define MIN_LIFETIME 30
40#define MAX_LIFETIME 600
41#define DEF_LIFETIME 300
42
43
44/* Parsed Allocation request. */
45typedef struct alloc_request
46{
47 unsigned tp_type; /* Requested transport */
48 char addr[PJ_INET6_ADDRSTRLEN]; /* Requested IP */
49 unsigned bandwidth; /* Requested bandwidth */
50 unsigned lifetime; /* Lifetime. */
51 unsigned rpp_bits; /* A bits */
52 unsigned rpp_port; /* Requested port */
53} alloc_request;
54
55
56
57/* Prototypes */
58static void destroy_allocation(pj_turn_allocation *alloc);
59static pj_status_t create_relay(pj_turn_srv *srv,
60 pj_turn_allocation *alloc,
61 const pj_stun_msg *msg,
62 const alloc_request *req,
63 pj_turn_relay_res *relay);
64static void destroy_relay(pj_turn_relay_res *relay);
65static void on_rx_from_peer(pj_ioqueue_key_t *key,
66 pj_ioqueue_op_key_t *op_key,
67 pj_ssize_t bytes_read);
68static pj_status_t stun_on_send_msg(pj_stun_session *sess,
69 void *token,
70 const void *pkt,
71 pj_size_t pkt_size,
72 const pj_sockaddr_t *dst_addr,
73 unsigned addr_len);
74static pj_status_t stun_on_rx_request(pj_stun_session *sess,
75 const pj_uint8_t *pkt,
76 unsigned pkt_len,
77 const pj_stun_rx_data *rdata,
78 void *token,
79 const pj_sockaddr_t *src_addr,
80 unsigned src_addr_len);
81static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
82 const pj_uint8_t *pkt,
83 unsigned pkt_len,
84 const pj_stun_msg *msg,
85 void *token,
86 const pj_sockaddr_t *src_addr,
87 unsigned src_addr_len);
88
89/* Log allocation error */
90static void alloc_err(pj_turn_allocation *alloc, const char *title,
91 pj_status_t status)
92{
93 char errmsg[PJ_ERR_MSG_SIZE];
94
95 pj_strerror(status, errmsg, sizeof(errmsg));
96 PJ_LOG(4,(alloc->obj_name, "%s for client %s: %s",
97 title, alloc->info, errmsg));
98}
99
100
101/* Parse ALLOCATE request */
102static pj_status_t parse_allocate_req(alloc_request *cfg,
103 pj_stun_session *sess,
104 const pj_stun_rx_data *rdata,
105 const pj_sockaddr_t *src_addr,
106 unsigned src_addr_len)
107{
108 const pj_stun_msg *req = rdata->msg;
109 pj_stun_bandwidth_attr *attr_bw;
110 pj_stun_req_transport_attr *attr_req_tp;
111 pj_stun_res_token_attr *attr_res_token;
112 pj_stun_lifetime_attr *attr_lifetime;
113
114 pj_bzero(cfg, sizeof(*cfg));
115
116 /* Get BANDWIDTH attribute, if any. */
117 attr_bw = (pj_stun_uint_attr*)
118 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_BANDWIDTH, 0);
119 if (attr_bw) {
120 cfg->bandwidth = attr_bw->value;
121 } else {
122 cfg->bandwidth = DEFA_CLIENT_BANDWIDTH;
123 }
124
125 /* Check if we can satisfy the bandwidth */
126 if (cfg->bandwidth > MAX_CLIENT_BANDWIDTH) {
127 pj_stun_session_respond(sess, rdata,
128 PJ_STUN_SC_ALLOCATION_QUOTA_REACHED,
129 "Invalid bandwidth", NULL, PJ_TRUE,
130 src_addr, src_addr_len);
131 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ALLOCATION_QUOTA_REACHED);
132 }
133
134 /* MUST have REQUESTED-TRANSPORT attribute */
135 attr_req_tp = (pj_stun_uint_attr*)
136 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_TRANSPORT, 0);
137 if (attr_req_tp == NULL) {
138 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
139 "Missing REQUESTED-TRANSPORT attribute",
140 NULL, PJ_TRUE, src_addr, src_addr_len);
141 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
142 }
143
144 cfg->tp_type = PJ_STUN_GET_RT_PROTO(attr_req_tp->value);
145
146 /* Can only support UDP for now */
147 if (cfg->tp_type != PJ_TURN_TP_UDP) {
148 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO,
149 NULL, NULL, PJ_TRUE, src_addr, src_addr_len);
150 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO);
151 }
152
153 /* Get RESERVATION-TOKEN attribute, if any */
154 attr_res_token = (pj_stun_res_token_attr*)
155 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_RESERVATION_TOKEN,
156 0);
157 if (attr_res_token) {
158 /* We don't support RESERVATION-TOKEN for now */
159 pj_stun_session_respond(sess, rdata,
160 PJ_STUN_SC_BAD_REQUEST,
161 "RESERVATION-TOKEN is not supported", NULL,
162 PJ_TRUE, src_addr, src_addr_len);
163 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
164 }
165
166 /* Get LIFETIME attribute */
167 attr_lifetime = (pj_stun_uint_attr*)
168 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
169 if (attr_lifetime) {
170 cfg->lifetime = attr_lifetime->value;
171 if (cfg->lifetime < MIN_LIFETIME) {
172 pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
173 "LIFETIME too short", NULL,
174 PJ_TRUE, src_addr, src_addr_len);
175 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
176 }
177 if (cfg->lifetime > MAX_LIFETIME)
178 cfg->lifetime = MAX_LIFETIME;
179 } else {
180 cfg->lifetime = DEF_LIFETIME;
181 }
182
183 return PJ_SUCCESS;
184}
185
186
187/* Respond to ALLOCATE request */
188static pj_status_t send_allocate_response(pj_turn_allocation *alloc,
189 pj_stun_session *srv_sess,
190 pj_turn_transport *transport,
191 const pj_stun_rx_data *rdata)
192{
193 pj_stun_tx_data *tdata;
194 pj_status_t status;
195
196 /* Respond the original ALLOCATE request */
197 status = pj_stun_session_create_res(srv_sess, rdata, 0, NULL, &tdata);
198 if (status != PJ_SUCCESS)
199 return status;
200
201 /* Add XOR-RELAYED-ADDRESS attribute */
202 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
203 PJ_STUN_ATTR_XOR_RELAYED_ADDR, PJ_TRUE,
204 &alloc->relay.hkey.addr,
205 pj_sockaddr_get_len(&alloc->relay.hkey.addr));
206
207 /* Add LIFETIME. */
208 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
209 PJ_STUN_ATTR_LIFETIME,
210 (unsigned)alloc->relay.lifetime);
211
212 /* Add BANDWIDTH */
213 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
214 PJ_STUN_ATTR_BANDWIDTH,
215 alloc->bandwidth);
216
217 /* Add RESERVATION-TOKEN */
218 PJ_TODO(ADD_RESERVATION_TOKEN);
219
220 /* Add XOR-MAPPED-ADDRESS */
221 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
222 PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
223 &alloc->hkey.clt_addr,
224 pj_sockaddr_get_len(&alloc->hkey.clt_addr));
225
226 /* Send the response */
227 return pj_stun_session_send_msg(srv_sess, transport, PJ_TRUE,
228 PJ_FALSE, &alloc->hkey.clt_addr,
229 pj_sockaddr_get_len(&alloc->hkey.clt_addr),
230 tdata);
231}
232
233
234/*
235 * Init credential for the allocation. We use static credential, meaning that
236 * the user's password must not change during allocation.
237 */
238static pj_status_t init_cred(pj_turn_allocation *alloc, const pj_stun_msg *req)
239{
240 const pj_stun_username_attr *user;
241 const pj_stun_realm_attr *realm;
242 const pj_stun_nonce_attr *nonce;
243 pj_status_t status;
244
245 realm = (const pj_stun_realm_attr*)
246 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REALM, 0);
247 PJ_ASSERT_RETURN(realm != NULL, PJ_EBUG);
248
249 user = (const pj_stun_username_attr*)
250 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0);
251 PJ_ASSERT_RETURN(user != NULL, PJ_EBUG);
252
253 nonce = (const pj_stun_nonce_attr*)
254 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_NONCE, 0);
255 PJ_ASSERT_RETURN(nonce != NULL, PJ_EBUG);
256
257 /* Lookup the password */
258 status = pj_turn_get_password(NULL, NULL, &realm->value,
259 &user->value, alloc->pool,
260 &alloc->cred.data.static_cred.data_type,
261 &alloc->cred.data.static_cred.data);
262 if (status != PJ_SUCCESS)
263 return status;
264
265 /* Save credential */
266 alloc->cred.type = PJ_STUN_AUTH_CRED_STATIC;
267 pj_strdup(alloc->pool, &alloc->cred.data.static_cred.realm, &realm->value);
268 pj_strdup(alloc->pool, &alloc->cred.data.static_cred.username, &user->value);
269 pj_strdup(alloc->pool, &alloc->cred.data.static_cred.nonce, &nonce->value);
270
271 return PJ_SUCCESS;
272}
273
274
275/*
276 * Create new allocation.
277 */
278PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport,
279 const pj_sockaddr_t *src_addr,
280 unsigned src_addr_len,
281 const pj_stun_rx_data *rdata,
282 pj_stun_session *srv_sess,
283 pj_turn_allocation **p_alloc)
284{
285 pj_turn_srv *srv = transport->listener->server;
286 const pj_stun_msg *msg = rdata->msg;
287 pj_pool_t *pool;
288 alloc_request req;
289 pj_turn_allocation *alloc;
290 pj_stun_session_cb sess_cb;
291 char str_tmp[80];
292 pj_status_t status;
293
294 /* Parse ALLOCATE request */
295 status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len);
296 if (status != PJ_SUCCESS)
297 return status;
298
299 pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);
300
301 /* Init allocation structure */
302 alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation);
303 alloc->pool = pool;
304 alloc->obj_name = pool->obj_name;
305 alloc->relay.tp.sock = PJ_INVALID_SOCKET;
306 alloc->server = transport->listener->server;
307
308 alloc->bandwidth = req.bandwidth;
309
310 /* Set transport */
311 alloc->transport = transport;
312 pj_turn_transport_add_ref(transport, alloc);
313
314 alloc->hkey.tp_type = transport->listener->tp_type;
315 pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);
316
317 status = pj_lock_create_recursive_mutex(pool, alloc->obj_name,
318 &alloc->lock);
319 if (status != PJ_SUCCESS) {
320 goto on_error;
321 }
322
323 /* Create peer hash table */
324 alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);
325
326 /* Create channel hash table */
327 alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);
328
329 /* Print info */
330 pj_ansi_strcpy(alloc->info,
331 pj_turn_tp_type_name(transport->listener->tp_type));
332 alloc->info[3] = ':';
333 pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3);
334
335 /* Create STUN session to handle STUN communication with client */
336 pj_bzero(&sess_cb, sizeof(sess_cb));
337 sess_cb.on_send_msg = &stun_on_send_msg;
338 sess_cb.on_rx_request = &stun_on_rx_request;
339 sess_cb.on_rx_indication = &stun_on_rx_indication;
340 status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name,
341 &sess_cb, PJ_FALSE, NULL, &alloc->sess);
342 if (status != PJ_SUCCESS) {
343 goto on_error;
344 }
345
346 /* Attach to STUN session */
347 pj_stun_session_set_user_data(alloc->sess, alloc);
348
349 /* Init authentication credential */
350 status = init_cred(alloc, msg);
351 if (status != PJ_SUCCESS) {
352 goto on_error;
353 }
354
355 /* Attach authentication credential to STUN session */
356 pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM,
357 &alloc->cred);
358
359 /* Create the relay resource */
360 status = create_relay(srv, alloc, msg, &req, &alloc->relay);
361 if (status != PJ_SUCCESS) {
362 goto on_error;
363 }
364
365 /* Register this allocation */
366 pj_turn_srv_register_allocation(srv, alloc);
367
368 /* Respond to ALLOCATE request */
369 status = send_allocate_response(alloc, srv_sess, transport, rdata);
370 if (status != PJ_SUCCESS)
371 goto on_error;
372
373 /* Done */
374 pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp,
375 sizeof(str_tmp), 3);
376 PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s",
377 alloc->info, pj_turn_tp_type_name(req.tp_type), str_tmp));
378
379 /* Success */
380 *p_alloc = alloc;
381 return PJ_SUCCESS;
382
383on_error:
384 /* Send reply to the ALLOCATE request */
385 pj_strerror(status, str_tmp, sizeof(str_tmp));
386 pj_stun_session_respond(srv_sess, rdata, PJ_STUN_SC_BAD_REQUEST, str_tmp,
387 transport, PJ_TRUE, src_addr, src_addr_len);
388
389 /* Cleanup */
390 destroy_allocation(alloc);
391 return status;
392}
393
394
395/* Destroy relay resource */
396static void destroy_relay(pj_turn_relay_res *relay)
397{
398 if (relay->timer.id) {
399 pj_timer_heap_cancel(relay->allocation->server->core.timer_heap,
400 &relay->timer);
401 relay->timer.id = PJ_FALSE;
402 }
403
404 if (relay->tp.key) {
405 pj_ioqueue_unregister(relay->tp.key);
406 relay->tp.key = NULL;
407 relay->tp.sock = PJ_INVALID_SOCKET;
408 } else if (relay->tp.sock != PJ_INVALID_SOCKET) {
409 pj_sock_close(relay->tp.sock);
410 relay->tp.sock = PJ_INVALID_SOCKET;
411 }
412
413 /* Mark as shutdown */
414 relay->lifetime = 0;
415}
416
417
418/*
419 * Really destroy allocation.
420 */
421static void destroy_allocation(pj_turn_allocation *alloc)
422{
423 pj_pool_t *pool;
424
425 /* Unregister this allocation */
426 pj_turn_srv_unregister_allocation(alloc->server, alloc);
427
428 /* Destroy relay */
429 destroy_relay(&alloc->relay);
430
431 /* Must lock only after destroying relay otherwise deadlock */
432 if (alloc->lock) {
433 pj_lock_acquire(alloc->lock);
434 }
435
436 /* Unreference transport */
437 if (alloc->transport) {
438 pj_turn_transport_dec_ref(alloc->transport, alloc);
439 alloc->transport = NULL;
440 }
441
442 /* Destroy STUN session */
443 if (alloc->sess) {
444 pj_stun_session_destroy(alloc->sess);
445 alloc->sess = NULL;
446 }
447
448 /* Destroy lock */
449 if (alloc->lock) {
450 pj_lock_release(alloc->lock);
451 pj_lock_destroy(alloc->lock);
452 alloc->lock = NULL;
453 }
454
455 /* Destroy pool */
456 pool = alloc->pool;
457 if (pool) {
458 alloc->pool = NULL;
459 pj_pool_release(pool);
460 }
461}
462
463
464PJ_DECL(void) pj_turn_allocation_destroy(pj_turn_allocation *alloc)
465{
466 destroy_allocation(alloc);
467}
468
469
470/*
471 * Handle transport closure.
472 */
473PJ_DEF(void) pj_turn_allocation_on_transport_closed( pj_turn_allocation *alloc,
474 pj_turn_transport *tp)
475{
476 PJ_LOG(5,(alloc->obj_name, "Transport %s unexpectedly closed, destroying "
477 "allocation %s", tp->info, alloc->info));
478 pj_turn_transport_dec_ref(tp, alloc);
479 alloc->transport = NULL;
480 destroy_allocation(alloc);
481}
482
483
484/* Initiate shutdown sequence for this allocation and start destroy timer.
485 * Once allocation is marked as shutting down, any packets will be
486 * rejected/discarded
487 */
488static void alloc_shutdown(pj_turn_allocation *alloc)
489{
490 pj_time_val destroy_delay = DESTROY_DELAY;
491
492 /* Work with existing schedule */
493 if (alloc->relay.timer.id == TIMER_ID_TIMEOUT) {
494 /* Cancel existing shutdown timer */
495 pj_timer_heap_cancel(alloc->server->core.timer_heap,
496 &alloc->relay.timer);
497 alloc->relay.timer.id = TIMER_ID_NONE;
498
499 } else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
500 /* We've been scheduled to be destroyed, ignore this
501 * shutdown request.
502 */
503 return;
504 }
505
506 pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);
507
508 /* Shutdown relay socket */
509 destroy_relay(&alloc->relay);
510
511 /* Don't unregister from hash table because we still need to
512 * handle REFRESH retransmission.
513 */
514
515 /* Schedule destroy timer */
516 alloc->relay.timer.id = TIMER_ID_DESTROY;
517 pj_timer_heap_schedule(alloc->server->core.timer_heap,
518 &alloc->relay.timer, &destroy_delay);
519}
520
521
522/* Reschedule timeout using current lifetime setting */
523static pj_status_t resched_timeout(pj_turn_allocation *alloc)
524{
525 pj_time_val delay;
526 pj_status_t status;
527
528 pj_gettimeofday(&alloc->relay.expiry);
529 alloc->relay.expiry.sec += alloc->relay.lifetime;
530
531 pj_assert(alloc->relay.timer.id != TIMER_ID_DESTROY);
532 if (alloc->relay.timer.id != 0) {
533 pj_timer_heap_cancel(alloc->server->core.timer_heap,
534 &alloc->relay.timer);
535 alloc->relay.timer.id = TIMER_ID_NONE;
536 }
537
538 delay.sec = alloc->relay.lifetime;
539 delay.msec = 0;
540
541 alloc->relay.timer.id = TIMER_ID_TIMEOUT;
542 status = pj_timer_heap_schedule(alloc->server->core.timer_heap,
543 &alloc->relay.timer, &delay);
544 if (status != PJ_SUCCESS) {
545 alloc->relay.timer.id = TIMER_ID_NONE;
546 return status;
547 }
548
549 return PJ_SUCCESS;
550}
551
552
553/* Timer timeout callback */
554static void relay_timeout_cb(pj_timer_heap_t *heap, pj_timer_entry *e)
555{
556 pj_turn_relay_res *rel;
557 pj_turn_allocation *alloc;
558
559 PJ_UNUSED_ARG(heap);
560
561 rel = (pj_turn_relay_res*) e->user_data;
562 alloc = rel->allocation;
563
564 if (e->id == TIMER_ID_TIMEOUT) {
565
566 e->id = TIMER_ID_NONE;
567
568 PJ_LOG(4,(alloc->obj_name,
569 "Client %s refresh timed-out, shutting down..",
570 alloc->info));
571
572 alloc_shutdown(alloc);
573
574 } else if (e->id == TIMER_ID_DESTROY) {
575 e->id = TIMER_ID_NONE;
576
577 PJ_LOG(4,(alloc->obj_name, "Client %s destroying..",
578 alloc->info));
579
580 destroy_allocation(alloc);
581 }
582}
583
584
585/*
586 * Create relay.
587 */
588static pj_status_t create_relay(pj_turn_srv *srv,
589 pj_turn_allocation *alloc,
590 const pj_stun_msg *msg,
591 const alloc_request *req,
592 pj_turn_relay_res *relay)
593{
594 enum { RETRY = 40 };
595 pj_pool_t *pool = alloc->pool;
596 int retry, retry_max, sock_type;
597 pj_ioqueue_callback icb;
598 int af, namelen;
599 pj_stun_string_attr *sa;
600 pj_status_t status;
601
602 pj_bzero(relay, sizeof(*relay));
603
604 relay->allocation = alloc;
605 relay->tp.sock = PJ_INVALID_SOCKET;
606
607 /* TODO: get the requested address family from somewhere */
608 af = alloc->transport->listener->addr.addr.sa_family;
609
610 /* Save realm */
611 sa = (pj_stun_string_attr*)
612 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
613 PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
614 pj_strdup(pool, &relay->realm, &sa->value);
615
616 /* Save username */
617 sa = (pj_stun_string_attr*)
618 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
619 PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
620 pj_strdup(pool, &relay->user, &sa->value);
621
622 /* Lifetime and timeout */
623 relay->lifetime = req->lifetime;
624 pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
625 &relay_timeout_cb);
626 resched_timeout(alloc);
627
628 /* Transport type */
629 relay->hkey.tp_type = req->tp_type;
630
631 /* Create the socket */
632 if (req->tp_type == PJ_TURN_TP_UDP) {
633 sock_type = pj_SOCK_DGRAM();
634 } else if (req->tp_type == PJ_TURN_TP_TCP) {
635 sock_type = pj_SOCK_STREAM();
636 } else {
637 pj_assert(!"Unknown transport");
638 return PJ_EINVALIDOP;
639 }
640
641 status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
642 if (status != PJ_SUCCESS) {
643 pj_bzero(relay, sizeof(*relay));
644 return status;
645 }
646
647 /* Find suitable port for this allocation */
648 if (req->rpp_port) {
649 retry_max = 1;
650 } else {
651 retry_max = RETRY;
652 }
653
654 for (retry=0; retry<retry_max; ++retry) {
655 pj_uint16_t port;
656 pj_sockaddr bound_addr;
657
658 pj_lock_acquire(srv->core.lock);
659
660 if (req->rpp_port) {
661 port = (pj_uint16_t) req->rpp_port;
662 } else if (req->tp_type == PJ_TURN_TP_UDP) {
663 port = (pj_uint16_t) srv->ports.next_udp++;
664 if (srv->ports.next_udp > srv->ports.max_udp)
665 srv->ports.next_udp = srv->ports.min_udp;
666 } else if (req->tp_type == PJ_TURN_TP_TCP) {
667 port = (pj_uint16_t) srv->ports.next_tcp++;
668 if (srv->ports.next_tcp > srv->ports.max_tcp)
669 srv->ports.next_tcp = srv->ports.min_tcp;
670 } else {
671 pj_assert(!"Invalid transport");
672 port = 0;
673 }
674
675 pj_lock_release(srv->core.lock);
676
677 pj_sockaddr_init(af, &bound_addr, NULL, port);
678
679 status = pj_sock_bind(relay->tp.sock, &bound_addr,
680 pj_sockaddr_get_len(&bound_addr));
681 if (status == PJ_SUCCESS)
682 break;
683 }
684
685 if (status != PJ_SUCCESS) {
686 /* Unable to allocate port */
687 PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
688 status));
689 pj_sock_close(relay->tp.sock);
690 relay->tp.sock = PJ_INVALID_SOCKET;
691 return status;
692 }
693
694 /* Init relay key */
695 namelen = sizeof(relay->hkey.addr);
696 status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
697 if (status != PJ_SUCCESS) {
698 PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d",
699 status));
700 pj_sock_close(relay->tp.sock);
701 relay->tp.sock = PJ_INVALID_SOCKET;
702 return status;
703 }
704 if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
705 pj_sockaddr_copy_addr(&relay->hkey.addr,
706 &alloc->transport->listener->addr);
707 }
708 if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
709 pj_sockaddr tmp_addr;
710 pj_gethostip(af, &tmp_addr);
711 pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
712 }
713
714 /* Init ioqueue */
715 pj_bzero(&icb, sizeof(icb));
716 icb.on_read_complete = &on_rx_from_peer;
717
718 status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
719 relay, &icb, &relay->tp.key);
720 if (status != PJ_SUCCESS) {
721 PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d",
722 status));
723 pj_sock_close(relay->tp.sock);
724 relay->tp.sock = PJ_INVALID_SOCKET;
725 return status;
726 }
727
728 /* Kick off pending read operation */
729 pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
730 on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);
731
732 /* Done */
733 return PJ_SUCCESS;
734}
735
736/* Create and send error response */
737static void send_reply_err(pj_turn_allocation *alloc,
738 const pj_stun_rx_data *rdata,
739 pj_bool_t cache,
740 int code, const char *errmsg)
741{
742 pj_status_t status;
743
744 status = pj_stun_session_respond(alloc->sess, rdata, code, errmsg, NULL,
745 cache, &alloc->hkey.clt_addr,
746 pj_sockaddr_get_len(&alloc->hkey.clt_addr.addr));
747 if (status != PJ_SUCCESS) {
748 alloc_err(alloc, "Error sending STUN error response", status);
749 return;
750 }
751}
752
753/* Create and send successful response */
754static void send_reply_ok(pj_turn_allocation *alloc,
755 const pj_stun_rx_data *rdata)
756{
757 pj_status_t status;
758 unsigned interval;
759 pj_stun_tx_data *tdata;
760
761 status = pj_stun_session_create_res(alloc->sess, rdata, 0, NULL, &tdata);
762 if (status != PJ_SUCCESS) {
763 alloc_err(alloc, "Error creating STUN success response", status);
764 return;
765 }
766
767 /* Calculate time to expiration */
768 if (alloc->relay.lifetime != 0) {
769 pj_time_val now;
770 pj_gettimeofday(&now);
771 interval = alloc->relay.expiry.sec - now.sec;
772 } else {
773 interval = 0;
774 }
775
776 /* Add LIFETIME if this is not ChannelBind. */
777 if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){
778 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
779 PJ_STUN_ATTR_LIFETIME, interval);
780
781 /* Add BANDWIDTH if lifetime is not zero */
782 if (interval != 0) {
783 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
784 PJ_STUN_ATTR_BANDWIDTH,
785 alloc->bandwidth);
786 }
787 }
788
789 status = pj_stun_session_send_msg(alloc->sess, NULL, PJ_TRUE,
790 PJ_FALSE, &alloc->hkey.clt_addr,
791 pj_sockaddr_get_len(&alloc->hkey.clt_addr),
792 tdata);
793 if (status != PJ_SUCCESS) {
794 alloc_err(alloc, "Error sending STUN success response", status);
795 return;
796 }
797}
798
799
800/* Create new permission */
801static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
802 const pj_sockaddr_t *peer_addr,
803 unsigned addr_len)
804{
805 pj_turn_permission *perm;
806
807 perm = PJ_POOL_ZALLOC_T(alloc->pool, pj_turn_permission);
808 pj_memcpy(&perm->hkey.peer_addr, peer_addr, addr_len);
809
810 perm->allocation = alloc;
811 perm->channel = PJ_TURN_INVALID_CHANNEL;
812
813 pj_gettimeofday(&perm->expiry);
814 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
815
816 /* Register to hash table (only the address part!) */
817 pj_hash_set(alloc->pool, alloc->peer_table,
818 pj_sockaddr_get_addr(&perm->hkey.peer_addr),
819 pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, perm);
820
821 return perm;
822}
823
824/* Check if a permission isn't expired. Return NULL if expired. */
825static pj_turn_permission *check_permission_expiry(pj_turn_permission *perm)
826{
827 pj_turn_allocation *alloc = perm->allocation;
828 pj_time_val now;
829
830 pj_gettimeofday(&now);
831 if (PJ_TIME_VAL_GT(perm->expiry, now)) {
832 /* Permission has not expired */
833 return perm;
834 }
835
836 /* Remove from permission hash table */
837 pj_hash_set(NULL, alloc->peer_table,
838 pj_sockaddr_get_addr(&perm->hkey.peer_addr),
839 pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, NULL);
840
841 /* Remove from channel hash table, if assigned a channel number */
842 if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
843 pj_hash_set(NULL, alloc->ch_table, &perm->channel,
844 sizeof(perm->channel), 0, NULL);
845 }
846
847 return NULL;
848}
849
850/* Lookup permission in hash table by the peer address */
851static pj_turn_permission*
852lookup_permission_by_addr(pj_turn_allocation *alloc,
853 const pj_sockaddr_t *peer_addr,
854 unsigned addr_len)
855{
856 pj_turn_permission *perm;
857
858 PJ_UNUSED_ARG(addr_len);
859
860 /* Lookup in peer hash table */
861 perm = (pj_turn_permission*)
862 pj_hash_get(alloc->peer_table,
863 pj_sockaddr_get_addr(peer_addr),
864 pj_sockaddr_get_addr_len(peer_addr),
865 NULL);
866 return perm ? check_permission_expiry(perm) : NULL;
867}
868
869/* Lookup permission in hash table by the channel number */
870static pj_turn_permission*
871lookup_permission_by_chnum(pj_turn_allocation *alloc,
872 unsigned chnum)
873{
874 pj_uint16_t chnum16 = (pj_uint16_t)chnum;
875 pj_turn_permission *perm;
876
877 /* Lookup in peer hash table */
878 perm = (pj_turn_permission*) pj_hash_get(alloc->ch_table, &chnum16,
879 sizeof(chnum16), NULL);
880 return perm ? check_permission_expiry(perm) : NULL;
881}
882
883/* Update permission because of data from client to peer.
884 * Return PJ_TRUE is permission is found.
885 */
886static pj_bool_t refresh_permission(pj_turn_permission *perm)
887{
888 pj_gettimeofday(&perm->expiry);
889 if (perm->channel == PJ_TURN_INVALID_CHANNEL)
890 perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
891 else
892 perm->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT;
893 return PJ_TRUE;
894}
895
896/*
897 * Handle incoming packet from client. This would have been called by
898 * server upon receiving packet from a listener.
899 */
900PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc,
901 pj_turn_pkt *pkt)
902{
903 pj_bool_t is_stun;
904 pj_status_t status;
905
906 /* Lock this allocation */
907 pj_lock_acquire(alloc->lock);
908
909 /* Quickly check if this is STUN message */
910 is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0);
911
912 if (is_stun) {
913 /*
914 * This could be an incoming STUN requests or indications.
915 * Pass this through to the STUN session, which will call
916 * our stun_on_rx_request() or stun_on_rx_indication()
917 * callbacks.
918 *
919 * Note: currently it is necessary to specify the
920 * PJ_STUN_NO_FINGERPRINT_CHECK otherwise the FINGERPRINT
921 * attribute inside STUN Send Indication message will mess up
922 * with fingerprint checking.
923 */
924 unsigned options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
925 pj_size_t parsed_len = 0;
926
927 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
928 options |= PJ_STUN_IS_DATAGRAM;
929
930 status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len,
931 options, NULL, &parsed_len,
932 &pkt->src.clt_addr,
933 pkt->src_addr_len);
934
935 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
936 pkt->len = 0;
937 } else if (parsed_len > 0) {
938 if (parsed_len == pkt->len) {
939 pkt->len = 0;
940 } else {
941 pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
942 pkt->len - parsed_len);
943 pkt->len -= parsed_len;
944 }
945 }
946
947 if (status != PJ_SUCCESS) {
948 alloc_err(alloc, "Error handling STUN packet", status);
949 goto on_return;
950 }
951
952 } else {
953 /*
954 * This is not a STUN packet, must be ChannelData packet.
955 */
956 pj_turn_channel_data *cd = (pj_turn_channel_data*)pkt->pkt;
957 pj_turn_permission *perm;
958 pj_ssize_t len;
959
960 pj_assert(sizeof(*cd)==4);
961
962 /* For UDP check the packet length */
963 if (alloc->transport->listener->tp_type == PJ_TURN_TP_UDP) {
964 if (pkt->len < pj_ntohs(cd->length)+sizeof(*cd)) {
965 PJ_LOG(4,(alloc->obj_name,
966 "ChannelData from %s discarded: UDP size error",
967 alloc->info));
968 goto on_return;
969 }
970 } else {
971 pj_assert(!"Unsupported transport");
972 goto on_return;
973 }
974
975 perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number));
976 if (!perm) {
977 /* Discard */
978 PJ_LOG(4,(alloc->obj_name,
979 "ChannelData from %s discarded: ch#0x%x not found",
980 alloc->info, pj_ntohs(cd->ch_number)));
981 goto on_return;
982 }
983
984 /* Relay the data */
985 len = pj_ntohs(cd->length);
986 pj_sock_sendto(alloc->relay.tp.sock, cd+1, &len, 0,
987 &perm->hkey.peer_addr,
988 pj_sockaddr_get_len(&perm->hkey.peer_addr));
989
990 /* Refresh permission */
991 refresh_permission(perm);
992 }
993
994on_return:
995 /* Release lock */
996 pj_lock_release(alloc->lock);
997}
998
999
1000/*
1001 * Handle incoming packet from peer. This function is called by
1002 * on_rx_from_peer().
1003 */
1004static void handle_peer_pkt(pj_turn_allocation *alloc,
1005 pj_turn_relay_res *rel,
1006 char *pkt, pj_size_t len,
1007 const pj_sockaddr *src_addr)
1008{
1009 pj_turn_permission *perm;
1010
1011 /* Lookup permission */
1012 perm = lookup_permission_by_addr(alloc, src_addr,
1013 pj_sockaddr_get_len(src_addr));
1014 if (perm == NULL) {
1015 /* No permission, discard data */
1016 return;
1017 }
1018
1019 /* Send Data Indication or ChannelData, depends on whether
1020 * this permission is attached to a channel number.
1021 */
1022 if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
1023 /* Send ChannelData */
1024 pj_turn_channel_data *cd = (pj_turn_channel_data*)rel->tp.tx_pkt;
1025
1026 if (len > PJ_TURN_MAX_PKT_LEN) {
1027 char peer_addr[80];
1028 pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3);
1029 PJ_LOG(4,(alloc->obj_name, "Client %s: discarded data from %s "
1030 "because it's too long (%d bytes)",
1031 alloc->info, peer_addr, len));
1032 return;
1033 }
1034
1035 /* Init header */
1036 cd->ch_number = pj_htons(perm->channel);
1037 cd->length = pj_htons((pj_uint16_t)len);
1038
1039 /* Copy data */
1040 pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
1041
1042 /* Send to client */
1043 alloc->transport->sendto(alloc->transport, rel->tp.tx_pkt,
1044 len+sizeof(pj_turn_channel_data), 0,
1045 &alloc->hkey.clt_addr,
1046 pj_sockaddr_get_len(&alloc->hkey.clt_addr));
1047 } else {
1048 /* Send Data Indication */
1049 pj_stun_tx_data *tdata;
1050 pj_status_t status;
1051
1052 status = pj_stun_session_create_ind(alloc->sess,
1053 PJ_STUN_DATA_INDICATION, &tdata);
1054 if (status != PJ_SUCCESS) {
1055 alloc_err(alloc, "Error creating Data indication", status);
1056 return;
1057 }
1058
1059 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
1060 PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
1061 src_addr, pj_sockaddr_get_len(src_addr));
1062 pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
1063 PJ_STUN_ATTR_DATA,
1064 (const pj_uint8_t*)pkt, len);
1065
1066 pj_stun_session_send_msg(alloc->sess, NULL, PJ_FALSE,
1067 PJ_FALSE, &alloc->hkey.clt_addr,
1068 pj_sockaddr_get_len(&alloc->hkey.clt_addr),
1069 tdata);
1070 }
1071}
1072
1073/*
1074 * ioqueue notification on RX packets from the relay socket.
1075 */
1076static void on_rx_from_peer(pj_ioqueue_key_t *key,
1077 pj_ioqueue_op_key_t *op_key,
1078 pj_ssize_t bytes_read)
1079{
1080 pj_turn_relay_res *rel;
1081 pj_status_t status;
1082
1083 rel = (pj_turn_relay_res*) pj_ioqueue_get_user_data(key);
1084
1085 /* Lock the allocation */
1086 pj_lock_acquire(rel->allocation->lock);
1087
1088 do {
1089 if (bytes_read > 0) {
1090 handle_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
1091 bytes_read, &rel->tp.src_addr);
1092 }
1093
1094 /* Read next packet */
1095 bytes_read = sizeof(rel->tp.rx_pkt);
1096 rel->tp.src_addr_len = sizeof(rel->tp.src_addr);
1097 status = pj_ioqueue_recvfrom(key, op_key,
1098 rel->tp.rx_pkt, &bytes_read, 0,
1099 &rel->tp.src_addr,
1100 &rel->tp.src_addr_len);
1101
1102 if (status != PJ_EPENDING && status != PJ_SUCCESS)
1103 bytes_read = -status;
1104
1105 } while (status != PJ_EPENDING && status != PJ_ECANCELLED);
1106
1107 /* Release allocation lock */
1108 pj_lock_release(rel->allocation->lock);
1109}
1110
1111/*
1112 * Callback notification from STUN session when it wants to send
1113 * a STUN message towards the client.
1114 */
1115static pj_status_t stun_on_send_msg(pj_stun_session *sess,
1116 void *token,
1117 const void *pkt,
1118 pj_size_t pkt_size,
1119 const pj_sockaddr_t *dst_addr,
1120 unsigned addr_len)
1121{
1122 pj_turn_allocation *alloc;
1123
1124 PJ_UNUSED_ARG(token);
1125
1126 alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1127
1128 return alloc->transport->sendto(alloc->transport, pkt, pkt_size, 0,
1129 dst_addr, addr_len);
1130}
1131
1132/*
1133 * Callback notification from STUN session when it receives STUN
1134 * requests. This callback was trigger by STUN incoming message
1135 * processing in pj_turn_allocation_on_rx_client_pkt().
1136 */
1137static pj_status_t stun_on_rx_request(pj_stun_session *sess,
1138 const pj_uint8_t *pkt,
1139 unsigned pkt_len,
1140 const pj_stun_rx_data *rdata,
1141 void *token,
1142 const pj_sockaddr_t *src_addr,
1143 unsigned src_addr_len)
1144{
1145 const pj_stun_msg *msg = rdata->msg;
1146 pj_turn_allocation *alloc;
1147
1148 PJ_UNUSED_ARG(pkt);
1149 PJ_UNUSED_ARG(pkt_len);
1150 PJ_UNUSED_ARG(token);
1151 PJ_UNUSED_ARG(src_addr);
1152 PJ_UNUSED_ARG(src_addr_len);
1153
1154 alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1155
1156 /* Refuse to serve any request if we've been shutdown */
1157 if (alloc->relay.lifetime == 0) {
1158 /* Reject with 437 if we're shutting down */
1159 send_reply_err(alloc, rdata, PJ_TRUE,
1160 PJ_STUN_SC_ALLOCATION_MISMATCH, NULL);
1161 return PJ_SUCCESS;
1162 }
1163
1164 if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) {
1165 /*
1166 * Handle REFRESH request
1167 */
1168 pj_stun_lifetime_attr *lifetime;
1169 pj_stun_bandwidth_attr *bandwidth;
1170
1171 /* Get LIFETIME attribute */
1172 lifetime = (pj_stun_lifetime_attr*)
1173 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1174
1175 /* Get BANDWIDTH attribute */
1176 bandwidth = (pj_stun_bandwidth_attr*)
1177 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
1178
1179 if (lifetime && lifetime->value==0) {
1180 /*
1181 * This is deallocation request.
1182 */
1183 alloc->relay.lifetime = 0;
1184
1185 /* Respond first */
1186 send_reply_ok(alloc, rdata);
1187
1188 /* Shutdown allocation */
1189 PJ_LOG(4,(alloc->obj_name,
1190 "Client %s request to dealloc, shutting down",
1191 alloc->info));
1192
1193 alloc_shutdown(alloc);
1194
1195 } else {
1196 /*
1197 * This is a refresh request.
1198 */
1199
1200 /* Update lifetime */
1201 if (lifetime) {
1202 alloc->relay.lifetime = lifetime->value;
1203 }
1204
1205 /* Update bandwidth */
1206 // TODO:
1207
1208 /* Update expiration timer */
1209 resched_timeout(alloc);
1210
1211 /* Send reply */
1212 send_reply_ok(alloc, rdata);
1213 }
1214
1215 } else if (msg->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
1216 /*
1217 * ChannelBind request.
1218 */
1219 pj_stun_channel_number_attr *ch_attr;
1220 pj_stun_xor_peer_addr_attr *peer_attr;
1221 pj_turn_permission *p1, *p2;
1222
1223 ch_attr = (pj_stun_channel_number_attr*)
1224 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CHANNEL_NUMBER, 0);
1225 peer_attr = (pj_stun_xor_peer_addr_attr*)
1226 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1227
1228 if (!ch_attr || !peer_attr) {
1229 send_reply_err(alloc, rdata, PJ_TRUE,
1230 PJ_STUN_SC_BAD_REQUEST, NULL);
1231 return PJ_SUCCESS;
1232 }
1233
1234 /* Find permission with the channel number */
1235 p1 = lookup_permission_by_chnum(alloc, PJ_STUN_GET_CH_NB(ch_attr->value));
1236
1237 /* If permission is found, this is supposed to be a channel bind
1238 * refresh. Make sure it's for the same peer.
1239 */
1240 if (p1) {
1241 if (pj_sockaddr_cmp(&p1->hkey.peer_addr, &peer_attr->sockaddr)) {
1242 /* Address mismatch. Send 400 */
1243 send_reply_err(alloc, rdata, PJ_TRUE,
1244 PJ_STUN_SC_BAD_REQUEST,
1245 "Peer address mismatch");
1246 return PJ_SUCCESS;
1247 }
1248
1249 /* Refresh permission */
1250 refresh_permission(p1);
1251
1252 /* Send response */
1253 send_reply_ok(alloc, rdata);
1254
1255 /* Done */
1256 return PJ_SUCCESS;
1257 }
1258
1259 /* If permission is not found, create a new one. Make sure the peer
1260 * has not alreadyy assigned with a channel number.
1261 */
1262 p2 = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1263 pj_sockaddr_get_len(&peer_attr->sockaddr));
1264 if (p2 && p2->channel != PJ_TURN_INVALID_CHANNEL) {
1265 send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST,
1266 "Peer address already assigned a channel number");
1267 return PJ_SUCCESS;
1268 }
1269
1270 /* Create permission if it doesn't exist */
1271 if (!p2) {
1272 p2 = create_permission(alloc, &peer_attr->sockaddr,
1273 pj_sockaddr_get_len(&peer_attr->sockaddr));
1274 if (!p2)
1275 return PJ_SUCCESS;
1276 }
1277
1278 /* Assign channel number to permission */
1279 p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
1280
1281 /* Register to hash table */
1282 pj_assert(sizeof(p2->channel==2));
1283 pj_hash_set(alloc->pool, alloc->ch_table, &p2->channel,
1284 sizeof(p2->channel), 0, p2);
1285
1286 /* Update */
1287 refresh_permission(p2);
1288
1289 /* Reply */
1290 send_reply_ok(alloc, rdata);
1291
1292 return PJ_SUCCESS;
1293
1294 } else if (msg->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
1295
1296 /* Respond with 437 (section 6.3 turn-07) */
1297 send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_ALLOCATION_MISMATCH,
1298 NULL);
1299
1300 } else {
1301
1302 /* Respond with Bad Request? */
1303 send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
1304
1305 }
1306
1307 return PJ_SUCCESS;
1308}
1309
1310/*
1311 * Callback notification from STUN session when it receives STUN
1312 * indications. This callback was trigger by STUN incoming message
1313 * processing in pj_turn_allocation_on_rx_client_pkt().
1314 */
1315static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
1316 const pj_uint8_t *pkt,
1317 unsigned pkt_len,
1318 const pj_stun_msg *msg,
1319 void *token,
1320 const pj_sockaddr_t *src_addr,
1321 unsigned src_addr_len)
1322{
1323 pj_stun_xor_peer_addr_attr *peer_attr;
1324 pj_stun_data_attr *data_attr;
1325 pj_turn_allocation *alloc;
1326 pj_turn_permission *perm;
1327 pj_ssize_t len;
1328
1329 PJ_UNUSED_ARG(pkt);
1330 PJ_UNUSED_ARG(pkt_len);
1331 PJ_UNUSED_ARG(token);
1332 PJ_UNUSED_ARG(src_addr);
1333 PJ_UNUSED_ARG(src_addr_len);
1334
1335 alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1336
1337 /* Only expect Send Indication */
1338 if (msg->hdr.type != PJ_STUN_SEND_INDICATION) {
1339 /* Ignore */
1340 return PJ_SUCCESS;
1341 }
1342
1343 /* Get XOR-PEER-ADDRESS attribute */
1344 peer_attr = (pj_stun_xor_peer_addr_attr*)
1345 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1346
1347 /* MUST have XOR-PEER-ADDRESS attribute */
1348 if (!peer_attr)
1349 return PJ_SUCCESS;
1350
1351 /* Get DATA attribute */
1352 data_attr = (pj_stun_data_attr*)
1353 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1354
1355 /* Create/update/refresh the permission */
1356 perm = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1357 pj_sockaddr_get_len(&peer_attr->sockaddr));
1358 if (perm == NULL) {
1359 perm = create_permission(alloc, &peer_attr->sockaddr,
1360 pj_sockaddr_get_len(&peer_attr->sockaddr));
1361 }
1362 refresh_permission(perm);
1363
1364 /* Return if we don't have data */
1365 if (data_attr == NULL)
1366 return PJ_SUCCESS;
1367
1368 /* Relay the data to peer */
1369 len = data_attr->length;
1370 pj_sock_sendto(alloc->relay.tp.sock, data_attr->data,
1371 &len, 0, &peer_attr->sockaddr,
1372 pj_sockaddr_get_len(&peer_attr->sockaddr));
1373
1374 return PJ_SUCCESS;
1375}
1376
1377