media: simplify conditional compilation of TCP support
[siplcs.git] / contrib / media-patches / libnice_msoc_tcp_relay.patch
blob71ac479276e61e074e072012f968f9d174922ed3
1 From c8fc05fa4b90f327375957a8f1525a11449f3492 Mon Sep 17 00:00:00 2001
2 From: Jakub Adam <jakub.adam@ktknet.cz>
3 Date: Fri, 12 Aug 2011 18:59:37 +0200
4 Subject: [PATCH] Support for TCP relay candidates in MSOC compatibility modes
6 ---
7 agent/agent.c | 193 +++++++++++++++++++++++++++-----------
8 agent/agent.h | 52 ++++++++++
9 agent/candidate.c | 58 ++++++++++++
10 agent/candidate.h | 29 ++++++-
11 agent/conncheck.c | 262 ++++++++++++++++++++++++++++++++++++++--------------
12 agent/conncheck.h | 1 +
13 agent/discovery.c | 79 +++++++++++++---
14 agent/discovery.h | 2 +
15 agent/stream.c | 14 +++
16 agent/stream.h | 8 ++
17 nice/libnice.sym | 2 +
18 socket/pseudossl.c | 61 +++++++++++-
19 socket/tcp-turn.c | 48 +++++++++-
20 socket/turn.c | 9 ++
21 stun/stunmessage.c | 10 ++-
22 stun/stunmessage.h | 3 +
23 stun/usages/turn.c | 22 ++++-
24 17 files changed, 703 insertions(+), 150 deletions(-)
26 diff --git a/agent/agent.c b/agent/agent.c
27 index 8eedc0c..140718e 100644
28 --- a/agent/agent.c
29 +++ b/agent/agent.c
30 @@ -65,6 +65,7 @@
31 #include "component.h"
32 #include "conncheck.h"
33 #include "discovery.h"
34 +#include "utils.h"
35 #include "agent.h"
36 #include "agent-priv.h"
37 #include "agent-signals-marshal.h"
38 @@ -1413,8 +1414,10 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
39 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &turn->server);
40 _priv_set_socket_tos (agent, socket, stream->tos);
42 - if (turn->type == NICE_RELAY_TYPE_TURN_TLS &&
43 - agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
44 + if ((turn->type == NICE_RELAY_TYPE_TURN_TLS &&
45 + agent->compatibility == NICE_COMPATIBILITY_GOOGLE) ||
46 + agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
47 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
48 socket = nice_pseudossl_socket_new (agent, socket);
50 cdisco->nicesock = nice_tcp_turn_socket_new (agent, socket,
51 @@ -1637,6 +1640,7 @@ static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
52 stream->id,
53 component->id,
54 &externaddr,
55 + NICE_CANDIDATE_TRANSPORT_UDP,
56 local_candidate->sockptr);
57 goto end;
59 @@ -1771,7 +1775,7 @@ nice_agent_gather_candidates (
60 /* generate a local host candidate for each local address */
61 for (i = local_addresses; i; i = i->next) {
62 NiceAddress *addr = i->data;
63 - NiceCandidate *host_candidate;
64 + NiceCandidate *host_candidate = NULL;
66 #ifdef HAVE_GUPNP
67 gchar local_ip[NICE_ADDRESS_STRING_LEN];
68 @@ -1789,51 +1793,53 @@ nice_agent_gather_candidates (
69 continue;
72 - host_candidate = NULL;
73 - while (host_candidate == NULL) {
74 - nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
75 - nice_address_set_port (addr, current_port);
76 - host_candidate = discovery_add_local_host_candidate (agent, stream->id,
77 - n + 1, addr);
78 - if (current_port > 0)
79 - current_port++;
80 - if (current_port == 0 || current_port > component->max_port)
81 - break;
82 - }
83 - nice_address_set_port (addr, 0);
85 - if (!host_candidate) {
86 - gchar ip[NICE_ADDRESS_STRING_LEN];
87 - nice_address_to_string (addr, ip);
88 - nice_debug ("Agent %p: Unable to add local host candidate %s for s%d:%d"
89 - ". Invalid interface?", agent, ip, stream->id, component->id);
90 - ret = FALSE;
91 - goto error;
92 - }
93 + if (stream->allowed_transports & NICE_CANDIDATE_TRANSPORT_UDP) {
94 + host_candidate = NULL;
95 + while (host_candidate == NULL) {
96 + nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
97 + nice_address_set_port (addr, current_port);
98 + host_candidate = discovery_add_local_host_candidate (agent, stream->id,
99 + n + 1, addr);
100 + if (current_port > 0)
101 + current_port++;
102 + if (current_port == 0 || current_port > component->max_port)
103 + break;
105 + nice_address_set_port (addr, 0);
107 + if (!host_candidate) {
108 + gchar ip[NICE_ADDRESS_STRING_LEN];
109 + nice_address_to_string (addr, ip);
110 + nice_debug ("Agent %p: Unable to add local host candidate %s for s%d:%d"
111 + ". Invalid interface?", agent, ip, stream->id, component->id);
112 + ret = FALSE;
113 + goto error;
116 #ifdef HAVE_GUPNP
117 - if (agent->upnp_enabled) {
118 - NiceAddress *addr = nice_address_dup (&host_candidate->base_addr);
119 - nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
120 - nice_address_get_port (&host_candidate->base_addr));
121 - gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
122 - 0, local_ip, nice_address_get_port (&host_candidate->base_addr),
123 - 0, PACKAGE_STRING);
124 - agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, addr);
126 + if (agent->upnp_enabled) {
127 + NiceAddress *addr = nice_address_dup (&host_candidate->base_addr);
128 + nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
129 + nice_address_get_port (&host_candidate->base_addr));
130 + gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
131 + 0, local_ip, nice_address_get_port (&host_candidate->base_addr),
132 + 0, PACKAGE_STRING);
133 + agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, addr);
135 #endif
137 - if (agent->full_mode &&
138 - agent->stun_server_ip) {
139 - NiceAddress stun_server;
140 - if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
141 - nice_address_set_port (&stun_server, agent->stun_server_port);
143 - priv_add_new_candidate_discovery_stun (agent,
144 - host_candidate->sockptr,
145 - stun_server,
146 - stream,
147 - n + 1);
148 + if (agent->full_mode &&
149 + agent->stun_server_ip) {
150 + NiceAddress stun_server;
151 + if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
152 + nice_address_set_port (&stun_server, agent->stun_server_port);
154 + priv_add_new_candidate_discovery_stun (agent,
155 + host_candidate->sockptr,
156 + stun_server,
157 + stream,
158 + n + 1);
163 @@ -1843,8 +1849,21 @@ nice_agent_gather_candidates (
164 for (item = component->turn_servers; item; item = item->next) {
165 TurnServer *turn = item->data;
167 + if (turn->type == NICE_RELAY_TYPE_TURN_UDP &&
168 + !(stream->allowed_transports & NICE_CANDIDATE_TRANSPORT_UDP))
169 + continue;
171 + /* When using TCP, in MSOC compatibility we allocate only one port on
172 + * TURN server per stream, as all components are multiplexed over a
173 + * single connection ([MS-ICE2] 3.1.4.8.1.3 Gathering TCP Candidates) */
174 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
175 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
176 + turn->type == NICE_RELAY_TYPE_TURN_TCP &&
177 + n > 0)
178 + continue;
180 priv_add_new_candidate_discovery_turn (agent,
181 - host_candidate->sockptr,
182 + host_candidate ? host_candidate->sockptr : NULL,
183 turn,
184 stream,
185 n + 1);
186 @@ -2207,7 +2226,8 @@ nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint compo
187 for (i = candidates; i && added >= 0; i = i->next) {
188 NiceCandidate *d = (NiceCandidate*) i->data;
190 - if (nice_address_is_valid (&d->addr) == TRUE) {
191 + if (stream_transport_is_allowed(stream, d->transport, TRUE) &&
192 + nice_address_is_valid (&d->addr) == TRUE) {
193 gboolean res =
194 priv_add_remote_candidate (agent,
195 stream_id,
196 @@ -2295,6 +2315,18 @@ _nice_agent_recv (
200 + /* Remove RFC 4571 framing from packets received by TCP */
201 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
202 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
203 + len > 2 &&
204 + nice_socket_is_reliable (socket)) {
205 + gint new_len = stun_getw((const uint8_t *)buf);
206 + if (new_len <= (len - 2)) {
207 + memmove (buf, buf + 2, new_len);
208 + len = new_len;
212 agent->media_after_tick = TRUE;
214 if (stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len,
215 @@ -2599,14 +2631,27 @@ nice_agent_g_source_cb (
216 } else if(len > 0 && agent->reliable) {
217 nice_debug ("Received data on a pseudo tcp FAILED component");
218 } else if (len > 0 && component->g_source_io_cb) {
219 - gpointer data = component->data;
220 - gint sid = stream->id;
221 - gint cid = component->id;
222 - NiceAgentRecvFunc callback = component->g_source_io_cb;
223 - /* Unlock the agent before calling the callback */
224 - agent_unlock();
225 - callback (agent, sid, cid, len, buf, data);
226 - goto done;
228 + if (stream->demultiplex_func &&
229 + (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
230 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
231 + nice_socket_is_reliable(ctx->socket)) {
233 + guint component_id = stream->demultiplex_func(buf, stream->data);
234 + component = stream_find_component_by_id(stream, component_id);
237 + if (component) {
238 + gpointer data = component->data;
239 + gint sid = stream->id;
240 + gint cid = component->id;
241 + NiceAgentRecvFunc callback = component->g_source_io_cb;
243 + /* Unlock the agent before calling the callback */
244 + agent_unlock();
245 + callback (agent, sid, cid, len, buf, data);
246 + goto done;
248 } else if (len < 0) {
249 GSource *source = ctx->source;
251 @@ -2755,6 +2800,32 @@ nice_agent_attach_recv (
254 NICEAPI_EXPORT gboolean
255 +nice_agent_attach_demultiplexer (
256 + NiceAgent *agent,
257 + guint stream_id,
258 + NiceAgentDemultiplexFunc func,
259 + gpointer data)
261 + Stream *stream;
262 + gboolean ret = FALSE;
264 + agent_lock();
266 + stream = agent_find_stream(agent, stream_id);
267 + if (!stream) {
268 + g_warning ("Could not find stream %u", stream_id);
269 + goto done;
272 + stream->demultiplex_func = func;
273 + stream->data = data;
275 + done:
276 + agent_unlock();
277 + return ret;
280 +NICEAPI_EXPORT gboolean
281 nice_agent_set_selected_pair (
282 NiceAgent *agent,
283 guint stream_id,
284 @@ -2914,6 +2985,20 @@ void nice_agent_set_stream_tos (NiceAgent *agent,
285 agent_unlock();
288 +void nice_agent_set_stream_transport (NiceAgent *agent,
289 + guint stream_id, NiceCandidateTransport transport)
291 + Stream *stream;
293 + agent_lock();
295 + stream = agent_find_stream(agent, stream_id);
296 + if (stream)
297 + stream->allowed_transports = transport;
299 + agent_unlock();
302 void nice_agent_set_software (NiceAgent *agent, const gchar *software)
304 agent_lock();
305 diff --git a/agent/agent.h b/agent/agent.h
306 index 5623258..d34b491 100644
307 --- a/agent/agent.h
308 +++ b/agent/agent.h
309 @@ -276,6 +276,19 @@ typedef void (*NiceAgentRecvFunc) (
310 NiceAgent *agent, guint stream_id, guint component_id, guint len,
311 gchar *buf, gpointer user_data);
313 +/**
314 + * NiceAgentDemultiplexFunc:
315 + * @agent: The #NiceAgent Object
316 + * @stream_id: The id of the stream
317 + * @buf: The buffer containing the data received
318 + * @user_data: The user data set in nice_agent_attach_demultiplexer()
320 + * Callback function when data is received on multiplexing connection. It should
321 + * return the id of component where the data belong. Id 0 means that function
322 + * could not decide and the data buffer is discarded.
323 + */
324 +typedef guint (*NiceAgentDemultiplexFunc) (
325 + const gchar *buf, gpointer *user_data);
328 * nice_agent_new:
329 @@ -658,6 +671,31 @@ nice_agent_attach_recv (
330 NiceAgentRecvFunc func,
331 gpointer data);
333 +/**
334 + * nice_agent_attach_demultiplexer:
335 + * @agent: The #NiceAgent Object
336 + * @stream_id: The ID of the stream
337 + * @func: The #NiceAgentDemultiplexFunc callback function
338 + * @data: User data associated with the callback
340 + * In some compatibility modes, when TCP transport is in use, data from all
341 + * components are multiplexed over single connection. This function is used to
342 + * set a callback that inspects received buffer, decides which component the
343 + * data belong to and which #NiceAgentRecvFunc should be called.
344 + * <para>
345 + * Callback is only needed in #NICE_COMPATIBILITY_OC2007 and
346 + * #NICE_COMPATIBILITY_OC2007R2 compatibility modes when TCP transport is
347 + * enabled.
348 + * </para>
350 + * Returns: %TRUE on success, %FALSE if the stream ID is invalid.
351 + */
352 +gboolean
353 +nice_agent_attach_demultiplexer (
354 + NiceAgent *agent,
355 + guint stream_id,
356 + NiceAgentDemultiplexFunc func,
357 + gpointer data);
360 * nice_agent_set_selected_pair:
361 @@ -724,6 +762,20 @@ void nice_agent_set_stream_tos (
362 gint tos);
365 +/**
366 + * nice_agent_set_stream_transport:
367 + * @agent: The #NiceAgent Object
368 + * @stream_id: The ID of the stream
369 + * @transport: OR-ed list of transports
371 + * Sets transport protocols allowed for the stream
373 + * Since: 0.2.0
374 + */
375 +void nice_agent_set_stream_transport (
376 + NiceAgent *agent,
377 + guint stream_id,
378 + NiceCandidateTransport transport);
381 * nice_agent_set_software:
382 diff --git a/agent/candidate.c b/agent/candidate.c
383 index b7636a8..c58a4c6 100644
384 --- a/agent/candidate.c
385 +++ b/agent/candidate.c
386 @@ -157,6 +157,64 @@ nice_candidate_ice_priority (const NiceCandidate *candidate)
390 + * ICE-TCP 3.2. "Prioritization" (ID-07)
391 + */
392 +guint32
393 +nice_candidate_local_priority_full (guint transport_preference,
394 + guint direction_preference, guint other_preference)
396 + return 0x1000 * transport_preference +
397 + 0x200 * direction_preference +
398 + 0x1 * other_preference;
401 +guint32
402 +nice_candidate_local_priority(const NiceCandidate *candidate)
404 + guint8 transport_preference = 0;
405 + guint8 direction_preference = 0;
407 + switch (candidate->transport)
409 + case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
410 + transport_preference = NICE_CANDIDATE_TRANSPORT_PREFERENCE_TCP;
411 + direction_preference = NICE_CANDIDATE_DIRECTION_PREFERENCE_ACTIVE;
412 + break;
413 + case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
414 + transport_preference = NICE_CANDIDATE_TRANSPORT_PREFERENCE_TCP;
415 + direction_preference = NICE_CANDIDATE_DIRECTION_PREFERENCE_PASSIVE;
416 + break;
417 + case NICE_CANDIDATE_TRANSPORT_UDP:
418 + transport_preference = NICE_CANDIDATE_TRANSPORT_PREFERENCE_UDP;
419 + break;
422 + return nice_candidate_local_priority_full(transport_preference,
423 + direction_preference, 0);
426 +guint32
427 +nice_candidate_ms_ice_priority (const NiceCandidate *candidate)
429 + guint8 type_preference = 0;
431 + switch (candidate->type)
433 + case NICE_CANDIDATE_TYPE_HOST:
434 + type_preference = NICE_CANDIDATE_TYPE_PREF_HOST; break;
435 + case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
436 + type_preference = NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE; break;
437 + case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
438 + type_preference = NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE; break;
439 + case NICE_CANDIDATE_TYPE_RELAYED:
440 + type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED; break;
443 + return nice_candidate_ice_priority_full (type_preference,
444 + nice_candidate_local_priority(candidate), candidate->component_id);
448 * Calculates the pair priority as specified in ICE
449 * sect 5.7.2. "Computing Pair Priority and Ordering Pairs" (ID-19).
451 diff --git a/agent/candidate.h b/agent/candidate.h
452 index 2eccbff..37073fb 100644
453 --- a/agent/candidate.h
454 +++ b/agent/candidate.h
455 @@ -62,6 +62,12 @@ G_BEGIN_DECLS
456 #define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100
457 #define NICE_CANDIDATE_TYPE_PREF_RELAYED 60
459 +#define NICE_CANDIDATE_TRANSPORT_PREFERENCE_UDP 15
460 +#define NICE_CANDIDATE_TRANSPORT_PREFERENCE_TCP 6
462 +#define NICE_CANDIDATE_DIRECTION_PREFERENCE_ACTIVE 5
463 +#define NICE_CANDIDATE_DIRECTION_PREFERENCE_PASSIVE 2
465 /* Max foundation size '1*32ice-char' plus terminating NULL, ICE ID-19 */
467 * NICE_CANDIDATE_MAX_FOUNDATION:
468 @@ -96,7 +102,9 @@ typedef enum
470 typedef enum
472 - NICE_CANDIDATE_TRANSPORT_UDP,
473 + NICE_CANDIDATE_TRANSPORT_UDP = 1,
474 + NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE = 2,
475 + NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE = 4,
476 } NiceCandidateTransport;
479 @@ -224,6 +232,25 @@ nice_candidate_ice_priority_full (guint type_pref, guint local_pref,
480 guint32
481 nice_candidate_ice_priority (const NiceCandidate *candidate);
483 +guint32
484 +nice_candidate_local_priority(const NiceCandidate *candidate);
486 +/**
487 + * nice_candidate_local_priority:
488 + * @transport_preference: value between 0-15
489 + * @direction_preference: value between 0-7
490 + * @other_preference: value between 0-511
492 + * Returns: local priority value computed with formula recommended in ICE-TCP
493 + * 3.2. "Prioritization" (ID-07)
494 + */
495 +guint32
496 +nice_candidate_local_priority_full (guint transport_preference,
497 + guint direction_preference, guint other_preference);
499 +guint32
500 +nice_candidate_ms_ice_priority (const NiceCandidate *candidate);
502 guint64
503 nice_candidate_pair_priority (guint32 o_prio, guint32 a_prio);
505 diff --git a/agent/conncheck.c b/agent/conncheck.c
506 index eea1009..ad2cd69 100644
507 --- a/agent/conncheck.c
508 +++ b/agent/conncheck.c
509 @@ -1094,38 +1094,49 @@ static GSList *priv_limit_conn_check_list_size (GSList *conncheck_list, guint up
510 return result;
513 +static void priv_do_update_selected_pair (NiceAgent *agent, Component *component, CandidateCheckPair *pair)
515 + nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s "
516 + "(prio:%" G_GUINT64_FORMAT ").", agent, component->id, pair->local->foundation,
517 + pair->remote->foundation, pair->priority);
519 + if (component->selected_pair.keepalive.tick_source != NULL) {
520 + g_source_destroy (component->selected_pair.keepalive.tick_source);
521 + g_source_unref (component->selected_pair.keepalive.tick_source);
522 + component->selected_pair.keepalive.tick_source = NULL;
525 + memset (&component->selected_pair, 0, sizeof(CandidatePair));
526 + component->selected_pair.local = pair->local;
527 + component->selected_pair.remote = pair->remote;
528 + component->selected_pair.priority = pair->priority;
530 + priv_conn_keepalive_tick_unlocked (agent);
532 + agent_signal_new_selected_pair (agent, pair->stream_id, component->id, pair->local->foundation, pair->remote->foundation);
536 * Changes the selected pair for the component if 'pair' is nominated
537 * and has higher priority than the currently selected pair. See
538 * ICE sect 11.1.1. "Procedures for Full Implementations" (ID-19).
540 -static gboolean priv_update_selected_pair (NiceAgent *agent, Component *component, CandidateCheckPair *pair)
541 +static void priv_update_selected_pair (NiceAgent *agent, Component *component, CandidateCheckPair *pair)
543 g_assert (component);
544 g_assert (pair);
545 if (pair->priority > component->selected_pair.priority) {
546 - nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s "
547 - "(prio:%" G_GUINT64_FORMAT ").", agent, component->id, pair->local->foundation,
548 - pair->remote->foundation, pair->priority);
550 - if (component->selected_pair.keepalive.tick_source != NULL) {
551 - g_source_destroy (component->selected_pair.keepalive.tick_source);
552 - g_source_unref (component->selected_pair.keepalive.tick_source);
553 - component->selected_pair.keepalive.tick_source = NULL;
554 + GSList *linked_pairs = pair->linked_pairs;
555 + priv_do_update_selected_pair (agent, component, pair);
557 + for (; linked_pairs; linked_pairs = linked_pairs->next) {
558 + component = NULL;
559 + pair = linked_pairs->data;
560 + agent_find_component (agent, pair->stream_id, pair->component_id, NULL, &component);
561 + if (component)
562 + priv_do_update_selected_pair(agent, component, pair);
565 - memset (&component->selected_pair, 0, sizeof(CandidatePair));
566 - component->selected_pair.local = pair->local;
567 - component->selected_pair.remote = pair->remote;
568 - component->selected_pair.priority = pair->priority;
570 - priv_conn_keepalive_tick_unlocked (agent);
572 - agent_signal_new_selected_pair (agent, pair->stream_id, component->id, pair->local->foundation, pair->remote->foundation);
576 - return TRUE;
580 @@ -1245,6 +1256,27 @@ static void priv_mark_pair_nominated (NiceAgent *agent, Stream *stream, Componen
584 +static gboolean priv_try_link_check_pair(NiceAgent *agent, Stream *stream, CandidateCheckPair *new_pair)
586 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
587 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
588 + new_pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
589 + GSList *connchecks = stream->conncheck_list;
590 + for (; connchecks; connchecks = connchecks->next) {
591 + CandidateCheckPair *pair = connchecks->data;
592 + if (!g_strcmp0(pair->foundation, new_pair->foundation)) {
593 + pair->linked_pairs = g_slist_append (pair->linked_pairs, new_pair);
595 + nice_debug ("Agent %p : linked new conncheck %p with foundation of '%s' to conncheck %p of stream %u.",
596 + agent, new_pair, new_pair->foundation, pair, stream->id);
597 + return TRUE;
602 + return FALSE;
606 * Creates a new connectivity check pair and adds it to
607 * the agent's list of checks.
608 @@ -1254,9 +1286,6 @@ static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Componen
609 Stream *stream = agent_find_stream (agent, stream_id);
610 CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
612 - stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
613 - (GCompareFunc)conn_check_compare);
615 pair->agent = agent;
616 pair->stream_id = stream_id;
617 pair->component_id = component->id;;
618 @@ -1274,13 +1303,19 @@ static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Componen
619 if (!stream->conncheck_list)
620 stream->conncheck_state = NICE_CHECKLIST_RUNNING;
622 - nice_debug ("Agent %p : added a new conncheck %p with foundation of '%s' to list %u.", agent, pair, pair->foundation, stream_id);
623 + if (!priv_try_link_check_pair (agent, stream, pair)) {
624 + stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
625 + (GCompareFunc)conn_check_compare);
627 - /* implement the hard upper limit for number of
628 - checks (see sect 5.7.3 ICE ID-19): */
629 - if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) {
630 - stream->conncheck_list =
631 - priv_limit_conn_check_list_size (stream->conncheck_list, agent->max_conn_checks);
632 + nice_debug ("Agent %p : added a new conncheck %p with foundation of '%s' to list %u.",
633 + agent, pair, pair->foundation, stream_id);
635 + /* implement the hard upper limit for number of
636 + checks (see sect 5.7.3 ICE ID-19): */
637 + if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) {
638 + stream->conncheck_list =
639 + priv_limit_conn_check_list_size (stream->conncheck_list, agent->max_conn_checks);
644 @@ -1305,9 +1340,18 @@ int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *
646 NiceCandidate *local = i->data;
648 - /* note: match pairs only if transport and address family are the same */
649 - if (local->transport == remote->transport &&
650 - local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) {
651 + /* note: do not create pairs where local candidate has TCP passive transport
652 + * (ice-tcp-13 6.2. "Forming the Check Lists") */
653 + if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
654 + continue;
656 + /* note: match pairs only if address families are the same and transport
657 + * are compatible */
658 + if (((local->transport == NICE_CANDIDATE_TRANSPORT_UDP &&
659 + remote->transport == NICE_CANDIDATE_TRANSPORT_UDP) ||
660 + (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE &&
661 + remote->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)) &&
662 + local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) {
664 /* note: do not create pairs where local candidate is
665 * a srv-reflexive (ICE 5.7.3. "Pruning the Pairs" ID-19) */
666 @@ -1315,7 +1359,7 @@ int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *
667 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
668 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
669 local->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE)
670 - continue;
671 + continue;
673 priv_add_new_check_pair (agent, stream_id, component, local, remote, NICE_CHECK_FROZEN, FALSE);
674 ++added;
675 @@ -1346,6 +1390,13 @@ void conn_check_free_item (gpointer data, gpointer user_data)
676 g_assert (user_data == NULL);
677 pair->stun_message.buffer = NULL;
678 pair->stun_message.buffer_len = 0;
680 + if (pair->linked_pairs) {
681 + g_slist_foreach (pair->linked_pairs, conn_check_free_item, NULL);
682 + g_slist_free (pair->linked_pairs);
683 + pair->linked_pairs = NULL;
686 g_slice_free (CandidateCheckPair, pair);
689 @@ -1637,7 +1688,7 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
690 uname, uname_len, password, password_len,
691 cand_use, controlling, priority,
692 agent->tie_breaker,
693 - pair->foundation,
694 + pair->local->foundation,
695 agent_to_ice_compatibility (agent));
697 nice_debug ("Agent %p: conncheck created %d - %p", agent, buffer_len, pair->stun_message.buffer);
698 @@ -1648,8 +1699,12 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
701 if (buffer_len > 0) {
702 - stun_timer_start (&pair->timer, STUN_TIMER_DEFAULT_TIMEOUT,
703 - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
704 + if (nice_socket_is_reliable(pair->local->sockptr)) {
705 + stun_timer_start_reliable(&pair->timer, STUN_TIMER_DEFAULT_TIMEOUT);
706 + } else {
707 + stun_timer_start (&pair->timer, STUN_TIMER_DEFAULT_TIMEOUT,
708 + STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
711 /* send the conncheck */
712 nice_socket_send (pair->local->sockptr, &pair->remote->addr,
713 @@ -1905,7 +1960,6 @@ static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint
714 CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
715 Stream *stream = agent_find_stream (agent, stream_id);
717 - stream->conncheck_list = g_slist_append (stream->conncheck_list, pair);
718 pair->agent = agent;
719 pair->stream_id = stream_id;
720 pair->component_id = component_id;;
721 @@ -1923,7 +1977,13 @@ static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint
722 local_cand->priority);
723 pair->nominated = FALSE;
724 pair->controlling = agent->controlling_mode;
725 - nice_debug ("Agent %p : added a new peer-discovered pair with foundation of '%s'.", agent, pair->foundation);
727 + if (!priv_try_link_check_pair(agent, stream, pair)) {
728 + stream->conncheck_list = g_slist_append (stream->conncheck_list, pair);
730 + nice_debug ("Agent %p : added a new peer-discovered pair with foundation of '%s'.",
731 + agent, pair->foundation);
734 return pair;
736 @@ -2023,6 +2083,28 @@ static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAg
737 return new_pair;
740 +static void priv_update_component_state_on_conn_check_success (NiceAgent *agent,
741 + Stream *stream, Component *component, CandidateCheckPair *check_pair)
743 + /* Do not step down to CONNECTED if we're already at state READY*/
744 + if (component->state != NICE_COMPONENT_STATE_READY) {
745 + /* step: notify the client of a new component state (must be done
746 + * before the possible check list state update step */
747 + agent_signal_component_state_change (agent,
748 + stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
752 + /* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
753 + Nominated Flag" (ID-19) */
754 + if (check_pair->nominated == TRUE)
755 + priv_update_selected_pair (agent, component, check_pair);
757 + /* step: update pair states (ICE 7.1.2.2.3 "Updating pair
758 + states" and 8.1.2 "Updating States", ID-19) */
759 + priv_update_check_list_state_for_ready (agent, stream, component);
763 * Tries to match STUN reply in 'buf' to an existing STUN connectivity
764 * check transaction. If found, the reply is processed. Implements
765 @@ -2108,24 +2190,19 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *
766 if (!ok_pair)
767 ok_pair = p;
769 - /* Do not step down to CONNECTED if we're already at state READY*/
770 - if (component->state != NICE_COMPONENT_STATE_READY) {
771 - /* step: notify the client of a new component state (must be done
772 - * before the possible check list state update step */
773 - agent_signal_component_state_change (agent,
774 - stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
775 + priv_update_component_state_on_conn_check_success (agent, stream,
776 + component, ok_pair);
777 + if (ok_pair->linked_pairs) {
778 + GSList *pairs = ok_pair->linked_pairs;
779 + for (; pairs; pairs = pairs->next) {
780 + CandidateCheckPair *pair = pairs->data;
781 + pair->nominated = ok_pair->nominated;
782 + pair->state = ok_pair->state;
783 + priv_update_component_state_on_conn_check_success (agent, stream,
784 + component, ok_pair);
789 - /* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
790 - Nominated Flag" (ID-19) */
791 - if (ok_pair->nominated == TRUE)
792 - priv_update_selected_pair (agent, component, ok_pair);
794 - /* step: update pair states (ICE 7.1.2.2.3 "Updating pair
795 - states" and 8.1.2 "Updating States", ID-19) */
796 - priv_update_check_list_state_for_ready (agent, stream, component);
798 trans_found = TRUE;
799 } else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
800 /* case: role conflict error, need to restart with new role */
801 @@ -2205,6 +2282,7 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessa
802 d->stream->id,
803 d->component->id,
804 &niceaddr,
805 + NICE_CANDIDATE_TRANSPORT_UDP,
806 d->nicesock);
808 d->stun_message.buffer = NULL;
809 @@ -2309,33 +2387,76 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
810 res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
811 /* case: successful allocate, create a new local candidate */
812 NiceAddress niceaddr;
813 - NiceCandidate *relay_cand;
814 + NiceCandidate *relay_cand = NULL;
816 /* We also received our mapped address */
817 if (res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
818 nice_address_set_from_sockaddr (&niceaddr,
819 (struct sockaddr *) &sockaddr);
821 - discovery_add_server_reflexive_candidate (
822 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
823 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
824 + d->turn->type == NICE_RELAY_TYPE_TURN_TCP) {
825 + GSList *components = d->stream->components;
826 + for (; components; components = components->next) {
827 + Component *component = components->data;
828 + discovery_add_server_reflexive_candidate(
829 + d->agent,
830 + d->stream->id,
831 + component->id,
832 + &niceaddr,
833 + NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE,
834 + d->nicesock);
836 + } else {
837 + discovery_add_server_reflexive_candidate (
838 + d->agent,
839 + d->stream->id,
840 + d->component->id,
841 + &niceaddr,
842 + NICE_CANDIDATE_TRANSPORT_UDP,
843 + d->nicesock);
847 + nice_address_set_from_sockaddr (&niceaddr,
848 + (struct sockaddr *) &relayaddr);
850 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
851 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
852 + d->turn->type == NICE_RELAY_TYPE_TURN_TCP) {
853 + GSList *components = d->stream->components;
854 + for (; components; components = components->next) {
855 + Component *component = components->data;
856 + relay_cand = discovery_add_relay_candidate (
857 + d->agent,
858 + d->stream->id,
859 + component->id,
860 + &niceaddr,
861 + NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE,
862 + d->nicesock,
863 + d->turn);
864 + discovery_add_relay_candidate (
865 + d->agent,
866 + d->stream->id,
867 + component->id,
868 + &niceaddr,
869 + NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE,
870 + d->nicesock,
871 + d->turn);
873 + } else {
874 + relay_cand = discovery_add_relay_candidate (
875 d->agent,
876 d->stream->id,
877 d->component->id,
878 &niceaddr,
879 - d->nicesock);
880 + NICE_CANDIDATE_TRANSPORT_UDP,
881 + d->nicesock,
882 + d->turn);
885 - nice_address_set_from_sockaddr (&niceaddr,
886 - (struct sockaddr *) &relayaddr);
887 - relay_cand = discovery_add_relay_candidate (
888 - d->agent,
889 - d->stream->id,
890 - d->component->id,
891 - &niceaddr,
892 - d->nicesock,
893 - d->turn);
895 if (relay_cand) {
896 - priv_add_new_turn_refresh (d, relay_cand, lifetime);
897 if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
898 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
899 /* These data are needed on TURN socket when sending requests,
900 @@ -2346,7 +2467,8 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
901 * so we are doing it here. */
902 nice_turn_socket_set_ms_realm(relay_cand->sockptr, &d->stun_message);
903 nice_turn_socket_set_ms_connection_id(relay_cand->sockptr, resp);
905 + } else
906 + priv_add_new_turn_refresh (d, relay_cand, lifetime);
909 d->stun_message.buffer = NULL;
910 diff --git a/agent/conncheck.h b/agent/conncheck.h
911 index 4745a9d..28054d2 100644
912 --- a/agent/conncheck.h
913 +++ b/agent/conncheck.h
914 @@ -79,6 +79,7 @@ struct _CandidateCheckPair
915 StunTimer timer;
916 uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE];
917 StunMessage stun_message;
918 + GSList *linked_pairs;
921 int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *remote);
922 diff --git a/agent/discovery.c b/agent/discovery.c
923 index 00afd5c..11f0051 100644
924 --- a/agent/discovery.c
925 +++ b/agent/discovery.c
926 @@ -253,7 +253,8 @@ static gboolean priv_add_local_candidate_pruned (Component *component, NiceCandi
927 NiceCandidate *c = i->data;
929 if (nice_address_equal (&c->base_addr, &candidate->base_addr) &&
930 - nice_address_equal (&c->addr, &candidate->addr)) {
931 + nice_address_equal (&c->addr, &candidate->addr) &&
932 + c->transport == candidate->transport) {
933 nice_debug ("Candidate %p (component-id %u) redundant, ignoring.", candidate, component->id);
934 return FALSE;
936 @@ -456,6 +457,7 @@ NiceCandidate *discovery_add_local_host_candidate (
937 return NULL;
939 candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST);
940 + candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
941 candidate->stream_id = stream_id;
942 candidate->component_id = component_id;
943 candidate->addr = *address;
944 @@ -465,6 +467,8 @@ NiceCandidate *discovery_add_local_host_candidate (
945 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
946 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
947 candidate->priority = nice_candidate_msn_priority (candidate);
948 + } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
949 + candidate->priority = nice_candidate_ms_ice_priority (candidate);
950 } else {
951 candidate->priority = nice_candidate_ice_priority (candidate);
953 @@ -513,6 +517,7 @@ discovery_add_server_reflexive_candidate (
954 guint stream_id,
955 guint component_id,
956 NiceAddress *address,
957 + NiceCandidateTransport transport,
958 NiceSocket *base_socket)
960 NiceCandidate *candidate;
961 @@ -525,17 +530,20 @@ discovery_add_server_reflexive_candidate (
963 candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE);
965 + candidate->transport = transport;
966 + candidate->stream_id = stream_id;
967 + candidate->component_id = component_id;
968 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
969 candidate->priority = nice_candidate_jingle_priority (candidate);
970 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
971 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
972 candidate->priority = nice_candidate_msn_priority (candidate);
973 + } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
974 + candidate->priority = nice_candidate_ms_ice_priority (candidate);
975 } else {
976 candidate->priority = nice_candidate_ice_priority_full
977 (NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE, 0, component_id);
979 - candidate->stream_id = stream_id;
980 - candidate->component_id = component_id;
981 candidate->addr = *address;
983 /* step: link to the base candidate+socket */
984 @@ -557,6 +565,26 @@ discovery_add_server_reflexive_candidate (
985 return candidate;
988 +static NiceSocket *
989 +priv_reuse_turn_socket(Stream *stream, NiceSocket *base_socket)
991 + GSList *i;
992 + for (i = stream->components; i; i = i->next) {
993 + Component *comp = i->data;
994 + GSList *j;
995 + for (j = comp->local_candidates; j; j = j->next) {
996 + NiceCandidate *cand = j->data;
997 + if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
998 + (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
999 + cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)) {
1000 + NiceSocket *sock = cand->sockptr;
1001 + if (sock->fileno == base_socket->fileno)
1002 + return sock;
1006 + return NULL;
1010 * Creates a server reflexive candidate for 'component_id' of stream
1011 @@ -570,6 +598,7 @@ discovery_add_relay_candidate (
1012 guint stream_id,
1013 guint component_id,
1014 NiceAddress *address,
1015 + NiceCandidateTransport transport,
1016 NiceSocket *base_socket,
1017 TurnServer *turn)
1019 @@ -577,31 +606,45 @@ discovery_add_relay_candidate (
1020 Component *component;
1021 Stream *stream;
1022 NiceSocket *relay_socket = NULL;
1023 + gboolean socket_is_new = TRUE;
1025 if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
1026 return NULL;
1028 candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_RELAYED);
1030 + candidate->stream_id = stream_id;
1031 + candidate->component_id = component_id;
1032 + candidate->transport = transport;
1033 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1034 candidate->priority = nice_candidate_jingle_priority (candidate);
1035 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1036 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1037 candidate->priority = nice_candidate_msn_priority (candidate);
1038 + } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1039 + candidate->priority = nice_candidate_ms_ice_priority (candidate);
1040 } else {
1041 candidate->priority = nice_candidate_ice_priority_full
1042 (NICE_CANDIDATE_TYPE_PREF_RELAYED, 0, component_id);
1044 - candidate->stream_id = stream_id;
1045 - candidate->component_id = component_id;
1046 candidate->addr = *address;
1047 candidate->turn = turn;
1049 /* step: link to the base candidate+socket */
1050 - relay_socket = nice_turn_socket_new (agent, address,
1051 - base_socket, &turn->server,
1052 - turn->username, turn->password,
1053 - agent_to_turn_socket_compatibility (agent));
1054 + if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1055 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
1056 + (transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
1057 + transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)) {
1058 + relay_socket = priv_reuse_turn_socket(stream, base_socket);
1060 + if (relay_socket) {
1061 + socket_is_new = FALSE;
1062 + } else {
1063 + relay_socket = nice_turn_socket_new (agent, address,
1064 + base_socket, &turn->server,
1065 + turn->username, turn->password,
1066 + agent_to_turn_socket_compatibility (agent));
1068 if (!relay_socket)
1069 goto errors;
1071 @@ -621,14 +664,15 @@ discovery_add_relay_candidate (
1072 if (!priv_add_local_candidate_pruned (component, candidate))
1073 goto errors;
1075 - component->sockets = g_slist_append (component->sockets, relay_socket);
1076 + if (socket_is_new)
1077 + component->sockets = g_slist_append (component->sockets, relay_socket);
1078 agent_signal_new_candidate (agent, candidate);
1080 return candidate;
1082 errors:
1083 nice_candidate_free (candidate);
1084 - if (relay_socket)
1085 + if (relay_socket && socket_is_new)
1086 nice_socket_free (relay_socket);
1087 return NULL;
1089 @@ -660,17 +704,19 @@ discovery_add_peer_reflexive_candidate (
1090 candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
1092 candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
1093 + candidate->stream_id = stream_id;
1094 + candidate->component_id = component_id;
1095 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1096 candidate->priority = nice_candidate_jingle_priority (candidate);
1097 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1098 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1099 candidate->priority = nice_candidate_msn_priority (candidate);
1100 + } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1101 + candidate->priority = nice_candidate_ms_ice_priority (candidate);
1102 } else {
1103 candidate->priority = nice_candidate_ice_priority_full
1104 (NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE, 0, component_id);
1106 - candidate->stream_id = stream_id;
1107 - candidate->component_id = component_id;
1108 candidate->addr = *address;
1109 candidate->base_addr = base_socket->addr;
1111 @@ -752,6 +798,8 @@ NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
1112 candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
1113 candidate->addr = *remote_address;
1114 candidate->base_addr = *remote_address;
1115 + candidate->stream_id = stream->id;
1116 + candidate->component_id = component->id;
1118 /* if the check didn't contain the PRIORITY attribute, then the priority will
1119 * be 0, which is invalid... */
1120 @@ -762,13 +810,12 @@ NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
1121 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1122 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1123 candidate->priority = nice_candidate_msn_priority (candidate);
1124 + } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1125 + candidate->priority = nice_candidate_ms_ice_priority (candidate);
1126 } else {
1127 candidate->priority = nice_candidate_ice_priority_full
1128 (NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE, 0, component->id);
1130 - candidate->stream_id = stream->id;
1131 - candidate->component_id = component->id;
1134 priv_assign_remote_foundation (agent, candidate);
1136 diff --git a/agent/discovery.h b/agent/discovery.h
1137 index 209fa95..0a31cce 100644
1138 --- a/agent/discovery.h
1139 +++ b/agent/discovery.h
1140 @@ -111,6 +111,7 @@ discovery_add_relay_candidate (
1141 guint stream_id,
1142 guint component_id,
1143 NiceAddress *address,
1144 + NiceCandidateTransport transport,
1145 NiceSocket *base_socket,
1146 TurnServer *turn);
1148 @@ -120,6 +121,7 @@ discovery_add_server_reflexive_candidate (
1149 guint stream_id,
1150 guint component_id,
1151 NiceAddress *address,
1152 + NiceCandidateTransport transport,
1153 NiceSocket *base_socket);
1155 NiceCandidate*
1156 diff --git a/agent/stream.c b/agent/stream.c
1157 index 1276ae2..e9fc76a 100644
1158 --- a/agent/stream.c
1159 +++ b/agent/stream.c
1160 @@ -62,6 +62,7 @@ stream_new (guint n_components)
1162 stream->n_components = n_components;
1163 stream->initial_binding_request_received = FALSE;
1164 + stream->allowed_transports = NICE_CANDIDATE_TRANSPORT_UDP;
1166 return stream;
1168 @@ -149,3 +150,16 @@ stream_restart (Stream *stream, NiceRNG *rng)
1169 return res;
1172 +gboolean
1173 +stream_transport_is_allowed(Stream *stream, NiceCandidateTransport transport,
1174 + gboolean candidate_is_remote)
1176 + if (candidate_is_remote) {
1177 + if (transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE)
1178 + return stream->allowed_transports & NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
1179 + if (transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
1180 + return stream->allowed_transports & NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1183 + return transport & stream->allowed_transports;
1185 diff --git a/agent/stream.h b/agent/stream.h
1186 index 171ea72..a4eeb19 100644
1187 --- a/agent/stream.h
1188 +++ b/agent/stream.h
1189 @@ -86,6 +86,10 @@ struct _Stream
1190 gchar remote_password[NICE_STREAM_MAX_PWD];
1191 gboolean gathering;
1192 gint tos;
1193 + NiceCandidateTransport allowed_transports;
1195 + NiceAgentDemultiplexFunc demultiplex_func;
1196 + gpointer data; /* user data passed to demultiplex_func */
1200 @@ -107,6 +111,10 @@ stream_initialize_credentials (Stream *stream, NiceRNG *rng);
1201 gboolean
1202 stream_restart (Stream *stream, NiceRNG *rng);
1204 +gboolean
1205 +stream_transport_is_allowed(Stream *stream, NiceCandidateTransport transport,
1206 + gboolean candidate_is_remote);
1208 G_END_DECLS
1210 #endif /* _NICE_STREAM_H */
1211 diff --git a/nice/libnice.sym b/nice/libnice.sym
1212 index dcb788e..6dd16dc 100644
1213 --- a/nice/libnice.sym
1214 +++ b/nice/libnice.sym
1215 @@ -15,6 +15,7 @@ nice_address_set_port
1216 nice_address_to_string
1217 nice_agent_add_local_address
1218 nice_agent_add_stream
1219 +nice_agent_attach_demultiplexer
1220 nice_agent_attach_recv
1221 nice_agent_gather_candidates
1222 nice_agent_get_local_candidates
1223 @@ -33,6 +34,7 @@ nice_agent_set_selected_pair
1224 nice_agent_set_selected_remote_candidate
1225 nice_agent_set_software
1226 nice_agent_set_stream_tos
1227 +nice_agent_set_stream_transport
1228 nice_candidate_copy
1229 nice_candidate_free
1230 nice_candidate_new
1231 diff --git a/socket/pseudossl.c b/socket/pseudossl.c
1232 index f3cf3e1..ae8a626 100644
1233 --- a/socket/pseudossl.c
1234 +++ b/socket/pseudossl.c
1235 @@ -43,6 +43,7 @@
1236 #endif
1238 #include "pseudossl.h"
1239 +#include "agent-priv.h"
1241 #include <string.h>
1243 @@ -51,6 +52,7 @@
1244 #endif
1246 typedef struct {
1247 + NiceAgent *agent;
1248 gboolean handshaken;
1249 NiceSocket *base_socket;
1250 GQueue send_queue;
1251 @@ -87,6 +89,27 @@ static const gchar SSL_CLIENT_HANDSHAKE[] = {
1252 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc,
1253 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea};
1255 +static const gchar SSL_SERVER_HANDSHAKE_MS_TURN[] = {
1256 + 0x16, 0x03, 0x01, 0x00, 0x4e, 0x02, 0x00, 0x00,
1257 + 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1258 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1259 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1260 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1261 + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
1262 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1263 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1264 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1265 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0e,
1266 + 0x00, 0x00, 0x00};
1268 +static const gchar SSL_CLIENT_HANDSHAKE_MS_TURN[] = {
1269 + 0x16, 0x03, 0x01, 0x00, 0x2d, 0x01, 0x00, 0x00,
1270 + 0x29, 0x03, 0x01, 0xc1, 0xfc, 0xd5, 0xa3, 0x6d,
1271 + 0x93, 0xdd, 0x7e, 0x0b, 0x45, 0x67, 0x3f, 0xec,
1272 + 0x79, 0x85, 0xfb, 0xbc, 0x3f, 0xd6, 0x60, 0xc2,
1273 + 0xce, 0x84, 0x85, 0x08, 0x1b, 0x81, 0x21, 0xbc,
1274 + 0xaa, 0x10, 0xfb, 0x00, 0x00, 0x02, 0x00, 0x18,
1275 + 0x01, 0x00};
1277 static void socket_close (NiceSocket *sock);
1278 static gint socket_recv (NiceSocket *sock, NiceAddress *from,
1279 @@ -105,8 +128,12 @@ nice_pseudossl_socket_new (NiceAgent *agent, NiceSocket *base_socket)
1281 PseudoSSLPriv *priv;
1282 NiceSocket *sock = g_slice_new0 (NiceSocket);
1283 + const gchar *buf;
1284 + guint len;
1286 sock->priv = priv = g_slice_new0 (PseudoSSLPriv);
1288 + priv->agent = agent;
1289 priv->handshaken = FALSE;
1290 priv->base_socket = base_socket;
1292 @@ -117,10 +144,18 @@ nice_pseudossl_socket_new (NiceAgent *agent, NiceSocket *base_socket)
1293 sock->is_reliable = socket_is_reliable;
1294 sock->close = socket_close;
1296 + if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1297 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1298 + buf = SSL_CLIENT_HANDSHAKE_MS_TURN;
1299 + len = sizeof(SSL_CLIENT_HANDSHAKE_MS_TURN);
1300 + } else {
1301 + buf = SSL_CLIENT_HANDSHAKE;
1302 + len = sizeof(SSL_CLIENT_HANDSHAKE);
1305 /* We send 'to' NULL because it will always be to an already connected
1306 * TCP base socket, which ignores the destination */
1307 - nice_socket_send (priv->base_socket, NULL,
1308 - sizeof(SSL_CLIENT_HANDSHAKE), SSL_CLIENT_HANDSHAKE);
1309 + nice_socket_send (priv->base_socket, NULL, len, buf);
1311 return sock;
1313 @@ -140,6 +175,23 @@ socket_close (NiceSocket *sock)
1314 g_slice_free(PseudoSSLPriv, sock->priv);
1317 +static gboolean
1318 +server_handshake_valid(NiceAgent *agent, guint len, gchar *buf)
1320 + if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1321 + agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1322 + if (len == sizeof(SSL_SERVER_HANDSHAKE_MS_TURN)) {
1323 + memset(buf + 11, 0, 32);
1324 + memset(buf + 44, 0, 32);
1325 + return memcmp(SSL_SERVER_HANDSHAKE_MS_TURN, buf,
1326 + sizeof(SSL_SERVER_HANDSHAKE_MS_TURN)) == 0;
1328 + return FALSE;
1329 + } else {
1330 + return len == sizeof(SSL_SERVER_HANDSHAKE) &&
1331 + memcmp(SSL_SERVER_HANDSHAKE, buf, sizeof(SSL_SERVER_HANDSHAKE)) == 0;
1335 static gint
1336 socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
1337 @@ -150,7 +202,7 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
1338 if (priv->base_socket)
1339 return nice_socket_recv (priv->base_socket, from, len, buf);
1340 } else {
1341 - gchar data[sizeof(SSL_SERVER_HANDSHAKE)];
1342 + gchar data[MAX(sizeof(SSL_SERVER_HANDSHAKE), sizeof(SSL_SERVER_HANDSHAKE_MS_TURN))];
1343 gint ret = -1;
1345 if (priv->base_socket)
1346 @@ -158,8 +210,7 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
1348 if (ret <= 0) {
1349 return ret;
1350 - } else if ((guint) ret == sizeof(SSL_SERVER_HANDSHAKE) &&
1351 - memcmp(SSL_SERVER_HANDSHAKE, data, sizeof(SSL_SERVER_HANDSHAKE)) == 0) {
1352 + } else if (server_handshake_valid(priv->agent, (guint) ret, data)) {
1353 struct to_be_sent *tbs = NULL;
1354 priv->handshaken = TRUE;
1355 while ((tbs = g_queue_pop_head (&priv->send_queue))) {
1356 diff --git a/socket/tcp-turn.c b/socket/tcp-turn.c
1357 index 9777849..1a7cde0 100644
1358 --- a/socket/tcp-turn.c
1359 +++ b/socket/tcp-turn.c
1360 @@ -60,8 +60,16 @@ typedef struct {
1361 NiceSocket *base_socket;
1362 } TurnTcpPriv;
1364 +typedef enum {
1365 + MS_TURN_CONTROL_MESSAGE = 2,
1366 + MS_TURN_END_TO_END_DATA = 3
1367 +} MsTurnPayloadType;
1369 #define MAX_UDP_MESSAGE_SIZE 65535
1371 +#define MAGIC_COOKIE_OFFSET \
1372 + STUN_MESSAGE_HEADER_LENGTH + STUN_MESSAGE_TYPE_LEN + STUN_MESSAGE_LENGTH_LEN
1374 static void socket_close (NiceSocket *sock);
1375 static gint socket_recv (NiceSocket *sock, NiceAddress *from,
1376 guint len, gchar *buf);
1377 @@ -114,7 +122,8 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
1378 guint headerlen = 0;
1380 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
1381 - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766)
1382 + priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 ||
1383 + priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007)
1384 headerlen = 4;
1385 else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE)
1386 headerlen = 2;
1387 @@ -149,6 +158,17 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
1388 priv->expecting_len = len;
1389 priv->recv_buf_len = 0;
1391 + else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) {
1392 + guint8 magic = *priv->recv_buf;
1393 + guint16 packetlen = ntohs (*(guint16*)(priv->recv_buf + 2));
1395 + if (magic != 0x02 && magic != 0x03) {
1396 + /* Unexpected data, error in stream */
1397 + return -1;
1399 + priv->expecting_len = packetlen;
1400 + priv->recv_buf_len = 0;
1404 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
1405 @@ -196,6 +216,32 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
1406 guint16 tmpbuf = htons (len);
1407 memcpy (buffer + buffer_len, (gchar *)&tmpbuf, sizeof(guint16));
1408 buffer_len += sizeof(guint16);
1409 + } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) {
1410 + guint32 cookie = ntohl(*(guint32*)(buf + MAGIC_COOKIE_OFFSET));
1411 + MsTurnPayloadType payload_type;
1412 + guint16 tmpbuf = len;
1414 + if ((len > sizeof (TURN_MAGIC_COOKIE) + MAGIC_COOKIE_OFFSET) &&
1415 + cookie == TURN_MAGIC_COOKIE) {
1416 + payload_type = MS_TURN_CONTROL_MESSAGE;
1417 + } else {
1418 + payload_type = MS_TURN_END_TO_END_DATA;
1419 + tmpbuf += 2;
1422 + tmpbuf = htons (tmpbuf);
1424 + memset (buffer + buffer_len++, payload_type, 1);
1425 + memset (buffer + buffer_len++, 0x00, 1);
1426 + memcpy (buffer + buffer_len, (gchar *)&tmpbuf, sizeof (guint16));
1427 + buffer_len += sizeof (guint16);
1429 + /* RFC 4561 framing method */
1430 + if (payload_type == MS_TURN_END_TO_END_DATA) {
1431 + tmpbuf = htons (len);
1432 + memcpy (buffer + buffer_len, (gchar *)&tmpbuf, sizeof (guint16));
1433 + buffer_len += sizeof (guint16);
1437 memcpy (buffer + buffer_len, buf, len);
1438 diff --git a/socket/turn.c b/socket/turn.c
1439 index b0c790c..38e0197 100644
1440 --- a/socket/turn.c
1441 +++ b/socket/turn.c
1442 @@ -499,6 +499,7 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
1443 return nice_socket_send (priv->base_socket, &priv->server_addr, len, buf);
1445 } else {
1446 + gchar data_buffer[STUN_MAX_MESSAGE_SIZE + sizeof (uint16_t)];
1447 if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
1448 priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
1449 if (!stun_agent_init_indication (&priv->agent, &msg,
1450 @@ -542,6 +543,14 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
1451 ++priv->ms_sequence_num);
1453 stun_message_ensure_ms_realm(&msg, priv->ms_realm);
1455 + if (nice_socket_is_reliable (sock)) {
1456 + uint16_t len16 = htons ((uint16_t) len);
1457 + memcpy (data_buffer, &len16, sizeof (uint16_t));
1458 + memcpy (data_buffer + sizeof (uint16_t), buf, len);
1459 + buf = data_buffer;
1460 + len += sizeof (uint16_t);
1464 if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_DATA,
1465 diff --git a/stun/stunmessage.c b/stun/stunmessage.c
1466 index 5401acd..c99c664 100644
1467 --- a/stun/stunmessage.c
1468 +++ b/stun/stunmessage.c
1469 @@ -570,7 +570,15 @@ int stun_message_validate_buffer_length (const uint8_t *msg, size_t length,
1470 /* from then on, we know we have the entire packet in buffer */
1471 while (len > 0)
1473 - size_t alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN);
1474 + size_t alen;
1476 + if (len < 4)
1478 + stun_debug ("STUN error: Incomplete STUN attribute header!\n");
1479 + return STUN_MESSAGE_BUFFER_INVALID;
1482 + alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN);
1483 if (has_padding)
1484 alen = stun_align (alen);
1486 diff --git a/stun/stunmessage.h b/stun/stunmessage.h
1487 index b31189e..627880a 100644
1488 --- a/stun/stunmessage.h
1489 +++ b/stun/stunmessage.h
1490 @@ -211,6 +211,8 @@ typedef enum
1491 * libjingle
1492 * @STUN_ATTRIBUTE_MS_VERSION: The MS-VERSION optional attribute as defined
1493 * by [MS-TURN]
1494 + * @STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS: The XOR-MAPPED-ADDRESS optional
1495 + * attribute as defined by [MS-TURN]
1496 * @STUN_ATTRIBUTE_SOFTWARE: The SOFTWARE optional attribute as defined by RFC5389
1497 * @STUN_ATTRIBUTE_ALTERNATE_SERVER: The ALTERNATE-SERVER optional attribute as
1498 * defined by RFC5389
1499 @@ -288,6 +290,7 @@ typedef enum
1500 /* 0x8000-0x8021 */ /* reserved */
1501 STUN_ATTRIBUTE_OPTIONS=0x8001, /* libjingle */
1502 STUN_ATTRIBUTE_MS_VERSION=0x8008, /* MS-TURN */
1503 + STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS=0x8020, /* MS-TURN */
1504 STUN_ATTRIBUTE_SOFTWARE=0x8022, /* RFC5389 */
1505 STUN_ATTRIBUTE_ALTERNATE_SERVER=0x8023, /* RFC5389 */
1506 /* 0x8024 */ /* reserved */
1507 diff --git a/stun/usages/turn.c b/stun/usages/turn.c
1508 index 5bcf89b..3b62fda 100644
1509 --- a/stun/usages/turn.c
1510 +++ b/stun/usages/turn.c
1511 @@ -339,8 +339,7 @@ StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
1512 stun_debug (" No MAPPED-ADDRESS: %d\n", val);
1513 return STUN_USAGE_TURN_RETURN_ERROR;
1515 - } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
1516 - compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
1517 + } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN) {
1518 val = stun_message_find_addr (msg,
1519 STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS, addr, addrlen);
1521 @@ -353,6 +352,25 @@ StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
1522 stun_debug (" No MAPPED-ADDRESS: %d\n", val);
1523 return STUN_USAGE_TURN_RETURN_ERROR;
1525 + } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
1526 + StunTransactionId transid;
1527 + uint32_t magic_cookie;
1528 + stun_message_id (msg, transid);
1529 + magic_cookie = *((uint32_t *) transid);
1531 + val = stun_message_find_xor_addr_full (msg,
1532 + STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS, addr, addrlen, htonl (magic_cookie));
1534 + if (val == STUN_MESSAGE_RETURN_SUCCESS)
1535 + ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS;
1537 + val = stun_message_find_addr (msg,
1538 + STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen);
1539 + if (val != STUN_MESSAGE_RETURN_SUCCESS) {
1540 + stun_debug (" No MAPPED-ADDRESS: %d\n", val);
1541 + return STUN_USAGE_TURN_RETURN_ERROR;
1546 stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime);
1548 1.7.5.4