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