📄 sip_transaction.c
字号:
pjsip_tx_data_dec_ref( tsx->last_tx ); tsx->last_tx = NULL; } /* Cancel timeout timer. */ if (tsx->timeout_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); tsx->timeout_timer._timer_id = -1; } /* Cancel retransmission timer. */ if (tsx->retransmit_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); tsx->retransmit_timer._timer_id = -1; } /* Clear some pending flags. */ tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED | TSX_HAS_PENDING_SEND); /* Refuse to destroy transaction if it has pending resolving. */ if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) { tsx->transport_flag |= TSX_HAS_PENDING_DESTROY; tsx->tsx_user = NULL; PJ_LOG(4,(tsx->obj_name, "Will destroy later because transport is " "in progress")); return PJ_EBUSY; } /* Clear TLS, so that mutex will not be unlocked */ lck = pj_thread_local_get(pjsip_tsx_lock_tls_id); while (lck) { if (lck->tsx == tsx) { lck->is_alive = 0; } lck = lck->prev; } pj_mutex_destroy(tsx->mutex); PJ_LOG(5,(tsx->obj_name, "Transaction destroyed!")); pjsip_endpt_release_pool(tsx->endpt, tsx->pool); return PJ_SUCCESS;}/* * Callback when timer expires. */static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry){ pjsip_event event; pjsip_transaction *tsx = entry->user_data; struct tsx_lock_data lck; PJ_UNUSED_ARG(theap); PJ_LOG(5,(tsx->obj_name, "%s timer event", (entry->id==TSX_TIMER_RETRANSMISSION ? "Retransmit":"Timeout"))); if (entry->id == TSX_TIMER_RETRANSMISSION) { PJSIP_EVENT_INIT_TIMER(event, &tsx->retransmit_timer); } else { PJSIP_EVENT_INIT_TIMER(event, &tsx->timeout_timer); } /* Dispatch event to transaction. */ lock_tsx(tsx, &lck); (*tsx->state_handler)(tsx, &event); unlock_tsx(tsx, &lck);}/* * Set transaction state, and inform TU about the transaction state change. */static void tsx_set_state( pjsip_transaction *tsx, pjsip_tsx_state_e state, pjsip_event_id_e event_src_type, void *event_src ){ pjsip_tsx_state_e prev_state = tsx->state; /* New state must be greater than previous state */ pj_assert(state >= tsx->state); PJ_LOG(5, (tsx->obj_name, "State changed from %s to %s, event=%s", state_str[tsx->state], state_str[state], pjsip_event_str(event_src_type))); /* Change state. */ tsx->state = state; /* Update the state handlers. */ if (tsx->role == PJSIP_ROLE_UAC) { tsx->state_handler = tsx_state_handler_uac[state]; } else { tsx->state_handler = tsx_state_handler_uas[state]; } /* Before informing TU about state changed, inform TU about * rx event. */ if (event_src_type==PJSIP_EVENT_RX_MSG && tsx->tsx_user) { pjsip_rx_data *rdata = event_src; pj_assert(rdata != NULL); if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG && tsx->tsx_user->on_rx_response) { (*tsx->tsx_user->on_rx_response)(rdata); } } /* Inform TU about state changed. */ if (tsx->tsx_user && tsx->tsx_user->on_tsx_state) { pjsip_event e; PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src, prev_state); (*tsx->tsx_user->on_tsx_state)(tsx, &e); } /* When the transaction is terminated, release transport, and free the * saved last transmitted message. */ if (state == PJSIP_TSX_STATE_TERMINATED) { pj_time_val timeout = {0, 0}; /* Reschedule timeout timer to destroy this transaction. */ if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) { tsx->transport_flag |= TSX_HAS_PENDING_DESTROY; } else { /* Cancel timeout timer. */ if (tsx->timeout_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); tsx->timeout_timer._timer_id = -1; } pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout); } } else if (state == PJSIP_TSX_STATE_DESTROYED) { /* Unregister transaction. */ mod_tsx_layer_unregister_tsx(tsx); /* Destroy transaction. */ tsx_destroy(tsx); }}/* * Create, initialize, and register UAC transaction. */PJ_DEF(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user, pjsip_tx_data *tdata, pjsip_transaction **p_tsx){ pjsip_transaction *tsx; pjsip_msg *msg; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; pjsip_host_info dst_info; struct tsx_lock_data lck; pj_status_t status; /* Validate arguments. */ PJ_ASSERT_RETURN(tdata && tdata->msg && p_tsx, PJ_EINVAL); PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); /* Method MUST NOT be ACK! */ PJ_ASSERT_RETURN(tdata->msg->line.req.method.id != PJSIP_ACK_METHOD, PJ_EINVALIDOP); /* Keep shortcut */ msg = tdata->msg; /* Make sure CSeq header is present. */ cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL); if (!cseq) { pj_assert(!"CSeq header not present in outgoing message!"); return PJSIP_EMISSINGHDR; } /* Create transaction instance. */ status = tsx_create( tsx_user, &tsx); if (status != PJ_SUCCESS) return status; /* Lock transaction. */ lock_tsx(tsx, &lck); /* Role is UAC. */ tsx->role = PJSIP_ROLE_UAC; /* Save method. */ pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method); /* Save CSeq. */ tsx->cseq = cseq->cseq; /* Generate Via header if it doesn't exist. */ via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL); if (via == NULL) { via = pjsip_via_hdr_create(tdata->pool); pjsip_msg_insert_first_hdr(msg, (pjsip_hdr*) via); } /* Generate branch parameter if it doesn't exist. */ if (via->branch_param.slen == 0) { pj_str_t tmp; via->branch_param.ptr = pj_pool_alloc(tsx->pool, PJSIP_MAX_BRANCH_LEN); via->branch_param.slen = PJSIP_MAX_BRANCH_LEN; pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID, PJSIP_RFC3261_BRANCH_LEN); tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2; *(tmp.ptr-2) = 80; *(tmp.ptr-1) = 106; pj_generate_unique_string( &tmp ); /* Save branch parameter. */ tsx->branch = via->branch_param; } else { /* Copy branch parameter. */ pj_strdup(tsx->pool, &tsx->branch, &via->branch_param); } /* Generate transaction key. */ create_tsx_key_3261( tsx->pool, &tsx->transaction_key, PJSIP_ROLE_UAC, &tsx->method, &via->branch_param); /* Calculate hashed key value. */#ifdef PRECALC_HASH tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr, tsx->transaction_key.slen);#endif PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen, tsx->transaction_key.ptr)); /* Begin with State_Null. * Manually set-up the state becase we don't want to call the callback. */ tsx->state = PJSIP_TSX_STATE_NULL; tsx->state_handler = &tsx_on_state_null; /* Save the message. */ tsx->last_tx = tdata; pjsip_tx_data_add_ref(tsx->last_tx); /* Determine whether reliable transport should be used initially. * This will be updated whenever transport has changed. */ status = pjsip_get_request_dest(tdata, &dst_info); if (status != PJ_SUCCESS) { tsx_destroy(tsx); return status; } tsx->is_reliable = (dst_info.flag & PJSIP_TRANSPORT_RELIABLE); /* Register transaction to hash table. */ status = mod_tsx_layer_register_tsx(tsx); if (status != PJ_SUCCESS) { pj_assert(!"Bug in branch_param generator (i.e. not unique)"); tsx_destroy(tsx); return status; } /* Unlock transaction and return. */ unlock_tsx(tsx, &lck); PJ_LOG(5,(tsx->obj_name, "Transaction created for %s", pjsip_tx_data_get_info(tdata))); *p_tsx = tsx; return PJ_SUCCESS;}/* * Create, initialize, and register UAS transaction. */PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user, pjsip_rx_data *rdata, pjsip_transaction **p_tsx){ pjsip_transaction *tsx; pjsip_msg *msg; pj_str_t *branch; pjsip_cseq_hdr *cseq; pj_status_t status; struct tsx_lock_data lck; /* Validate arguments. */ PJ_ASSERT_RETURN(rdata && rdata->msg_info.msg && p_tsx, PJ_EINVAL); /* Keep shortcut to message */ msg = rdata->msg_info.msg; /* Make sure this is a request message. */ PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); /* Make sure method is not ACK */ PJ_ASSERT_RETURN(msg->line.req.method.id != PJSIP_ACK_METHOD, PJ_EINVALIDOP); /* Make sure CSeq header is present. */ cseq = rdata->msg_info.cseq; if (!cseq) return PJSIP_EMISSINGHDR; /* Make sure Via header is present. */ if (rdata->msg_info.via == NULL) return PJSIP_EMISSINGHDR; /* Check that method in CSeq header match request method. * Reference: PROTOS #1922 */ if (pjsip_method_cmp(&msg->line.req.method, &rdata->msg_info.cseq->method) != 0) { PJ_LOG(4,(THIS_FILE, "Error: CSeq header contains different " "method than the request line")); return PJSIP_EINVALIDHDR; } /* * Create transaction instance. */ status = tsx_create( tsx_user, &tsx); if (status != PJ_SUCCESS) return status; /* Lock transaction. */ lock_tsx(tsx, &lck); /* Role is UAS */ tsx->role = PJSIP_ROLE_UAS; /* Save method. */ pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method); /* Save CSeq */ tsx->cseq = cseq->cseq; /* Get transaction key either from branch for RFC3261 message, or * create transaction key. */ status = pjsip_tsx_create_key(tsx->pool, &tsx->transaction_key, PJSIP_ROLE_UAS, &tsx->method, rdata); if (status != PJ_SUCCESS) { tsx_destroy(tsx); return status; } /* Calculate hashed key value. */#ifdef PRECALC_HASH tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr, tsx->transaction_key.slen);#endif /* Duplicate branch parameter for transaction. */ branch = &rdata->msg_info.via->branch_param; pj_strdup(tsx->pool, &tsx->branch, branch); PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen, tsx->transaction_key.ptr)); /* Begin with state NULL. * Manually set-up the state becase we don't want to call the callback. */ tsx->state = PJSIP_TSX_STATE_NULL; tsx->state_handler = &tsx_on_state_null; /* Get response address. */ status = pjsip_get_response_addr( tsx->pool, rdata, &tsx->res_addr ); if (status != PJ_SUCCESS) { tsx_destroy(tsx); return status; } /* If it's decided that we should use current transport, keep the * transport. */ if (tsx->res_addr.transport) { tsx->transport = tsx->res_addr.transport; pjsip_transport_add_ref(tsx->transport); pj_memcpy(&tsx->addr, &tsx->res_addr.addr, tsx->res_addr.addr_len); tsx->addr_len = tsx->res_addr.addr_len; tsx->is_reliable = PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport); } /* Register the transaction. */ status = mod_tsx_layer_register_tsx(tsx); if (status != PJ_SUCCESS) { tsx_destroy(tsx); return status; } /* Put this transaction in rdata's mod_data. */ rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx; /* Unlock transaction and return. */ unlock_tsx(tsx, &lck); PJ_LOG(5,(tsx->obj_name, "Transaction created for %s", pjsip_rx_data_get_info(rdata))); *p_tsx = tsx; return PJ_SUCCESS;}/* * Bind transaction to a specific transport/listener. */PJ_DEF(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx, const pjsip_tpselector *sel){ struct tsx_lock_data lck; /* Must be UAC transaction */ PJ_ASSERT_RETURN(tsx && sel, PJ_EINVAL); /* Start locking the transaction. */ lock_tsx(tsx, &lck); /* Decrement reference counter of previous transport selector */ pjsip_tpselector_dec_ref(&tsx->tp_sel); /* Copy transport selector structure .*/ pj_memcpy(&tsx->tp_sel, sel, sizeof(*sel)); /* Increment reference counter */ pjsip_tpselector_add_ref(&tsx->tp_sel); /* Unlock transaction. */ unlock_tsx(tsx, &lck); return PJ_SUCCESS;}/* * Set transaction status code and reason. */static void tsx_set_status_code(pjsip_transaction *tsx, int code, const pj_str_t *reason){ tsx->status_code = code; if (reason) pj_strdup(tsx->pool, &tsx->status_text, reason); else tsx->status_text = *pjsip_get_status_text(code);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -