Commit a6954838 authored by Youness Alaoui's avatar Youness Alaoui Committed by Olivier Crête

Add support for ICE-TCP

This is a massive commit that can't be split. We add ice-tcp support
into the agent by creating local host tcp-active/tcp-passive candidates.
We also need to find the local and remote candidates whenever we discover
a peer-reflexive because their data is important to setup the peer-reflexive
so a few changes were added to look for the local or remote candidate.
For TCP-ACTIVE remote peer-reflexive candidates, we can't add conncheck
pairs normally because TCP-PASSIVE (local) do not generate candidate pairs,
and we also can't have a connection from any local host, so we can only create
a single candidatepair with the local/remote that are connected.
The pair->socket of a candidate check pair will hold the connected tcp socket
(through connect for ACT or accept for PASS) and we will either have a
remote or a local peer-reflexive which will create a new candidate pair,
we cannot trigger checks on the initial candidate pair, we must only do it
on the new check pairs. but in the case of a tcp-passive, we don't get a new
local peer-reflexive candidate, so there is no new candidate with a new NiceSocket, so
when we get a triggered check, we need to match it to the candidate check pair
or when we select a pair, it will still use the original TCP-PASS socket.
We must store the new connected tcp socket in the peer reflexive candidates
since they represent that unique peer-reflx candidate's connection
parent 53b3e445
......@@ -133,6 +133,7 @@ tests/test-build-io-stream
tests/test-dribble
tests/test-fallback
tests/test-fullmode
tests/test-icetcp
tests/test-io-stream-cancelling
tests/test-io-stream-closing-read
tests/test-io-stream-closing-write
......
......@@ -161,6 +161,8 @@ struct _NiceAgent
GQueue pending_signals;
guint16 rfc4571_expecting_length;
gboolean use_ice_udp;
gboolean use_ice_tcp;
/* XXX: add pointer to internal data struct for ABI-safe extensions */
};
......
This diff is collapsed.
......@@ -1040,6 +1040,14 @@ void conn_check_remote_candidates_set(NiceAgent *agent)
}
}
}
} else {
for (l = component->local_candidates; l; l = l->next) {
NiceCandidate *cand = l->data;
if (nice_address_equal (&cand->addr, &icheck->local_socket->addr)) {
local_candidate = cand;
break;
}
}
}
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
......@@ -1062,7 +1070,12 @@ void conn_check_remote_candidates_set(NiceAgent *agent)
icheck->local_socket,
local_candidate, remote_candidate);
if (candidate) {
conn_check_add_for_candidate (agent, stream->id, component, candidate);
if (local_candidate &&
local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
priv_conn_check_add_for_candidate_pair_matched (agent,
stream->id, component, local_candidate, candidate);
else
conn_check_add_for_candidate (agent, stream->id, component, candidate);
if (icheck->use_candidate)
priv_mark_pair_nominated (agent, stream, component, candidate);
......@@ -1300,7 +1313,10 @@ static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Componen
pair->component_id = component->id;;
pair->local = local;
pair->remote = remote;
pair->sockptr = (NiceSocket *) local->sockptr;
if (remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
pair->sockptr = (NiceSocket *) remote->sockptr;
else
pair->sockptr = (NiceSocket *) local->sockptr;
g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s", local->foundation, remote->foundation);
pair->priority = agent_candidate_pair_priority (agent, local, remote);
......@@ -1787,6 +1803,26 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
}
/* TCP-ACTIVE candidate must create a new socket before sending
* by connecting to the peer. The new socket is stored in the candidate
* check pair, until we discover a new local peer reflexive */
if (pair->sockptr->fileno == NULL &&
pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
Stream *stream = NULL;
Component *component = NULL;
NiceSocket *new_socket;
if (agent_find_component (agent, pair->stream_id, pair->component_id,
&stream, &component)) {
new_socket = nice_tcp_active_socket_connect (pair->sockptr,
&pair->remote->addr);
if (new_socket) {
pair->sockptr = new_socket;
_priv_set_socket_tos (agent, pair->sockptr, stream->tos);
component_attach_socket (component, new_socket);
}
}
}
/* send the conncheck */
agent_socket_send (pair->sockptr, &pair->remote->addr,
buffer_len, (gchar *)pair->stun_buffer);
......@@ -1893,7 +1929,13 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream,
CandidateCheckPair *p = i->data;
if (p->component_id == component->id &&
p->remote == remote_cand &&
p->sockptr == local_socket) {
((p->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
p->sockptr == local_socket) ||
(p->local->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
p->local->sockptr == local_socket))) {
/* We don't check for p->sockptr because in the case of
* tcp-active we don't want to retrigger a check on a pair that
* was FAILED when a peer-reflexive pair was created */
nice_debug ("Agent %p : Found a matching pair %p for triggered check.", agent, p);
......@@ -2133,7 +2175,7 @@ static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAg
{
CandidateCheckPair *new_pair = NULL;
NiceAddress mapped;
GSList *j;
GSList *i, *j;
gboolean local_cand_matches = FALSE;
nice_address_set_from_sockaddr (&mapped, mapped_sockaddr);
......@@ -2141,7 +2183,19 @@ static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAg
for (j = component->local_candidates; j; j = j->next) {
NiceCandidate *cand = j->data;
if (nice_address_equal (&mapped, &cand->addr)) {
local_cand_matches = TRUE;
local_cand_matches = TRUE;
/* We always need to select the peer-reflexive Candidate Pair in the case
* of a TCP-ACTIVE local candidate, so we find it even if an incoming
* check matched an existing pair because it could be the original
* ACTIVE-PASSIVE candidate pair which was retriggered */
for (i = stream->conncheck_list; i; i = i->next) {
CandidateCheckPair *pair = i->data;
if (pair->local == cand && remote_candidate == pair->remote) {
new_pair = pair;
break;
}
}
break;
}
}
......@@ -2988,7 +3042,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
}
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand->sockptr == nicesock) {
if (nice_address_equal (&nicesock->addr, &cand->addr)) {
local_candidate = cand;
break;
}
......@@ -3123,8 +3177,14 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
agent, stream, component, priority, from, nicesock,
local_candidate,
remote_candidate2 ? remote_candidate2 : remote_candidate);
if(remote_candidate)
conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
if(remote_candidate) {
if (local_candidate &&
local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
priv_conn_check_add_for_candidate_pair_matched (agent,
stream->id, component, local_candidate, remote_candidate);
else
conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
}
}
priv_reply_to_conn_check (agent, stream, component, remote_candidate,
......
......@@ -500,8 +500,12 @@ NiceCandidate *discovery_add_local_host_candidate (
level ufrag/password are used */
if (transport == NICE_CANDIDATE_TRANSPORT_UDP) {
nicesock = nice_udp_bsd_socket_new (address);
} else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
nicesock = nice_tcp_active_socket_new (agent->main_context, address);
} else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
nicesock = nice_tcp_passive_socket_new (agent->main_context, address);
} else {
/* TODO: Add ICE-TCP */
/* TODO: Add TCP-SO */
}
if (!nicesock)
goto errors;
......@@ -693,10 +697,21 @@ discovery_add_peer_reflexive_candidate (
return NULL;
candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
candidate->transport = local->transport;
if (local)
candidate->transport = local->transport;
else if (remote)
candidate->transport = conn_check_match_transport (remote->transport);
else {
if (base_socket->type == NICE_SOCKET_TYPE_UDP_BSD ||
base_socket->type == NICE_SOCKET_TYPE_UDP_TURN)
candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
else
candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
}
candidate->stream_id = stream_id;
candidate->component_id = component_id;
candidate->addr = *address;
candidate->sockptr = base_socket;
candidate->base_addr = base_socket->addr;
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
......@@ -746,10 +761,6 @@ discovery_add_peer_reflexive_candidate (
candidate->password = g_strdup(local->password);
}
/* step: link to the base candidate+socket */
candidate->sockptr = base_socket;
candidate->base_addr = base_socket->addr;
result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate);
if (result != TRUE) {
/* error: memory allocation, or duplicate candidate */
......@@ -796,6 +807,7 @@ NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
else
candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
}
candidate->sockptr = nicesock;
candidate->stream_id = stream->id;
candidate->component_id = component->id;
......@@ -849,7 +861,6 @@ NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
candidate->password = g_strdup(remote->password);
}
candidate->sockptr = NULL; /* not stored for remote candidates */
/* note: candidate username and password are left NULL as stream
level ufrag/password are used */
......
......@@ -42,7 +42,8 @@ check_PROGRAMS = \
test-thread \
test-dribble \
test-new-dribble \
test-tcp
test-tcp \
test-icetcp
dist_check_SCRIPTS = \
check-test-fullmode-with-stun.sh \
......@@ -102,6 +103,8 @@ test_new_dribble_LDADD = $(COMMON_LDADD)
test_tcp_LDADD = $(COMMON_LDADD)
test_icetcp_LDADD = $(COMMON_LDADD)
all-local:
chmod a+x $(srcdir)/check-test-fullmode-with-stun.sh
chmod a+x $(srcdir)/test-pseudotcp-random.sh
......@@ -857,6 +857,10 @@ int main (void)
NICE_COMPATIBILITY);
#endif
g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL);
g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL);
nice_agent_set_software (lagent, "Test-fullmode, Left Agent");
nice_agent_set_software (ragent, "Test-fullmode, Right Agent");
......
This diff is collapsed.
......@@ -744,6 +744,9 @@ int main(void)
lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL);
g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL);
g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
......
......@@ -414,6 +414,8 @@ int main (void)
/* step: create the agents L and R */
lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245);
ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245);
g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL);
g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL);
/* step: add a timer to catch state changes triggered by signals */
......
......@@ -69,6 +69,7 @@ main (void)
nice_address_set_port (&addr_remote, 2345);
agent = nice_agent_new ( NULL, NICE_COMPATIBILITY_RFC5245);
g_object_set (G_OBJECT (agent), "ice-tcp", FALSE, NULL);
g_assert (agent->local_addresses == NULL);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment