Esempio n. 1
0
static void end_session(nat_detect_session *sess,
			pj_status_t status,
			pj_stun_nat_type nat_type)
{
    pj_stun_nat_detect_result result;
    char errmsg[PJ_ERR_MSG_SIZE];
    pj_time_val delay;

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

    pj_bzero(&result, sizeof(result));
    errmsg[0] = '\0';
    result.status_text = errmsg;

    result.status = status;
    pj_strerror(status, errmsg, sizeof(errmsg));
    result.nat_type = nat_type;
    result.nat_type_name = nat_type_names[result.nat_type];

    if (sess->cb)
	(*sess->cb)(sess->user_data, &result);

    delay.sec = 0;
    delay.msec = 0;

    sess->timer.id = TIMER_DESTROY;
    pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
}
Esempio n. 2
0
/* Initiate shutdown sequence for this allocation and start destroy timer.
 * Once allocation is marked as shutting down, any packets will be
 * rejected/discarded
 */
static void alloc_shutdown(pj_turn_allocation *alloc)
{
    pj_time_val destroy_delay = DESTROY_DELAY;

    /* Work with existing schedule */
    if (alloc->relay.timer.id == TIMER_ID_TIMEOUT) {
	/* Cancel existing shutdown timer */
	pj_timer_heap_cancel(alloc->server->core.timer_heap,
			     &alloc->relay.timer);
	alloc->relay.timer.id = TIMER_ID_NONE;

    } else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
	/* We've been scheduled to be destroyed, ignore this
	 * shutdown request.
	 */
	return;
    }

    pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);

    /* Shutdown relay socket */
    destroy_relay(&alloc->relay);

    /* Don't unregister from hash table because we still need to
     * handle REFRESH retransmission.
     */

    /* Schedule destroy timer */
    alloc->relay.timer.id = TIMER_ID_DESTROY;
    pj_timer_heap_schedule(alloc->server->core.timer_heap,
			   &alloc->relay.timer, &destroy_delay);
}
Esempio n. 3
0
/* Reschedule timeout using current lifetime setting */
static pj_status_t resched_timeout(pj_turn_allocation *alloc)
{
    pj_time_val delay;
    pj_status_t status;

    pj_gettimeofday(&alloc->relay.expiry);
    alloc->relay.expiry.sec += alloc->relay.lifetime;

    pj_assert(alloc->relay.timer.id != TIMER_ID_DESTROY);
    if (alloc->relay.timer.id != 0) {
	pj_timer_heap_cancel(alloc->server->core.timer_heap,
			     &alloc->relay.timer);
	alloc->relay.timer.id = TIMER_ID_NONE;
    }

    delay.sec = alloc->relay.lifetime;
    delay.msec = 0;

    alloc->relay.timer.id = TIMER_ID_TIMEOUT;
    status = pj_timer_heap_schedule(alloc->server->core.timer_heap,
				    &alloc->relay.timer, &delay);
    if (status != PJ_SUCCESS) {
	alloc->relay.timer.id = TIMER_ID_NONE;
	return status;
    }

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_stun_client_tsx_schedule_destroy(
				    pj_stun_client_tsx *tsx,
				    const pj_time_val *delay)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(tsx && delay, PJ_EINVAL);
    PJ_ASSERT_RETURN(tsx->cb.on_destroy, PJ_EINVAL);

    /* Cancel previously registered timer */
    if (tsx->destroy_timer.id != 0) {
	pj_timer_heap_cancel(tsx->timer_heap, &tsx->destroy_timer);
	tsx->destroy_timer.id = 0;
    }

    /* Stop retransmission, just in case */
    if (tsx->retransmit_timer.id != 0) {
	pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
	tsx->retransmit_timer.id = 0;
    }

    status = pj_timer_heap_schedule(tsx->timer_heap,
				    &tsx->destroy_timer, delay);
    if (status != PJ_SUCCESS)
	return status;

    tsx->destroy_timer.id = TIMER_ACTIVE;
    tsx->cb.on_complete = NULL;

    return PJ_SUCCESS;
}
Esempio n. 5
0
    static bool schedule_timer( pj_timer_heap_t *timer, 
                                Pj_Event_Handler *handler,
				const Pj_Time_Val &delay, 
                                int id=-1)
    {
        handler->timer_.id = id;
        return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;
    }
