std::shared_ptr<SipTransport> SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l, const std::string& remoteSipUri) { if (!l) { ERROR("Can't create TLS transport without listener."); return nullptr; } static const char SIPS_PREFIX[] = "<sips:"; size_t sips = remoteSipUri.find(SIPS_PREFIX) + (sizeof SIPS_PREFIX) - 1; size_t trns = remoteSipUri.find(";transport"); const std::string remoteHost {remoteSipUri.substr(sips, trns-sips)}; IpAddr remoteAddr = {remoteHost}; DEBUG("getTlsTransport host %s resolved to -> %s", remoteHost.c_str(), remoteAddr.toString(true).c_str()); if (!remoteAddr) return nullptr; if (remoteAddr.getPort() == 0) remoteAddr.setPort(pjsip_transport_get_default_port_for_type(l->get()->type)); DEBUG("Get new TLS transport to %s", remoteAddr.toString(true).c_str()); pjsip_tpselector sel {PJSIP_TPSELECTOR_LISTENER, { .listener = l->get() }}; pjsip_transport *transport = nullptr; pj_status_t status = pjsip_endpt_acquire_transport( endpt_, l->get()->type, remoteAddr.pjPtr(), remoteAddr.getLength(), &sel, &transport); if (!transport || status != PJ_SUCCESS) { ERROR("Could not get new TLS transport"); sip_utils::sip_strerror(status); return nullptr; } auto ret = std::make_shared<SipTransport>(transport, l); pjsip_transport_dec_ref(transport); { std::lock_guard<std::mutex> lock(transportMapMutex_); transports_[ret->get()] = ret; } return ret; }
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, ®istrar.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, ®_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(®istrar_uri); if (rc != 0) goto on_return; /* Send error on refresh without destroy on callback */ rc = refresh_error(®istrar_uri, PJ_FALSE); if (rc != 0) goto on_return; /* Send error on refresh, destroy on callback */ rc = refresh_error(®istrar_uri, PJ_TRUE); if (rc != 0) goto on_return; /* Updating contact */ rc = update_test(®istrar_uri); if (rc != 0) goto on_return; /* Send error during auth, don't destroy on callback */ rc = auth_send_error(®istrar_uri, PJ_FALSE); if (rc != 0) goto on_return; /* Send error during auth, destroy on callback */ rc = auth_send_error(®istrar_uri, PJ_FALSE); if (rc != 0) goto on_return; on_return: if (registrar.mod.id != -1) { pjsip_endpt_unregister_module(endpt, ®istrar.mod); } if (send_mod.mod.id != -1) { pjsip_endpt_unregister_module(endpt, &send_mod.mod); } if (udp) { pjsip_transport_dec_ref(udp); } return rc; }
/* * UDP transport test. */ int transport_udp_test(void) { enum { SEND_RECV_LOOP = 8 }; pjsip_transport *udp_tp, *tp; pj_sockaddr_in addr, rem_addr; pj_str_t s; pj_status_t status; int rtt[SEND_RECV_LOOP], min_rtt; int i, pkt_lost; pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); /* Start UDP transport. */ status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); if (status != PJ_SUCCESS) { app_perror(" Error: unable to start UDP transport", status); return -10; } /* UDP transport must have initial reference counter set to 1. */ if (pj_atomic_get(udp_tp->ref_cnt) != 1) return -20; /* Test basic transport attributes */ status = generic_transport_test(udp_tp); if (status != PJ_SUCCESS) return status; /* Test that transport manager is returning the correct * transport. */ pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &rem_addr, sizeof(rem_addr), NULL, &tp); if (status != PJ_SUCCESS) return -50; if (tp != udp_tp) return -60; /* pjsip_endpt_acquire_transport() adds reference, so we need * to decrement it. */ pjsip_transport_dec_ref(tp); /* Check again that reference counter is 1. */ if (pj_atomic_get(udp_tp->ref_cnt) != 1) return -70; /* Basic transport's send/receive loopback test. */ pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); for (i=0; i<SEND_RECV_LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp, "sip:[email protected]:"TEST_UDP_PORT_STR, &rtt[i]); if (status != 0) return status; } min_rtt = 0xFFFFFFF; for (i=0; i<SEND_RECV_LOOP; ++i) if (rtt[i] < min_rtt) min_rtt = rtt[i]; report_ival("udp-rtt-usec", min_rtt, "usec", "Best UDP transport round trip time, in microseconds " "(time from sending request until response is received. " "Tests were performed on local machine only)"); /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp, "sip:[email protected]:"TEST_UDP_PORT_STR, &pkt_lost); if (status != 0) return status; if (pkt_lost != 0) PJ_LOG(3,(THIS_FILE, " note: %d packet(s) was lost", pkt_lost)); /* Check again that reference counter is 1. */ if (pj_atomic_get(udp_tp->ref_cnt) != 1) return -80; /* Destroy this transport. */ pjsip_transport_dec_ref(udp_tp); /* Force destroy this transport. */ status = pjsip_transport_destroy(udp_tp); if (status != PJ_SUCCESS) return -90; /* Flush events. */ PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); flush_events(1000); /* Done */ return 0; }
static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) { unsigned i; pjsip_tx_data *request; pjsip_via_hdr *via; pjsip_rx_data rdata; pj_sockaddr_in remote; pjsip_transaction **tsx; pj_timestamp t1, t2, elapsed; char branch_buf[80] = PJSIP_RFC3261_BRANCH_ID "0000000000"; pj_status_t status; /* Create the request first. */ pj_str_t str_target = pj_str("sip:[email protected]"); pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>"); pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>"); pj_str_t str_contact = str_from; status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &str_target, &str_from, &str_to, &str_contact, NULL, -1, NULL, &request); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); return status; } /* Create Via */ via = pjsip_via_hdr_create(request->pool); via->sent_by.host = pj_str("192.168.0.7"); via->sent_by.port = 5061; via->transport = pj_str("udp"); via->rport_param = 1; via->recvd_param = pj_str("192.168.0.7"); pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); /* Create "dummy" rdata from the tdata */ pj_bzero(&rdata, sizeof(pjsip_rx_data)); rdata.tp_info.pool = request->pool; rdata.msg_info.msg = request->msg; rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); rdata.msg_info.via = via; pj_sockaddr_in_init(&remote, 0, 0); status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &remote, sizeof(pj_sockaddr_in), NULL, &rdata.tp_info.transport); if (status != PJ_SUCCESS) { app_perror(" error: unable to get loop transport", status); return status; } /* Create transaction array */ tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user)); mod_tsx_user.id = -1; /* Benchmark */ elapsed.u64 = 0; pj_get_timestamp(&t1); for (i=0; i<working_set; ++i) { via->branch_param.ptr = branch_buf; via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, "-%d", i); status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]); if (status != PJ_SUCCESS) goto on_error; } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); pj_add_timestamp(&elapsed, &t2); p_elapsed->u64 = elapsed.u64; status = PJ_SUCCESS; on_error: for (i=0; i<working_set; ++i) { if (tsx[i]) { pjsip_tsx_terminate(tsx[i], 601); tsx[i] = NULL; } } pjsip_tx_data_dec_ref(request); flush_events(2000); return status; }
/***************************************************************************** ** ** 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; }
/***************************************************************************** ** ** UAS Transaction Test. ** ***************************************************************************** */ int tsx_uas_test(struct tsx_test_param *param) { pj_sockaddr_in addr; pj_status_t status; test_param = param; tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)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 -3; } status = pjsip_endpt_register_module(endpt, &msg_sender); if (status != PJ_SUCCESS) { app_perror(" Error: unable to register module", status); return -4; } /* TEST1_BRANCH_ID: Basic 2xx final response. * TEST2_BRANCH_ID: Basic non-2xx final response. */ status = tsx_basic_final_response_test(); if (status != 0) return status; /* TEST3_BRANCH_ID: with provisional response */ status = tsx_basic_provisional_response_test(); if (status != 0) return status; /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state */ status = tsx_retransmit_last_response_test(TEST4_TITLE, TEST4_BRANCH_ID, TEST4_REQUEST_COUNT, TEST4_STATUS_CODE); if (status != 0) return status; /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state */ status = tsx_retransmit_last_response_test(TEST5_TITLE, TEST5_BRANCH_ID, TEST5_REQUEST_COUNT, TEST5_STATUS_CODE); if (status != 0) return status; /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state * This only applies to non-reliable transports, * since UAS transaction is destroyed as soon * as final response is sent for reliable transports. */ if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { status = tsx_retransmit_last_response_test(TEST6_TITLE, TEST6_BRANCH_ID, TEST6_REQUEST_COUNT, TEST6_STATUS_CODE); if (status != 0) return status; } /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test */ status = tsx_final_response_retransmission_test(); if (status != 0) return status; /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must * cease when ACK is received * Only applicable for non-reliable transports. */ if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { status = tsx_ack_test(); if (status != 0) return status; } /* TEST10_BRANCH_ID: test transport failure in TRYING state. * TEST11_BRANCH_ID: test transport failure in PROCEEDING state. * TEST12_BRANCH_ID: test transport failure in CONNECTED state. * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. */ /* Only valid for loop-dgram */ if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { status = tsx_transport_failure_test(); if (status != 0) return status; } /* Register modules. */ status = pjsip_endpt_unregister_module(endpt, &tsx_user); if (status != PJ_SUCCESS) { app_perror(" Error: unable to unregister module", status); return -8; } status = pjsip_endpt_unregister_module(endpt, &msg_sender); if (status != PJ_SUCCESS) { app_perror(" Error: unable to unregister module", status); return -9; } if (loop) pjsip_transport_dec_ref(loop); return 0; }
static int datagram_loop_test() { enum { LOOP = 8 }; pjsip_transport *loop; int i, pkt_lost; pj_sockaddr_in addr; pj_status_t status; long ref_cnt; int rtt[LOOP], min_rtt; PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); /* Test acquire transport. */ status = pjsip_endpt_acquire_transport( endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &addr, sizeof(addr), NULL, &loop); if (status != PJ_SUCCESS) { app_perror(" error: loop transport is not configured", status); return -20; } /* Get initial reference counter */ ref_cnt = pj_atomic_get(loop->ref_cnt); /* Test basic transport attributes */ status = generic_transport_test(loop); if (status != PJ_SUCCESS) return status; /* Basic transport's send/receive loopback test. */ for (i=0; i<LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop, "sip:[email protected];transport=loop-dgram", &rtt[i]); if (status != 0) return status; } min_rtt = 0xFFFFFFF; for (i=0; i<LOOP; ++i) if (rtt[i] < min_rtt) min_rtt = rtt[i]; report_ival("loop-rtt-usec", min_rtt, "usec", "Best Loopback transport round trip time, in microseconds " "(time from sending request until response is received. " "Tests were performed on local machine only)"); /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop, "sip:[email protected];transport=loop-dgram", &pkt_lost); if (status != 0) return status; if (pkt_lost != 0) { PJ_LOG(3,(THIS_FILE, " error: %d packet(s) was lost", pkt_lost)); return -40; } /* Put delay. */ PJ_LOG(3,(THIS_FILE," setting network delay to 10 ms")); pjsip_loop_set_delay(loop, 10); /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop, "sip:[email protected];transport=loop-dgram", &pkt_lost); if (status != 0) return status; if (pkt_lost != 0) { PJ_LOG(3,(THIS_FILE, " error: %d packet(s) was lost", pkt_lost)); return -50; } /* Restore delay. */ pjsip_loop_set_delay(loop, 0); /* Check reference counter. */ if (pj_atomic_get(loop->ref_cnt) != ref_cnt) { PJ_LOG(3,(THIS_FILE, " error: ref counter is not %d (%d)", ref_cnt, pj_atomic_get(loop->ref_cnt))); return -51; } /* Decrement reference. */ pjsip_transport_dec_ref(loop); return 0; }
int transport_tcp_test(void) { enum { SEND_RECV_LOOP = 8 }; pjsip_tpfactory *tpfactory; pjsip_transport *tcp; pj_sockaddr_in rem_addr; pj_status_t status; char url[PJSIP_MAX_URL_SIZE]; int rtt[SEND_RECV_LOOP], min_rtt; int i, pkt_lost; /* Start TCP listener on arbitrary port. */ status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); if (status != PJ_SUCCESS) { app_perror(" Error: unable to start TCP transport", status); return -10; } /* Get the listener address */ status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, (pj_uint16_t)tpfactory->addr_name.port); if (status != PJ_SUCCESS) { app_perror(" Error: possibly invalid TCP address name", status); return -14; } pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", pj_inet_ntoa(rem_addr.sin_addr), pj_ntohs(rem_addr.sin_port)); /* Acquire one TCP transport. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, &rem_addr, sizeof(rem_addr), NULL, &tcp); if (status != PJ_SUCCESS || tcp == NULL) { app_perror(" Error: unable to acquire TCP transport", status); return -17; } /* After pjsip_endpt_acquire_transport, TCP transport must have * reference counter 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -20; /* Test basic transport attributes */ status = generic_transport_test(tcp); if (status != PJ_SUCCESS) return status; /* Check again that reference counter is 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -40; /* Load test */ if (transport_load_test(url) != 0) return -60; /* Basic transport's send/receive loopback test. */ for (i=0; i<SEND_RECV_LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]); if (status != 0) { pjsip_transport_dec_ref(tcp); flush_events(500); return -72; } } min_rtt = 0xFFFFFFF; for (i=0; i<SEND_RECV_LOOP; ++i) if (rtt[i] < min_rtt) min_rtt = rtt[i]; report_ival("tcp-rtt-usec", min_rtt, "usec", "Best TCP transport round trip time, in microseconds " "(time from sending request until response is received. " "Tests were performed on local machine only, and after " "TCP socket has been established by previous test)"); /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost); if (status != 0) { pjsip_transport_dec_ref(tcp); return status; } if (pkt_lost != 0) PJ_LOG(3,(THIS_FILE, " note: %d packet(s) was lost", pkt_lost)); /* Check again that reference counter is still 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -80; /* Destroy this transport. */ pjsip_transport_dec_ref(tcp); /* Force destroy this transport. */ status = pjsip_transport_destroy(tcp); if (status != PJ_SUCCESS) return -90; /* Unregister factory */ status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), tpfactory); if (status != PJ_SUCCESS) return -95; /* Flush events. */ PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); flush_events(1000); /* Done */ return 0; }
pj_status_t UE::init_int(pj_log_func* logger, std::string realm, std::string myurl, std::string username, std::string password, std::string outbound_proxy) { pj_status_t status; char errmsg[PJ_ERR_MSG_SIZE]; pj_sockaddr addr; pj_str_t remote; pj_sockaddr remote_addr; init_pjsip(logger); std::string server_uri = std::string("sip:") + realm + std::string(";lr;transport=tcp"); _pool = pj_pool_create(get_global_pool_factory(), "a", 256, 256, NULL); pj_sockaddr_init(pj_AF_INET(), &addr, NULL, (pj_uint16_t)0); //status = pjsip_udp_transport_start(get_global_endpoint(), &addr.ipv4, NULL, 1, &_transport); //assert(status == PJ_SUCCESS); if (outbound_proxy.empty()) { outbound_proxy = realm; } pj_cstr(&remote, outbound_proxy.c_str()); pj_sockaddr_init(pj_AF_INET(), &remote_addr, &remote, (pj_uint16_t)5060); pjsip_tpselector sel2; sel2.type = PJSIP_TPSELECTOR_LISTENER; sel2.u.listener = get_global_tcp_factory(); status = pjsip_endpt_acquire_transport(get_global_endpoint(), PJSIP_TRANSPORT_TCP, &remote_addr, pj_sockaddr_get_len(&remote_addr), &sel2, &_transport); if (status != PJ_SUCCESS) { pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(1, (__FILE__, "TCP connection to %s failed: %s (%d)", outbound_proxy.c_str(), errmsg, status)); return status; } transport_mapping[_transport] = this; status = pjsip_regc_create(get_global_endpoint(), this, ®c_cb, &_regc); if (status != PJ_SUCCESS) { pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(1, (__FILE__, "Creating the REGISTER session failed: %s (%d)", errmsg, status)); return status; } pjsip_regc_set_reg_tsx_cb(_regc, ®_tsx_cb); pjsip_tpselector sel; sel.type = PJSIP_TPSELECTOR_TRANSPORT; sel.u.transport = _transport; pjsip_regc_set_transport(_regc, &sel); pjsip_auth_clt_pref prefs = {}; prefs.initial_auth = PJ_TRUE; pjsip_regc_set_prefs(_regc, &prefs); pjsip_cred_info cred; stra(&cred.realm, realm.c_str()); stra(&cred.scheme, "Digest"); stra(&cred.username, username.c_str()); stra(&cred.data, password.c_str()); cred.data_type = 0; // Plaintext password pjsip_cred_info creds[1] = {cred}; pjsip_regc_set_credentials(_regc, 1, creds); char contact[32]; snprintf(contact, 32, "sip:phone@%.*s:%d", (int)_transport->local_name.host.slen, _transport->local_name.host.ptr, _transport->local_name.port); stra(&_realm, realm.c_str()); stra(&_server, server_uri.c_str()); _server_uri = pjsip_parse_uri(_pool, _server.ptr, _server.slen, 0); stra(&_my_uri, myurl.c_str()); stra(&_username, username.c_str()); stra(&_contact, contact); return PJ_SUCCESS; }