// Determine the type of a URI. // // Parameters: // // - uri - the URI to classify // - prefer_sip - for ambiguous URIs like sip:[email protected] (which could be a global phone // number or just a SIP URI), prefer to interpret it as SIP // - check_np - check for the presence of Number Portability parameters and // classify accordingly // URIClass URIClassifier::classify_uri(const pjsip_uri* uri, bool prefer_sip, bool check_np) { URIClass ret = URIClass::UNKNOWN; // First, check to see if this URI has number portability data - this takes priority bool has_rn = false; bool has_npdi = false; if (check_np) { if (PJSIP_URI_SCHEME_IS_TEL(uri)) { // If the URI is a tel URI, pull out the information from the other_params has_rn = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_RN) != NULL); has_npdi = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_NPDI) != NULL); } else if (PJSIP_URI_SCHEME_IS_SIP(uri)) { // If the URI is a tel URI, pull out the information from the userinfo_params has_rn = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_RN) != NULL); has_npdi = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_NPDI) != NULL); } } if (has_rn) { if (has_npdi) { ret = FINAL_NP_DATA; } else { ret = NP_DATA; } } // No number portability data else if (PJSIP_URI_SCHEME_IS_TEL(uri)) { // TEL URIs can only represent phone numbers - decide if it's a global (E.164) number or not pjsip_tel_uri* tel_uri = (pjsip_tel_uri*)uri; std::string user = PJUtils::pj_str_to_string(&tel_uri->number); boost::match_results<std::string::const_iterator> results; if (boost::regex_match(user, results, CHARS_ALLOWED_IN_GLOBAL_NUM)) { ret = GLOBAL_PHONE_NUMBER; } else { ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER; } } else if (PJSIP_URI_SCHEME_IS_SIP(uri)) { pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri; pj_str_t host = sip_uri->host; bool home_domain = is_home_domain(host); bool local_to_node = is_local_name(host); bool is_gruu = (pjsip_param_find(&((pjsip_sip_uri*)uri)->other_param, &STR_GR) != NULL); bool treat_number_as_phone = !enforce_user_phone && !prefer_sip; TRC_DEBUG("home domain: %s, local_to_node: %s, is_gruu: %s, enforce_user_phone: %s, prefer_sip: %s, treat_number_as_phone: %s", home_domain ? "true" : "false", local_to_node ? "true" : "false", is_gruu ? "true" : "false", enforce_user_phone ? "true" : "false", prefer_sip ? "true" : "false", treat_number_as_phone ? "true" : "false"); bool classified = false; // SIP URI that's 'really' a phone number - apply the same logic as for TEL URIs if ((!pj_strcmp(&((pjsip_sip_uri*)uri)->user_param, &STR_USER_PHONE) || (home_domain && treat_number_as_phone && !is_gruu))) { // Get the user part minus any parameters. std::string user = PJUtils::pj_str_to_string(&sip_uri->user); if (!user.empty()) { std::vector<std::string> user_tokens; Utils::split_string(user, ';', user_tokens, 0, true); boost::match_results<std::string::const_iterator> results; if (boost::regex_match(user_tokens[0], results, CHARS_ALLOWED_IN_GLOBAL_NUM)) { ret = GLOBAL_PHONE_NUMBER; classified = true; } else if (boost::regex_match(user_tokens[0], results, CHARS_ALLOWED_IN_LOCAL_NUM)) { ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER; classified = true; } } } if (!classified) { // Not a phone number - classify it based on domain ret = (home_domain) ? HOME_DOMAIN_SIP_URI : ((local_to_node) ? NODE_LOCAL_SIP_URI : OFFNET_SIP_URI); } } std::string uri_str = PJUtils::uri_to_string(PJSIP_URI_IN_OTHER, uri); TRC_DEBUG("Classified URI %s as %d", uri_str.c_str(), (int)ret); return ret; }
static pj_status_t pjsip_url_compare( pjsip_uri_context_e context, const pjsip_sip_uri *url1, const pjsip_sip_uri *url2) { const pjsip_param *p1; /* * Compare two SIP URL's according to Section 19.1.4 of RFC 3261. */ /* SIP and SIPS URI are never equivalent. * Note: just compare the vptr to avoid string comparison. * Pretty neat huh!! */ if (url1->vptr != url2->vptr) return PJSIP_ECMPSCHEME; /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. * This includes userinfo containing passwords or formatted as * telephone-subscribers. */ if (pj_strcmp(&url1->user, &url2->user) != 0) return PJSIP_ECMPUSER; if (pj_strcmp(&url1->passwd, &url2->passwd) != 0) return PJSIP_ECMPPASSWD; /* Comparison of all other components of the URI is * case-insensitive unless explicitly defined otherwise. */ /* The ordering of parameters and header fields is not significant * in comparing SIP and SIPS URIs. */ /* Characters other than those in the reserved set (see RFC 2396 [5]) * are equivalent to their encoding. */ /* An IP address that is the result of a DNS lookup of a host name * does not match that host name. */ if (pj_stricmp(&url1->host, &url2->host) != 0) return PJSIP_ECMPHOST; /* A URI omitting any component with a default value will not match a URI * explicitly containing that component with its default value. * For instance, a URI omitting the optional port component will not match * a URI explicitly declaring port 5060. * The same is true for the transport-parameter, ttl-parameter, * user-parameter, and method components. */ /* Port is not allowed in To and From header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { if (url1->port != url2->port) return PJSIP_ECMPPORT; } /* Transport is not allowed in From/To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0) return PJSIP_ECMPTRANSPORTPRM; } /* TTL param is not allowed in From, To, Route, and Record-Route header. */ if (context != PJSIP_URI_IN_FROMTO_HDR && context != PJSIP_URI_IN_ROUTING_HDR) { if (url1->ttl_param != url2->ttl_param) return PJSIP_ECMPTTLPARAM; } /* User param is allowed in all contexes */ if (pj_stricmp(&url1->user_param, &url2->user_param) != 0) return PJSIP_ECMPUSERPARAM; /* Method param is only allowed in external/other context. */ if (context == PJSIP_URI_IN_OTHER) { if (pj_stricmp(&url1->method_param, &url2->method_param) != 0) return PJSIP_ECMPMETHODPARAM; } /* maddr param is not allowed in From and To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0) return PJSIP_ECMPMADDRPARAM; } /* lr parameter is ignored (?) */ /* lr param is not allowed in From, To, and Contact header. */ /* All other uri-parameters appearing in only one URI are ignored when * comparing the URIs. */ if (pjsip_param_cmp(&url1->other_param, &url2->other_param, 1)!=0) return PJSIP_ECMPOTHERPARAM; /* URI header components are never ignored. Any present header component * MUST be present in both URIs and match for the URIs to match. * The matching rules are defined for each header field in Section 20. */ p1 = url1->header_param.next; while (p1 != &url1->header_param) { const pjsip_param *p2; p2 = pjsip_param_find(&url2->header_param, &p1->name); if (p2) { /* It seems too much to compare two header params according to * the rule of each header. We'll just compare them string to * string.. */ if (pj_stricmp(&p1->value, &p2->value) != 0) return PJSIP_ECMPHEADERPARAM; } else { return PJSIP_ECMPHEADERPARAM; } p1 = p1->next; } /* Equal!! Pheuww.. */ return PJ_SUCCESS; }
/* This tests the request creating functions against the following * requirements: * - header params in URI creates header in the request. * - method and headers params are correctly shown or hidden in * request URI, From, To, and Contact header. */ static int txdata_test_uri_params(void) { char msgbuf[512]; pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" "?X-Hdr-1=Header%201" "&X-Empty-Hdr="); pj_str_t contact; pj_str_t pname = pj_str("x-param"); pj_str_t hname = pj_str("X-Hdr-1"); pj_str_t hemptyname = pj_str("X-Empty-Hdr"); pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; pjsip_contact_hdr *contact_hdr; pjsip_generic_string_hdr *hdr; pjsip_tx_data *tdata; pjsip_sip_uri *uri; pjsip_param *param; pjsip_via_hdr *via; pjsip_parser_err_report err_list; pjsip_msg *msg; int len; pj_status_t status; PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); /* Due to #930, contact argument is now parsed as Contact header, so * must enclose it with <> to make it be parsed as URI. */ pj_ansi_snprintf(msgbuf, sizeof(msgbuf), "<%.*s>", (int)target.slen, target.ptr); contact.ptr = msgbuf; contact.slen = strlen(msgbuf); /* Create request with header param in target URI. */ status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, &target, &target, &contact, NULL, -1, NULL, &tdata); if (status != 0) { app_perror(" error: Unable to create request", status); return -200; } /* Fill up the Via header to prevent syntax error on parsing */ via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); via->transport = pj_str("TCP"); via->sent_by.host = pj_str("127.0.0.1"); /* Print and parse the request. * We'll check that header params are not present in */ len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); if (len < 1) { PJ_LOG(3,(THIS_FILE, " error: printing message")); pjsip_tx_data_dec_ref(tdata); return -250; } msgbuf[len] = '\0'; PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" "%s\n" "--end-msg--", len, msgbuf)); /* Now parse the message. */ pj_list_init(&err_list); msg = pjsip_parse_msg( 0, tdata->pool, msgbuf, len, &err_list); if (msg == NULL) { pjsip_parser_err_report *e; PJ_LOG(3,(THIS_FILE, " error: parsing message message")); e = err_list.next; while (e != &err_list) { PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", pj_exception_id_name(0, e->except_code), e->line, e->col+1, (int)e->hname.slen, e->hname.ptr)); e = e->next; } pjsip_tx_data_dec_ref(tdata); return -256; } /* Check the existence of port, other_param, and header param. * Port is now allowed in To and From header. */ /* Port in request URI. */ uri = (pjsip_sip_uri*) pjsip_uri_get_uri(msg->line.req.uri); if (uri->port != 5061) { PJ_LOG(3,(THIS_FILE, " error: port not present in request URI")); pjsip_tx_data_dec_ref(tdata); return -260; } /* other_param in request_uri */ param = pjsip_param_find(&uri->other_param, &pname); if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { PJ_LOG(3,(THIS_FILE, " error: x-param not present in request URI")); pjsip_tx_data_dec_ref(tdata); return -261; } /* header param in request uri. */ if (!pj_list_empty(&uri->header_param)) { PJ_LOG(3,(THIS_FILE, " error: hparam in request URI")); pjsip_tx_data_dec_ref(tdata); return -262; } /* Port in From header. */ from_hdr = (pjsip_from_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); uri = (pjsip_sip_uri*) pjsip_uri_get_uri(from_hdr->uri); if (uri->port != 0) { PJ_LOG(3,(THIS_FILE, " error: port most not exist in From header")); pjsip_tx_data_dec_ref(tdata); return -270; } /* other_param in From header */ param = pjsip_param_find(&uri->other_param, &pname); if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { PJ_LOG(3,(THIS_FILE, " error: x-param not present in From header")); pjsip_tx_data_dec_ref(tdata); return -271; } /* header param in From header. */ if (!pj_list_empty(&uri->header_param)) { PJ_LOG(3,(THIS_FILE, " error: hparam in From header")); pjsip_tx_data_dec_ref(tdata); return -272; } /* Port in To header. */ to_hdr = (pjsip_to_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); uri = (pjsip_sip_uri*) pjsip_uri_get_uri(to_hdr->uri); if (uri->port != 0) { PJ_LOG(3,(THIS_FILE, " error: port most not exist in To header")); pjsip_tx_data_dec_ref(tdata); return -280; } /* other_param in To header */ param = pjsip_param_find(&uri->other_param, &pname); if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { PJ_LOG(3,(THIS_FILE, " error: x-param not present in To header")); pjsip_tx_data_dec_ref(tdata); return -281; } /* header param in From header. */ if (!pj_list_empty(&uri->header_param)) { PJ_LOG(3,(THIS_FILE, " error: hparam in To header")); pjsip_tx_data_dec_ref(tdata); return -282; } /* Port in Contact header. */ contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL); uri = (pjsip_sip_uri*) pjsip_uri_get_uri(contact_hdr->uri); if (uri->port != 5061) { PJ_LOG(3,(THIS_FILE, " error: port not present in Contact header")); pjsip_tx_data_dec_ref(tdata); return -290; } /* other_param in Contact header */ param = pjsip_param_find(&uri->other_param, &pname); if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { PJ_LOG(3,(THIS_FILE, " error: x-param not present in Contact header")); pjsip_tx_data_dec_ref(tdata); return -291; } /* header param in Contact header. */ if (pj_list_empty(&uri->header_param)) { PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); pjsip_tx_data_dec_ref(tdata); return -292; } /* Check for X-Hdr-1 */ param = pjsip_param_find(&uri->header_param, &hname); if (param == NULL || pj_strcmp2(¶m->value, "Header 1")!=0) { PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); pjsip_tx_data_dec_ref(tdata); return -293; } /* Check for X-Empty-Hdr */ param = pjsip_param_find(&uri->header_param, &hemptyname); if (param == NULL || pj_strcmp2(¶m->value, "")!=0) { PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); pjsip_tx_data_dec_ref(tdata); return -294; } /* Check that headers are present in the request. */ hdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(msg, &hname, NULL); if (hdr == NULL || pj_strcmp2(&hdr->hvalue, "Header 1")!=0) { PJ_LOG(3,(THIS_FILE, " error: header X-Hdr-1 not created")); pjsip_tx_data_dec_ref(tdata); return -300; } hdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(msg, &hemptyname, NULL); if (hdr == NULL || pj_strcmp2(¶m->value, "")!=0) { PJ_LOG(3,(THIS_FILE, " error: header X-Empty-Hdr not created")); pjsip_tx_data_dec_ref(tdata); return -330; } pjsip_tx_data_dec_ref(tdata); return 0; }
void ICSCFSproutletTsx::on_rx_initial_request(pjsip_msg* req) { pj_pool_t* pool = get_pool(req); pjsip_route_hdr* hroute = (pjsip_route_hdr*) pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL); // TS 24.229 says I-CSCF processing shouldn't be done if a message has more than one Route header. // We've stripped one off in Sproutlet processing, so check for a second and just forward the // message if it's there. if (hroute != NULL) { send_request(req); return; } pjsip_uri* next_hop = PJUtils::next_hop(req); URIClass next_hop_class = URIClassifier::classify_uri(next_hop); if (req->line.req.method.id == PJSIP_ACK_METHOD && next_hop == req->line.req.uri && ((next_hop_class == NODE_LOCAL_SIP_URI) || (next_hop_class == HOME_DOMAIN_SIP_URI))) { // Ignore ACK messages with no Route headers and a local Request-URI, as: // - the I-CSCF should not be handling these // - we've seen ACKs matching this descrption being generated at overload and looping repeatedly // // This is a fairly targeted fix for https://github.com/Metaswitch/sprout/issues/1091. // TODO: remove this code when #1091 is fixed by other means. free_msg(req); return; } // Create an ACR for this transaction. _acr = _icscf->get_acr(trail()); _acr->rx_request(req); TRC_DEBUG("I-CSCF initialize transaction for non-REGISTER request"); // Before we clone the request for retries, remove the P-Profile-Key header // if present. PJUtils::remove_hdr(req, &STR_P_PROFILE_KEY); // Determine orig/term and the served user's name. const pjsip_route_hdr* route = route_hdr(); std::string impu; if ((route != NULL) && (pjsip_param_find(&((pjsip_sip_uri*)route->name_addr.uri)->other_param, &STR_ORIG) != NULL)) { // Originating request. TRC_DEBUG("Originating request"); _originating = true; impu = PJUtils::public_id_from_uri(PJUtils::orig_served_user(req)); SAS::Event event(trail(), SASEvent::ICSCF_RCVD_ORIG_NON_REG, 0); event.add_var_param(impu); event.add_var_param(req->line.req.method.name.slen, req->line.req.method.name.ptr); SAS::report_event(event); } else { // Terminating request. TRC_DEBUG("Terminating request"); _originating = false; pjsip_uri* uri = PJUtils::term_served_user(req); // If the Req URI is a SIP URI with the user=phone parameter set, is not a // GRUU and the user part starts with '+' (i.e. is a global phone number), // we should replace it with a tel URI, as per TS24.229 5.3.2.1. if (PJSIP_URI_SCHEME_IS_SIP(uri)) { URIClass uri_class = URIClassifier::classify_uri(uri); pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri; if (uri_class == GLOBAL_PHONE_NUMBER) { TRC_DEBUG("Change request URI from SIP URI to tel URI"); req->line.req.uri = PJUtils::translate_sip_uri_to_tel_uri(sip_uri, pool); } } impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req)); SAS::Event event(trail(), SASEvent::ICSCF_RCVD_TERM_NON_REG, 0); event.add_var_param(impu); event.add_var_param(req->line.req.method.name.slen, req->line.req.method.name.ptr); SAS::report_event(event); } // Create an LIR router to handle the HSS interactions and S-CSCF // selection. _router = (ICSCFRouter*)new ICSCFLIRouter(_icscf->get_hss_connection(), _icscf->get_scscf_selector(), trail(), _acr, _icscf->port(), impu, _originating); pjsip_sip_uri* scscf_sip_uri = NULL; // Use the router we just created to query the HSS for an S-CSCF to use. // TS 32.260 Table 5.2.1.1 says an EVENT ACR should be generated on the // completion of a Cx query issued in response to a SIP INVITE bool do_billing = (req->line.req.method.id == PJSIP_INVITE_METHOD); std::string wildcard; pjsip_status_code status_code = (pjsip_status_code)_router->get_scscf(pool, scscf_sip_uri, wildcard, do_billing); if ((!_originating) && (scscf_not_found(status_code))) { TRC_DEBUG("Couldn't find an S-CSCF, attempt to translate the URI"); pjsip_uri* uri = PJUtils::term_served_user(req); URIClass uri_class = URIClassifier::classify_uri(uri, false); // For terminating processing, if the HSS indicates that the user does not // exist, and if the request URI is a tel URI, try an ENUM translation. If // this succeeds, go back to the HSS. See TS24.229, 5.3.2.1. // // Before doing that we should check whether the enforce_user_phone flag is // set. If it isn't, and we have a numeric SIP URI, it is possible that // this should have been a tel URI, so translate it and do the HSS lookup // again. Once again, only do this for global numbers. if (PJSIP_URI_SCHEME_IS_SIP(uri) && (uri_class == GLOBAL_PHONE_NUMBER)) { TRC_DEBUG("enforce_user_phone set to false, try using a tel URI"); uri = PJUtils::translate_sip_uri_to_tel_uri((pjsip_sip_uri*)uri, pool); req->line.req.uri = uri; // We need to change the IMPU stored on our LIR router so that when // we do a new LIR we look up the new IMPU. impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req)); ((ICSCFLIRouter *)_router)->change_impu(impu); status_code = (pjsip_status_code)_router->get_scscf(pool, scscf_sip_uri, wildcard, do_billing); } if (_icscf->_enum_service) { // If we still haven't found an S-CSCF, we can now try an ENUM lookup. // We put this processing in a loop because in theory we may go round // several times before finding an S-CSCF. In reality this is unlikely // so we set MAX_ENUM_LOOKUPS to 2. for (int ii = 0; (ii < MAX_ENUM_LOOKUPS) && (scscf_not_found(status_code)); ++ii) { if (PJSIP_URI_SCHEME_IS_TEL(uri)) { // Do an ENUM lookup and see if we should translate the TEL URI pjsip_uri* original_req_uri = req->line.req.uri; _icscf->translate_request_uri(req, get_pool(req), trail()); uri = req->line.req.uri; URIClass uri_class = URIClassifier::classify_uri(uri, false, true); std::string rn; if ((uri_class == NP_DATA) || (uri_class == FINAL_NP_DATA)) { // We got number portability information from ENUM - drop out and route to the BGCF. route_to_bgcf(req); return; } else if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, original_req_uri, req->line.req.uri) != PJ_SUCCESS) { // The URI has changed, so make sure we do a LIR lookup on it. impu = PJUtils::public_id_from_uri(req->line.req.uri); ((ICSCFLIRouter *)_router)->change_impu(impu); } // If we successfully translate the req URI and end up with either another TEL URI or a // local SIP URI, we should look for an S-CSCF again. if ((uri_class == LOCAL_PHONE_NUMBER) || (uri_class == GLOBAL_PHONE_NUMBER) || (uri_class == HOME_DOMAIN_SIP_URI)) { // TEL or local SIP URI. Look up the S-CSCF again. status_code = (pjsip_status_code)_router->get_scscf(pool, scscf_sip_uri, wildcard, do_billing); } else { // Number translated to off-switch. Drop out of the loop. ii = MAX_ENUM_LOOKUPS; } } else { // Can't translate the number, skip to the end of the loop. ii = MAX_ENUM_LOOKUPS; } } } else { // The user is not in the HSS and ENUM is not configured. TS 24.229 // says that, as an alternative to ENUM, we can "forward the request to // the transit functionality for subsequent routeing". Let's do that // (currently, we assume the BGCF is the transit functionality, but that // may be made configurable in future). TRC_DEBUG("No ENUM service available - outing request directly to transit function (BGCF)"); route_to_bgcf(req); return; } } URIClass uri_class = URIClassifier::classify_uri(req->line.req.uri); if (status_code == PJSIP_SC_OK) { TRC_DEBUG("Found SCSCF for non-REGISTER"); if (_originating) { // Add the `orig` parameter. pjsip_param* orig_param = PJ_POOL_ALLOC_T(get_pool(req), pjsip_param); pj_strdup(get_pool(req), &orig_param->name, &STR_ORIG); orig_param->value.slen = 0; pj_list_insert_after(&scscf_sip_uri->other_param, orig_param); } // Add the P-Profile-Key header here if we've got a wildcard if (wildcard != "") { add_p_profile_header(wildcard, req); } PJUtils::add_route_header(req, scscf_sip_uri, get_pool(req)); send_request(req); } else if ((uri_class == OFFNET_SIP_URI) || (uri_class == GLOBAL_PHONE_NUMBER)) { // Target is a TEL URI or not in our home domain. Pass to the BGCF. route_to_bgcf(req); } else { // Target is in our home domain, but we failed to find an S-CSCF. This is the final response. pjsip_msg* rsp = create_response(req, status_code); send_response(rsp); free_msg(req); } }
/* Public function to parse multipart message bodies into its parts */ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool, char *buf, pj_size_t len, const pjsip_media_type *ctype, unsigned options) { pj_str_t boundary, delim; char *curptr, *endptr; const pjsip_param *ctype_param; const pj_str_t STR_BOUNDARY = { "boundary", 8 }; pjsip_msg_body *body = NULL; PJ_ASSERT_RETURN(pool && buf && len && ctype && !options, NULL); TRACE_((THIS_FILE, "Started parsing multipart body")); /* Get the boundary value in the ctype */ boundary.ptr = NULL; boundary.slen = 0; ctype_param = pjsip_param_find(&ctype->param, &STR_BOUNDARY); if (ctype_param) { boundary = ctype_param->value; if (boundary.slen>2 && *boundary.ptr=='"') { /* Remove quote */ boundary.ptr++; boundary.slen -= 2; } TRACE_((THIS_FILE, "Boundary is specified: '%.*s'", (int)boundary.slen, boundary.ptr)); } if (!boundary.slen) { /* Boundary not found or not specified. Try to be clever, get * the boundary from the body. */ char *p=buf, *end=buf+len; PJ_LOG(4,(THIS_FILE, "Warning: boundary parameter not found or " "not specified when parsing multipart body")); /* Find the first "--". This "--" must be right after a CRLF, unless * it really appears at the start of the buffer. */ for (;;) { while (p!=end && *p!='-') ++p; if (p!=end && *(p+1)=='-' && ((p>buf && *(p-1)=='\n') || (p==buf))) { p+=2; break; } else { ++p; } } if (p==end) { /* Unable to determine boundary. Maybe this is not a multipart * message? */ PJ_LOG(4,(THIS_FILE, "Error: multipart boundary not specified and" " unable to calculate from the body")); return NULL; } boundary.ptr = p; while (p!=end && !pj_isspace(*p)) ++p; boundary.slen = p - boundary.ptr; TRACE_((THIS_FILE, "Boundary is calculated: '%.*s'", (int)boundary.slen, boundary.ptr)); } /* Build the delimiter: * delimiter = "--" boundary */ delim.slen = boundary.slen+2; delim.ptr = (char*)pj_pool_alloc(pool, (int)delim.slen); delim.ptr[0] = '-'; delim.ptr[1] = '-'; pj_memcpy(delim.ptr+2, boundary.ptr, boundary.slen); /* Start parsing the body, skip until the first delimiter. */ curptr = buf; endptr = buf + len; { pj_str_t body; body.ptr = buf; body.slen = len; curptr = pj_strstr(&body, &delim); if (!curptr) return NULL; } body = pjsip_multipart_create(pool, ctype, &boundary); for (;;) { char *start_body, *end_body; pjsip_multipart_part *part; /* Eat the boundary */ curptr += delim.slen; if (*curptr=='-' && curptr<endptr-1 && *(curptr+1)=='-') { /* Found the closing delimiter */ curptr += 2; break; } /* Optional whitespace after delimiter */ while (curptr!=endptr && IS_SPACE(*curptr)) ++curptr; /* Mandatory CRLF */ if (*curptr=='\r') ++curptr; if (*curptr!='\n') { /* Expecting a newline here */ return NULL; } ++curptr; /* We now in the start of the body */ start_body = curptr; /* Find the next delimiter */ { pj_str_t subbody; subbody.ptr = curptr; subbody.slen = endptr - curptr; curptr = pj_strstr(&subbody, &delim); if (!curptr) { /* We're really expecting end delimiter to be found. */ return NULL; } } end_body = curptr; /* The newline preceeding the delimiter is conceptually part of * the delimiter, so trim it from the body. */ if (*(end_body-1) == '\n') --end_body; if (*(end_body-1) == '\r') --end_body; /* Now that we have determined the part's boundary, parse it * to get the header and body part of the part. */ part = parse_multipart_part(pool, start_body, end_body - start_body, ctype); if (part) { pjsip_multipart_add_part(pool, body, part); } } return body; }
/// Initialise the UAS transaction object. pj_status_t ICSCFProxy::UASTsx::init(pjsip_rx_data* rdata) { // Do the BasicProxy initialization first. pj_status_t status = BasicProxy::UASTsx::init(rdata); pjsip_msg* msg = rdata->msg_info.msg; // Create an ACR if ACR generation is enabled. _acr = create_acr(); // Parse interesting parameters from the request for the later lookups. if (msg->line.req.method.id == PJSIP_REGISTER_METHOD) { // REGISTER request. LOG_DEBUG("I-CSCF initialize transaction for REGISTER request"); _case = SessionCase::REGISTER; std::string impu; std::string impi; std::string visited_network; std::string auth_type; // Get the public identity from the To: header. pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(msg); pjsip_uri* to_uri = (pjsip_uri*)pjsip_uri_get_uri(to_hdr->uri); impu = PJUtils::public_id_from_uri(to_uri); // Get the private identity from the Authentication header, or generate // a default if there is no Authentication header or no username in the // header. pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL); if ((auth_hdr != NULL) && (auth_hdr->credential.digest.username.slen != 0)) { // Get the IMPI from the username. impi = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username); } else { // Create a default IMPI from the IMPU by removing the sip: prefix. impi = impu.substr(4); } // Get the visted network identification if present. If not, homestead will // default it. pjsip_generic_string_hdr* vn_hdr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg, &STR_P_V_N_I, NULL); if (vn_hdr != NULL) { visited_network = PJUtils::pj_str_to_string(&vn_hdr->hvalue); } else if (PJSIP_URI_SCHEME_IS_SIP(to_uri) || PJSIP_URI_SCHEME_IS_SIPS(to_uri)) { // Use the domain of the IMPU as the visited network. visited_network = PJUtils::pj_str_to_string(&((pjsip_sip_uri*)to_uri)->host); } // Work out what authorization type to use by looking at the expiry // values in the request. (Use a default of 1 because if there is no // expires header or expires values in the contact headers this will // be a registration not a deregistration.) auth_type = (PJUtils::max_expires(msg, 1) > 0) ? "REG" : "DEREG"; // Create an UAR router to handle the HSS interactions and S-CSCF // selection. _router = (ICSCFRouter*)new ICSCFUARouter(((ICSCFProxy*)_proxy)->_hss, ((ICSCFProxy*)_proxy)->_scscf_selector, trail(), _acr, impi, impu, visited_network, auth_type); } else { // Non-register request. LOG_DEBUG("I-CSCF initialize transaction for non-REGISTER request"); // Check for a route header containing the orig parameter; pjsip_route_hdr* route = rdata->msg_info.route; std::string impu; if ((route != NULL) && (pjsip_param_find(&((pjsip_sip_uri*)route->name_addr.uri)->other_param, &STR_ORIG) != NULL)) { // Originating request. LOG_DEBUG("Originating request"); _case = SessionCase::ORIGINATING; impu = PJUtils::public_id_from_uri(PJUtils::orig_served_user(msg)); } else { // Terminating request. LOG_DEBUG("Terminating request"); _case = SessionCase::TERMINATING; impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(msg)); } // Create an LIR router to handle the HSS interactions and S-CSCF // selection. _router = (ICSCFRouter*)new ICSCFLIRouter(((ICSCFProxy*)_proxy)->_hss, ((ICSCFProxy*)_proxy)->_scscf_selector, trail(), _acr, impu, (_case == SessionCase::ORIGINATING)); } // Pass the received request to the ACR. _acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp); // Record whether or not this is an in-dialog request. This is needed // to determine whether or not to send interim ACRs on provisional // responses. _in_dialog = (rdata->msg_info.msg->line.req.method.id != PJSIP_BYE_METHOD) && (rdata->msg_info.to->tag.slen != 0); return status; }
void MementoAppServerTsx::on_initial_request(pjsip_msg* req) { TRC_DEBUG("Memento processing an initial request of type %s", (req->line.req.method.id == PJSIP_INVITE_METHOD) ? "INVITE" : "BYE"); // Get the current time time_t rawtime; time(&rawtime); tm* start_time = localtime(&rawtime); _start_time_xml = create_formatted_timestamp(start_time, XML_PATTERN); _start_time_cassandra = create_formatted_timestamp(start_time, TIMESTAMP_PATTERN); // Is the call originating or terminating? std::string served_user; pjsip_routing_hdr* psu_hdr = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(req, &P_SERVED_USER, NULL); if (psu_hdr != NULL) { pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(&psu_hdr->name_addr); served_user = uri_to_string(PJSIP_URI_IN_ROUTING_HDR, uri); pjsip_param* sescase = pjsip_param_find(&psu_hdr->other_param, &SESCASE); if ((sescase != NULL) && (pj_stricmp(&sescase->value, &ORIG) == 0)) { TRC_DEBUG("Request is originating"); _outgoing = true; } } // Get the caller, callee and impu values if (_outgoing) { // Get the callee's URI amd name from the To header. _callee_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(req)->uri)); _callee_name = pj_str_to_string(&((pjsip_name_addr*) (PJSIP_MSG_TO_HDR(req)->uri))->display); // Get the caller's URI and name from the P-Asserted Identity header. If // this is missing, use the From header. pjsip_routing_hdr* asserted_id = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(req, &P_ASSERTED_IDENTITY, NULL); if (asserted_id != NULL) { _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(&asserted_id->name_addr)); _caller_name = pj_str_to_string(&asserted_id->name_addr.display); } else { TRC_WARNING("INVITE missing P-Asserted-Identity"); send_request(req); return; } // Set the IMPU equal to the caller's URI _impu = _caller_uri; } else { // Get the callee's URI from the request URI. There can be no name value. _callee_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, req->line.req.uri); // Get the caller's URI and name from the From header. _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_FROM_HDR(req)->uri)); _caller_name = pj_str_to_string(&((pjsip_name_addr*) (PJSIP_MSG_FROM_HDR(req)->uri))->display); // Set the IMPU equal to the callee's URI _impu = _callee_uri; } // Add a unique ID containing the IMPU to the record route header. // This has the format: // <YYYYMMDDHHMMSS>_<unique_id>_<base64 encoded impu>.memento.<home domain> _unique_id = std::to_string(Utils::generate_unique_integer(0,0)); std::string encoded_impu = base64_encode(reinterpret_cast<const unsigned char*>(_impu.c_str()), _impu.length()); std::string dialog_id = std::string(_start_time_cassandra). append("_"). append(_unique_id). append("_"). append(encoded_impu); add_to_dialog(dialog_id); send_request(req); }
static pjsip_param *get_diversion_reason(pjsip_fromto_hdr *hdr) { static const pj_str_t reason_str = { "reason", 6 }; return pjsip_param_find(&hdr->other_param, &reason_str); }
/// Creates a MangelwurzelTsx instance. SproutletTsx* Mangelwurzel::get_tsx(SproutletHelper* helper, const std::string& alias, pjsip_msg* req, pjsip_sip_uri*& next_hop, pj_pool_t* pool, SAS::TrailId trail) { MangelwurzelTsx::Config config; // Find the mangewurzel Route header, parse the parameters and use them to // build a Config object. Then construct the MangelwurzelTsx. pjsip_route_hdr* route_hdr = (pjsip_route_hdr*) pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL); pjsip_sip_uri* mangelwurzel_uri; if (route_hdr != NULL) { mangelwurzel_uri = (pjsip_sip_uri*)route_hdr->name_addr.uri; } else { mangelwurzel_uri = (pjsip_sip_uri*)req->line.req.uri; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &DIALOG_PARAM) != NULL) { config.dialog = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &REQ_URI_PARAM) != NULL) { config.req_uri = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &TO_PARAM) != NULL) { config.to = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &ROUTES_PARAM) != NULL) { config.routes = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &DOMAIN_PARAM) != NULL) { config.change_domain = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &ORIG_PARAM) != NULL) { config.orig = true; } if (pjsip_param_find(&mangelwurzel_uri->other_param, &OOTB_PARAM) != NULL) { config.ootb = true; } // The mangalgorithm defaults to ROT_13, so only change it if REVERSE is // specified, but raise a log if an invalid mangalgorithm is specified. pjsip_param* mangalgorithm_param = pjsip_param_find(&mangelwurzel_uri->other_param, &MANGALGORITHM_PARAM); if (mangalgorithm_param != NULL) { std::string mangalgorithm = PJUtils::pj_str_to_string(&mangalgorithm_param->value); if (mangalgorithm == REVERSE_MANGALGORITHM) { config.mangalgorithm = MangelwurzelTsx::REVERSE; } else if (mangalgorithm != ROT_13_MANGALGORITHM) { TRC_ERROR("Invalid mangalgorithm specified: %s", mangalgorithm.c_str()); SAS::Event event(trail, SASEvent::INVALID_MANGALGORITHM, 0); event.add_var_param(mangalgorithm); SAS::report_event(event); } } return new MangelwurzelTsx(this, config); }
// Determine the type of a URI. // // Parameters: // // - uri - the URI to classify // - prefer_sip - for ambiguous URIs like sip:[email protected] (which could be a global phone // number or just a SIP URI), prefer to interpret it as SIP // URIClass URIClassifier::classify_uri(const pjsip_uri* uri, bool prefer_sip) { URIClass ret = URIClass::UNKNOWN; // First, check to see if this URI has number portability data - this takes priority bool has_rn = false; bool has_npdi = false; if (PJSIP_URI_SCHEME_IS_TEL(uri)) { // If the URI is a tel URI, pull out the information from the other_params has_rn = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_RN) != NULL); has_npdi = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_NPDI) != NULL); } else if (PJSIP_URI_SCHEME_IS_SIP(uri)) { // If the URI is a tel URI, pull out the information from the userinfo_params has_rn = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_RN) != NULL); has_npdi = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_NPDI) != NULL); } if (has_rn) { if (has_npdi) { ret = FINAL_NP_DATA; } else { ret = NP_DATA; } } // No number portability data else if (PJSIP_URI_SCHEME_IS_TEL(uri)) { // TEL URIs can only represent phone numbers - decide if it's a global (E.164) number or not pjsip_tel_uri* tel_uri = (pjsip_tel_uri*)uri; if (tel_uri->number.slen > 0 && tel_uri->number.ptr[0] == '+') { ret = GLOBAL_PHONE_NUMBER; } else { ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER; } } else if (PJSIP_URI_SCHEME_IS_SIP(uri)) { pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri; pj_str_t host = sip_uri->host; bool home_domain = is_home_domain(host); bool local_to_node = is_local_name(host); bool is_gruu = (pjsip_param_find(&((pjsip_sip_uri*)uri)->other_param, &STR_GR) != NULL); bool treat_number_as_phone = !enforce_user_phone && !prefer_sip; TRC_DEBUG("home domain: %s, local_to_node: %s, is_gruu: %s, enforce_user_phone: %s, prefer_sip: %s, treat_number_as_phone: %s", home_domain ? "true" : "false", local_to_node ? "true" : "false", is_gruu ? "true" : "false", enforce_user_phone ? "true" : "false", prefer_sip ? "true" : "false", treat_number_as_phone ? "true" : "false"); // SIP URI that's 'really' a phone number - apply the same logic as for TEL URIs if ((!pj_strcmp(&((pjsip_sip_uri*)uri)->user_param, &STR_USER_PHONE) || (home_domain && treat_number_as_phone && !is_gruu))) { if (sip_uri->user.slen > 0 && sip_uri->user.ptr[0] == '+') { ret = GLOBAL_PHONE_NUMBER; } else { ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER; } } // Not a phone number - classify it based on domain else if (home_domain) { ret = HOME_DOMAIN_SIP_URI; } else if (local_to_node) { ret = NODE_LOCAL_SIP_URI; } else { ret = OFFNET_SIP_URI; } } TRC_DEBUG("Classified URI as %d", (int)ret); return ret; }
pj_bool_t authenticate_rx_request(pjsip_rx_data* rdata) { pj_status_t status; std::string resync; SAS::TrailId trail = get_trail(rdata); if (rdata->tp_info.transport->local_name.port != stack_data.scscf_port) { // Request not received on S-CSCF port, so don't authenticate it. std::string error_msg = "Request wasn't received on S-CSCF port"; log_sas_auth_not_needed_event(trail, error_msg); return PJ_FALSE; } if (rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD) { // Non-REGISTER request, so don't do authentication as it must have come // from an authenticated or trusted source. std::string error_msg = "Request wasn't a REGISTER"; log_sas_auth_not_needed_event(trail, error_msg); return PJ_FALSE; } // Authentication isn't required for emergency registrations. An emergency // registration is one where each Contact header contains 'sos' as the SIP // URI parameter. bool emergency_reg = true; pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); while ((contact_hdr != NULL) && (emergency_reg)) { emergency_reg = PJUtils::is_emergency_registration(contact_hdr); contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next); } if (emergency_reg) { std::string error_msg = "Request is an emergency REGISTER"; log_sas_auth_not_needed_event(trail, error_msg); return PJ_FALSE; } // Check to see if the request has already been integrity protected? pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL); if ((auth_hdr != NULL) && (auth_hdr->credential.digest.response.slen == 0)) { // There is an authorization header with no challenge response, so check // for the integrity-protected indication. LOG_DEBUG("Authorization header in request with no challenge response"); pjsip_param* integrity = pjsip_param_find(&auth_hdr->credential.digest.other_param, &STR_INTEGRITY_PROTECTED); // Request has an integrity protected indication, so let it through if // it is set to a "yes" value. if ((integrity != NULL) && ((pj_stricmp(&integrity->value, &STR_YES) == 0) || (pj_stricmp(&integrity->value, &STR_TLS_YES) == 0) || (pj_stricmp(&integrity->value, &STR_IP_ASSOC_YES) == 0))) { // Request is already integrity protected, so let it through. LOG_INFO("Request integrity protected by edge proxy"); std::string error_msg = "Request integrity protected by edge proxy"; log_sas_auth_not_needed_event(trail, error_msg); return PJ_FALSE; } } int sc = PJSIP_SC_UNAUTHORIZED; status = PJSIP_EAUTHNOAUTH; if ((auth_hdr != NULL) && (auth_hdr->credential.digest.response.slen != 0)) { std::string impi = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username); std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce); uint64_t cas = 0; Json::Value* av = av_store->get_av(impi, nonce, cas, trail); // Request contains a response to a previous challenge, so pass it to // the authentication module to verify. LOG_DEBUG("Verify authentication information in request"); status = pjsip_auth_srv_verify2(&auth_srv, rdata, &sc, (void*)av); if (status == PJ_SUCCESS) { // The authentication information in the request was verified. LOG_DEBUG("Request authenticated successfully"); SAS::Event event(trail, SASEvent::AUTHENTICATION_SUCCESS, 0); SAS::report_event(event); (*av)["tombstone"] = Json::Value("true"); bool rc = av_store->set_av(impi, nonce, av, cas, trail); if (!rc) { // LCOV_EXCL_START LOG_ERROR("Tried to tombstone AV for %s/%s after processing an authentication, but failed", impi.c_str(), nonce.c_str()); // LCOV_EXCL_STOP } // If doing AKA authentication, check for an AUTS parameter. We only // check this if the request authenticated as actioning it otherwise // is a potential denial of service attack. if (!pj_strcmp(&auth_hdr->credential.digest.algorithm, &STR_AKAV1_MD5)) { LOG_DEBUG("AKA authentication so check for client resync request"); pjsip_param* p = pjsip_param_find(&auth_hdr->credential.digest.other_param, &STR_AUTS); if (p != NULL) { // Found AUTS parameter, so UE is requesting a resync. We need to // redo the authentication, passing an auts parameter to the HSS // comprising the first 16 octets of the nonce (RAND) and the 14 // octets of the auts parameter. (See TS 33.203 and table 6.3.3 of // TS 29.228 for details.) LOG_DEBUG("AKA SQN resync request from UE"); std::string auts = PJUtils::pj_str_to_string(&p->value); std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce); if ((auts.length() != 14) || (nonce.length() != 32)) { // AUTS and/or nonce are malformed, so reject the request. LOG_WARNING("Invalid auts/nonce on resync request from private identity %.*s", auth_hdr->credential.digest.username.slen, auth_hdr->credential.digest.username.ptr); status = PJSIP_EAUTHINAKACRED; sc = PJSIP_SC_FORBIDDEN; } else { // auts and nonce are as expected, so create the resync string // that needs to be passed to the HSS, and act as if no // authentication information was received. resync = nonce.substr(0,16) + auts; status = PJSIP_EAUTHNOAUTH; sc = PJSIP_SC_UNAUTHORIZED; } } } if (status == PJ_SUCCESS) { // Request authentication completed, so let the message through to // other modules. delete av; return PJ_FALSE; } } delete av; } // The message either has insufficient authentication information, or // has failed authentication. In either case, the message will be // absorbed and responded to by the authentication module, so we need to // add SAS markers so the trail will become searchable. SAS::Marker start_marker(trail, MARKER_ID_START, 1u); SAS::report_marker(start_marker); PJUtils::report_sas_to_from_markers(trail, rdata->msg_info.msg); PJUtils::mark_sas_call_branch_ids(trail, NULL, rdata->msg_info.msg); // Add a SAS end marker SAS::Marker end_marker(trail, MARKER_ID_END, 1u); SAS::report_marker(end_marker); // Create an ACR for the message and pass the request to it. ACR* acr = acr_factory->get_acr(trail, CALLING_PARTY, ACR::requested_node_role(rdata->msg_info.msg)); acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp); pjsip_tx_data* tdata; if ((status == PJSIP_EAUTHNOAUTH) || (status == PJSIP_EAUTHACCNOTFOUND)) { // No authorization information in request, or no authentication vector // found in the store (so request is likely stale), so must issue // challenge. LOG_DEBUG("No authentication information in request or stale nonce, so reject with challenge"); sc = PJSIP_SC_UNAUTHORIZED; status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata); if (status != PJ_SUCCESS) { // Failed to create a response. This really shouldn't happen, but there // is nothing else we can do. // LCOV_EXCL_START delete acr; return PJ_TRUE; // LCOV_EXCL_STOP } create_challenge(auth_hdr, resync, rdata, tdata); } else { // Authentication failed. std::string error_msg = PJUtils::pj_status_to_string(status); LOG_ERROR("Authentication failed, %s", error_msg.c_str()); SAS::Event event(trail, SASEvent::AUTHENTICATION_FAILED, 0); event.add_var_param(error_msg); SAS::report_event(event); if (sc != PJSIP_SC_UNAUTHORIZED) { // Notify Homestead and the HSS that this authentication attempt // has definitively failed. std::string impi; std::string impu; PJUtils::get_impi_and_impu(rdata, impi, impu); hss->update_registration_state(impu, impi, HSSConnection::AUTH_FAIL, 0); } if (analytics != NULL) { analytics->auth_failure(PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username), PJUtils::public_id_from_uri((pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri))); } // @TODO - need more diagnostics here so we can identify and flag // attacks. status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata); if (status != PJ_SUCCESS) { // Failed to create a response. This really shouldn't happen, but there // is nothing else we can do. // LCOV_EXCL_START delete acr; return PJ_TRUE; // LCOV_EXCL_STOP } } acr->tx_response(tdata->msg); status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL); // Send the ACR. acr->send_message(); delete acr; return PJ_TRUE; }
void create_challenge(pjsip_authorization_hdr* auth_hdr, std::string resync, pjsip_rx_data* rdata, pjsip_tx_data* tdata) { // Get the public and private identities from the request. std::string impi; std::string impu; std::string nonce; PJUtils::get_impi_and_impu(rdata, impi, impu); // Set up the authorization type, following Annex P.4 of TS 33.203. Currently // only support AKA and SIP Digest, so only implement the subset of steps // required to distinguish between the two. std::string auth_type; if (auth_hdr != NULL) { pjsip_param* integrity = pjsip_param_find(&auth_hdr->credential.digest.other_param, &STR_INTEGRITY_PROTECTED); if ((integrity != NULL) && ((pj_stricmp(&integrity->value, &STR_YES) == 0) || (pj_stricmp(&integrity->value, &STR_NO) == 0))) { // Authentication scheme is AKA. auth_type = "aka"; } } // Get the Authentication Vector from the HSS. Json::Value* av = NULL; HTTPCode http_code = hss->get_auth_vector(impi, impu, auth_type, resync, av, get_trail(rdata)); if ((av != NULL) && (!verify_auth_vector(av, impi, get_trail(rdata)))) { // Authentication Vector is badly formed. delete av; av = NULL; } if (av != NULL) { // Retrieved a valid authentication vector, so generate the challenge. LOG_DEBUG("Valid AV - generate challenge"); char buf[16]; pj_str_t random; random.ptr = buf; random.slen = sizeof(buf); LOG_DEBUG("Create WWW-Authenticate header"); pjsip_www_authenticate_hdr* hdr = pjsip_www_authenticate_hdr_create(tdata->pool); // Set up common fields for Digest and AKA cases (both are considered // Digest authentication). hdr->scheme = STR_DIGEST; if (av->isMember("aka")) { // AKA authentication. LOG_DEBUG("Add AKA information"); SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE, 0); std::string AKA = "AKA"; event.add_var_param(AKA); SAS::report_event(event); Json::Value& aka = (*av)["aka"]; // Use default realm for AKA as not specified in the AV. pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &aka_realm); hdr->challenge.digest.algorithm = STR_AKAV1_MD5; nonce = aka["challenge"].asString(); pj_strdup2(tdata->pool, &hdr->challenge.digest.nonce, nonce.c_str()); pj_create_random_string(buf, sizeof(buf)); pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random); hdr->challenge.digest.qop = STR_AUTH; hdr->challenge.digest.stale = PJ_FALSE; // Add the cryptography key parameter. pjsip_param* ck_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param)); ck_param->name = STR_CK; std::string ck = "\"" + aka["cryptkey"].asString() + "\""; pj_strdup2(tdata->pool, &ck_param->value, ck.c_str()); pj_list_insert_before(&hdr->challenge.digest.other_param, ck_param); // Add the integrity key parameter. pjsip_param* ik_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param)); ik_param->name = STR_IK; std::string ik = "\"" + aka["integritykey"].asString() + "\""; pj_strdup2(tdata->pool, &ik_param->value, ik.c_str()); pj_list_insert_before(&hdr->challenge.digest.other_param, ik_param); } else { // Digest authentication. LOG_DEBUG("Add Digest information"); SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE, 0); std::string DIGEST = "DIGEST"; event.add_var_param(DIGEST); SAS::report_event(event); Json::Value& digest = (*av)["digest"]; pj_strdup2(tdata->pool, &hdr->challenge.digest.realm, digest["realm"].asCString()); hdr->challenge.digest.algorithm = STR_MD5; pj_create_random_string(buf, sizeof(buf)); nonce.assign(buf, sizeof(buf)); pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random); pj_create_random_string(buf, sizeof(buf)); pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random); pj_strdup2(tdata->pool, &hdr->challenge.digest.qop, digest["qop"].asCString()); hdr->challenge.digest.stale = PJ_FALSE; } // Add the header to the message. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); // Store the branch parameter in memcached for correlation purposes pjsip_via_hdr* via_hdr = (pjsip_via_hdr*)pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL); std::string branch = (via_hdr != NULL) ? PJUtils::pj_str_to_string(&via_hdr->branch_param) : ""; (*av)["branch"] = branch; // Write the authentication vector (as a JSON string) into the AV store. LOG_DEBUG("Write AV to store"); uint64_t cas = 0; bool success = av_store->set_av(impi, nonce, av, cas, get_trail(rdata)); if (success) { // We've written the AV into the store, so need to set a Chronos // timer so that an AUTHENTICATION_TIMEOUT SAR is sent to the // HSS when it expires. std::string timer_id; std::string chronos_body = "{\"impi\": \"" + impi + "\", \"impu\": \"" + impu +"\", \"nonce\": \"" + nonce +"\"}"; LOG_DEBUG("Sending %s to Chronos to set AV timer", chronos_body.c_str()); chronos->send_post(timer_id, 30, "/authentication-timeout", chronos_body, 0); } delete av; } else { std::string error_msg; // If we couldn't get the AV because a downstream node is overloaded then don't return // a 4xx error to the client. if ((http_code == HTTP_SERVER_UNAVAILABLE) || (http_code == HTTP_GATEWAY_TIMEOUT)) { error_msg = "Downstream node is overloaded or unresponsive, unable to get Authentication vector"; LOG_DEBUG(error_msg.c_str()); tdata->msg->line.status.code = PJSIP_SC_SERVER_TIMEOUT; tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_SERVER_TIMEOUT); } else { error_msg = "Failed to get Authentication vector"; LOG_DEBUG(error_msg.c_str()); tdata->msg->line.status.code = PJSIP_SC_FORBIDDEN; tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_FORBIDDEN); } SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_FAILED, 0); event.add_var_param(error_msg); SAS::report_event(event); pjsip_tx_data_invalidate_msg(tdata); } }
pj_bool_t authenticate_rx_request(pjsip_rx_data* rdata) { TRC_DEBUG("Authentication module invoked"); pj_status_t status; bool is_register = (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD); SNMP::SuccessFailCountTable* auth_stats_table = NULL; std::string resync; SAS::TrailId trail = get_trail(rdata); if (!needs_authentication(rdata, trail)) { TRC_DEBUG("Request does not need authentication"); return PJ_FALSE; } TRC_DEBUG("Request needs authentication"); rapidjson::Document* av = NULL; const int unauth_sc = is_register ? PJSIP_SC_UNAUTHORIZED : PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED; int sc = unauth_sc; status = PJSIP_EAUTHNOAUTH; pjsip_digest_credential* credentials = get_credentials(rdata); if ((credentials != NULL) && (credentials->response.slen != 0)) { std::string impi = PJUtils::pj_str_to_string(&credentials->username); std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce); uint64_t cas = 0; av = av_store->get_av(impi, nonce, cas, trail); if (!is_register) { // Challenged non-register requests must be SIP digest, so only one table // needed for this case. auth_stats_table = auth_stats_tables->non_register_auth_tbl; } else { if (!pj_strcmp2(&credentials->algorithm, "MD5")) { auth_stats_table = auth_stats_tables->sip_digest_auth_tbl; } else if (!pj_strcmp2(&credentials->algorithm, "AKAv1-MD5")) { auth_stats_table = auth_stats_tables->ims_aka_auth_tbl; } else { // Authorization header did not specify an algorithm, so check the av for // this information instead. if ((av != NULL) && (av->HasMember("aka"))) { auth_stats_table = auth_stats_tables->ims_aka_auth_tbl; } else { // Use the digest table if the AV specified digest, or as a fallback if there was no AV auth_stats_table = auth_stats_tables->sip_digest_auth_tbl; } } } if (auth_stats_table != NULL) { auth_stats_table->increment_attempts(); } // Request contains a response to a previous challenge, so pass it to // the authentication module to verify. TRC_DEBUG("Verify authentication information in request"); status = pjsip_auth_srv_verify2((is_register ? &auth_srv : &auth_srv_proxy), rdata, &sc, (void*)av); if (status == PJ_SUCCESS) { // The authentication information in the request was verified. TRC_DEBUG("Request authenticated successfully"); SAS::Event event(trail, SASEvent::AUTHENTICATION_SUCCESS, 0); SAS::report_event(event); if (auth_stats_table != NULL) { auth_stats_table->increment_successes(); } // Write a tombstone flag back to the AV store, handling contention. // We don't actually expect anything else to be writing to this row in // the AV store, but there is a window condition where we failed to read // from the primary, successfully read from the backup (with a different // CAS value) and then try to write back to the primary, which fails due // to "contention". Store::Status store_status; do { // Set the tomestone flag in the JSON authentication vector. rapidjson::Value tombstone_value; tombstone_value.SetBool(true); av->AddMember("tombstone", tombstone_value, (*av).GetAllocator()); // Store it. If this fails due to contention, read the updated JSON. store_status = av_store->set_av(impi, nonce, av, cas, trail); if (store_status == Store::DATA_CONTENTION) { // LCOV_EXCL_START - No support for contention in UT TRC_DEBUG("Data contention writing tombstone - retry"); delete av; av = av_store->get_av(impi, nonce, cas, trail); if (av == NULL) { store_status = Store::ERROR; } // LCOV_EXCL_STOP } } while (store_status == Store::DATA_CONTENTION); if (store_status != Store::OK) { // LCOV_EXCL_START TRC_ERROR("Tried to tombstone AV for %s/%s after processing an authentication, but failed", impi.c_str(), nonce.c_str()); // LCOV_EXCL_STOP } // If doing AKA authentication, check for an AUTS parameter. We only // check this if the request authenticated as actioning it otherwise // is a potential denial of service attack. if (!pj_strcmp(&credentials->algorithm, &STR_AKAV1_MD5)) { TRC_DEBUG("AKA authentication so check for client resync request"); pjsip_param* p = pjsip_param_find(&credentials->other_param, &STR_AUTS); if (p != NULL) { // Found AUTS parameter, so UE is requesting a resync. We need to // redo the authentication, passing an auts parameter to the HSS // comprising the first 16 octets of the nonce (RAND) and the 14 // octets of the auts parameter. (See TS 33.203 and table 6.3.3 of // TS 29.228 for details.) TRC_DEBUG("AKA SQN resync request from UE"); std::string auts = PJUtils::pj_str_to_string(&p->value); std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce); // Convert the auts and nonce to binary for manipulation nonce = base64_decode(nonce); auts = base64_decode(auts); if ((auts.length() != 14) || (nonce.length() != 32)) { // AUTS and/or nonce are malformed, so reject the request. TRC_WARNING("Invalid auts/nonce on resync request from private identity %.*s", credentials->username.slen, credentials->username.ptr); status = PJSIP_EAUTHINAKACRED; sc = PJSIP_SC_FORBIDDEN; } else { // auts and nonce are as expected, so create the resync string // that needs to be passed to the HSS, and act as if no // authentication information was received. The resync string // should be RAND || AUTS. resync = base64_encode(nonce.substr(0, 16) + auts); status = PJSIP_EAUTHNOAUTH; sc = unauth_sc; } } } if (status == PJ_SUCCESS) { // Request authentication completed, so let the message through to other // modules. Remove any Proxy-Authorization headers first so they are not // passed to downstream devices. We can't do this for Authorization // headers, as these may need to be included in 3rd party REGISTER // messages. while (pjsip_msg_find_remove_hdr(rdata->msg_info.msg, PJSIP_H_PROXY_AUTHORIZATION, NULL) != NULL); delete av; return PJ_FALSE; } } } // The message either has insufficient authentication information, or // has failed authentication. In either case, the message will be // absorbed and responded to by the authentication module, so we need to // add SAS markers so the trail will become searchable. SAS::Marker start_marker(trail, MARKER_ID_START, 1u); SAS::report_marker(start_marker); // Add a SAS end marker SAS::Marker end_marker(trail, MARKER_ID_END, 1u); SAS::report_marker(end_marker); // Create an ACR for the message and pass the request to it. Role is always // considered originating for a REGISTER request. ACR* acr = acr_factory->get_acr(trail, CALLING_PARTY, NODE_ROLE_ORIGINATING); acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp); pjsip_tx_data* tdata; if ((status == PJSIP_EAUTHNOAUTH) || (status == PJSIP_EAUTHACCNOTFOUND)) { // No authorization information in request, or no authentication vector // found in the store (so request is likely stale), so must issue // challenge. TRC_DEBUG("No authentication information in request or stale nonce, so reject with challenge"); pj_bool_t stale = (status == PJSIP_EAUTHACCNOTFOUND); sc = unauth_sc; if (stale && auth_stats_table != NULL) { auth_stats_table->increment_failures(); } status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata); if (status != PJ_SUCCESS) { // Failed to create a response. This really shouldn't happen, but there // is nothing else we can do. // LCOV_EXCL_START delete acr; return PJ_TRUE; // LCOV_EXCL_STOP } create_challenge(credentials, stale, resync, rdata, tdata); } else { // Authentication failed. std::string error_msg = PJUtils::pj_status_to_string(status); TRC_ERROR("Authentication failed, %s", error_msg.c_str()); if (auth_stats_table != NULL) { auth_stats_table->increment_failures(); } SAS::Event event(trail, SASEvent::AUTHENTICATION_FAILED, 0); event.add_var_param(error_msg); SAS::report_event(event); if (sc != unauth_sc) { // Notify Homestead and the HSS that this authentication attempt // has definitively failed. std::string impi; std::string impu; PJUtils::get_impi_and_impu(rdata, impi, impu); hss->update_registration_state(impu, impi, HSSConnection::AUTH_FAIL, trail); } if (analytics != NULL) { analytics->auth_failure(PJUtils::pj_str_to_string(&credentials->username), PJUtils::public_id_from_uri((pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri))); } status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata); if (status != PJ_SUCCESS) { // Failed to create a response. This really shouldn't happen, but there // is nothing else we can do. // LCOV_EXCL_START delete acr; return PJ_TRUE; // LCOV_EXCL_STOP } } acr->tx_response(tdata->msg); // Issue the challenge response transaction-statefully. This is so that: // * if we challenge an INVITE, the UE can ACK the 407 // * if a challenged request gets retransmitted, we don't repeat the work pjsip_transaction* tsx = NULL; status = pjsip_tsx_create_uas2(NULL, rdata, NULL, &tsx); set_trail(tsx, trail); if (status != PJ_SUCCESS) { // LCOV_EXCL_START - defensive code not hit in UT TRC_WARNING("Couldn't create PJSIP transaction for authentication response: %d" " (sending statelessly instead)", status); // Send the response statelessly in this case - it's better than nothing pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL); // LCOV_EXCL_STOP } else { // Let the tsx know about the original message pjsip_tsx_recv_msg(tsx, rdata); // Send our response in this transaction pjsip_tsx_send_msg(tsx, tdata); } // Send the ACR. acr->send(); delete acr; delete av; return PJ_TRUE; }
// Determine whether this request should be challenged (and SAS log appropriately). static pj_bool_t needs_authentication(pjsip_rx_data* rdata, SAS::TrailId trail) { if (rdata->tp_info.transport->local_name.port != stack_data.scscf_port) { TRC_DEBUG("Request does not need authentication - not on S-CSCF port"); // Request not received on S-CSCF port, so don't authenticate it. SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_NOT_SCSCF_PORT, 0); SAS::report_event(event); return PJ_FALSE; } if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) { // Authentication isn't required for emergency registrations. An emergency // registration is one where each Contact header contains 'sos' as the SIP // URI parameter. bool emergency_reg = true; pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); while ((contact_hdr != NULL) && (emergency_reg)) { emergency_reg = PJUtils::is_emergency_registration(contact_hdr); contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next); } if (emergency_reg) { SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_EMERGENCY_REGISTER, 0); SAS::report_event(event); return PJ_FALSE; } // Check to see if the request has already been integrity protected? pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL); if (auth_hdr != NULL) { // There is an authorization header, so check for the integrity-protected // indication. TRC_DEBUG("Authorization header in request"); pjsip_param* integrity = pjsip_param_find(&auth_hdr->credential.digest.other_param, &STR_INTEGRITY_PROTECTED); if ((integrity != NULL) && ((pj_stricmp(&integrity->value, &STR_TLS_YES) == 0) || (pj_stricmp(&integrity->value, &STR_IP_ASSOC_YES) == 0))) { // The integrity protected indicator is included and set to tls-yes or // ip-assoc-yes. This indicates the client has already been authenticated // so we will accept this REGISTER even if there is a challenge response. // (Values of tls-pending or ip-assoc-pending indicate the challenge // should be checked.) TRC_INFO("SIP Digest authenticated request integrity protected by edge proxy"); SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_INTEGRITY_PROTECTED, 0); SAS::report_event(event); return PJ_FALSE; } else if ((integrity != NULL) && (pj_stricmp(&integrity->value, &STR_YES) == 0) && (auth_hdr->credential.digest.response.slen == 0)) { // The integrity protected indicator is include and set to yes. This // indicates that AKA authentication is in use and the REGISTER was // received on an integrity protected channel, so we will let the // request through if there is no challenge response, but must check // the challenge response if included. TRC_INFO("AKA authenticated request integrity protected by edge proxy"); SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_INTEGRITY_PROTECTED, 1); SAS::report_event(event); return PJ_FALSE; } } return PJ_TRUE; } else { if (PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->tag.slen != 0) { // This is an in-dialog request which needs no authentication. return PJ_FALSE; } // Check to see if we should authenticate this non-REGISTER message - this if (non_register_auth_mode == NonRegisterAuthentication::NEVER) { // Configured to never authenticate non-REGISTER requests. SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_NEVER_AUTH_NON_REG, 0); SAS::report_event(event); return PJ_FALSE; } else if (non_register_auth_mode == NonRegisterAuthentication::IF_PROXY_AUTHORIZATION_PRESENT) { // Only authenticate the request if it has a Proxy-Authorization header. pjsip_proxy_authorization_hdr* auth_hdr = (pjsip_proxy_authorization_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_PROXY_AUTHORIZATION, NULL); if (auth_hdr != NULL) { // Edge proxy has explicitly asked us to authenticate this non-REGISTER // message SAS::Event event(trail, SASEvent::AUTHENTICATION_NEEDED_PROXY_AUTHORIZATION, 0); SAS::report_event(event); return PJ_TRUE; } else { // No Proxy-Authorization header - this indicates the P-CSCF trusts this // message so we don't need to perform further authentication. SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_PROXY_AUTHORIZATION, 0); SAS::report_event(event); return PJ_FALSE; } } else { // Unrecognized authentication mode - should never happen. LCOV_EXCL_START assert(!"Unrecognized authentication mode"); return PJ_FALSE; // LCOV_EXCL_STOP } } }
pj_status_t user_lookup(pj_pool_t *pool, const pjsip_auth_lookup_cred_param *param, pjsip_cred_info *cred_info, void* av_param) { const pj_str_t* acc_name = ¶m->acc_name; const pj_str_t* realm = ¶m->realm; const pjsip_rx_data* rdata = param->rdata; SAS::TrailId trail = get_trail(rdata); pj_status_t status = PJSIP_EAUTHACCNOTFOUND; // Get the impi and the nonce. There must be an authorization header otherwise // PJSIP wouldn't have called this method. std::string impi = PJUtils::pj_str_to_string(acc_name); pjsip_digest_credential* credentials = get_credentials(rdata); std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce); // Get the Authentication Vector from the store. rapidjson::Document* av = (rapidjson::Document*)av_param; if (av == NULL) { TRC_WARNING("Received an authentication request for %s with nonce %s, but no matching AV found", impi.c_str(), nonce.c_str()); } if ((av != NULL) && (!verify_auth_vector(av, impi, trail))) { // Authentication vector is badly formed. av = NULL; // LCOV_EXCL_LINE } if (av != NULL) { pj_cstr(&cred_info->scheme, "digest"); pj_strdup(pool, &cred_info->username, acc_name); if (av->HasMember("aka")) { pjsip_param* auts_param = pjsip_param_find(&credentials->other_param, &STR_AUTS); // AKA authentication. The response in the AV must be used as a // plain-text password for the MD5 Digest computation. Convert the text // into binary as this is what PJSIP is expecting. If we find the 'auts' // parameter, then leave the response as the empty string in accordance // with RFC 3310. std::string response = ""; if (((*av)["aka"].HasMember("response")) && ((*av)["aka"]["response"].IsString()) && auts_param == NULL) { response = (*av)["aka"]["response"].GetString(); } std::string xres; for (size_t ii = 0; ii < response.length(); ii += 2) { xres.push_back((char)(pj_hex_digit_to_val(response[ii]) * 16 + pj_hex_digit_to_val(response[ii+1]))); } cred_info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; pj_strdup2(pool, &cred_info->data, xres.c_str()); TRC_DEBUG("Found AKA XRES = %.*s", cred_info->data.slen, cred_info->data.ptr); // Use default realm as it isn't specified in the AV. pj_strdup(pool, &cred_info->realm, realm); status = PJ_SUCCESS; } else if (av->HasMember("digest")) { std::string digest_realm = ""; if (((*av)["digest"].HasMember("realm")) && ((*av)["digest"]["realm"].IsString())) { digest_realm = (*av)["digest"]["realm"].GetString(); } if (pj_strcmp2(realm, digest_realm.c_str()) == 0) { // Digest authentication, so ha1 field is hashed password. cred_info->data_type = PJSIP_CRED_DATA_DIGEST; std::string digest_ha1 = ""; if (((*av)["digest"].HasMember("ha1")) && ((*av)["digest"]["ha1"].IsString())) { digest_ha1 = (*av)["digest"]["ha1"].GetString(); } pj_strdup2(pool, &cred_info->data, digest_ha1.c_str()); cred_info->realm = *realm; TRC_DEBUG("Found Digest HA1 = %.*s", cred_info->data.slen, cred_info->data.ptr); status = PJ_SUCCESS; } else { // These credentials are for a different realm, so no credentials were // actually provided for us to check. status = PJSIP_EAUTHNOAUTH; } } correlate_branch_from_av(av, trail); } return status; }
int dummy_function() { pj_caching_pool cp; sprintf(NULL, "%d", 0); rand(); #ifdef HAS_PJLIB pj_init(); pj_caching_pool_init(&cp, NULL, 0); pj_array_erase(NULL, 0, 0, 0); pj_create_unique_string(NULL, NULL); pj_hash_create(NULL, 0); pj_hash_get(NULL, NULL, 0, NULL); pj_hash_set(NULL, NULL, NULL, 0, 0, NULL); pj_ioqueue_create(NULL, 0, NULL); pj_ioqueue_register_sock(NULL, NULL, 0, NULL, NULL, NULL); pj_pool_alloc(NULL, 0); pj_timer_heap_create(NULL, 0, NULL); #endif #ifdef HAS_PJLIB_STUN pjstun_get_mapped_addr(&cp.factory, 0, NULL, NULL, 80, NULL, 80, NULL); #endif #ifdef HAS_PJLIB_GETOPT pj_getopt_long(0, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJLIB_XML pj_xml_parse(NULL, NULL, 100); pj_xml_print(NULL, NULL, 10, PJ_FALSE); pj_xml_clone(NULL, NULL); pj_xml_node_new(NULL, NULL); pj_xml_attr_new(NULL, NULL, NULL); pj_xml_add_node(NULL, NULL); pj_xml_add_attr(NULL, NULL); pj_xml_find_node(NULL, NULL); pj_xml_find_next_node(NULL, NULL, NULL); pj_xml_find_attr(NULL, NULL, NULL); pj_xml_find(NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJLIB_SCANNER pj_cis_buf_init(NULL); pj_cis_init(NULL, NULL); pj_cis_dup(NULL, NULL); pj_cis_add_alpha(NULL); pj_cis_add_str(NULL, NULL); pj_scan_init(NULL, NULL, 0, 0, NULL); pj_scan_fini(NULL); pj_scan_peek(NULL, NULL, NULL); pj_scan_peek_n(NULL, 0, NULL); pj_scan_peek_until(NULL, NULL, NULL); pj_scan_get(NULL, NULL, NULL); pj_scan_get_unescape(NULL, NULL, NULL); pj_scan_get_quote(NULL, 0, 0, NULL); pj_scan_get_n(NULL, 0, NULL); pj_scan_get_char(NULL); pj_scan_get_until(NULL, NULL, NULL); pj_scan_strcmp(NULL, NULL, 0); pj_scan_stricmp(NULL, NULL, 0); pj_scan_stricmp_alnum(NULL, NULL, 0); pj_scan_get_newline(NULL); pj_scan_restore_state(NULL, NULL); #endif #ifdef HAS_PJLIB_DNS pj_dns_make_query(NULL, NULL, 0, 0, NULL); pj_dns_parse_packet(NULL, NULL, 0, NULL); pj_dns_packet_dup(NULL, NULL, 0, NULL); #endif #ifdef HAS_PJLIB_RESOLVER pj_dns_resolver_create(NULL, NULL, 0, NULL, NULL, NULL); pj_dns_resolver_set_ns(NULL, 0, NULL, NULL); pj_dns_resolver_handle_events(NULL, NULL); pj_dns_resolver_destroy(NULL, 0); pj_dns_resolver_start_query(NULL, NULL, 0, 0, NULL, NULL, NULL); pj_dns_resolver_cancel_query(NULL, 0); pj_dns_resolver_add_entry(NULL, NULL, 0); #endif #ifdef HAS_PJLIB_SRV_RESOLVER pj_dns_srv_resolve(NULL, NULL, 0, NULL, NULL, PJ_FALSE, NULL, NULL); #endif #ifdef HAS_PJLIB_CRC32 pj_crc32_init(NULL); pj_crc32_update(NULL, NULL, 0); pj_crc32_final(NULL); #endif #ifdef HAS_PJLIB_HMAC_MD5 pj_hmac_md5(NULL, 0, NULL, 0, NULL); #endif #ifdef HAS_PJLIB_HMAC_SHA1 pj_hmac_sha1(NULL, 0, NULL, 0, NULL); #endif #ifdef HAS_PJNATH_STUN pj_stun_session_create(NULL, NULL, NULL, PJ_FALSE, NULL); pj_stun_session_destroy(NULL); pj_stun_session_set_credential(NULL, NULL); pj_stun_session_create_req(NULL, 0, NULL, NULL); pj_stun_session_create_ind(NULL, 0, NULL); pj_stun_session_create_res(NULL, NULL, 0, NULL, NULL); pj_stun_session_send_msg(NULL, PJ_FALSE, NULL, 0, NULL); #endif #ifdef HAS_PJNATH_ICE pj_ice_strans_create(NULL, NULL, 0, NULL, NULL, NULL); pj_ice_strans_set_stun_domain(NULL, NULL, NULL); pj_ice_strans_create_comp(NULL, 0, 0, NULL); pj_ice_strans_add_cand(NULL, 0, PJ_ICE_CAND_TYPE_HOST, 0, NULL, PJ_FALSE); pj_ice_strans_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); pj_ice_strans_start_ice(NULL, NULL, NULL, 0, NULL); pj_ice_strans_stop_ice(NULL); pj_ice_strans_sendto(NULL, 0, NULL, 0, NULL, 0); #endif #ifdef HAS_PJSIP_CORE_MSG_ELEM /* Parameter container */ pjsip_param_find(NULL, NULL); pjsip_param_print_on(NULL, NULL, 0, NULL, NULL, 0); /* SIP URI */ pjsip_sip_uri_create(NULL, 0); pjsip_name_addr_create(NULL); /* TEL URI */ pjsip_tel_uri_create(NULL); /* Message and headers */ pjsip_msg_create(NULL, PJSIP_REQUEST_MSG); pjsip_msg_print(NULL, NULL, 0); pjsip_accept_hdr_create(NULL); pjsip_allow_hdr_create(NULL); pjsip_cid_hdr_create(NULL); pjsip_clen_hdr_create(NULL); pjsip_cseq_hdr_create(NULL); pjsip_contact_hdr_create(NULL); pjsip_ctype_hdr_create(NULL); pjsip_expires_hdr_create(NULL, 0); pjsip_from_hdr_create(NULL); pjsip_max_fwd_hdr_create(NULL, 0); pjsip_min_expires_hdr_create(NULL, 0); pjsip_rr_hdr_create(NULL); pjsip_require_hdr_create(NULL); pjsip_retry_after_hdr_create(NULL, 0); pjsip_supported_hdr_create(NULL); pjsip_unsupported_hdr_create(NULL); pjsip_via_hdr_create(NULL); pjsip_warning_hdr_create(NULL, 0, NULL, NULL); pjsip_parse_uri(NULL, NULL, 0, 0); pjsip_parse_msg(NULL, NULL, 0, NULL); pjsip_parse_rdata(NULL, 0, NULL); pjsip_find_msg(NULL, 0, 0, NULL); #endif #ifdef HAS_PJSIP_CORE pjsip_endpt_create(NULL, NULL, NULL); pjsip_tpmgr_create(NULL, NULL, NULL, NULL, NULL); pjsip_tpmgr_destroy(NULL); pjsip_transport_send(NULL, NULL, NULL, 0, NULL, NULL); #endif #ifdef HAS_PJSIP_CORE_MSG_UTIL pjsip_endpt_create_request(NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_request_from_hdr(NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_response(NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_ack(NULL, NULL, NULL, NULL); pjsip_endpt_create_cancel(NULL, NULL, NULL); pjsip_get_request_dest(NULL, NULL); pjsip_endpt_send_request_stateless(NULL, NULL, NULL, NULL); pjsip_get_response_addr(NULL, NULL, NULL); pjsip_endpt_send_response(NULL, NULL, NULL, NULL, NULL); pjsip_endpt_respond_stateless(NULL, NULL, -1, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_UDP_TRANSPORT pjsip_udp_transport_start(NULL, NULL, NULL, 1, NULL); #endif #ifdef HAS_PJSIP_TCP_TRANSPORT pjsip_tcp_transport_start(NULL, NULL, 1, NULL); #endif #ifdef HAS_PJSIP_TLS_TRANSPORT pjsip_tls_transport_start(NULL, NULL, NULL, NULL, 0, NULL); #endif #ifdef HAS_PJSIP_TRANSACTION pjsip_tsx_layer_init_module(NULL); pjsip_tsx_layer_destroy(); pjsip_tsx_create_uac(NULL, NULL, NULL); pjsip_tsx_create_uas(NULL, NULL, NULL); pjsip_tsx_recv_msg(NULL, NULL); pjsip_tsx_send_msg(NULL, NULL); pjsip_tsx_terminate(NULL, 200); pjsip_endpt_send_request(NULL, NULL, -1, NULL, NULL); pjsip_endpt_respond(NULL, NULL, NULL, -1, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SDP pjmedia_sdp_parse(NULL, NULL, 1024, NULL); pjmedia_sdp_print(NULL, NULL, 1024); pjmedia_sdp_validate(NULL); pjmedia_sdp_session_clone(NULL, NULL); pjmedia_sdp_session_cmp(NULL, NULL, 0); pjmedia_sdp_attr_to_rtpmap(NULL, NULL, NULL); pjmedia_sdp_attr_get_fmtp(NULL, NULL); pjmedia_sdp_attr_get_rtcp(NULL, NULL); pjmedia_sdp_conn_clone(NULL, NULL); pjmedia_sdp_media_clone(NULL, NULL); pjmedia_sdp_media_find_attr(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SDP_NEGOTIATOR pjmedia_sdp_neg_create_w_local_offer(NULL, NULL, NULL); pjmedia_sdp_neg_create_w_remote_offer(NULL, NULL, NULL, NULL); pjmedia_sdp_neg_get_state(NULL); pjmedia_sdp_neg_negotiate(NULL, NULL, PJ_FALSE); #endif #ifdef HAS_PJSIP_UA_LAYER pjsip_ua_init_module(NULL, NULL); pjsip_ua_destroy(); pjsip_dlg_create_uac(NULL, NULL, NULL, NULL, NULL, NULL); pjsip_dlg_create_uas_and_inc_lock(NULL, NULL, NULL, NULL); pjsip_dlg_terminate(NULL); pjsip_dlg_set_route_set(NULL, NULL); pjsip_dlg_create_request(NULL, NULL, -1, NULL); pjsip_dlg_send_request(NULL, NULL, -1, NULL); pjsip_dlg_create_response(NULL, NULL, -1, NULL, NULL); pjsip_dlg_modify_response(NULL, NULL, -1, NULL); pjsip_dlg_send_response(NULL, NULL, NULL); pjsip_dlg_respond(NULL, NULL, -1, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_AUTH_CLIENT pjsip_auth_clt_init(NULL, NULL, NULL, 0); pjsip_auth_clt_clone(NULL, NULL, NULL); pjsip_auth_clt_set_credentials(NULL, 0, NULL); pjsip_auth_clt_init_req(NULL, NULL); pjsip_auth_clt_reinit_req(NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_INV_SESSION pjsip_inv_usage_init(NULL, NULL); pjsip_inv_create_uac(NULL, NULL, 0, NULL); pjsip_inv_verify_request(NULL, NULL, NULL, NULL, NULL, NULL); pjsip_inv_create_uas(NULL, NULL, NULL, 0, NULL); pjsip_inv_terminate(NULL, 200, PJ_FALSE); pjsip_inv_invite(NULL, NULL); pjsip_inv_initial_answer(NULL, NULL, 200, NULL, NULL, NULL); pjsip_inv_answer(NULL, 200, NULL, NULL, NULL); pjsip_inv_end_session(NULL, 200, NULL, NULL); pjsip_inv_reinvite(NULL, NULL, NULL, NULL); pjsip_inv_update(NULL, NULL, NULL, NULL); pjsip_inv_send_msg(NULL, NULL); pjsip_dlg_get_inv_session(NULL); //pjsip_tsx_get_inv_session(NULL); pjsip_inv_state_name(PJSIP_INV_STATE_NULL); #endif #ifdef HAS_PJSIP_REGC //pjsip_regc_get_module(); pjsip_regc_create(NULL, NULL, NULL, NULL); pjsip_regc_destroy(NULL); pjsip_regc_get_info(NULL, NULL); pjsip_regc_get_pool(NULL); pjsip_regc_init(NULL, NULL, NULL, NULL, 0, NULL, 600); pjsip_regc_set_credentials(NULL, 1, NULL); pjsip_regc_set_route_set(NULL, NULL); pjsip_regc_register(NULL, PJ_TRUE, NULL); pjsip_regc_unregister(NULL, NULL); pjsip_regc_update_contact(NULL, 10, NULL); pjsip_regc_update_expires(NULL, 600); pjsip_regc_send(NULL, NULL); #endif #ifdef HAS_PJSIP_EVENT_FRAMEWORK pjsip_evsub_init_module(NULL); pjsip_evsub_instance(); pjsip_evsub_register_pkg(NULL, NULL, 30, 10, NULL); pjsip_evsub_create_uac(NULL, NULL, NULL, 10, NULL); pjsip_evsub_create_uas(NULL, NULL, NULL, 10, NULL); pjsip_evsub_terminate(NULL, PJ_FALSE); pjsip_evsub_get_state(NULL); pjsip_evsub_get_state_name(NULL); pjsip_evsub_initiate(NULL, NULL, -1, NULL); pjsip_evsub_accept(NULL, NULL, 200, NULL); pjsip_evsub_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL); pjsip_evsub_current_notify(NULL, NULL); pjsip_evsub_send_request(NULL, NULL); pjsip_tsx_get_evsub(NULL); pjsip_evsub_set_mod_data(NULL, 1, NULL); pjsip_evsub_get_mod_data(NULL, 1); #endif #ifdef HAS_PJSIP_CALL_TRANSFER pjsip_xfer_init_module(NULL); pjsip_xfer_create_uac(NULL, NULL, NULL); pjsip_xfer_create_uas(NULL, NULL, NULL, NULL); pjsip_xfer_initiate(NULL, NULL, NULL); pjsip_xfer_accept(NULL, NULL, 200, NULL); pjsip_xfer_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, 200, NULL, NULL); pjsip_xfer_current_notify(NULL, NULL); pjsip_xfer_send_request(NULL, NULL); #endif #ifdef HAS_PJSIP_PRESENCE pjsip_pres_init_module(NULL, NULL); pjsip_pres_instance(); pjsip_pres_create_uac(NULL, NULL, 0, NULL); pjsip_pres_create_uas(NULL, NULL, NULL, NULL); pjsip_pres_terminate(NULL, PJ_FALSE); pjsip_pres_initiate(NULL, 100, NULL); pjsip_pres_accept(NULL, NULL, 200, NULL); pjsip_pres_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL); pjsip_pres_current_notify(NULL, NULL); pjsip_pres_send_request(NULL, NULL); pjsip_pres_get_status(NULL, NULL); pjsip_pres_set_status(NULL, NULL); #endif #ifdef HAS_PJSIP_IS_COMPOSING pjsip_iscomposing_create_xml(NULL, PJ_TRUE, NULL, NULL, 0); pjsip_iscomposing_create_body(NULL, PJ_TRUE, NULL, NULL, 0); pjsip_iscomposing_parse(NULL, NULL, 0, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA pjmedia_endpt_create(NULL, NULL, 1, NULL); pjmedia_endpt_destroy(NULL); pjmedia_endpt_create_sdp(NULL, NULL, 1, NULL, NULL); #endif #ifdef HAS_PJMEDIA_EC pjmedia_echo_create(NULL, 0, 0, 0, 0, 0, NULL); pjmedia_echo_destroy(NULL); pjmedia_echo_playback(NULL, NULL); pjmedia_echo_capture(NULL, NULL, 0); pjmedia_echo_cancel(NULL, NULL, NULL, 0, NULL); #endif #ifdef HAS_PJMEDIA_SND_DEV pjmedia_snd_init(NULL); pjmedia_snd_get_dev_count(); pjmedia_snd_get_dev_info(0); pjmedia_snd_open(-1, -1, 8000, 1, 80, 16, NULL, NULL, NULL, NULL); pjmedia_snd_open_rec(-1, 8000, 1, 160, 16, NULL, NULL, NULL); pjmedia_snd_open_player(-1, 8000, 1, 160, 16, NULL, NULL, NULL); pjmedia_snd_stream_start(NULL); pjmedia_snd_stream_stop(NULL); pjmedia_snd_stream_close(NULL); pjmedia_snd_deinit(); #endif #ifdef HAS_PJMEDIA_SND_PORT pjmedia_snd_port_create(NULL, -1, -1, 8000, 1, 180, 16, 0, NULL); pjmedia_snd_port_create_rec(NULL, -1, 8000, 1, 160, 16, 0, NULL); pjmedia_snd_port_create_player(NULL, -1, 8000, 1, 160, 16, 0, NULL); pjmedia_snd_port_destroy(NULL); pjmedia_snd_port_get_snd_stream(NULL); pjmedia_snd_port_connect(NULL, NULL); pjmedia_snd_port_get_port(NULL); pjmedia_snd_port_disconnect(NULL); #endif #ifdef HAS_PJMEDIA_RESAMPLE pjmedia_resample_create(NULL, PJ_TRUE, PJ_TRUE, 0, 0, 0, 0, NULL); pjmedia_resample_run(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SILENCE_DET pjmedia_silence_det_create(NULL, 8000, 80, NULL); pjmedia_silence_det_detect(NULL, NULL, 0, NULL); pjmedia_silence_det_apply(NULL, 0); #endif #ifdef HAS_PJMEDIA_PLC pjmedia_plc_create(NULL, 8000, 80, 0, NULL); pjmedia_plc_save(NULL, NULL); pjmedia_plc_generate(NULL, NULL); #endif #ifdef HAS_PJMEDIA_CONFERENCE pjmedia_conf_create(NULL, 10, 8000, 1, 160, 16, 0, NULL); pjmedia_conf_destroy(NULL); pjmedia_conf_get_master_port(NULL); pjmedia_conf_add_port(NULL, NULL, NULL, NULL, NULL); pjmedia_conf_configure_port(NULL, 1, 0, 0); pjmedia_conf_connect_port(NULL, 0, 0, 0); pjmedia_conf_disconnect_port(NULL, 0, 0); pjmedia_conf_remove_port(NULL, 0); pjmedia_conf_enum_ports(NULL, NULL, NULL); pjmedia_conf_get_port_info(NULL, 0, NULL); pjmedia_conf_get_ports_info(NULL, NULL, NULL); pjmedia_conf_get_signal_level(NULL, 0, NULL, NULL); pjmedia_conf_adjust_rx_level(NULL, 0, 0); pjmedia_conf_adjust_tx_level(NULL, 0, 0); #endif #ifdef HAS_PJMEDIA_MASTER_PORT pjmedia_master_port_create(NULL, NULL, NULL, 0, NULL); pjmedia_master_port_start(NULL); pjmedia_master_port_stop(NULL); pjmedia_master_port_set_uport(NULL, NULL); pjmedia_master_port_get_uport(NULL); pjmedia_master_port_set_dport(NULL, NULL); pjmedia_master_port_get_dport(NULL); pjmedia_master_port_destroy(NULL, PJ_FALSE); #endif #ifdef HAS_PJMEDIA_RTP pjmedia_rtp_session_init(NULL, 0, 0); pjmedia_rtp_encode_rtp(NULL, 0, 0, 0, 0, NULL, NULL); pjmedia_rtp_decode_rtp(NULL, NULL, 0, NULL, NULL, NULL); pjmedia_rtp_session_update(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_RTCP pjmedia_rtcp_init(NULL, NULL, 0, 0, 0); pjmedia_rtcp_get_ntp_time(NULL, NULL); pjmedia_rtcp_fini(NULL); pjmedia_rtcp_rx_rtp(NULL, 0, 0, 0); pjmedia_rtcp_tx_rtp(NULL, 0); pjmedia_rtcp_rx_rtcp(NULL, NULL, 0); pjmedia_rtcp_build_rtcp(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_JBUF pjmedia_jbuf_create(NULL, NULL, 0, 0, 0, NULL); pjmedia_jbuf_set_fixed(NULL, 0); pjmedia_jbuf_set_adaptive(NULL, 0, 0, 0); pjmedia_jbuf_destroy(NULL); pjmedia_jbuf_put_frame(NULL, NULL, 0, 0); pjmedia_jbuf_get_frame(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_STREAM pjmedia_stream_create(NULL, NULL, NULL, NULL, NULL, NULL); pjmedia_stream_destroy(NULL); pjmedia_stream_get_port(NULL, NULL); pjmedia_stream_get_transport(NULL); pjmedia_stream_start(NULL); pjmedia_stream_get_stat(NULL, NULL); pjmedia_stream_pause(NULL, PJMEDIA_DIR_ENCODING); pjmedia_stream_resume(NULL, PJMEDIA_DIR_ENCODING); pjmedia_stream_dial_dtmf(NULL, NULL); pjmedia_stream_check_dtmf(NULL); pjmedia_stream_get_dtmf(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_TONEGEN pjmedia_tonegen_create(NULL, 0, 0, 0, 0, 0, NULL); pjmedia_tonegen_is_busy(NULL); pjmedia_tonegen_stop(NULL); pjmedia_tonegen_play(NULL, 0, NULL, 0); pjmedia_tonegen_play_digits(NULL, 0, NULL, 0); pjmedia_tonegen_get_digit_map(NULL, NULL); pjmedia_tonegen_set_digit_map(NULL, NULL); #endif #ifdef HAS_PJMEDIA_UDP_TRANSPORT pjmedia_transport_udp_create(NULL, NULL, 0, 0, NULL); pjmedia_transport_udp_close(NULL); #endif #ifdef HAS_PJMEDIA_FILE_PLAYER pjmedia_wav_player_port_create(NULL, NULL, 0, 0, 0, NULL); pjmedia_wav_player_port_set_pos(NULL, 0); pjmedia_wav_player_port_get_pos(NULL); pjmedia_wav_player_set_eof_cb(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_FILE_CAPTURE pjmedia_wav_writer_port_create(NULL, NULL, 8000, 1, 80, 16, 0, 0, NULL); pjmedia_wav_writer_port_get_pos(NULL); pjmedia_wav_writer_port_set_cb(NULL, 0, NULL, NULL); #endif #ifdef HAS_PJMEDIA_MEM_PLAYER pjmedia_mem_player_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL); #endif #ifdef HAS_PJMEDIA_MEM_CAPTURE pjmedia_mem_capture_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL); #endif #ifdef HAS_PJMEDIA_ICE pjmedia_ice_create(NULL, NULL, 0, NULL, NULL); pjmedia_ice_destroy(NULL); pjmedia_ice_start_init(NULL, 0, NULL, NULL, NULL); pjmedia_ice_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); pjmedia_ice_modify_sdp(NULL, NULL, NULL); pjmedia_ice_start_ice(NULL, NULL, NULL, 0); pjmedia_ice_stop_ice(NULL); #endif #ifdef HAS_PJMEDIA_G711_CODEC pjmedia_codec_g711_init(NULL); pjmedia_codec_g711_deinit(); #endif #ifdef HAS_PJMEDIA_GSM_CODEC pjmedia_codec_gsm_init(NULL); pjmedia_codec_gsm_deinit(); #endif #ifdef HAS_PJMEDIA_SPEEX_CODEC pjmedia_codec_speex_init(NULL, 0, 0, 0); pjmedia_codec_speex_deinit(); #endif #ifdef HAS_PJMEDIA_ILBC_CODEC pjmedia_codec_ilbc_init(NULL, 0); pjmedia_codec_ilbc_deinit(); #endif return 0; }