PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc, const pj_str_t *event, const pj_str_t *target_uri, const pj_str_t *from_uri, const pj_str_t *to_uri, pj_uint32_t expires) { pj_str_t tmp; PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri && expires, PJ_EINVAL); /* Copy event type */ pj_strdup_with_null(pubc->pool, &pubc->event, event); /* Copy server URL. */ pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri); /* Set server URL. */ tmp = pubc->str_target_uri; pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0); if (pubc->target_uri == NULL) { return PJSIP_EINVALIDURI; } /* Set "From" header. */ pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri); tmp = pubc->from_uri; pubc->from_hdr = pjsip_from_hdr_create(pubc->pool); pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!pubc->from_hdr->uri) { return PJSIP_EINVALIDURI; } /* Set "To" header. */ pj_strdup_with_null(pubc->pool, &tmp, to_uri); pubc->to_hdr = pjsip_to_hdr_create(pubc->pool); pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!pubc->to_hdr->uri) { return PJSIP_EINVALIDURI; } /* Set "Expires" header, if required. */ set_expires( pubc, expires); /* Set "Call-ID" header. */ pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool); pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id); /* Set "CSeq" header. */ pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool); pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF; pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD); /* Done. */ return PJ_SUCCESS; }
void RegistrationUtils::register_with_application_servers(Ifcs& ifcs, RegStore* store, pjsip_rx_data *received_register, pjsip_tx_data *ok_response, // Can only be NULL if received_register is int expires, bool is_initial_registration, const std::string& served_user, SAS::TrailId trail) { // Function preconditions if (received_register == NULL) { // We should have both messages or neither assert(ok_response == NULL); } else { // We should have both messages or neither assert(ok_response != NULL); } std::vector<AsInvocation> as_list; // Choice of SessionCase::Originating is not arbitrary - we don't expect iFCs to specify SessionCase // constraints for REGISTER messages, but we only get the served user from the From address in an // Originating message, otherwise we use the Request-URI. We need to use the From for REGISTERs. // See 3GPP TS 23.218 s5.2.1 note 2: "REGISTER is considered part of the UE-originating". if (received_register == NULL) { pj_status_t status; pjsip_method method; pjsip_method_set(&method, PJSIP_REGISTER_METHOD); pjsip_tx_data *tdata; std::string served_user_uri_string = "<"+served_user+">"; const pj_str_t served_user_uri = pj_str(const_cast<char *>(served_user_uri_string.c_str())); LOG_INFO("Generating a fake REGISTER to send to IfcHandler using AOR %s", served_user.c_str()); SAS::Event event(trail, SASEvent::REGISTER_AS_START, 0); event.add_var_param(served_user); SAS::report_event(event); status = pjsip_endpt_create_request(stack_data.endpt, &method, // Method &stack_data.scscf_uri, // Target &served_user_uri, // From &served_user_uri, // To &served_user_uri, // Contact NULL, // Auto-generate Call-ID 1, // CSeq NULL, // No body &tdata); // OUT assert(status == PJ_SUCCESS); // As per TS 24.229, section 5.4.1.7, note 1, we don't fill in any P-Associated-URI details. ifcs.interpret(SessionCase::Originating, true, is_initial_registration, tdata->msg, as_list, trail); status = pjsip_tx_data_dec_ref(tdata); assert(status == PJSIP_EBUFDESTROYED); } else { ifcs.interpret(SessionCase::Originating, true, is_initial_registration, received_register->msg_info.msg, as_list, trail); } LOG_INFO("Found %d Application Servers", as_list.size()); // Loop through the as_list for (std::vector<AsInvocation>::iterator as_iter = as_list.begin(); as_iter != as_list.end(); as_iter++) { send_register_to_as(received_register, ok_response, *as_iter, expires, served_user, trail); } }
void send_register_to_as(pjsip_rx_data *received_register, pjsip_tx_data *ok_response, AsInvocation& as, int expires, const std::string& served_user, SAS::TrailId trail) { pj_status_t status; pjsip_tx_data *tdata; pjsip_method method; pjsip_method_set(&method, PJSIP_REGISTER_METHOD); pj_str_t user_uri; pj_cstr(&user_uri, served_user.c_str()); pj_str_t as_uri; pj_cstr(&as_uri, as.server_name.c_str()); status = pjsip_endpt_create_request(stack_data.endpt, &method, // Method &as_uri, // Target &stack_data.scscf_uri, // From &user_uri, // To &stack_data.scscf_uri, // Contact NULL, // Auto-generate Call-ID 1, // CSeq NULL, // No body &tdata); // OUT if (status != PJ_SUCCESS) { //LCOV_EXCL_START LOG_ERROR("Failed to build third-party REGISTER request for server %s", as.server_name.c_str()); return; //LCOV_EXCL_STOP } // Expires header based on 200 OK response pjsip_expires_hdr_create(tdata->pool, expires); pjsip_expires_hdr* expires_hdr = pjsip_expires_hdr_create(tdata->pool, expires); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr); // TODO: modify orig-ioi of P-Charging-Vector and remove term-ioi if (received_register && ok_response) { // Copy P-Access-Network-Info, P-Visited-Network-Id and P-Charging-Vector // from original message PJUtils::clone_header(&STR_P_A_N_I, received_register->msg_info.msg, tdata->msg, tdata->pool); PJUtils::clone_header(&STR_P_V_N_I, received_register->msg_info.msg, tdata->msg, tdata->pool); PJUtils::clone_header(&STR_P_C_V, received_register->msg_info.msg, tdata->msg, tdata->pool); // Copy P-Charging-Function-Addresses from the OK response. PJUtils::clone_header(&STR_P_C_F_A, ok_response->msg, tdata->msg, tdata->pool); // Generate a message body based on Filter Criteria values char buf[MAX_SIP_MSG_SIZE]; pj_str_t sip_type = pj_str("message"); pj_str_t sip_subtype = pj_str("sip"); pj_str_t xml_type = pj_str("application"); pj_str_t xml_subtype = pj_str("3gpp-ims+xml"); // Build up this multipart body incrementally, based on the ServiceInfo, IncludeRegisterRequest and IncludeRegisterResponse fields pjsip_msg_body *final_body = pjsip_multipart_create(tdata->pool, NULL, NULL); // If we only have one part, we don't want a multipart MIME body - store the reference to each one here to use instead pjsip_msg_body *possible_final_body = NULL; int multipart_parts = 0; if (!as.service_info.empty()) { pjsip_multipart_part *xml_part = pjsip_multipart_create_part(tdata->pool); std::string xml_str = "<ims-3gpp><service-info>"+as.service_info+"</service-info></ims-3gpp>"; pj_str_t xml_pj_str; pj_cstr(&xml_pj_str, xml_str.c_str()); xml_part->body = pjsip_msg_body_create(tdata->pool, &xml_type, &xml_subtype, &xml_pj_str), possible_final_body = xml_part->body; multipart_parts++; pjsip_multipart_add_part(tdata->pool, final_body, xml_part); } if (as.include_register_request) { pjsip_multipart_part *request_part = pjsip_multipart_create_part(tdata->pool); pjsip_msg_print(received_register->msg_info.msg, buf, sizeof(buf)); pj_str_t request_str = pj_str(buf); request_part->body = pjsip_msg_body_create(tdata->pool, &sip_type, &sip_subtype, &request_str), possible_final_body = request_part->body; multipart_parts++; pjsip_multipart_add_part(tdata->pool, final_body, request_part); } if (as.include_register_response) { pjsip_multipart_part *response_part = pjsip_multipart_create_part(tdata->pool); pjsip_msg_print(ok_response->msg, buf, sizeof(buf)); pj_str_t response_str = pj_str(buf); response_part->body = pjsip_msg_body_create(tdata->pool, &sip_type, &sip_subtype, &response_str), possible_final_body = response_part->body; multipart_parts++; pjsip_multipart_add_part(tdata->pool, final_body, response_part); } if (multipart_parts == 0) { final_body = NULL; } else if (multipart_parts == 1) { final_body = possible_final_body; } else { // Just use the multipart MIME body you've built up } tdata->msg->body = final_body; } // Set the SAS trail on the request. set_trail(tdata, trail); // Allocate a temporary structure to record the default handling for this // REGISTER, and send it statefully. ThirdPartyRegData* tsxdata = new ThirdPartyRegData; tsxdata->default_handling = as.default_handling; tsxdata->trail = trail; tsxdata->public_id = served_user; pj_status_t resolv_status = PJUtils::send_request(tdata, 0, tsxdata, &send_register_cb); if (resolv_status != PJ_SUCCESS) { delete tsxdata; // LCOV_EXCL_LINE } }
/* Test that we receive loopback message. */ int transport_send_recv_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, char *target_url, int *p_usec_rtt) { pj_bool_t msg_log_enabled; pj_status_t status; pj_str_t target, from, to, contact, call_id, body; pjsip_method method; pjsip_tx_data *tdata; pj_time_val timeout; PJ_UNUSED_ARG(tp_type); PJ_UNUSED_ARG(ref_tp); PJ_LOG(3,(THIS_FILE, " single message round-trip test...")); /* Register out test module to receive the message (if necessary). */ if (my_module.id == -1) { status = pjsip_endpt_register_module( endpt, &my_module ); if (status != PJ_SUCCESS) { app_perror(" error: unable to register module", status); return -500; } } /* Disable message logging. */ msg_log_enabled = msg_logger_set_enabled(0); /* Create a request message. */ target = pj_str(target_url); from = pj_str(FROM_HDR); to = pj_str(target_url); contact = pj_str(CONTACT_HDR); call_id = pj_str(CALL_ID_HDR); body = pj_str(BODY); pjsip_method_set(&method, PJSIP_OPTIONS_METHOD); status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to, &contact, &call_id, CSEQ_VALUE, &body, &tdata ); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); return -510; } /* Reset statuses */ send_status = recv_status = NO_STATUS; /* Start time. */ pj_get_timestamp(&my_send_time); /* Send the message (statelessly). */ PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", (int)target.slen, target.ptr)); status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, &send_msg_callback); if (status != PJ_SUCCESS) { /* Immediate error! */ pjsip_tx_data_dec_ref(tdata); send_status = status; } /* Set the timeout (2 seconds from now) */ pj_gettimeofday(&timeout); timeout.sec += 2; /* Loop handling events until we get status */ do { pj_time_val now; pj_time_val poll_interval = { 0, 10 }; pj_gettimeofday(&now); if (PJ_TIME_VAL_GTE(now, timeout)) { PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test")); status = -540; goto on_return; } if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) { app_perror(" error sending message", send_status); status = -550; goto on_return; } if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) { app_perror(" error receiving message", recv_status); status = -560; goto on_return; } if (send_status!=NO_STATUS && recv_status!=NO_STATUS) { /* Success! */ break; } pjsip_endpt_handle_events(endpt, &poll_interval); } while (1); if (status == PJ_SUCCESS) { unsigned usec_rt; usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); *p_usec_rtt = usec_rt; } /* Restore message logging. */ msg_logger_set_enabled(msg_log_enabled); status = PJ_SUCCESS; on_return: return status; }
PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc, const pj_str_t *srv_url, const pj_str_t *from_url, const pj_str_t *to_url, int contact_cnt, const pj_str_t contact[], pj_uint32_t expires) { pj_str_t tmp; pj_status_t status; PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url && expires, PJ_EINVAL); /* Copy server URL. */ pj_strdup_with_null(regc->pool, ®c->str_srv_url, srv_url); /* Set server URL. */ tmp = regc->str_srv_url; regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0); if (regc->srv_url == NULL) { return PJSIP_EINVALIDURI; } /* Set "From" header. */ pj_strdup_with_null(regc->pool, ®c->from_uri, from_url); tmp = regc->from_uri; regc->from_hdr = pjsip_from_hdr_create(regc->pool); regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!regc->from_hdr->uri) { PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s", from_url->slen, from_url->ptr)); return PJSIP_EINVALIDURI; } /* Set "To" header. */ pj_strdup_with_null(regc->pool, &tmp, to_url); regc->to_hdr = pjsip_to_hdr_create(regc->pool); regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (!regc->to_hdr->uri) { PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr)); return PJSIP_EINVALIDURI; } /* Set "Contact" header. */ status = set_contact( regc, contact_cnt, contact); if (status != PJ_SUCCESS) return status; /* Set "Expires" header, if required. */ set_expires( regc, expires); regc->delay_before_refresh = DELAY_BEFORE_REFRESH; /* Set "Call-ID" header. */ regc->cid_hdr = pjsip_cid_hdr_create(regc->pool); pj_create_unique_string(regc->pool, ®c->cid_hdr->id); /* Set "CSeq" header. */ regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool); regc->cseq_hdr->cseq = pj_rand() % 0xFFFF; pjsip_method_set( ®c->cseq_hdr->method, PJSIP_REGISTER_METHOD); /* Done. */ return PJ_SUCCESS; }