⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_transaction.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -