pjsip_tx_data* PJUtils::clone_tdata(pjsip_tx_data* tdata) { pjsip_tx_data* cloned_tdata; pj_status_t status; status = pjsip_endpt_create_tdata(stack_data.endpt, &cloned_tdata); if (status != PJ_SUCCESS) { return NULL; } // Always increment ref counter to 1. pjsip_tx_data_add_ref(cloned_tdata); // Clone the message from the supplied tdata. cloned_tdata->msg = pjsip_msg_clone(cloned_tdata->pool, tdata->msg); if (cloned_tdata->msg == NULL) { pjsip_tx_data_dec_ref(cloned_tdata); cloned_tdata = NULL; } // Copy the trail identifier to the cloned message. set_trail(cloned_tdata, get_trail(tdata)); if (tdata->msg->type == PJSIP_REQUEST_MSG) { // Substitute the branch value in the top Via header with a unique // branch identifier. generate_new_branch_id(cloned_tdata); } // If the original message already had a specified transport set this // on the clone. (Must use pjsip_tx_data_set_transport to ensure // reference counts get updated.) if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) { pjsip_tx_data_set_transport(cloned_tdata, &tdata->tp_sel); } // If the message has any addr in dest_info, copy that if (tdata->dest_info.addr.count != 0) { pj_memcpy(&cloned_tdata->dest_info, &tdata->dest_info, sizeof(cloned_tdata->dest_info)); } return cloned_tdata; }
pjsip_tx_data* PJUtils::clone_tdata(pjsip_tx_data* tdata) { pjsip_tx_data* cloned_tdata; pj_status_t status; status = pjsip_endpt_create_tdata(stack_data.endpt, &cloned_tdata); if (status != PJ_SUCCESS) { return NULL; } // Always increment ref counter to 1. pjsip_tx_data_add_ref(cloned_tdata); // Clone the message from the supplied tdata. cloned_tdata->msg = pjsip_msg_clone(cloned_tdata->pool, tdata->msg); if (cloned_tdata->msg == NULL) { pjsip_tx_data_dec_ref(cloned_tdata); cloned_tdata = NULL; } // Copy the trail identifier to the cloned message. set_trail(cloned_tdata, get_trail(tdata)); if (tdata->msg->type == PJSIP_REQUEST_MSG) { // Substitute the branch value in the top Via header with a unique // branch identifier. pjsip_via_hdr* via = (pjsip_via_hdr*) pjsip_msg_find_hdr(cloned_tdata->msg, PJSIP_H_VIA, NULL); via->branch_param.ptr = (char*) pj_pool_alloc(cloned_tdata->pool, PJSIP_MAX_BRANCH_LEN); via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN; pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID, PJSIP_RFC3261_BRANCH_LEN); pj_str_t tmp; tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2; // I have absolutely no idea what the following two lines do, but it // doesn't seem to work without them! *(tmp.ptr-2) = (pj_int8_t)(via->branch_param.slen+73); *(tmp.ptr-1) = (pj_int8_t)(via->branch_param.slen+99); pj_generate_unique_string( &tmp ); via->branch_param.slen = PJSIP_MAX_BRANCH_LEN; } // If the original message already had a specified transport set this // on the clone. (Must use pjsip_tx_data_set_transport to ensure // reference counts get updated.) if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) { pjsip_tx_data_set_transport(cloned_tdata, &tdata->tp_sel); } // If the message has any addr in dest_info, copy that if (tdata->dest_info.addr.count != 0) { pj_memcpy(&cloned_tdata->dest_info, &tdata->dest_info, sizeof(cloned_tdata->dest_info)); } return cloned_tdata; }
/* * Create new request message to be forwarded upstream to new destination URI * in uri. */ PJ_DEF(pj_status_t) pjsip_endpt_create_request_fwd(pjsip_endpoint *endpt, pjsip_rx_data *rdata, const pjsip_uri *uri, const pj_str_t *branch, unsigned options, pjsip_tx_data **p_tdata) { pjsip_tx_data *tdata; pj_status_t status; PJ_USE_EXCEPTION; PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL); PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); PJ_UNUSED_ARG(options); /* Request forwarding rule in RFC 3261 section 16.6: * * For each target, the proxy forwards the request following these * steps: * * 1. Make a copy of the received request * 2. Update the Request-URI * 3. Update the Max-Forwards header field * 4. Optionally add a Record-route header field value * 5. Optionally add additional header fields * 6. Postprocess routing information * 7. Determine the next-hop address, port, and transport * 8. Add a Via header field value * 9. Add a Content-Length header field if necessary * 10. Forward the new request * * Of these steps, we only do step 1-3, since the later will be * done by application. */ status = pjsip_endpt_create_tdata(endpt, &tdata); if (status != PJ_SUCCESS) return status; /* Always increment ref counter to 1 */ pjsip_tx_data_add_ref(tdata); /* Duplicate the request */ PJ_TRY { pjsip_msg *dst; const pjsip_msg *src = rdata->msg_info.msg; const pjsip_hdr *hsrc; /* Create the request */ tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG); /* Duplicate request method */ pjsip_method_copy(tdata->pool, &tdata->msg->line.req.method, &src->line.req.method); /* Set request URI */ if (uri) { dst->line.req.uri = (pjsip_uri*) pjsip_uri_clone(tdata->pool, uri); } else { dst->line.req.uri= (pjsip_uri*) pjsip_uri_clone(tdata->pool, src->line.req.uri); } /* Clone ALL headers */ hsrc = src->hdr.next; while (hsrc != &src->hdr) { pjsip_hdr *hdst; /* If this is the top-most Via header, insert our own before * cloning the header. */ if (hsrc == (pjsip_hdr*)rdata->msg_info.via) { pjsip_via_hdr *hvia; hvia = pjsip_via_hdr_create(tdata->pool); if (branch) pj_strdup(tdata->pool, &hvia->branch_param, branch); else { pj_str_t new_branch = pjsip_calculate_branch_id(rdata); pj_strdup(tdata->pool, &hvia->branch_param, &new_branch); } pjsip_msg_add_hdr(dst, (pjsip_hdr*)hvia); } /* Skip Content-Type and Content-Length as these would be * generated when the the message is printed. */ else if (hsrc->type == PJSIP_H_CONTENT_LENGTH || hsrc->type == PJSIP_H_CONTENT_TYPE) { hsrc = hsrc->next; continue; } #if 0 /* If this is the top-most Route header and it indicates loose * route, remove the header. */ else if (hsrc == (pjsip_hdr*)rdata->msg_info.route) { const pjsip_route_hdr *hroute = (const pjsip_route_hdr*) hsrc; const pjsip_sip_uri *sip_uri; if (!PJSIP_URI_SCHEME_IS_SIP(hroute->name_addr.uri) && !PJSIP_URI_SCHEME_IS_SIPS(hroute->name_addr.uri)) { /* This is a bad request! */ status = PJSIP_EINVALIDHDR; goto on_error; } sip_uri = (pjsip_sip_uri*) hroute->name_addr.uri; if (sip_uri->lr_param) { /* Yes lr param is present, skip this Route header */ hsrc = hsrc->next; continue; } } #endif /* Clone the header */ hdst = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hsrc); /* If this is Max-Forward header, decrement the value */ if (hdst->type == PJSIP_H_MAX_FORWARDS) { pjsip_max_fwd_hdr *hmaxfwd = (pjsip_max_fwd_hdr*)hdst; --hmaxfwd->ivalue; } /* Append header to new request */ pjsip_msg_add_hdr(dst, hdst); hsrc = hsrc->next; } /* 16.6.3: * If the copy does not contain a Max-Forwards header field, the * proxy MUST add one with a field value, which SHOULD be 70. */ if (rdata->msg_info.max_fwd == NULL) { pjsip_max_fwd_hdr *hmaxfwd = pjsip_max_fwd_hdr_create(tdata->pool, 70); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hmaxfwd); } /* Clone request body */ if (src->body) { dst->body = pjsip_msg_body_clone(tdata->pool, src->body); } } PJ_CATCH_ANY { status = PJ_ENOMEM; goto on_error; } PJ_END /* Done */ *p_tdata = tdata; return PJ_SUCCESS; on_error: pjsip_tx_data_dec_ref(tdata); return status; }
PJ_DEF(pj_status_t) pjsip_endpt_create_response_fwd( pjsip_endpoint *endpt, pjsip_rx_data *rdata, unsigned options, pjsip_tx_data **p_tdata) { pjsip_tx_data *tdata; pj_status_t status; PJ_USE_EXCEPTION; PJ_UNUSED_ARG(options); status = pjsip_endpt_create_tdata(endpt, &tdata); if (status != PJ_SUCCESS) return status; pjsip_tx_data_add_ref(tdata); PJ_TRY { pjsip_msg *dst; const pjsip_msg *src = rdata->msg_info.msg; const pjsip_hdr *hsrc; /* Create the request */ tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG); /* Clone the status line */ dst->line.status.code = src->line.status.code; pj_strdup(tdata->pool, &dst->line.status.reason, &src->line.status.reason); /* Duplicate all headers */ hsrc = src->hdr.next; while (hsrc != &src->hdr) { /* Skip Content-Type and Content-Length as these would be * generated when the the message is printed. */ if (hsrc->type == PJSIP_H_CONTENT_LENGTH || hsrc->type == PJSIP_H_CONTENT_TYPE) { hsrc = hsrc->next; continue; } /* Remove the first Via header */ else if (hsrc == (pjsip_hdr*) rdata->msg_info.via) { hsrc = hsrc->next; continue; } pjsip_msg_add_hdr(dst, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hsrc)); hsrc = hsrc->next; } /* Clone message body */ if (src->body) dst->body = pjsip_msg_body_clone(tdata->pool, src->body); } PJ_CATCH_ANY { status = PJ_ENOMEM; goto on_error; } PJ_END; *p_tdata = tdata; return PJ_SUCCESS; on_error: pjsip_tx_data_dec_ref(tdata); return status; }