sip_inv.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 2,560 行 · 第 1/5 页
C
2,560 行
/* * Handle the INVITE state transition. */ switch (tsx->state) { case PJSIP_TSX_STATE_TRYING: inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e); break; case PJSIP_TSX_STATE_PROCEEDING: /* * Transaction sent provisional response. */ if (tsx->status_code > 100) inv_set_state(inv, PJSIP_INV_STATE_EARLY, e); break; case PJSIP_TSX_STATE_COMPLETED: /* * Transaction sent final response. */ if (tsx->status_code/100 == 2) { inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e); } else { inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } break; case PJSIP_TSX_STATE_TERMINATED: /* * This happens on transport error (e.g. failed to send * response) */ inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); break; default: pj_assert(!"Unexpected INVITE state"); break; } } else if (tsx->method.id == PJSIP_CANCEL_METHOD && tsx->role == PJSIP_ROLE_UAS && tsx->state < PJSIP_TSX_STATE_COMPLETED && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG ) { /* * Handle incoming CANCEL request. */ inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata); }}/* * State EARLY is for both UAS and UAC, after response with To tag * is sent/received. */static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e){ pjsip_transaction *tsx = e->body.tsx_state.tsx; pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx); PJ_ASSERT_ON_FAIL(tsx && dlg, return); if (tsx == inv->invite_tsx) { /* * Handle the INVITE state progress. */ switch (tsx->state) { case PJSIP_TSX_STATE_PROCEEDING: /* Send/received another provisional response. */ inv_set_state(inv, PJSIP_INV_STATE_EARLY, e); if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); } break; case PJSIP_TSX_STATE_COMPLETED: if (tsx->status_code/100 == 2) { inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e); if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); } } else { inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } break; case PJSIP_TSX_STATE_CONFIRMED: /* For some reason can go here */ case PJSIP_TSX_STATE_TERMINATED: /* INVITE transaction can be terminated either because UAC * transaction received 2xx response or because of transport * error. */ if (tsx->status_code/100 == 2) { /* This must be receipt of 2xx response */ /* Set state to CONNECTING */ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e); if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); } /* if UAC, send ACK and move state to confirmed. */ if (tsx->role == PJSIP_ROLE_UAC) { pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG); inv_send_ack(inv, e->body.tsx_state.src.rdata); inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e); } } else { inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } break; default: pj_assert(!"Unexpected INVITE tsx state"); } } else if (inv->role == PJSIP_ROLE_UAS && tsx->role == PJSIP_ROLE_UAS && tsx->method.id == PJSIP_CANCEL_METHOD && tsx->state < PJSIP_TSX_STATE_COMPLETED && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG ) { /* * Handle incoming CANCEL request. */ inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata); } else if (inv->role == PJSIP_ROLE_UAC && tsx->role == PJSIP_ROLE_UAC && tsx->method.id == PJSIP_CANCEL_METHOD) { /* * Handle case when outgoing CANCEL is answered with 481 (Call/ * Transaction Does Not Exist), 408, or when it's timed out. In these * cases, disconnect session (i.e. dialog usage only). */ if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || tsx->status_code == PJSIP_SC_TSX_TIMEOUT || tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) { inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } }}/* * State CONNECTING is after 2xx response to INVITE is sent/received. */static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e){ pjsip_transaction *tsx = e->body.tsx_state.tsx; pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx); PJ_ASSERT_ON_FAIL(tsx && dlg, return); if (tsx == inv->invite_tsx) { /* * Handle INVITE state progression. */ switch (tsx->state) { case PJSIP_TSX_STATE_CONFIRMED: if (tsx->status_code/100 == 2) inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e); break; case PJSIP_TSX_STATE_TERMINATED: /* INVITE transaction can be terminated either because UAC * transaction received 2xx response or because of transport * error. */ if (tsx->status_code/100 != 2) { inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } break; case PJSIP_TSX_STATE_DESTROYED: /* Do nothing. */ break; default: pj_assert(!"Unexpected state"); } } else if (tsx->role == PJSIP_ROLE_UAS && tsx->method.id == PJSIP_BYE_METHOD && tsx->status_code < 200 && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { /* * Handle incoming BYE. */ inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e ); } else if (tsx->method.id == PJSIP_BYE_METHOD && tsx->role == PJSIP_ROLE_UAC && (tsx->state == PJSIP_TSX_STATE_COMPLETED || tsx->state == PJSIP_TSX_STATE_TERMINATED)) { /* * Outgoing BYE */ inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e); } else if (tsx->method.id == PJSIP_CANCEL_METHOD && tsx->role == PJSIP_ROLE_UAS && tsx->status_code < 200 && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { /* * Handle strandled incoming CANCEL. */ pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; pjsip_tx_data *tdata; pj_status_t status; status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; status = pjsip_dlg_send_response(dlg, tsx, tdata); if (status != PJ_SUCCESS) return; }}/* * State CONFIRMED is after ACK is sent/received. */static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e){ pjsip_transaction *tsx = e->body.tsx_state.tsx; pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx); PJ_ASSERT_ON_FAIL(tsx && dlg, return); if (tsx->method.id == PJSIP_BYE_METHOD && tsx->role == PJSIP_ROLE_UAC && (tsx->state == PJSIP_TSX_STATE_COMPLETED || tsx->state == PJSIP_TSX_STATE_TERMINATED)) { /* * Outgoing BYE */ inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e); } else if (tsx->method.id == PJSIP_BYE_METHOD && tsx->role == PJSIP_ROLE_UAS && tsx->status_code < 200 && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { /* * Handle incoming BYE. */ inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e ); } else if (tsx->method.id == PJSIP_CANCEL_METHOD && tsx->role == PJSIP_ROLE_UAS && tsx->status_code < 200 && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { /* * Handle strandled incoming CANCEL. */ pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; pjsip_tx_data *tdata; pj_status_t status; status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; status = pjsip_dlg_send_response(dlg, tsx, tdata); if (status != PJ_SUCCESS) return; } else if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->role == PJSIP_ROLE_UAS) { /* * Handle incoming re-INVITE */ if (tsx->state == PJSIP_TSX_STATE_TRYING) { pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; pjsip_tx_data *tdata; pj_status_t status; /* Check if we have INVITE pending. */ if (inv->invite_tsx && inv->invite_tsx!=tsx) { pj_str_t reason; reason = pj_str("Another INVITE transaction in progress"); /* Can not receive re-INVITE while another one is pending. */ status = pjsip_dlg_create_response( inv->dlg, rdata, 500, &reason, &tdata); if (status != PJ_SUCCESS) return; status = pjsip_dlg_send_response( inv->dlg, tsx, tdata); return; } /* Save the invite transaction. */ inv->invite_tsx = tsx; /* Process SDP in incoming message. */ status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata); if (status != PJ_SUCCESS) { /* Not Acceptable */ const pjsip_hdr *accept; status = pjsip_dlg_create_response(inv->dlg, rdata, 488, NULL, &tdata); if (status != PJ_SUCCESS) return; accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT, NULL); if (accept) { pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, accept)); } status = pjsip_dlg_send_response(dlg, tsx, tdata); return; } /* Create 2xx ANSWER */ status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; /* Process SDP in the answer */ status = process_answer(inv, 200, tdata, NULL); if (status != PJ_SUCCESS) { /* * SDP negotiation has failed. */ pj_status_t rc; pj_str_t reason; /* Delete the 2xx answer */ pjsip_tx_data_dec_ref(tdata); /* Create 500 response */ reason = pj_str("SDP negotiation failed"); rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason, &tdata); if (rc == PJ_SUCCESS) { pjsip_warning_hdr *w; const pj_str_t *endpt_name; endpt_name = pjsip_endpt_name(dlg->endpt); w = pjsip_warning_hdr_create_from_status(tdata->pool, endpt_name, status); if (w) pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w); pjsip_inv_send_msg(inv, tdata); } return; } /* Send 2xx regardless of the status of negotiation */ status = pjsip_inv_send_msg(inv, tdata); } } else if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->role == PJSIP_ROLE_UAC) { /* * Handle outgoing re-INVITE */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED && tsx->status_code/100 == 2) { /* Re-INVITE was accepted. */ /* Process SDP */ inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); /* Send ACK */ inv_send_ack(inv, e->body.tsx_state.src.rdata); } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED && (tsx->status_code==401 || tsx->status_code==407)) { pjsip_tx_data *tdata; pj_status_t status; /* Handle authentication challenge. */ status = pjsip_auth_clt_reinit_req( &dlg->auth_sess, e->body.tsx_state.src.rdata, tsx->last_tx, &tdata); if (status != PJ_SUCCESS) return; /* Send re-INVITE */ status = pjsip_inv_send_msg( inv, tdata); } else if (tsx->status_code==PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || tsx->status_code==PJSIP_SC_REQUEST_TIMEOUT || tsx->status_code >= 700) { /* * Handle responses that terminates dialog. */ inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } }}/* * After session has been terminated, but before dialog is destroyed * (because dialog has other usages, or because dialog is waiting for * the last transaction to terminate). */static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e){ pjsip_transaction *tsx = e->body.tsx_state.tsx; pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx); PJ_ASSERT_ON_FAIL(tsx && dlg, return); if (tsx->role == PJSIP_ROLE_UAS && tsx->status_code < 200 && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; /* * Respond BYE with 200/OK */ if (tsx->method.id == PJSIP_BYE_METHOD) { inv_respond_incoming_bye( inv, tsx, rdata, e ); } else if (tsx->method.id == PJSIP_CANCEL_METHOD) { /* * Respond CANCEL with 200/OK too. */ pjsip_tx_data *tdata; pj_status_t status; status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; status = pjsip_dlg_send_response(dlg, tsx, tdata); if (status != PJ_SUCCESS) return; } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?