1
/* $Id: allocation.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
24
#define THIS_FILE "allocation.c"
33
#define DESTROY_DELAY {0, 500}
34
#define PEER_TABLE_SIZE 32
36
#define MAX_CLIENT_BANDWIDTH 128 /* In Kbps */
37
#define DEFA_CLIENT_BANDWIDTH 64
39
#define MIN_LIFETIME 30
40
#define MAX_LIFETIME 600
41
#define DEF_LIFETIME 300
44
/* Parsed Allocation request. */
45
typedef struct alloc_request
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 */
58
static void destroy_allocation(pj_turn_allocation *alloc);
59
static 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);
64
static void destroy_relay(pj_turn_relay_res *relay);
65
static void on_rx_from_peer(pj_ioqueue_key_t *key,
66
pj_ioqueue_op_key_t *op_key,
67
pj_ssize_t bytes_read);
68
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
72
const pj_sockaddr_t *dst_addr,
74
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
75
const pj_uint8_t *pkt,
77
const pj_stun_rx_data *rdata,
79
const pj_sockaddr_t *src_addr,
80
unsigned src_addr_len);
81
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
82
const pj_uint8_t *pkt,
84
const pj_stun_msg *msg,
86
const pj_sockaddr_t *src_addr,
87
unsigned src_addr_len);
89
/* Log allocation error */
90
static void alloc_err(pj_turn_allocation *alloc, const char *title,
93
char errmsg[PJ_ERR_MSG_SIZE];
95
pj_strerror(status, errmsg, sizeof(errmsg));
96
PJ_LOG(4,(alloc->obj_name, "%s for client %s: %s",
97
title, alloc->info, errmsg));
101
/* Parse ALLOCATE request */
102
static 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)
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;
114
pj_bzero(cfg, sizeof(*cfg));
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);
120
cfg->bandwidth = attr_bw->value;
122
cfg->bandwidth = DEFA_CLIENT_BANDWIDTH;
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);
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);
144
cfg->tp_type = PJ_STUN_GET_RT_PROTO(attr_req_tp->value);
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);
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,
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);
166
/* Get LIFETIME attribute */
167
attr_lifetime = (pj_stun_uint_attr*)
168
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
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);
177
if (cfg->lifetime > MAX_LIFETIME)
178
cfg->lifetime = MAX_LIFETIME;
180
cfg->lifetime = DEF_LIFETIME;
187
/* Respond to ALLOCATE request */
188
static 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)
193
pj_stun_tx_data *tdata;
196
/* Respond the original ALLOCATE request */
197
status = pj_stun_session_create_res(srv_sess, rdata, 0, NULL, &tdata);
198
if (status != PJ_SUCCESS)
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));
208
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
209
PJ_STUN_ATTR_LIFETIME,
210
(unsigned)alloc->relay.lifetime);
213
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
214
PJ_STUN_ATTR_BANDWIDTH,
217
/* Add RESERVATION-TOKEN */
218
PJ_TODO(ADD_RESERVATION_TOKEN);
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));
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),
235
* Init credential for the allocation. We use static credential, meaning that
236
* the user's password must not change during allocation.
238
static pj_status_t init_cred(pj_turn_allocation *alloc, const pj_stun_msg *req)
240
const pj_stun_username_attr *user;
241
const pj_stun_realm_attr *realm;
242
const pj_stun_nonce_attr *nonce;
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);
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);
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);
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)
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);
276
* Create new allocation.
278
PJ_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)
285
pj_turn_srv *srv = transport->listener->server;
286
const pj_stun_msg *msg = rdata->msg;
289
pj_turn_allocation *alloc;
290
pj_stun_session_cb sess_cb;
294
/* Parse ALLOCATE request */
295
status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len);
296
if (status != PJ_SUCCESS)
299
pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);
301
/* Init allocation structure */
302
alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation);
304
alloc->obj_name = pool->obj_name;
305
alloc->relay.tp.sock = PJ_INVALID_SOCKET;
306
alloc->server = transport->listener->server;
308
alloc->bandwidth = req.bandwidth;
311
alloc->transport = transport;
312
pj_turn_transport_add_ref(transport, alloc);
314
alloc->hkey.tp_type = transport->listener->tp_type;
315
pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);
317
status = pj_lock_create_recursive_mutex(pool, alloc->obj_name,
319
if (status != PJ_SUCCESS) {
323
/* Create peer hash table */
324
alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);
326
/* Create channel hash table */
327
alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);
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);
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, &alloc->sess);
342
if (status != PJ_SUCCESS) {
346
/* Attach to STUN session */
347
pj_stun_session_set_user_data(alloc->sess, alloc);
349
/* Init authentication credential */
350
status = init_cred(alloc, msg);
351
if (status != PJ_SUCCESS) {
355
/* Attach authentication credential to STUN session */
356
pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM,
359
/* Create the relay resource */
360
status = create_relay(srv, alloc, msg, &req, &alloc->relay);
361
if (status != PJ_SUCCESS) {
365
/* Register this allocation */
366
pj_turn_srv_register_allocation(srv, alloc);
368
/* Respond to ALLOCATE request */
369
status = send_allocate_response(alloc, srv_sess, transport, rdata);
370
if (status != PJ_SUCCESS)
374
pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp,
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));
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);
390
destroy_allocation(alloc);
395
/* Destroy relay resource */
396
static void destroy_relay(pj_turn_relay_res *relay)
398
if (relay->timer.id) {
399
pj_timer_heap_cancel(relay->allocation->server->core.timer_heap,
401
relay->timer.id = PJ_FALSE;
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;
413
/* Mark as shutdown */
419
* Really destroy allocation.
421
static void destroy_allocation(pj_turn_allocation *alloc)
425
/* Unregister this allocation */
426
pj_turn_srv_unregister_allocation(alloc->server, alloc);
429
destroy_relay(&alloc->relay);
431
/* Must lock only after destroying relay otherwise deadlock */
433
pj_lock_acquire(alloc->lock);
436
/* Unreference transport */
437
if (alloc->transport) {
438
pj_turn_transport_dec_ref(alloc->transport, alloc);
439
alloc->transport = NULL;
442
/* Destroy STUN session */
444
pj_stun_session_destroy(alloc->sess);
450
pj_lock_release(alloc->lock);
451
pj_lock_destroy(alloc->lock);
459
pj_pool_release(pool);
464
PJ_DECL(void) pj_turn_allocation_destroy(pj_turn_allocation *alloc)
466
destroy_allocation(alloc);
471
* Handle transport closure.
473
PJ_DEF(void) pj_turn_allocation_on_transport_closed( pj_turn_allocation *alloc,
474
pj_turn_transport *tp)
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);
484
/* Initiate shutdown sequence for this allocation and start destroy timer.
485
* Once allocation is marked as shutting down, any packets will be
488
static void alloc_shutdown(pj_turn_allocation *alloc)
490
pj_time_val destroy_delay = DESTROY_DELAY;
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;
499
} else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
500
/* We've been scheduled to be destroyed, ignore this
506
pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);
508
/* Shutdown relay socket */
509
destroy_relay(&alloc->relay);
511
/* Don't unregister from hash table because we still need to
512
* handle REFRESH retransmission.
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);
522
/* Reschedule timeout using current lifetime setting */
523
static pj_status_t resched_timeout(pj_turn_allocation *alloc)
528
pj_gettimeofday(&alloc->relay.expiry);
529
alloc->relay.expiry.sec += alloc->relay.lifetime;
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;
538
delay.sec = alloc->relay.lifetime;
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;
553
/* Timer timeout callback */
554
static void relay_timeout_cb(pj_timer_heap_t *heap, pj_timer_entry *e)
556
pj_turn_relay_res *rel;
557
pj_turn_allocation *alloc;
561
rel = (pj_turn_relay_res*) e->user_data;
562
alloc = rel->allocation;
564
if (e->id == TIMER_ID_TIMEOUT) {
566
e->id = TIMER_ID_NONE;
568
PJ_LOG(4,(alloc->obj_name,
569
"Client %s refresh timed-out, shutting down..",
572
alloc_shutdown(alloc);
574
} else if (e->id == TIMER_ID_DESTROY) {
575
e->id = TIMER_ID_NONE;
577
PJ_LOG(4,(alloc->obj_name, "Client %s destroying..",
580
destroy_allocation(alloc);
588
static 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)
595
pj_pool_t *pool = alloc->pool;
596
int retry, retry_max, sock_type;
597
pj_ioqueue_callback icb;
599
pj_stun_string_attr *sa;
602
pj_bzero(relay, sizeof(*relay));
604
relay->allocation = alloc;
605
relay->tp.sock = PJ_INVALID_SOCKET;
607
/* TODO: get the requested address family from somewhere */
608
af = alloc->transport->listener->addr.addr.sa_family;
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);
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);
622
/* Lifetime and timeout */
623
relay->lifetime = req->lifetime;
624
pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
626
resched_timeout(alloc);
629
relay->hkey.tp_type = req->tp_type;
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();
637
pj_assert(!"Unknown transport");
638
return PJ_EINVALIDOP;
641
status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
642
if (status != PJ_SUCCESS) {
643
pj_bzero(relay, sizeof(*relay));
647
/* Find suitable port for this allocation */
654
for (retry=0; retry<retry_max; ++retry) {
656
pj_sockaddr bound_addr;
658
pj_lock_acquire(srv->core.lock);
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;
671
pj_assert(!"Invalid transport");
675
pj_lock_release(srv->core.lock);
677
pj_sockaddr_init(af, &bound_addr, NULL, port);
679
status = pj_sock_bind(relay->tp.sock, &bound_addr,
680
pj_sockaddr_get_len(&bound_addr));
681
if (status == PJ_SUCCESS)
685
if (status != PJ_SUCCESS) {
686
/* Unable to allocate port */
687
PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
689
pj_sock_close(relay->tp.sock);
690
relay->tp.sock = PJ_INVALID_SOCKET;
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",
700
pj_sock_close(relay->tp.sock);
701
relay->tp.sock = PJ_INVALID_SOCKET;
704
if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
705
pj_sockaddr_copy_addr(&relay->hkey.addr,
706
&alloc->transport->listener->addr);
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);
715
pj_bzero(&icb, sizeof(icb));
716
icb.on_read_complete = &on_rx_from_peer;
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",
723
pj_sock_close(relay->tp.sock);
724
relay->tp.sock = PJ_INVALID_SOCKET;
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);
736
/* Create and send error response */
737
static void send_reply_err(pj_turn_allocation *alloc,
738
const pj_stun_rx_data *rdata,
740
int code, const char *errmsg)
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);
753
/* Create and send successful response */
754
static void send_reply_ok(pj_turn_allocation *alloc,
755
const pj_stun_rx_data *rdata)
759
pj_stun_tx_data *tdata;
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);
767
/* Calculate time to expiration */
768
if (alloc->relay.lifetime != 0) {
770
pj_gettimeofday(&now);
771
interval = alloc->relay.expiry.sec - now.sec;
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);
781
/* Add BANDWIDTH if lifetime is not zero */
783
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
784
PJ_STUN_ATTR_BANDWIDTH,
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),
793
if (status != PJ_SUCCESS) {
794
alloc_err(alloc, "Error sending STUN success response", status);
800
/* Create new permission */
801
static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
802
const pj_sockaddr_t *peer_addr,
805
pj_turn_permission *perm;
807
perm = PJ_POOL_ZALLOC_T(alloc->pool, pj_turn_permission);
808
pj_memcpy(&perm->hkey.peer_addr, peer_addr, addr_len);
810
perm->allocation = alloc;
811
perm->channel = PJ_TURN_INVALID_CHANNEL;
813
pj_gettimeofday(&perm->expiry);
814
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
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);
824
/* Check if a permission isn't expired. Return NULL if expired. */
825
static pj_turn_permission *check_permission_expiry(pj_turn_permission *perm)
827
pj_turn_allocation *alloc = perm->allocation;
830
pj_gettimeofday(&now);
831
if (PJ_TIME_VAL_GT(perm->expiry, now)) {
832
/* Permission has not expired */
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);
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);
850
/* Lookup permission in hash table by the peer address */
851
static pj_turn_permission*
852
lookup_permission_by_addr(pj_turn_allocation *alloc,
853
const pj_sockaddr_t *peer_addr,
856
pj_turn_permission *perm;
858
PJ_UNUSED_ARG(addr_len);
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),
866
return perm ? check_permission_expiry(perm) : NULL;
869
/* Lookup permission in hash table by the channel number */
870
static pj_turn_permission*
871
lookup_permission_by_chnum(pj_turn_allocation *alloc,
874
pj_uint16_t chnum16 = (pj_uint16_t)chnum;
875
pj_turn_permission *perm;
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;
883
/* Update permission because of data from client to peer.
884
* Return PJ_TRUE is permission is found.
886
static pj_bool_t refresh_permission(pj_turn_permission *perm)
888
pj_gettimeofday(&perm->expiry);
889
if (perm->channel == PJ_TURN_INVALID_CHANNEL)
890
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
892
perm->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT;
897
* Handle incoming packet from client. This would have been called by
898
* server upon receiving packet from a listener.
900
PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc,
906
/* Lock this allocation */
907
pj_lock_acquire(alloc->lock);
909
/* Quickly check if this is STUN message */
910
is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0);
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()
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.
924
unsigned options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
925
pj_size_t parsed_len = 0;
927
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
928
options |= PJ_STUN_IS_DATAGRAM;
930
status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len,
931
options, NULL, &parsed_len,
935
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
937
} else if (parsed_len > 0) {
938
if (parsed_len == pkt->len) {
941
pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
942
pkt->len - parsed_len);
943
pkt->len -= parsed_len;
947
if (status != PJ_SUCCESS) {
948
alloc_err(alloc, "Error handling STUN packet", status);
954
* This is not a STUN packet, must be ChannelData packet.
956
pj_turn_channel_data *cd = (pj_turn_channel_data*)pkt->pkt;
957
pj_turn_permission *perm;
960
pj_assert(sizeof(*cd)==4);
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",
971
pj_assert(!"Unsupported transport");
975
perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number));
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)));
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));
990
/* Refresh permission */
991
refresh_permission(perm);
996
pj_lock_release(alloc->lock);
1001
* Handle incoming packet from peer. This function is called by
1002
* on_rx_from_peer().
1004
static 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)
1009
pj_turn_permission *perm;
1011
/* Lookup permission */
1012
perm = lookup_permission_by_addr(alloc, src_addr,
1013
pj_sockaddr_get_len(src_addr));
1015
/* No permission, discard data */
1019
/* Send Data Indication or ChannelData, depends on whether
1020
* this permission is attached to a channel number.
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;
1026
if (len > PJ_TURN_MAX_PKT_LEN) {
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));
1036
cd->ch_number = pj_htons(perm->channel);
1037
cd->length = pj_htons((pj_uint16_t)len);
1040
pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
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));
1048
/* Send Data Indication */
1049
pj_stun_tx_data *tdata;
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);
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,
1064
(const pj_uint8_t*)pkt, len);
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),
1074
* ioqueue notification on RX packets from the relay socket.
1076
static void on_rx_from_peer(pj_ioqueue_key_t *key,
1077
pj_ioqueue_op_key_t *op_key,
1078
pj_ssize_t bytes_read)
1080
pj_turn_relay_res *rel;
1083
rel = (pj_turn_relay_res*) pj_ioqueue_get_user_data(key);
1085
/* Lock the allocation */
1086
pj_lock_acquire(rel->allocation->lock);
1089
if (bytes_read > 0) {
1090
handle_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
1091
bytes_read, &rel->tp.src_addr);
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,
1100
&rel->tp.src_addr_len);
1102
if (status != PJ_EPENDING && status != PJ_SUCCESS)
1103
bytes_read = -status;
1105
} while (status != PJ_EPENDING && status != PJ_ECANCELLED);
1107
/* Release allocation lock */
1108
pj_lock_release(rel->allocation->lock);
1112
* Callback notification from STUN session when it wants to send
1113
* a STUN message towards the client.
1115
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
1119
const pj_sockaddr_t *dst_addr,
1122
pj_turn_allocation *alloc;
1124
PJ_UNUSED_ARG(token);
1126
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1128
return alloc->transport->sendto(alloc->transport, pkt, pkt_size, 0,
1129
dst_addr, addr_len);
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().
1137
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
1138
const pj_uint8_t *pkt,
1140
const pj_stun_rx_data *rdata,
1142
const pj_sockaddr_t *src_addr,
1143
unsigned src_addr_len)
1145
const pj_stun_msg *msg = rdata->msg;
1146
pj_turn_allocation *alloc;
1149
PJ_UNUSED_ARG(pkt_len);
1150
PJ_UNUSED_ARG(token);
1151
PJ_UNUSED_ARG(src_addr);
1152
PJ_UNUSED_ARG(src_addr_len);
1154
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
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);
1164
if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) {
1166
* Handle REFRESH request
1168
pj_stun_lifetime_attr *lifetime;
1169
pj_stun_bandwidth_attr *bandwidth;
1171
/* Get LIFETIME attribute */
1172
lifetime = (pj_stun_lifetime_attr*)
1173
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1175
/* Get BANDWIDTH attribute */
1176
bandwidth = (pj_stun_bandwidth_attr*)
1177
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
1179
if (lifetime && lifetime->value==0) {
1181
* This is deallocation request.
1183
alloc->relay.lifetime = 0;
1186
send_reply_ok(alloc, rdata);
1188
/* Shutdown allocation */
1189
PJ_LOG(4,(alloc->obj_name,
1190
"Client %s request to dealloc, shutting down",
1193
alloc_shutdown(alloc);
1197
* This is a refresh request.
1200
/* Update lifetime */
1202
alloc->relay.lifetime = lifetime->value;
1205
/* Update bandwidth */
1208
/* Update expiration timer */
1209
resched_timeout(alloc);
1212
send_reply_ok(alloc, rdata);
1215
} else if (msg->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
1217
* ChannelBind request.
1219
pj_stun_channel_number_attr *ch_attr;
1220
pj_stun_xor_peer_addr_attr *peer_attr;
1221
pj_turn_permission *p1, *p2;
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);
1228
if (!ch_attr || !peer_attr) {
1229
send_reply_err(alloc, rdata, PJ_TRUE,
1230
PJ_STUN_SC_BAD_REQUEST, NULL);
1234
/* Find permission with the channel number */
1235
p1 = lookup_permission_by_chnum(alloc, PJ_STUN_GET_CH_NB(ch_attr->value));
1237
/* If permission is found, this is supposed to be a channel bind
1238
* refresh. Make sure it's for the same peer.
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");
1249
/* Refresh permission */
1250
refresh_permission(p1);
1253
send_reply_ok(alloc, rdata);
1259
/* If permission is not found, create a new one. Make sure the peer
1260
* has not alreadyy assigned with a channel number.
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");
1270
/* Create permission if it doesn't exist */
1272
p2 = create_permission(alloc, &peer_attr->sockaddr,
1273
pj_sockaddr_get_len(&peer_attr->sockaddr));
1278
/* Assign channel number to permission */
1279
p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
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);
1287
refresh_permission(p2);
1290
send_reply_ok(alloc, rdata);
1294
} else if (msg->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
1296
/* Respond with 437 (section 6.3 turn-07) */
1297
send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_ALLOCATION_MISMATCH,
1302
/* Respond with Bad Request? */
1303
send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
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().
1315
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
1316
const pj_uint8_t *pkt,
1318
const pj_stun_msg *msg,
1320
const pj_sockaddr_t *src_addr,
1321
unsigned src_addr_len)
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;
1330
PJ_UNUSED_ARG(pkt_len);
1331
PJ_UNUSED_ARG(token);
1332
PJ_UNUSED_ARG(src_addr);
1333
PJ_UNUSED_ARG(src_addr_len);
1335
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1337
/* Only expect Send Indication */
1338
if (msg->hdr.type != PJ_STUN_SEND_INDICATION) {
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);
1347
/* MUST have XOR-PEER-ADDRESS attribute */
1351
/* Get DATA attribute */
1352
data_attr = (pj_stun_data_attr*)
1353
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1355
/* Create/update/refresh the permission */
1356
perm = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1357
pj_sockaddr_get_len(&peer_attr->sockaddr));
1359
perm = create_permission(alloc, &peer_attr->sockaddr,
1360
pj_sockaddr_get_len(&peer_attr->sockaddr));
1362
refresh_permission(perm);
1364
/* Return if we don't have data */
1365
if (data_attr == NULL)
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));