1
/* $Id: server.c 4728 2014-02-04 10:13:56Z bennylp $ */
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
23
#define MAX_CLIENTS 32
24
#define MAX_PEERS_PER_CLIENT 8
25
//#define MAX_HANDLES (MAX_CLIENTS*MAX_PEERS_PER_CLIENT+MAX_LISTENERS)
26
#define MAX_HANDLES PJ_IOQUEUE_MAX_HANDLES
27
#define MAX_TIMER (MAX_HANDLES * 2)
28
#define MIN_PORT 49152
29
#define MAX_PORT 65535
30
#define MAX_LISTENERS 16
32
#define MAX_NET_EVENTS 1000
35
static int server_thread_proc(void *arg);
36
static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
40
const pj_sockaddr_t *dst_addr,
42
static pj_status_t on_rx_stun_request(pj_stun_session *sess,
43
const pj_uint8_t *pkt,
45
const pj_stun_rx_data *rdata,
47
const pj_sockaddr_t *src_addr,
48
unsigned src_addr_len);
61
* Get transport type name, normally for logging purpose only.
63
PJ_DEF(const char*) pj_turn_tp_type_name(int tp_type)
65
/* Must be 3 characters long! */
66
if (tp_type == PJ_TURN_TP_UDP) {
68
} else if (tp_type == PJ_TURN_TP_TCP) {
71
pj_assert(!"Unsupported transport");
79
PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,
83
pj_stun_session_cb sess_cb;
88
PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL);
90
/* Create server and init core settings */
91
pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL);
92
srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv);
93
srv->obj_name = pool->obj_name;
95
srv->core.pool = pool;
96
srv->core.tls_key = srv->core.tls_data = -1;
99
status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue);
100
if (status != PJ_SUCCESS)
104
status = pj_lock_create_recursive_mutex(pool, srv->obj_name,
106
if (status != PJ_SUCCESS)
110
status = pj_thread_local_alloc(&srv->core.tls_key);
111
if (status != PJ_SUCCESS)
114
status = pj_thread_local_alloc(&srv->core.tls_data);
115
if (status != PJ_SUCCESS)
118
/* Create timer heap */
119
status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap);
120
if (status != PJ_SUCCESS)
123
/* Configure lock for the timer heap */
124
pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE);
126
/* Array of listeners */
127
srv->core.listener = (pj_turn_listener**)
128
pj_pool_calloc(pool, MAX_LISTENERS,
129
sizeof(srv->core.listener[0]));
131
/* Create hash tables */
132
srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
133
srv->tables.res = pj_hash_create(pool, MAX_CLIENTS);
135
/* Init ports settings */
136
srv->ports.min_udp = srv->ports.next_udp = MIN_PORT;
137
srv->ports.max_udp = MAX_PORT;
138
srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT;
139
srv->ports.max_tcp = MAX_PORT;
141
/* Init STUN config */
142
pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue,
143
srv->core.timer_heap);
145
/* Init STUN credential */
146
srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
147
srv->core.cred.data.dyn_cred.user_data = srv;
148
srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth;
149
srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password;
150
srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce;
152
/* Create STUN session to handle new allocation */
153
pj_bzero(&sess_cb, sizeof(sess_cb));
154
sess_cb.on_rx_request = &on_rx_stun_request;
155
sess_cb.on_send_msg = &on_tx_stun_msg;
157
status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name,
158
&sess_cb, PJ_FALSE, NULL,
159
&srv->core.stun_sess);
160
if (status != PJ_SUCCESS) {
164
pj_stun_session_set_user_data(srv->core.stun_sess, srv);
165
pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM,
169
/* Array of worker threads */
170
srv->core.thread_cnt = MAX_THREADS;
171
srv->core.thread = (pj_thread_t**)
172
pj_pool_calloc(pool, srv->core.thread_cnt,
173
sizeof(pj_thread_t*));
175
/* Start the worker threads */
176
for (i=0; i<srv->core.thread_cnt; ++i) {
177
status = pj_thread_create(pool, srv->obj_name, &server_thread_proc,
178
srv, 0, 0, &srv->core.thread[i]);
179
if (status != PJ_SUCCESS)
183
/* We're done. Application should add listeners now */
184
PJ_LOG(4,(srv->obj_name, "TURN server v%s is running",
191
pj_turn_srv_destroy(srv);
197
* Handle timer and network events
199
static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout)
201
/* timeout is 'out' var. This just to make compiler happy. */
202
pj_time_val timeout = { 0, 0};
203
unsigned net_event_count = 0;
206
/* Poll the timer. The timer heap has its own mutex for better
207
* granularity, so we don't need to lock the server.
209
timeout.sec = timeout.msec = 0;
210
c = pj_timer_heap_poll( srv->core.timer_heap, &timeout );
212
/* timer_heap_poll should never ever returns negative value, or otherwise
213
* ioqueue_poll() will block forever!
215
pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
216
if (timeout.msec >= 1000) timeout.msec = 999;
218
/* If caller specifies maximum time to wait, then compare the value with
219
* the timeout to wait from timer, and use the minimum value.
221
if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
222
timeout = *max_timeout;
226
* Repeat polling the ioqueue while we have immediate events, because
227
* timer heap may process more than one events, so if we only process
228
* one network events at a time (such as when IOCP backend is used),
229
* the ioqueue may have trouble keeping up with the request rate.
231
* For example, for each send() request, one network event will be
232
* reported by ioqueue for the send() completion. If we don't poll
233
* the ioqueue often enough, the send() completion will not be
234
* reported in timely manner.
237
c = pj_ioqueue_poll( srv->core.ioqueue, &timeout);
239
pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
244
net_event_count += c;
245
timeout.sec = timeout.msec = 0;
247
} while (c > 0 && net_event_count < MAX_NET_EVENTS);
252
* Server worker thread proc.
254
static int server_thread_proc(void *arg)
256
pj_turn_srv *srv = (pj_turn_srv*)arg;
258
while (!srv->core.quit) {
259
pj_time_val timeout_max = {0, 100};
260
srv_handle_events(srv, &timeout_max);
267
* Destroy the server.
269
PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
271
pj_hash_iterator_t itbuf, *it;
274
/* Stop all worker threads */
275
srv->core.quit = PJ_TRUE;
276
for (i=0; i<srv->core.thread_cnt; ++i) {
277
if (srv->core.thread[i]) {
278
pj_thread_join(srv->core.thread[i]);
279
pj_thread_destroy(srv->core.thread[i]);
280
srv->core.thread[i] = NULL;
284
/* Destroy all allocations FIRST */
285
if (srv->tables.alloc) {
286
it = pj_hash_first(srv->tables.alloc, &itbuf);
288
pj_turn_allocation *alloc = (pj_turn_allocation*)
289
pj_hash_this(srv->tables.alloc, it);
290
pj_hash_iterator_t *next = pj_hash_next(srv->tables.alloc, it);
291
pj_turn_allocation_destroy(alloc);
296
/* Destroy all listeners. */
297
for (i=0; i<srv->core.lis_cnt; ++i) {
298
if (srv->core.listener[i]) {
299
pj_turn_listener_destroy(srv->core.listener[i]);
300
srv->core.listener[i] = NULL;
304
/* Destroy STUN session */
305
if (srv->core.stun_sess) {
306
pj_stun_session_destroy(srv->core.stun_sess);
307
srv->core.stun_sess = NULL;
310
/* Destroy hash tables (well, sort of) */
311
if (srv->tables.alloc) {
312
srv->tables.alloc = NULL;
313
srv->tables.res = NULL;
316
/* Destroy timer heap */
317
if (srv->core.timer_heap) {
318
pj_timer_heap_destroy(srv->core.timer_heap);
319
srv->core.timer_heap = NULL;
322
/* Destroy ioqueue */
323
if (srv->core.ioqueue) {
324
pj_ioqueue_destroy(srv->core.ioqueue);
325
srv->core.ioqueue = NULL;
328
/* Destroy thread local IDs */
329
if (srv->core.tls_key != -1) {
330
pj_thread_local_free(srv->core.tls_key);
331
srv->core.tls_key = -1;
333
if (srv->core.tls_data != -1) {
334
pj_thread_local_free(srv->core.tls_data);
335
srv->core.tls_data = -1;
338
/* Destroy server lock */
339
if (srv->core.lock) {
340
pj_lock_destroy(srv->core.lock);
341
srv->core.lock = NULL;
345
if (srv->core.pool) {
346
pj_pool_t *pool = srv->core.pool;
347
srv->core.pool = NULL;
348
pj_pool_release(pool);
359
PJ_DEF(pj_status_t) pj_turn_srv_add_listener(pj_turn_srv *srv,
360
pj_turn_listener *lis)
364
PJ_ASSERT_RETURN(srv && lis, PJ_EINVAL);
365
PJ_ASSERT_RETURN(srv->core.lis_cnt < MAX_LISTENERS, PJ_ETOOMANY);
368
index = srv->core.lis_cnt;
369
srv->core.listener[index] = lis;
374
PJ_LOG(4,(srv->obj_name, "Listener %s/%s added at index %d",
375
lis->obj_name, lis->info, lis->id));
384
PJ_DEF(pj_status_t) pj_turn_listener_destroy(pj_turn_listener *listener)
386
pj_turn_srv *srv = listener->server;
389
/* Remove from our listener list */
390
pj_lock_acquire(srv->core.lock);
391
for (i=0; i<srv->core.lis_cnt; ++i) {
392
if (srv->core.listener[i] == listener) {
393
srv->core.listener[i] = NULL;
395
listener->id = PJ_TURN_INVALID_LIS_ID;
399
pj_lock_release(srv->core.lock);
402
return listener->destroy(listener);
407
* Add a reference to a transport.
409
PJ_DEF(void) pj_turn_transport_add_ref( pj_turn_transport *transport,
410
pj_turn_allocation *alloc)
412
transport->add_ref(transport, alloc);
417
* Decrement transport reference counter.
419
PJ_DEF(void) pj_turn_transport_dec_ref( pj_turn_transport *transport,
420
pj_turn_allocation *alloc)
422
transport->dec_ref(transport, alloc);
427
* Register an allocation to the hash tables.
429
PJ_DEF(pj_status_t) pj_turn_srv_register_allocation(pj_turn_srv *srv,
430
pj_turn_allocation *alloc)
432
/* Add to hash tables */
433
pj_lock_acquire(srv->core.lock);
434
pj_hash_set(alloc->pool, srv->tables.alloc,
435
&alloc->hkey, sizeof(alloc->hkey), 0, alloc);
436
pj_hash_set(alloc->pool, srv->tables.res,
437
&alloc->relay.hkey, sizeof(alloc->relay.hkey), 0,
439
pj_lock_release(srv->core.lock);
446
* Unregister an allocation from the hash tables.
448
PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv,
449
pj_turn_allocation *alloc)
451
/* Unregister from hash tables */
452
pj_lock_acquire(srv->core.lock);
453
pj_hash_set(alloc->pool, srv->tables.alloc,
454
&alloc->hkey, sizeof(alloc->hkey), 0, NULL);
455
pj_hash_set(alloc->pool, srv->tables.res,
456
&alloc->relay.hkey, sizeof(alloc->relay.hkey), 0, NULL);
457
pj_lock_release(srv->core.lock);
463
/* Callback from our own STUN session whenever it needs to send
464
* outgoing STUN packet.
466
static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
470
const pj_sockaddr_t *dst_addr,
473
pj_turn_transport *transport = (pj_turn_transport*) token;
475
PJ_ASSERT_RETURN(transport!=NULL, PJ_EINVALIDOP);
479
return transport->sendto(transport, pdu, pdu_size, 0,
484
/* Respond to STUN request */
485
static pj_status_t stun_respond(pj_stun_session *sess,
486
pj_turn_transport *transport,
487
const pj_stun_rx_data *rdata,
491
const pj_sockaddr_t *dst_addr,
496
pj_stun_tx_data *tdata;
498
/* Create response */
499
status = pj_stun_session_create_res(sess, rdata, code,
500
(errmsg?pj_cstr(&reason,errmsg):NULL),
502
if (status != PJ_SUCCESS)
505
/* Send the response */
506
return pj_stun_session_send_msg(sess, transport, cache, PJ_FALSE,
507
dst_addr, addr_len, tdata);
511
/* Callback from our own STUN session when incoming request arrives.
512
* This function is triggered by pj_stun_session_on_rx_pkt() call in
513
* pj_turn_srv_on_rx_pkt() function below.
515
static pj_status_t on_rx_stun_request(pj_stun_session *sess,
516
const pj_uint8_t *pdu,
518
const pj_stun_rx_data *rdata,
520
const pj_sockaddr_t *src_addr,
521
unsigned src_addr_len)
523
pj_turn_transport *transport;
524
const pj_stun_msg *msg = rdata->msg;
525
pj_turn_allocation *alloc;
529
PJ_UNUSED_ARG(pdu_len);
531
transport = (pj_turn_transport*) token;
533
/* Respond any requests other than ALLOCATE with 437 response */
534
if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
535
stun_respond(sess, transport, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
536
NULL, PJ_FALSE, src_addr, src_addr_len);
540
/* Create new allocation. The relay resource will be allocated
543
status = pj_turn_allocation_create(transport, src_addr, src_addr_len,
544
rdata, sess, &alloc);
545
if (status != PJ_SUCCESS) {
546
/* STUN response has been sent, no need to reply here */
554
/* Handle STUN Binding request */
555
static void handle_binding_request(pj_turn_pkt *pkt,
558
pj_stun_msg *request, *response;
564
status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options,
565
&request, NULL, NULL);
566
if (status != PJ_SUCCESS)
569
/* Create response */
570
status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL,
572
if (status != PJ_SUCCESS)
575
/* Add XOR-MAPPED-ADDRESS */
576
pj_stun_msg_add_sockaddr_attr(pkt->pool, response,
577
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
583
status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len);
584
if (status != PJ_SUCCESS)
588
pkt->transport->sendto(pkt->transport, pdu, len, 0,
589
&pkt->src.clt_addr, pkt->src_addr_len);
593
* This callback is called by UDP listener on incoming packet. This is
594
* the first entry for incoming packet (from client) to the server. From
595
* here, the packet may be handed over to an allocation if an allocation
596
* is found for the client address, or handed over to owned STUN session
597
* if an allocation is not found.
599
PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv,
602
pj_turn_allocation *alloc;
604
/* Get TURN allocation from the source address */
605
pj_lock_acquire(srv->core.lock);
606
alloc = (pj_turn_allocation*)
607
pj_hash_get(srv->tables.alloc, &pkt->src, sizeof(pkt->src), NULL);
608
pj_lock_release(srv->core.lock);
610
/* If allocation is found, just hand over the packet to the
614
pj_turn_allocation_on_rx_client_pkt(alloc, pkt);
616
/* Otherwise this is a new client */
618
pj_size_t parsed_len;
621
/* Check that this is a STUN message */
622
options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
623
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
624
options |= PJ_STUN_IS_DATAGRAM;
626
status = pj_stun_msg_check(pkt->pkt, pkt->len, options);
627
if (status != PJ_SUCCESS) {
628
/* If the first byte are not STUN, drop the packet. First byte
629
* of STUN message is always 0x00 or 0x01. Otherwise wait for
630
* more data as the data might have come from TCP.
632
* Also drop packet if it's unreasonably too big, as this might
633
* indicate invalid data that's building up in the buffer.
635
* Or if packet is a datagram.
637
if ((*pkt->pkt != 0x00 && *pkt->pkt != 0x01) ||
639
(options & PJ_STUN_IS_DATAGRAM))
641
char errmsg[PJ_ERR_MSG_SIZE];
642
char ip[PJ_INET6_ADDRSTRLEN+10];
646
pj_strerror(status, errmsg, sizeof(errmsg));
647
PJ_LOG(5,(srv->obj_name,
648
"Non-STUN packet from %s is dropped: %s",
649
pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
655
/* Special handling for Binding Request. We won't give it to the
656
* STUN session since this request is not authenticated.
658
if (pkt->pkt[1] == 1) {
659
handle_binding_request(pkt, options);
663
/* Hand over processing to STUN session. This will trigger
664
* on_rx_stun_request() callback to be called if the STUN
665
* message is a request.
667
options &= ~PJ_STUN_CHECK_PACKET;
669
status = pj_stun_session_on_rx_pkt(srv->core.stun_sess, pkt->pkt,
670
pkt->len, options, pkt->transport,
671
&parsed_len, &pkt->src.clt_addr,
673
if (status != PJ_SUCCESS) {
674
char errmsg[PJ_ERR_MSG_SIZE];
675
char ip[PJ_INET6_ADDRSTRLEN+10];
677
pj_strerror(status, errmsg, sizeof(errmsg));
678
PJ_LOG(5,(srv->obj_name,
679
"Error processing STUN packet from %s: %s",
680
pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
684
if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
686
} else if (parsed_len > 0) {
687
if (parsed_len == pkt->len) {
690
pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
691
pkt->len - parsed_len);
692
pkt->len -= parsed_len;