📄 stateful_proxy.c
字号:
/* 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;
}
/* 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->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);
}
}
}
}
/*
* main()
*/
int main(int argc, char *argv[])
{
pj_status_t status;
global.port = 5060;
global.record_route = 0;
pj_log_set_level(4);
status = init_options(argc, argv);
if (status != PJ_SUCCESS)
return 1;
status = init_stack();
if (status != PJ_SUCCESS) {
app_perror("Error initializing stack", status);
return 1;
}
status = init_proxy();
if (status != PJ_SUCCESS) {
app_perror("Error initializing proxy", status);
return 1;
}
status = init_stateful_proxy();
if (status != PJ_SUCCESS) {
app_perror("Error initializing stateful proxy", status);
return 1;
}
#if PJ_HAS_THREADS
status = pj_thread_create(global.pool, "sproxy", &worker_thread,
NULL, 0, 0, &global.thread);
if (status != PJ_SUCCESS) {
app_perror("Error creating thread", status);
return 1;
}
while (!global.quit_flag) {
char line[10];
puts("\n"
"Menu:\n"
" q quit\n"
" d dump status\n"
" dd dump detailed status\n"
"");
fgets(line, sizeof(line), stdin);
if (line[0] == 'q') {
global.quit_flag = PJ_TRUE;
} else if (line[0] == 'd') {
pj_bool_t detail = (line[1] == 'd');
pjsip_endpt_dump(global.endpt, detail);
pjsip_tsx_layer_dump(detail);
}
}
pj_thread_join(global.thread);
#else
puts("\nPress Ctrl-C to quit\n");
for (;;) {
pj_time_val delay = {0, 0};
pjsip_endpt_handle_events(global.endpt, &delay);
}
#endif
destroy_stack();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -