Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/include/switch_rtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ typedef struct icand_s {
switch_port_t rport;
char *generation;
uint8_t ready;
switch_time_t last_binding_response;
switch_sockaddr_t *addr;
} icand_t;

#define MAX_CAND 50
Expand Down
8 changes: 8 additions & 0 deletions src/switch_core_media.c
Original file line number Diff line number Diff line change
Expand Up @@ -4367,6 +4367,14 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].priority = atol(fields[3]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_addr = switch_core_session_strdup(smh->session, con_addr);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_port = (switch_port_t)atoi(fields[5]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].last_binding_response = 0;

switch_sockaddr_new(
&engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].addr,
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_addr,
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_port,
smh->session->pool
);

j = 6;

Expand Down
192 changes: 102 additions & 90 deletions src/switch_rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,9 @@ static void switch_rtp_change_ice_dest(switch_rtp_t *rtp_session, switch_rtp_ice

ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].con_addr = switch_core_strdup(rtp_session->pool, host);
ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].con_port = port;
ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].addr->hostname = switch_core_strdup(rtp_session->pool, host);
ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].addr->port = port;

ice->missed_count = 0;

if (is_rtcp) {
Expand Down Expand Up @@ -816,7 +819,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags);


static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice)
static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, icand_t *cand)
{
uint8_t buf[256] = { 0 };
switch_stun_packet_t *packet;
Expand All @@ -826,17 +829,25 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice)
//switch_sockaddr_t *remote_addr = rtp_session->remote_addr;
switch_socket_t *sock_output = rtp_session->sock_output;
switch_time_t now = switch_micro_time_now();
switch_sockaddr_t *addr;

if (ice->type & ICE_LITE) {
// no connectivity checks for ICE-Lite
return SWITCH_STATUS_BREAK;
}

if (ice->next_run && ice->next_run > now) {
if (!cand && ice->next_run && ice->next_run > now) {
return SWITCH_STATUS_BREAK;
}

ice->next_run = now + RTP_STUN_FREQ;
if (!cand) {
cand = &ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto];
addr = ice->addr;
ice->next_run = now + RTP_STUN_FREQ;
} else {
addr = cand->addr;
}


if (ice == &rtp_session->rtcp_ice && rtp_session->rtcp_sock_output) {
sock_output = rtp_session->rtcp_sock_output;
Expand Down Expand Up @@ -874,7 +885,7 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice)
if ((ice->type & ICE_VANILLA)) {
char sw[128] = "";

switch_stun_packet_attribute_add_priority(packet, ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].priority);
switch_stun_packet_attribute_add_priority(packet, cand->priority);

switch_snprintf(sw, sizeof(sw), "FreeSWITCH (%s)", switch_version_revision_human());
switch_stun_packet_attribute_add_software(packet, sw, (uint16_t)strlen(sw));
Expand All @@ -890,13 +901,13 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice)
switch_stun_packet_attribute_add_fingerprint(packet);
}


bytes = switch_stun_packet_length(packet);

#ifdef DEBUG_EXTRA
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s send %s stun\n", rtp_session_name(rtp_session), rtp_type(rtp_session));
#endif
switch_socket_sendto(sock_output, ice->addr, 0, (void *) packet, &bytes);

switch_socket_sendto(sock_output, addr, 0, (void *) packet, &bytes);

ice->sending = 3;

Expand All @@ -915,6 +926,28 @@ int icecmp(const char *them, switch_rtp_ice_t *ice)
return strcmp(them, ice->luser_ice);
}

static int locate_candidate(switch_rtp_ice_t *ice, switch_sockaddr_t *from_addr, icand_t **cand)
{
const char *host = NULL;
switch_port_t port = 0;
char buf[80] = "";
int i;

host = switch_get_addr(buf, sizeof(buf), from_addr);
port = switch_sockaddr_get_port(from_addr);
for (i = 0; i < MAX_CAND; i++) {
if (!ice->ice_params->cands[i][ice->proto].con_addr) {
continue;
}
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) && ice->ice_params->cands[i][ice->proto].con_port == port) {
*cand = &ice->ice_params->cands[i][ice->proto];
return i;
}
}

return -1;
}