/*
 * 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;
}
Esempio n. 7
0
/* Timer callback */
static void on_sess_timer(pj_timer_heap_t *th,
			     pj_timer_entry *te)
{
    nat_detect_session *sess;

    sess = (nat_detect_session*) te->user_data;

    if (te->id == TIMER_DESTROY) {
	pj_grp_lock_acquire(sess->grp_lock);
	pj_ioqueue_unregister(sess->key);
	sess->key = NULL;
	sess->sock = PJ_INVALID_SOCKET;
	te->id = 0;
	pj_grp_lock_release(sess->grp_lock);

	sess_destroy(sess);

    } else if (te->id == TIMER_TEST) {

	pj_bool_t next_timer;

	pj_grp_lock_acquire(sess->grp_lock);

	next_timer = PJ_FALSE;

	if (sess->timer_executed == 0) {
	    send_test(sess, ST_TEST_1, NULL, 0);
	    next_timer = PJ_TRUE;
	} else if (sess->timer_executed == 1) {
	    send_test(sess, ST_TEST_2, NULL, CHANGE_IP_PORT_FLAG);
	    next_timer = PJ_TRUE;
	} else if (sess->timer_executed == 2) {
	    send_test(sess, ST_TEST_3, NULL, CHANGE_PORT_FLAG);
	} else {
	    pj_assert(!"Shouldn't have timer at this state");
	}

	++sess->timer_executed;

	if (next_timer) {
	    pj_time_val delay = {0, TEST_INTERVAL};
	    pj_timer_heap_schedule(th, te, &delay);
	} else {
	    te->id = 0;
	}

	pj_grp_lock_release(sess->grp_lock);

    } else {
	pj_assert(!"Invalid timer ID");
    }
}
Esempio n. 8
0
static int timer_add_entry(pj_timer_entry* entry, pj_time_val* delay)
{
    pj_status_t rc;

    if (timer_initialized && timer != NULL)
    {
        rc = pj_timer_heap_schedule(timer, entry, delay);
        pj_sem_post(timer_sem);
        return rc;
    }
    else
        return PJ_EIGNORED;
}
Esempio n. 9
0
PJ_DEF(pj_status_t) pj_timer_heap_schedule_w_grp_lock(pj_timer_heap_t *ht,
                                                      pj_timer_entry *entry,
                                                      const pj_time_val *delay,
                                                      int id_val,
                                                      pj_grp_lock_t *grp_lock)
{
    pj_status_t status;
	    
    PJ_UNUSED_ARG(grp_lock);

    status = pj_timer_heap_schedule(ht, entry, delay);
    
    if (status == PJ_SUCCESS)
    	entry->id = id_val;
    
    return status;
}
Esempio n. 10
0
static int32_t zrtp_activateTimer(ZrtpContext* ctx, int32_t time)
{
    pj_time_val timeout;
    struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData;

    timeout.sec = time / 1000;
    timeout.msec = time % 1000;

    pj_timer_entry_init(&zrtp->timeoutEntry, 0, zrtp, &timer_callback);
#ifndef DYNAMIC_TIMER
    timer_add_entry(&zrtp->timeoutEntry, &timeout);
#else
    if(zrtp->timer_heap != NULL){
    	pj_timer_heap_schedule(zrtp->timer_heap, &zrtp->timeoutEntry, &timeout);
    }
#endif

    return 1;
}
Esempio n. 11
0
/*
 * Timer event.
 */
