Пример #1
0
static pj_status_t init_stack()
{
    pj_sockaddr addr;
    pjsip_inv_callback inv_cb;
    pj_status_t status;

    pj_log_set_level(5);

    status = pj_init();
    CHECK_STATUS();

    pj_log_set_level(3);

    status = pjlib_util_init();
    CHECK_STATUS();

    pj_caching_pool_init(&app.cp, NULL, 0);
    app.pool = pj_pool_create( &app.cp.factory, "sipecho", 512, 512, 0);

    status = pjsip_endpt_create(&app.cp.factory, NULL, &app.sip_endpt);
    CHECK_STATUS();

    pj_log_set_level(4);
    pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
    if (AF == pj_AF_INET()) {
	status = pjsip_udp_transport_start( app.sip_endpt, &addr.ipv4, NULL,
					    1, NULL);
    } else if (AF == pj_AF_INET6()) {
	status = pjsip_udp_transport_start6(app.sip_endpt, &addr.ipv6, NULL,
					    1, NULL);
    } else {
	status = PJ_EAFNOTSUP;
    }

    pj_log_set_level(3);
    CHECK_STATUS();

    status = pjsip_tsx_layer_init_module(app.sip_endpt) ||
	     pjsip_ua_init_module( app.sip_endpt, NULL );
    CHECK_STATUS();

    pj_bzero(&inv_cb, sizeof(inv_cb));
    inv_cb.on_state_changed = &call_on_state_changed;
    inv_cb.on_new_session = &call_on_forked;
    inv_cb.on_media_update = &call_on_media_update;
    inv_cb.on_rx_offer = &call_on_rx_offer;

    status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb) ||
	     pjsip_100rel_init_module(app.sip_endpt) ||
	     pjsip_endpt_register_module( app.sip_endpt, &mod_sipecho) ||
	     pjsip_endpt_register_module( app.sip_endpt, &msg_logger) ||
	     //pjmedia_endpt_create(&app.cp.factory,
		//		  pjsip_endpt_get_ioqueue(app.sip_endpt),
		//		  0, &app.med_endpt) ||
             pj_thread_create(app.pool, "sipecho", &worker_proc, NULL, 0, 0,
                              &app.worker_thread);
    CHECK_STATUS();

    return PJ_SUCCESS;
}
Пример #2
0
int inv_offer_answer_test(void)
{
    unsigned i;
    int rc = 0;

    /* Init UA layer */
    if (pjsip_ua_instance()->id == -1) {
	pjsip_ua_init_param ua_param;
	pj_bzero(&ua_param, sizeof(ua_param));
	ua_param.on_dlg_forked = &on_dlg_forked;
	pjsip_ua_init_module(endpt, &ua_param);
    }

    /* Init inv-usage */
    if (pjsip_inv_usage_instance()->id == -1) {
	pjsip_inv_callback inv_cb;
	pj_bzero(&inv_cb, sizeof(inv_cb));
	inv_cb.on_media_update = &on_media_update;
	inv_cb.on_rx_offer = &on_rx_offer;
	inv_cb.on_create_offer = &on_create_offer;
	inv_cb.on_state_changed = &on_state_changed;
	inv_cb.on_new_session = &on_new_session;
	pjsip_inv_usage_init(endpt, &inv_cb);
    }

    /* 100rel module */
    pjsip_100rel_init_module(endpt);

    /* Our module */
    pjsip_endpt_register_module(endpt, &mod_inv_oa_test);
    pjsip_endpt_register_module(endpt, &mod_msg_logger);

    /* Create SIP UDP transport */
    {
	pj_sockaddr_in addr;
	pjsip_transport *tp;
	pj_status_t status;

	pj_sockaddr_in_init(&addr, NULL, PORT);
	status = pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp);
	pj_assert(status == PJ_SUCCESS);
    }

    /* Do tests */
    for (i=0; i<PJ_ARRAY_SIZE(test_params); ++i) {
	rc = perform_test(&test_params[i]);
	if (rc != 0)
	    goto on_return;
    }


on_return:
    return rc;
}
static pj_status_t init_stateful_proxy(void)
{
    pj_status_t status;

    status = pjsip_endpt_register_module( global.endpt, &mod_stateful_proxy);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    status = pjsip_endpt_register_module( global.endpt, &mod_tu);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    return PJ_SUCCESS;
}
Пример #4
0
pj_status_t init_authentication(const std::string& realm_name,
                                AvStore* avstore,
                                HSSConnection* hss_connection,
                                ChronosConnection* chronos_connection,
                                ACRFactory* rfacr_factory,
                                AnalyticsLogger* analytics_logger)
{
  pj_status_t status;

  aka_realm = (realm_name != "") ? pj_strdup3(stack_data.pool, realm_name.c_str()) : stack_data.local_host;
  av_store = avstore;
  hss = hss_connection;
  chronos = chronos_connection;
  acr_factory = rfacr_factory;
  analytics = analytics_logger;

  // Register the authentication module.  This needs to be in the stack
  // before the transaction layer.
  status = pjsip_endpt_register_module(stack_data.endpt, &mod_auth);

  // Initialize the authorization server.
  pjsip_auth_srv_init_param params;
  params.realm = &WILDCARD_REALM;
  params.lookup3 = user_lookup;
  params.options = 0;
  status = pjsip_auth_srv_init2(stack_data.pool, &auth_srv, &params);

  return status;
}
Пример #5
0
static pj_status_t init_stateless_proxy(void)
{
    static pjsip_module mod_stateless_proxy =
    {
	NULL, NULL,			    /* prev, next.	*/
	{ "mod-stateless-proxy", 19 },	    /* Name.		*/
	-1,				    /* Id		*/
	PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,  /* Priority		*/
	NULL,				    /* load()		*/
	NULL,				    /* start()		*/
	NULL,				    /* stop()		*/
	NULL,				    /* unload()		*/
	&on_rx_request,			    /* on_rx_request()	*/
	&on_rx_response,		    /* on_rx_response()	*/
	NULL,				    /* on_tx_request.	*/
	NULL,				    /* on_tx_response()	*/
	NULL,				    /* on_tsx_state()	*/
    };

    pj_status_t status;

    /* Register our module to receive incoming requests. */
    status = pjsip_endpt_register_module( global.endpt, &mod_stateless_proxy);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    return PJ_SUCCESS;
}
Пример #6
0
/*
 * Init pjsua IM module.
 */
pj_status_t pjsua_im_init(void)
{
    const pj_str_t msg_tag = { "MESSAGE", 7 };
    const pj_str_t STR_MIME_TEXT_PLAIN = { "text/plain", 10 };
    const pj_str_t STR_MIME_APP_ISCOMPOSING = 
		    { "application/im-iscomposing+xml", 30 };
    pj_status_t status;

    /* Register module */
    status = pjsip_endpt_register_module(pjsua_var.endpt, &mod_pjsua_im);
    if (status != PJ_SUCCESS)
	return status;

    /* Register support for MESSAGE method. */
    pjsip_endpt_add_capability( pjsua_var.endpt, &mod_pjsua_im, PJSIP_H_ALLOW,
				NULL, 1, &msg_tag);

    /* Register support for "application/im-iscomposing+xml" content */
    pjsip_endpt_add_capability( pjsua_var.endpt, &mod_pjsua_im, PJSIP_H_ACCEPT,
				NULL, 1, &STR_MIME_APP_ISCOMPOSING);

    /* Register support for "text/plain" content */
    pjsip_endpt_add_capability( pjsua_var.endpt, &mod_pjsua_im, PJSIP_H_ACCEPT,
				NULL, 1, &STR_MIME_TEXT_PLAIN);

    return PJ_SUCCESS;
}
Пример #7
0
/*
 * init module
 */
PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
{
    if (mod_100rel.mod.id != -1)
	return PJ_SUCCESS;

    return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
}
Пример #8
0
/*
 * Initialize the REFER subsystem.
 */
PJ_DEF(pj_status_t) pjsip_xfer_init_module(pjsip_endpoint *endpt)
{
    const pj_str_t accept = { "message/sipfrag;version=2.0", 27 };
    pj_status_t status;

    PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
    PJ_ASSERT_RETURN(mod_xfer.id == -1, PJ_EINVALIDOP);

    status = pjsip_endpt_register_module(endpt, &mod_xfer);
    if (status != PJ_SUCCESS)
	return status;

    status = pjsip_endpt_add_capability( endpt, &mod_xfer, PJSIP_H_ALLOW, 
					 NULL, 1, 
					 &pjsip_get_refer_method()->name);
    if (status != PJ_SUCCESS)
	return status;

    status = pjsip_evsub_register_pkg(&mod_xfer, &STR_REFER, 
				      PJSIP_XFER_EXPIRES, 1, &accept);
    if (status != PJ_SUCCESS)
	return status;

    return PJ_SUCCESS;
}
Пример #9
0
/*
 * Init presence module.
 */
PJ_DEF(pj_status_t) pjsip_pres_init_module( pjsip_endpoint *endpt,
					    pjsip_module *mod_evsub)
{
    pj_status_t status;
    pj_str_t accept[2];

    /* Check arguments. */
    PJ_ASSERT_RETURN(endpt && mod_evsub, PJ_EINVAL);

    /* Must have not been registered */
    PJ_ASSERT_RETURN(mod_presence.id == -1, PJ_EINVALIDOP);

    /* Register to endpoint */
    status = pjsip_endpt_register_module(endpt, &mod_presence);
    if (status != PJ_SUCCESS)
	return status;

    accept[0] = STR_APP_PIDF_XML;
    accept[1] = STR_APP_XPIDF_XML;

    /* Register event package to event module. */
    status = pjsip_evsub_register_pkg( &mod_presence, &STR_PRESENCE, 
				       PRES_DEFAULT_EXPIRES, 
				       PJ_ARRAY_SIZE(accept), accept);
    if (status != PJ_SUCCESS) {
	pjsip_endpt_unregister_module(endpt, &mod_presence);
	return status;
    }

    return PJ_SUCCESS;
}
Пример #10
0
/*
 * Init mwi module.
 */
PJ_DEF(pj_status_t) pjsip_mwi_init_module( pjsip_endpoint *endpt,
					   pjsip_module *mod_evsub)
{
    pj_status_t status;
    pj_str_t accept[1];

    /* Check arguments. */
    PJ_ASSERT_RETURN(endpt && mod_evsub, PJ_EINVAL);

    /* Must have not been registered */
    PJ_ASSERT_RETURN(mod_mwi.id == -1, PJ_EINVALIDOP);

    /* Register to endpoint */
    status = pjsip_endpt_register_module(endpt, &mod_mwi);
    if (status != PJ_SUCCESS)
	return status;

    accept[0] = STR_APP_SIMPLE_SMS;

    /* Register event package to event module. */
    status = pjsip_evsub_register_pkg( &mod_mwi, &STR_MWI, 
				       MWI_DEFAULT_EXPIRES, 
				       PJ_ARRAY_SIZE(accept), accept);
    if (status != PJ_SUCCESS) {
	pjsip_endpt_unregister_module(endpt, &mod_mwi);
	return status;
    }

    return PJ_SUCCESS;
}
PJ_DECL(pj_status_t) pjsip_opus_sdp_rewriter_init(unsigned target_clock_rate) {
    if(target_clock_rate > 0 && target_clock_rate <= 48000){
        pjopus_internal_clockrate = target_clock_rate;
    }else{
        pjopus_internal_clockrate = 48000;
    }
    return pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
                            &pjsua_opus_sdp_rewriter);
}
Пример #12
0
pj_status_t init_registrar(RegData::Store* registrar_store, HSSConnection* hss_connection, AnalyticsLogger* analytics_logger, IfcHandler* ifchandler_ref)
{
  pj_status_t status;

  store = registrar_store;
  hss = hss_connection;
  analytics = analytics_logger;
  ifchandler = ifchandler_ref;

  status = pjsip_endpt_register_module(stack_data.endpt, &mod_registrar);
  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

  return status;
}
Пример #13
0
static pj_status_t init_stack(void)
{
    pj_status_t status;

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Then init PJLIB-UTIL: */
    status = pjlib_util_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&global.cp, &pj_pool_factory_default_policy, 0);

    /* Create the endpoint: */
    status = pjsip_endpt_create(&global.cp.factory, NULL, &global.endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /* Init transaction layer for stateful proxy only */
#if STATEFUL
    status = pjsip_tsx_layer_init_module(global.endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#endif

    /* Create listening transport */
    {
        pj_sockaddr_in addr;

        addr.sin_family = pj_AF_INET();
        addr.sin_addr.s_addr = 0;
        addr.sin_port = pj_htons((pj_uint16_t)global.port);

        status = pjsip_udp_transport_start( global.endpt, &addr,
                                            NULL, 1, NULL);
        if (status != PJ_SUCCESS)
            return status;
    }

    /* Create pool for the application */
    global.pool = pj_pool_create(&global.cp.factory, "proxyapp",
                                 4000, 4000, NULL);

    /* Register the logger module */
    pjsip_endpt_register_module(global.endpt, &mod_msg_logger);

    return PJ_SUCCESS;
}
Пример #14
0
int init_msg_logger(void)
{
    pj_status_t status;

    if (mod_msg_logger.id != -1)
	return 0;

    status = pjsip_endpt_register_module(endpt, &mod_msg_logger);
    if (status != PJ_SUCCESS) {
	app_perror("  error registering module", status);
	return -10;
    }

    return 0;
}
Пример #15
0
/*
 * Init user agent module and register it to the endpoint.
 */
PJ_DEF(pj_status_t) pjsip_ua_init_module( pjsip_endpoint *endpt,
					  const pjsip_ua_init_param *prm)
{
    pj_status_t status;

    /* Check if module already registered. */
    PJ_ASSERT_RETURN(mod_ua.mod.id == -1, PJ_EINVALIDOP);

    /* Copy param, if exists. */
    if (prm)
	pj_memcpy(&mod_ua.param, prm, sizeof(pjsip_ua_init_param));

    /* Register the module. */
    status = pjsip_endpt_register_module(endpt, &mod_ua.mod);

    return status;
}
Пример #16
0
/*
 * Init presence
 */
pj_status_t pjsua_pres_init()
{
    unsigned i;
    pj_status_t status;

    status = pjsip_endpt_register_module( pjsua_var.endpt, &mod_pjsua_pres);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Unable to register pjsua presence module", 
		     status);
    }

    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
	reset_buddy(i);
    }

    return status;
}
Пример #17
0
int ast_res_pjsip_init_options_handling(int reload)
{
	static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };

	if (reload) {
		qualify_and_schedule_all();
		return 0;
	}

	sched_qualifies = ao2_t_container_alloc(QUALIFIED_BUCKETS,
		sched_qualifies_hash_fn, sched_qualifies_cmp_fn,
		"Create container for scheduled qualifies");
	if (!sched_qualifies) {
		return -1;
	}

	if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module) != PJ_SUCCESS) {
		ao2_cleanup(sched_qualifies);
		sched_qualifies = NULL;
		return -1;
	}

	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
		NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
		pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
		ao2_cleanup(sched_qualifies);
		sched_qualifies = NULL;
		return -1;
	}

	if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "aor", &observer_callbacks_options)) {
		pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
		ao2_cleanup(sched_qualifies);
		sched_qualifies = NULL;
		return -1;
	}

	internal_sip_register_endpoint_formatter(&contact_status_formatter);
	ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify);
	ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));

	update_all_unqualified_endpoints();
	qualify_and_schedule_all();

	return 0;
}
Пример #18
0
pj_status_t init_subscription(RegStore* registrar_store,
                              RegStore* remote_reg_store,
                              HSSConnection* hss_connection,
                              ACRFactory* rfacr_factory,
                              AnalyticsLogger* analytics_logger)
{
  pj_status_t status;

  store = registrar_store;
  remote_store = remote_reg_store;
  hss = hss_connection;
  acr_factory = rfacr_factory;
  analytics = analytics_logger;

  status = pjsip_endpt_register_module(stack_data.endpt, &mod_subscription);
  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

  return status;
}
pj_status_t
init_common_sip_processing(LoadMonitor* load_monitor_arg,
                           SNMP::CounterByScopeTable* requests_counter_arg,
                           SNMP::CounterByScopeTable* overload_counter_arg,
                           HealthChecker* health_checker_arg)
{
  // Register the stack modules.
  pjsip_endpt_register_module(stack_data.endpt, &mod_common_processing);
  stack_data.sas_logging_module_id = mod_common_processing.id;

  overload_counter = overload_counter_arg;
  requests_counter = requests_counter_arg;

  load_monitor = load_monitor_arg;

  health_checker = health_checker_arg;

  return PJ_SUCCESS;
}
Пример #20
0
pj_status_t init_registrar(RegStore* registrar_store,
                           RegStore* remote_reg_store,
                           HSSConnection* hss_connection,
                           AnalyticsLogger* analytics_logger,
                           ACRFactory* rfacr_factory,
                           int cfg_max_expires)
{
  pj_status_t status;

  store = registrar_store;
  remote_store = remote_reg_store;
  hss = hss_connection;
  analytics = analytics_logger;
  max_expires = cfg_max_expires;
  acr_factory = rfacr_factory;

  // Construct a Service-Route header pointing at the S-CSCF ready to be added
  // to REGISTER 200 OK response.
  pjsip_sip_uri* service_route_uri = (pjsip_sip_uri*)
                        pjsip_parse_uri(stack_data.pool,
                                        stack_data.scscf_uri.ptr,
                                        stack_data.scscf_uri.slen,
                                        0);
  service_route_uri->lr_param = 1;

  // Add the orig parameter.  The UE must provide this back on future messages
  // to ensure we perform originating processing.
  pjsip_param *orig_param = PJ_POOL_ALLOC_T(stack_data.pool, pjsip_param);
  pj_strdup(stack_data.pool, &orig_param->name, &STR_ORIG);
  pj_strdup2(stack_data.pool, &orig_param->value, "");
  pj_list_insert_after(&service_route_uri->other_param, orig_param);

  service_route = pjsip_route_hdr_create(stack_data.pool);
  service_route->name = STR_SERVICE_ROUTE;
  service_route->sname = pj_str("");
  service_route->name_addr.uri = (pjsip_uri*)service_route_uri;

  status = pjsip_endpt_register_module(stack_data.endpt, &mod_registrar);
  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

  return status;
}
Пример #21
0
int main(int argc, char *argv[])
{
    /* At least on Linux, we have to initialize SDL video subsystem prior to
     * creating/initializing QApplication, otherwise we'll segfault miserably
     * in SDL_CreateWindow(). Here's a stack trace if you're interested:

	Thread [7] (Suspended: Signal 'SIGSEGV' received. Description: Segmentation fault.)
	13 XCreateIC()
	12 SetupWindowData()
	11 X11_CreateWindow()
	10 SDL_CreateWindow()
	..
     */
    if ( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) {
        printf("Unable to init SDL: %s\n", SDL_GetError());
        return 1;
    }

    QApplication app(argc, argv);

    MainWin win;
    win.show();

    if (!win.initStack()) {
	win.quit();
	return 1;
    }

    /* We want to be registrar too! */
    if (pjsua_get_pjsip_endpt()) {
	pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
				    &mod_default_handler);
    }

    return app.exec();
}
Пример #22
0
int transport_load_test(char *target_url)
{
    enum { COUNT = 2000 };
    unsigned i;
    pj_status_t status = PJ_SUCCESS;

    /* exhaust packets */
    do {
	pj_time_val delay = {1, 0};
	i = 0;
	pjsip_endpt_handle_events2(endpt, &delay, &i);
    } while (i != 0);

    PJ_LOG(3,(THIS_FILE, "  transport load test..."));

    if (mod_load.mod.id == -1) {
	status = pjsip_endpt_register_module( endpt, &mod_load.mod);
	if (status != PJ_SUCCESS) {
	    app_perror("error registering module", status);
	    return -1;
	}
    }
    mod_load.err = PJ_FALSE;
    mod_load.next_seq = 0;

    for (i=0; i<COUNT && !mod_load.err; ++i) {
	pj_str_t target, from, call_id;
	pjsip_tx_data *tdata;

	target = pj_str(target_url);
	from = pj_str("<sip:user@host>");
	call_id = pj_str("thecallid");
	status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, 
					    &target, &from, 
					    &target, &from, &call_id, 
					    i, NULL, &tdata );
	if (status != PJ_SUCCESS) {
	    app_perror("error creating request", status);
	    goto on_return;
	}

	status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL);
	if (status != PJ_SUCCESS) {
	    app_perror("error sending request", status);
	    goto on_return;
	}
    }

    do {
	pj_time_val delay = {1, 0};
	i = 0;
	pjsip_endpt_handle_events2(endpt, &delay, &i);
    } while (i != 0);

    if (mod_load.next_seq != COUNT) {
	PJ_LOG(1,("THIS_FILE", "    err: expecting %u msg, got only %u", 
		  COUNT, mod_load.next_seq));
	status = -2;
	goto on_return;
    }

