Example #1
0
static pj_status_t transport_destroy  (pjmedia_transport *tp)
{
    transport_srtp *srtp = (transport_srtp *) tp;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    /* Close keying */
    for (i=0; i < srtp->keying_cnt; i++)
	pjmedia_transport_close(srtp->keying[i]);

    /* Close member if configured */
    if (srtp->setting.close_member_tp && srtp->member_tp) {
	pjmedia_transport_close(srtp->member_tp);
    }

    status = pjmedia_transport_srtp_stop(tp);

    /* In case mutex is being acquired by other thread */
    pj_lock_acquire(srtp->mutex);
    pj_lock_release(srtp->mutex);

    pj_lock_destroy(srtp->mutex);
    pj_pool_release(srtp->pool);

    return status;
}
Example #2
0
static pj_status_t transport_send_rtp( pjmedia_transport *tp,
				       const void *pkt,
				       pj_size_t size)
{
    pj_status_t status;
    transport_srtp *srtp = (transport_srtp*) tp;
    int len = size;
    err_status_t err;

    if (srtp->bypass_srtp)
	return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size);

    if (size > sizeof(srtp->rtp_tx_buffer))
	return PJ_ETOOBIG;

    pj_memcpy(srtp->rtp_tx_buffer, pkt, size);

    pj_lock_acquire(srtp->mutex);
    if (!srtp->session_inited) {
	pj_lock_release(srtp->mutex);
	return PJ_EINVALIDOP;
    }
    err = srtp_protect(srtp->srtp_tx_ctx, srtp->rtp_tx_buffer, &len);
    pj_lock_release(srtp->mutex);

    if (err == err_status_ok) {
	status = pjmedia_transport_send_rtp(srtp->member_tp, srtp->rtp_tx_buffer, len);
    } else {
	status = PJMEDIA_ERRNO_FROM_LIBSRTP(err);
    }
    
    return status;
}
Example #3
0
/*
 * ioqueue notification on RX packets from the relay socket.
 */
static void on_rx_from_peer(pj_ioqueue_key_t *key,
                            pj_ioqueue_op_key_t *op_key,
                            pj_ssize_t bytes_read)
{
    pj_turn_relay_res *rel;
    pj_status_t status;

    rel = (pj_turn_relay_res*) pj_ioqueue_get_user_data(key);

    /* Lock the allocation */
    pj_lock_acquire(rel->allocation->lock);

    do {
	if (bytes_read > 0) {
	    handle_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
			    bytes_read, &rel->tp.src_addr);
	}

	/* Read next packet */
	bytes_read = sizeof(rel->tp.rx_pkt);
	rel->tp.src_addr_len = sizeof(rel->tp.src_addr);
	status = pj_ioqueue_recvfrom(key, op_key,
				     rel->tp.rx_pkt, &bytes_read, 0,
				     &rel->tp.src_addr,
				     &rel->tp.src_addr_len);

	if (status != PJ_EPENDING && status != PJ_SUCCESS)
	    bytes_read = -status;

    } while (status != PJ_EPENDING && status != PJ_ECANCELLED);

    /* Release allocation lock */
    pj_lock_release(rel->allocation->lock);
}
Example #4
0
/* 
 * This callback is called by transport manager to send SIP message 
 */
static pj_status_t tcp_send_msg(pjsip_transport *transport, 
				pjsip_tx_data *tdata,
				const pj_sockaddr_t *rem_addr,
				int addr_len,
				void *token,
				pjsip_transport_callback callback)
{
    struct tcp_transport *tcp = (struct tcp_transport*)transport;
    pj_ssize_t size;
    pj_bool_t delayed = PJ_FALSE;
    pj_status_t status = PJ_SUCCESS;

    /* Sanity check */
    PJ_ASSERT_RETURN(transport && tdata, PJ_EINVAL);

    /* Check that there's no pending operation associated with the tdata */
    PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
    
    /* Check the address is supported */
    PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);



    /* Init op key. */
    tdata->op_key.tdata = tdata;
    tdata->op_key.token = token;
    tdata->op_key.callback = callback;

    /* If asynchronous connect() has not completed yet, just put the
     * transmit data in the pending transmission list since we can not
     * use the socket yet.
     */
    if (tcp->has_pending_connect) {

	/*
	 * Looks like connect() is still in progress. Check again (this time
	 * with holding the lock) to be sure.
	 */
	pj_lock_acquire(tcp->base.lock);

	if (tcp->has_pending_connect) {
	    struct delayed_tdata *delayed_tdata;

	    /*
	     * connect() is still in progress. Put the transmit data to
	     * the delayed list.
	     */
	    delayed_tdata = PJ_POOL_ALLOC_T(tdata->pool, 
					    struct delayed_tdata);
	    delayed_tdata->tdata_op_key = &tdata->op_key;

	    pj_list_push_back(&tcp->delayed_list, delayed_tdata);
	    status = PJ_EPENDING;

	    /* Prevent pj_ioqueue_send() to be called below */
	    delayed = PJ_TRUE;
	}

	pj_lock_release(tcp->base.lock);
    } 
Example #5
0
/*
 * Stop SRTP session.
 */
PJ_DEF(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp)
{
    transport_srtp *p_srtp = (transport_srtp*) srtp;
    err_status_t err;

    PJ_ASSERT_RETURN(srtp, PJ_EINVAL);

    pj_lock_acquire(p_srtp->mutex);

    if (!p_srtp->session_inited) {
	pj_lock_release(p_srtp->mutex);
	return PJ_SUCCESS;
    }

    err = srtp_dealloc(p_srtp->srtp_rx_ctx);
    if (err != err_status_ok) {
	PJ_LOG(4, (p_srtp->pool->obj_name, 
		   "Failed to dealloc RX SRTP context: %s",
		   get_libsrtp_errstr(err)));
    }
    err = srtp_dealloc(p_srtp->srtp_tx_ctx);
    if (err != err_status_ok) {
	PJ_LOG(4, (p_srtp->pool->obj_name, 
		   "Failed to dealloc TX SRTP context: %s",
		   get_libsrtp_errstr(err)));
    }

    p_srtp->session_inited = PJ_FALSE;
    pj_bzero(&p_srtp->rx_policy, sizeof(p_srtp->rx_policy));
    pj_bzero(&p_srtp->tx_policy, sizeof(p_srtp->tx_policy));

    pj_lock_release(p_srtp->mutex);

    return PJ_SUCCESS;
}
Example #6
0
static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx,
					const void *stun_pkt,
					pj_size_t pkt_size)
{
    pj_stun_tx_data *tdata;
    pj_stun_session *sess;
    pj_status_t status;

    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
    sess = tdata->sess;

    /* Lock the session and prevent user from destroying us in the callback */
    pj_atomic_inc(sess->busy);
    pj_lock_acquire(sess->lock);
    
    status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt, 
				  pkt_size, tdata->dst_addr, 
				  tdata->addr_len);
    pj_lock_release(sess->lock);

    if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
	pj_stun_session_destroy(sess);
	return PJNATH_ESTUNDESTROYED;
    } else {
	return status;
    }
}
PJ_DEF(pj_status_t) pj_ioqueue_lock_key(pj_ioqueue_key_t *key)
{
    if (key->grp_lock)
	return pj_grp_lock_acquire(key->grp_lock);
    else
	return pj_lock_acquire(key->lock);
}
Example #8
0
/**
 * Relay data to the specified peer through the session.
 */
PJ_DEF(pj_status_t) pj_tcp_session_sendto( pj_tcp_session *sess,
        const pj_uint8_t *pkt,
        unsigned pkt_len,
        const pj_sockaddr_t *addr,
        unsigned addr_len)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len,
                     PJ_EINVAL);

    /* Return error if we're not ready */
#if 1
    if (sess->state != PJ_TCP_STATE_READY) {
        return PJ_EIGNORED;
    }
#endif

    /* Lock session now */
    pj_lock_acquire(sess->lock);

    status = sess->cb.on_send_pkt(sess, pkt, pkt_len,
                                  addr, addr_len);

    pj_lock_release(sess->lock);
    return status;
}
Example #9
0
PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);

    pj_lock_acquire(regc->lock);
    if (regc->has_tsx || pj_atomic_get(regc->busy_ctr) != 0) {
	regc->_delete_flag = 1;
	regc->cb = NULL;
	pj_lock_release(regc->lock);
    } else {
	pjsip_tpselector_dec_ref(&regc->tp_sel);
	if (regc->last_transport) {
	    pjsip_transport_dec_ref(regc->last_transport);
	    regc->last_transport = NULL;
	}
	if (regc->timer.id != 0) {
	    pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	    regc->timer.id = 0;
	}
	pj_atomic_destroy(regc->busy_ctr);
	pj_lock_release(regc->lock);
	pj_lock_destroy(regc->lock);
	regc->lock = NULL;
	pjsip_endpt_release_pool(regc->endpt, regc->pool);
    }

    return PJ_SUCCESS;
}
Example #10
0
/*
 * pj_ioqueue_destroy()
 *
 * Destroy ioqueue.
 */
PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
{
    pj_ioqueue_key_t *key;

    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

    pj_lock_acquire(ioqueue->lock);

#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Destroy reference counters */
    key = ioqueue->active_list.next;
    while (key != &ioqueue->active_list) {
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }

    key = ioqueue->closing_list.next;
    while (key != &ioqueue->closing_list) {
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }

    key = ioqueue->free_list.next;
    while (key != &ioqueue->free_list) {
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }

    pj_mutex_destroy(ioqueue->ref_cnt_mutex);
#endif

    return ioqueue_destroy(ioqueue);
}
Example #11
0
PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
					 pjsip_regc_info *info )
{
    PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);

    pj_lock_acquire(regc->lock);

    info->server_uri = regc->str_srv_url;
    info->client_uri = regc->from_uri;
    info->is_busy = (pj_atomic_get(regc->busy_ctr) || regc->has_tsx);
    info->auto_reg = regc->auto_reg;
    info->interval = regc->expires;
    info->transport = regc->last_transport;
    
    if (regc->has_tsx)
	info->next_reg = 0;
    else if (regc->auto_reg == 0)
	info->next_reg = 0;
    else if (regc->expires < 0)
	info->next_reg = regc->expires;
    else {
	pj_time_val now, next_reg;

	next_reg = regc->next_reg;
	pj_gettimeofday(&now);
	PJ_TIME_VAL_SUB(next_reg, now);
	info->next_reg = next_reg.sec;
    }

    pj_lock_release(regc->lock);

    return PJ_SUCCESS;
}
Example #12
0
pjsip_regc_set_delay_before_refresh( pjsip_regc *regc,
				     pj_uint32_t delay )
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);

    if (delay > regc->expires)
        return PJ_ETOOBIG;

    pj_lock_acquire(regc->lock);

    if (regc->delay_before_refresh != delay)
    {
        regc->delay_before_refresh = delay;

        if (regc->timer.id != 0) {
            /* Cancel registration timer */
            pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
            regc->timer.id = 0;

            /* Schedule next registration */
            schedule_registration(regc, regc->expires);
        }
    }

    pj_lock_release(regc->lock);

    return PJ_SUCCESS;
}
Example #13
0
/*
 * Change the downstream port.
 */
PJ_DEF(pj_status_t) pjmedia_master_port_set_dport(pjmedia_master_port *m,
						  pjmedia_port *port)
{
    PJ_ASSERT_RETURN(m && port, PJ_EINVAL);

    /* Only supports audio for now */
    PJ_ASSERT_RETURN(port->info.fmt.type==PJMEDIA_TYPE_AUDIO, PJ_ENOTSUP);

    /* If we have upstream port, make sure they have matching samples per
     * frame.
     */
    if (m->u_port) {
	PJ_ASSERT_RETURN(
	    PJMEDIA_PIA_PTIME(&port->info) ==
		    PJMEDIA_PIA_PTIME(&m->u_port->info),
	    PJMEDIA_ENCSAMPLESPFRAME
	);
    }

    pj_lock_acquire(m->lock);

    m->d_port = port;

    pj_lock_release(m->lock);

    return PJ_SUCCESS;
}
Example #14
0
/* Flush all delayed transmision once the socket is connected. */
static void tcp_flush_pending_tx(struct tcp_transport *tcp)
{
    pj_lock_acquire(tcp->base.lock);
    while (!pj_list_empty(&tcp->delayed_list)) {
	struct delayed_tdata *pending_tx;
	pjsip_tx_data *tdata;
	pj_ioqueue_op_key_t *op_key;
	pj_ssize_t size;
	pj_status_t status;

	pending_tx = tcp->delayed_list.next;
	pj_list_erase(pending_tx);

	tdata = pending_tx->tdata_op_key->tdata;
	op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;

	/* send! */
	size = tdata->buf.cur - tdata->buf.start;
	status = pj_activesock_send(tcp->asock, op_key, tdata->buf.start, 
				    &size, 0);
	if (status != PJ_EPENDING) {
	    on_data_sent(tcp->asock, op_key, size);
	}

    }
    pj_lock_release(tcp->base.lock);
}
Example #15
0
/*
 * Destroy.
 */