static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *data, switch_size_t len)
{
switch_stun_packet_t *packet;
Expand All @@ -929,6 +962,14 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
int is_rtcp = ice == &rtp_session->rtcp_ice;
uint32_t elapsed;
switch_time_t ref_point;
int cur_idx = -1;
icand_t *cand = NULL;
uint32_t priority = 0;

cur_idx = locate_candidate(ice, rtp_session->from_addr, &cand);
if (cand) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG2, "ICE packet from candidate %s:%d idx %d\n", cand->con_addr, cand->con_port, cur_idx);
}

//if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
// switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "WTF OK %s CALL\n", rtp_type(rtp_session));
Expand Down Expand Up @@ -1039,7 +1080,6 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d

case SWITCH_STUN_ATTR_PRIORITY:
{
uint32_t priority = 0;
pri = (uint32_t *) attr->value;
priority = ntohl(*pri);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %u\n", priority);
Expand All @@ -1055,6 +1095,39 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
xlen += 4 + switch_stun_attribute_padded_length(attr);
} while (xlen <= packet->header.length);

if (!cand) {
const char *__host = NULL;
switch_port_t __port = 0;
char __buf[80] = "";
int cid = ice->proto;
int next_idx = ice->ice_params->cand_idx[ice->proto];

__host = switch_get_addr(__buf, sizeof(__buf), rtp_session->from_addr);
__port = switch_sockaddr_get_port(rtp_session->from_addr);

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG2, "ICE packet from unknown candidate %s:%d - Updating candidate list idx %d\n", __host, __port, next_idx);
//should we check for ACL?

//ice->ice_params->cands[next_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
ice->ice_params->cands[next_idx][cid].transport = "udp"; //switch_core_session_strdup(smh->session, fields[2]);

ice->ice_params->cands[next_idx][cid].component_id = ice->proto;
ice->ice_params->cands[next_idx][cid].priority = priority;
ice->ice_params->cands[next_idx][cid].con_addr = switch_core_session_strdup(rtp_session->session, __host);
ice->ice_params->cands[next_idx][cid].con_port = __port;
ice->ice_params->cands[next_idx][cid].last_binding_response = 0;

switch_sockaddr_new(
&ice->ice_params->cands[next_idx][cid].addr,
ice->ice_params->cands[next_idx][cid].con_addr,
ice->ice_params->cands[next_idx][cid].con_port,
rtp_session->pool
);
cand = &ice->ice_params->cands[next_idx][cid];

ice->ice_params->cand_idx[ice->proto]++;
}

if ((ice->type & ICE_GOOGLE_JINGLE) && ok) {
ok = !strcmp(ice->user_ice, username);
}
Expand All @@ -1067,6 +1140,25 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
if (!ok) ok = !memcmp(packet->header.id, ice->last_sent_id, 12);

if (packet->header.type == SWITCH_STUN_BINDING_RESPONSE) {
int chosen_idx = ice->ice_params->chosen[ice->proto];
if (cand) {
cand->last_binding_response = switch_micro_time_now();

if (!ice->ice_params->cands[chosen_idx][ice->proto].last_binding_response) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG2, "BINDING_RESPONSE from candidate %s:%d\n", cand->con_addr, cand->con_port);
if (cur_idx > -1) {
ice->ice_params->chosen[ice->proto] = cur_idx;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_NOTICE,
"Auto Changing %s stun/%s/dtls port from %s:%u lr:%ld idx:%d to %s:%u lr:%ld idx:%d\n", rtp_type(rtp_session), is_rtcp ? "rtcp" : "rtp",
ice->ice_params->cands[chosen_idx][ice->proto].con_addr, ice->ice_params->cands[chosen_idx][ice->proto].con_port, ice->ice_params->cands[chosen_idx][ice->proto].last_binding_response, chosen_idx,
cand->con_addr, cand->con_port, cand->last_binding_response, cur_idx);

switch_rtp_change_ice_dest(rtp_session, ice, cand->con_addr, cand->con_port);
}
}
} else {
}

ok = 1;
if (!ice->rready) {
if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
Expand Down Expand Up @@ -1205,11 +1297,6 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
//}

if (ok) {
const char *host = NULL, *host2 = NULL;
switch_port_t port = 0, port2 = 0;
char buf[80] = "";
char buf2[80] = "";

if (packet->header.type == SWITCH_STUN_BINDING_REQUEST) {
uint8_t stunbuf[512];
switch_stun_packet_t *rpacket;
Expand All @@ -1218,11 +1305,6 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
char ipbuf[50];
switch_sockaddr_t *from_addr = rtp_session->from_addr;
switch_socket_t *sock_output = rtp_session->sock_output;
uint8_t do_adj = 0;
switch_time_t now = switch_micro_time_now();
int cmp = 0;
int cur_idx = -1;//, is_relay = 0;
int i;

if (is_rtcp) {
from_addr = rtp_session->rtcp_from_addr;
Expand Down Expand Up @@ -1251,78 +1333,8 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d

bytes = switch_stun_packet_length(rpacket);

host = switch_get_addr(buf, sizeof(buf), from_addr);
port = switch_sockaddr_get_port(from_addr);
host2 = switch_get_addr(buf2, sizeof(buf2), ice->addr);
port2 = switch_sockaddr_get_port(ice->addr);
cmp = switch_cmp_addr(from_addr, ice->addr, SWITCH_FALSE);

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG2,
"STUN from %s:%d %s\n", host, port, cmp ? "EXPECTED" : "IGNORED");

if (ice->init && !cmp && switch_cmp_addr(from_addr, ice->addr, SWITCH_TRUE)) {
do_adj++;
rtp_session->ice_adj++;
rtp_session->wrong_addrs = 0;
ice->init = 0;
}

if (cmp) {
ice->last_ok = now;
rtp_session->wrong_addrs = 0;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG10, "ICE %d dt:%d i:%d i2:%d w:%d cmp:%d adj:%d\n", elapsed, (rtp_session->dtls && rtp_session->dtls->state != DS_READY), !ice->ready, !ice->rready, rtp_session->wrong_addrs, switch_cmp_addr(from_addr, ice->addr, SWITCH_TRUE), rtp_session->ice_adj);

if ((rtp_session->dtls && rtp_session->dtls->state != DS_READY) ||
((!ice->ready || !ice->rready) && (rtp_session->wrong_addrs > 2 || switch_cmp_addr(from_addr, ice->addr, SWITCH_TRUE)) &&
rtp_session->ice_adj < 10)) {
do_adj++;
rtp_session->ice_adj++;
rtp_session->wrong_addrs = 0;
} else if (rtp_session->wrong_addrs > 10 || elapsed >= 5000) {
do_adj++;
}

if (!do_adj) {
rtp_session->wrong_addrs++;
}

for (i = 0; i < ice->ice_params->cand_idx[ice->proto]; i++) {
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host)) {
cur_idx = i;
//if (!strcasecmp(ice->ice_params->cands[i][ice->proto].cand_type, "relay")) {
// is_relay = 1;
//}
}
}


if (ice->ice_params && ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].cand_type &&
!strcasecmp(ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].cand_type, "relay")) {
do_adj++;
}
}

if ((ice->type & ICE_VANILLA) && ice->ice_params && do_adj) {
ice->missed_count = 0;
ice->rready = 1;

if (cur_idx > -1) {
ice->ice_params->chosen[ice->proto] = cur_idx;
}

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_NOTICE,
"Auto Changing %s stun/%s/dtls port from %s:%u to %s:%u idx:%d\n", rtp_type(rtp_session), is_rtcp ? "rtcp" : "rtp",
host2, port2,
host, port, cur_idx);

switch_rtp_change_ice_dest(rtp_session, ice, host, port);
ice->last_ok = now;
rtp_session->wrong_addrs = 0;
}
//if (cmp) {
switch_socket_sendto(sock_output, from_addr, 0, (void *) rpacket, &bytes);
//}
ice_out(rtp_session, ice, cand);
}
} else if (packet->header.type == SWITCH_STUN_BINDING_ERROR_RESPONSE) {

Expand Down Expand Up @@ -2592,15 +2604,15 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
}

if (rtp_session->ice.ice_user) {
if (ice_out(rtp_session, &rtp_session->ice) == SWITCH_STATUS_GENERR) {
if (ice_out(rtp_session, &rtp_session->ice, NULL) == SWITCH_STATUS_GENERR) {
ret = -1;
goto end;
}
}

if (!rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
if (rtp_session->rtcp_ice.ice_user) {
if (ice_out(rtp_session, &rtp_session->rtcp_ice) == SWITCH_STATUS_GENERR) {
if (ice_out(rtp_session, &rtp_session->rtcp_ice, NULL) == SWITCH_STATUS_GENERR) {
ret = -1;
goto end;
}
Expand Down