NiceStream *stream = NULL;
gboolean ret = TRUE;
TurnServer *turn;
+ guint length;
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
g_return_val_if_fail (stream_id >= 1, FALSE);
goto done;
}
+ length = g_list_length (component->turn_servers);
+ if (length == NICE_CANDIDATE_MAX_TURN_SERVERS) {
+ nice_debug ("Agent %p : cannot have more than %d turn servers.",
+ agent, length);
+ ret = FALSE;
+ goto done;
+ }
+
turn = turn_server_new (server_ip, server_port, username, password, type);
if (!turn) {
stream_id, component_id, username,
nice_debug_is_verbose() ? password : "****");
+ /* The turn server preference (used to setup its priority in the
+ * conncheck) is simply its position in the list. The preference must
+ * be unique for each one.
+ */
+ turn->preference = length;
component->turn_servers = g_list_append (component->turn_servers, turn);
if (stream->gathering_started) {
NiceStream *stream;
GSList *local_addresses = NULL;
gboolean ret = TRUE;
+ guint length;
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
g_return_val_if_fail (stream_id >= 1, FALSE);
}
}
+ length = g_slist_length (local_addresses);
+ if (length > NICE_CANDIDATE_MAX_LOCAL_ADDRESSES) {
+ nice_debug ("Agent %p : cannot have more than %d local addresses.",
+ agent, length);
+ }
+
for (cid = 1; cid <= stream->n_components; cid++) {
NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
gboolean found_local_address = FALSE;
continue;
/* generate a local host candidate for each local address */
- for (i = local_addresses; i; i = i->next) {
+ length = 0;
+ for (i = local_addresses;
+ i && length <= NICE_CANDIDATE_MAX_LOCAL_ADDRESSES;
+ i = i->next, length++) {
NiceAddress *addr = i->data;
NiceCandidate *host_candidate;
(0x100 - component_id));
}
-static guint32
+static guint16
nice_candidate_ice_local_preference_full (guint direction_preference,
- guint other_preference)
+ guint turn_preference, guint other_preference)
{
- return (0x2000 * direction_preference +
- other_preference);
+ /*
+ * bits 0- 5: other_preference (ip local preference)
+ * 6- 8: turn_preference
+ * 9-12: <unused>
+ * 13-15: direction_preference
+ */
+ g_assert (other_preference <= NICE_CANDIDATE_MAX_LOCAL_ADDRESSES);
+ g_assert (turn_preference <= NICE_CANDIDATE_MAX_TURN_SERVERS);
+ g_assert (direction_preference < 8);
+
+ return (direction_preference << 13) +
+ (turn_preference << 6) +
+ other_preference;
}
-static guint8
+static guint
nice_candidate_ip_local_preference (const NiceCandidate *candidate)
{
- guint8 preference = 0;
+ guint preference = 0;
gchar ip_string[INET6_ADDRSTRLEN];
GList/*<owned gchar*>*/ *ips = NULL;
GList/*<unowned gchar*>*/ *iter;
static guint16
nice_candidate_ice_local_preference (const NiceCandidate *candidate)
{
- guint direction_preference;
+ guint direction_preference = 0;
+ guint turn_preference = 0;
switch (candidate->transport)
{
break;
}
+ /* Relay candidates are assigned a unique local preference at
+ * creation time.
+ */
+ if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
+ g_assert (candidate->turn);
+ turn_preference = candidate->turn->preference;
+ }
+
return nice_candidate_ice_local_preference_full (direction_preference,
- nice_candidate_ip_local_preference (candidate));
+ turn_preference, nice_candidate_ip_local_preference (candidate));
}
-static guint32
+static guint16
nice_candidate_ms_ice_local_preference_full (guint transport_preference,
- guint direction_preference, guint other_preference)
+ guint direction_preference, guint turn_preference, guint other_preference)
{
- return 0x1000 * transport_preference +
- 0x200 * direction_preference +
- 0x1 * other_preference;
+ /*
+ * bits 0- 5: other_preference (ip local preference)
+ * 6- 8: turn_preference
+ * 9-11: direction_preference
+ * 12-15: transport_preference
+ */
+ g_assert (other_preference <= NICE_CANDIDATE_MAX_LOCAL_ADDRESSES);
+ g_assert (turn_preference <= NICE_CANDIDATE_MAX_TURN_SERVERS);
+ g_assert (direction_preference < 8);
+ g_assert (transport_preference < 16);
+
+ return (transport_preference << 12) +
+ (direction_preference << 9) +
+ (turn_preference << 6) +
+ other_preference;
}
static guint32
nice_candidate_ms_ice_local_preference (const NiceCandidate *candidate)
{
- guint8 transport_preference = 0;
- guint8 direction_preference = 0;
+ guint transport_preference = 0;
+ guint direction_preference = 0;
+ guint turn_preference = 0;
switch (candidate->transport)
{
break;
}
+ /* Relay candidates are assigned a unique local preference at
+ * creation time.
+ */
+ if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
+ g_assert (candidate->turn);
+ turn_preference = candidate->turn->preference;
+ }
+
return nice_candidate_ms_ice_local_preference_full(transport_preference,
- direction_preference, nice_candidate_ip_local_preference (candidate));
+ direction_preference, turn_preference,
+ nice_candidate_ip_local_preference (candidate));
}
static guint8
*/
#define NICE_CANDIDATE_MAX_FOUNDATION (32+1)
+/**
+ * NICE_CANDIDATE_MAX_TURN_SERVERS
+ *
+ * The maximum number of turns servers.
+ */
+#define NICE_CANDIDATE_MAX_TURN_SERVERS 7
+
+/**
+ * NICE_CANDIDATE_MAX_LOCAL_ADDRESSES
+ *
+ * The maximum number of local addresses. The constraint is that the
+ * maximum number of local addresses and number of turn servers must
+ * fit on 9 bits, to ensure candidate priority uniqueness. See also
+ * @NICE_CANDIDATE_MAX_TURN_SERVERS. We choose 6 bits for the number of
+ * local addresses, and 3 bits for the number of turn servers.
+ */
+#define NICE_CANDIDATE_MAX_LOCAL_ADDRESSES 63
/**
* NiceCandidateType:
* @decoded_username_len: The length of @decoded_username
* @decoded_password_len: The length of @decoded_password
* @type: The #NiceRelayType of the server
+ * @preference: A unique identifier used to compute priority
*
* A structure to store the TURN relay settings
*/
gsize decoded_username_len;
gsize decoded_password_len;
NiceRelayType type;
+ guint preference;
};
/**