static void destroy(pj_turn_sock *turn_sock)
{
    if (turn_sock->lock) {
	pj_lock_acquire(turn_sock->lock);
    }

    if (turn_sock->sess) {
	pj_turn_session_set_user_data(turn_sock->sess, NULL);
	pj_turn_session_shutdown(turn_sock->sess);
	turn_sock->sess = NULL;
    }

    if (turn_sock->active_sock) {
	pj_activesock_close(turn_sock->active_sock);
	turn_sock->active_sock = NULL;
    }

    if (turn_sock->lock) {
	pj_lock_release(turn_sock->lock);
	pj_lock_destroy(turn_sock->lock);
	turn_sock->lock = NULL;
    }

    if (turn_sock->pool) {
	pj_pool_t *pool = turn_sock->pool;
	turn_sock->pool = NULL;
	pj_pool_release(pool);
    }
}
Example #16
0
/*
 * pj_ioqueue_unregister()
 *
 * Unregister handle from ioqueue.
 */
PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
{
    pj_ioqueue_t *ioqueue;

    PJ_ASSERT_RETURN(key, PJ_EINVAL);

    ioqueue = key->ioqueue;

    /* Lock the key to make sure no callback is simultaneously modifying
     * the key. We need to lock the key before ioqueue here to prevent
     * deadlock.
     */
    pj_mutex_lock(key->mutex);

    /* Also lock ioqueue */
    pj_lock_acquire(ioqueue->lock);

    pj_assert(ioqueue->count > 0);
    --ioqueue->count;
#if !PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Ticket #520, key will be erased more than once */
    pj_list_erase(key);
#endif
    PJ_FD_CLR(key->fd, &ioqueue->rfdset);
    PJ_FD_CLR(key->fd, &ioqueue->wfdset);
#if PJ_HAS_TCP
    PJ_FD_CLR(key->fd, &ioqueue->xfdset);
#endif

    /* Close socket. */
    pj_sock_close(key->fd);

    /* Clear callback */
    key->cb.on_accept_complete = NULL;
    key->cb.on_connect_complete = NULL;
    key->cb.on_read_complete = NULL;
    key->cb.on_write_complete = NULL;

    /* Must release ioqueue lock first before decrementing counter, to
     * prevent deadlock.
     */
    pj_lock_release(ioqueue->lock);

#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Mark key is closing. */
    key->closing = 1;

    /* Decrement counter. */
    decrement_counter(key);

    /* Done. */
    pj_mutex_unlock(key->mutex);
#else
    pj_mutex_destroy(key->mutex);
#endif

    return PJ_SUCCESS;
}
Example #17
0
/*
 * Clock thread
 */
