blob: f27d3a9c84093a264289969ea5b1f3fe50cefba2 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id: server.c 4360 2013-02-21 11:26:35Z bennylp $ */
Tristan Matthews0a329cc2013-07-17 13:20:14 -04002/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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"
21#include "auth.h"
22
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
31#define MAX_THREADS 2
32#define MAX_NET_EVENTS 1000
33
34/* Prototypes */
35static int server_thread_proc(void *arg);
36static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
37 void *token,
38 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,
45 const pj_stun_rx_data *rdata,
46 void *user_data,
47 const pj_sockaddr_t *src_addr,
48 unsigned src_addr_len);
49
50struct 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
60/*
61 * Get transport type name, normally for logging purpose only.
62 */
63PJ_DEF(const char*) pj_turn_tp_type_name(int tp_type)
64{
65 /* Must be 3 characters long! */
66 if (tp_type == PJ_TURN_TP_UDP) {
67 return "UDP";
68 } else if (tp_type == PJ_TURN_TP_TCP) {
69 return "TCP";
70 } else {
71 pj_assert(!"Unsupported transport");
72 return "???";
73 }
74}
75
76/*
77 * Create server.
78 */
79PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,
80 pj_turn_srv **p_srv)
81{
82 pj_pool_t *pool;
83 pj_stun_session_cb sess_cb;
84 pj_turn_srv *srv;
85 unsigned i;
86 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);
92 srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv);
93 srv->obj_name = pool->obj_name;
94 srv->core.pf = pf;
95 srv->core.pool = pool;
96 srv->core.tls_key = srv->core.tls_data = -1;
97
98 /* Create ioqueue */
99 status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue);
100 if (status != PJ_SUCCESS)
101 goto on_error;
102
103 /* 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 */
119 status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap);
120 if (status != PJ_SUCCESS)
121 goto on_error;
122
123 /* 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,
129 sizeof(srv->core.listener[0]));
130
131 /* Create hash tables */
132 srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
133 srv->tables.res = pj_hash_create(pool, MAX_CLIENTS);
134
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;
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
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;
151
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;
156
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) {
161 goto on_error;
162 }
163
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,
166 &srv->core.cred);
167
168
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*));
174
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)
180 goto on_error;
181 }
182
183 /* We're done. Application should add listeners now */
184 PJ_LOG(4,(srv->obj_name, "TURN server v%s is running",
185 pj_get_version()));
186
187 *p_srv = srv;
188 return PJ_SUCCESS;
189
190on_error:
191 pj_turn_srv_destroy(srv);
192 return status;
193}
194
195
196/*
197 * Handle timer and network events
198 */
199static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout)
200{
201 /* timeout is 'out' var. This just to make compiler happy. */
202 pj_time_val timeout = { 0, 0};
203 unsigned net_event_count = 0;
204 int c;
205
206 /* Poll the timer. The timer heap has its own mutex for better
207 * granularity, so we don't need to lock the server.
208 */
209 timeout.sec = timeout.msec = 0;
210 c = pj_timer_heap_poll( srv->core.timer_heap, &timeout );
211
212 /* timer_heap_poll should never ever returns negative value, or otherwise
213 * ioqueue_poll() will block forever!
214 */
215 pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
216 if (timeout.msec >= 1000) timeout.msec = 999;
217
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.
220 */
221 if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
222 timeout = *max_timeout;
223 }
224
225 /* Poll ioqueue.
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.
230 *
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.
235 */
236 do {
237 c = pj_ioqueue_poll( srv->core.ioqueue, &timeout);
238 if (c < 0) {
239 pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
240 return;
241 } else if (c == 0) {
242 break;
243 } else {
244 net_event_count += c;
245 timeout.sec = timeout.msec = 0;
246 }
247 } while (c > 0 && net_event_count < MAX_NET_EVENTS);
248
249}
250
251/*
252 * Server worker thread proc.
253 */
254static int server_thread_proc(void *arg)
255{
256 pj_turn_srv *srv = (pj_turn_srv*)arg;
257
258 while (!srv->core.quit) {
259 pj_time_val timeout_max = {0, 100};
260 srv_handle_events(srv, &timeout_max);
261 }
262
263 return 0;
264}
265
266/*
267 * Destroy the server.
268 */
269PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
270{
271 pj_hash_iterator_t itbuf, *it;
272 unsigned i;
273
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;
281 }
282 }
283
284 /* Destroy all allocations FIRST */
285 if (srv->tables.alloc) {
286 it = pj_hash_first(srv->tables.alloc, &itbuf);
287 while (it != NULL) {
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);
292 it = next;
293 }
294 }
295
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;
301 }
302 }
303
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;
308 }
309
310 /* Destroy hash tables (well, sort of) */
311 if (srv->tables.alloc) {
312 srv->tables.alloc = NULL;
313 srv->tables.res = NULL;
314 }
315
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;
320 }
321
322 /* Destroy ioqueue */
323 if (srv->core.ioqueue) {
324 pj_ioqueue_destroy(srv->core.ioqueue);
325 srv->core.ioqueue = NULL;
326 }
327
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;
332 }
333 if (srv->core.tls_data != -1) {
334 pj_thread_local_free(srv->core.tls_data);
335 srv->core.tls_data = -1;
336 }
337
338 /* Destroy server lock */
339 if (srv->core.lock) {
340 pj_lock_destroy(srv->core.lock);
341 srv->core.lock = NULL;
342 }
343
344 /* Release pool */
345 if (srv->core.pool) {
346 pj_pool_t *pool = srv->core.pool;
347 srv->core.pool = NULL;
348 pj_pool_release(pool);
349 }
350
351 /* Done */
352 return PJ_SUCCESS;
353}
354
355
356/*
357 * Add listener.
358 */
359PJ_DEF(pj_status_t) pj_turn_srv_add_listener(pj_turn_srv *srv,
360 pj_turn_listener *lis)
361{
362 unsigned index;
363
364 PJ_ASSERT_RETURN(srv && lis, PJ_EINVAL);
365 PJ_ASSERT_RETURN(srv->core.lis_cnt < MAX_LISTENERS, PJ_ETOOMANY);
366
367 /* Add to array */
368 index = srv->core.lis_cnt;
369 srv->core.listener[index] = lis;
370 lis->server = srv;
371 lis->id = index;
372 srv->core.lis_cnt++;
373
374 PJ_LOG(4,(srv->obj_name, "Listener %s/%s added at index %d",
375 lis->obj_name, lis->info, lis->id));
376
377 return PJ_SUCCESS;
378}
379
380
381/*
382 * Destroy listener.
383 */
384PJ_DEF(pj_status_t) pj_turn_listener_destroy(pj_turn_listener *listener)
385{
386 pj_turn_srv *srv = listener->server;
387 unsigned i;
388
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;
394 srv->core.lis_cnt--;
395 listener->id = PJ_TURN_INVALID_LIS_ID;
396 break;
397 }
398 }
399 pj_lock_release(srv->core.lock);
400
401 /* Destroy */
402 return listener->destroy(listener);
403}
404
405
406/**
407 * Add a reference to a transport.
408 */
409PJ_DEF(void) pj_turn_transport_add_ref( pj_turn_transport *transport,
410 pj_turn_allocation *alloc)
411{
412 transport->add_ref(transport, alloc);
413}
414
415
416/**
417 * Decrement transport reference counter.
418 */
419PJ_DEF(void) pj_turn_transport_dec_ref( pj_turn_transport *transport,
420 pj_turn_allocation *alloc)
421{
422 transport->dec_ref(transport, alloc);
423}
424
425
426/*
427 * Register an allocation to the hash tables.
428 */
429PJ_DEF(pj_status_t) pj_turn_srv_register_allocation(pj_turn_srv *srv,
430 pj_turn_allocation *alloc)
431{
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,
438 &alloc->relay);
439 pj_lock_release(srv->core.lock);
440
441 return PJ_SUCCESS;
442}
443
444
445/*
446 * Unregister an allocation from the hash tables.
447 */
448PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv,
449 pj_turn_allocation *alloc)
450{
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);
458
459 return PJ_SUCCESS;
460}
461
462
463/* Callback from our own STUN session whenever it needs to send
464 * outgoing STUN packet.
465 */
466static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
467 void *token,
468 const void *pdu,
469 pj_size_t pdu_size,
470 const pj_sockaddr_t *dst_addr,
471 unsigned addr_len)
472{
473 pj_turn_transport *transport = (pj_turn_transport*) token;
474
475 PJ_ASSERT_RETURN(transport!=NULL, PJ_EINVALIDOP);
476
477 PJ_UNUSED_ARG(sess);
478
479 return transport->sendto(transport, pdu, pdu_size, 0,
480 dst_addr, addr_len);
481}
482
483
484/* Respond to STUN request */
485static pj_status_t stun_respond(pj_stun_session *sess,
486 pj_turn_transport *transport,
487 const pj_stun_rx_data *rdata,
488 unsigned code,
489 const char *errmsg,
490 pj_bool_t cache,
491 const pj_sockaddr_t *dst_addr,
492 unsigned addr_len)
493{
494 pj_status_t status;
495 pj_str_t reason;
496 pj_stun_tx_data *tdata;
497
498 /* Create response */
499 status = pj_stun_session_create_res(sess, rdata, code,
500 (errmsg?pj_cstr(&reason,errmsg):NULL),
501 &tdata);
502 if (status != PJ_SUCCESS)
503 return status;
504
505 /* Send the response */
506 return pj_stun_session_send_msg(sess, transport, cache, PJ_FALSE,
507 dst_addr, addr_len, tdata);
508}
509
510
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.
514 */
515static pj_status_t on_rx_stun_request(pj_stun_session *sess,
516 const pj_uint8_t *pdu,
517 unsigned pdu_len,
518 const pj_stun_rx_data *rdata,
519 void *token,
520 const pj_sockaddr_t *src_addr,
521 unsigned src_addr_len)
522{
523 pj_turn_transport *transport;
524 const pj_stun_msg *msg = rdata->msg;
525 pj_turn_srv *srv;
526 pj_turn_allocation *alloc;
527 pj_status_t status;
528
529 PJ_UNUSED_ARG(pdu);
530 PJ_UNUSED_ARG(pdu_len);
531
532 transport = (pj_turn_transport*) token;
533 srv = transport->listener->server;
534
535 /* Respond any requests other than ALLOCATE with 437 response */
536 if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
537 stun_respond(sess, transport, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
538 NULL, PJ_FALSE, src_addr, src_addr_len);
539 return PJ_SUCCESS;
540 }
541
542 /* Create new allocation. The relay resource will be allocated
543 * in this function.
544 */
545 status = pj_turn_allocation_create(transport, src_addr, src_addr_len,
546 rdata, sess, &alloc);
547 if (status != PJ_SUCCESS) {
548 /* STUN response has been sent, no need to reply here */
549 return PJ_SUCCESS;
550 }
551
552 /* Done. */
553 return PJ_SUCCESS;
554}
555
556/* Handle STUN Binding request */
557static void handle_binding_request(pj_turn_pkt *pkt,
558 unsigned options)
559{
560 pj_stun_msg *request, *response;
561 pj_uint8_t pdu[200];
562 pj_size_t len;
563 pj_status_t status;
564
565 /* Decode request */
566 status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options,
567 &request, NULL, NULL);
568 if (status != PJ_SUCCESS)
569 return;
570
571 /* Create response */
572 status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL,
573 &response);
574 if (status != PJ_SUCCESS)
575 return;
576
577 /* Add XOR-MAPPED-ADDRESS */
578 pj_stun_msg_add_sockaddr_attr(pkt->pool, response,
579 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
580 PJ_TRUE,
581 &pkt->src.clt_addr,
582 pkt->src_addr_len);
583
584 /* Encode */
585 status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len);
586 if (status != PJ_SUCCESS)
587 return;
588
589 /* Send response */
590 pkt->transport->sendto(pkt->transport, pdu, len, 0,
591 &pkt->src.clt_addr, pkt->src_addr_len);
592}
593
594/*
595 * This callback is called by UDP listener on incoming packet. This is
596 * the first entry for incoming packet (from client) to the server. From
597 * here, the packet may be handed over to an allocation if an allocation
598 * is found for the client address, or handed over to owned STUN session
599 * if an allocation is not found.
600 */
601PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv,
602 pj_turn_pkt *pkt)
603{
604 pj_turn_allocation *alloc;
605
606 /* Get TURN allocation from the source address */
607 pj_lock_acquire(srv->core.lock);
608 alloc = (pj_turn_allocation*)
609 pj_hash_get(srv->tables.alloc, &pkt->src, sizeof(pkt->src), NULL);
610 pj_lock_release(srv->core.lock);
611
612 /* If allocation is found, just hand over the packet to the
613 * allocation.
614 */
615 if (alloc) {
616 pj_turn_allocation_on_rx_client_pkt(alloc, pkt);
617 } else {
618 /* Otherwise this is a new client */
619 unsigned options;
620 pj_size_t parsed_len;
621 pj_status_t status;
622
623 /* Check that this is a STUN message */
624 options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
625 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
626 options |= PJ_STUN_IS_DATAGRAM;
627
628 status = pj_stun_msg_check(pkt->pkt, pkt->len, options);
629 if (status != PJ_SUCCESS) {
630 /* If the first byte are not STUN, drop the packet. First byte
631 * of STUN message is always 0x00 or 0x01. Otherwise wait for
632 * more data as the data might have come from TCP.
633 *
634 * Also drop packet if it's unreasonably too big, as this might
635 * indicate invalid data that's building up in the buffer.
636 *
637 * Or if packet is a datagram.
638 */
639 if ((*pkt->pkt != 0x00 && *pkt->pkt != 0x01) ||
640 pkt->len > 1600 ||
641 (options & PJ_STUN_IS_DATAGRAM))
642 {
643 char errmsg[PJ_ERR_MSG_SIZE];
644 char ip[PJ_INET6_ADDRSTRLEN+10];
645
646 pkt->len = 0;
647
648 pj_strerror(status, errmsg, sizeof(errmsg));
649 PJ_LOG(5,(srv->obj_name,
650 "Non-STUN packet from %s is dropped: %s",
651 pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
652 errmsg));
653 }
654 return;
655 }
656
657 /* Special handling for Binding Request. We won't give it to the
658 * STUN session since this request is not authenticated.
659 */
660 if (pkt->pkt[1] == 1) {
661 handle_binding_request(pkt, options);
662 return;
663 }
664
665 /* Hand over processing to STUN session. This will trigger
666 * on_rx_stun_request() callback to be called if the STUN
667 * message is a request.
668 */
669 options &= ~PJ_STUN_CHECK_PACKET;
670 parsed_len = 0;
671 status = pj_stun_session_on_rx_pkt(srv->core.stun_sess, pkt->pkt,
672 pkt->len, options, pkt->transport,
673 &parsed_len, &pkt->src.clt_addr,
674 pkt->src_addr_len);
675 if (status != PJ_SUCCESS) {
676 char errmsg[PJ_ERR_MSG_SIZE];
677 char ip[PJ_INET6_ADDRSTRLEN+10];
678
679 pj_strerror(status, errmsg, sizeof(errmsg));
680 PJ_LOG(5,(srv->obj_name,
681 "Error processing STUN packet from %s: %s",
682 pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
683 errmsg));
684 }
685
686 if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
687 pkt->len = 0;
688 } else if (parsed_len > 0) {
689 if (parsed_len == pkt->len) {
690 pkt->len = 0;
691 } else {
692 pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
693 pkt->len - parsed_len);
694 pkt->len -= parsed_len;
695 }
696 }
697 }
698}
699
700