blob: 725863ce8b9dd496fe6ddca7e7b7f1371ec5a0e4 [file] [log] [blame]
Benny Prijonob05aafc2008-03-08 00:54:04 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "turn.h"
20
21#define THIS_FILE "allocation.c"
22
23
24enum {
25 TIMER_ID_NONE,
26 TIMER_ID_TIMEOUT,
27 TIMER_ID_DESTROY
28};
29
30#define DESTROY_DELAY {0, 500}
31#define PEER_TABLE_SIZE 32
32
33/* ChannelData header */
34typedef struct channel_data_hdr
35{
36 pj_uint16_t ch_number;
37 pj_uint16_t length;
38} channel_data_hdr;
39
40
41/* Prototypes */
42static pj_status_t create_relay(pjturn_allocation *alloc,
43 const pjturn_allocation_req *req);
44static void on_rx_from_peer(pj_ioqueue_key_t *key,
45 pj_ioqueue_op_key_t *op_key,
46 pj_ssize_t bytes_read);
47static void destroy_relay(pjturn_relay_res *relay);
48static pj_status_t stun_on_send_msg(pj_stun_session *sess,
49 const void *pkt,
50 pj_size_t pkt_size,
51 const pj_sockaddr_t *dst_addr,
52 unsigned addr_len);
53static pj_status_t stun_on_rx_request(pj_stun_session *sess,
54 const pj_uint8_t *pkt,
55 unsigned pkt_len,
56 const pj_stun_msg *msg,
57 const pj_sockaddr_t *src_addr,
58 unsigned src_addr_len);
59static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
60 const pj_uint8_t *pkt,
61 unsigned pkt_len,
62 const pj_stun_msg *msg,
63 const pj_sockaddr_t *src_addr,
64 unsigned src_addr_len);
65
66/* Log allocation error */
67static void alloc_err(pjturn_allocation *alloc, const char *title,
68 pj_status_t status)
69{
70 char errmsg[PJ_ERR_MSG_SIZE];
71
72 pj_strerror(status, errmsg, sizeof(errmsg));
73 PJ_LOG(4,(alloc->obj_name, "%s for client %s: %s",
74 title, alloc->info, errmsg));
75}
76
77/*
78 * Create new allocation.
79 */
80PJ_DEF(pj_status_t) pjturn_allocation_create(pjturn_listener *listener,
81 const pj_sockaddr_t *src_addr,
82 unsigned src_addr_len,
83 const pj_stun_msg *msg,
84 const pjturn_allocation_req *req,
85 pjturn_allocation **p_alloc)
86{
87 pjturn_srv *srv = listener->server;
88 pj_pool_t *pool;
89 pjturn_allocation *alloc;
90 pj_stun_session_cb sess_cb;
91 char relay_info[80];
92 pj_status_t status;
93
94 pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);
95
96 /* Init allocation structure */
97 alloc = PJ_POOL_ZALLOC_T(pool, pjturn_allocation);
98 alloc->pool = pool;
99 alloc->obj_name = pool->obj_name;
100 alloc->listener = listener;
101 alloc->clt_sock = PJ_INVALID_SOCKET;
102 alloc->relay.tp.sock = PJ_INVALID_SOCKET;
103
104 alloc->bandwidth = req->bandwidth;
105
106 alloc->hkey.tp_type = listener->tp_type;
107 pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);
108
109 status = pj_lock_create_recursive_mutex(pool, alloc->obj_name,
110 &alloc->lock);
111 if (status != PJ_SUCCESS) {
112 pjturn_allocation_destroy(alloc);
113 return status;
114 }
115
116 /* Create peer hash table */
117 alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);
118
119 /* Create channel hash table */
120 alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);
121
122 /* Print info */
123 pj_ansi_strcpy(alloc->info, pjturn_tp_type_name(listener->tp_type));
124 alloc->info[3] = ':';
125 pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3);
126
127 /* Create STUN session to handle STUN communication with client */
128 pj_bzero(&sess_cb, sizeof(sess_cb));
129 sess_cb.on_send_msg = &stun_on_send_msg;
130 sess_cb.on_rx_request = &stun_on_rx_request;
131 sess_cb.on_rx_indication = &stun_on_rx_indication;
132 status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name,
133 &sess_cb, PJ_FALSE, &alloc->sess);
134 if (status != PJ_SUCCESS) {
135 pjturn_allocation_destroy(alloc);
136 return status;
137 }
138
139 /* Attach to STUN session */
140 pj_stun_session_set_user_data(alloc->sess, alloc);
141
142 /* Create the relay resource */
143 status = pjturn_allocation_create_relay(srv, alloc, msg, req,
144 &alloc->relay);
145 if (status != PJ_SUCCESS) {
146 pjturn_allocation_destroy(alloc);
147 return status;
148 }
149
150 /* Register this allocation */
151 pjturn_srv_register_allocation(srv, alloc);
152
153 pj_sockaddr_print(&alloc->relay.hkey.addr, relay_info,
154 sizeof(relay_info), 3);
155 PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s",
156 alloc->info, pjturn_tp_type_name(req->tp_type), relay_info));
157
158 /* Success */
159 *p_alloc = alloc;
160 return PJ_SUCCESS;
161}
162
163
164/*
165 * Destroy allocation.
166 */
167PJ_DECL(void) pjturn_allocation_destroy(pjturn_allocation *alloc)
168{
169 pj_pool_t *pool;
170
171 /* Unregister this allocation */
172 pjturn_srv_unregister_allocation(alloc->listener->server, alloc);
173
174 /* Destroy relay */
175 destroy_relay(&alloc->relay);
176
177 /* Must lock only after destroying relay otherwise deadlock */
178 if (alloc->lock) {
179 pj_lock_acquire(alloc->lock);
180 }
181
182 /* Destroy STUN session */
183 if (alloc->sess) {
184 pj_stun_session_destroy(alloc->sess);
185 alloc->sess = NULL;
186 }
187
188 /* Destroy lock */
189 if (alloc->lock) {
190 pj_lock_release(alloc->lock);
191 pj_lock_destroy(alloc->lock);
192 alloc->lock = NULL;
193 }
194
195 /* Destroy pool */
196 pool = alloc->pool;
197 if (pool) {
198 alloc->pool = NULL;
199 pj_pool_release(pool);
200 }
201}
202
203
204/* Destroy relay resource */
205static void destroy_relay(pjturn_relay_res *relay)
206{
207 if (relay->timer.id) {
208 pj_timer_heap_cancel(relay->allocation->listener->server->core.timer_heap,
209 &relay->timer);
210 relay->timer.id = PJ_FALSE;
211 }
212
213 if (relay->tp.key) {
214 pj_ioqueue_unregister(relay->tp.key);
215 relay->tp.key = NULL;
216 relay->tp.sock = PJ_INVALID_SOCKET;
217 } else if (relay->tp.sock != PJ_INVALID_SOCKET) {
218 pj_sock_close(relay->tp.sock);
219 relay->tp.sock = PJ_INVALID_SOCKET;
220 }
221
222 /* Mark as shutdown */
223 relay->lifetime = 0;
224}
225
226/* Initiate shutdown sequence for this allocation */
227static void alloc_shutdown(pjturn_allocation *alloc)
228{
229 pj_time_val destroy_delay = DESTROY_DELAY;
230
231 /* Work with existing schedule */
232 if (alloc->relay.timer.id == TIMER_ID_TIMEOUT) {
233 /* Cancel existing timer */
234 pj_timer_heap_cancel(alloc->listener->server->core.timer_heap,
235 &alloc->relay.timer);
236 alloc->relay.timer.id = TIMER_ID_NONE;
237
238 } else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
239 /* We've been scheduled to be destroyed, ignore this
240 * shutdown request.
241 */
242 return;
243 }
244
245 pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);
246
247 /* Shutdown relay socket */
248 destroy_relay(&alloc->relay);
249
250 /* Don't unregister from hash table because we still need to
251 * handle REFRESH retransmission.
252 */
253
254 /* Schedule destroy timer */
255 alloc->relay.timer.id = TIMER_ID_DESTROY;
256 pj_timer_heap_schedule(alloc->listener->server->core.timer_heap,
257 &alloc->relay.timer, &destroy_delay);
258}
259
260/* Reschedule timeout using current lifetime setting */
261static pj_status_t resched_timeout(pjturn_allocation *alloc)
262{
263 pj_time_val delay;
264 pj_status_t status;
265
266 pj_gettimeofday(&alloc->relay.expiry);
267 alloc->relay.expiry.sec += alloc->relay.lifetime;
268
269 pj_assert(alloc->relay.timer.id != TIMER_ID_DESTROY);
270 if (alloc->relay.timer.id != 0) {
271 pj_timer_heap_cancel(alloc->listener->server->core.timer_heap,
272 &alloc->relay.timer);
273 alloc->relay.timer.id = TIMER_ID_NONE;
274 }
275
276 delay.sec = alloc->relay.lifetime;
277 delay.msec = 0;
278
279 alloc->relay.timer.id = TIMER_ID_TIMEOUT;
280 status = pj_timer_heap_schedule(alloc->listener->server->core.timer_heap,
281 &alloc->relay.timer, &delay);
282 if (status != PJ_SUCCESS) {
283 alloc->relay.timer.id = TIMER_ID_NONE;
284 return status;
285 }
286
287 return PJ_SUCCESS;
288}
289
290
291/* Timer timeout callback */
292static void relay_timeout_cb(pj_timer_heap_t *heap, pj_timer_entry *e)
293{
294 pjturn_relay_res *rel;
295 pjturn_allocation *alloc;
296
297 rel = (pjturn_relay_res*) e->user_data;
298 alloc = rel->allocation;
299
300 if (e->id == TIMER_ID_TIMEOUT) {
301
302 e->id = TIMER_ID_NONE;
303
304 PJ_LOG(4,(alloc->obj_name,
305 "Client %s refresh timed-out, shutting down..",
306 alloc->info));
307
308 alloc_shutdown(alloc);
309
310 } else if (e->id == TIMER_ID_DESTROY) {
311 e->id = TIMER_ID_NONE;
312
313 PJ_LOG(4,(alloc->obj_name, "Client %s destroying..",
314 alloc->info));
315
316 pjturn_allocation_destroy(alloc);
317 }
318}
319
320
321/*
322 * Create relay.
323 */
324PJ_DEF(pj_status_t) pjturn_allocation_create_relay(pjturn_srv *srv,
325 pjturn_allocation *alloc,
326 const pj_stun_msg *msg,
327 const pjturn_allocation_req *req,
328 pjturn_relay_res *relay)
329{
330 enum { RETRY = 40 };
331 pj_pool_t *pool = alloc->pool;
332 int retry, retry_max, sock_type;
333 pj_ioqueue_callback icb;
334 int af, namelen;
335 pj_stun_string_attr *sa;
336 pj_status_t status;
337
338 pj_bzero(relay, sizeof(*relay));
339
340 relay->allocation = alloc;
341 relay->tp.sock = PJ_INVALID_SOCKET;
342
343 /* TODO: get the requested address family from somewhere */
344 af = alloc->listener->addr.addr.sa_family;
345
346 /* Save realm */
347 sa = (pj_stun_string_attr*)
348 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
349 PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
350 pj_strdup(pool, &relay->realm, &sa->value);
351
352 /* Save username */
353 sa = (pj_stun_string_attr*)
354 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
355 PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
356 pj_strdup(pool, &relay->user, &sa->value);
357
358 /* Lifetime and timeout */
359 relay->lifetime = req->lifetime;
360 pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
361 &relay_timeout_cb);
362 resched_timeout(alloc);
363
364 /* Transport type */
365 relay->hkey.tp_type = req->tp_type;
366
367 /* Create the socket */
368 if (req->tp_type == PJTURN_TP_UDP) {
369 sock_type = pj_SOCK_DGRAM();
370 } else if (req->tp_type == PJTURN_TP_TCP) {
371 sock_type = pj_SOCK_STREAM();
372 } else {
373 pj_assert(!"Unknown transport");
374 return PJ_EINVALIDOP;
375 }
376
377 status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
378 if (status != PJ_SUCCESS) {
379 pj_bzero(relay, sizeof(*relay));
380 return status;
381 }
382
383 /* Find suitable port for this allocation */
384 if (req->rpp_port) {
385 retry_max = 1;
386 } else {
387 retry_max = RETRY;
388 }
389
390 for (retry=0; retry<retry_max; ++retry) {
391 pj_uint16_t port;
392 pj_sockaddr bound_addr;
393
394 pj_lock_acquire(srv->core.lock);
395
396 if (req->rpp_port) {
397 port = (pj_uint16_t) req->rpp_port;
398 } else if (req->tp_type == PJTURN_TP_UDP) {
399 port = (pj_uint16_t) srv->ports.next_udp++;
400 if (srv->ports.next_udp > srv->ports.max_udp)
401 srv->ports.next_udp = srv->ports.min_udp;
402 } else if (req->tp_type == PJTURN_TP_TCP) {
403 port = (pj_uint16_t) srv->ports.next_tcp++;
404 if (srv->ports.next_tcp > srv->ports.max_tcp)
405 srv->ports.next_tcp = srv->ports.min_tcp;
406 } else {
407 pj_assert(!"Invalid transport");
408 }
409
410 pj_lock_release(srv->core.lock);
411
412 pj_sockaddr_init(af, &bound_addr, NULL, port);
413
414 status = pj_sock_bind(relay->tp.sock, &bound_addr,
415 pj_sockaddr_get_len(&bound_addr));
416 if (status == PJ_SUCCESS)
417 break;
418 }
419
420 if (status != PJ_SUCCESS) {
421 /* Unable to allocate port */
422 PJ_LOG(4,(THIS_FILE, "bind() failed: err %d",
423 status));
424 pj_sock_close(relay->tp.sock);
425 relay->tp.sock = PJ_INVALID_SOCKET;
426 return status;
427 }
428
429 /* Init relay key */
430 namelen = sizeof(relay->hkey.addr);
431 status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
432 if (status != PJ_SUCCESS) {
433 PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d",
434 status));
435 pj_sock_close(relay->tp.sock);
436 relay->tp.sock = PJ_INVALID_SOCKET;
437 return status;
438 }
439 if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
440 pj_sockaddr_copy_addr(&relay->hkey.addr, &alloc->listener->addr);
441 }
442
443 /* Init ioqueue */
444 pj_bzero(&icb, sizeof(icb));
445 icb.on_read_complete = &on_rx_from_peer;
446
447 status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
448 relay, &icb, &relay->tp.key);
449 if (status != PJ_SUCCESS) {
450 PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d",
451 status));
452 pj_sock_close(relay->tp.sock);
453 relay->tp.sock = PJ_INVALID_SOCKET;
454 return status;
455 }
456
457 /* Kick off pending read operation */
458 pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
459 on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);
460
461 /* Done */
462 return PJ_SUCCESS;
463}
464
465/* Create and send error response */
466static void send_reply_err(pjturn_allocation *alloc,
467 const pj_stun_msg *req,
468 pj_bool_t cache,
469 int code, const char *errmsg)
470{
471 pj_status_t status;
472 pj_str_t reason;
473 pj_stun_tx_data *tdata;
474
475 status = pj_stun_session_create_res(alloc->sess, req,
476 code, (errmsg?pj_cstr(&reason,errmsg):NULL),
477 &tdata);
478 if (status != PJ_SUCCESS) {
479 alloc_err(alloc, "Error creating STUN error response", status);
480 return;
481 }
482
483 status = pj_stun_session_send_msg(alloc->sess, cache,
484 &alloc->hkey.clt_addr,
485 pj_sockaddr_get_len(&alloc->hkey.clt_addr),
486 tdata);
487 if (status != PJ_SUCCESS) {
488 alloc_err(alloc, "Error sending STUN error response", status);
489 return;
490 }
491}
492
493/* Create and send successful response */
494static void send_reply_ok(pjturn_allocation *alloc,
495 const pj_stun_msg *req)
496{
497 pj_status_t status;
498 unsigned interval;
499 pj_stun_tx_data *tdata;
500
501 status = pj_stun_session_create_res(alloc->sess, req, 0, NULL, &tdata);
502 if (status != PJ_SUCCESS) {
503 alloc_err(alloc, "Error creating STUN success response", status);
504 return;
505 }
506
507 /* Calculate time to expiration */
508 if (alloc->relay.lifetime != 0) {
509 pj_time_val now;
510 pj_gettimeofday(&now);
511 interval = alloc->relay.expiry.sec - now.sec;
512 } else {
513 interval = 0;
514 }
515
516 /* Add LIFETIME. */
517 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
518 PJ_STUN_ATTR_LIFETIME, interval);
519
520 /* Add BANDWIDTH */
521 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
522 PJ_STUN_ATTR_BANDWIDTH,
523 alloc->bandwidth);
524
525 status = pj_stun_session_send_msg(alloc->sess, PJ_TRUE,
526 &alloc->hkey.clt_addr,
527 pj_sockaddr_get_len(&alloc->hkey.clt_addr),
528 tdata);
529 if (status != PJ_SUCCESS) {
530 alloc_err(alloc, "Error sending STUN success response", status);
531 return;
532 }
533}
534
535
536/* Create new permission */
537static pjturn_permission *create_permission(pjturn_allocation *alloc,
538 const pj_sockaddr_t *peer_addr,
539 unsigned addr_len)
540{
541 pjturn_permission *perm;
542
543 perm = PJ_POOL_ZALLOC_T(alloc->pool, pjturn_permission);
544 pj_memcpy(&perm->hkey.peer_addr, peer_addr, addr_len);
545
546 if (alloc->listener->tp_type == PJTURN_TP_UDP) {
547 perm->sock = alloc->listener->sock;
548 } else {
549 pj_assert(!"TCP is not supported yet");
550 return NULL;
551 }
552
553 perm->allocation = alloc;
554 perm->channel = PJTURN_INVALID_CHANNEL;
555
556 pj_gettimeofday(&perm->expiry);
557 perm->expiry.sec += PJTURN_PERM_TIMEOUT;
558
559 return perm;
560}
561
562/* Check if a permission isn't expired. Return NULL if expired. */
563static pjturn_permission *check_permission_expiry(pjturn_permission *perm)
564{
565 pjturn_allocation *alloc = perm->allocation;
566 pj_time_val now;
567
568 pj_gettimeofday(&now);
569 if (PJ_TIME_VAL_LT(perm->expiry, now)) {
570 /* Permission has not expired */
571 return perm;
572 }
573
574 /* Remove from permission hash table */
575 pj_hash_set(NULL, alloc->peer_table, &perm->hkey, sizeof(perm->hkey),
576 0, NULL);
577
578 /* Remove from channel hash table, if assigned a channel number */
579 if (perm->channel != PJTURN_INVALID_CHANNEL) {
580 pj_hash_set(NULL, alloc->ch_table, &perm->channel,
581 sizeof(perm->channel), 0, NULL);
582 }
583
584 return NULL;
585}
586
587/* Lookup permission in hash table by the peer address */
588static pjturn_permission*
589lookup_permission_by_addr(pjturn_allocation *alloc,
590 const pj_sockaddr_t *peer_addr,
591 unsigned addr_len)
592{
593 pjturn_permission_key key;
594 pjturn_permission *perm;
595
596 pj_bzero(&key, sizeof(key));
597 pj_memcpy(&key, peer_addr, addr_len);
598
599 /* Lookup in peer hash table */
600 perm = (pjturn_permission*) pj_hash_get(alloc->peer_table, &key,
601 sizeof(key), NULL);
602 return check_permission_expiry(perm);
603}
604
605/* Lookup permission in hash table by the channel number */
606static pjturn_permission*
607lookup_permission_by_chnum(pjturn_allocation *alloc,
608 unsigned chnum)
609{
610 pj_uint16_t chnum16 = (pj_uint16_t)chnum;
611 pjturn_permission *perm;
612
613 /* Lookup in peer hash table */
614 perm = (pjturn_permission*) pj_hash_get(alloc->peer_table, &chnum16,
615 sizeof(chnum16), NULL);
616 return check_permission_expiry(perm);
617}
618
619/* Update permission because of data from client to peer.
620 * Return PJ_TRUE is permission is found.
621 */
622static pj_bool_t refresh_permission(pjturn_permission *perm)
623{
624 pj_gettimeofday(&perm->expiry);
625 if (perm->channel == PJTURN_INVALID_CHANNEL)
626 perm->expiry.sec += PJTURN_PERM_TIMEOUT;
627 else
628 perm->expiry.sec += PJTURN_CHANNEL_TIMEOUT;
629 return PJ_TRUE;
630}
631
632/*
633 * Handle incoming packet from client.
634 */
635PJ_DEF(void) pjturn_allocation_on_rx_client_pkt( pjturn_allocation *alloc,
636 pjturn_pkt *pkt)
637{
638 pj_bool_t is_stun;
639 pj_status_t status;
640
641 /* Quickly check if this is STUN message */
642 is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0);
643
644 if (is_stun) {
645 /*
646 * This could be an incoming STUN requests or indications.
647 * Pass this through to the STUN session, which will call
648 * our stun_on_rx_request() or stun_on_rx_indication()
649 * callbacks.
650 */
651 unsigned options = PJ_STUN_CHECK_PACKET;
652 if (pkt->listener->tp_type == PJTURN_TP_UDP)
653 options |= PJ_STUN_IS_DATAGRAM;
654
655 status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len,
656 options, NULL,
657 &pkt->src.clt_addr,
658 pkt->src_addr_len);
659 if (status != PJ_SUCCESS) {
660 alloc_err(alloc, "Error handling STUN packet", status);
661 return;
662 }
663
664 } else {
665 /*
666 * This is not a STUN packet, must be ChannelData packet.
667 */
668 channel_data_hdr *cd = (channel_data_hdr*)pkt->pkt;
669 pjturn_permission *perm;
670 pj_ssize_t len;
671
672 /* For UDP check the packet length */
673 if (alloc->listener->tp_type == PJTURN_TP_UDP) {
674 if (pkt->len < pj_ntohs(cd->length)+sizeof(*cd)) {
675 PJ_LOG(4,(alloc->obj_name,
676 "ChannelData from %s discarded: UDP size error",
677 alloc->info));
678 return;
679 }
680 } else {
681 pj_assert(!"Unsupported transport");
682 return;
683 }
684
685 perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number));
686 if (!perm) {
687 /* Discard */
688 PJ_LOG(4,(alloc->obj_name,
689 "ChannelData from %s discarded: not found",
690 alloc->info));
691 return;
692 }
693
694 /* Relay the data */
695 len = pj_ntohs(cd->length);
696 pj_sock_sendto(alloc->relay.tp.sock, cd+1, &len, 0,
697 &perm->hkey.peer_addr,
698 pj_sockaddr_get_len(&perm->hkey.peer_addr));
699
700 /* Refresh permission */
701 refresh_permission(perm);
702 }
703}
704
705/*
706 * Handle incoming packet from peer. This function is called by
707 * on_rx_from_peer().
708 */
709static void on_rx_peer_pkt(pjturn_allocation *alloc,
710 pjturn_relay_res *rel,
711 char *pkt, pj_size_t len,
712 const pj_sockaddr *src_addr)
713{
714 pjturn_permission *perm;
715
716 /* Lookup permission */
717 perm = lookup_permission_by_addr(alloc, src_addr,
718 pj_sockaddr_get_len(src_addr));
719 if (perm == NULL) {
720 /* No permission, discard data */
721 return;
722 }
723
724 /* Send Data Indication or ChannelData, depends on whether
725 * this permission is attached to a channel number.
726 */
727 if (perm->channel != PJTURN_INVALID_CHANNEL) {
728 /* Send ChannelData */
729 channel_data_hdr *cd = (channel_data_hdr*)rel->tp.tx_pkt;
730
731 if (len > PJTURN_MAX_PKT_LEN) {
732 char peer_addr[80];
733 pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3);
734 PJ_LOG(1,(alloc->obj_name, "Client %s: discarded data from %s "
735 "because it's too long (%d bytes)",
736 alloc->info, peer_addr, len));
737 return;
738 }
739
740 /* Init header */
741 cd->ch_number = pj_htons(perm->channel);
742 cd->length = pj_htons((pj_uint16_t)len);
743
744 /* Copy data */
745 pj_memcpy(rel->tp.rx_pkt+sizeof(channel_data_hdr), pkt, len);
746
747 /* Send to client */
748 pjturn_listener_sendto(alloc->listener, rel->tp.tx_pkt,
749 len+sizeof(channel_data_hdr), 0,
750 &alloc->hkey.clt_addr,
751 pj_sockaddr_get_len(&alloc->hkey.clt_addr));
752 } else {
753 /* Send Data Indication */
754 pj_stun_tx_data *tdata;
755 pj_status_t status;
756
757 status = pj_stun_session_create_ind(alloc->sess,
758 PJ_STUN_DATA_INDICATION, &tdata);
759 if (status != PJ_SUCCESS) {
760 alloc_err(alloc, "Error creating Data indication", status);
761 return;
762 }
763 }
764}
765
766/*
767 * ioqueue notification on RX packets from the relay socket.
768 */
769static void on_rx_from_peer(pj_ioqueue_key_t *key,
770 pj_ioqueue_op_key_t *op_key,
771 pj_ssize_t bytes_read)
772{
773 pjturn_relay_res *rel;
774 pj_status_t status;
775
776 rel = (pjturn_relay_res*) pj_ioqueue_get_user_data(key);
777
778 do {
779 if (bytes_read > 0) {
780 on_rx_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
781 bytes_read, &rel->tp.src_addr);
782 }
783
784 /* Read next packet */
785 bytes_read = sizeof(rel->tp.rx_pkt);
786 rel->tp.src_addr_len = sizeof(rel->tp.src_addr);
787 status = pj_ioqueue_recvfrom(key, op_key,
788 rel->tp.rx_pkt, &bytes_read, 0,
789 &rel->tp.src_addr,
790 &rel->tp.src_addr_len);
791
792 if (status != PJ_EPENDING && status != PJ_SUCCESS)
793 bytes_read = -status;
794
795 } while (status != PJ_EPENDING && status != PJ_ECANCELLED);
796
797}
798
799/*
800 * Callback notification from STUN session when it wants to send
801 * a STUN message towards the client.
802 */
803static pj_status_t stun_on_send_msg(pj_stun_session *sess,
804 const void *pkt,
805 pj_size_t pkt_size,
806 const pj_sockaddr_t *dst_addr,
807 unsigned addr_len)
808{
809 pjturn_allocation *alloc;
810
811 alloc = (pjturn_allocation*) pj_stun_session_get_user_data(sess);
812
813 return pjturn_listener_sendto(alloc->listener, pkt, pkt_size, 0,
814 dst_addr, addr_len);
815}
816
817/*
818 * Callback notification from STUN session when it receives STUN
819 * requests. This callback was trigger by STUN incoming message
820 * processing in pjturn_allocation_on_rx_client_pkt().
821 */
822static pj_status_t stun_on_rx_request(pj_stun_session *sess,
823 const pj_uint8_t *pkt,
824 unsigned pkt_len,
825 const pj_stun_msg *msg,
826 const pj_sockaddr_t *src_addr,
827 unsigned src_addr_len)
828{
829 pjturn_allocation *alloc;
830
831 alloc = (pjturn_allocation*) pj_stun_session_get_user_data(sess);
832
833 /* Refuse to serve any request if we've been shutdown */
834 if (alloc->relay.lifetime == 0) {
835 send_reply_err(alloc, msg, PJ_TRUE,
836 PJ_STUN_SC_ALLOCATION_MISMATCH, NULL);
837 return PJ_SUCCESS;
838 }
839
840 if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) {
841 /*
842 * Handle REFRESH request
843 */
844 pj_stun_lifetime_attr *lifetime;
845 pj_stun_bandwidth_attr *bandwidth;
846
847 /* Get LIFETIME attribute */
848 lifetime = (pj_stun_lifetime_attr*)
849 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
850
851 /* Get BANDWIDTH attribute */
852 bandwidth = (pj_stun_bandwidth_attr*)
853 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
854
855 if (lifetime && lifetime->value==0) {
856 /*
857 * This is deallocation request.
858 */
859 alloc->relay.lifetime = 0;
860
861 /* Respond first */
862 send_reply_ok(alloc, msg);
863
864 /* Shutdown allocation */
865 PJ_LOG(4,(alloc->obj_name,
866 "Client %s request to dealloc, shutting down",
867 alloc->info));
868
869 alloc_shutdown(alloc);
870
871 } else {
872 /*
873 * This is a refresh request.
874 */
875
876 /* Update lifetime */
877 if (lifetime) {
878 alloc->relay.lifetime = lifetime->value;
879 }
880
881 /* Update bandwidth */
882 // TODO:
883
884 /* Update expiration timer */
885 resched_timeout(alloc);
886
887 /* Send reply */
888 send_reply_ok(alloc, msg);
889 }
890
891 } else if (msg->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
892 /*
893 * ChannelBind request.
894 */
895 pj_stun_channel_number_attr *ch_attr;
896 pj_stun_peer_addr_attr *peer_attr;
897 pjturn_permission *p1, *p2;
898
899 ch_attr = (pj_stun_channel_number_attr*)
900 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CHANNEL_NUMBER, 0);
901 peer_attr = (pj_stun_peer_addr_attr*)
902 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PEER_ADDR, 0);
903
904 if (!ch_attr || !peer_attr) {
905 send_reply_err(alloc, msg, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
906 return PJ_SUCCESS;
907 }
908
909 /* Find permission with the channel number */
910 p1 = lookup_permission_by_chnum(alloc, PJ_STUN_GET_CH_NB(ch_attr->value));
911
912 /* If permission is found, this is supposed to be a channel bind
913 * refresh. Make sure it's for the same peer.
914 */
915 if (p1) {
916 if (pj_sockaddr_cmp(&p1->hkey.peer_addr, &peer_attr->sockaddr)) {
917 /* Address mismatch. Send 400 */
918 send_reply_err(alloc, msg, PJ_TRUE,
919 PJ_STUN_SC_BAD_REQUEST,
920 "Peer address mismatch");
921 return PJ_SUCCESS;
922 }
923
924 /* Refresh permission */
925 refresh_permission(p1);
926
927 /* Done */
928 return PJ_SUCCESS;
929 }
930
931 /* If permission is not found, create a new one. Make sure the peer
932 * has not alreadyy assigned with a channel number.
933 */
934 p2 = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
935 pj_sockaddr_get_len(&peer_attr->sockaddr));
936 if (p2 && p2->channel != PJTURN_INVALID_CHANNEL) {
937 send_reply_err(alloc, msg, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST,
938 "Peer address already assigned a channel number");
939 return PJ_SUCCESS;
940 }
941
942 /* Create permission if it doesn't exist */
943 if (!p2) {
944 p2 = create_permission(alloc, &peer_attr->sockaddr,
945 pj_sockaddr_get_len(&peer_attr->sockaddr));
946 if (!p2)
947 return PJ_SUCCESS;
948 }
949
950 /* Assign channel number to permission */
951 p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
952
953 /* Update */
954 refresh_permission(p2);
955
956 /* Reply */
957 send_reply_ok(alloc, msg);
958
959 return PJ_SUCCESS;
960
961 } else if (msg->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
962
963 /* Respond with 437 (section 6.3 turn-07) */
964 send_reply_err(alloc, msg, PJ_TRUE, PJ_STUN_SC_ALLOCATION_MISMATCH, NULL);
965
966 } else {
967
968 /* Respond with Bad Request? */
969 send_reply_err(alloc, msg, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
970
971 }
972
973 return PJ_SUCCESS;
974}
975
976/*
977 * Callback notification from STUN session when it receives STUN
978 * indications. This callback was trigger by STUN incoming message
979 * processing in pjturn_allocation_on_rx_client_pkt().
980 */
981static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
982 const pj_uint8_t *pkt,
983 unsigned pkt_len,
984 const pj_stun_msg *msg,
985 const pj_sockaddr_t *src_addr,
986 unsigned src_addr_len)
987{
988 pj_stun_peer_addr_attr *peer_attr;
989 pj_stun_data_attr *data_attr;
990 pjturn_allocation *alloc;
991 pjturn_permission *perm;
992
993 alloc = (pjturn_allocation*) pj_stun_session_get_user_data(sess);
994
995 /* Only expect Send Indication */
996 if (msg->hdr.type != PJ_STUN_SEND_INDICATION) {
997 /* Ignore */
998 return PJ_SUCCESS;
999 }
1000
1001 /* Get PEER-ADDRESS attribute */
1002 peer_attr = (pj_stun_peer_addr_attr*)
1003 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PEER_ADDR, 0);
1004
1005 /* MUST have PEER-ADDRESS attribute */
1006 if (!peer_attr)
1007 return PJ_SUCCESS;
1008
1009 /* Get DATA attribute */
1010 data_attr = (pj_stun_data_attr*)
1011 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1012
1013 /* Create/update/refresh the permission */
1014 perm = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1015 pj_sockaddr_get_len(&peer_attr->sockaddr));
1016 if (perm == NULL) {
1017 perm = create_permission(alloc, &peer_attr->sockaddr,
1018 pj_sockaddr_get_len(&peer_attr->sockaddr));
1019 }
1020 refresh_permission(perm);
1021
1022 /* Return if we don't have data */
1023 if (data_attr == NULL)
1024 return PJ_SUCCESS;
1025
1026 /* Relay the data to client */
1027 if (alloc->hkey.tp_type == PJTURN_TP_UDP) {
1028 pj_ssize_t len = data_attr->length;
1029 pj_sock_sendto(alloc->listener->sock, data_attr->data,
1030 &len, 0, &peer_attr->sockaddr,
1031 pj_sockaddr_get_len(&peer_attr->sockaddr));
1032 } else {
1033 pj_assert(!"TCP is not supported");
1034 }
1035
1036 return PJ_SUCCESS;
1037}
1038
1039