示例#1
0
/* Retransmit timer callback */
static void retransmit_timer_callback(pj_timer_heap_t *timer_heap, 
				      pj_timer_entry *timer)
{
    pj_stun_client_tsx *tsx = (pj_stun_client_tsx *) timer->user_data;
    pj_status_t status;

    PJ_UNUSED_ARG(timer_heap);
    pj_grp_lock_acquire(tsx->grp_lock);

    if (tsx->transmit_count >= PJ_STUN_MAX_TRANSMIT_COUNT) {
        /* tsx may be destroyed when calling the callback below */
        pj_grp_lock_t *grp_lock = tsx->grp_lock;

	/* Retransmission count exceeded. Transaction has failed */
	tsx->retransmit_timer.id = 0;
	PJ_LOG(4,(tsx->obj_name, "STUN timeout waiting for response"));
	pj_log_push_indent();
	if (!tsx->complete) {
	    tsx->complete = PJ_TRUE;
	    if (tsx->cb.on_complete) {
		tsx->cb.on_complete(tsx, PJNATH_ESTUNTIMEDOUT, NULL, NULL, 0);
	    }
	}
	pj_grp_lock_release(grp_lock);
	/* We might have been destroyed, don't try to access the object */
	pj_log_pop_indent();
	return;
    }

    tsx->retransmit_timer.id = 0;
    status = tsx_transmit_msg(tsx, PJ_TRUE);
    if (status != PJ_SUCCESS) {
	tsx->retransmit_timer.id = 0;
	if (!tsx->complete) {
	    tsx->complete = PJ_TRUE;
	    if (tsx->cb.on_complete) {
		tsx->cb.on_complete(tsx, status, NULL, NULL, 0);
	    }
	}
    }

    pj_grp_lock_release(tsx->grp_lock);
    /* We might have been destroyed, don't try to access the object */
}
示例#2
0
/*
 * Transmit message.
 */
static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx,
                                    pj_bool_t mod_count)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(tsx->retransmit_timer.id == TIMER_INACTIVE ||
		     !tsx->require_retransmit, PJ_EBUSY);

    if (tsx->require_retransmit && mod_count) {
	/* Calculate retransmit/timeout delay */
	if (tsx->transmit_count == 0) {
	    tsx->retransmit_time.sec = 0;
	    tsx->retransmit_time.msec = tsx->rto_msec;

	} else if (tsx->transmit_count < PJ_STUN_MAX_TRANSMIT_COUNT-1) {
	    unsigned msec;

	    msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
	    msec <<= 1;
	    tsx->retransmit_time.sec = msec / 1000;
	    tsx->retransmit_time.msec = msec % 1000;

	} else {
	    tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000;
	    tsx->retransmit_time.msec = PJ_STUN_TIMEOUT_VALUE % 1000;
	}

	/* Schedule timer first because when send_msg() failed we can
	 * cancel it (as opposed to when schedule_timer() failed we cannot
	 * cancel transmission).
	 */;
	status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap,
						   &tsx->retransmit_timer,
						   &tsx->retransmit_time,
						   TIMER_ACTIVE,
						   tsx->grp_lock);
	if (status != PJ_SUCCESS) {
	    tsx->retransmit_timer.id = TIMER_INACTIVE;
	    return status;
	}
    }


    if (mod_count)
        tsx->transmit_count++;

    PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
	      tsx->transmit_count));
    pj_log_push_indent();

    /* Send message */
    status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);

    if (status == PJNATH_ESTUNDESTROYED) {
	/* We've been destroyed, don't access the object. */
    } else if (status != PJ_SUCCESS) {
	if (mod_count) {
		pj_timer_heap_cancel_if_active( tsx->timer_heap,
	                               		&tsx->retransmit_timer,
	                               		TIMER_INACTIVE);
	}
	PJ_PERROR(4, (tsx->obj_name, status, "STUN error sending message"));
    }

    pj_log_pop_indent();
    return status;
}