sip_inv.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 2,560 行 · 第 1/5 页
C
2,560 行
case PJSIP_INV_STATE_CONNECTING: case PJSIP_INV_STATE_CONFIRMED: /* For established dialog, send BYE */ status = pjsip_dlg_create_request(inv->dlg, &pjsip_bye_method, -1, &tdata); break; case PJSIP_INV_STATE_DISCONNECTED: /* No need to do anything. */ return PJSIP_ESESSIONTERMINATED; default: pj_assert("!Invalid operation!"); return PJ_EINVALIDOP; } if (status != PJ_SUCCESS) return status; /* Done */ *p_tdata = tdata; return PJ_SUCCESS;}/* * Create re-INVITE. */PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv, const pj_str_t *new_contact, const pjmedia_sdp_session *new_offer, pjsip_tx_data **p_tdata ){ pj_status_t status; pjsip_contact_hdr *contact_hdr = NULL; /* Check arguments. */ PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL); /* Must NOT have a pending INVITE transaction */ PJ_ASSERT_RETURN(inv->invite_tsx==NULL, PJ_EINVALIDOP); pjsip_dlg_inc_lock(inv->dlg); if (new_contact) { pj_str_t tmp; const pj_str_t STR_CONTACT = { "Contact", 7 }; pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact); contact_hdr = pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT, tmp.ptr, tmp.slen, NULL); if (!contact_hdr) { status = PJSIP_EINVALIDURI; goto on_return; } } if (new_offer) { if (!inv->neg) { status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer, &inv->neg); if (status != PJ_SUCCESS) goto on_return; } else switch (pjmedia_sdp_neg_get_state(inv->neg)) { case PJMEDIA_SDP_NEG_STATE_NULL: pj_assert(!"Unexpected SDP neg state NULL"); status = PJ_EBUG; goto on_return; case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER: PJ_LOG(4,(inv->obj_name, "pjsip_inv_reinvite: already have an offer, new " "offer is ignored")); break; case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER: status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg, new_offer); if (status != PJ_SUCCESS) goto on_return; break; case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO: PJ_LOG(4,(inv->obj_name, "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new " "offer is ignored")); break; case PJMEDIA_SDP_NEG_STATE_DONE: status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg, new_offer); if (status != PJ_SUCCESS) goto on_return; break; } } if (contact_hdr) inv->dlg->local.contact = contact_hdr; status = pjsip_inv_invite(inv, p_tdata);on_return: pjsip_dlg_dec_lock(inv->dlg); return status;}/* * Create UPDATE. */PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv, const pj_str_t *new_contact, const pjmedia_sdp_session *new_offer, pjsip_tx_data **p_tdata ){ PJ_UNUSED_ARG(inv); PJ_UNUSED_ARG(new_contact); PJ_UNUSED_ARG(new_offer); PJ_UNUSED_ARG(p_tdata); PJ_TODO(CREATE_UPDATE_REQUEST); return PJ_ENOTSUP;}/* * Send a request or response message. */PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv, pjsip_tx_data *tdata){ pj_status_t status; /* Verify arguments. */ PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL); PJ_LOG(5,(inv->obj_name, "Sending %s", pjsip_tx_data_get_info(tdata))); if (tdata->msg->type == PJSIP_REQUEST_MSG) { struct tsx_inv_data *tsx_inv_data; pjsip_dlg_inc_lock(inv->dlg); tsx_inv_data = pj_pool_zalloc(inv->pool, sizeof(struct tsx_inv_data)); tsx_inv_data->inv = inv; pjsip_dlg_dec_lock(inv->dlg); status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id, tsx_inv_data); if (status != PJ_SUCCESS) return status; } else { pjsip_cseq_hdr *cseq; /* Can only do this to send response to original INVITE * request. */ PJ_ASSERT_RETURN((cseq=pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL))!=NULL && (cseq->cseq == inv->invite_tsx->cseq), PJ_EINVALIDOP); status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); if (status != PJ_SUCCESS) return status; } /* Done (?) */ return PJ_SUCCESS;}/* * Respond to incoming CANCEL request. */static void inv_respond_incoming_cancel(pjsip_inv_session *inv, pjsip_transaction *cancel_tsx, pjsip_rx_data *rdata){ pjsip_tx_data *tdata; pjsip_transaction *invite_tsx; pj_str_t key; pj_status_t status; /* See if we have matching INVITE server transaction: */ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &pjsip_invite_method, rdata); invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); if (invite_tsx == NULL) { /* Invite transaction not found! * Respond CANCEL with 491 (RFC 3261 Section 9.2 page 42) */ status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL, &tdata); } else { /* Always answer CANCEL will 200 (OK) regardless of * the state of the INVITE transaction. */ status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL, &tdata); } /* See if we have created the response successfully. */ if (status != PJ_SUCCESS) return; /* Send the CANCEL response */ status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata); if (status != PJ_SUCCESS) return; /* See if we need to terminate the UAS INVITE transaction * with 487 (Request Terminated) response. */ if (invite_tsx && invite_tsx->status_code < 200) { pj_assert(invite_tsx->last_tx != NULL); tdata = invite_tsx->last_tx; status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL); if (status == PJ_SUCCESS) pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata); } if (invite_tsx) pj_mutex_unlock(invite_tsx->mutex);}/* * Respond to incoming BYE request. */static void inv_respond_incoming_bye( pjsip_inv_session *inv, pjsip_transaction *bye_tsx, pjsip_rx_data *rdata, pjsip_event *e ){ pj_status_t status; pjsip_tx_data *tdata; /* Respond BYE with 200: */ status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata); if (status != PJ_SUCCESS) return; /* Terminate session: */ if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { inv_set_cause(inv, PJSIP_SC_OK, NULL); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); }}/* * Respond to BYE request. */static void inv_handle_bye_response( pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_rx_data *rdata, pjsip_event *e ){ pj_status_t status; if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) { inv_set_cause(inv, PJSIP_SC_OK, NULL); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); return; } /* Handle 401/407 challenge. */ if (tsx->status_code == 401 || tsx->status_code == 407) { pjsip_tx_data *tdata; status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess, rdata, tsx->last_tx, &tdata); if (status != PJ_SUCCESS) { /* Does not have proper credentials. * End the session anyway. */ inv_set_cause(inv, PJSIP_SC_OK, NULL); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } else { /* Re-send BYE. */ status = pjsip_inv_send_msg(inv, tdata); } } else { /* End the session. */ inv_set_cause(inv, PJSIP_SC_OK, NULL); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); }}/* * State NULL is before anything is sent/received. */static void inv_on_state_null( 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_INVITE_METHOD) { /* Keep the initial INVITE transaction. */ if (inv->invite_tsx == NULL) inv->invite_tsx = tsx; if (dlg->role == PJSIP_ROLE_UAC) { switch (tsx->state) { case PJSIP_TSX_STATE_CALLING: inv_set_state(inv, PJSIP_INV_STATE_CALLING, e); break; default: inv_on_state_calling(inv, e); break; } } else { switch (tsx->state) { case PJSIP_TSX_STATE_TRYING: inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e); break; case PJSIP_TSX_STATE_PROCEEDING: inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e); if (tsx->status_code > 100) inv_set_state(inv, PJSIP_INV_STATE_EARLY, e); break; default: inv_on_state_incoming(inv, e); break; } } } else { pj_assert(!"Unexpected transaction type"); }}/* * State CALLING is after sending initial INVITE request but before * any response (with tag) is received. */static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e){ pjsip_transaction *tsx = e->body.tsx_state.tsx; pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx); pj_status_t status; PJ_ASSERT_ON_FAIL(tsx && dlg, return); if (tsx == inv->invite_tsx) { switch (tsx->state) { case PJSIP_TSX_STATE_CALLING: inv_set_state(inv, PJSIP_INV_STATE_CALLING, e); break; case PJSIP_TSX_STATE_PROCEEDING: if (dlg->remote.info->tag.slen) { inv_set_state(inv, PJSIP_INV_STATE_EARLY, e); inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); } else { /* Ignore 100 (Trying) response, as it doesn't change * session state. It only ceases retransmissions. */ } break; case PJSIP_TSX_STATE_COMPLETED: if (tsx->status_code/100 == 2) { /* This should not happen. * When transaction receives 2xx, it should be terminated */ pj_assert(0); inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e); inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); } else if (tsx->status_code==401 || tsx->status_code==407) { /* Handle authentication failure: * Resend the request with Authorization header. */ pjsip_tx_data *tdata; status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess, e->body.tsx_state.src.rdata, tsx->last_tx, &tdata); if (status != PJ_SUCCESS) { /* Does not have proper credentials. * End the session. */ inv_set_cause(inv, tsx->status_code, &tsx->status_text); inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); } else { /* Restart session. */ inv->state = PJSIP_INV_STATE_NULL; inv->invite_tsx = NULL; /* Send the request. */ status = pjsip_inv_send_msg(inv, tdata); } } 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: /* 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); inv_check_sdp_in_incoming_msg(inv, tsx, e->body.tsx_state.src.rdata); /* Send ACK */ 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: break; } } 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 INCOMING is after we received the request, but before * responses with tag are sent. */static void inv_on_state_incoming( 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) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?