on_return:
    if (mod_load.mod.id != -1) {
	pjsip_endpt_unregister_module( endpt, &mod_load.mod);
	mod_load.mod.id = -1;
    }
    if (status != PJ_SUCCESS || mod_load.err) {
	return -2;
    }
    PJ_LOG(3,(THIS_FILE, "   success"));
    return 0;
}
Пример #23
0
int transport_rt_test( pjsip_transport_type_e tp_type,
		       pjsip_transport *ref_tp,
		       char *target_url,
		       int *lost)
{
    enum { THREADS = 4, INTERVAL = 10 };
    int i;
    pj_status_t status;
    pj_pool_t *pool;
    pj_bool_t logger_enabled;

    pj_timestamp zero_time, total_time;
    unsigned usec_rt;
    unsigned total_sent;
    unsigned total_recv;

    PJ_UNUSED_ARG(tp_type);
    PJ_UNUSED_ARG(ref_tp);

    PJ_LOG(3,(THIS_FILE, "  multithreaded round-trip test (%d threads)...",
		  THREADS));
    PJ_LOG(3,(THIS_FILE, "    this will take approx %d seconds, please wait..",
		INTERVAL));

    /* Make sure msg logger is disabled. */
    logger_enabled = msg_logger_set_enabled(0);

    /* Register module (if not yet registered) */
    if (rt_module.id == -1) {
	status = pjsip_endpt_register_module( endpt, &rt_module );
	if (status != PJ_SUCCESS) {
	    app_perror("   error: unable to register module", status);
	    return -600;
	}
    }

    /* Create pool for this test. */
    pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
    if (!pool)
	return -610;

    /* Initialize static test data. */
    pj_ansi_strcpy(rt_target_uri, target_url);
    rt_call_id = pj_str("RT-Call-Id/");
    rt_stop = PJ_FALSE;

    /* Initialize thread data. */
    for (i=0; i<THREADS; ++i) {
	char buf[1];
	pj_str_t str_id;
	
	pj_strset(&str_id, buf, 1);
	pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i]));

	/* Init timer entry */
	rt_test_data[i].tx_timer.id = i;
	rt_test_data[i].tx_timer.cb = &rt_tx_timer;
	rt_test_data[i].timeout_timer.id = i;
	rt_test_data[i].timeout_timer.cb = &rt_timeout_timer;

	/* Generate Call-ID for each thread. */
	rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1);
	pj_strcpy(&rt_test_data[i].call_id, &rt_call_id);
	buf[0] = '0' + (char)i;
	pj_strcat(&rt_test_data[i].call_id, &str_id);

	/* Init mutex. */
	status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex);
	if (status != PJ_SUCCESS) {
	    app_perror("   error: unable to create mutex", status);
	    return -615;
	}

	/* Create thread, suspended. */
	status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)i, 0,
				  PJ_THREAD_SUSPENDED, &rt_test_data[i].thread);
	if (status != PJ_SUCCESS) {
	    app_perror("   error: unable to create thread", status);
	    return -620;
	}
    }

    /* Start threads! */
    for (i=0; i<THREADS; ++i) {
	pj_time_val delay = {0,0};
	pj_thread_resume(rt_test_data[i].thread);

	/* Schedule first message transmissions. */
	rt_test_data[i].tx_timer.user_data = (void*)1;
	pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay);
    }

    /* Sleep for some time. */
    pj_thread_sleep(INTERVAL * 1000);

    /* Signal thread to stop. */
    rt_stop = PJ_TRUE;

    /* Wait threads to complete. */
    for (i=0; i<THREADS; ++i) {
	pj_thread_join(rt_test_data[i].thread);
	pj_thread_destroy(rt_test_data[i].thread);
    }

    /* Destroy rt_test_data */
    for (i=0; i<THREADS; ++i) {
	pj_mutex_destroy(rt_test_data[i].mutex);
	pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer);
    }

    /* Gather statistics. */
    pj_bzero(&total_time, sizeof(total_time));
    pj_bzero(&zero_time, sizeof(zero_time));
    usec_rt = total_sent = total_recv = 0;
    for (i=0; i<THREADS; ++i) {
	total_sent += rt_test_data[i].sent_request_count;
	total_recv +=  rt_test_data[i].recv_response_count;
	pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time);
    }

    /* Display statistics. */
    if (total_recv)
	total_time.u64 = total_time.u64/total_recv;
    else
	total_time.u64 = 0;
    usec_rt = pj_elapsed_usec(&zero_time, &total_time);
    PJ_LOG(3,(THIS_FILE, "    done."));
    PJ_LOG(3,(THIS_FILE, "    total %d messages sent", total_sent));
    PJ_LOG(3,(THIS_FILE, "    average round-trip=%d usec", usec_rt));

    pjsip_endpt_release_pool(endpt, pool);

    *lost = total_sent-total_recv;

    /* Flush events. */
    flush_events(500);

    /* Restore msg logger. */
    msg_logger_set_enabled(logger_enabled);

    return 0;
}
Пример #24
0
/* Test that we receive loopback message. */
int transport_send_recv_test( pjsip_transport_type_e tp_type,
			      pjsip_transport *ref_tp,
			      char *target_url,
			      int *p_usec_rtt)
{
    pj_bool_t msg_log_enabled;
    pj_status_t status;
    pj_str_t target, from, to, contact, call_id, body;
    pjsip_method method;
    pjsip_tx_data *tdata;
    pj_time_val timeout;

    PJ_UNUSED_ARG(tp_type);
    PJ_UNUSED_ARG(ref_tp);

    PJ_LOG(3,(THIS_FILE, "  single message round-trip test..."));

    /* Register out test module to receive the message (if necessary). */
    if (my_module.id == -1) {
	status = pjsip_endpt_register_module( endpt, &my_module );
	if (status != PJ_SUCCESS) {
	    app_perror("   error: unable to register module", status);
	    return -500;
	}
    }

    /* Disable message logging. */
    msg_log_enabled = msg_logger_set_enabled(0);

    /* Create a request message. */
    target = pj_str(target_url);
    from = pj_str(FROM_HDR);
    to = pj_str(target_url);
    contact = pj_str(CONTACT_HDR);
    call_id = pj_str(CALL_ID_HDR);
    body = pj_str(BODY);

    pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
    status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
					 &contact, &call_id, CSEQ_VALUE, 
					 &body, &tdata );
    if (status != PJ_SUCCESS) {
	app_perror("   error: unable to create request", status);
	return -510;
    }

    /* Reset statuses */
    send_status = recv_status = NO_STATUS;

    /* Start time. */
    pj_get_timestamp(&my_send_time);

    /* Send the message (statelessly). */
    PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", 
			 (int)target.slen, target.ptr));
    status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
					         &send_msg_callback);
    if (status != PJ_SUCCESS) {
	/* Immediate error! */
	pjsip_tx_data_dec_ref(tdata);
	send_status = status;
    }

    /* Set the timeout (2 seconds from now) */
    pj_gettimeofday(&timeout);
    timeout.sec += 2;

    /* Loop handling events until we get status */
    do {
	pj_time_val now;
	pj_time_val poll_interval = { 0, 10 };

	pj_gettimeofday(&now);
	if (PJ_TIME_VAL_GTE(now, timeout)) {
	    PJ_LOG(3,(THIS_FILE, "   error: timeout in send/recv test"));
	    status = -540;
	    goto on_return;
	}

	if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
	    app_perror("   error sending message", send_status);
	    status = -550;
	    goto on_return;
	}

	if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
	    app_perror("   error receiving message", recv_status);
	    status = -560;
	    goto on_return;
	}

	if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
	    /* Success! */
	    break;
	}

	pjsip_endpt_handle_events(endpt, &poll_interval);

    } while (1);

    if (status == PJ_SUCCESS) {
	unsigned usec_rt;
	usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);

	PJ_LOG(3,(THIS_FILE, "    round-trip = %d usec", usec_rt));

	*p_usec_rtt = usec_rt;
    }

    /* Restore message logging. */
    msg_logger_set_enabled(msg_log_enabled);

    status = PJ_SUCCESS;

