/* Callback to be called to handle incoming requests. */ static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) { pjsip_tx_data *tdata; pj_status_t status; /* Verify incoming request */ status = proxy_verify_request(rdata); if (status != PJ_SUCCESS) { app_perror("RX invalid request", status); return PJ_TRUE; } /* * Request looks sane, next clone the request to create transmit data. */ status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL, NULL, 0, &tdata); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); return PJ_TRUE; } /* Process routing */ status = proxy_process_routing(tdata); if (status != PJ_SUCCESS) { app_perror("Error processing route", status); return PJ_TRUE; } /* Calculate target */ status = proxy_calculate_target(rdata, tdata); if (status != PJ_SUCCESS) { app_perror("Error calculating target", status); return PJ_TRUE; } /* Target is set, forward the request */ status = pjsip_endpt_send_request_stateless(global.endpt, tdata, NULL, NULL); if (status != PJ_SUCCESS) { app_perror("Error forwarding request", status); return PJ_TRUE; } return PJ_TRUE; }
pj_status_t PJUtils::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) { pj_status_t status = pjsip_endpt_create_request_fwd(endpt, rdata, uri, branch, 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 new incoming requests. */ static pj_bool_t proxy_on_rx_request( pjsip_rx_data *rdata ) { pjsip_transaction *uas_tsx, *uac_tsx; struct uac_data *uac_data; struct uas_data *uas_data; pjsip_tx_data *tdata; pj_status_t status; if (rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) { /* Verify incoming request */ status = proxy_verify_request(rdata); if (status != PJ_SUCCESS) { app_perror("RX invalid request", status); return PJ_TRUE; } /* * Request looks sane, next clone the request to create transmit data. */ status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL, NULL, 0, &tdata); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); return PJ_TRUE; } /* Process routing */ status = proxy_process_routing(tdata); if (status != PJ_SUCCESS) { app_perror("Error processing route", status); return PJ_TRUE; } /* Calculate target */ status = proxy_calculate_target(rdata, tdata); if (status != PJ_SUCCESS) { app_perror("Error calculating target", status); return PJ_TRUE; } /* Everything is set to forward the request. */ /* If this is an ACK request, forward statelessly. * This happens if the proxy records route and this ACK * is sent for 2xx response. An ACK that is sent for non-2xx * final response will be absorbed by transaction layer, and * it will not be received by on_rx_request() callback. */ if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) { status = pjsip_endpt_send_request_stateless(global.endpt, tdata, NULL, NULL); if (status != PJ_SUCCESS) { app_perror("Error forwarding request", status); return PJ_TRUE; } return PJ_TRUE; } /* Create UAC transaction for forwarding the request. * Set our module as the transaction user to receive further * events from this transaction. */ status = pjsip_tsx_create_uac(&mod_tu, tdata, &uac_tsx); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); return PJ_TRUE; } /* Create UAS transaction to handle incoming request */ status = pjsip_tsx_create_uas(&mod_tu, rdata, &uas_tsx); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); return PJ_TRUE; } /* Feed the request to the UAS transaction to drive it's state * out of NULL state. */ pjsip_tsx_recv_msg(uas_tsx, rdata); /* Attach a data to the UAC transaction, to be used to find the * UAS transaction when we receive response in the UAC side. */ uac_data = (struct uac_data*) pj_pool_alloc(uac_tsx->pool, sizeof(struct uac_data)); uac_data->uas_tsx = uas_tsx; uac_tsx->mod_data[mod_tu.id] = (void*)uac_data; /* Attach data to the UAS transaction, to find the UAC transaction * when cancelling INVITE request. */ uas_data = (struct uas_data*) pj_pool_alloc(uas_tsx->pool, sizeof(struct uas_data)); uas_data->uac_tsx = uac_tsx; uas_tsx->mod_data[mod_tu.id] = (void*)uas_data; /* Everything is setup, forward the request */ status = pjsip_tsx_send_msg(uac_tsx, tdata); if (status != PJ_SUCCESS) { pjsip_tx_data *err_res; /* Fail to send request, for some reason */ /* Destroy transmit data */ pjsip_tx_data_dec_ref(tdata); /* I think UAC transaction should have been destroyed when * it fails to send request, so no need to destroy it. pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); */ /* Send 500/Internal Server Error to UAS transaction */ pjsip_endpt_create_response(global.endpt, rdata, 500, NULL, &err_res); pjsip_tsx_send_msg(uas_tsx, err_res); return PJ_TRUE; } /* Send 100/Trying if this is an INVITE */ if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { pjsip_tx_data *res100; pjsip_endpt_create_response(global.endpt, rdata, 100, NULL, &res100); pjsip_tsx_send_msg(uas_tsx, res100); } } else { /* This is CANCEL request */ pjsip_transaction *invite_uas; struct uas_data *uas_data; pj_str_t key; /* Find the UAS INVITE transaction */ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_UAS_ROLE, pjsip_get_invite_method(), rdata); invite_uas = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); if (!invite_uas) { /* Invite transaction not found, respond CANCEL with 481 */ pjsip_endpt_respond_stateless(global.endpt, rdata, 481, NULL, NULL, NULL); return PJ_TRUE; } /* Respond 200 OK to CANCEL */ pjsip_endpt_respond(global.endpt, NULL, rdata, 200, NULL, NULL, NULL, NULL); /* Send CANCEL to cancel the UAC transaction. * The UAS INVITE transaction will get final response when * we receive final response from the UAC INVITE transaction. */ uas_data = (struct uas_data*) invite_uas->mod_data[mod_tu.id]; if (uas_data->uac_tsx && uas_data->uac_tsx->status_code < 200) { pjsip_tx_data *cancel; pj_mutex_lock(uas_data->uac_tsx->mutex); pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx, &cancel); pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL); pj_mutex_unlock(uas_data->uac_tsx->mutex); } /* Unlock UAS tsx because it is locked in find_tsx() */ pj_mutex_unlock(invite_uas->mutex); } return PJ_TRUE; }