blob: d1f66b8c7961493f3e10ef2b82bc5eba4058f4c9 [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
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 <pjsip/sip_endpoint.h>
21#include <pjsip/sip_transaction.h>
22#include <pjsip/sip_private.h>
23#include <pjsip/sip_event.h>
24#include <pjsip/sip_resolve.h>
25#include <pjsip/sip_module.h>
26#include <pjsip/sip_util.h>
27#include <pjsip/sip_errno.h>
28#include <pj/except.h>
29#include <pj/log.h>
30#include <pj/string.h>
31#include <pj/os.h>
32#include <pj/pool.h>
33#include <pj/hash.h>
34#include <pj/assert.h>
35#include <pj/errno.h>
36#include <pj/lock.h>
37
38#define PJSIP_EX_NO_MEMORY pj_NO_MEMORY_EXCEPTION()
39#define THIS_FILE "sip_endpoint.c"
40
41#define MAX_METHODS 32
42
43
44/* List of SIP endpoint exit callback. */
45typedef struct exit_cb
46{
47 PJ_DECL_LIST_MEMBER (struct exit_cb);
48 pjsip_endpt_exit_callback func;
49} exit_cb;
50
51
52/**
53 * The SIP endpoint.
54 */
55struct pjsip_endpoint
56{
57 /** Pool to allocate memory for the endpoint. */
58 pj_pool_t *pool;
59
60 /** Mutex for the pool, hash table, and event list/queue. */
61 pj_mutex_t *mutex;
62
63 /** Pool factory. */
64 pj_pool_factory *pf;
65
66 /** Name. */
67 pj_str_t name;
68
69 /** Timer heap. */
70 pj_timer_heap_t *timer_heap;
71
72 /** Transport manager. */
73 pjsip_tpmgr *transport_mgr;
74
75 /** Ioqueue. */
76 pj_ioqueue_t *ioqueue;
77
78 /** Last ioqueue err */
79 pj_status_t ioq_last_err;
80
81 /** DNS Resolver. */
82 pjsip_resolver_t *resolver;
83
84 /** Modules lock. */
85 pj_rwmutex_t *mod_mutex;
86
87 /** Modules. */
88 pjsip_module *modules[PJSIP_MAX_MODULE];
89
90 /** Module list, sorted by priority. */
91 pjsip_module module_list;
92
93 /** Capability header list. */
94 pjsip_hdr cap_hdr;
95
96 /** Additional request headers. */
97 pjsip_hdr req_hdr;
98
99 /** List of exit callback. */
100 exit_cb exit_cb_list;
101};
102
103
104#if defined(PJSIP_SAFE_MODULE) && PJSIP_SAFE_MODULE!=0
105# define LOCK_MODULE_ACCESS(ept) pj_rwmutex_lock_read(ept->mod_mutex)
106# define UNLOCK_MODULE_ACCESS(ept) pj_rwmutex_unlock_read(ept->mod_mutex)
107#else
108# define LOCK_MODULE_ACCESS(endpt)
109# define UNLOCK_MODULE_ACCESS(endpt)
110#endif
111
112
113
114/*
115 * Prototypes.
116 */
117static void endpt_on_rx_msg( pjsip_endpoint*,
118 pj_status_t, pjsip_rx_data*);
119static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt,
120 pjsip_tx_data *tdata );
121static pj_status_t unload_module(pjsip_endpoint *endpt,
122 pjsip_module *mod);
123
124/* Defined in sip_parser.c */
125void init_sip_parser(void);
126void deinit_sip_parser(void);
127
128/* Defined in sip_tel_uri.c */
129pj_status_t pjsip_tel_uri_subsys_init(void);
130
131
132/*
133 * This is the global handler for memory allocation failure, for pools that
134 * are created by the endpoint (by default, all pools ARE allocated by
135 * endpoint). The error is handled by throwing exception, and hopefully,
136 * the exception will be handled by the application (or this library).
137 */
138static void pool_callback( pj_pool_t *pool, pj_size_t size )
139{
140 PJ_UNUSED_ARG(pool);
141 PJ_UNUSED_ARG(size);
142
143 PJ_THROW(PJSIP_EX_NO_MEMORY);
144}
145
146
147/* Compare module name, used for searching module based on name. */
148static int cmp_mod_name(void *name, const void *mod)
149{
150 return pj_stricmp((const pj_str_t*)name, &((pjsip_module*)mod)->name);
151}
152
153/*
154 * Register new module to the endpoint.
155 * The endpoint will then call the load and start function in the module to
156 * properly initialize the module, and assign a unique module ID for the
157 * module.
158 */
159PJ_DEF(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,
160 pjsip_module *mod )
161{
162 pj_status_t status = PJ_SUCCESS;
163 pjsip_module *m;
164 unsigned i;
165
166 pj_rwmutex_lock_write(endpt->mod_mutex);
167
168 /* Make sure that this module has not been registered. */
169 PJ_ASSERT_ON_FAIL( pj_list_find_node(&endpt->module_list, mod) == NULL,
170 {status = PJ_EEXISTS; goto on_return;});
171
172 /* Make sure that no module with the same name has been registered. */
173 PJ_ASSERT_ON_FAIL( pj_list_search(&endpt->module_list, &mod->name,
174 &cmp_mod_name)==NULL,
175 {status = PJ_EEXISTS; goto on_return; });
176
177 /* Find unused ID for this module. */
178 for (i=0; i<PJ_ARRAY_SIZE(endpt->modules); ++i) {
179 if (endpt->modules[i] == NULL)
180 break;
181 }
182 if (i == PJ_ARRAY_SIZE(endpt->modules)) {
183 pj_assert(!"Too many modules registered!");
184 status = PJ_ETOOMANY;
185 goto on_return;
186 }
187
188 /* Assign the ID. */
189 mod->id = i;
190
191 /* Try to load the module. */
192 if (mod->load) {
193 status = (*mod->load)(endpt);
194 if (status != PJ_SUCCESS)
195 goto on_return;
196 }
197
198 /* Try to start the module. */
199 if (mod->start) {
200 status = (*mod->start)();
201 if (status != PJ_SUCCESS)
202 goto on_return;
203 }
204
205 /* Save the module. */
206 endpt->modules[i] = mod;
207
208 /* Put in the module list, sorted by priority. */
209 m = endpt->module_list.next;
210 while (m != &endpt->module_list) {
211 if (m->priority > mod->priority)
212 break;
213 m = m->next;
214 }
215 pj_list_insert_before(m, mod);
216
217 /* Done. */
218
219 PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" registered",
220 (int)mod->name.slen, mod->name.ptr));
221
222on_return:
223 pj_rwmutex_unlock_write(endpt->mod_mutex);
224 return status;
225}
226
227/*
228 * Unregister a module from the endpoint.
229 * The endpoint will then call the stop and unload function in the module to
230 * properly shutdown the module.
231 */
232PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
233 pjsip_module *mod )
234{
235 pj_status_t status;
236
237 pj_rwmutex_lock_write(endpt->mod_mutex);
238
239 /* Make sure the module exists in the list. */
240 PJ_ASSERT_ON_FAIL( pj_list_find_node(&endpt->module_list, mod) == mod,
241 {status = PJ_ENOTFOUND;goto on_return;} );
242
243 /* Make sure the module exists in the array. */
244 PJ_ASSERT_ON_FAIL( mod->id>=0 &&
245 mod->id<(int)PJ_ARRAY_SIZE(endpt->modules) &&
246 endpt->modules[mod->id] == mod,
247 {status = PJ_ENOTFOUND; goto on_return;});
248
249 /* Try to stop the module. */
250 if (mod->stop) {
251 status = (*mod->stop)();
252 if (status != PJ_SUCCESS) goto on_return;
253 }
254
255 /* Unload module */
256 status = unload_module(endpt, mod);
257
258on_return:
259 pj_rwmutex_unlock_write(endpt->mod_mutex);
260
261 if (status != PJ_SUCCESS) {
262 char errmsg[PJ_ERR_MSG_SIZE];
263
264 pj_strerror(status, errmsg, sizeof(errmsg));
265 PJ_LOG(3,(THIS_FILE, "Module \"%.*s\" can not be unregistered: %s",
266 (int)mod->name.slen, mod->name.ptr, errmsg));
267 }
268
269 return status;
270}
271
272static pj_status_t unload_module(pjsip_endpoint *endpt,
273 pjsip_module *mod)
274{
275 pj_status_t status;
276
277 /* Try to unload the module. */
278 if (mod->unload) {
279 status = (*mod->unload)();
280 if (status != PJ_SUCCESS)
281 return status;
282 }
283
284 /* Module MUST NOT set module ID to -1. */
285 pj_assert(mod->id >= 0);
286
287 /* Remove module from array. */
288 endpt->modules[mod->id] = NULL;
289
290 /* Remove module from list. */
291 pj_list_erase(mod);
292
293 /* Set module Id to -1. */
294 mod->id = -1;
295
296 /* Done. */
297 status = PJ_SUCCESS;
298
299 PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" unregistered",
300 (int)mod->name.slen, mod->name.ptr));
301
302 return status;
303}
304
305
306/*
307 * Get the value of the specified capability header field.
308 */
309PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
310 int htype,
311 const pj_str_t *hname)
312{
313 pjsip_hdr *hdr = endpt->cap_hdr.next;
314
315 /* Check arguments. */
316 PJ_ASSERT_RETURN(endpt != NULL, NULL);
317 PJ_ASSERT_RETURN(htype != PJSIP_H_OTHER || hname, NULL);
318
319 if (htype != PJSIP_H_OTHER) {
320 while (hdr != &endpt->cap_hdr) {
321 if (hdr->type == htype)
322 return hdr;
323 hdr = hdr->next;
324 }
325 }
326 return NULL;
327}
328
329
330/*
331 * Check if the specified capability is supported.
332 */
333PJ_DEF(pj_bool_t) pjsip_endpt_has_capability( pjsip_endpoint *endpt,
334 int htype,
335 const pj_str_t *hname,
336 const pj_str_t *token)
337{
338 const pjsip_generic_array_hdr *hdr;
339 unsigned i;
340
341 hdr = (const pjsip_generic_array_hdr*)
342 pjsip_endpt_get_capability(endpt, htype, hname);
343 if (!hdr)
344 return PJ_FALSE;
345
346 PJ_ASSERT_RETURN(token != NULL, PJ_FALSE);
347
348 for (i=0; i<hdr->count; ++i) {
349 if (!pj_stricmp(&hdr->values[i], token))
350 return PJ_TRUE;
351 }
352
353 return PJ_FALSE;
354}
355
356/*
357 * Add or register new capabilities as indicated by the tags to the
358 * appropriate header fields in the endpoint.
359 */
360PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
361 pjsip_module *mod,
362 int htype,
363 const pj_str_t *hname,
364 unsigned count,
365 const pj_str_t tags[])
366{
367 pjsip_generic_array_hdr *hdr;
368 unsigned i;
369
370 PJ_UNUSED_ARG(mod);
371
372 /* Check arguments. */
373 PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL);
374 PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT ||
375 htype==PJSIP_H_ALLOW ||
376 htype==PJSIP_H_SUPPORTED,
377 PJ_EINVAL);
378
379 /* Find the header. */
380 hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt,
381 htype, hname);
382
383 /* Create the header when it's not present */
384 if (hdr == NULL) {
385 switch (htype) {
386 case PJSIP_H_ACCEPT:
387 hdr = pjsip_accept_hdr_create(endpt->pool);
388 break;
389 case PJSIP_H_ALLOW:
390 hdr = pjsip_allow_hdr_create(endpt->pool);
391 break;
392 case PJSIP_H_SUPPORTED:
393 hdr = pjsip_supported_hdr_create(endpt->pool);
394 break;
395 default:
396 return PJ_EINVAL;
397 }
398
399 if (hdr) {
400 pj_list_push_back(&endpt->cap_hdr, hdr);
401 }
402 }
403
404 /* Add the tags to the header. */
405 for (i=0; i<count; ++i) {
406 pj_strdup(endpt->pool, &hdr->values[hdr->count], &tags[i]);
407 ++hdr->count;
408 }
409
410 /* Done. */
411 return PJ_SUCCESS;
412}
413
414/*
415 * Get additional headers to be put in outgoing request message.
416 */
417PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt)
418{
419 return &endpt->req_hdr;
420}
421
422
423/*
424 * Initialize endpoint.
425 */
426PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
427 const char *name,
428 pjsip_endpoint **p_endpt)
429{
430 pj_status_t status;
431 pj_pool_t *pool;
432 pjsip_endpoint *endpt;
433 pjsip_max_fwd_hdr *mf_hdr;
434 pj_lock_t *lock = NULL;
435
436
437 status = pj_register_strerror(PJSIP_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
438 &pjsip_strerror);
439 pj_assert(status == PJ_SUCCESS);
440
441 PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));
442
443 *p_endpt = NULL;
444
445 /* Create pool */
446 pool = pj_pool_create(pf, "pept%p",
447 PJSIP_POOL_LEN_ENDPT, PJSIP_POOL_INC_ENDPT,
448 &pool_callback);
449 if (!pool)
450 return PJ_ENOMEM;
451
452 /* Create endpoint. */
453 endpt = PJ_POOL_ZALLOC_T(pool, pjsip_endpoint);
454 endpt->pool = pool;
455 endpt->pf = pf;
456
457 /* Init modules list. */
458 pj_list_init(&endpt->module_list);
459
460 /* Initialize exit callback list. */
461 pj_list_init(&endpt->exit_cb_list);
462
463 /* Create R/W mutex for module manipulation. */
464 status = pj_rwmutex_create(endpt->pool, "ept%p", &endpt->mod_mutex);
465 if (status != PJ_SUCCESS)
466 goto on_error;
467
468 /* Init parser. */
469 init_sip_parser();
470
471 /* Init tel: uri */
472 pjsip_tel_uri_subsys_init();
473
474 /* Get name. */
475 if (name != NULL) {
476 pj_str_t temp;
477 pj_strdup_with_null(endpt->pool, &endpt->name, pj_cstr(&temp, name));
478 } else {
479 pj_strdup_with_null(endpt->pool, &endpt->name, pj_gethostname());
480 }
481
482 /* Create mutex for the events, etc. */
483 status = pj_mutex_create_recursive( endpt->pool, "ept%p", &endpt->mutex );
484 if (status != PJ_SUCCESS) {
485 goto on_error;
486 }
487
488 /* Create timer heap to manage all timers within this endpoint. */
489 status = pj_timer_heap_create( endpt->pool, PJSIP_MAX_TIMER_COUNT,
490 &endpt->timer_heap);
491 if (status != PJ_SUCCESS) {
492 goto on_error;
493 }
494
495 /* Set recursive lock for the timer heap. */
496 status = pj_lock_create_recursive_mutex( endpt->pool, "edpt%p", &lock);
497 if (status != PJ_SUCCESS) {
498 goto on_error;
499 }
500 pj_timer_heap_set_lock(endpt->timer_heap, lock, PJ_TRUE);
501
502 /* Set maximum timed out entries to process in a single poll. */
503 pj_timer_heap_set_max_timed_out_per_poll(endpt->timer_heap,
504 PJSIP_MAX_TIMED_OUT_ENTRIES);
505
506 /* Create ioqueue. */
507 status = pj_ioqueue_create( endpt->pool, PJSIP_MAX_TRANSPORTS, &endpt->ioqueue);
508 if (status != PJ_SUCCESS) {
509 goto on_error;
510 }
511
512 /* Create transport manager. */
513 status = pjsip_tpmgr_create( endpt->pool, endpt,
514 &endpt_on_rx_msg,
515 &endpt_on_tx_msg,
516 &endpt->transport_mgr);
517 if (status != PJ_SUCCESS) {
518 goto on_error;
519 }
520
521 /* Create asynchronous DNS resolver. */
522 status = pjsip_resolver_create(endpt->pool, &endpt->resolver);
523 if (status != PJ_SUCCESS) {
524 PJ_LOG(4, (THIS_FILE, "Error creating resolver instance"));
525 goto on_error;
526 }
527
528 /* Initialize request headers. */
529 pj_list_init(&endpt->req_hdr);
530
531 /* Add "Max-Forwards" for request header. */
532 mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,
533 PJSIP_MAX_FORWARDS_VALUE);
534 pj_list_insert_before( &endpt->req_hdr, mf_hdr);
535
536 /* Initialize capability header list. */
537 pj_list_init(&endpt->cap_hdr);
538
539
540 /* Done. */
541 *p_endpt = endpt;
542 return status;
543
544on_error:
545 if (endpt->transport_mgr) {
546 pjsip_tpmgr_destroy(endpt->transport_mgr);
547 endpt->transport_mgr = NULL;
548 }
549 if (endpt->ioqueue) {
550 pj_ioqueue_destroy(endpt->ioqueue);
551 endpt->ioqueue = NULL;
552 }
553 if (endpt->timer_heap) {
554 pj_timer_heap_destroy(endpt->timer_heap);
555 endpt->timer_heap = NULL;
556 }
557 if (endpt->mutex) {
558 pj_mutex_destroy(endpt->mutex);
559 endpt->mutex = NULL;
560 }
561 deinit_sip_parser();
562 if (endpt->mod_mutex) {
563 pj_rwmutex_destroy(endpt->mod_mutex);
564 endpt->mod_mutex = NULL;
565 }
566 pj_pool_release( endpt->pool );
567
568 PJ_LOG(4, (THIS_FILE, "Error creating endpoint"));
569 return status;
570}
571
572/*
573 * Destroy endpoint.
574 */
575PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
576{
577 pjsip_module *mod;
578 exit_cb *ecb;
579
580 PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance.."));
581
582 /* Phase 1: stop all modules */
583 mod = endpt->module_list.prev;
584 while (mod != &endpt->module_list) {
585 pjsip_module *prev = mod->prev;
586 if (mod->stop) {
587 (*mod->stop)();
588 }
589 mod = prev;
590 }
591
592 /* Phase 2: unload modules. */
593 mod = endpt->module_list.prev;
594 while (mod != &endpt->module_list) {
595 pjsip_module *prev = mod->prev;
596 unload_module(endpt, mod);
597 mod = prev;
598 }
599
600 /* Destroy resolver */
601 pjsip_resolver_destroy(endpt->resolver);
602
603 /* Shutdown and destroy all transports. */
604 pjsip_tpmgr_destroy(endpt->transport_mgr);
605
606 /* Destroy ioqueue */
607 pj_ioqueue_destroy(endpt->ioqueue);
608
609 /* Destroy timer heap */
610#if PJ_TIMER_DEBUG
611 pj_timer_heap_dump(endpt->timer_heap);
612#endif
613 pj_timer_heap_destroy(endpt->timer_heap);
614
615 /* Call all registered exit callbacks */
616 ecb = endpt->exit_cb_list.next;
617 while (ecb != &endpt->exit_cb_list) {
618 (*ecb->func)(endpt);
619 ecb = ecb->next;
620 }
621
622 /* Delete endpoint mutex. */
623 pj_mutex_destroy(endpt->mutex);
624
625 /* Deinit parser */
626 deinit_sip_parser();
627
628 /* Delete module's mutex */
629 pj_rwmutex_destroy(endpt->mod_mutex);
630
631 /* Finally destroy pool. */
632 pj_pool_release(endpt->pool);
633
634 PJ_LOG(4, (THIS_FILE, "Endpoint %p destroyed", endpt));
635}
636
637/*
638 * Get endpoint name.
639 */
640PJ_DEF(const pj_str_t*) pjsip_endpt_name(const pjsip_endpoint *endpt)
641{
642 return &endpt->name;
643}
644
645
646/*
647 * Create new pool.
648 */
649PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,
650 const char *pool_name,
651 pj_size_t initial,
652 pj_size_t increment )
653{
654 pj_pool_t *pool;
655
656 /* Lock endpoint mutex. */
657 /* No need to lock mutex. Factory is thread safe.
658 pj_mutex_lock(endpt->mutex);
659 */
660
661 /* Create pool */
662 pool = pj_pool_create( endpt->pf, pool_name,
663 initial, increment, &pool_callback);
664
665 /* Unlock mutex. */
666 /* No need to lock mutex. Factory is thread safe.
667 pj_mutex_unlock(endpt->mutex);
668 */
669
670 if (!pool) {
671 PJ_LOG(4, (THIS_FILE, "Unable to create pool %s!", pool_name));
672 }
673
674 return pool;
675}
676
677/*
678 * Return back pool to endpoint's pool manager to be either destroyed or
679 * recycled.
680 */
681PJ_DEF(void) pjsip_endpt_release_pool( pjsip_endpoint *endpt, pj_pool_t *pool )
682{
683 PJ_LOG(6, (THIS_FILE, "Releasing pool %s", pj_pool_getobjname(pool)));
684
685 /* Don't need to acquire mutex since pool factory is thread safe
686 pj_mutex_lock(endpt->mutex);
687 */
688 pj_pool_release( pool );
689
690 PJ_UNUSED_ARG(endpt);
691 /*
692 pj_mutex_unlock(endpt->mutex);
693 */
694}
695
696
697PJ_DEF(pj_status_t) pjsip_endpt_handle_events2(pjsip_endpoint *endpt,
698 const pj_time_val *max_timeout,
699 unsigned *p_count)
700{
701 /* timeout is 'out' var. This just to make compiler happy. */
702 pj_time_val timeout = { 0, 0};
703 unsigned count = 0, net_event_count = 0;
704 int c;
705
706 PJ_LOG(6, (THIS_FILE, "pjsip_endpt_handle_events()"));
707
708 /* Poll the timer. The timer heap has its own mutex for better
709 * granularity, so we don't need to lock end endpoint.
710 */
711 timeout.sec = timeout.msec = 0;
712 c = pj_timer_heap_poll( endpt->timer_heap, &timeout );
713 if (c > 0)
714 count += c;
715
716 /* timer_heap_poll should never ever returns negative value, or otherwise
717 * ioqueue_poll() will block forever!
718 */
719 pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
720 if (timeout.msec >= 1000) timeout.msec = 999;
721
722 /* If caller specifies maximum time to wait, then compare the value with
723 * the timeout to wait from timer, and use the minimum value.
724 */
725 if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
726 timeout = *max_timeout;
727 }
728
729 /* Poll ioqueue.
730 * Repeat polling the ioqueue while we have immediate events, because
731 * timer heap may process more than one events, so if we only process
732 * one network events at a time (such as when IOCP backend is used),
733 * the ioqueue may have trouble keeping up with the request rate.
734 *
735 * For example, for each send() request, one network event will be
736 * reported by ioqueue for the send() completion. If we don't poll
737 * the ioqueue often enough, the send() completion will not be
738 * reported in timely manner.
739 */
740 do {
741 c = pj_ioqueue_poll( endpt->ioqueue, &timeout);
742 if (c < 0) {
743 pj_status_t err = pj_get_netos_error();
744 pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
745 if (p_count)
746 *p_count = count;
747 return err;
748 } else if (c == 0) {
749 break;
750 } else {
751 net_event_count += c;
752 timeout.sec = timeout.msec = 0;
753 }
754 } while (c > 0 && net_event_count < PJSIP_MAX_NET_EVENTS);
755
756 count += net_event_count;
757 if (p_count)
758 *p_count = count;
759
760 return PJ_SUCCESS;
761}
762
763/*
764 * Handle events.
765 */
766PJ_DEF(pj_status_t) pjsip_endpt_handle_events(pjsip_endpoint *endpt,
767 const pj_time_val *max_timeout)
768{
769 return pjsip_endpt_handle_events2(endpt, max_timeout, NULL);
770}
771
772/*
773 * Schedule timer.
774 */
775#if PJ_TIMER_DEBUG
776PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_dbg(pjsip_endpoint *endpt,
777 pj_timer_entry *entry,
778 const pj_time_val *delay,
779 const char *src_file,
780 int src_line)
781{
782 PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)",
783 entry, delay->sec, delay->msec));
784 return pj_timer_heap_schedule_dbg(endpt->timer_heap, entry, delay,
785 src_file, src_line);
786}
787#else
788PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,
789 pj_timer_entry *entry,
790 const pj_time_val *delay )
791{
792 PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)",
793 entry, delay->sec, delay->msec));
794 return pj_timer_heap_schedule( endpt->timer_heap, entry, delay );
795}
796#endif
797
798/*
799 * Cancel the previously registered timer.
800 */
801PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt,
802 pj_timer_entry *entry )
803{
804 PJ_LOG(6, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry));
805 pj_timer_heap_cancel( endpt->timer_heap, entry );
806}
807
808/*
809 * Get the timer heap instance of the SIP endpoint.
810 */
811PJ_DEF(pj_timer_heap_t*) pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt)
812{
813 return endpt->timer_heap;
814}
815
816/* Init with default */
817PJ_DEF(void) pjsip_process_rdata_param_default(pjsip_process_rdata_param *p)
818{
819 pj_bzero(p, sizeof(*p));
820}
821
822/* Distribute rdata */
823PJ_DEF(pj_status_t) pjsip_endpt_process_rx_data( pjsip_endpoint *endpt,
824 pjsip_rx_data *rdata,
825 pjsip_process_rdata_param *p,
826 pj_bool_t *p_handled)
827{
828 pjsip_msg *msg;
829 pjsip_process_rdata_param def_prm;
830 pjsip_module *mod;
831 pj_bool_t handled = PJ_FALSE;
832 unsigned i;
833 pj_status_t status;
834
835 PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
836
837 if (p==NULL) {
838 p = &def_prm;
839 pjsip_process_rdata_param_default(p);
840 }
841
842 msg = rdata->msg_info.msg;
843
844 if (p_handled)
845 *p_handled = PJ_FALSE;
846
847 if (!p->silent) {
848 PJ_LOG(5, (THIS_FILE, "Distributing rdata to modules: %s",
849 pjsip_rx_data_get_info(rdata)));
850 pj_log_push_indent();
851 }
852
853 LOCK_MODULE_ACCESS(endpt);
854
855 /* Find start module */
856 if (p->start_mod) {
857 mod = (pjsip_module*)
858 pj_list_find_node(&endpt->module_list, p->start_mod);
859 if (!mod) {
860 status = PJ_ENOTFOUND;
861 goto on_return;
862 }
863 } else {
864 mod = endpt->module_list.next;
865 }
866
867 /* Start after the specified index */
868 for (i=0; i < p->idx_after_start && mod != &endpt->module_list; ++i) {
869 mod = mod->next;
870 }
871
872 /* Start with the specified priority */
873 while (mod != &endpt->module_list && mod->priority < (int)p->start_prio) {
874 mod = mod->next;
875 }
876
877 if (mod == &endpt->module_list) {
878 status = PJ_ENOTFOUND;
879 goto on_return;
880 }
881
882 /* Distribute */
883 if (msg->type == PJSIP_REQUEST_MSG) {
884 do {
885 if (mod->on_rx_request)
886 handled = (*mod->on_rx_request)(rdata);
887 if (handled)
888 break;
889 mod = mod->next;
890 } while (mod != &endpt->module_list);
891 } else {
892 do {
893 if (mod->on_rx_response)
894 handled = (*mod->on_rx_response)(rdata);
895 if (handled)
896 break;
897 mod = mod->next;
898 } while (mod != &endpt->module_list);
899 }
900
901 status = PJ_SUCCESS;
902
903on_return:
904 if (p_handled)
905 *p_handled = handled;
906
907 UNLOCK_MODULE_ACCESS(endpt);
908 if (!p->silent) {
909 pj_log_pop_indent();
910 }
911 return status;
912}
913
914/*
915 * This is the callback that is called by the transport manager when it
916 * receives a message from the network.
917 */
918static void endpt_on_rx_msg( pjsip_endpoint *endpt,
919 pj_status_t status,
920 pjsip_rx_data *rdata )
921{
922 pjsip_msg *msg = rdata->msg_info.msg;
923 pjsip_process_rdata_param proc_prm;
924 pj_bool_t handled = PJ_FALSE;
925
926 PJ_UNUSED_ARG(msg);
927
928 if (status != PJ_SUCCESS) {
929 char info[30];
930 char errmsg[PJ_ERR_MSG_SIZE];
931
932 info[0] = '\0';
933
934 if (status == PJSIP_EMISSINGHDR) {
935 pj_str_t p;
936
937 p.ptr = info; p.slen = 0;
938
939 if (rdata->msg_info.cid == NULL || rdata->msg_info.cid->id.slen)
940 pj_strcpy2(&p, "Call-ID");
941 if (rdata->msg_info.from == NULL)
942 pj_strcpy2(&p, " From");
943 if (rdata->msg_info.to == NULL)
944 pj_strcpy2(&p, " To");
945 if (rdata->msg_info.via == NULL)
946 pj_strcpy2(&p, " Via");
947 if (rdata->msg_info.cseq == NULL)
948 pj_strcpy2(&p, " CSeq");
949
950 p.ptr[p.slen] = '\0';
951 }
952
953 pj_strerror(status, errmsg, sizeof(errmsg));
954
955 PJ_LOG(1, (THIS_FILE,
956 "Error processing packet from %s:%d: %s %s [code %d]:\n"
957 "%.*s\n"
958 "-- end of packet.",
959 rdata->pkt_info.src_name,
960 rdata->pkt_info.src_port,
961 errmsg,
962 info,
963 status,
964 (int)rdata->msg_info.len,
965 rdata->msg_info.msg_buf));
966 return;
967 }
968
969 PJ_LOG(5, (THIS_FILE, "Processing incoming message: %s",
970 pjsip_rx_data_get_info(rdata)));
971 pj_log_push_indent();
972
973#if defined(PJSIP_CHECK_VIA_SENT_BY) && PJSIP_CHECK_VIA_SENT_BY != 0
974 /* For response, check that the value in Via sent-by match the transport.
975 * If not matched, silently drop the response.
976 * Ref: RFC3261 Section 18.1.2 Receiving Response
977 */
978 if (msg->type == PJSIP_RESPONSE_MSG) {
979 const pj_str_t *local_addr;
980 int port = rdata->msg_info.via->sent_by.port;
981 pj_bool_t mismatch = PJ_FALSE;
982 if (port == 0) {
983 pjsip_transport_type_e type;
984 type = (pjsip_transport_type_e)rdata->tp_info.transport->key.type;
985 port = pjsip_transport_get_default_port_for_type(type);
986 }
987 local_addr = &rdata->tp_info.transport->local_name.host;
988
989 if (pj_strcmp(&rdata->msg_info.via->sent_by.host, local_addr) != 0) {
990
991 /* The RFC says that we should drop response when sent-by
992 * address mismatch. But it could happen (e.g. with SER) when
993 * endpoint with private IP is sending request to public
994 * server.
995
996 mismatch = PJ_TRUE;
997
998 */
999
1000 } else if (port != rdata->tp_info.transport->local_name.port) {
1001 /* Port or address mismatch, we should discard response */
1002 /* But we saw one implementation (we don't want to name it to
1003 * protect the innocence) which put wrong sent-by port although
1004 * the "rport" parameter is correct.
1005 * So we discard the response only if the port doesn't match
1006 * both the port in sent-by and rport. We try to be lenient here!
1007 */
1008 if (rdata->msg_info.via->rport_param !=
1009 rdata->tp_info.transport->local_name.port)
1010 mismatch = PJ_TRUE;
1011 else {
1012 PJ_LOG(4,(THIS_FILE, "Message %s from %s has mismatch port in "
1013 "sent-by but the rport parameter is "
1014 "correct",
1015 pjsip_rx_data_get_info(rdata),
1016 rdata->pkt_info.src_name));
1017 }
1018 }
1019
1020 if (mismatch) {
1021 PJ_TODO(ENDPT_REPORT_WHEN_DROPPING_MESSAGE);
1022 PJ_LOG(4,(THIS_FILE, "Dropping response %s from %s:%d because "
1023 "sent-by is mismatch",
1024 pjsip_rx_data_get_info(rdata),
1025 rdata->pkt_info.src_name,
1026 rdata->pkt_info.src_port));
1027 pj_log_pop_indent();
1028 return;
1029 }
1030 }
1031#endif
1032
1033 pjsip_process_rdata_param_default(&proc_prm);
1034 proc_prm.silent = PJ_TRUE;
1035
1036 pjsip_endpt_process_rx_data(endpt, rdata, &proc_prm, &handled);
1037
1038 /* No module is able to handle the message */
1039 if (!handled) {
1040 PJ_LOG(4,(THIS_FILE, "%s from %s:%d was dropped/unhandled by"
1041 " any modules",
1042 pjsip_rx_data_get_info(rdata),
1043 rdata->pkt_info.src_name,
1044 rdata->pkt_info.src_port));
1045 }
1046
1047 /* Must clear mod_data before returning rdata to transport, since
1048 * rdata may be reused.
1049 */
1050 pj_bzero(&rdata->endpt_info, sizeof(rdata->endpt_info));
1051
1052 pj_log_pop_indent();
1053}
1054
1055/*
1056 * This callback is called by transport manager before message is sent.
1057 * Modules may inspect the message before it's actually sent.
1058 */
1059static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt,
1060 pjsip_tx_data *tdata )
1061{
1062 pj_status_t status = PJ_SUCCESS;
1063 pjsip_module *mod;
1064
1065 /* Distribute to modules, starting from modules with LOWEST priority */
1066 LOCK_MODULE_ACCESS(endpt);
1067
1068 mod = endpt->module_list.prev;
1069 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
1070 while (mod != &endpt->module_list) {
1071 if (mod->on_tx_request)
1072 status = (*mod->on_tx_request)(tdata);
1073 if (status != PJ_SUCCESS)
1074 break;
1075 mod = mod->prev;
1076 }
1077
1078 } else {
1079 while (mod != &endpt->module_list) {
1080 if (mod->on_tx_response)
1081 status = (*mod->on_tx_response)(tdata);
1082 if (status != PJ_SUCCESS)
1083 break;
1084 mod = mod->prev;
1085 }
1086 }
1087
1088 UNLOCK_MODULE_ACCESS(endpt);
1089
1090 return status;
1091}
1092
1093
1094/*
1095 * Create transmit data buffer.
1096 */
1097PJ_DEF(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt,
1098 pjsip_tx_data **p_tdata)
1099{
1100 return pjsip_tx_data_create(endpt->transport_mgr, p_tdata);
1101}
1102
1103/*
1104 * Create the DNS resolver instance.
1105 */
1106PJ_DEF(pj_status_t) pjsip_endpt_create_resolver(pjsip_endpoint *endpt,
1107 pj_dns_resolver **p_resv)
1108{
1109#if PJSIP_HAS_RESOLVER
1110 PJ_ASSERT_RETURN(endpt && p_resv, PJ_EINVAL);
1111 return pj_dns_resolver_create( endpt->pf, NULL, 0, endpt->timer_heap,
1112 endpt->ioqueue, p_resv);
1113#else
1114 PJ_UNUSED_ARG(endpt);
1115 PJ_UNUSED_ARG(p_resv);
1116 pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");
1117 return PJ_EINVALIDOP;
1118#endif
1119}
1120
1121/*
1122 * Set DNS resolver to be used by the SIP resolver.
1123 */
1124PJ_DEF(pj_status_t) pjsip_endpt_set_resolver( pjsip_endpoint *endpt,
1125 pj_dns_resolver *resv)
1126{
1127 return pjsip_resolver_set_resolver(endpt->resolver, resv);
1128}
1129
1130/*
1131 * Get the DNS resolver being used by the SIP resolver.
1132 */
1133PJ_DEF(pj_dns_resolver*) pjsip_endpt_get_resolver(pjsip_endpoint *endpt)
1134{
1135 PJ_ASSERT_RETURN(endpt, NULL);
1136 return pjsip_resolver_get_resolver(endpt->resolver);
1137}
1138
1139/*
1140 * Resolve
1141 */
1142PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
1143 pj_pool_t *pool,
1144 pjsip_host_info *target,
1145 void *token,
1146 pjsip_resolver_callback *cb)
1147{
1148 pjsip_resolve( endpt->resolver, pool, target, token, cb);
1149}
1150
1151/*
1152 * Get transport manager.
1153 */
1154PJ_DEF(pjsip_tpmgr*) pjsip_endpt_get_tpmgr(pjsip_endpoint *endpt)
1155{
1156 return endpt->transport_mgr;
1157}
1158
1159/*
1160 * Get ioqueue instance.
1161 */
1162PJ_DEF(pj_ioqueue_t*) pjsip_endpt_get_ioqueue(pjsip_endpoint *endpt)
1163{
1164 return endpt->ioqueue;
1165}
1166
1167/*
1168 * Find/create transport.
1169 */
1170PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport(pjsip_endpoint *endpt,
1171 pjsip_transport_type_e type,
1172 const pj_sockaddr_t *remote,
1173 int addr_len,
1174 const pjsip_tpselector *sel,
1175 pjsip_transport **transport)
1176{
1177 return pjsip_tpmgr_acquire_transport(endpt->transport_mgr, type,
1178 remote, addr_len, sel, transport);
1179}
1180
1181
1182/*
1183 * Find/create transport.
1184 */
1185PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport2(pjsip_endpoint *endpt,
1186 pjsip_transport_type_e type,
1187 const pj_sockaddr_t *remote,
1188 int addr_len,
1189 const pjsip_tpselector *sel,
1190 pjsip_tx_data *tdata,
1191 pjsip_transport **transport)
1192{
1193 return pjsip_tpmgr_acquire_transport2(endpt->transport_mgr, type, remote,
1194 addr_len, sel, tdata, transport);
1195}
1196
1197
1198/*
1199 * Report error.
1200 */
1201PJ_DEF(void) pjsip_endpt_log_error( pjsip_endpoint *endpt,
1202 const char *sender,
1203 pj_status_t error_code,
1204 const char *format,
1205 ... )
1206{
1207#if PJ_LOG_MAX_LEVEL > 0
1208 char newformat[256];
1209 pj_size_t len;
1210 va_list marker;
1211
1212 va_start(marker, format);
1213
1214 PJ_UNUSED_ARG(endpt);
1215
1216 len = pj_ansi_strlen(format);
1217 if (len < (int)sizeof(newformat)-30) {
1218 pj_str_t errstr;
1219
1220 pj_ansi_strcpy(newformat, format);
1221 pj_ansi_snprintf(newformat+len, sizeof(newformat)-len-1,
1222 ": [err %d] ", error_code);
1223 len += pj_ansi_strlen(newformat+len);
1224
1225 errstr = pj_strerror( error_code, newformat+len,
1226 sizeof(newformat)-len-1);
1227
1228 len += errstr.slen;
1229 newformat[len] = '\0';
1230
1231 pj_log(sender, 1, newformat, marker);
1232 } else {
1233 pj_log(sender, 1, format, marker);
1234 }
1235
1236 va_end(marker);
1237#else
1238 PJ_UNUSED_ARG(format);
1239 PJ_UNUSED_ARG(error_code);
1240 PJ_UNUSED_ARG(sender);
1241 PJ_UNUSED_ARG(endpt);
1242#endif
1243}
1244
1245
1246/*
1247 * Dump endpoint.
1248 */
1249PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
1250{
1251#if PJ_LOG_MAX_LEVEL >= 3
1252 PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()"));
1253
1254 /* Lock mutex. */
1255 pj_mutex_lock(endpt->mutex);
1256
1257 PJ_LOG(3, (THIS_FILE, "Dumping endpoint %p:", endpt));
1258
1259 /* Dumping pool factory. */
1260 pj_pool_factory_dump(endpt->pf, detail);
1261
1262 /* Pool health. */
1263 PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%u, used_size=%u",
1264 pj_pool_get_capacity(endpt->pool),
1265 pj_pool_get_used_size(endpt->pool)));
1266
1267 /* Resolver */
1268#if PJSIP_HAS_RESOLVER
1269 if (pjsip_endpt_get_resolver(endpt)) {
1270 pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), detail);
1271 }
1272#endif
1273
1274 /* Transports.
1275 */
1276 pjsip_tpmgr_dump_transports( endpt->transport_mgr );
1277
1278 /* Timer. */
1279#if PJ_TIMER_DEBUG
1280 pj_timer_heap_dump(endpt->timer_heap);
1281#else
1282 PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries",
1283 pj_timer_heap_count(endpt->timer_heap)));
1284#endif
1285
1286 /* Unlock mutex. */
1287 pj_mutex_unlock(endpt->mutex);
1288#else
1289 PJ_UNUSED_ARG(endpt);
1290 PJ_UNUSED_ARG(detail);
1291 PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled."));
1292#endif
1293}
1294
1295
1296PJ_DEF(pj_status_t) pjsip_endpt_atexit( pjsip_endpoint *endpt,
1297 pjsip_endpt_exit_callback func)
1298{
1299 exit_cb *new_cb;
1300
1301 PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
1302
1303 new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
1304 new_cb->func = func;
1305
1306 pj_mutex_lock(endpt->mutex);
1307 pj_list_push_back(&endpt->exit_cb_list, new_cb);
1308 pj_mutex_unlock(endpt->mutex);
1309
1310 return PJ_SUCCESS;
1311}