on_return:
    return status;
}
Пример #25
0
//Wrap start & stop
PJ_DECL(pj_status_t) csipsimple_init(pjsua_config *ua_cfg,
				pjsua_logging_config *log_cfg,
				pjsua_media_config *media_cfg,
				csipsimple_config *css_cfg){
	pj_status_t result;

	// Finalize configuration
	log_cfg->cb = &pj_android_log_msg;
	if(css_cfg->turn_username.slen){
		media_cfg->turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC;
		media_cfg->turn_auth_cred.data.static_cred.realm = pj_str("*");
		media_cfg->turn_auth_cred.data.static_cred.username = css_cfg->turn_username;

		if (css_cfg->turn_password.slen) {
			 media_cfg->turn_auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
			 media_cfg->turn_auth_cred.data.static_cred.data = css_cfg->turn_password;
		}
	}

	// Static cfg
	extern pj_bool_t pjsip_use_compact_form;
	extern pj_bool_t pjsip_include_allow_hdr_in_dlg;
	extern pj_bool_t pjmedia_add_rtpmap_for_static_pt;
	extern pj_bool_t pjsua_no_update;


	pjsua_no_update = css_cfg->use_no_update ? PJ_TRUE : PJ_FALSE;

	pjsip_use_compact_form = css_cfg->use_compact_form_headers ? PJ_TRUE : PJ_FALSE;
	/* do not transmit Allow header */
	pjsip_include_allow_hdr_in_dlg = css_cfg->use_compact_form_headers ? PJ_FALSE : PJ_TRUE;
	/* Do not include rtpmap for static payload types (<96) */
	pjmedia_add_rtpmap_for_static_pt = css_cfg->use_compact_form_sdp ? PJ_FALSE : PJ_TRUE;


#if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0
	if(css_cfg->use_zrtp){
		ua_cfg->cb.on_create_media_transport = &on_zrtp_transport_created;
	}
#endif
	result = (pj_status_t) pjsua_init(ua_cfg, log_cfg, media_cfg);
	if(result == PJ_SUCCESS){
		init_ringback_tone();
#if PJMEDIA_AUDIO_DEV_HAS_ANDROID
#if PJ_ANDROID_DEVICE==1
		pjmedia_aud_register_factory(&pjmedia_android_factory);
#endif
#if PJ_ANDROID_DEVICE==2
		pjmedia_aud_register_factory(&pjmedia_opensl_factory);
#endif
#endif

#if USE_TCP_HACK==1
	    // Registering module for tcp hack
	    static pjsip_module tcp_hack_mod; // cannot be a stack variable

	    memset(&tcp_hack_mod, 0, sizeof(tcp_hack_mod));
	    tcp_hack_mod.id = -1;
	    tcp_hack_mod.priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1;
	    tcp_hack_mod.on_rx_response = &on_rx_request_tcp_hack;
	    tcp_hack_mod.name = pj_str("TCP-Hack");

	    result = pjsip_endpt_register_module(pjsip_ua_get_endpt(pjsip_ua_instance()), &tcp_hack_mod);
#endif


	}


	return result;
}
Пример #26
0
/*
 * main()
 *
 * If called with argument, treat argument as SIP URL to be called.
 * Otherwise wait for incoming calls.
 */
int main(int argc, char *argv[])
{
    pj_pool_t *pool = NULL;
    pj_status_t status;
    unsigned i;

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    pj_log_set_level(5);

    /* Then init PJLIB-UTIL: */
    status = pjlib_util_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);


    /* Create global endpoint: */
    {
	const pj_str_t *hostname;
	const char *endpt_name;

	/* Endpoint MUST be assigned a globally unique name.
	 * The name will be used as the hostname in Warning header.
	 */

	/* For this implementation, we'll use hostname for simplicity */
	hostname = pj_gethostname();
	endpt_name = hostname->ptr;

	/* Create the endpoint: */

	status = pjsip_endpt_create(&cp.factory, endpt_name, 
				    &g_endpt);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }


    /* 
     * Add UDP transport, with hard-coded port 
     * Alternatively, application can use pjsip_udp_transport_attach() to
     * start UDP transport, if it already has an UDP socket (e.g. after it
     * resolves the address with STUN).
     */
    {
	pj_sockaddr addr;

	pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
	
	if (AF == pj_AF_INET()) {
	    status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL, 
						1, NULL);
	} else if (AF == pj_AF_INET6()) {
	    status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL,
						1, NULL);
	} else {
	    status = PJ_EAFNOTSUP;
	}

	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to start UDP transport", status);
	    return 1;
	}
    }


    /* 
     * Init transaction layer.
     * This will create/initialize transaction hash tables etc.
     */
    status = pjsip_tsx_layer_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize UA layer module.
     * This will create/initialize dialog hash tables etc.
     */
    status = pjsip_ua_init_module( g_endpt, NULL );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Init invite session module.
     * The invite session module initialization takes additional argument,
     * i.e. a structure containing callbacks to be called on specific
     * occurence of events.
     *
     * The on_state_changed and on_new_session callbacks are mandatory.
     * Application must supply the callback function.
     *
     * We use on_media_update() callback in this application to start
     * media transmission.
     */
    {
	pjsip_inv_callback inv_cb;

	/* Init the callback for INVITE session: */
	pj_bzero(&inv_cb, sizeof(inv_cb));
	inv_cb.on_state_changed = &call_on_state_changed;
	inv_cb.on_new_session = &call_on_forked;
	inv_cb.on_media_update = &call_on_media_update;

	/* Initialize invite session module:  */
	status = pjsip_inv_usage_init(g_endpt, &inv_cb);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }

    /* Initialize 100rel support */
    status = pjsip_100rel_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /*
     * Register our module to receive incoming requests.
     */
    status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /*
     * Register message logger module.
     */
    status = pjsip_endpt_register_module( g_endpt, &msg_logger);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
#if PJ_HAS_THREADS
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
#else
    status = pjmedia_endpt_create(&cp.factory, 
				  pjsip_endpt_get_ioqueue(g_endpt), 
				  0, &g_med_endpt);
#endif
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* 
     * Add PCMA/PCMU codec to the media endpoint. 
     */
#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
    status = pjmedia_codec_g711_init(g_med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#endif


#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Init video subsystem */
    pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512);
    status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_converter_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_codec_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_dev_subsys_init(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

#  if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    /* Init ffmpeg video codecs */
    status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#  endif  /* PJMEDIA_HAS_FFMPEG_VID_CODEC */

#endif	/* PJMEDIA_HAS_VIDEO */
    
    /* 
     * Create media transport used to send/receive RTP/RTCP socket.
     * One media transport is needed for each call. Application may
     * opt to re-use the same media transport for subsequent calls.
     */
    for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) {
	status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL, 
					       RTP_PORT + i*2, 0, 
					       &g_med_transport[i]);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create media transport", status);
	    return 1;
	}

	/* 
	 * Get socket info (address, port) of the media transport. We will
	 * need this info to create SDP (i.e. the address and port info in
	 * the SDP).
	 */
	pjmedia_transport_info_init(&g_med_tpinfo[i]);
	pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]);

	pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info,
		  sizeof(pjmedia_sock_info));
    }

    /*
     * If URL is specified, then make call immediately.
     */
    if (argc > 1) {
	pj_sockaddr hostaddr;
	char hostip[PJ_INET6_ADDRSTRLEN+2];
	char temp[80];
	pj_str_t dst_uri = pj_str(argv[1]);
	pj_str_t local_uri;
	pjsip_dialog *dlg;
	pjmedia_sdp_session *local_sdp;
	pjsip_tx_data *tdata;

	if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
	    return 1;
	}
	pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);

	pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>", 
			hostip, SIP_PORT);
	local_uri = pj_str(temp);

	/* Create UAC dialog */
	status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
				       &local_uri,  /* local URI */
				       &local_uri,  /* local Contact */
				       &dst_uri,    /* remote URI */
				       &dst_uri,    /* remote target */
				       &dlg);	    /* dialog */
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create UAC dialog", status);
	    return 1;
	}

	/* If we expect the outgoing INVITE to be challenged, then we should
	 * put the credentials in the dialog here, with something like this:
	 *
	    {
		pjsip_cred_info	cred[1];

		cred[0].realm	  = pj_str("sip.server.realm");
		cred[0].scheme    = pj_str("digest");
		cred[0].username  = pj_str("theuser");
		cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
		cred[0].data      = pj_str("thepassword");

		pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred);
	    }
	 *
	 */


	/* Get the SDP body to be put in the outgoing INVITE, by asking
	 * media endpoint to create one for us.
	 */
	status = pjmedia_endpt_create_sdp( g_med_endpt,	    /* the media endpt	*/
					   dlg->pool,	    /* pool.		*/
					   MAX_MEDIA_CNT,   /* # of streams	*/
					   g_sock_info,     /* RTP sock info	*/
					   &local_sdp);	    /* the SDP result	*/
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Create the INVITE session, and pass the SDP returned earlier
	 * as the session's initial capability.
	 */
	status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

	/* If we want the initial INVITE to travel to specific SIP proxies,
	 * then we should put the initial dialog's route set here. The final
	 * route set will be updated once a dialog has been established.
	 * To set the dialog's initial route set, we do it with something
	 * like this:
	 *
	    {
		pjsip_route_hdr route_set;
		pjsip_route_hdr *route;
		const pj_str_t hname = { "Route", 5 };
		char *uri = "sip:proxy.server;lr";

		pj_list_init(&route_set);

		route = pjsip_parse_hdr( dlg->pool, &hname, 
					 uri, strlen(uri),
					 NULL);
		PJ_ASSERT_RETURN(route != NULL, 1);
		pj_list_push_back(&route_set, route);

		pjsip_dlg_set_route_set(dlg, &route_set);
	    }
	 *
	 * Note that Route URI SHOULD have an ";lr" parameter!
	 */

	/* Create initial INVITE request.
	 * This INVITE request will contain a perfectly good request and 
	 * an SDP body as well.
	 */
	status = pjsip_inv_invite(g_inv, &tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Send initial INVITE request. 
	 * From now on, the invite session's state will be reported to us
	 * via the invite session callbacks.
	 */
	status = pjsip_inv_send_msg(g_inv, tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    } else {

	/* No URL to make call to */

	PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
    }


    /* Loop until one call is completed */
    for (;!g_complete;) {
	pj_time_val timeout = {0, 10};
	pjsip_endpt_handle_events(g_endpt, &timeout);
    }

    /* On exit, dump current memory usage: */
    dump_pool_usage(THIS_FILE, &cp);

    /* Destroy audio ports. Destroy the audio port first
     * before the stream since the audio port has threads
     * that get/put frames to the stream.
     */
    if (g_snd_port)
	pjmedia_snd_port_destroy(g_snd_port);

#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Destroy video ports */
    if (g_vid_capturer)
	pjmedia_vid_port_destroy(g_vid_capturer);
    if (g_vid_renderer)
	pjmedia_vid_port_destroy(g_vid_renderer);
#endif

    /* Destroy streams */
    if (g_med_stream)
	pjmedia_stream_destroy(g_med_stream);
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    if (g_med_vstream)
	pjmedia_vid_stream_destroy(g_med_vstream);

    /* Deinit ffmpeg codec */
#   if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    pjmedia_codec_ffmpeg_vid_deinit();
#   endif

#endif

    /* Destroy media transports */
    for (i = 0; i < MAX_MEDIA_CNT; ++i) {
	if (g_med_transport[i])
	    pjmedia_transport_close(g_med_transport[i]);
    }

    /* Deinit pjmedia endpoint */
    if (g_med_endpt)
	pjmedia_endpt_destroy(g_med_endpt);

    /* Deinit pjsip endpoint */
    if (g_endpt)
	pjsip_endpt_destroy(g_endpt);

    /* Release pool */
    if (pool)
	pj_pool_release(pool);

    return 0;
}
Пример #27
0
pj_status_t init_stack(const std::string& system_name,
                       const std::string& sas_address,
                       int trusted_port,
                       int untrusted_port,
                       const std::string& local_host,
                       const std::string& home_domain,
                       const std::string& sprout_cluster_domain,
                       const std::string& alias_hosts,
                       int num_pjsip_threads,
                       int num_worker_threads)
{
  pj_status_t status;
  pj_sockaddr pri_addr;
  pj_sockaddr addr_list[16];
  unsigned addr_cnt = PJ_ARRAY_SIZE(addr_list);
  unsigned i;

  // Set up the vectors of threads.  The threads don't get created until
  // start_stack is called.
  pjsip_threads.resize(num_pjsip_threads);
  worker_threads.resize(num_worker_threads);

  // Get ports and host names specified on options.  If local host was not
  // specified, use the host name returned by pj_gethostname.
  memset(&stack_data, 0, sizeof(stack_data));
  char* local_host_cstr = strdup(local_host.c_str());
  char* home_domain_cstr = strdup(home_domain.c_str());
  char* sprout_cluster_domain_cstr = strdup(sprout_cluster_domain.c_str());
  stack_data.trusted_port = trusted_port;
  stack_data.untrusted_port = untrusted_port;
  stack_data.local_host = (local_host != "") ? pj_str(local_host_cstr) : *pj_gethostname();
  stack_data.home_domain = (home_domain != "") ? pj_str(home_domain_cstr) : stack_data.local_host;
  stack_data.sprout_cluster_domain = (sprout_cluster_domain != "") ? pj_str(sprout_cluster_domain_cstr) : stack_data.local_host;

  // Initialize SAS logging.
  if (system_name != "")
  {
    SAS::init(system_name.length(), system_name.c_str(), sas_address);
  }
  else
  {
    SAS::init(stack_data.local_host.slen, stack_data.local_host.ptr, sas_address);
  }

  // Initialise PJSIP and all the associated resources.
  status = init_pjsip();

  // Register the stack module.
  pjsip_endpt_register_module(stack_data.endpt, &mod_stack);
  stack_data.module_id = mod_stack.id;

  // Create listening transports for trusted and untrusted ports.
  if (stack_data.trusted_port != 0)
  {
    status = create_listener_transports(stack_data.trusted_port, &stack_data.tcp_factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  }
  if (stack_data.untrusted_port != 0)
  {
    status = create_listener_transports(stack_data.untrusted_port, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  }

  // List all names matching local endpoint.
  // Note that PJLIB version 0.6 and newer has a function to
  // enumerate local IP interface (pj_enum_ip_interface()), so
  // by using it would be possible to list all IP interfaces in
  // this host.

  // The first address is important since this would be the one
  // to be added in Record-Route.
  stack_data.name[stack_data.name_cnt] = stack_data.local_host;
  stack_data.name_cnt++;

  if (pj_gethostip(pj_AF_INET(), &pri_addr) == PJ_SUCCESS)
  {
    pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt],
               pj_inet_ntoa(pri_addr.ipv4.sin_addr));
    stack_data.name_cnt++;
  }

  // Get the rest of IP interfaces.
  if (pj_enum_ip_interface(pj_AF_INET(), &addr_cnt, addr_list) == PJ_SUCCESS)
  {
    for (i = 0; i < addr_cnt; ++i)
    {
      if (addr_list[i].ipv4.sin_addr.s_addr == pri_addr.ipv4.sin_addr.s_addr)
      {
        continue;
      }

      pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt],
                 pj_inet_ntoa(addr_list[i].ipv4.sin_addr));
      stack_data.name_cnt++;
    }
  }

  // Add loopback address.
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
  stack_data.name[stack_data.name_cnt] = pj_str("127.0.0.1");
  stack_data.name_cnt++;
#endif

  stack_data.name[stack_data.name_cnt] = pj_str("localhost");
  stack_data.name_cnt++;
  // Parse the list of alias host names.
  if (alias_hosts != "")
  {
    std::list<std::string> hosts;
    Utils::split_string(alias_hosts, ',', hosts, 0, true);
    for (std::list<std::string>::iterator it = hosts.begin();
         it != hosts.end();
         ++it)
    {
      pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], it->c_str());
      stack_data.name_cnt++;
    }
  }

  LOG_STATUS("Local host aliases:");
  for (i = 0; i < stack_data.name_cnt; ++i)
  {
    LOG_STATUS(" %.*s",
               (int)stack_data.name[i].slen,
               stack_data.name[i].ptr);
  }

  stack_data.stats_aggregator = new LastValueCache(Statistic::known_stats_count(),
                                                   Statistic::known_stats());

  latency_accumulator = new StatisticAccumulator("latency_us");

  return status;
}
Пример #28
0
/*****************************************************************************
 **
 ** UAC Transaction Test.
 **
 *****************************************************************************
 */