static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
{
    pj_tcp_session *sess = (pj_tcp_session*)e->user_data;
    enum timer_id_t eid;

    PJ_UNUSED_ARG(th);

    pj_lock_acquire(sess->lock);

    eid = (enum timer_id_t) e->id;
    e->id = TIMER_NONE;

    if (eid == TIMER_KEEP_ALIVE) {
        pj_time_val now;
        pj_bool_t resched = PJ_TRUE;

        pj_gettimeofday(&now);

        /* Reshcedule timer */
        if (resched) {
            pj_time_val delay;

            delay.sec = sess->ka_interval;
            delay.msec = 0;

            sess->timer.id = TIMER_KEEP_ALIVE;
            pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
        }

        pj_lock_release(sess->lock);

    } else if (eid == TIMER_DESTROY) {
        /* Time to destroy */
        pj_lock_release(sess->lock);
        do_destroy(sess);
    } else {
        pj_assert(!"Unknown timer event");
        pj_lock_release(sess->lock);
    }
}
Esempio n. 12
0
/* Schedule keep-alive timer */
static void start_ka_timer(pj_stun_sock *stun_sock)
{
    if (stun_sock->ka_timer.id != 0) {
	pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap, 
			     &stun_sock->ka_timer);
	stun_sock->ka_timer.id = 0;
    }

    pj_assert(stun_sock->ka_interval != 0);
    if (stun_sock->ka_interval > 0) {
	pj_time_val delay;

	delay.sec = stun_sock->ka_interval;
	delay.msec = 0;

	if (pj_timer_heap_schedule(stun_sock->stun_cfg.timer_heap, 
				   &stun_sock->ka_timer, 
				   &delay) == PJ_SUCCESS)
	{
	    stun_sock->ka_timer.id = PJ_TRUE;
	}
    }
}
Esempio n. 13
0
/*
 * Callback from TURN session when state has changed
 */
static void turn_on_state(pj_turn_session *sess, 
			  pj_turn_state_t old_state,
			  pj_turn_state_t new_state)
{
    pj_turn_sock *turn_sock = (pj_turn_sock*) 
			   pj_turn_session_get_user_data(sess);
    pj_status_t status;

    if (turn_sock == NULL) {
	/* We've been destroyed */
	return;
    }

    /* Notify app first */
    if (turn_sock->cb.on_state) {
	(*turn_sock->cb.on_state)(turn_sock, old_state, new_state);
    }

    /* Make sure user hasn't destroyed us in the callback */
    if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
	pj_turn_session_info info;
	pj_turn_session_get_info(turn_sock->sess, &info);
	new_state = info.state;
    }

    if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
	/*
	 * Once server has been resolved, initiate outgoing TCP
	 * connection to the server.
	 */
	pj_turn_session_info info;
	char addrtxt[PJ_INET6_ADDRSTRLEN+8];
	int sock_type;
	pj_sock_t sock;
	pj_activesock_cb asock_cb;
    pj_activesock_cfg asock_cfg;

	/* Close existing connection, if any. This happens when
	 * we're switching to alternate TURN server when either TCP
	 * connection or ALLOCATE request failed.
	 */
	if (turn_sock->active_sock) {
		PJ_LOG(4, (THIS_FILE, "turn_on_state() Close connection for new_state == PJ_TURN_STATE_RESOLVED."));
	    pj_activesock_close(turn_sock->active_sock);
	    turn_sock->active_sock = NULL;
	}

	/* Get server address from session info */
	pj_turn_session_get_info(sess, &info);

	if (turn_sock->conn_type == PJ_TURN_TP_UDP)
	    sock_type = pj_SOCK_DGRAM();
	else
	    sock_type = pj_SOCK_STREAM();

	/* Init socket */
	status = pj_sock_socket(turn_sock->af, sock_type, 0, &sock);
	if (status != PJ_SUCCESS) {
		PJ_LOG(1, (THIS_FILE, "turn_on_state() Failed to destroy turn_sock for sock creation. status=[%d]", status));
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	{
		int flag = turn_sock->setting.sock_recv_buf_size ? turn_sock->setting.sock_recv_buf_size : PJ_TCP_MAX_PKT_LEN;

		status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_RCVBUF(),
			&flag, sizeof(flag));
		if (status != PJ_SUCCESS) {
			PJ_LOG(2, (THIS_FILE, "turn_on_state() Failed to set SO_RCVBUF option. status=[%d]", status));
			return;
		}

		flag = turn_sock->setting.sock_send_buf_size ? turn_sock->setting.sock_send_buf_size : PJ_SOCKET_SND_BUFFER_SIZE;
		status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_SNDBUF(),
			&flag, sizeof(flag));
		if (status != PJ_SUCCESS) {
			PJ_LOG(2, (THIS_FILE, "turn_on_state() Failed to set SO_SNDBUF option. status=[%d]", status));
			return;
		}
	}

        /* Apply QoS, if specified */
	status = pj_sock_apply_qos2(sock, turn_sock->setting.qos_type,
				    &turn_sock->setting.qos_params, 
				    (turn_sock->setting.qos_ignore_error?2:1),
				    turn_sock->pool->obj_name, NULL);
	if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) {
		PJ_LOG(1, (THIS_FILE, "turn_on_state() Failed to destroy turn_sock for pj_sock_apply_qos2. status=[%d]", status));
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	/* Create active socket */
	pj_activesock_cfg_default(&asock_cfg);
	asock_cfg.concurrency = 1;
	asock_cfg.whole_data = PJ_TRUE;

    pj_bzero(&asock_cb, sizeof(asock_cb));
	asock_cb.on_data_read = &on_data_read;
	asock_cb.on_connect_complete = &on_connect_complete;
	status = pj_activesock_create(turn_sock->pool, sock,
				      sock_type, &asock_cfg,
				      turn_sock->cfg.ioqueue, &asock_cb, 
				      turn_sock,
				      &turn_sock->active_sock);
	if (status != PJ_SUCCESS) {
		PJ_LOG(1, (THIS_FILE, "turn_on_state() Failed to destroy turn_sock for pj_activesock_create. status=[%d]", status));
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	PJ_LOG(5,(turn_sock->pool->obj_name,
		  "Connecting to %s", 
		  pj_sockaddr_print(&info.server, addrtxt, 
				    sizeof(addrtxt), 3)));

	/* Initiate non-blocking connect */
#if PJ_HAS_TCP
	status=pj_activesock_start_connect(turn_sock->active_sock, 
					   turn_sock->pool,
					   &info.server, 
					   pj_sockaddr_get_len(&info.server));
	if (status == PJ_SUCCESS) {
	    on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
	} else if (status != PJ_EPENDING) {
		PJ_LOG(1, (THIS_FILE, "turn_on_state() Failed to destroy turn_sock for pj_activesock_start_connect. status=[%d]", status));
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}
#else
	on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
#endif

	/* Done for now. Subsequent work will be done in 
	 * on_connect_complete() callback.
	 */
    }

    if (new_state >= PJ_TURN_STATE_DESTROYING && turn_sock->sess) {
	pj_time_val delay = {0, 0};

	turn_sock->sess = NULL;
	pj_turn_session_set_user_data(sess, NULL);

	if (turn_sock->timer.id) {
	    pj_timer_heap_cancel(turn_sock->cfg.timer_heap, &turn_sock->timer);
	    turn_sock->timer.id = 0;
	}

	turn_sock->timer.id = TIMER_DESTROY;
	pj_timer_heap_schedule(turn_sock->cfg.timer_heap, &turn_sock->timer, 
			       &delay);
    }
}
Esempio n. 14
0
    //
    // Schedule a timer.
    //
    bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay,
                   int id)
    {
        ent->entry_.id = id;
	return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0;
    }
static int test_timer_heap(void)
{
    int i, j;
    pj_timer_entry *entry;
    pj_pool_t *pool;
    pj_timer_heap_t *timer;
    pj_time_val delay;
    pj_status_t rc;    int err=0;
    unsigned size, count;

    size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);
    pool = pj_pool_create( mem, NULL, size, 4000, NULL);
    if (!pool) {
	PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",
		  size));
	return -10;
    }

    entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));
    if (!entry)
	return -20;

    for (i=0; i<MAX_COUNT; ++i) {
	entry[i].cb = &timer_callback;
    }
    rc = pj_timer_heap_create(pool, MAX_COUNT, &timer);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: unable to create timer heap", rc);
	return -30;
    }

    count = MIN_COUNT;
    for (i=0; i<LOOP; ++i) {
	int early = 0;
	int done=0;
	int cancelled=0;
	int rc;
	pj_timestamp t1, t2, t_sched, t_cancel, t_poll;
	pj_time_val now, expire;

	pj_gettimeofday(&now);
	pj_srand(now.sec);
	t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;

	// Register timers
	for (j=0; j<(int)count; ++j) {
	    delay.sec = pj_rand() % DELAY;
	    delay.msec = pj_rand() % 1000;

	    // Schedule timer
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_schedule(timer, &entry[j], &delay);
	    if (rc != 0)
		return -40;
	    pj_get_timestamp(&t2);

	    t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);

	    // Poll timers.
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_poll(timer, NULL);
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
		early += rc;
	    }
	}

	// Set the time where all timers should finish
	pj_gettimeofday(&expire);
	delay.sec = DELAY; 
	delay.msec = 0;
	PJ_TIME_VAL_ADD(expire, delay);

	// Wait unfil all timers finish, cancel some of them.
	do {
	    int index = pj_rand() % count;
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_cancel(timer, &entry[index]);
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		cancelled += rc;
		t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);
	    }

	    pj_gettimeofday(&now);

	    pj_get_timestamp(&t1);
