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; }
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; }
/* * 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); }
/* * 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); }
/* * 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; }
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); }
/** * 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; }
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(®c->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, ®c->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; }
/* * 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); }
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; }
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, ®c->timer); regc->timer.id = 0; /* Schedule next registration */ schedule_registration(regc, regc->expires); } } pj_lock_release(regc->lock); return PJ_SUCCESS; }
/* * 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; }
/* 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); }
/* * 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); } }
/* * 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; }
/* * 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; }
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; }
/* * 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; }
/* * 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; }
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 != ®c->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(®c->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, ®c->timer); regc->timer.id = 0; } regc->auto_reg = autoreg; pj_lock_release(regc->lock); /* Done */ *p_tdata = tdata; return PJ_SUCCESS; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* 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); }
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; }
/** * 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; }