Add support for ICE-TCP
authorYouness Alaoui <youness.alaoui@collabora.co.uk>
Wed, 16 Apr 2014 22:51:54 +0000 (18:51 -0400)
committerOlivier CrĂȘte <olivier.crete@collabora.com>
Sat, 17 May 2014 04:22:36 +0000 (00:22 -0400)
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

.gitignore
agent/agent-priv.h
agent/agent.c
agent/conncheck.c
agent/discovery.c
tests/Makefile.am
tests/test-fullmode.c
tests/test-icetcp.c [new file with mode: 0644]
tests/test-new-dribble.c
tests/test-restart.c
tests/test.c

index 20ce7e0..665be66 100644 (file)
@@ -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
index 8495b24..1c535ae 100644 (file)
@@ -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 */
 };
 
index 45ac302..7d35c24 100644 (file)
@@ -106,7 +106,9 @@ enum
   PROP_PROXY_PASSWORD,
   PROP_UPNP,
   PROP_UPNP_TIMEOUT,
-  PROP_RELIABLE
+  PROP_RELIABLE,
+  PROP_ICE_UDP,
+  PROP_ICE_TCP,
 };
 
 
@@ -582,6 +584,20 @@ nice_agent_class_init (NiceAgentClass *klass)
        FALSE,
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+   g_object_class_install_property (gobject_class, PROP_ICE_UDP,
+      g_param_spec_boolean (
+        "ice-udp",
+        "Use ICE-UDP",
+        "Use ICE-UDP specification to generate UDP candidates",
+        TRUE, /* use ice-udp by default */
+        G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class, PROP_ICE_TCP,
+      g_param_spec_boolean (
+        "ice-tcp",
+        "Use ICE-TCP",
+        "Use ICE-TCP specification to generate TCP candidates",
+        TRUE, /* use ice-tcp by default */
+        G_PARAM_READWRITE));
   /* install signals */
 
   /**
@@ -807,6 +823,8 @@ nice_agent_init (NiceAgent *agent)
 
   agent->compatibility = NICE_COMPATIBILITY_RFC5245;
   agent->reliable = FALSE;
+  agent->use_ice_udp = TRUE;
+  agent->use_ice_tcp = TRUE;
 
   stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
       STUN_COMPATIBILITY_RFC5389,
@@ -932,6 +950,14 @@ nice_agent_get_property (
       g_value_set_boolean (value, agent->reliable);
       break;
 
+    case PROP_ICE_UDP:
+      g_value_set_boolean (value, agent->use_ice_udp);
+      break;
+
+    case PROP_ICE_TCP:
+      g_value_set_boolean (value, agent->use_ice_tcp);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -1062,6 +1088,17 @@ nice_agent_set_property (
       agent->reliable = g_value_get_boolean (value);
       break;
 
+      /* Don't allow ice-udp and ice-tcp to be disabled at the same time */
+    case PROP_ICE_UDP:
+      if (agent->use_ice_tcp == TRUE || g_value_get_boolean (value) == TRUE)
+        agent->use_ice_udp = g_value_get_boolean (value);
+      break;
+
+    case PROP_ICE_TCP:
+      if (agent->use_ice_udp == TRUE || g_value_get_boolean (value) == TRUE)
+        agent->use_ice_tcp = g_value_get_boolean (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -1821,6 +1858,10 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
   cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
 
   if (turn->type ==  NICE_RELAY_TYPE_TURN_UDP) {
+    if (agent->use_ice_udp == FALSE) {
+      g_slice_free (CandidateDiscovery, cdisco);
+      return;
+    }
     if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
       NiceAddress addr = nicesock->addr;
       NiceSocket *new_socket;
@@ -1850,7 +1891,15 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
         agent->compatibility == NICE_COMPATIBILITY_OC2007R2)
       reliable_tcp = TRUE;
 
+    /* Ignore tcp candidates if we disabled ice-tcp */
+    if ((agent->use_ice_udp == FALSE && reliable_tcp == FALSE) ||
+        (agent->use_ice_tcp == FALSE && reliable_tcp == TRUE)) {
+      g_slice_free (CandidateDiscovery, cdisco);
+      return;
+    }
     nicesock = NULL;
+
+    /* TODO: add support for turn-tcp RFC 6062 */
     if (agent->proxy_type != NICE_PROXY_TYPE_NONE &&
         agent->proxy_ip != NULL &&
         nice_address_set_from_string (&proxy_server, agent->proxy_ip)) {
@@ -2273,81 +2322,111 @@ nice_agent_gather_candidates (
 
     for (cid = 1; cid <= stream->n_components; cid++) {
       Component *component = stream_find_component_by_id (stream, cid);
-      guint current_port;
-      guint start_port;
+      enum {
+        ADD_HOST_MIN = 0,
+        ADD_HOST_UDP = ADD_HOST_MIN,
+        ADD_HOST_TCP_ACTIVE,
+        ADD_HOST_TCP_PASSIVE,
+        ADD_HOST_MAX = ADD_HOST_TCP_PASSIVE
+      } add_type;
 
       if (component == NULL)
         continue;
 
-      start_port = component->min_port;
-      if(component->min_port != 0) {
-        start_port = nice_rng_generate_int(agent->rng, component->min_port, component->max_port+1);
-      }
-      current_port = start_port;
-
-      host_candidate = NULL;
-      while (host_candidate == NULL) {
-        nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
-        nice_address_set_port (addr, current_port);
-        host_candidate = discovery_add_local_host_candidate (agent, stream->id,
-            cid, addr, NICE_CANDIDATE_TRANSPORT_UDP);
-        if (current_port > 0)
-          current_port++;
-        if (current_port > component->max_port) current_port = component->min_port;
-        if (current_port == 0 || current_port == start_port)
-          break;
-      }
-      nice_address_set_port (addr, 0);
-
-      if (!host_candidate) {
-        if (nice_debug_is_enabled ()) {
-          gchar ip[NICE_ADDRESS_STRING_LEN];
-          nice_address_to_string (addr, ip);
-          nice_debug ("Agent %p: Unable to add local host candidate %s for"
-              " s%d:%d. Invalid interface?", agent, ip, stream->id,
-              component->id);
+      for (add_type = ADD_HOST_MIN; add_type <= ADD_HOST_MAX; add_type++) {
+        NiceCandidateTransport transport;
+        guint current_port;
+        guint start_port;
+
+        if ((agent->use_ice_udp == FALSE && add_type == ADD_HOST_UDP) ||
+            (agent->use_ice_tcp == FALSE && add_type != ADD_HOST_UDP))
+          continue;
+
+        switch (add_type) {
+          default:
+          case ADD_HOST_UDP:
+            transport = NICE_CANDIDATE_TRANSPORT_UDP;
+            break;
+          case ADD_HOST_TCP_ACTIVE:
+            transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
+            break;
+          case ADD_HOST_TCP_PASSIVE:
+            transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
+            break;
+        }
+
+        start_port = component->min_port;
+        if(component->min_port != 0) {
+          start_port = nice_rng_generate_int(agent->rng, component->min_port, component->max_port+1);
+        }
+        current_port = start_port;
+
+        host_candidate = NULL;
+        while (host_candidate == NULL) {
+          nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
+          nice_address_set_port (addr, current_port);
+          host_candidate = discovery_add_local_host_candidate (agent, stream->id,
+              cid, addr, transport);
+          if (current_port > 0)
+            current_port++;
+          if (current_port > component->max_port) current_port = component->min_port;
+          if (current_port == 0 || current_port == start_port)
+            break;
+        }
+        nice_address_set_port (addr, 0);
+
+        if (!host_candidate) {
+          if (nice_debug_is_enabled ()) {
+            gchar ip[NICE_ADDRESS_STRING_LEN];
+            nice_address_to_string (addr, ip);
+            nice_debug ("Agent %p: Unable to add local host candidate %s for"
+                " s%d:%d. Invalid interface?", agent, ip, stream->id,
+                component->id);
+          }
+          ret = FALSE;
+          goto error;
         }
-        ret = FALSE;
-        goto error;
-      }
 
 #ifdef HAVE_GUPNP
-      if (agent->upnp_enabled) {
-        NiceAddress *base_addr = nice_address_dup (&host_candidate->base_addr);
-        nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
-            nice_address_get_port (base_addr));
-        gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
-            0, local_ip, nice_address_get_port (base_addr),
-            0, PACKAGE_STRING);
-        agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr);
+        if (agent->upnp_enabled) {
+          NiceAddress *base_addr = nice_address_dup (&host_candidate->base_addr);
+          nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
+              nice_address_get_port (base_addr));
+          gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp),
+              transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "TCP",
+              0, local_ip, nice_address_get_port (base_addr),
+              0, PACKAGE_STRING);
+          agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr);
       }
 #endif
 
-      if (agent->full_mode &&
-          agent->stun_server_ip) {
-        NiceAddress stun_server;
-        if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
-          nice_address_set_port (&stun_server, agent->stun_server_port);
-
-          priv_add_new_candidate_discovery_stun (agent,
-              host_candidate->sockptr,
-              stun_server,
-              stream,
-              cid);
+        /* TODO: Add server-reflexive support for TCP candidates */
+        if (agent->full_mode && agent->stun_server_ip &&
+            transport == NICE_CANDIDATE_TRANSPORT_UDP) {
+          NiceAddress stun_server;
+          if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
+            nice_address_set_port (&stun_server, agent->stun_server_port);
+
+            priv_add_new_candidate_discovery_stun (agent,
+                host_candidate->sockptr,
+                stun_server,
+                stream,
+                cid);
+          }
         }
-      }
 