#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
	    /* On Symbian, we must use OS poll (Active Scheduler poll) since 
	     * timer is implemented using Active Object.
	     */
	    rc = 0;
	    while (pj_symbianos_poll(-1, 0))
		++rc;
#else
	    rc = pj_timer_heap_poll(timer, NULL);
#endif
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		done += rc;
		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
	    }

	} while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);

	if (pj_timer_heap_count(timer)) {
	    PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", 
		       pj_timer_heap_count(timer)));
	    ++err;
	}
	t_sched.u32.lo /= count; 
	t_cancel.u32.lo /= count;
	t_poll.u32.lo /= count;
	PJ_LOG(4, (THIS_FILE, 
	        "...ok (count:%d, early:%d, cancelled:%d, "
		"sched:%d, cancel:%d poll:%d)", 
		count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,
		t_poll.u32.lo));

	count = count * 2;
	if (count > MAX_COUNT)
	    break;
    }

    pj_pool_release(pool);
    return err;
}
/*
 * 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 == 0 ||
		     !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(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;
    }


    if (mod_count)
    tsx->transmit_count++;

    PJ_LOG(4,(tsx->obj_name, "[%s] STUN sending message (transmit count=%d)",
	      tsx->obj_name, tsx->transmit_count));

    /* 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 && status != PJ_EPENDING) {
	if (tsx->retransmit_timer.id != 0 && mod_count) {
	    pj_timer_heap_cancel(tsx->timer_heap, 
				 &tsx->retransmit_timer);
	    tsx->retransmit_timer.id = 0;
	}
	stun_perror(tsx, "STUN error sending message", status);
	return status;
    }

    return status;
}
Esempio n. 17
0
/*
 * Notify application and shutdown the TCP session.
 */
static void sess_shutdown(pj_tcp_session *sess,
                          pj_status_t status)
{
    pj_bool_t can_destroy = PJ_TRUE;

    PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d",
              state_names[sess->state], status));

    if (sess->last_status == PJ_SUCCESS && status != PJ_SUCCESS)
        sess->last_status = status;

    switch (sess->state) {
    case PJ_TCP_STATE_NULL:
        break;
    case PJ_TCP_STATE_RESOLVING:
        if (sess->dns_async != NULL) {
            pj_dns_srv_cancel_query(sess->dns_async, PJ_FALSE);
            sess->dns_async = NULL;
        }
        break;
    case PJ_TCP_STATE_RESOLVED:
        break;
    case PJ_TCP_STATE_CONNECTING:
        /* We need to wait until connection complete */
        sess->pending_destroy = PJ_TRUE;
        can_destroy = PJ_FALSE;
        break;
    case PJ_TCP_STATE_READY:
        /* Send REFRESH with LIFETIME=0 */
#if 0
        can_destroy = PJ_FALSE;
        send_refresh(sess, 0);
#endif
        break;
    case PJ_TCP_STATE_DISCONNECTING:
        can_destroy = PJ_FALSE;
        /* This may recursively call this function again with
         * state==PJ_TCP_STATE_DISCONNECTING.
         */
#if 0
        send_refresh(sess, 0);
#endif
        break;
    case PJ_TCP_STATE_DISCONNECTED:
    case PJ_TCP_STATE_DESTROYING:
        break;
    }

    if (can_destroy) {
        /* Schedule destroy */
        pj_time_val delay = {0, 0};

        pj_tcp_session_set_state(sess, PJ_TCP_STATE_DESTROYING);

        if (sess->timer.id != TIMER_NONE) {
            pj_timer_heap_cancel(sess->timer_heap, &sess->timer);
            sess->timer.id = TIMER_NONE;
        }

        sess->timer.id = TIMER_DESTROY;
        pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
    }
}