int tsx_uac_test(struct tsx_test_param *param)
{
    pj_sockaddr_in addr;
    pj_status_t status;

    timer.tsx_key.ptr = timer.key_buf;

    test_param = param;

    /* Get transport flag */
    tp_flag = pjsip_transport_get_flag_from_type(test_param->type);

    pj_ansi_sprintf(TARGET_URI, "sip:[email protected]:%d;transport=%s", 
		    param->port, param->tp_type);
    pj_ansi_sprintf(FROM_URI, "sip:[email protected]:%d;transport=%s", 
		    param->port, param->tp_type);

    /* Check if loop transport is configured. */
    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, 
				      &addr, sizeof(addr), NULL, &loop);
    if (status != PJ_SUCCESS) {
	PJ_LOG(3,(THIS_FILE, "  Error: loop transport is not configured!"));
	return -10;
    }

    /* Register modules. */
    status = pjsip_endpt_register_module(endpt, &tsx_user);
    if (status != PJ_SUCCESS) {
	app_perror("   Error: unable to register module", status);
	return -30;
    }
    status = pjsip_endpt_register_module(endpt, &msg_receiver);
    if (status != PJ_SUCCESS) {
	app_perror("   Error: unable to register module", status);
	return -40;
    }

    /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */
    status = tsx_uac_retransmit_test();
    if (status != 0)
	return status;

    /* TEST2_BRANCH_ID: Resolve error test. */
    status = tsx_resolve_error_test();
    if (status != 0)
	return status;

    /* TEST3_BRANCH_ID: UAC terminate while resolving test. */
    status = tsx_terminate_resolving_test();
    if (status != 0)
	return status;

    /* TEST4_BRANCH_ID: Transport failed after several retransmissions.
     *                  Only applies to loop transport.
     */
    if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
	status = tsx_retransmit_fail_test();
	if (status != 0)
	    return status;
    }

    /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions 
     *			Only applicable to non-reliable transports.
     */
    if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) {
	status = tsx_terminate_after_retransmit_test();
	if (status != 0)
	    return status;
    }

    /* TEST6_BRANCH_ID: Successfull non-invite transaction */
    status = perform_generic_test("test6: successfull non-invite transaction",
				  TEST6_BRANCH_ID, &pjsip_options_method);
    if (status != 0)
	return status;

    /* TEST7_BRANCH_ID: Successfull non-invite transaction */
    status = perform_generic_test("test7: successfull non-invite transaction "
				  "with provisional response",
				  TEST7_BRANCH_ID, &pjsip_options_method);
    if (status != 0)
	return status;

    /* TEST8_BRANCH_ID: Failed invite transaction */
    status = perform_generic_test("test8: failed invite transaction",
				  TEST8_BRANCH_ID, &pjsip_invite_method);
    if (status != 0)
	return status;

    /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */
    status = perform_generic_test("test9: failed invite transaction with "
				  "provisional response",
				  TEST9_BRANCH_ID, &pjsip_invite_method);
    if (status != 0)
	return status;

    pjsip_transport_dec_ref(loop);
    flush_events(500);

    /* Unregister modules. */
    status = pjsip_endpt_unregister_module(endpt, &tsx_user);
    if (status != PJ_SUCCESS) {
	app_perror("   Error: unable to unregister module", status);
	return -31;
    }
    status = pjsip_endpt_unregister_module(endpt, &msg_receiver);
    if (status != PJ_SUCCESS) {
	app_perror("   Error: unable to unregister module", status);
	return -41;
    }

    return 0;
}
Пример #29
0
/*
 * main()
 *
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pj_thread_t *thread;
    pj_pool_t *pool;
    pj_status_t status;
    
    if (argc != 2) {
	puts("Error: destination URL needed");
	return 0;
    }

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Then init PJLIB-UTIL: */
    status = pjlib_util_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);


    /* Create the endpoint: */
    status = pjsip_endpt_create(&cp.factory, "sipstateless", 
				&sip_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* 
     * Add UDP transport, with hard-coded port 
     */
    {
	pj_sockaddr_in addr;

	addr.sin_family = pj_AF_INET();
	addr.sin_addr.s_addr = 0;
	addr.sin_port = pj_htons(PORT);

	status = pjsip_udp_transport_start( sip_endpt, &addr, NULL, 1, NULL);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(3,(THIS_FILE, 
		      "Error starting UDP transport (port in use?)"));
	    return 1;
	}
    }

    status = pjsip_tsx_layer_init_module(sip_endpt);
    pj_assert(status == PJ_SUCCESS);

    status = pjsip_ua_init_module(sip_endpt, NULL);
    pj_assert(status == PJ_SUCCESS);

    /*
     * Register our module to receive incoming requests.
     */
    status = pjsip_endpt_register_module( sip_endpt, &mod_app);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    pool = pjsip_endpt_create_pool(sip_endpt, "", 1000, 1000);

    status = pj_thread_create(pool, "", &worker_thread, NULL, 0, 0, &thread);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    printf("Destination URL: %s\n", argv[1]);

    for (;;) {
	char line[10];

	fgets(line, sizeof(line), stdin);

	switch (line[0]) {
	case 'm':
	    make_call(argv[1], PJ_FALSE);
	    break;
	case 'M':
	    make_call(argv[1], PJ_TRUE);
	    break;
	case 'r':
	    reinvite(PJ_FALSE);
	    break;
	case 'R':
	    reinvite(PJ_TRUE);
	    break;
	case 'h':
	    hangup();
	    break;
	case 'q':
	    goto on_quit;
	}
    }

on_quit:
    quit_flag = 1;
    pj_thread_join(thread);

    pjsip_endpt_destroy(sip_endpt);
    pj_caching_pool_destroy(&cp);
    pj_shutdown();
    return 0;
}
Пример #30
0
int regc_test(void)
{
    struct test_rec {
	unsigned		 check_contact;
	unsigned		 add_xuid_param;

	const char		*title;
	char			*alt_registrar;
	unsigned		 contact_cnt;
	char			*contacts[4];
	unsigned		 expires;
	struct registrar_cfg	 server_cfg;
	struct client		 client_cfg;
    } test_rec[] = 
    {
	/* immediate error */
	{
	    OFF,			    /* check_contact	*/
	    OFF,			    /* add_xuid_param	*/
	    "immediate error",		    /* title		*/
	    "sip:unresolved-host-xyy",	    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "sip:[email protected]:5060" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_FALSE,	200,	PJ_FALSE, NONE,	    0,	    0,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	502,	PJ_FALSE,   600,	0,	    PJ_FALSE}
	},

	/* timeout test */
	{
	    OFF,			    /* check_contact	*/
	    OFF,			    /* add_xuid_param	*/
	    "timeout test (takes ~32 secs)",/* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "sip:[email protected]:5060" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_FALSE,	200,	PJ_FALSE, NONE,	    0,	    0,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth? */
	    { PJ_FALSE,	408,	PJ_FALSE,   600,	0,	    PJ_FALSE}
	},

	/* Basic successful registration scenario:
	 * a good registrar returns the Contact header as is and
	 * add expires parameter. In this test no additional bindings
	 * are returned.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "basic",			    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060;transport=udp;x-param=1234>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact  exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, EXACT,    75,	    65,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    75,		1,	    PJ_FALSE}
	},

	/* Basic successful registration scenario with authentication
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "authentication",		    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060;transport=udp;x-param=1234>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact  exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_TRUE,  EXACT,    75,	    65,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    75,		1,	    PJ_TRUE}
	},

	/* a good registrar returns the Contact header as is and
	 * add expires parameter. Also it adds bindings from other
	 * clients in this test.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON,				    /* add_xuid_param	*/
	    "more bindings in response",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060;transport=udp>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact  exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, EXACT,   75,	    65,	    {"<sip:a@a>;expires=70", 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    75,		2,	    PJ_FALSE}
	},


	/* a bad registrar returns modified Contact header, but it
	 * still returns all parameters intact. In this case
	 * the expiration is taken from the expires param because
	 * of matching xuid param or because the number of
	 * Contact header matches.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "registrar modifies Contact header",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, MODIFIED, 75,	    65,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    75,		1,	    PJ_FALSE}
	},


	/* a bad registrar returns modified Contact header, but it
	 * still returns all parameters intact. In addition it returns
	 * bindings from other clients.
	 *
	 * In this case the expiration is taken from the expires param 
	 * because add_xuid_param is enabled.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON,				    /* add_xuid_param	*/
	    "registrar modifies Contact header and add bindings",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, MODIFIED, 75,	    65,	    {"<sip:a@a>;expires=70", 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    75,		2,	    PJ_FALSE}
	},


	/* a bad registrar returns completely different Contact and
	 * all parameters are gone. In this case the expiration is 
	 * also taken from the expires param since the number of 
	 * header matches.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "registrar replaces Contact header",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	202,	PJ_FALSE, NONE,	    0,	    65,	    {"<sip:a@A>;expires=75", 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	202,	PJ_TRUE,    75,		1,	    PJ_FALSE}
	},


	/* a bad registrar returns completely different Contact (and
	 * all parameters are gone) and it also includes bindings from
	 * other clients.
	 * In this case the expiration is taken from the Expires header.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    " as above with additional bindings",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, NONE,	    0,	    65,	    {"<sip:a@A>;expires=75, <sip:b@B;expires=70>", 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    65,		2,	    PJ_FALSE}
	},

	/* the registrar doesn't return any bindings, but for some
	 * reason it includes an Expires header.
	 * In this case the expiration is taken from the Expires header.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "no Contact but with Expires",  /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },  /* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, NONE,	    0,	    65,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    65,		0,	    PJ_FALSE}
	},

	/* Neither Contact header nor Expires header are present.
	 * In this case the expiration is taken from the request.
	 */
	{
	    ON_OFF,			    /* check_contact	*/
	    ON_OFF,			    /* add_xuid_param	*/
	    "no Contact and no Expires",    /* title		*/
	    NULL,			    /* alt_registrar	*/
	    1,				    /* contact cnt	*/
	    { "<sip:[email protected]:5060>" },/* contacts[]	*/
	    600,			    /* expires		*/

	    /* registrar config: */
	    /* respond	code	auth	  contact   exp_prm expires more_contacts */
	    { PJ_TRUE,	200,	PJ_FALSE, NONE,	    0,	    0,	    {NULL, 0}},

	    /* client expected results: */
	    /* error	code	have_reg    expiration	contact_cnt auth?*/
	    { PJ_FALSE,	200,	PJ_TRUE,    600,	0,	    PJ_FALSE}
	},
    };

    unsigned i;
    pj_sockaddr_in addr;
    pjsip_transport *udp = NULL;
    pj_uint16_t port; 
    char registrar_uri_buf[80];
    pj_str_t registrar_uri;
    int rc = 0;

    pj_sockaddr_in_init(&addr, 0, 0);

    /* Acquire existing transport, if any */
    rc = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &addr, sizeof(addr), NULL, &udp);
    if (rc == PJ_SUCCESS) {
	port = pj_sockaddr_get_port(&udp->local_addr);
	pjsip_transport_dec_ref(udp);
	udp = NULL;
    } else {
	rc = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &udp);
	if (rc != PJ_SUCCESS) {
	    app_perror("   error creating UDP transport", rc);
	    rc = -2;
	    goto on_return;
	}

	port = pj_sockaddr_get_port(&udp->local_addr);
    }

    /* Register registrar module */
    rc = pjsip_endpt_register_module(endpt, &registrar.mod);
    if (rc != PJ_SUCCESS) {
	app_perror("   error registering module", rc);
	rc = -3;
	goto on_return;
    }

    /* Register send module */
    rc = pjsip_endpt_register_module(endpt, &send_mod.mod);
    if (rc != PJ_SUCCESS) {
	app_perror("   error registering module", rc);
	rc = -3;
	goto on_return;
    }

    pj_ansi_snprintf(registrar_uri_buf, sizeof(registrar_uri_buf),
		    "sip:127.0.0.1:%d", (int)port);
    registrar_uri = pj_str(registrar_uri_buf);

    for (i=0; i<PJ_ARRAY_SIZE(test_rec); ++i) {
	struct test_rec *t = &test_rec[i];
	unsigned j, x;
	pj_str_t reg_uri;
	pj_str_t contacts[8];

	/* Fill in the registrar address if it's not specified */
	if (t->alt_registrar == NULL) {
	    reg_uri = registrar_uri;
	} else {
	    reg_uri = pj_str(t->alt_registrar);
	}

	/* Build contact pj_str_t's */
	for (j=0; j<t->contact_cnt; ++j) {
	    contacts[j] = pj_str(t->contacts[j]);
	}

	/* Normalize more_contacts field */
	if (t->server_cfg.more_contacts.ptr)
	    t->server_cfg.more_contacts.slen = strlen(t->server_cfg.more_contacts.ptr);

	/* Do tests with three combinations:
	 *  - check_contact on/off
	 *  - add_xuid_param on/off
	 *  - destroy_on_callback on/off
	 */
	for (x=1; x<=2; ++x) {
	    unsigned y;

	    if ((t->check_contact & x) == 0)
		continue;

	    pjsip_cfg()->regc.check_contact = (x-1);

	    for (y=1; y<=2; ++y) {
		unsigned z;

		if ((t->add_xuid_param & y) == 0)
		    continue;

		pjsip_cfg()->regc.add_xuid_param = (y-1);

		for (z=0; z<=1; ++z) {
		    char new_title[200];

		    t->client_cfg.destroy_on_cb = z;

		    sprintf(new_title, "%s [check=%d, xuid=%d, destroy=%d]", 
			    t->title, pjsip_cfg()->regc.check_contact,
			    pjsip_cfg()->regc.add_xuid_param, z);
		    rc = do_test(new_title, &t->server_cfg, &t->client_cfg, 
				 &reg_uri, t->contact_cnt, contacts, 
				 t->expires, PJ_FALSE, NULL);
		    if (rc != 0)
			goto on_return;
		}

	    }
	}

	/* Sleep between test groups to avoid using up too many
	 * active transactions.
	 */
	pj_thread_sleep(1000);
    }

    /* keep-alive test */
    rc = keep_alive_test(&registrar_uri);
    if (rc != 0)
	goto on_return;

    /* Send error on refresh without destroy on callback */
    rc = refresh_error(&registrar_uri, PJ_FALSE);
    if (rc != 0)
	goto on_return;

    /* Send error on refresh, destroy on callback */
    rc = refresh_error(&registrar_uri, PJ_TRUE);
    if (rc != 0)
	goto on_return;

    /* Updating contact */
    rc = update_test(&registrar_uri);
    if (rc != 0)
	goto on_return;

    /* Send error during auth, don't destroy on callback */
    rc = auth_send_error(&registrar_uri, PJ_FALSE);
    if (rc != 0)
	goto on_return;

    /* Send error during auth, destroy on callback */
    rc = auth_send_error(&registrar_uri, PJ_FALSE);
    if (rc != 0)
	goto on_return;

on_return:
    if (registrar.mod.id != -1) {
	pjsip_endpt_unregister_module(endpt, &registrar.mod);
    }
    if (send_mod.mod.id != -1) {
	pjsip_endpt_unregister_module(endpt, &send_mod.mod);
    }
    if (udp) {
	pjsip_transport_dec_ref(udp);
    }
    return rc;
}