-      if (agent->full_mode && component) {
-        GList *item;
+        if (agent->full_mode && component) {
+          GList *item;
 
-        for (item = component->turn_servers; item; item = item->next) {
-          TurnServer *turn = item->data;
+          for (item = component->turn_servers; item; item = item->next) {
+            TurnServer *turn = item->data;
 
-          priv_add_new_candidate_discovery_turn (agent,
-              host_candidate->sockptr,
-              turn,
-              stream,
-              cid);
+            priv_add_new_candidate_discovery_turn (agent,
+                host_candidate->sockptr,
+                turn,
+                stream,
+                cid);
+          }
         }
       }
     }
@@ -2827,77 +2906,91 @@ agent_recv_message_unlocked (
       }
       g_free (local_bufs);
     } else {
-      /* In the case of a real ICE-TCP connection, we can use the socket as a
-       * bytestream and do the read here with caching of data being read
-       */
-      gssize available = g_socket_get_available_bytes (nicesock->fileno);
+      if (nicesock->type == NICE_SOCKET_TYPE_TCP_PASSIVE) {
+        NiceSocket *new_socket;
+
+        /* Passive candidates when readable should accept and create a new
+         * socket. When established, the connchecks will create a peer reflexive
+         * candidate for it */
+        new_socket = nice_tcp_passive_socket_accept (nicesock);
+        if (new_socket) {
+          _priv_set_socket_tos (agent, new_socket, stream->tos);
+          component_attach_socket (component, new_socket);
+        }
+        retval = 0;
+      } else {
+        /* In the case of a real ICE-TCP connection, we can use the socket as a
+         * bytestream and do the read here with caching of data being read
+         */
+        gssize available = g_socket_get_available_bytes (nicesock->fileno);
+
+        /* TODO: Support bytestream reads */
+        message->length = 0;
+        if (available <= 0) {
+          retval = available;
+        } else if (agent->rfc4571_expecting_length == 0) {
+          if ((gsize) available >= sizeof(guint16)) {
+            guint16 rfc4571_frame;
+            GInputVector local_buf = { &rfc4571_frame, sizeof(guint16)};
+            NiceInputMessage local_message = { &local_buf, 1, message->from, 0};
 
-      /* TODO: Support bytestream reads */
-      message->length = 0;
-      if (available <= 0) {
-        retval = available;
-      } else if (agent->rfc4571_expecting_length == 0) {
-        if ((gsize) available >= sizeof(guint16)) {
-          guint16 rfc4571_frame;
-          GInputVector local_buf = { &rfc4571_frame, sizeof(guint16)};
-          NiceInputMessage local_message = { &local_buf, 1, message->from, 0};
+            retval = nice_socket_recv_messages (nicesock, &local_message, 1);
+            if (retval == 1) {
+              agent->rfc4571_expecting_length = ntohs (rfc4571_frame);
+              available = g_socket_get_available_bytes (nicesock->fileno);
+            }
+          } else {
+            retval = 0;
+          }
+        }
+        if (agent->rfc4571_expecting_length > 0 &&
+            available >= agent->rfc4571_expecting_length) {
+          GInputVector *local_bufs;
+          NiceInputMessage local_message;
+          gsize off;
+          guint n_bufs = 0;
+          guint i;
 
+          /* Count the number of buffers. */
+          if (message->n_buffers == -1) {
+            for (i = 0; message->buffers[i].buffer != NULL; i++)
+              n_bufs++;
+          } else {
+            n_bufs = message->n_buffers;
+          }
+
+          local_bufs = g_malloc_n (n_bufs, sizeof (GInputVector));
+          local_message.buffers = local_bufs;
+          local_message.from = message->from;
+          local_message.length = 0;
+          local_message.n_buffers = 0;
+
+          /* Only read up to the expected number of bytes in the frame */
+          off = 0;
+          for (i = 0; i < n_bufs; i++) {
+            if (message->buffers[i].size < agent->rfc4571_expecting_length - off) {
+              local_bufs[i].buffer = message->buffers[i].buffer;
+              local_bufs[i].size = message->buffers[i].size;
+              local_message.n_buffers++;
+              off += message->buffers[i].size;
+            } else {
+              local_bufs[i].buffer = message->buffers[i].buffer;
+              local_bufs[i].size = MIN (message->buffers[i].size,
+                  agent->rfc4571_expecting_length - off);
+              local_message.n_buffers++;
+              off += local_bufs[i].size;
+            }
+          }
           retval = nice_socket_recv_messages (nicesock, &local_message, 1);
           if (retval == 1) {
-            agent->rfc4571_expecting_length = ntohs (rfc4571_frame);
-            available = g_socket_get_available_bytes (nicesock->fileno);
+            message->length = local_message.length;
+            agent->rfc4571_expecting_length -= local_message.length;
           }
+          g_free (local_bufs);
         } else {
           retval = 0;
         }
       }
-      if (agent->rfc4571_expecting_length > 0 &&
-          available >= agent->rfc4571_expecting_length) {
-        GInputVector *local_bufs;
-        NiceInputMessage local_message;
-        gsize off;
-        guint n_bufs = 0;
-        guint i;
-
-        /* Count the number of buffers. */
-        if (message->n_buffers == -1) {
-          for (i = 0; message->buffers[i].buffer != NULL; i++)
-            n_bufs++;
-        } else {
-          n_bufs = message->n_buffers;
-        }
-
-        local_bufs = g_malloc_n (n_bufs, sizeof (GInputVector));
-        local_message.buffers = local_bufs;
-        local_message.from = message->from;
-        local_message.length = 0;
-        local_message.n_buffers = 0;
-
-        /* Only read up to the expected number of bytes in the frame */
-        off = 0;
-        for (i = 0; i < n_bufs; i++) {
-          if (message->buffers[i].size < agent->rfc4571_expecting_length - off) {
-            local_bufs[i].buffer = message->buffers[i].buffer;
-            local_bufs[i].size = message->buffers[i].size;
-            local_message.n_buffers++;
-            off += message->buffers[i].size;
-          } else {
-            local_bufs[i].buffer = message->buffers[i].buffer;
-            local_bufs[i].size = MIN (message->buffers[i].size,
-                agent->rfc4571_expecting_length - off);
-            local_message.n_buffers++;
-            off += local_bufs[i].size;
-          }
-        }
-        retval = nice_socket_recv_messages (nicesock, &local_message, 1);
-        if (retval == 1) {
-          message->length = local_message.length;
-          agent->rfc4571_expecting_length -= local_message.length;
-        }
-        g_free (local_bufs);
-      } else {
-        retval = 0;
-      }
     }
   } else {
     retval = nice_socket_recv_messages (nicesock, message, 1);
index c0cb307..ee0b661 100644 (file)
@@ -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,
index e39c2f9..42666d7 100644 (file)
@@ -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 */
 
index 5cd765f..19deff5 100644 (file)
@@ -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
index 7de33d0..03778f7 100644 (file)
@@ -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");
 
diff --git a/tests/test-icetcp.c b/tests/test-icetcp.c
new file mode 100644 (file)
index 0000000..8be28ba
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * This file is part of the Nice GLib ICE library.
+ *
+ * Unit test for ICE full-mode related features.
+ *
+ * (C) 2007 Nokia Corporation. All rights reserved.
+ *  Contact: Kai Vehmanen
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Nice GLib ICE library.
+ *
+ * The Initial Developers of the Original Code are Collabora Ltd and Nokia
+ * Corporation. All Rights Reserved.
+ *
+ * Contributors:
+ *   Kai Vehmanen, Nokia
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
+ * case the provisions of LGPL are applicable instead of those above. If you
+ * wish to allow use of your version of this file only under the terms of the
+ * LGPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replace
+ * them with the notice and other provisions required by the LGPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the LGPL.
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "agent.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
+static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
+static guint global_components_ready = 0;
+static guint global_components_ready_exit = 0;
+static guint global_components_failed = 0;
+static guint global_components_failed_exit = 0;
+static GMainLoop *global_mainloop = NULL;
+static gboolean global_lagent_gathering_done = FALSE;
+static gboolean global_ragent_gathering_done = FALSE;
+static gboolean global_lagent_ibr_received = FALSE;
+static gboolean global_ragent_ibr_received = FALSE;
+static int global_lagent_cands = 0;
+static int global_ragent_cands = 0;
+static gint global_ragent_read = 0;
+static guint global_exit_when_ibr_received = 0;
+
+static void priv_print_global_status (void)
+{
+  g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done);
+  g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]);
+  g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]);
+  g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands);
+}
+
+static gboolean timer_cb (gpointer pointer)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, pointer);
+
+  /* signal status via a global variable */
+
+  /* note: should not be reached, abort */
+  g_error ("ERROR: test has got stuck, aborting...");
+
+  return FALSE;
+}
+
+static void cb_writable (NiceAgent*agent, guint stream_id, guint component_id)
+{
+    g_debug ("Transport is now writable, stopping mainloop");
+    g_main_loop_quit (global_mainloop);
+}
+
+static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, user_data);
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent; (void)stream_id; (void)component_id; (void)buf;
+
+  /*
+   * Lets ignore stun packets that got through
+   */
+  if (len < 8)
+    return;
+  if (strncmp ("12345678", buf, 8))
+    return;
+
+  if (GPOINTER_TO_UINT (user_data) == 2) {
+    g_debug ("right agent received %d bytes, stopping mainloop", len);
+    global_ragent_read = len;
+    g_main_loop_quit (global_mainloop);
+  }
+}
+
+static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
+
+  if (GPOINTER_TO_UINT (data) == 1)
+    global_lagent_gathering_done = TRUE;
+  else if (GPOINTER_TO_UINT (data) == 2)
+    global_ragent_gathering_done = TRUE;
+
+  if (global_lagent_gathering_done &&
+      global_ragent_gathering_done)
+    g_main_loop_quit (global_mainloop);
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent;
+}
+
+static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
+
+  if (GPOINTER_TO_UINT (data) == 1)
+    global_lagent_state[component_id - 1] = state;
+  else if (GPOINTER_TO_UINT (data) == 2)
+    global_ragent_state[component_id - 1] = state;
+  
+  if (state == NICE_COMPONENT_STATE_READY)
+    global_components_ready++;
+  if (state == NICE_COMPONENT_STATE_FAILED)
+    global_components_failed++;
+
+  g_debug ("test-icetcp: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit);
+  g_debug ("test-icetcp: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit);
+
+  /* signal status via a global variable */
+  if (global_components_ready == global_components_ready_exit &&
+      global_components_failed == global_components_failed_exit) {
+    g_debug ("Components ready/failed achieved. Stopping mailoop");
+    g_main_loop_quit (global_mainloop); 
+    return;
+  }
+
+#if 0
+  /* signal status via a global variable */
+  if (global_components_failed == global_components_failed_exit) {
+    g_main_loop_quit (global_mainloop); 
+    return;
+  }
+#endif
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent; (void)stream_id; (void)data; (void)component_id;
+}
+
+static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, 
+                                gchar *lfoundation, gchar* rfoundation, gpointer data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
+
+  if (GPOINTER_TO_UINT (data) == 1)
+    ++global_lagent_cands;
+  else if (GPOINTER_TO_UINT (data) == 2)
+    ++global_ragent_cands;
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation;
+}
+
+static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, 
+                            gchar *foundation, gpointer data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation;
+}
+
+static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data)
+{
+  g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
+
+  if (GPOINTER_TO_UINT (data) == 1)
+    global_lagent_ibr_received = TRUE;
+  else if (GPOINTER_TO_UINT (data) == 2)
+    global_ragent_ibr_received = TRUE;
+
+  if (global_exit_when_ibr_received) {
+    g_debug ("Received initial binding request. Stopping mailoop");
+    g_main_loop_quit (global_mainloop);
+  }
+
+  /* XXX: dear compiler, these are for you: */
+  (void)agent; (void)stream_id; (void)data;
+}
+
+static void set_candidates (NiceAgent *from, guint from_stream,
+    NiceAgent *to, guint to_stream, guint component)
+{
+  GSList *cands = NULL, *i;
+
+  cands = nice_agent_get_local_candidates (from, from_stream, component);
+
+ restart:
+  for (i = cands; i; i = i->next) {
+    NiceCandidate *cand = i->data;
+    if (cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
+      cands = g_slist_remove (cands, cand);
+      nice_candidate_free (cand);
+      goto restart;
+    }
+  }
+
+
+  nice_agent_set_remote_candidates (to, to_stream, component, cands);
+
+  for (i = cands; i; i = i->next)
+    nice_candidate_free ((NiceCandidate *) i->data);
+  g_slist_free (cands);
+}
+
+static void set_credentials (NiceAgent *lagent, guint lstream,
+    NiceAgent *ragent, guint rstream)
+{
+  gchar *ufrag = NULL, *password = NULL;
+
+  nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password);
+  nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
+  g_free (ufrag);
+  g_free (password);
+  nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password);
+  nice_agent_set_remote_credentials (lagent, lstream, ufrag, password);
+  g_free (ufrag);
+  g_free (password);
+}
+
+static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed)
+{
+  guint ls_id, rs_id;
+  gint ret;
+
+  /* XXX: dear compiler, this is for you */
+  (void)baseaddr;
+
+  /* step: initialize variables modified by the callbacks */
+  global_components_ready = 0;
+  global_components_ready_exit = ready;
+  global_components_failed = 0;
+  global_components_failed_exit = failed;
+  global_lagent_gathering_done = FALSE;
+  global_ragent_gathering_done = FALSE;
+  global_lagent_ibr_received =
+    global_ragent_ibr_received = FALSE;
+  global_lagent_cands =
+    global_ragent_cands = 0;
+
+  g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
+  g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
+
+  /* step: add one stream, with RTP+RTCP components, to each agent */
+  ls_id = nice_agent_add_stream (lagent, 2);
+
+  rs_id = nice_agent_add_stream (ragent, 2);
+  g_assert (ls_id > 0);
+  g_assert (rs_id > 0);
+
+  /* Gather candidates */
+  g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE);
+  g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE);
+
+  {
+    GSList *cands = NULL, *i;
+    NiceCandidate *cand = NULL;
+
+    cands = nice_agent_get_local_candidates (lagent, ls_id, 1);
+    g_assert (g_slist_length (cands) == 2);
+    cand = cands->data;
+    g_assert (cand->type == NICE_CANDIDATE_TYPE_HOST);
+    g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
+              cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE);
+    cand = cands->next->data;
+    g_assert (cand->type == NICE_CANDIDATE_TYPE_HOST);
+    g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
+              cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE);
+    for (i = cands; i; i = i->next)
+      nice_candidate_free ((NiceCandidate *) i->data);
+    g_slist_free (cands);
+  }
+
+  /* step: attach to mainloop (needed to register the fds) */
+  nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
+      g_main_loop_get_context (global_mainloop), cb_nice_recv,
+      GUINT_TO_POINTER (1));
+  nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP,
+      g_main_loop_get_context (global_mainloop), cb_nice_recv,
+      GUINT_TO_POINTER (1));
+  nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
+      g_main_loop_get_context (global_mainloop), cb_nice_recv,
+      GUINT_TO_POINTER (2));
+  nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP,
+      g_main_loop_get_context (global_mainloop), cb_nice_recv,
+      GUINT_TO_POINTER (2));
+
+  /* step: run mainloop until local candidates are ready
+   *       (see timer_cb() above) */
+  if (global_lagent_gathering_done != TRUE ||
+      global_ragent_gathering_done != TRUE) {
+    g_debug ("test-icetcp: Added streams, running mainloop until 'candidate-gathering-done'...");
+    g_main_loop_run (global_mainloop);
+    g_assert (global_lagent_gathering_done == TRUE);
+    g_assert (global_ragent_gathering_done == TRUE);
+  }
+
+  set_credentials (lagent, ls_id, ragent, rs_id);
+
+  /* step: pass the remote candidates to agents  */
+  set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP);
+  set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP);
+  set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP);
+  set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP);
+
+  g_debug ("test-icetcp: Set properties, next running mainloop until connectivity checks succeed...");
+
+  /* step: run the mainloop until connectivity checks succeed
+   *       (see timer_cb() above) */
+  g_main_loop_run (global_mainloop);
+
+  /* note: verify that STUN binding requests were sent */
+  g_assert (global_lagent_ibr_received == TRUE);
+  g_assert (global_ragent_ibr_received == TRUE);
+
+  /* note: test payload send and receive */
+  global_ragent_read = 0;
+  ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678");
+  if (ret == -1)
+  {
+    gboolean reliable = FALSE;
+    g_object_get (G_OBJECT (lagent), "reliable", &reliable, NULL);
+    g_debug ("Sending data returned -1 in %s mode", reliable?"Reliable":"Non-reliable");
+    if (reliable) {
+      gulong signal_handler;
+      signal_handler = g_signal_connect (G_OBJECT (lagent),
+          "reliable-transport-writable", G_CALLBACK (cb_writable), NULL);
+      g_debug ("Running mainloop until transport is writable");
+      g_main_loop_run (global_mainloop);
+      g_signal_handler_disconnect(G_OBJECT (lagent), signal_handler);
+
+      ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678");
+    }
+  }
+  g_debug ("Sent %d bytes", ret);
+  g_assert (ret == 16);
+  g_main_loop_run (global_mainloop);
+  g_assert (global_ragent_read == 16);
+
+  g_debug ("test-icetcp: Ran mainloop, removing streams...");
+
+  /* step: clean up resources and exit */
+
+  nice_agent_remove_stream (lagent, ls_id);
+  nice_agent_remove_stream (ragent, rs_id);
+
+  return 0;
+}
+
+int main (void)
+{
+  NiceAgent *lagent, *ragent;      /* agent's L and R */
+  NiceAddress baseaddr;
+  int result;
+  guint timer_id;
+
+#ifdef G_OS_WIN32
+  WSADATA w;
+
+  WSAStartup(0x0202, &w);
+#endif
+  g_type_init ();
+#if !GLIB_CHECK_VERSION(2,31,8)
+  g_thread_init(NULL);
+#endif
+
+  global_mainloop = g_main_loop_new (NULL, FALSE);
+
+  /* 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-udp", FALSE,  NULL);
+  g_object_set (G_OBJECT (ragent), "ice-udp", FALSE,  NULL);
+  nice_agent_set_software (lagent, "Test-icetcp, Left Agent");
+  nice_agent_set_software (ragent, "Test-icetcp, Right Agent");
+
+  /* step: add a timer to catch state changes triggered by signals */
+  timer_id = g_timeout_add (30000, timer_cb, NULL);
+
+  /* step: specify which local interface to use */
+  if (!nice_address_set_from_string (&baseaddr, "127.0.0.1"))
+    g_assert_not_reached ();
+  nice_agent_add_local_address (lagent, &baseaddr);
+  nice_agent_add_local_address (ragent, &baseaddr);
+
+  g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
+      G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
+  g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
+      G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2));
+  g_signal_connect (G_OBJECT (lagent), "component-state-changed",
+      G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1));
+  g_signal_connect (G_OBJECT (ragent), "component-state-changed",
+      G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2));
+  g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
+      G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
+  g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
+      G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2));
+  g_signal_connect (G_OBJECT (lagent), "new-candidate",
+      G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1));
+  g_signal_connect (G_OBJECT (ragent), "new-candidate",
+      G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2));
+  g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received",
+      G_CALLBACK (cb_initial_binding_request_received),
+      GUINT_TO_POINTER (1));
+  g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received",
+      G_CALLBACK (cb_initial_binding_request_received),
+      GUINT_TO_POINTER (2));
+
+  /* step: run test the first time */
+  g_debug ("test-icetcp: TEST STARTS / running test for the 1st time");
+  result = run_full_test (lagent, ragent, &baseaddr, 4 ,0);
+  priv_print_global_status ();
+  g_assert (result == 0);
+  g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_lagent_state[1] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_ragent_state[0] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_ragent_state[1] == NICE_COMPONENT_STATE_READY);
+  /* note: verify that correct number of local candidates were reported */
+  g_assert (global_lagent_cands >= 2);
+  g_assert (global_ragent_cands >= 2);
+
+
+  /* step: run test again without unref'ing agents */
+  g_debug ("test-icetcp: TEST STARTS / running test for the 2nd time");
+  result = run_full_test (lagent, ragent, &baseaddr, 4, 0);
+  priv_print_global_status ();
+  g_assert (result == 0);
+  g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_lagent_state[1] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_ragent_state[0] == NICE_COMPONENT_STATE_READY);
+  g_assert (global_ragent_state[1] == NICE_COMPONENT_STATE_READY);
+  /* note: verify that correct number of local candidates were reported */
+  g_assert (global_lagent_cands >= 2);
+  g_assert (global_ragent_cands >= 2);
+
+  g_object_unref (lagent);
+  g_object_unref (ragent);
+
+  g_main_loop_unref (global_mainloop);
+  global_mainloop = NULL;
+
+  g_source_remove (timer_id);
+#ifdef G_OS_WIN32
+  WSACleanup();
+#endif
+  return result;
+}
index b00e6ab..59f8b13 100644 (file)
@@ -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);
 
index 8f8fa8d..c7f2f25 100644 (file)
@@ -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 */
index edef196..febf065 100644 (file)
@@ -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);