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

📄 transport_ice.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: transport_ice.c 1266 2007-05-11 15:14:34Z bennylp $ */
/* 
 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */
#include <pjmedia/transport_ice.h>
#include <pjnath/errno.h>
#include <pj/assert.h>
#include <pj/log.h>

struct transport_ice
{
    pjmedia_transport	 base;
    pj_ice_strans	*ice_st;

    pj_time_val		 start_ice;
    
    void		*stream;
    pj_sockaddr_in	 remote_rtp;
    pj_sockaddr_in	 remote_rtcp;

    void	       (*rtp_cb)(void*,
			         const void*,
				 pj_ssize_t);
    void	       (*rtcp_cb)(void*,
				  const void*,
				  pj_ssize_t);
};


/*
 * These are media transport operations.
 */
static pj_status_t tp_get_info(pjmedia_transport *tp,
			       pjmedia_sock_info *info);
static pj_status_t tp_attach( pjmedia_transport *tp,
			      void *stream,
			      const pj_sockaddr_t *rem_addr,
			      const pj_sockaddr_t *rem_rtcp,
			      unsigned addr_len,
			      void (*rtp_cb)(void*,
					     const void*,
					     pj_ssize_t),
			      void (*rtcp_cb)(void*,
					      const void*,
					      pj_ssize_t));
static void	   tp_detach( pjmedia_transport *tp,
			      void *strm);
static pj_status_t tp_send_rtp( pjmedia_transport *tp,
			        const void *pkt,
			        pj_size_t size);
static pj_status_t tp_send_rtcp( pjmedia_transport *tp,
			         const void *pkt,
			         pj_size_t size);

/*
 * And these are ICE callbacks.
 */
static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id, 
			   void *pkt, pj_size_t size,
			   const pj_sockaddr_t *src_addr,
			   unsigned src_addr_len);
static void ice_on_ice_complete(pj_ice_strans *ice_st, 
			        pj_status_t status);


static pjmedia_transport_op tp_ice_op = 
{
    &tp_get_info,
    &tp_attach,
    &tp_detach,
    &tp_send_rtp,
    &tp_send_rtcp,
    &pjmedia_ice_destroy
};


/*
 * Create ICE media transport.
 */
PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
				       const char *name,
				       unsigned comp_cnt,
				       pj_stun_config *stun_cfg,
	    			       pjmedia_transport **p_tp)
{
    pj_ice_strans *ice_st;
    pj_ice_strans_cb ice_st_cb;
    struct transport_ice *tp_ice;
    pj_status_t status;

    PJ_UNUSED_ARG(endpt);

    /* Configure ICE callbacks */
    pj_bzero(&ice_st_cb, sizeof(ice_st_cb));
    ice_st_cb.on_ice_complete = &ice_on_ice_complete;
    ice_st_cb.on_rx_data = &ice_on_rx_data;

    /* Create ICE */
    status = pj_ice_strans_create(stun_cfg, name, comp_cnt, NULL, 
			      &ice_st_cb, &ice_st);
    if (status != PJ_SUCCESS)
	return status;


    /* Create transport instance and attach to ICE */
    tp_ice = PJ_POOL_ZALLOC_T(ice_st->pool, struct transport_ice);
    tp_ice->ice_st = ice_st;
    pj_ansi_strcpy(tp_ice->base.name, ice_st->obj_name);
    tp_ice->base.op = &tp_ice_op;
    tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE;

    ice_st->user_data = (void*)tp_ice;

    /* Done */
    if (p_tp)
	*p_tp = &tp_ice->base;

    return PJ_SUCCESS;
}


/*
 * Destroy ICE media transport.
 */
PJ_DEF(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;

    if (tp_ice->ice_st) {
	pj_ice_strans_destroy(tp_ice->ice_st);
	/*Must not touch tp_ice after ice_st is destroyed!
	 (it has the pool)
	 tp_ice->ice_st = NULL;
	 */
    }

    return PJ_SUCCESS;
}


/*
 * Start media transport initialization.
 */
PJ_DEF(pj_status_t) pjmedia_ice_start_init( pjmedia_transport *tp,
					    unsigned options,
					    const pj_sockaddr_in *start_addr,
					    const pj_sockaddr_in *stun_srv,
					    const pj_sockaddr_in *turn_srv)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    pj_status_t status;

    status = pj_ice_strans_set_stun_srv(tp_ice->ice_st, stun_srv, turn_srv);
    if (status != PJ_SUCCESS)
	return status;

    status = pj_ice_strans_create_comp(tp_ice->ice_st, 1, options, start_addr);
    if (status != PJ_SUCCESS)
	return status;

    if (tp_ice->ice_st->comp_cnt > 1) {
	pj_sockaddr_in addr;
	pj_uint16_t port;

	pj_memcpy(&addr, &tp_ice->ice_st->comp[0]->local_addr.ipv4,
		  sizeof(pj_sockaddr_in));
	if (start_addr)
	    addr.sin_addr.s_addr = start_addr->sin_addr.s_addr;
	else
	    addr.sin_addr.s_addr = 0;

	port = pj_ntohs(addr.sin_port);
	++port;
	addr.sin_port = pj_htons(port);
	status = pj_ice_strans_create_comp(tp_ice->ice_st, 2, options, &addr);
	if (status != PJ_SUCCESS)
	    return status;
    }
    return status;
}


