/*
 * Send outgoing message and start STUN transaction.
 */
PJ_DEF(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
						pj_bool_t retransmit,
						void *pkt,
						unsigned pkt_len)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(tsx && pkt && pkt_len, PJ_EINVAL);
    PJ_ASSERT_RETURN(tsx->retransmit_timer.id == 0, PJ_EBUSY);

    /* Encode message */
    tsx->last_pkt = pkt;
    tsx->last_pkt_size = pkt_len;

    /* Update STUN retransmit flag */
    tsx->require_retransmit = retransmit;

    /* For TCP, schedule timeout timer after PJ_STUN_TIMEOUT_VALUE.
     * Since we don't have timeout timer, simulate this by using
     * retransmit timer.
     */
    if (!retransmit) {
	unsigned timeout;

	pj_assert(tsx->retransmit_timer.id == 0);
	tsx->transmit_count = PJ_STUN_MAX_TRANSMIT_COUNT;

	timeout = tsx->rto_msec * 16;
	tsx->retransmit_time.sec = timeout / 1000;
	tsx->retransmit_time.msec = timeout % 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(tsx->timer_heap, 
					&tsx->retransmit_timer,
					&tsx->retransmit_time);
	if (status != PJ_SUCCESS) {
	    tsx->retransmit_timer.id = 0;
	    return status;
	}
	tsx->retransmit_timer.id = TIMER_ACTIVE;
    }

    /* Send the message */
    status = tsx_transmit_msg(tsx, PJ_TRUE);
    if (status != PJ_SUCCESS) {
	if (tsx->retransmit_timer.id != 0) {
	    pj_timer_heap_cancel(tsx->timer_heap, 
				 &tsx->retransmit_timer);
	    tsx->retransmit_timer.id = 0;
	}
	return status;
    }

    return PJ_SUCCESS;
}
Exemple #2
0
/*
 * Request to retransmit the request.
 */
PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx,
                                                  pj_bool_t mod_count)
{
    if (tsx->destroy_timer.id != 0) {
	return PJ_SUCCESS;
    }

    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->retransmit_timer,
                                   TIMER_INACTIVE);

    return tsx_transmit_msg(tsx, mod_count);
}
Exemple #3
0
/*
 * Request to retransmit the request.
 */
PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx)
{
    if (tsx->destroy_timer.id != 0) {
	return PJ_SUCCESS;
    }

    if (tsx->retransmit_timer.id != 0) {
	pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
	tsx->retransmit_timer.id = 0;
    }

    return tsx_transmit_msg(tsx);
}
Exemple #4
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 */
}
/* 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);

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

    tsx->retransmit_timer.id = 0;
    status = tsx_transmit_msg(tsx, PJ_TRUE);
    if (status == PJNATH_ESTUNDESTROYED) {
	/* We've been destroyed, don't try to access the object */
    } else if (status != PJ_SUCCESS && status != PJ_EPENDING) {
	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);
	    }
	}
	/* We might have been destroyed, don't try to access the object */
    }
}