Commit 07bbffd0 authored by Fabrice Bellet's avatar Fabrice Bellet

conncheck: implement ice regular nomination method

This patch implements Regular Nomation as described in RFC5245
8.1.1.1. The controlling agent lets valid pairs accumulate, and
decides which pair to recheck with the use-candidate attribute set.
priv_mark_pair_nominated() follows 7.2.1.5, to update the nominated
pair when acting as a STUN server, and
priv_map_reply_to_conn_check_request() implements 7.1.3.2.4 to
update the nominated pair when acting as a STUN client. A new
property is also added to the agent to control the nomination
mode, which can be regular of aggressive, with default value
set to aggressive.

Two new flags are introduced in the CandidateCheckPair structure:

- use_candidate_on_next_check indicates the STUN client to add the
  use-candidate attribute when the pair will be checked. At this
  time, the nominated flag has not been set on this pair yet.

- mark_nominated_on_response_arrival indicates the STUN server
  to nominate the pair when its succesfull response to a
  previous triggered check will arrive (7.2.1.5, item #2)

Differential Revision: https://phabricator.freedesktop.org/D811
parent b29770ca
......@@ -22,6 +22,12 @@ if WINDOWS
AM_CFLAGS += -DWINVER=0x0501 # _WIN32_WINNT_WINXP
endif
BUILT_SOURCES = \
agent-enum-types.h \
agent-enum-types.c
CLEANFILES += $(BUILT_SOURCES)
noinst_LTLIBRARIES = libagent.la
libagent_la_SOURCES = \
......@@ -54,6 +60,23 @@ libagent_la_SOURCES = \
outputstream.c \
$(BUILT_SOURCES)
agent-enum-types.h: agent.h Makefile
$(AM_V_GEN)$(GLIB_MKENUMS) \
--fhead "#ifndef __AGENT_ENUM_TYPES_H__\n#define __AGENT_ENUM_TYPES_H__ 1\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
--fprod "/* enumerations from \"@filename@\" */\n" \
--vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define NICE_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* !AGENT_ENUM_TYPES_H */" \
$(addprefix $(srcdir)/,agent.h) > $@
agent-enum-types.c: agent.h Makefile agent-enum-types.h
$(AM_V_GEN)$(GLIB_MKENUMS) \
--fhead "#include <config.h>\n#include <glib-object.h>\n#include \"agent.h\"\n#include \"agent-enum-types.h\"" \
--fprod "\n/* enumerations from \"@filename@\" */" \
--vhead "GType\n@enum_name@_get_type (void)\n{\n static GType type = 0;\n if (!type) {\n static const G@Type@Value values[] = {" \
--vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
--vtail " { 0, NULL, NULL }\n };\n type = g_@type@_register_static (\"@EnumName@\", values);\n }\n return type;\n}\n\n" \
$(addprefix $(srcdir)/,agent.h) > $@
libagent_la_LIBADD = \
$(top_builddir)/random/libnice-random.la \
$(top_builddir)/socket/libsocket.la \
......
......@@ -116,6 +116,13 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
#define NICE_COMPONENT_MAX_VALID_CANDIDATES 50 /* maximum number of validates remote candidates to keep, the number is arbitrary but hopefully large enough */
/* A convenient macro to test if the agent is compatible with RFC5245
* or OC2007R2. Specifically these two modes share the support
* of the regular or aggressive nomination mode */
#define NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2(obj) \
((obj)->compatibility == NICE_COMPATIBILITY_RFC5245 || \
(obj)->compatibility == NICE_COMPATIBILITY_OC2007R2)
struct _NiceAgent
{
GObject parent; /* gobject pointer */
......@@ -132,6 +139,7 @@ struct _NiceAgent
guint timer_ta; /* property: timer Ta */
guint max_conn_checks; /* property: max connectivity checks */
gboolean force_relay; /* property: force relay */
NiceNominationMode nomination_mode; /* property: Nomination mode */
GSList *local_addresses; /* list of NiceAddresses for local
interfaces */
......
......@@ -73,6 +73,7 @@
#include "interfaces.h"
#include "pseudotcp.h"
#include "agent-enum-types.h"
/* Maximum size of a UDP packet’s payload, as the packet’s length field is 16b
* wide. */
......@@ -113,6 +114,7 @@ enum
PROP_BYTESTREAM_TCP,
PROP_KEEPALIVE_CONNCHECK,
PROP_FORCE_RELAY,
PROP_NOMINATION_MODE,
};
......@@ -436,6 +438,24 @@ nice_agent_class_init (NiceAgentClass *klass)
0, /* default set in init */
G_PARAM_READWRITE));
/**
* NiceAgent:nomination-mode:
*
* The nomination mode used in the ICE specification for describing
* the selection of valid pairs to be used upstream.
* <para> See also: #NiceNominationMode </para>
*
* Since: UNRELEASED
*/
g_object_class_install_property (gobject_class, PROP_NOMINATION_MODE,
g_param_spec_enum (
"nomination-mode",
"ICE nomination mode",
"Nomination mode used in the ICE specification for describing "
"the selection of valid pairs to be used upstream",
NICE_TYPE_NOMINATION_MODE, NICE_NOMINATION_MODE_AGGRESSIVE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/**
* NiceAgent:proxy-ip:
*
......@@ -1023,6 +1043,7 @@ nice_agent_init (NiceAgent *agent)
agent->stun_server_port = DEFAULT_STUN_PORT;
agent->controlling_mode = TRUE;
agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
agent->nomination_mode = NICE_NOMINATION_MODE_AGGRESSIVE;
agent->discovery_list = NULL;
agent->discovery_unsched_items = 0;
......@@ -1071,6 +1092,20 @@ nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat)
}
NICEAPI_EXPORT NiceAgent *
nice_agent_new_regular_nomination (GMainContext *ctx, NiceCompatibility compat)
{
NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
"compatibility", compat,
"main-context", ctx,
"reliable", FALSE,
"nomination-mode", NICE_NOMINATION_MODE_REGULAR,
NULL);
return agent;
}
static void
nice_agent_get_property (
GObject *object,
......@@ -1117,6 +1152,10 @@ nice_agent_get_property (
/* XXX: should we prune the list of already existing checks? */
break;
case PROP_NOMINATION_MODE:
g_value_set_enum (value, agent->nomination_mode);
break;
case PROP_PROXY_IP:
g_value_set_string (value, agent->proxy_ip);
break;
......@@ -1309,6 +1348,10 @@ nice_agent_set_property (
agent->max_conn_checks = g_value_get_uint (value);
break;
case PROP_NOMINATION_MODE:
agent->nomination_mode = g_value_get_enum (value);
break;
case PROP_PROXY_IP:
g_free (agent->proxy_ip);
agent->proxy_ip = g_value_dup_string (value);
......@@ -3201,6 +3244,19 @@ static gboolean priv_add_remote_candidate (
username, password, priority);
}
if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
/* note: If there are TCP candidates for a media stream,
* a controlling agent MUST use the regular selection algorithm,
* RFC 6544, sect 8, "Concluding ICE Processing"
*/
if (agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE &&
transport != NICE_CANDIDATE_TRANSPORT_UDP) {
nice_debug ("Agent %p : we have TCP candidates, switching back "
"to regular nomination mode", agent);
agent->nomination_mode = NICE_NOMINATION_MODE_REGULAR;
}
}
if (base_addr)
candidate->base_addr = *base_addr;
......
......@@ -377,6 +377,26 @@ typedef enum
NICE_PROXY_TYPE_LAST = NICE_PROXY_TYPE_HTTP,
} NiceProxyType;
/**
* NiceNominationMode:
* @NICE_NOMINATION_MODE_AGGRESSIVE: Aggressive nomination mode
* @NICE_NOMINATION_MODE_REGULAR: Regular nomination mode
*
* An enum to specity the kind of nomination mode to use by
* the agent, as described in RFC 5245. Two modes exists,
* regular and aggressive. They differ by the way the controlling
* agent chooses to put the USE-CANDIDATE attribute in its STUN
* messages. The aggressive mode is supposed to nominate a pair
* faster, than the regular mode, potentially causing the nominated
* pair to change until the connection check completes.
*
* Since: UNRELEASED
*/
typedef enum
{
NICE_NOMINATION_MODE_REGULAR = 0,
NICE_NOMINATION_MODE_AGGRESSIVE,
} NiceNominationMode;
/**
* NiceAgentRecvFunc:
......@@ -428,6 +448,26 @@ nice_agent_new (GMainContext *ctx, NiceCompatibility compat);
NiceAgent *
nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat);
/**
* nice_agent_new_regular_nomination:
* @ctx: The Glib Mainloop Context to use for timers
* @compat: The compatibility mode of the agent
*
* Create a new #NiceAgent with regular nomination mode. The nomination
* mode is defined in the ICE specification and decribes the way pairs of
* connection candidates are selected by the agents. Two modes are
* available, aggressive and regular. libnice default mode is
* aggressive.
* The returned object must be freed with g_object_unref()
* <para> See also: #NiceNominationMode </para>
*
* Since: UNRELEASED
*
* Returns: The new agent GObject
*/
NiceAgent *
nice_agent_new_regular_nomination (GMainContext *ctx, NiceCompatibility compat);
/**
* nice_agent_add_local_address:
* @agent: The #NiceAgent Object
......
This diff is collapsed.
......@@ -87,6 +87,8 @@ struct _CandidateCheckPair
gboolean nominated;
gboolean timer_restarted;
gboolean valid;
gboolean use_candidate_on_next_check;
gboolean mark_nominated_on_response_arrival;
guint64 priority;
guint32 prflx_priority;
GTimeVal next_tick; /* next tick timestamp */
......
......@@ -57,6 +57,7 @@ AC_PROG_CC
AM_PROG_AR
LT_PREREQ([2.2.6])
LT_INIT([dlopen win32-dll disable-static])
AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums])
# Check Operating System
AC_MSG_CHECKING([operating system])
......
......@@ -5,6 +5,7 @@ NiceAgent
NiceComponentState
NiceComponentType
NiceProxyType
NiceNominationMode
NiceCompatibility
NiceAgentRecvFunc
NiceInputMessage
......@@ -12,6 +13,7 @@ NiceOutputMessage
NICE_AGENT_MAX_REMOTE_CANDIDATES
nice_agent_new
nice_agent_new_reliable
nice_agent_new_regular_nomination
nice_agent_add_local_address
nice_agent_set_port_range
nice_agent_add_stream
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment