?? ice_strans.c
字號:
if (ifs[i].s_addr == comp->local_addr.ipv4.sin_addr.s_addr) {
set_default = PJ_TRUE;
local_pref = 65535;
} else {
set_default = PJ_FALSE;
local_pref = 0;
}
status = add_cand(ice_st, comp, comp_id,
PJ_ICE_CAND_TYPE_HOST,
local_pref, &cand_addr, set_default);
if (status != PJ_SUCCESS)
goto on_error;
}
} else if ((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) {
/* Socket is bound to specific address.
* In this case only add that address as a single entry in the
* cand_list table.
*/
status = add_cand(ice_st, comp, comp_id,
PJ_ICE_CAND_TYPE_HOST,
65535, &comp->local_addr.ipv4,
PJ_TRUE);
if (status != PJ_SUCCESS)
goto on_error;
} else if (options & PJ_ICE_ST_OPT_DONT_ADD_CAND) {
/* If application doesn't want to add candidate, just fix local_addr
* in case its value is zero.
*/
if (comp->local_addr.ipv4.sin_addr.s_addr == 0) {
status = pj_gethostip(&comp->local_addr.ipv4.sin_addr);
if (status != PJ_SUCCESS)
return status;
}
}
/* Done */
if (p_comp)
*p_comp = comp;
return PJ_SUCCESS;
on_error:
destroy_component(comp);
return status;
}
/*
* This is callback called by ioqueue on incoming packet
*/
static void on_read_complete(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_read)
{
pj_ice_strans_comp *comp = (pj_ice_strans_comp*)
pj_ioqueue_get_user_data(key);
pj_ice_strans *ice_st = comp->ice_st;
pj_ssize_t pkt_size;
enum { RETRY = 4 };
unsigned retry;
pj_status_t status;
if (bytes_read > 0) {
/*
* Okay, we got a packet from the socket for the component. There is
* a bit of situation here, since this packet could be one of these:
*
* 1) this could be the response of STUN binding request sent by
* this component to a) an initial request to get the STUN mapped
* address of this component, or b) subsequent request to keep
* the binding alive.
*
* 2) this could be a packet (STUN or not STUN) sent from the STUN
* relay server. In this case, still there are few options to do
* for this packet: a) process this locally if this packet is
* related to TURN session management (e.g. Allocate response),
* b) forward this packet to ICE if this is related to ICE
* discovery process.
*
* 3) this could be a STUN request or response sent as part of ICE
* discovery process.
*
* 4) this could be application's packet, e.g. when ICE processing
* is done and agents start sending RTP/RTCP packets to each
* other, or when ICE processing is not done and this ICE stream
* transport decides to allow sending data.
*
* So far we don't have good solution for this.
* The process below is just a workaround.
*/
status = pj_stun_msg_check(comp->pkt, bytes_read,
PJ_STUN_IS_DATAGRAM);
if (status == PJ_SUCCESS) {
if (ice_st->ice==NULL ||
(comp->stun_sess &&
pj_memcmp(comp->pkt+8, comp->ka_tsx_id, 12) == 0))
{
status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt,
bytes_read,
PJ_STUN_IS_DATAGRAM, NULL,
&comp->src_addr,
comp->src_addr_len);
} else if (ice_st->ice) {
PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY);
TRACE_PKT((comp->ice_st->obj_name,
"Component %d RX packet from %s:%d",
comp->comp_id,
pj_inet_ntoa(comp->src_addr.ipv4.sin_addr),
(int)pj_ntohs(comp->src_addr.ipv4.sin_port)));
status = pj_ice_sess_on_rx_pkt(ice_st->ice, comp->comp_id,
comp->pkt, bytes_read,
&comp->src_addr,
comp->src_addr_len);
} else {
/* This must have been a very late STUN reponse */
}
} else {
(*ice_st->cb.on_rx_data)(ice_st, comp->comp_id,
comp->pkt, bytes_read,
&comp->src_addr, comp->src_addr_len);
}
} else if (bytes_read < 0) {
ice_st_perror(comp->ice_st, "ioqueue read callback error",
-bytes_read);
}
/* Read next packet */
for (retry=0; retry<RETRY; ++retry) {
pkt_size = sizeof(comp->pkt);
comp->src_addr_len = sizeof(comp->src_addr);
status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size,
PJ_IOQUEUE_ALWAYS_ASYNC,
&comp->src_addr, &comp->src_addr_len);
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status);
} else {
break;
}
}
}
/*
* Destroy a component
*/
static void destroy_component(pj_ice_strans_comp *comp)
{
if (comp->stun_sess) {
pj_stun_session_destroy(comp->stun_sess);
comp->stun_sess = NULL;
}
if (comp->key) {
pj_ioqueue_unregister(comp->key);
comp->key = NULL;
comp->sock = PJ_INVALID_SOCKET;
} else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) {
pj_sock_close(comp->sock);
comp->sock = PJ_INVALID_SOCKET;
}
}
/* STUN keep-alive timer callback */
static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
{
pj_ice_strans *ice_st = (pj_ice_strans*)te->user_data;
unsigned i;
pj_status_t status;
PJ_UNUSED_ARG(th);
ice_st->ka_timer.id = PJ_FALSE;
for (i=0; i<ice_st->comp_cnt; ++i) {
pj_ice_strans_comp *comp = ice_st->comp[i];
pj_stun_tx_data *tdata;
unsigned j;
/* Does this component have STUN server reflexive candidate? */
for (j=0; j<comp->cand_cnt; ++j) {
if (comp->cand_list[j].type == PJ_ICE_CAND_TYPE_SRFLX)
break;
}
if (j == comp->cand_cnt)
continue;
/* Create STUN binding request */
status = pj_stun_session_create_req(comp->stun_sess,
PJ_STUN_BINDING_REQUEST,
comp->ka_tsx_id, &tdata);
if (status != PJ_SUCCESS)
continue;
/* tdata->user_data is NULL for keep-alive */
tdata->user_data = NULL;
/* Send STUN binding request */
PJ_LOG(5,(ice_st->obj_name, "Sending STUN keep-alive"));
status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,
&ice_st->stun_srv,
sizeof(pj_sockaddr_in), tdata);
}
/* Start next timer */
start_ka_timer(ice_st);
}
/* Start STUN keep-alive timer */
static void start_ka_timer(pj_ice_strans *ice_st)
{
pj_time_val delay;
/* Skip if timer is already running */
if (ice_st->ka_timer.id != PJ_FALSE)
return;
delay.sec = PJ_ICE_ST_KEEP_ALIVE_MIN;
delay.msec = pj_rand() % (PJ_ICE_ST_KEEP_ALIVE_MAX_RAND * 1000);
pj_time_val_normalize(&delay);
ice_st->ka_timer.cb = &ka_timer_cb;
ice_st->ka_timer.user_data = ice_st;
if (pj_timer_heap_schedule(ice_st->stun_cfg.timer_heap,
&ice_st->ka_timer, &delay)==PJ_SUCCESS)
{
ice_st->ka_timer.id = PJ_TRUE;
}
}
/* Stop STUN keep-alive timer */
static void stop_ka_timer(pj_ice_strans *ice_st)
{
/* Skip if timer is already stop */
if (ice_st->ka_timer.id == PJ_FALSE)
return;
pj_timer_heap_cancel(ice_st->stun_cfg.timer_heap, &ice_st->ka_timer);
ice_st->ka_timer.id = PJ_FALSE;
}
/*
* Add STUN mapping to a component.
*/
static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st,
pj_ice_strans_comp *comp)
{
pj_ice_strans_cand *cand;
pj_stun_session_cb sess_cb;
pj_stun_tx_data *tdata;
pj_status_t status;
PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL);
/* Bail out if STUN server is still being resolved */
if (ice_st->has_rjob)
return PJ_EBUSY;
/* Just return (successfully) if STUN server is not configured */
if (ice_st->stun_srv.sin_family == 0)
return PJ_SUCCESS;
/* Create STUN session for this component */
pj_bzero(&sess_cb, sizeof(sess_cb));
sess_cb.on_request_complete = &stun_on_request_complete;
sess_cb.on_send_msg = &stun_on_send_msg;
status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name,
&sess_cb, PJ_FALSE, &comp->stun_sess);
if (status != PJ_SUCCESS)
return status;
/* Associate component with STUN session */
pj_stun_session_set_user_data(comp->stun_sess, (void*)comp);
/* Create STUN binding request */
status = pj_stun_session_create_req(comp->stun_sess,
PJ_STUN_BINDING_REQUEST,
comp->ka_tsx_id,
&tdata);
if (status != PJ_SUCCESS)
return status;
/* Attach alias instance to tdata */
cand = &comp->cand_list[comp->cand_cnt];
tdata->user_data = (void*)cand;
/* Send STUN binding request */
status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,
&ice_st->stun_srv,
sizeof(pj_sockaddr_in), tdata);
if (status != PJ_SUCCESS)
return status;
/* Add new alias to this component */
cand->type = PJ_ICE_CAND_TYPE_SRFLX;
cand->status = PJ_EPENDING;
cand->ice_cand_id = -1;
cand->local_pref = 65535;
pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
PJ_ICE_CAND_TYPE_SRFLX, &comp->local_addr);
++comp->cand_cnt;
/* Add pending count for this component */
comp->pending_cnt++;
return PJ_SUCCESS;
}
/*
* Create the component.
*/
PJ_DEF(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st,
unsigned comp_id,
pj_uint32_t options,
const pj_sockaddr_in *addr)
{
pj_ice_strans_comp *comp = NULL;
pj_status_t status;
/* Verify arguments */
PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
/* Check that component ID present */
PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
/* Can't add new component while ICE is running */
PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
/* Can't add new component while resolver is running */
PJ_ASSERT_RETURN(ice_st->has_rjob == PJ_FALSE, PJ_EBUSY);
/* Create component */
status = create_component(ice_st, comp_id, options, addr, &comp);
if (status != PJ_SUCCESS)
return status;
if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) {
status = get_stun_mapped_addr(ice_st, comp);
if (status != PJ_SUCCESS) {
destroy_component(comp);
return status;
}
}
/* Store this component */
ice_st->comp[comp_id-1] = comp;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_ice_strans_add_cand( pj_ice_strans *ice_st,
unsigned comp_id,
pj_ice_cand_type type,
pj_uint16_t local_pref,
const pj_sockaddr_in *addr,
pj_bool_t set_default)
{
pj_ice_strans_comp *comp;
PJ_ASSERT_RETURN(ice_st && comp_id && addr, PJ_EINVAL);
PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJ_EINVAL);
PJ_ASSERT_RETURN(ice_st->comp[comp_id-1] != NULL, PJ_EINVALIDOP);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -