📄 transport_ice.c
字号:
/* $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 + -