static int clock_thread(void *arg)
{
    pj_timestamp now;
    pjmedia_clock *clock = (pjmedia_clock*) arg;

    /* Set thread priority to maximum unless not wanted. */
    if ((clock->options & PJMEDIA_CLOCK_NO_HIGHEST_PRIO) == 0) {
	int max = pj_thread_get_prio_max(pj_thread_this());
	if (max > 0)
	    pj_thread_set_prio(pj_thread_this(), max);
    }

    //printf("%s:------------11--------------\n", THIS_FILE);
    /* Get the first tick */
    pj_get_timestamp(&clock->next_tick);
    clock->next_tick.u64 += clock->interval.u64;


    while (!clock->quitting) {

	pj_get_timestamp(&now);

	/* Wait for the next tick to happen */
	if (now.u64 < clock->next_tick.u64) {
	    unsigned msec;
	    msec = pj_elapsed_msec(&now, &clock->next_tick);
	    pj_thread_sleep(msec);
	}
    //printf("%s:------------12--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting));
	/* Skip if not running */
	if (!clock->running) {
	    /* Calculate next tick */
	    clock_calc_next_tick(clock, &now);
	    continue;
	}

	pj_lock_acquire(clock->lock);
    //printf("%s:------------13--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting));
	/* Call callback, if any */
	if (clock->cb)
	    (*clock->cb)(&clock->timestamp, clock->user_data);

	/* Best effort way to detect if we've been destroyed in the callback */
	if (clock->quitting)
	    break;

	/* Increment timestamp */
	clock->timestamp.u64 += clock->timestamp_inc;
    //printf("%s:------------14--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting));
	/* Calculate next tick */
	clock_calc_next_tick(clock, &now);
    //printf("%s:------------15--------------\n", THIS_FILE);
	pj_lock_release(clock->lock);
    }

    return 0;
}
Example #18
0
PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess,
						   void *user_data)
{
    PJ_ASSERT_RETURN(sess, PJ_EINVAL);
    pj_lock_acquire(sess->lock);
    sess->user_data = user_data;
    pj_lock_release(sess->lock);
    return PJ_SUCCESS;
}
Example #19
0
/*
 * This callback is called by transport when incoming rtp is received
 */
static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
{
    transport_srtp *srtp = (transport_srtp *) user_data;
    int len = size;
    err_status_t err;

    if (srtp->bypass_srtp) {
	srtp->rtp_cb(srtp->user_data, pkt, size);
	return;
    }

    if (size < 0 || !srtp->session_inited) {
	return;
    }

    /* Make sure buffer is 32bit aligned */
    PJ_ASSERT_ON_FAIL( (((long)pkt) & 0x03)==0, return );

    if (srtp->probation_cnt > 0)
	--srtp->probation_cnt;

    pj_lock_acquire(srtp->mutex);

    err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);

    if (srtp->probation_cnt > 0 && 
	(err == err_status_replay_old || err == err_status_replay_fail)) 
    {
	/* Handle such condition that stream is updated (RTP seq is reinited
	* & SRTP is restarted), but some old packets are still coming 
	* so SRTP is learning wrong RTP seq. While the newly inited RTP seq
	* comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect() 
	* will returning err_status_replay_*. Restarting SRTP can resolve 
	* this.
	*/
	if (pjmedia_transport_srtp_start((pjmedia_transport*)srtp, 
					 &srtp->tx_policy, &srtp->rx_policy) 
					 != PJ_SUCCESS)
	{
	    PJ_LOG(5,(srtp->pool->obj_name, "Failed to restart SRTP, err=%s", 
		      get_libsrtp_errstr(err)));
	} else {
	    err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
	}
    }

    if (err == err_status_ok) {
	srtp->rtp_cb(srtp->user_data, pkt, len);
    } else {
	PJ_LOG(5,(srtp->pool->obj_name, 
		  "Failed to unprotect SRTP, pkt size=%d, err=%s", 
		  size, get_libsrtp_errstr(err)));
    }

    pj_lock_release(srtp->mutex);
}
/*
 * Poll for the completion of non-blocking connect().
 * If there's a completion, the function return the key of the completed
 * socket, and 'result' argument contains the connect() result. If connect()
 * succeeded, 'result' will have value zero, otherwise will have the error
 * code.
 */
static int check_connecting( pj_ioqueue_t *ioqueue )
{
    if (ioqueue->connecting_count) {
	int i, count;
	struct 
	{
	    pj_ioqueue_key_t *key;
	    pj_status_t	      status;
	} events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL-1];

	pj_lock_acquire(ioqueue->lock);
	for (count=0; count<PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL-1; ++count) {
	    DWORD result;

	    result = WaitForMultipleObjects(ioqueue->connecting_count,
					    ioqueue->connecting_handles,
					    FALSE, 0);
	    if (result >= WAIT_OBJECT_0 && 
		result < WAIT_OBJECT_0+ioqueue->connecting_count) 
	    {
		WSANETWORKEVENTS net_events;

		/* Got completed connect(). */
		unsigned pos = result - WAIT_OBJECT_0;
		events[count].key = ioqueue->connecting_keys[pos];

		/* See whether connect has succeeded. */
		WSAEnumNetworkEvents((pj_sock_t)events[count].key->hnd, 
				     ioqueue->connecting_handles[pos], 
				     &net_events);
		events[count].status = 
		    PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);

		/* Erase socket from pending connect. */
		erase_connecting_socket(ioqueue, pos);
	    } else {
		/* No more events */
		break;
	    }
	}
	pj_lock_release(ioqueue->lock);

	/* Call callbacks. */
	for (i=0; i<count; ++i) {
	    if (events[i].key->cb.on_connect_complete) {
		events[i].key->cb.on_connect_complete(events[i].key, 
						      events[i].status);
	    }
	}

	return count;
    }

    return 0;
    
}
Example #21
0
/*
 * pj_ioqueue_unregister()
 *
 * Unregister handle from ioqueue.
 */
PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
{
    pj_ioqueue_t *ioqueue;
    struct epoll_event ev;
    int status;
    
    PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);

    ioqueue = key->ioqueue;

    /* Lock the key to make sure no callback is simultaneously modifying
     * the key. We need to lock the key before ioqueue here to prevent
     * deadlock.
     */
    pj_mutex_lock(key->mutex);

    /* Also lock ioqueue */
    pj_lock_acquire(ioqueue->lock);

    pj_assert(ioqueue->count > 0);
    --ioqueue->count;
#if !PJ_IOQUEUE_HAS_SAFE_UNREG
    pj_list_erase(key);
#endif

    ev.events = 0;
    ev.epoll_data = (epoll_data_type)key;
    status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
    if (status != 0) {
	pj_status_t rc = pj_get_os_error();
	pj_lock_release(ioqueue->lock);
	return rc;
    }

    /* Destroy the key. */
    pj_sock_close(key->fd);

    pj_lock_release(ioqueue->lock);


#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Mark key is closing. */
    key->closing = 1;

    /* Decrement counter. */
    decrement_counter(key);

    /* Done. */
    pj_mutex_unlock(key->mutex);
#else
    pj_mutex_destroy(key->mutex);
#endif

    return PJ_SUCCESS;
}
Example #22
0
PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
					pjsip_tx_data **p_tdata)
{
    pjsip_msg *msg;
    pjsip_contact_hdr *hdr;
    pj_status_t status;
    pjsip_tx_data *tdata;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    pj_lock_acquire(regc->lock);

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS) {
	pj_lock_release(regc->lock);
	return status;
    }

    msg = tdata->msg;

    /* Add Contact headers. */
    hdr = regc->contact_hdr_list.next;
    while (hdr != &regc->contact_hdr_list) {
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_shallow_clone(tdata->pool, hdr));
	hdr = hdr->next;
    }

    /* Also add bindings which are to be removed */
    while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
	hdr = regc->removed_contact_hdr_list.next;
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_clone(tdata->pool, hdr));
	pj_list_erase(hdr);
    }
    

    if (regc->expires_hdr)
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_shallow_clone(tdata->pool,
						       regc->expires_hdr));

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    regc->auto_reg = autoreg;

    pj_lock_release(regc->lock);

    /* Done */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}
Example #23
0
PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,
					        pj_uint32_t expires )
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);

    pj_lock_acquire(regc->lock);
    set_expires( regc, expires );
    pj_lock_release(regc->lock);

    return PJ_SUCCESS;
}
Example #24
0
/*
 * Set software name
 */
PJ_DEF(pj_status_t) pj_tcp_session_set_software_name( pj_tcp_session *sess,
        const pj_str_t *sw)
{
    pj_status_t status;

    pj_lock_acquire(sess->lock);
    status = pj_stun_session_set_software_name(sess->stun, sw);
    pj_lock_release(sess->lock);

    return status;
}
Example #25
0
/*
 * Public API to destroy TCP client session.
 */
PJ_DEF(pj_status_t) pj_tcp_session_shutdown(pj_tcp_session *sess)
{
    PJ_ASSERT_RETURN(sess, PJ_EINVAL);

    pj_lock_acquire(sess->lock);

    sess_shutdown(sess, PJ_SUCCESS);

    pj_lock_release(sess->lock);

    return PJ_SUCCESS;
}
/*
 * pj_ioqueue_destroy()
 */
PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
{
#if PJ_HAS_TCP
    unsigned i;
#endif
    pj_ioqueue_key_t *key;

    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

    pj_lock_acquire(ioqueue->lock);

#if PJ_HAS_TCP
    /* Destroy events in the pool */
    for (i=0; i<ioqueue->event_count; ++i) {
	CloseHandle(ioqueue->event_pool[i]);
    }
    ioqueue->event_count = 0;
#endif

    if (CloseHandle(ioqueue->iocp) != TRUE)
	return PJ_RETURN_OS_ERROR(GetLastError());

#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Destroy reference counters */
    key = ioqueue->active_list.next;
    while (key != &ioqueue->active_list) {
	pj_atomic_destroy(key->ref_count);
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }

    key = ioqueue->closing_list.next;
    while (key != &ioqueue->closing_list) {
	pj_atomic_destroy(key->ref_count);
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }

    key = ioqueue->free_list.next;
    while (key != &ioqueue->free_list) {
	pj_atomic_destroy(key->ref_count);
	pj_mutex_destroy(key->mutex);
	key = key->next;
    }
#endif

    if (ioqueue->auto_delete_lock)
        pj_lock_destroy(ioqueue->lock);

    return PJ_SUCCESS;
}
Example #27
0
/*
 * Unregister an allocation from the hash tables.
 */
PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv,
						     pj_turn_allocation *alloc)
{
    /* Unregister from hash tables */
    pj_lock_acquire(srv->core.lock);
    pj_hash_set(alloc->pool, srv->tables.alloc,
		&alloc->hkey, sizeof(alloc->hkey), 0, NULL);
    pj_hash_set(alloc->pool, srv->tables.res,
		&alloc->relay.hkey, sizeof(alloc->relay.hkey), 0, NULL);
    pj_lock_release(srv->core.lock);

    return PJ_SUCCESS;
}
Example #28
0
/* Flush all delayed transmision once the socket is connected. */
static void tcp_flush_pending_tx(struct tcp_transport *tcp)
{
    pj_time_val now;

    pj_gettickcount(&now);
    pj_lock_acquire(tcp->base.lock);
    while (!pj_list_empty(&tcp->delayed_list)) {
	struct delayed_tdata *pending_tx;
	pjsip_tx_data *tdata;
	pj_ioqueue_op_key_t *op_key;
	pj_ssize_t size;
	pj_status_t status;

	pending_tx = tcp->delayed_list.next;
	pj_list_erase(pending_tx);

	tdata = pending_tx->tdata_op_key->tdata;
	op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;

        if (pending_tx->timeout.sec > 0 &&
            PJ_TIME_VAL_GT(now, pending_tx->timeout))
        {
            continue;
        }

	/* send! */
	size = tdata->buf.cur - tdata->buf.start;
	status = pj_activesock_send(tcp->asock, op_key, tdata->buf.start, 
				    &size, 0);
	if (status != PJ_EPENDING) {
            pj_lock_release(tcp->base.lock);
	    on_data_sent(tcp->asock, op_key, size);
            pj_lock_acquire(tcp->base.lock);
	}

    }
    pj_lock_release(tcp->base.lock);
}
Example #29
0
PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,
					        int contact_cnt,
						const pj_str_t contact[] )
{
    pj_status_t status;

    PJ_ASSERT_RETURN(regc, PJ_EINVAL);

    pj_lock_acquire(regc->lock);
    status = set_contact( regc, contact_cnt, contact );
    pj_lock_release(regc->lock);

    return status;
}
Example #30
0
/**
 * Set credential to be used by the session.
 */
PJ_DEF(pj_status_t) pj_tcp_session_set_credential(pj_tcp_session *sess,
        const pj_stun_auth_cred *cred)
{
    PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
    PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);

    pj_lock_acquire(sess->lock);

    pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);

    pj_lock_release(sess->lock);

    return PJ_SUCCESS;
}