1
/* $Id: allocation.c 2589 2009-04-13 08:54:10Z bennylp $ */
3
* Copyright (C) 2008-2009 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
20
* Additional permission under GNU GPL version 3 section 7:
22
* If you modify this program, or any covered work, by linking or
23
* combining it with the OpenSSL project's OpenSSL library (or a
24
* modified version of that library), containing parts covered by the
25
* terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
26
* grants you additional permission to convey the resulting work.
27
* Corresponding Source for a non-source form of such a combination
28
* shall include the source code for the parts of OpenSSL used as well
29
* as that of the covered work.
35
#define THIS_FILE "allocation.c"
44
#define DESTROY_DELAY {0, 500}
45
#define PEER_TABLE_SIZE 32
47
#define MAX_CLIENT_BANDWIDTH 128 /* In Kbps */
48
#define DEFA_CLIENT_BANDWIDTH 64
50
#define MIN_LIFETIME 30
51
#define MAX_LIFETIME 600
52
#define DEF_LIFETIME 300
55
/* Parsed Allocation request. */
56
typedef struct alloc_request
58
unsigned tp_type; /* Requested transport */
59
char addr[PJ_INET6_ADDRSTRLEN]; /* Requested IP */
60
unsigned bandwidth; /* Requested bandwidth */
61
unsigned lifetime; /* Lifetime. */
62
unsigned rpp_bits; /* A bits */
63
unsigned rpp_port; /* Requested port */
69
static void destroy_allocation(pj_turn_allocation *alloc);
70
static pj_status_t create_relay(pj_turn_srv *srv,
71
pj_turn_allocation *alloc,
72
const pj_stun_msg *msg,
73
const alloc_request *req,
74
pj_turn_relay_res *relay);
75
static void destroy_relay(pj_turn_relay_res *relay);
76
static void on_rx_from_peer(pj_ioqueue_key_t *key,
77
pj_ioqueue_op_key_t *op_key,
78
pj_ssize_t bytes_read);
79
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
83
const pj_sockaddr_t *dst_addr,
85
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
86
const pj_uint8_t *pkt,
88
const pj_stun_rx_data *rdata,
90
const pj_sockaddr_t *src_addr,
91
unsigned src_addr_len);
92
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
93
const pj_uint8_t *pkt,
95
const pj_stun_msg *msg,
97
const pj_sockaddr_t *src_addr,
98
unsigned src_addr_len);
100
/* Log allocation error */
101
static void alloc_err(pj_turn_allocation *alloc, const char *title,
104
char errmsg[PJ_ERR_MSG_SIZE];
106
pj_strerror(status, errmsg, sizeof(errmsg));
107
PJ_LOG(4,(alloc->obj_name, "%s for client %s: %s",
108
title, alloc->info, errmsg));
112
/* Parse ALLOCATE request */
113
static pj_status_t parse_allocate_req(alloc_request *cfg,
114
pj_stun_session *sess,
115
const pj_stun_rx_data *rdata,
116
const pj_sockaddr_t *src_addr,
117
unsigned src_addr_len)
119
const pj_stun_msg *req = rdata->msg;
120
pj_stun_bandwidth_attr *attr_bw;
121
pj_stun_req_transport_attr *attr_req_tp;
122
pj_stun_res_token_attr *attr_res_token;
123
pj_stun_lifetime_attr *attr_lifetime;
125
pj_bzero(cfg, sizeof(*cfg));
127
/* Get BANDWIDTH attribute, if any. */
128
attr_bw = (pj_stun_uint_attr*)
129
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_BANDWIDTH, 0);
131
cfg->bandwidth = attr_bw->value;
133
cfg->bandwidth = DEFA_CLIENT_BANDWIDTH;
136
/* Check if we can satisfy the bandwidth */
137
if (cfg->bandwidth > MAX_CLIENT_BANDWIDTH) {
138
pj_stun_session_respond(sess, rdata,
139
PJ_STUN_SC_ALLOCATION_QUOTA_REACHED,
140
"Invalid bandwidth", NULL, PJ_TRUE,
141
src_addr, src_addr_len);
142
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ALLOCATION_QUOTA_REACHED);
145
/* MUST have REQUESTED-TRANSPORT attribute */
146
attr_req_tp = (pj_stun_uint_attr*)
147
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_TRANSPORT, 0);
148
if (attr_req_tp == NULL) {
149
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
150
"Missing REQUESTED-TRANSPORT attribute",
151
NULL, PJ_TRUE, src_addr, src_addr_len);
152
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
155
cfg->tp_type = PJ_STUN_GET_RT_PROTO(attr_req_tp->value);
157
/* Can only support UDP for now */
158
if (cfg->tp_type != PJ_TURN_TP_UDP) {
159
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO,
160
NULL, NULL, PJ_TRUE, src_addr, src_addr_len);
161
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO);
164
/* Get RESERVATION-TOKEN attribute, if any */
165
attr_res_token = (pj_stun_res_token_attr*)
166
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_RESERVATION_TOKEN,
168
if (attr_res_token) {
169
/* We don't support RESERVATION-TOKEN for now */
170
pj_stun_session_respond(sess, rdata,
171
PJ_STUN_SC_BAD_REQUEST,
172
"RESERVATION-TOKEN is not supported", NULL,
173
PJ_TRUE, src_addr, src_addr_len);
174
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
177
/* Get LIFETIME attribute */
178
attr_lifetime = (pj_stun_uint_attr*)
179
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
181
cfg->lifetime = attr_lifetime->value;
182
if (cfg->lifetime < MIN_LIFETIME) {
183
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
184
"LIFETIME too short", NULL,
185
PJ_TRUE, src_addr, src_addr_len);
186
return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
188
if (cfg->lifetime > MAX_LIFETIME)
189
cfg->lifetime = MAX_LIFETIME;
191
cfg->lifetime = DEF_LIFETIME;
198
/* Respond to ALLOCATE request */
199
static pj_status_t send_allocate_response(pj_turn_allocation *alloc,
200
pj_stun_session *srv_sess,
201
pj_turn_transport *transport,
202
const pj_stun_rx_data *rdata)
204
pj_stun_tx_data *tdata;
207
/* Respond the original ALLOCATE request */
208
status = pj_stun_session_create_res(srv_sess, rdata, 0, NULL, &tdata);
209
if (status != PJ_SUCCESS)
212
/* Add XOR-RELAYED-ADDRESS attribute */
213
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
214
PJ_STUN_ATTR_XOR_RELAYED_ADDR, PJ_TRUE,
215
&alloc->relay.hkey.addr,
216
pj_sockaddr_get_len(&alloc->relay.hkey.addr));
219
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
220
PJ_STUN_ATTR_LIFETIME,
221
(unsigned)alloc->relay.lifetime);
224
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
225
PJ_STUN_ATTR_BANDWIDTH,
228
/* Add RESERVATION-TOKEN */
229
PJ_TODO(ADD_RESERVATION_TOKEN);
231
/* Add XOR-MAPPED-ADDRESS */
232
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
233
PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
234
&alloc->hkey.clt_addr,
235
pj_sockaddr_get_len(&alloc->hkey.clt_addr));
237
/* Send the response */
238
return pj_stun_session_send_msg(srv_sess, transport, PJ_TRUE,
239
PJ_FALSE, &alloc->hkey.clt_addr,
240
pj_sockaddr_get_len(&alloc->hkey.clt_addr),
246
* Init credential for the allocation. We use static credential, meaning that
247
* the user's password must not change during allocation.
249
static pj_status_t init_cred(pj_turn_allocation *alloc, const pj_stun_msg *req)
251
const pj_stun_username_attr *user;
252
const pj_stun_realm_attr *realm;
253
const pj_stun_nonce_attr *nonce;
256
realm = (const pj_stun_realm_attr*)
257
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REALM, 0);
258
PJ_ASSERT_RETURN(realm != NULL, PJ_EBUG);
260
user = (const pj_stun_username_attr*)
261
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0);
262
PJ_ASSERT_RETURN(user != NULL, PJ_EBUG);
264
nonce = (const pj_stun_nonce_attr*)
265
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_NONCE, 0);
266
PJ_ASSERT_RETURN(nonce != NULL, PJ_EBUG);
268
/* Lookup the password */
269
status = pj_turn_get_password(NULL, NULL, &realm->value,
270
&user->value, alloc->pool,
271
&alloc->cred.data.static_cred.data_type,
272
&alloc->cred.data.static_cred.data);
273
if (status != PJ_SUCCESS)
276
/* Save credential */
277
alloc->cred.type = PJ_STUN_AUTH_CRED_STATIC;
278
pj_strdup(alloc->pool, &alloc->cred.data.static_cred.realm, &realm->value);
279
pj_strdup(alloc->pool, &alloc->cred.data.static_cred.username, &user->value);
280
pj_strdup(alloc->pool, &alloc->cred.data.static_cred.nonce, &nonce->value);
287
* Create new allocation.
289
PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport,
290
const pj_sockaddr_t *src_addr,
291
unsigned src_addr_len,
292
const pj_stun_rx_data *rdata,
293
pj_stun_session *srv_sess,
294
pj_turn_allocation **p_alloc)
296
pj_turn_srv *srv = transport->listener->server;
297
const pj_stun_msg *msg = rdata->msg;
300
pj_turn_allocation *alloc;
301
pj_stun_session_cb sess_cb;
305
/* Parse ALLOCATE request */
306
status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len);
307
if (status != PJ_SUCCESS)
310
pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);
312
/* Init allocation structure */
313
alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation);
315
alloc->obj_name = pool->obj_name;
316
alloc->relay.tp.sock = PJ_INVALID_SOCKET;
317
alloc->server = transport->listener->server;
319
alloc->bandwidth = req.bandwidth;
322
alloc->transport = transport;
323
pj_turn_transport_add_ref(transport, alloc);
325
alloc->hkey.tp_type = transport->listener->tp_type;
326
pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);
328
status = pj_lock_create_recursive_mutex(pool, alloc->obj_name,
330
if (status != PJ_SUCCESS) {
334
/* Create peer hash table */
335
alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);
337
/* Create channel hash table */
338
alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);
341
pj_ansi_strcpy(alloc->info,
342
pj_turn_tp_type_name(transport->listener->tp_type));
343
alloc->info[3] = ':';
344
pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3);
346
/* Create STUN session to handle STUN communication with client */
347
pj_bzero(&sess_cb, sizeof(sess_cb));
348
sess_cb.on_send_msg = &stun_on_send_msg;
349
sess_cb.on_rx_request = &stun_on_rx_request;
350
sess_cb.on_rx_indication = &stun_on_rx_indication;
351
status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name,
352
&sess_cb, PJ_FALSE, &alloc->sess);
353
if (status != PJ_SUCCESS) {
357
/* Attach to STUN session */
358
pj_stun_session_set_user_data(alloc->sess, alloc);
360
/* Init authentication credential */
361
status = init_cred(alloc, msg);
362
if (status != PJ_SUCCESS) {
366
/* Attach authentication credential to STUN session */
367
pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM,
370
/* Create the relay resource */
371
status = create_relay(srv, alloc, msg, &req, &alloc->relay);
372
if (status != PJ_SUCCESS) {
376
/* Register this allocation */
377
pj_turn_srv_register_allocation(srv, alloc);
379
/* Respond to ALLOCATE request */
380
status = send_allocate_response(alloc, srv_sess, transport, rdata);
381
if (status != PJ_SUCCESS)
385
pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp,
387
PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s",
388
alloc->info, pj_turn_tp_type_name(req.tp_type), str_tmp));
395
/* Send reply to the ALLOCATE request */
396
pj_strerror(status, str_tmp, sizeof(str_tmp));
397
pj_stun_session_respond(srv_sess, rdata, PJ_STUN_SC_BAD_REQUEST, str_tmp,
398
transport, PJ_TRUE, src_addr, src_addr_len);
401
destroy_allocation(alloc);
406
/* Destroy relay resource */
407
static void destroy_relay(pj_turn_relay_res *relay)
409
if (relay->timer.id) {
410
pj_timer_heap_cancel(relay->allocation->server->core.timer_heap,
412
relay->timer.id = PJ_FALSE;
416
pj_ioqueue_unregister(relay->tp.key);
417
relay->tp.key = NULL;
418
relay->tp.sock = PJ_INVALID_SOCKET;
419
} else if (relay->tp.sock != PJ_INVALID_SOCKET) {
420
pj_sock_close(relay->tp.sock);
421
relay->tp.sock = PJ_INVALID_SOCKET;
424
/* Mark as shutdown */
430
* Really destroy allocation.
432
static void destroy_allocation(pj_turn_allocation *alloc)
436
/* Unregister this allocation */
437
pj_turn_srv_unregister_allocation(alloc->server, alloc);
440
destroy_relay(&alloc->relay);
442
/* Must lock only after destroying relay otherwise deadlock */
444
pj_lock_acquire(alloc->lock);
447
/* Unreference transport */
448
if (alloc->transport) {
449
pj_turn_transport_dec_ref(alloc->transport, alloc);
450
alloc->transport = NULL;
453
/* Destroy STUN session */
455
pj_stun_session_destroy(alloc->sess);
461
pj_lock_release(alloc->lock);
462
pj_lock_destroy(alloc->lock);
470
pj_pool_release(pool);
475
PJ_DECL(void) pj_turn_allocation_destroy(pj_turn_allocation *alloc)
477
destroy_allocation(alloc);
482
* Handle transport closure.
484
PJ_DEF(void) pj_turn_allocation_on_transport_closed( pj_turn_allocation *alloc,
485
pj_turn_transport *tp)
487
PJ_LOG(5,(alloc->obj_name, "Transport %s unexpectedly closed, destroying "
488
"allocation %s", tp->info, alloc->info));
489
pj_turn_transport_dec_ref(tp, alloc);
490
alloc->transport = NULL;
491
destroy_allocation(alloc);
495
/* Initiate shutdown sequence for this allocation and start destroy timer.
496
* Once allocation is marked as shutting down, any packets will be
499
static void alloc_shutdown(pj_turn_allocation *alloc)
501
pj_time_val destroy_delay = DESTROY_DELAY;
503
/* Work with existing schedule */
504
if (alloc->relay.timer.id == TIMER_ID_TIMEOUT) {
505
/* Cancel existing shutdown timer */
506
pj_timer_heap_cancel(alloc->server->core.timer_heap,
507
&alloc->relay.timer);
508
alloc->relay.timer.id = TIMER_ID_NONE;
510
} else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
511
/* We've been scheduled to be destroyed, ignore this
517
pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);
519
/* Shutdown relay socket */
520
destroy_relay(&alloc->relay);
522
/* Don't unregister from hash table because we still need to
523
* handle REFRESH retransmission.
526
/* Schedule destroy timer */
527
alloc->relay.timer.id = TIMER_ID_DESTROY;
528
pj_timer_heap_schedule(alloc->server->core.timer_heap,
529
&alloc->relay.timer, &destroy_delay);
533
/* Reschedule timeout using current lifetime setting */
534
static pj_status_t resched_timeout(pj_turn_allocation *alloc)
539
pj_gettimeofday(&alloc->relay.expiry);
540
alloc->relay.expiry.sec += alloc->relay.lifetime;
542
pj_assert(alloc->relay.timer.id != TIMER_ID_DESTROY);
543
if (alloc->relay.timer.id != 0) {
544
pj_timer_heap_cancel(alloc->server->core.timer_heap,
545
&alloc->relay.timer);
546
alloc->relay.timer.id = TIMER_ID_NONE;
549
delay.sec = alloc->relay.lifetime;
552
alloc->relay.timer.id = TIMER_ID_TIMEOUT;
553
status = pj_timer_heap_schedule(alloc->server->core.timer_heap,
554
&alloc->relay.timer, &delay);
555
if (status != PJ_SUCCESS) {
556
alloc->relay.timer.id = TIMER_ID_NONE;
564
/* Timer timeout callback */
565
static void relay_timeout_cb(pj_timer_heap_t *heap, pj_timer_entry *e)
567
pj_turn_relay_res *rel;
568
pj_turn_allocation *alloc;
572
rel = (pj_turn_relay_res*) e->user_data;
573
alloc = rel->allocation;
575
if (e->id == TIMER_ID_TIMEOUT) {
577
e->id = TIMER_ID_NONE;
579
PJ_LOG(4,(alloc->obj_name,
580
"Client %s refresh timed-out, shutting down..",
583
alloc_shutdown(alloc);
585
} else if (e->id == TIMER_ID_DESTROY) {
586
e->id = TIMER_ID_NONE;
588
PJ_LOG(4,(alloc->obj_name, "Client %s destroying..",
591
destroy_allocation(alloc);
599
static pj_status_t create_relay(pj_turn_srv *srv,
600
pj_turn_allocation *alloc,
601
const pj_stun_msg *msg,
602
const alloc_request *req,
603
pj_turn_relay_res *relay)
606
pj_pool_t *pool = alloc->pool;
607
int retry, retry_max, sock_type;
608
pj_ioqueue_callback icb;
610
pj_stun_string_attr *sa;
613
pj_bzero(relay, sizeof(*relay));
615
relay->allocation = alloc;
616
relay->tp.sock = PJ_INVALID_SOCKET;
618
/* TODO: get the requested address family from somewhere */
619
af = alloc->transport->listener->addr.addr.sa_family;
622
sa = (pj_stun_string_attr*)
623
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
624
PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
625
pj_strdup(pool, &relay->realm, &sa->value);
628
sa = (pj_stun_string_attr*)
629
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
630
PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
631
pj_strdup(pool, &relay->user, &sa->value);
633
/* Lifetime and timeout */
634
relay->lifetime = req->lifetime;
635
pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
637
resched_timeout(alloc);
640
relay->hkey.tp_type = req->tp_type;
642
/* Create the socket */
643
if (req->tp_type == PJ_TURN_TP_UDP) {
644
sock_type = pj_SOCK_DGRAM();
645
} else if (req->tp_type == PJ_TURN_TP_TCP) {
646
sock_type = pj_SOCK_STREAM();
648
pj_assert(!"Unknown transport");
649
return PJ_EINVALIDOP;
652
status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
653
if (status != PJ_SUCCESS) {
654
pj_bzero(relay, sizeof(*relay));
658
/* Find suitable port for this allocation */
665
for (retry=0; retry<retry_max; ++retry) {
667
pj_sockaddr bound_addr;
669
pj_lock_acquire(srv->core.lock);
672
port = (pj_uint16_t) req->rpp_port;
673
} else if (req->tp_type == PJ_TURN_TP_UDP) {
674
port = (pj_uint16_t) srv->ports.next_udp++;
675
if (srv->ports.next_udp > srv->ports.max_udp)
676
srv->ports.next_udp = srv->ports.min_udp;
677
} else if (req->tp_type == PJ_TURN_TP_TCP) {
678
port = (pj_uint16_t) srv->ports.next_tcp++;
679
if (srv->ports.next_tcp > srv->ports.max_tcp)
680
srv->ports.next_tcp = srv->ports.min_tcp;
682
pj_assert(!"Invalid transport");
686
pj_lock_release(srv->core.lock);
688
pj_sockaddr_init(af, &bound_addr, NULL, port);
690
status = pj_sock_bind(relay->tp.sock, &bound_addr,
691
pj_sockaddr_get_len(&bound_addr));
692
if (status == PJ_SUCCESS)
696
if (status != PJ_SUCCESS) {
697
/* Unable to allocate port */
698
PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
700
pj_sock_close(relay->tp.sock);
701
relay->tp.sock = PJ_INVALID_SOCKET;
706
namelen = sizeof(relay->hkey.addr);
707
status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
708
if (status != PJ_SUCCESS) {
709
PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d",
711
pj_sock_close(relay->tp.sock);
712
relay->tp.sock = PJ_INVALID_SOCKET;
715
if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
716
pj_sockaddr_copy_addr(&relay->hkey.addr,
717
&alloc->transport->listener->addr);
719
if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
720
pj_sockaddr tmp_addr;
721
pj_gethostip(af, &tmp_addr);
722
pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
726
pj_bzero(&icb, sizeof(icb));
727
icb.on_read_complete = &on_rx_from_peer;
729
status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
730
relay, &icb, &relay->tp.key);
731
if (status != PJ_SUCCESS) {
732
PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d",
734
pj_sock_close(relay->tp.sock);
735
relay->tp.sock = PJ_INVALID_SOCKET;
739
/* Kick off pending read operation */
740
pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
741
on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);
747
/* Create and send error response */
748
static void send_reply_err(pj_turn_allocation *alloc,
749
const pj_stun_rx_data *rdata,
751
int code, const char *errmsg)
755
status = pj_stun_session_respond(alloc->sess, rdata, code, errmsg, NULL,
756
cache, &alloc->hkey.clt_addr,
757
pj_sockaddr_get_len(&alloc->hkey.clt_addr.addr));
758
if (status != PJ_SUCCESS) {
759
alloc_err(alloc, "Error sending STUN error response", status);
764
/* Create and send successful response */
765
static void send_reply_ok(pj_turn_allocation *alloc,
766
const pj_stun_rx_data *rdata)
770
pj_stun_tx_data *tdata;
772
status = pj_stun_session_create_res(alloc->sess, rdata, 0, NULL, &tdata);
773
if (status != PJ_SUCCESS) {
774
alloc_err(alloc, "Error creating STUN success response", status);
778
/* Calculate time to expiration */
779
if (alloc->relay.lifetime != 0) {
781
pj_gettimeofday(&now);
782
interval = alloc->relay.expiry.sec - now.sec;
787
/* Add LIFETIME if this is not ChannelBind. */
788
if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){
789
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
790
PJ_STUN_ATTR_LIFETIME, interval);
792
/* Add BANDWIDTH if lifetime is not zero */
794
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
795
PJ_STUN_ATTR_BANDWIDTH,
800
status = pj_stun_session_send_msg(alloc->sess, NULL, PJ_TRUE,
801
PJ_FALSE, &alloc->hkey.clt_addr,
802
pj_sockaddr_get_len(&alloc->hkey.clt_addr),
804
if (status != PJ_SUCCESS) {
805
alloc_err(alloc, "Error sending STUN success response", status);
811
/* Create new permission */
812
static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
813
const pj_sockaddr_t *peer_addr,
816
pj_turn_permission *perm;
818
perm = PJ_POOL_ZALLOC_T(alloc->pool, pj_turn_permission);
819
pj_memcpy(&perm->hkey.peer_addr, peer_addr, addr_len);
821
perm->allocation = alloc;
822
perm->channel = PJ_TURN_INVALID_CHANNEL;
824
pj_gettimeofday(&perm->expiry);
825
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
827
/* Register to hash table (only the address part!) */
828
pj_hash_set(alloc->pool, alloc->peer_table,
829
pj_sockaddr_get_addr(&perm->hkey.peer_addr),
830
pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, perm);
835
/* Check if a permission isn't expired. Return NULL if expired. */
836
static pj_turn_permission *check_permission_expiry(pj_turn_permission *perm)
838
pj_turn_allocation *alloc = perm->allocation;
841
pj_gettimeofday(&now);
842
if (PJ_TIME_VAL_GT(perm->expiry, now)) {
843
/* Permission has not expired */
847
/* Remove from permission hash table */
848
pj_hash_set(NULL, alloc->peer_table,
849
pj_sockaddr_get_addr(&perm->hkey.peer_addr),
850
pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, NULL);
852
/* Remove from channel hash table, if assigned a channel number */
853
if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
854
pj_hash_set(NULL, alloc->ch_table, &perm->channel,
855
sizeof(perm->channel), 0, NULL);
861
/* Lookup permission in hash table by the peer address */
862
static pj_turn_permission*
863
lookup_permission_by_addr(pj_turn_allocation *alloc,
864
const pj_sockaddr_t *peer_addr,
867
pj_turn_permission *perm;
869
PJ_UNUSED_ARG(addr_len);
871
/* Lookup in peer hash table */
872
perm = (pj_turn_permission*)
873
pj_hash_get(alloc->peer_table,
874
pj_sockaddr_get_addr(peer_addr),
875
pj_sockaddr_get_addr_len(peer_addr),
877
return perm ? check_permission_expiry(perm) : NULL;
880
/* Lookup permission in hash table by the channel number */
881
static pj_turn_permission*
882
lookup_permission_by_chnum(pj_turn_allocation *alloc,
885
pj_uint16_t chnum16 = (pj_uint16_t)chnum;
886
pj_turn_permission *perm;
888
/* Lookup in peer hash table */
889
perm = (pj_turn_permission*) pj_hash_get(alloc->ch_table, &chnum16,
890
sizeof(chnum16), NULL);
891
return perm ? check_permission_expiry(perm) : NULL;
894
/* Update permission because of data from client to peer.
895
* Return PJ_TRUE is permission is found.
897
static pj_bool_t refresh_permission(pj_turn_permission *perm)
899
pj_gettimeofday(&perm->expiry);
900
if (perm->channel == PJ_TURN_INVALID_CHANNEL)
901
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
903
perm->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT;
908
* Handle incoming packet from client. This would have been called by
909
* server upon receiving packet from a listener.
911
PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc,
917
/* Lock this allocation */
918
pj_lock_acquire(alloc->lock);
920
/* Quickly check if this is STUN message */
921
is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0);
925
* This could be an incoming STUN requests or indications.
926
* Pass this through to the STUN session, which will call
927
* our stun_on_rx_request() or stun_on_rx_indication()
930
* Note: currently it is necessary to specify the
931
* PJ_STUN_NO_FINGERPRINT_CHECK otherwise the FINGERPRINT
932
* attribute inside STUN Send Indication message will mess up
933
* with fingerprint checking.
935
unsigned options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
936
pj_size_t parsed_len = 0;
938
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
939
options |= PJ_STUN_IS_DATAGRAM;
941
status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len,
942
options, NULL, &parsed_len,
946
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
948
} else if (parsed_len > 0) {
949
if (parsed_len == pkt->len) {
952
pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
953
pkt->len - parsed_len);
954
pkt->len -= parsed_len;
958
if (status != PJ_SUCCESS) {
959
alloc_err(alloc, "Error handling STUN packet", status);
965
* This is not a STUN packet, must be ChannelData packet.
967
pj_turn_channel_data *cd = (pj_turn_channel_data*)pkt->pkt;
968
pj_turn_permission *perm;
971
pj_assert(sizeof(*cd)==4);
973
/* For UDP check the packet length */
974
if (alloc->transport->listener->tp_type == PJ_TURN_TP_UDP) {
975
if (pkt->len < pj_ntohs(cd->length)+sizeof(*cd)) {
976
PJ_LOG(4,(alloc->obj_name,
977
"ChannelData from %s discarded: UDP size error",
982
pj_assert(!"Unsupported transport");
986
perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number));
989
PJ_LOG(4,(alloc->obj_name,
990
"ChannelData from %s discarded: ch#0x%x not found",
991
alloc->info, pj_ntohs(cd->ch_number)));
996
len = pj_ntohs(cd->length);
997
pj_sock_sendto(alloc->relay.tp.sock, cd+1, &len, 0,
998
&perm->hkey.peer_addr,
999
pj_sockaddr_get_len(&perm->hkey.peer_addr));
1001
/* Refresh permission */
1002
refresh_permission(perm);
1007
pj_lock_release(alloc->lock);
1012
* Handle incoming packet from peer. This function is called by
1013
* on_rx_from_peer().
1015
static void handle_peer_pkt(pj_turn_allocation *alloc,
1016
pj_turn_relay_res *rel,
1017
char *pkt, pj_size_t len,
1018
const pj_sockaddr *src_addr)
1020
pj_turn_permission *perm;
1022
/* Lookup permission */
1023
perm = lookup_permission_by_addr(alloc, src_addr,
1024
pj_sockaddr_get_len(src_addr));
1026
/* No permission, discard data */
1030
/* Send Data Indication or ChannelData, depends on whether
1031
* this permission is attached to a channel number.
1033
if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
1034
/* Send ChannelData */
1035
pj_turn_channel_data *cd = (pj_turn_channel_data*)rel->tp.tx_pkt;
1037
if (len > PJ_TURN_MAX_PKT_LEN) {
1039
pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3);
1040
PJ_LOG(4,(alloc->obj_name, "Client %s: discarded data from %s "
1041
"because it's too long (%d bytes)",
1042
alloc->info, peer_addr, len));
1047
cd->ch_number = pj_htons(perm->channel);
1048
cd->length = pj_htons((pj_uint16_t)len);
1051
pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
1053
/* Send to client */
1054
alloc->transport->sendto(alloc->transport, rel->tp.tx_pkt,
1055
len+sizeof(pj_turn_channel_data), 0,
1056
&alloc->hkey.clt_addr,
1057
pj_sockaddr_get_len(&alloc->hkey.clt_addr));
1059
/* Send Data Indication */
1060
pj_stun_tx_data *tdata;
1063
status = pj_stun_session_create_ind(alloc->sess,
1064
PJ_STUN_DATA_INDICATION, &tdata);
1065
if (status != PJ_SUCCESS) {
1066
alloc_err(alloc, "Error creating Data indication", status);
1070
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
1071
PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
1072
src_addr, pj_sockaddr_get_len(src_addr));
1073
pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
1075
(const pj_uint8_t*)pkt, len);
1077
pj_stun_session_send_msg(alloc->sess, NULL, PJ_FALSE,
1078
PJ_FALSE, &alloc->hkey.clt_addr,
1079
pj_sockaddr_get_len(&alloc->hkey.clt_addr),
1085
* ioqueue notification on RX packets from the relay socket.
1087
static void on_rx_from_peer(pj_ioqueue_key_t *key,
1088
pj_ioqueue_op_key_t *op_key,
1089
pj_ssize_t bytes_read)
1091
pj_turn_relay_res *rel;
1094
rel = (pj_turn_relay_res*) pj_ioqueue_get_user_data(key);
1096
/* Lock the allocation */
1097
pj_lock_acquire(rel->allocation->lock);
1100
if (bytes_read > 0) {
1101
handle_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
1102
bytes_read, &rel->tp.src_addr);
1105
/* Read next packet */
1106
bytes_read = sizeof(rel->tp.rx_pkt);
1107
rel->tp.src_addr_len = sizeof(rel->tp.src_addr);
1108
status = pj_ioqueue_recvfrom(key, op_key,
1109
rel->tp.rx_pkt, &bytes_read, 0,
1111
&rel->tp.src_addr_len);
1113
if (status != PJ_EPENDING && status != PJ_SUCCESS)
1114
bytes_read = -status;
1116
} while (status != PJ_EPENDING && status != PJ_ECANCELLED);
1118
/* Release allocation lock */
1119
pj_lock_release(rel->allocation->lock);
1123
* Callback notification from STUN session when it wants to send
1124
* a STUN message towards the client.
1126
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
1130
const pj_sockaddr_t *dst_addr,
1133
pj_turn_allocation *alloc;
1135
PJ_UNUSED_ARG(token);
1137
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1139
return alloc->transport->sendto(alloc->transport, pkt, pkt_size, 0,
1140
dst_addr, addr_len);
1144
* Callback notification from STUN session when it receives STUN
1145
* requests. This callback was trigger by STUN incoming message
1146
* processing in pj_turn_allocation_on_rx_client_pkt().
1148
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
1149
const pj_uint8_t *pkt,
1151
const pj_stun_rx_data *rdata,
1153
const pj_sockaddr_t *src_addr,
1154
unsigned src_addr_len)
1156
const pj_stun_msg *msg = rdata->msg;
1157
pj_turn_allocation *alloc;
1160
PJ_UNUSED_ARG(pkt_len);
1161
PJ_UNUSED_ARG(token);
1162
PJ_UNUSED_ARG(src_addr);
1163
PJ_UNUSED_ARG(src_addr_len);
1165
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1167
/* Refuse to serve any request if we've been shutdown */
1168
if (alloc->relay.lifetime == 0) {
1169
/* Reject with 437 if we're shutting down */
1170
send_reply_err(alloc, rdata, PJ_TRUE,
1171
PJ_STUN_SC_ALLOCATION_MISMATCH, NULL);
1175
if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) {
1177
* Handle REFRESH request
1179
pj_stun_lifetime_attr *lifetime;
1180
pj_stun_bandwidth_attr *bandwidth;
1182
/* Get LIFETIME attribute */
1183
lifetime = (pj_stun_lifetime_attr*)
1184
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1186
/* Get BANDWIDTH attribute */
1187
bandwidth = (pj_stun_bandwidth_attr*)
1188
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
1190
if (lifetime && lifetime->value==0) {
1192
* This is deallocation request.
1194
alloc->relay.lifetime = 0;
1197
send_reply_ok(alloc, rdata);
1199
/* Shutdown allocation */
1200
PJ_LOG(4,(alloc->obj_name,
1201
"Client %s request to dealloc, shutting down",
1204
alloc_shutdown(alloc);
1208
* This is a refresh request.
1211
/* Update lifetime */
1213
alloc->relay.lifetime = lifetime->value;
1216
/* Update bandwidth */
1219
/* Update expiration timer */
1220
resched_timeout(alloc);
1223
send_reply_ok(alloc, rdata);
1226
} else if (msg->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
1228
* ChannelBind request.
1230
pj_stun_channel_number_attr *ch_attr;
1231
pj_stun_xor_peer_addr_attr *peer_attr;
1232
pj_turn_permission *p1, *p2;
1234
ch_attr = (pj_stun_channel_number_attr*)
1235
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CHANNEL_NUMBER, 0);
1236
peer_attr = (pj_stun_xor_peer_addr_attr*)
1237
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1239
if (!ch_attr || !peer_attr) {
1240
send_reply_err(alloc, rdata, PJ_TRUE,
1241
PJ_STUN_SC_BAD_REQUEST, NULL);
1245
/* Find permission with the channel number */
1246
p1 = lookup_permission_by_chnum(alloc, PJ_STUN_GET_CH_NB(ch_attr->value));
1248
/* If permission is found, this is supposed to be a channel bind
1249
* refresh. Make sure it's for the same peer.
1252
if (pj_sockaddr_cmp(&p1->hkey.peer_addr, &peer_attr->sockaddr)) {
1253
/* Address mismatch. Send 400 */
1254
send_reply_err(alloc, rdata, PJ_TRUE,
1255
PJ_STUN_SC_BAD_REQUEST,
1256
"Peer address mismatch");
1260
/* Refresh permission */
1261
refresh_permission(p1);
1264
send_reply_ok(alloc, rdata);
1270
/* If permission is not found, create a new one. Make sure the peer
1271
* has not alreadyy assigned with a channel number.
1273
p2 = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1274
pj_sockaddr_get_len(&peer_attr->sockaddr));
1275
if (p2 && p2->channel != PJ_TURN_INVALID_CHANNEL) {
1276
send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST,
1277
"Peer address already assigned a channel number");
1281
/* Create permission if it doesn't exist */
1283
p2 = create_permission(alloc, &peer_attr->sockaddr,
1284
pj_sockaddr_get_len(&peer_attr->sockaddr));
1289
/* Assign channel number to permission */
1290
p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
1292
/* Register to hash table */
1293
pj_assert(sizeof(p2->channel==2));
1294
pj_hash_set(alloc->pool, alloc->ch_table, &p2->channel,
1295
sizeof(p2->channel), 0, p2);
1298
refresh_permission(p2);
1301
send_reply_ok(alloc, rdata);
1305
} else if (msg->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
1307
/* Respond with 437 (section 6.3 turn-07) */
1308
send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_ALLOCATION_MISMATCH,
1313
/* Respond with Bad Request? */
1314
send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
1322
* Callback notification from STUN session when it receives STUN
1323
* indications. This callback was trigger by STUN incoming message
1324
* processing in pj_turn_allocation_on_rx_client_pkt().
1326
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
1327
const pj_uint8_t *pkt,
1329
const pj_stun_msg *msg,
1331
const pj_sockaddr_t *src_addr,
1332
unsigned src_addr_len)
1334
pj_stun_xor_peer_addr_attr *peer_attr;
1335
pj_stun_data_attr *data_attr;
1336
pj_turn_allocation *alloc;
1337
pj_turn_permission *perm;
1341
PJ_UNUSED_ARG(pkt_len);
1342
PJ_UNUSED_ARG(token);
1343
PJ_UNUSED_ARG(src_addr);
1344
PJ_UNUSED_ARG(src_addr_len);
1346
alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1348
/* Only expect Send Indication */
1349
if (msg->hdr.type != PJ_STUN_SEND_INDICATION) {
1354
/* Get XOR-PEER-ADDRESS attribute */
1355
peer_attr = (pj_stun_xor_peer_addr_attr*)
1356
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1358
/* MUST have XOR-PEER-ADDRESS attribute */
1362
/* Get DATA attribute */
1363
data_attr = (pj_stun_data_attr*)
1364
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1366
/* Create/update/refresh the permission */
1367
perm = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1368
pj_sockaddr_get_len(&peer_attr->sockaddr));
1370
perm = create_permission(alloc, &peer_attr->sockaddr,
1371
pj_sockaddr_get_len(&peer_attr->sockaddr));
1373
refresh_permission(perm);
1375
/* Return if we don't have data */
1376
if (data_attr == NULL)
1379
/* Relay the data to peer */
1380
len = data_attr->length;
1381
pj_sock_sendto(alloc->relay.tp.sock, data_attr->data,
1382
&len, 0, &peer_attr->sockaddr,
1383
pj_sockaddr_get_len(&peer_attr->sockaddr));