/*
 * Get the status of media transport initialization.
 */
PJ_DEF(pj_status_t) pjmedia_ice_get_init_status(pjmedia_transport *tp)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    return pj_ice_strans_get_comps_status(tp_ice->ice_st);
}


/*
 * Get the component for the specified component ID.
 */
PJ_DEF(pj_status_t) pjmedia_ice_get_comp( pjmedia_transport *tp,
					  unsigned comp_id,
					  pj_ice_strans_comp *comp)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    PJ_ASSERT_RETURN(tp && comp_id && comp_id <= tp_ice->ice_st->comp_cnt &&
		     comp, PJ_EINVAL);

    pj_memcpy(comp, tp_ice->ice_st->comp[comp_id-1], sizeof(pj_ice_strans_comp));
    return PJ_SUCCESS;		    
}


/*
 * Create ICE! This happens when:
 *  - UAC is ready to send offer
 *  - UAS have just received an offer.
 */
PJ_DEF(pj_status_t) pjmedia_ice_init_ice(pjmedia_transport *tp,
					 pj_ice_sess_role role,
					 const pj_str_t *local_ufrag,
					 const pj_str_t *local_passwd)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    return pj_ice_strans_init_ice(tp_ice->ice_st, role, local_ufrag, local_passwd);
}


/*
 * For both UAC and UAS, pass in the SDP before sending it to remote.
 * This will add ICE attributes to the SDP.
 */
PJ_DEF(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp,
					   pj_pool_t *pool,
					   pjmedia_sdp_session *sdp)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    enum { MAXLEN = 256 };
    char *buffer;
    pjmedia_sdp_attr *attr;
    unsigned i, cand_cnt;

    buffer = (char*) pj_pool_alloc(pool, MAXLEN);

    /* Create ice-ufrag attribute */
    attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", 
				   &tp_ice->ice_st->ice->rx_ufrag);
    sdp->attr[sdp->attr_count++] = attr;

    /* Create ice-pwd attribute */
    attr = pjmedia_sdp_attr_create(pool, "ice-pwd", 
				   &tp_ice->ice_st->ice->rx_pass);
    sdp->attr[sdp->attr_count++] = attr;

    /* Add all candidates (to media level) */
    cand_cnt = tp_ice->ice_st->ice->lcand_cnt;
    for (i=0; i<cand_cnt; ++i) {
	pj_ice_sess_cand *cand;
	pj_str_t value;
	int len;

	cand = &tp_ice->ice_st->ice->lcand[i];

	len = pj_ansi_snprintf( buffer, MAXLEN,
				"%.*s %d UDP %u %s %d typ ",
				(int)cand->foundation.slen,
				cand->foundation.ptr,
				cand->comp_id,
				cand->prio,
				pj_inet_ntoa(cand->addr.ipv4.sin_addr),
				(int)pj_ntohs(cand->addr.ipv4.sin_port));
	if (len < 1 || len >= MAXLEN)
	    return PJ_ENAMETOOLONG;

	switch (cand->type) {
	case PJ_ICE_CAND_TYPE_HOST:
	    len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
			     "host");
	    break;
	case PJ_ICE_CAND_TYPE_SRFLX:
	    len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
			     "srflx raddr %s rport %d",
			     pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
			     (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
	    break;
	case PJ_ICE_CAND_TYPE_RELAYED:
	    PJ_TODO(RELATED_ADDR_FOR_RELAYED_ADDR);
	    len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
			     "srflx raddr %s rport %d",
			     pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
			     (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
	    break;
	case PJ_ICE_CAND_TYPE_PRFLX:
	    len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
			     "prflx raddr %s rport %d",
			     pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
			     (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
	    break;
	default:
	    pj_assert(!"Invalid candidate type");
	    break;
	}
	if (len < 1 || len >= MAXLEN)
	    return PJ_ENAMETOOLONG;

	value = pj_str(buffer);
	attr = pjmedia_sdp_attr_create(pool, "candidate", &value);
	sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
    }

    /* Done */
    return PJ_SUCCESS;

}


/* Parse a=candidate line */
static pj_status_t parse_cand(pj_pool_t *pool,
			      const pj_str_t *orig_input,
			      pj_ice_sess_cand *cand)
{
    pj_str_t input;
    char *token, *host;
    pj_str_t s;
    pj_status_t status = PJNATH_EICEINCANDSDP;

    pj_bzero(cand, sizeof(*cand));
    pj_strdup_with_null(pool, &input, orig_input);

    /* Foundation */
    token = strtok(input.ptr, " ");
    if (!token)
	goto on_return;
    pj_strdup2(pool, &cand->foundation, token);

    /* Component ID */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;
    cand->comp_id = atoi(token);

    /* Transport */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;
    if (strcmp(token, "UDP") != 0)
	goto on_return;

    /* Priority */
    token = strtok(NULL, " ");
    if (!token)
	goto on_return;
    cand->prio = atoi(token);

    /* Host */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -