⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ice_strans.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	    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 + -