/* Callback to be called to handle incoming response outside * any transactions. This happens for example when 2xx/OK * for INVITE is received and transaction will be destroyed * immediately, so we need to forward the subsequent 2xx/OK * retransmission statelessly. */ static pj_bool_t proxy_on_rx_response( pjsip_rx_data *rdata ) { pjsip_tx_data *tdata; pjsip_response_addr res_addr; pjsip_via_hdr *hvia; pj_status_t status; /* Create response to be forwarded upstream (Via will be stripped here) */ status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, &tdata); if (status != PJ_SUCCESS) { app_perror("Error creating response", status); return PJ_TRUE; } /* Get topmost Via header */ hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); if (hvia == NULL) { /* Invalid response! Just drop it */ pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } /* Calculate the address to forward the response */ pj_bzero(&res_addr, sizeof(res_addr)); res_addr.dst_host.type = PJSIP_TRANSPORT_UDP; res_addr.dst_host.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); /* Destination address is Via's received param */ res_addr.dst_host.addr.host = hvia->recvd_param; if (res_addr.dst_host.addr.host.slen == 0) { /* Someone has messed up our Via header! */ res_addr.dst_host.addr.host = hvia->sent_by.host; } /* Destination port is the rport */ if (hvia->rport_param != 0 && hvia->rport_param != -1) res_addr.dst_host.addr.port = hvia->rport_param; if (res_addr.dst_host.addr.port == 0) { /* Ugh, original sender didn't put rport! * At best, can only send the response to the port in Via. */ res_addr.dst_host.addr.port = hvia->sent_by.port; } /* Forward response */ status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata, NULL, NULL); if (status != PJ_SUCCESS) { app_perror("Error forwarding response", status); return PJ_TRUE; } return PJ_TRUE; }
pj_status_t PJUtils::create_response_fwd(pjsip_endpoint* endpt, pjsip_rx_data* rdata, unsigned options, pjsip_tx_data** p_tdata) { pj_status_t status = pjsip_endpt_create_response_fwd(endpt, rdata, options, p_tdata); if (status == PJ_SUCCESS) { // Copy the SAS trail across from the request. set_trail(*p_tdata, get_trail(rdata)); } return status; }
/* Callback to be called to handle transaction state changed. */ static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) { struct uac_data *uac_data; pj_status_t status; if (tsx->role == PJSIP_ROLE_UAS) { if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { struct uas_data *uas_data; uas_data = (struct uas_data*) tsx->mod_data[mod_tu.id]; if (uas_data->uac_tsx) { uac_data = (struct uac_data*) uas_data->uac_tsx->mod_data[mod_tu.id]; uac_data->uas_tsx = NULL; } } return; } /* Get the data that we attached to the UAC transaction previously */ uac_data = (struct uac_data*) tsx->mod_data[mod_tu.id]; /* Handle incoming response */ if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { pjsip_rx_data *rdata; pjsip_response_addr res_addr; pjsip_via_hdr *hvia; pjsip_tx_data *tdata; rdata = event->body.tsx_state.src.rdata; /* Do not forward 100 response for INVITE (we already responded * INVITE with 100) */ if (tsx->method.id == PJSIP_INVITE_METHOD && rdata->msg_info.msg->line.status.code == 100) { return; } /* Create response to be forwarded upstream * (Via will be stripped here) */ status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, &tdata); if (status != PJ_SUCCESS) { app_perror("Error creating response", status); return; } /* Get topmost Via header of the new response */ hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); if (hvia == NULL) { /* Invalid response! Just drop it */ pjsip_tx_data_dec_ref(tdata); return; } /* Calculate the address to forward the response */ pj_bzero(&res_addr, sizeof(res_addr)); res_addr.dst_host.type = PJSIP_TRANSPORT_UDP; res_addr.dst_host.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); /* Destination address is Via's received param */ res_addr.dst_host.addr.host = hvia->recvd_param; if (res_addr.dst_host.addr.host.slen == 0) { /* Someone has messed up our Via header! */ res_addr.dst_host.addr.host = hvia->sent_by.host; } /* Destination port is the rport */ if (hvia->rport_param != 0 && hvia->rport_param != -1) res_addr.dst_host.addr.port = hvia->rport_param; if (res_addr.dst_host.addr.port == 0) { /* Ugh, original sender didn't put rport! * At best, can only send the response to the port in Via. */ res_addr.dst_host.addr.port = hvia->sent_by.port; } /* Forward response with the UAS transaction */ pjsip_tsx_send_msg(uac_data->uas_tsx, tdata); } /* If UAC transaction is terminated, terminate the UAS as well. * This could happen because of: * - timeout on the UAC side * - receipt of 2xx response to INVITE */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED && uac_data && uac_data->uas_tsx) { pjsip_transaction *uas_tsx; struct uas_data *uas_data; uas_tsx = uac_data->uas_tsx; uas_data = (struct uas_data*) uas_tsx->mod_data[mod_tu.id]; uas_data->uac_tsx = NULL; if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) { /* Send 408/Timeout if this is an INVITE transaction, since * we must have sent provisional response before. For non * INVITE transaction, just destroy it. */ if (tsx->method.id == PJSIP_INVITE_METHOD) { pjsip_tx_data *tdata = uas_tsx->last_tx; tdata->msg->line.status.code = PJSIP_SC_REQUEST_TIMEOUT; tdata->msg->line.status.reason = pj_str("Request timed out"); tdata->msg->body = NULL; pjsip_tx_data_add_ref(tdata); pjsip_tx_data_invalidate_msg(tdata); pjsip_tsx_send_msg(uas_tsx, tdata); } else { /* For non-INVITE, just destroy the UAS transaction */ pjsip_tsx_terminate(uas_tsx, PJSIP_SC_REQUEST_TIMEOUT); } } else if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { if (uas_tsx->state < PJSIP_TSX_STATE_TERMINATED) { pjsip_msg *msg; int code; msg = event->body.tsx_state.src.rdata->msg_info.msg; code = msg->line.status.code; uac_data->uas_tsx = NULL; pjsip_tsx_terminate(uas_tsx, code); } } } }