blob: 50b5357139d0a9f053327b05cc7726dbc5b4cb7f [file] [log] [blame]
Benny Prijonod1e862f2008-02-21 15:54:27 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonod1e862f2008-02-21 15:54:27 +00005 *
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"
Benny Prijono708725a2008-03-09 12:55:00 +000021#include "auth.h"
Benny Prijonod1e862f2008-02-21 15:54:27 +000022
23#define MAX_CLIENTS 32
24#define MAX_PEERS_PER_CLIENT 8
Benny Prijono708725a2008-03-09 12:55:00 +000025//#define MAX_HANDLES (MAX_CLIENTS*MAX_PEERS_PER_CLIENT+MAX_LISTENERS)
26#define MAX_HANDLES PJ_IOQUEUE_MAX_HANDLES
Benny Prijonod1e862f2008-02-21 15:54:27 +000027#define MAX_TIMER (MAX_HANDLES * 2)
28#define MIN_PORT 49152
29#define MAX_PORT 65535
30#define MAX_LISTENERS 16
31#define MAX_THREADS 2
Benny Prijono879ad1a2008-04-09 09:38:12 +000032#define MAX_NET_EVENTS 1000
Benny Prijonod1e862f2008-02-21 15:54:27 +000033
Benny Prijonod1e862f2008-02-21 15:54:27 +000034/* Prototypes */
Benny Prijono708725a2008-03-09 12:55:00 +000035static int server_thread_proc(void *arg);
Benny Prijonod1e862f2008-02-21 15:54:27 +000036static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
Benny Prijono879ad1a2008-04-09 09:38:12 +000037 void *token,
Benny Prijonod1e862f2008-02-21 15:54:27 +000038 const void *pkt,
39 pj_size_t pkt_size,
40 const pj_sockaddr_t *dst_addr,
41 unsigned addr_len);
42static pj_status_t on_rx_stun_request(pj_stun_session *sess,
43 const pj_uint8_t *pkt,
44 unsigned pkt_len,
Benny Prijonoa5d214f2008-03-19 23:00:30 +000045 const pj_stun_rx_data *rdata,
Benny Prijono879ad1a2008-04-09 09:38:12 +000046 void *user_data,
Benny Prijonod1e862f2008-02-21 15:54:27 +000047 const pj_sockaddr_t *src_addr,
48 unsigned src_addr_len);
49
Benny Prijono708725a2008-03-09 12:55:00 +000050struct saved_cred
51{
52 pj_str_t realm;
53 pj_str_t username;
54 pj_str_t nonce;
55 int data_type;
56 pj_str_t data;
57};
58
59
Benny Prijonob05aafc2008-03-08 00:54:04 +000060/*
Benny Prijono708725a2008-03-09 12:55:00 +000061 * Get transport type name, normally for logging purpose only.
Benny Prijonob05aafc2008-03-08 00:54:04 +000062 */
Benny Prijono708725a2008-03-09 12:55:00 +000063PJ_DEF(const char*) pj_turn_tp_type_name(int tp_type)
Benny Prijonob05aafc2008-03-08 00:54:04 +000064{
65 /* Must be 3 characters long! */
Benny Prijono708725a2008-03-09 12:55:00 +000066 if (tp_type == PJ_TURN_TP_UDP) {
Benny Prijonob05aafc2008-03-08 00:54:04 +000067 return "UDP";
Benny Prijono708725a2008-03-09 12:55:00 +000068 } else if (tp_type == PJ_TURN_TP_TCP) {
Benny Prijonob05aafc2008-03-08 00:54:04 +000069 return "TCP";
Benny Prijono708725a2008-03-09 12:55:00 +000070 } else {
71 pj_assert(!"Unsupported transport");
Benny Prijonob05aafc2008-03-08 00:54:04 +000072 return "???";
Benny Prijono708725a2008-03-09 12:55:00 +000073 }
Benny Prijonob05aafc2008-03-08 00:54:04 +000074}
Benny Prijonod1e862f2008-02-21 15:54:27 +000075
76/*
77 * Create server.
78 */
Benny Prijono708725a2008-03-09 12:55:00 +000079PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,
80 pj_turn_srv **p_srv)
Benny Prijonod1e862f2008-02-21 15:54:27 +000081{
82 pj_pool_t *pool;
Benny Prijono879ad1a2008-04-09 09:38:12 +000083 pj_stun_session_cb sess_cb;
Benny Prijono708725a2008-03-09 12:55:00 +000084 pj_turn_srv *srv;
85 unsigned i;
Benny Prijonod1e862f2008-02-21 15:54:27 +000086 pj_status_t status;
87
88 PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL);
89
90 /* Create server and init core settings */
91 pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL);
Benny Prijono708725a2008-03-09 12:55:00 +000092 srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv);
93 srv->obj_name = pool->obj_name;
Benny Prijonod1e862f2008-02-21 15:54:27 +000094 srv->core.pf = pf;
95 srv->core.pool = pool;
Benny Prijono708725a2008-03-09 12:55:00 +000096 srv->core.tls_key = srv->core.tls_data = -1;
Benny Prijonod1e862f2008-02-21 15:54:27 +000097
Benny Prijono708725a2008-03-09 12:55:00 +000098 /* Create ioqueue */
Benny Prijonod1e862f2008-02-21 15:54:27 +000099 status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue);
100 if (status != PJ_SUCCESS)
101 goto on_error;
102
Benny Prijono708725a2008-03-09 12:55:00 +0000103 /* Server mutex */
104 status = pj_lock_create_recursive_mutex(pool, srv->obj_name,
105 &srv->core.lock);
106 if (status != PJ_SUCCESS)
107 goto on_error;
108
109 /* Allocate TLS */
110 status = pj_thread_local_alloc(&srv->core.tls_key);
111 if (status != PJ_SUCCESS)
112 goto on_error;
113
114 status = pj_thread_local_alloc(&srv->core.tls_data);
115 if (status != PJ_SUCCESS)
116 goto on_error;
117
118 /* Create timer heap */
Benny Prijonod1e862f2008-02-21 15:54:27 +0000119 status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap);
120 if (status != PJ_SUCCESS)
121 goto on_error;
122
Benny Prijono708725a2008-03-09 12:55:00 +0000123 /* Configure lock for the timer heap */
124 pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE);
125
126 /* Array of listeners */
127 srv->core.listener = (pj_turn_listener**)
128 pj_pool_calloc(pool, MAX_LISTENERS,
Benny Prijonod1e862f2008-02-21 15:54:27 +0000129 sizeof(srv->core.listener[0]));
Benny Prijono708725a2008-03-09 12:55:00 +0000130
Benny Prijonod1e862f2008-02-21 15:54:27 +0000131 /* Create hash tables */
132 srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
133 srv->tables.res = pj_hash_create(pool, MAX_CLIENTS);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000134
135 /* Init ports settings */
136 srv->ports.min_udp = srv->ports.next_udp = MIN_PORT;
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000137 srv->ports.max_udp = MAX_PORT;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000138 srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT;
139 srv->ports.max_tcp = MAX_PORT;
140
141 /* Init STUN config */
142 pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue,
143 srv->core.timer_heap);
144
Benny Prijono708725a2008-03-09 12:55:00 +0000145 /* 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;
Benny Prijono708725a2008-03-09 12:55:00 +0000149 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;
151
Benny Prijono879ad1a2008-04-09 09:38:12 +0000152 /* 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;
156
157 status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name,
158 &sess_cb, PJ_FALSE, &srv->core.stun_sess);
159 if (status != PJ_SUCCESS) {
160 goto on_error;
161 }
162
163 pj_stun_session_set_user_data(srv->core.stun_sess, srv);
164 pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM,
165 &srv->core.cred);
166
167
Benny Prijono708725a2008-03-09 12:55:00 +0000168 /* Array of worker threads */
169 srv->core.thread_cnt = MAX_THREADS;
170 srv->core.thread = (pj_thread_t**)
171 pj_pool_calloc(pool, srv->core.thread_cnt,
172 sizeof(pj_thread_t*));
173
174 /* Start the worker threads */
175 for (i=0; i<srv->core.thread_cnt; ++i) {
176 status = pj_thread_create(pool, srv->obj_name, &server_thread_proc,
177 srv, 0, 0, &srv->core.thread[i]);
178 if (status != PJ_SUCCESS)
179 goto on_error;
180 }
181
182 /* We're done. Application should add listeners now */
183 PJ_LOG(4,(srv->obj_name, "TURN server v%s is running",
184 pj_get_version()));
185
Benny Prijonod1e862f2008-02-21 15:54:27 +0000186 *p_srv = srv;
187 return PJ_SUCCESS;
188
189on_error:
Benny Prijono708725a2008-03-09 12:55:00 +0000190 pj_turn_srv_destroy(srv);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000191 return status;
192}
193
Benny Prijono708725a2008-03-09 12:55:00 +0000194
195/*
196 * Handle timer and network events
Benny Prijonod1e862f2008-02-21 15:54:27 +0000197 */
Benny Prijono708725a2008-03-09 12:55:00 +0000198static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout)
Benny Prijonod1e862f2008-02-21 15:54:27 +0000199{
Benny Prijono708725a2008-03-09 12:55:00 +0000200 /* timeout is 'out' var. This just to make compiler happy. */
201 pj_time_val timeout = { 0, 0};
202 unsigned net_event_count = 0;
203 int c;
204
205 /* Poll the timer. The timer heap has its own mutex for better
206 * granularity, so we don't need to lock the server.
207 */
208 timeout.sec = timeout.msec = 0;
209 c = pj_timer_heap_poll( srv->core.timer_heap, &timeout );
210
211 /* timer_heap_poll should never ever returns negative value, or otherwise
212 * ioqueue_poll() will block forever!
213 */
214 pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
215 if (timeout.msec >= 1000) timeout.msec = 999;
216
217 /* If caller specifies maximum time to wait, then compare the value with
218 * the timeout to wait from timer, and use the minimum value.
219 */
220 if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
221 timeout = *max_timeout;
222 }
223
224 /* Poll ioqueue.
225 * Repeat polling the ioqueue while we have immediate events, because
226 * timer heap may process more than one events, so if we only process
227 * one network events at a time (such as when IOCP backend is used),
228 * the ioqueue may have trouble keeping up with the request rate.
229 *
230 * For example, for each send() request, one network event will be
231 * reported by ioqueue for the send() completion. If we don't poll
232 * the ioqueue often enough, the send() completion will not be
233 * reported in timely manner.
234 */
235 do {
236 c = pj_ioqueue_poll( srv->core.ioqueue, &timeout);
237 if (c < 0) {
238 pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
239 return;
240 } else if (c == 0) {
241 break;
242 } else {
243 net_event_count += c;
244 timeout.sec = timeout.msec = 0;
245 }
246 } while (c > 0 && net_event_count < MAX_NET_EVENTS);
247
248}
249
250/*
251 * Server worker thread proc.
252 */
253static int server_thread_proc(void *arg)
254{
255 pj_turn_srv *srv = (pj_turn_srv*)arg;
256
257 while (!srv->core.quit) {
Benny Prijono879ad1a2008-04-09 09:38:12 +0000258 pj_time_val timeout_max = {0, 100};
Benny Prijono708725a2008-03-09 12:55:00 +0000259 srv_handle_events(srv, &timeout_max);
260 }
261
262 return 0;
263}
264
265/*
266 * Destroy the server.
267 */
268PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
269{
270 pj_hash_iterator_t itbuf, *it;
271 unsigned i;
272
273 /* Stop all worker threads */
274 srv->core.quit = PJ_TRUE;
275 for (i=0; i<srv->core.thread_cnt; ++i) {
276 if (srv->core.thread[i]) {
277 pj_thread_join(srv->core.thread[i]);
278 pj_thread_destroy(srv->core.thread[i]);
279 srv->core.thread[i] = NULL;
280 }
281 }
282
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000283 /* Destroy all allocations FIRST */
284 if (srv->tables.alloc) {
285 it = pj_hash_first(srv->tables.alloc, &itbuf);
286 while (it != NULL) {
287 pj_turn_allocation *alloc = (pj_turn_allocation*)
288 pj_hash_this(srv->tables.alloc, it);
289 pj_hash_iterator_t *next = pj_hash_next(srv->tables.alloc, it);
290 pj_turn_allocation_destroy(alloc);
291 it = next;
292 }
293 }
294
Benny Prijono879ad1a2008-04-09 09:38:12 +0000295 /* Destroy all listeners. */
Benny Prijono708725a2008-03-09 12:55:00 +0000296 for (i=0; i<srv->core.lis_cnt; ++i) {
297 if (srv->core.listener[i]) {
298 pj_turn_listener_destroy(srv->core.listener[i]);
299 srv->core.listener[i] = NULL;
300 }
Benny Prijono879ad1a2008-04-09 09:38:12 +0000301 }
302
303 /* Destroy STUN session */
304 if (srv->core.stun_sess) {
305 pj_stun_session_destroy(srv->core.stun_sess);
306 srv->core.stun_sess = NULL;
Benny Prijono708725a2008-03-09 12:55:00 +0000307 }
308
Benny Prijono708725a2008-03-09 12:55:00 +0000309 /* Destroy hash tables (well, sort of) */
310 if (srv->tables.alloc) {
311 srv->tables.alloc = NULL;
312 srv->tables.res = NULL;
313 }
314
315 /* Destroy timer heap */
316 if (srv->core.timer_heap) {
317 pj_timer_heap_destroy(srv->core.timer_heap);
318 srv->core.timer_heap = NULL;
319 }
320
321 /* Destroy ioqueue */
322 if (srv->core.ioqueue) {
323 pj_ioqueue_destroy(srv->core.ioqueue);
324 srv->core.ioqueue = NULL;
325 }
326
327 /* Destroy thread local IDs */
328 if (srv->core.tls_key != -1) {
329 pj_thread_local_free(srv->core.tls_key);
330 srv->core.tls_key = -1;
331 }
332 if (srv->core.tls_data != -1) {
333 pj_thread_local_free(srv->core.tls_data);
334 srv->core.tls_data = -1;
335 }
336
337 /* Destroy server lock */
338 if (srv->core.lock) {
339 pj_lock_destroy(srv->core.lock);
340 srv->core.lock = NULL;
341 }
342
343 /* Release pool */
344 if (srv->core.pool) {
345 pj_pool_t *pool = srv->core.pool;
346 srv->core.pool = NULL;
347 pj_pool_release(pool);
348 }
349
350 /* Done */
Benny Prijonod1e862f2008-02-21 15:54:27 +0000351 return PJ_SUCCESS;
352}
353
Benny Prijono708725a2008-03-09 12:55:00 +0000354
355/*
Benny Prijonod1e862f2008-02-21 15:54:27 +0000356 * Add listener.
357 */
Benny Prijono708725a2008-03-09 12:55:00 +0000358PJ_DEF(pj_status_t) pj_turn_srv_add_listener(pj_turn_srv *srv,
359 pj_turn_listener *lis)
Benny Prijonod1e862f2008-02-21 15:54:27 +0000360{
Benny Prijonod1e862f2008-02-21 15:54:27 +0000361 unsigned index;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000362
363 PJ_ASSERT_RETURN(srv && lis, PJ_EINVAL);
364 PJ_ASSERT_RETURN(srv->core.lis_cnt < MAX_LISTENERS, PJ_ETOOMANY);
365
366 /* Add to array */
367 index = srv->core.lis_cnt;
368 srv->core.listener[index] = lis;
369 lis->server = srv;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000370 lis->id = index;
371 srv->core.lis_cnt++;
372
Benny Prijono708725a2008-03-09 12:55:00 +0000373 PJ_LOG(4,(srv->obj_name, "Listener %s/%s added at index %d",
374 lis->obj_name, lis->info, lis->id));
375
Benny Prijonod1e862f2008-02-21 15:54:27 +0000376 return PJ_SUCCESS;
377}
378
Benny Prijono708725a2008-03-09 12:55:00 +0000379
380/*
Benny Prijono708725a2008-03-09 12:55:00 +0000381 * Destroy listener.
382 */
383PJ_DEF(pj_status_t) pj_turn_listener_destroy(pj_turn_listener *listener)
384{
385 pj_turn_srv *srv = listener->server;
386 unsigned i;
387
388 /* Remove from our listener list */
389 pj_lock_acquire(srv->core.lock);
390 for (i=0; i<srv->core.lis_cnt; ++i) {
391 if (srv->core.listener[i] == listener) {
392 srv->core.listener[i] = NULL;
393 srv->core.lis_cnt--;
394 listener->id = PJ_TURN_INVALID_LIS_ID;
Benny Prijono708725a2008-03-09 12:55:00 +0000395 break;
396 }
397 }
398 pj_lock_release(srv->core.lock);
399
400 /* Destroy */
401 return listener->destroy(listener);
402}
403
404
Benny Prijono879ad1a2008-04-09 09:38:12 +0000405/**
406 * Add a reference to a transport.
407 */
408PJ_DEF(void) pj_turn_transport_add_ref( pj_turn_transport *transport,
409 pj_turn_allocation *alloc)
410{
411 transport->add_ref(transport, alloc);
412}
413
414
415/**
416 * Decrement transport reference counter.
417 */
418PJ_DEF(void) pj_turn_transport_dec_ref( pj_turn_transport *transport,
419 pj_turn_allocation *alloc)
420{
421 transport->dec_ref(transport, alloc);
422}
423
424
Benny Prijono708725a2008-03-09 12:55:00 +0000425/*
426 * Register an allocation to the hash tables.
427 */
428PJ_DEF(pj_status_t) pj_turn_srv_register_allocation(pj_turn_srv *srv,
429 pj_turn_allocation *alloc)
Benny Prijonob05aafc2008-03-08 00:54:04 +0000430{
431 /* Add to hash tables */
432 pj_lock_acquire(srv->core.lock);
433 pj_hash_set(alloc->pool, srv->tables.alloc,
434 &alloc->hkey, sizeof(alloc->hkey), 0, alloc);
435 pj_hash_set(alloc->pool, srv->tables.res,
436 &alloc->relay.hkey, sizeof(alloc->relay.hkey), 0,
437 &alloc->relay);
438 pj_lock_release(srv->core.lock);
439
440 return PJ_SUCCESS;
441}
442
Benny Prijono708725a2008-03-09 12:55:00 +0000443
444/*
445 * Unregister an allocation from the hash tables.
Benny Prijonob05aafc2008-03-08 00:54:04 +0000446 */
Benny Prijono708725a2008-03-09 12:55:00 +0000447PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv,
448 pj_turn_allocation *alloc)
Benny Prijonob05aafc2008-03-08 00:54:04 +0000449{
450 /* Unregister from hash tables */
451 pj_lock_acquire(srv->core.lock);
452 pj_hash_set(alloc->pool, srv->tables.alloc,
453 &alloc->hkey, sizeof(alloc->hkey), 0, NULL);
454 pj_hash_set(alloc->pool, srv->tables.res,
455 &alloc->relay.hkey, sizeof(alloc->relay.hkey), 0, NULL);
456 pj_lock_release(srv->core.lock);
457
458 return PJ_SUCCESS;
459}
460
Benny Prijonod1e862f2008-02-21 15:54:27 +0000461
Benny Prijono708725a2008-03-09 12:55:00 +0000462/* Callback from our own STUN session whenever it needs to send
463 * outgoing STUN packet.
464 */
Benny Prijonod1e862f2008-02-21 15:54:27 +0000465static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
Benny Prijono879ad1a2008-04-09 09:38:12 +0000466 void *token,
467 const void *pdu,
468 pj_size_t pdu_size,
Benny Prijonod1e862f2008-02-21 15:54:27 +0000469 const pj_sockaddr_t *dst_addr,
470 unsigned addr_len)
471{
Benny Prijono879ad1a2008-04-09 09:38:12 +0000472 pj_turn_transport *transport = (pj_turn_transport*) token;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000473
Benny Prijono879ad1a2008-04-09 09:38:12 +0000474 PJ_ASSERT_RETURN(transport!=NULL, PJ_EINVALIDOP);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000475
Benny Prijono879ad1a2008-04-09 09:38:12 +0000476 PJ_UNUSED_ARG(sess);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000477
Benny Prijono879ad1a2008-04-09 09:38:12 +0000478 return transport->sendto(transport, pdu, pdu_size, 0,
479 dst_addr, addr_len);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000480}
481
Benny Prijono708725a2008-03-09 12:55:00 +0000482
483/* Respond to STUN request */
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000484static pj_status_t stun_respond(pj_stun_session *sess,
Benny Prijono879ad1a2008-04-09 09:38:12 +0000485 pj_turn_transport *transport,
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000486 const pj_stun_rx_data *rdata,
Benny Prijono708725a2008-03-09 12:55:00 +0000487 unsigned code,
488 const char *errmsg,
489 pj_bool_t cache,
490 const pj_sockaddr_t *dst_addr,
491 unsigned addr_len)
Benny Prijonod1e862f2008-02-21 15:54:27 +0000492{
493 pj_status_t status;
494 pj_str_t reason;
495 pj_stun_tx_data *tdata;
496
Benny Prijono708725a2008-03-09 12:55:00 +0000497 /* Create response */
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000498 status = pj_stun_session_create_res(sess, rdata, code,
Benny Prijono708725a2008-03-09 12:55:00 +0000499 (errmsg?pj_cstr(&reason,errmsg):NULL),
Benny Prijonod1e862f2008-02-21 15:54:27 +0000500 &tdata);
501 if (status != PJ_SUCCESS)
Benny Prijonob05aafc2008-03-08 00:54:04 +0000502 return status;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000503
Benny Prijono708725a2008-03-09 12:55:00 +0000504 /* Send the response */
Benny Prijono879ad1a2008-04-09 09:38:12 +0000505 return pj_stun_session_send_msg(sess, transport, cache, PJ_FALSE,
506 dst_addr, addr_len, tdata);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000507}
508
Benny Prijono708725a2008-03-09 12:55:00 +0000509
Benny Prijono708725a2008-03-09 12:55:00 +0000510/* Callback from our own STUN session when incoming request arrives.
511 * This function is triggered by pj_stun_session_on_rx_pkt() call in
Benny Prijono879ad1a2008-04-09 09:38:12 +0000512 * pj_turn_srv_on_rx_pkt() function below.
Benny Prijono708725a2008-03-09 12:55:00 +0000513 */
Benny Prijonod1e862f2008-02-21 15:54:27 +0000514static pj_status_t on_rx_stun_request(pj_stun_session *sess,
Benny Prijono879ad1a2008-04-09 09:38:12 +0000515 const pj_uint8_t *pdu,
516 unsigned pdu_len,
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000517 const pj_stun_rx_data *rdata,
Benny Prijono879ad1a2008-04-09 09:38:12 +0000518 void *token,
Benny Prijonod1e862f2008-02-21 15:54:27 +0000519 const pj_sockaddr_t *src_addr,
520 unsigned src_addr_len)
521{
Benny Prijono879ad1a2008-04-09 09:38:12 +0000522 pj_turn_transport *transport;
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000523 const pj_stun_msg *msg = rdata->msg;
Benny Prijono708725a2008-03-09 12:55:00 +0000524 pj_turn_srv *srv;
525 pj_turn_allocation *alloc;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000526 pj_status_t status;
527
Benny Prijono879ad1a2008-04-09 09:38:12 +0000528 PJ_UNUSED_ARG(pdu);
529 PJ_UNUSED_ARG(pdu_len);
Benny Prijono708725a2008-03-09 12:55:00 +0000530
Benny Prijono879ad1a2008-04-09 09:38:12 +0000531 transport = (pj_turn_transport*) token;
532 srv = transport->listener->server;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000533
Benny Prijono708725a2008-03-09 12:55:00 +0000534 /* Respond any requests other than ALLOCATE with 437 response */
Benny Prijonod1e862f2008-02-21 15:54:27 +0000535 if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
Benny Prijono879ad1a2008-04-09 09:38:12 +0000536 stun_respond(sess, transport, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
Benny Prijono708725a2008-03-09 12:55:00 +0000537 NULL, PJ_FALSE, src_addr, src_addr_len);
538 return PJ_SUCCESS;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000539 }
540
Benny Prijonob05aafc2008-03-08 00:54:04 +0000541 /* Create new allocation. The relay resource will be allocated
542 * in this function.
543 */
Benny Prijono879ad1a2008-04-09 09:38:12 +0000544 status = pj_turn_allocation_create(transport, src_addr, src_addr_len,
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000545 rdata, sess, &alloc);
Benny Prijonob05aafc2008-03-08 00:54:04 +0000546 if (status != PJ_SUCCESS) {
Benny Prijono708725a2008-03-09 12:55:00 +0000547 /* STUN response has been sent, no need to reply here */
548 return PJ_SUCCESS;
Benny Prijonob05aafc2008-03-08 00:54:04 +0000549 }
550
Benny Prijonob05aafc2008-03-08 00:54:04 +0000551 /* Done. */
552 return PJ_SUCCESS;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000553}
554
Benny Prijonoefa014b2008-08-22 17:46:33 +0000555/* Handle STUN Binding request */
556static void handle_binding_request(pj_turn_pkt *pkt,
557 unsigned options)
558{
559 pj_stun_msg *request, *response;
560 pj_uint8_t pdu[200];
561 pj_size_t len;
562 pj_status_t status;
563
564 /* Decode request */
565 status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options,
566 &request, NULL, NULL);
567 if (status != PJ_SUCCESS)
568 return;
569
570 /* Create response */
571 status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL,
572 &response);
573 if (status != PJ_SUCCESS)
574 return;
575
576 /* Add XOR-MAPPED-ADDRESS */
577 pj_stun_msg_add_sockaddr_attr(pkt->pool, response,
578 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
579 PJ_TRUE,
580 &pkt->src.clt_addr,
581 pkt->src_addr_len);
582
583 /* Encode */
584 status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len);
585 if (status != PJ_SUCCESS)
586 return;
587
588 /* Send response */
589 pkt->transport->sendto(pkt->transport, pdu, len, 0,
590 &pkt->src.clt_addr, pkt->src_addr_len);
591}
Benny Prijonod1e862f2008-02-21 15:54:27 +0000592
Benny Prijonod1e862f2008-02-21 15:54:27 +0000593/*
Benny Prijono708725a2008-03-09 12:55:00 +0000594 * This callback is called by UDP listener on incoming packet. This is
595 * the first entry for incoming packet (from client) to the server. From
596 * here, the packet may be handed over to an allocation if an allocation
597 * is found for the client address, or handed over to owned STUN session
598 * if an allocation is not found.
Benny Prijonod1e862f2008-02-21 15:54:27 +0000599 */
Benny Prijono708725a2008-03-09 12:55:00 +0000600PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv,
601 pj_turn_pkt *pkt)
Benny Prijonod1e862f2008-02-21 15:54:27 +0000602{
Benny Prijono708725a2008-03-09 12:55:00 +0000603 pj_turn_allocation *alloc;
Benny Prijonod1e862f2008-02-21 15:54:27 +0000604
605 /* Get TURN allocation from the source address */
606 pj_lock_acquire(srv->core.lock);
Benny Prijono24a21852008-04-14 04:04:30 +0000607 alloc = (pj_turn_allocation*)
608 pj_hash_get(srv->tables.alloc, &pkt->src, sizeof(pkt->src), NULL);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000609 pj_lock_release(srv->core.lock);
610
611 /* If allocation is found, just hand over the packet to the
612 * allocation.
613 */
614 if (alloc) {
Benny Prijono708725a2008-03-09 12:55:00 +0000615 pj_turn_allocation_on_rx_client_pkt(alloc, pkt);
Benny Prijonod1e862f2008-02-21 15:54:27 +0000616 } else {
617 /* Otherwise this is a new client */
Benny Prijono879ad1a2008-04-09 09:38:12 +0000618 unsigned options;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000619 pj_size_t parsed_len;
Benny Prijono708725a2008-03-09 12:55:00 +0000620 pj_status_t status;
621
622 /* Check that this is a STUN message */
Benny Prijonoe7226852008-04-13 21:48:44 +0000623 options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
Benny Prijono879ad1a2008-04-09 09:38:12 +0000624 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
Benny Prijono708725a2008-03-09 12:55:00 +0000625 options |= PJ_STUN_IS_DATAGRAM;
626
627 status = pj_stun_msg_check(pkt->pkt, pkt->len, options);
628 if (status != PJ_SUCCESS) {
Benny Prijono879ad1a2008-04-09 09:38:12 +0000629 /* If the first byte are not STUN, drop the packet. First byte
630 * of STUN message is always 0x00 or 0x01. Otherwise wait for
631 * more data as the data might have come from TCP.
632 *
633 * Also drop packet if it's unreasonably too big, as this might
634 * indicate invalid data that's building up in the buffer.
635 *
636 * Or if packet is a datagram.
637 */
638 if ((*pkt->pkt != 0x00 && *pkt->pkt != 0x01) ||
639 pkt->len > 1600 ||
640 (options & PJ_STUN_IS_DATAGRAM))
641 {
642 char errmsg[PJ_ERR_MSG_SIZE];
643 char ip[PJ_INET6_ADDRSTRLEN+10];
Benny Prijono708725a2008-03-09 12:55:00 +0000644
Benny Prijono879ad1a2008-04-09 09:38:12 +0000645 pkt->len = 0;
646
647 pj_strerror(status, errmsg, sizeof(errmsg));
648 PJ_LOG(5,(srv->obj_name,
649 "Non-STUN packet from %s is dropped: %s",
650 pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
651 errmsg));
652 }
Benny Prijono708725a2008-03-09 12:55:00 +0000653 return;
654 }
655
Benny Prijonoefa014b2008-08-22 17:46:33 +0000656 /* Special handling for Binding Request. We won't give it to the
657 * STUN session since this request is not authenticated.
658 */
659 if (pkt->pkt[1] == 1) {
660 handle_binding_request(pkt, options);
661 return;
662 }
663
Benny Prijono708725a2008-03-09 12:55:00 +0000664 /* Hand over processing to STUN session. This will trigger
665 * on_rx_stun_request() callback to be called if the STUN
666 * message is a request.
667 */
668 options &= ~PJ_STUN_CHECK_PACKET;
Benny Prijono879ad1a2008-04-09 09:38:12 +0000669 parsed_len = 0;
670 status = pj_stun_session_on_rx_pkt(srv->core.stun_sess, pkt->pkt,
671 pkt->len, options, pkt->transport,
672 &parsed_len, &pkt->src.clt_addr,
Benny Prijono708725a2008-03-09 12:55:00 +0000673 pkt->src_addr_len);
674 if (status != PJ_SUCCESS) {
675 char errmsg[PJ_ERR_MSG_SIZE];
676 char ip[PJ_INET6_ADDRSTRLEN+10];
677
678 pj_strerror(status, errmsg, sizeof(errmsg));
679 PJ_LOG(5,(srv->obj_name,
680 "Error processing STUN packet from %s: %s",
681 pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
682 errmsg));
Benny Prijono879ad1a2008-04-09 09:38:12 +0000683 }
684
685 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
686 pkt->len = 0;
687 } else if (parsed_len > 0) {
688 if (parsed_len == pkt->len) {
689 pkt->len = 0;
690 } else {
691 pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
692 pkt->len - parsed_len);
693 pkt->len -= parsed_len;
694 }
Benny Prijono708725a2008-03-09 12:55:00 +0000695 }
Benny Prijonod1e862f2008-02-21 15:54:27 +0000696 }
697}
698
699