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

📄 sip_transaction.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
	    msec_time = PJSIP_T2_TIMEOUT;
    } else {
	/* Retransmission of INVITE final response also caps-off at T2 */
	pj_assert(tsx->status_code >= 200);
	if (msec_time>PJSIP_T2_TIMEOUT)
	    msec_time = PJSIP_T2_TIMEOUT;
    }

    timeout.sec = msec_time / 1000;
    timeout.msec = msec_time % 1000;
    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, 
				&timeout);
}

/*
 * Retransmit last message sent.
 */
static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(tsx->last_tx!=NULL, PJ_EBUG);

    PJ_LOG(5,(tsx->obj_name, "Retransmiting %s, count=%d, restart?=%d", 
	      pjsip_tx_data_get_info(tsx->last_tx), 
	      tsx->retransmit_count, resched));

    ++tsx->retransmit_count;

    /* Restart timer T1 first before sending the message to ensure that
     * retransmission timer is not engaged when loop transport is used.
     */
    if (resched) {
	pj_assert(tsx->state != PJSIP_TSX_STATE_CONFIRMED);
	if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
	    tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
	} else {
	    tsx_resched_retransmission(tsx);
	}
    }

    status = tsx_send_msg( tsx, tsx->last_tx);
    if (status != PJ_SUCCESS) {
	return status;
    }

    return PJ_SUCCESS;
}


/*
 * Handler for events in state Null.
 */
static pj_status_t tsx_on_state_null( pjsip_transaction *tsx, 
                                      pjsip_event *event )
{
    pj_status_t status;

    pj_assert(tsx->state == PJSIP_TSX_STATE_NULL);

    if (tsx->role == PJSIP_ROLE_UAS) {

	/* Set state to Trying. */
	pj_assert(event->type == PJSIP_EVENT_RX_MSG &&
		  event->body.rx_msg.rdata->msg_info.msg->type == 
		    PJSIP_REQUEST_MSG);
	tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG,
		       event->body.rx_msg.rdata);

    } else {
	pjsip_tx_data *tdata;

	/* Must be transmit event. 
	 * You may got this assertion when using loop transport with delay 
	 * set to zero. That would cause on_rx_response() callback to be 
	 * called before tsx_send_msg() has completed.
	 */
	PJ_ASSERT_RETURN(event->type == PJSIP_EVENT_TX_MSG, PJ_EBUG);

	/* Get the txdata */
	tdata = event->body.tx_msg.tdata;

	/* Save the message for retransmission. */
	if (tsx->last_tx && tsx->last_tx != tdata) {
	    pjsip_tx_data_dec_ref(tsx->last_tx);
	    tsx->last_tx = NULL;
	}
	if (tsx->last_tx != tdata) {
	    tsx->last_tx = tdata;
	    pjsip_tx_data_add_ref(tdata);
	}

	/* Send the message. */
        status = tsx_send_msg( tsx, tdata);
	if (status != PJ_SUCCESS) {
	    return status;
	}

	/* Start Timer B (or called timer F for non-INVITE) for transaction 
	 * timeout. If user has configured the timeout value with 
	 * pjsip_tsx_set_uac_timeout(), use the timeout value there.
	 */
	if (tsx->msec_timeout > 0) {
	    pj_time_val timeout;

	    timeout.sec = tsx->msec_timeout / 1000;
	    timeout.msec = tsx->msec_timeout % 1000;

	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
					&timeout);

	} else {
	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
					&timeout_timer_val);
	}

	/* Start Timer A (or timer E) for retransmission only if unreliable 
	 * transport is being used.
	 */
	if (!tsx->is_reliable)  {
	    tsx->retransmit_count = 0;
	    if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
		tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
	    } else {
		pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer,
					   &t1_timer_val);
	    }
	}

	/* Move state. */
	tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, 
                       PJSIP_EVENT_TX_MSG, tdata);
    }

    return PJ_SUCCESS;
}


/*
 * State Calling is for UAC after it sends request but before any responses
 * is received.
 */
static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx, 
				         pjsip_event *event )
{
    pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING);
    pj_assert(tsx->role == PJSIP_ROLE_UAC);

    if (event->type == PJSIP_EVENT_TIMER && 
	event->body.timer.entry == &tsx->retransmit_timer) 
    {
        pj_status_t status;

	/* Retransmit the request. */
        status = tsx_retransmit( tsx, 1 );
	if (status != PJ_SUCCESS) {
	    return status;
	}

    } else if (event->type == PJSIP_EVENT_TIMER && 
	       event->body.timer.entry == &tsx->timeout_timer) 
    {

	/* 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;
	}
	tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);

	/* Set status code */
	tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);

	/* Inform TU. */
	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);

	/* Transaction is destroyed */
	//return PJSIP_ETSXDESTROYED;

    } else if (event->type == PJSIP_EVENT_RX_MSG) {
	pjsip_msg *msg;
	int code;

	/* Get message instance */
	msg = event->body.rx_msg.rdata->msg_info.msg;

	/* Better be a response message. */
	if (msg->type != PJSIP_RESPONSE_MSG)
	    return PJSIP_ENOTRESPONSEMSG;

	/* Cancel retransmission timer A. */
	if (tsx->retransmit_timer._timer_id != -1) {
	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
	    tsx->retransmit_timer._timer_id = -1;
	}
	tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);


	/* Cancel timer B (transaction timeout) but look at the timeout policy
	 * as set by pjsip_tsx_set_uac_timeout().
	 */
	code = msg->line.status.code;
	if ((code==100 && tsx->timeout_policy==PJSIP_TSX_IGNORE_100) ||
	    (code<200 && tsx->timeout_policy==PJSIP_TSX_IGNORE_1xx))
	{
	    /* Don't cancel the timeout timer */
	}
	else {
	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
	}

	/* Discard retransmission message if it is not INVITE.
	 * The INVITE tdata is needed in case we have to generate ACK for
	 * the final response.
	 */
	/* Keep last_tx for authorization. */
	//blp: always keep last_tx until transaction is destroyed
	//code = msg->line.status.code;
	//if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {
	//    pjsip_tx_data_dec_ref(tsx->last_tx);
	//    tsx->last_tx = NULL;
	//}

	/* Processing is similar to state Proceeding. */
	tsx_on_state_proceeding_uac( tsx, event);

    } else {
	pj_assert(!"Unexpected event");
        return PJ_EBUG;
    }

    return PJ_SUCCESS;
}


/*
 * State Trying is for UAS after it received request but before any responses
 * is sent.
 * Note: this is different than RFC3261, which can use Trying state for
 *	 non-INVITE client transaction (bug in RFC?).
 */
static pj_status_t tsx_on_state_trying( pjsip_transaction *tsx, 
                                        pjsip_event *event)
{
    pj_status_t status;

    pj_assert(tsx->state == PJSIP_TSX_STATE_TRYING);

    /* This state is only for UAS */
    pj_assert(tsx->role == PJSIP_ROLE_UAS);

    /* Better be transmission of response message.
     * If we've got request retransmission, this means that the TU hasn't
     * transmitted any responses within 500 ms, which is not allowed. If
     * this happens, just ignore the event (we couldn't retransmit last
     * response because we haven't sent any!).
     */
    if (event->type != PJSIP_EVENT_TX_MSG) {
	return PJ_SUCCESS;
    }

    /* The rest of the processing of the event is exactly the same as in
     * "Proceeding" state.
     */
    status = tsx_on_state_proceeding_uas( tsx, event);

    /* Inform the TU of the state transision if state is still State_Trying */
    if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) {

	tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 
                       PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata);

    }

    return status;
}


/*
 * Handler for events in Proceeding for UAS
 * This state happens after the TU sends provisional response.
 */
static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
                                                pjsip_event *event)
{
    pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || 
	      tsx->state == PJSIP_TSX_STATE_TRYING);

    /* This state is only for UAS. */
    pj_assert(tsx->role == PJSIP_ROLE_UAS);

    /* Receive request retransmission. */
    if (event->type == PJSIP_EVENT_RX_MSG) {

        pj_status_t status;

	/* Must have last response sent. */
	PJ_ASSERT_RETURN(tsx->last_tx != NULL, PJ_EBUG);

	/* Send last response */
	if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
	    tsx->transport_flag |= TSX_HAS_PENDING_SEND;
	} else {
	    status = tsx_send_msg(tsx, tsx->last_tx);
	    if (status != PJ_SUCCESS)
		return status;
	}
	
    } else if (event->type == PJSIP_EVENT_TX_MSG ) {
	pjsip_tx_data *tdata = event->body.tx_msg.tdata;
        pj_status_t status;

	/* The TU sends response message to the request. Save this message so
	 * that we can retransmit the last response in case we receive request
	 * retransmission.
	 */
	pjsip_msg *msg = tdata->msg;

	/* This can only be a response message. */
	PJ_ASSERT_RETURN(msg->type==PJSIP_RESPONSE_MSG, PJSIP_ENOTRESPONSEMSG);

	/* Update last status */
	tsx_set_status_code(tsx, msg->line.status.code, 
			    &msg->line.status.reason);

	/* Discard the saved last response (it will be updated later as
	 * necessary).
	 */
	if (tsx->last_tx && tsx->last_tx != tdata) {
	    pjsip_tx_data_dec_ref( tsx->last_tx );
	    tsx->last_tx = NULL;
	}

	/* Send the message. */
        status = tsx_send_msg(tsx, tdata);
	if (status != PJ_SUCCESS) {
	    return status;
	}

	// Update To tag header for RFC2543 transaction.
	// TODO:

	/* Update transaction state */
	if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {

	    if (tsx->last_tx != tdata) {
		tsx->last_tx = tdata;
		pjsip_tx_data_add_ref( tdata );
	    }

	    tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 
                           PJSIP_EVENT_TX_MSG, tdata );

	} else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

	    if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_200resp==0) {

		/* 2xx class message is not saved, because retransmission 
                 * is handled by TU.
		 */
		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
                               PJSIP_EVENT_TX_MSG, tdata );

		/* Transaction is destroyed. */
		//return PJSIP_ETSXDESTROYED;

	    } else {
		pj_time_val timeout;

		if (tsx->method.id == PJSIP_INVITE_METHOD) {
		    tsx->retransmit_count = 0;
		    if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
			tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
		    } else {
			pjsip_endpt_schedule_timer( tsx->endpt, 
						    &tsx->retransmit_timer,
						    &t1_timer_val);
		    }
		}

		/* Save last response sent for retransmission when request 
		 * retransmission is received.
		 */
		if (tsx->last_tx != tdata) {
		    tsx->last_tx = tdata;
		    pjsip_tx_data_add_ref(tdata);
		}

		/* Setup timeout timer: */
		
		if (tsx->method.id == PJSIP_INVITE_METHOD) {
		    
		    /* Start Timer H at 64*T1 for INVITE server transaction,
		     * regardless of transport.
		     */
		    timeout = timeout_timer_val;
		    
		} else if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
		    
		    /* For non-INVITE, start timer J at 64*T1 for unreliable
		     * transport.
		     */
		    timeout = timeout_timer_val;
		    
		} else {
		    
		    /* Transaction terminates immediately for non-INVITE when
		     * reliable transport is used.
		     */
		    timeout.sec = timeout.msec = 0;
		}

		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
                                            &timeout);

		/* Set state to "Completed" */
		tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
                               PJSIP_EVENT_TX_MSG, tdata );
	    }

	} else if (tsx->status_code >= 300) {

	    /* 3xx-6xx class message causes transaction to move to 
             * "Completed" state. 
             */
	    if (tsx->last_tx != tdata) {
		tsx->last_tx = tdata;
		pjsip_tx_data_add_ref( tdata );
	    }

	    /* For INVITE, start timer H for transaction termination 
	     * regardless whether transport is reliable or not.
	     * For non-INVITE, start timer J with the value of 64*T1 for
	     * non-reliable transports, and zero for reliable transports.
	     */
	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
		/* Start timer H for INVITE */
		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
					   &timeout_timer_val);
	    } else if (!tsx->is_reliable) {
		/* Start timer J on 64*T1 seconds for non-INVITE */
		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
					   &timeout_timer_val);
	    } else {
		/* Start timer J on zero seconds for non-INVITE */
		pj_time_val zero_time = { 0, 0 };
		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
					   &zero_time);
	    }

	    /* For INVITE, if unre

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -