Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
libnice
libnice
Commits
02ff6c5f
Commit
02ff6c5f
authored
Apr 24, 2009
by
Youness Alaoui
Browse files
Add UPnP support to libnice
parent
c4968e09
Changes
8
Hide whitespace changes
Inline
Side-by-side
agent/Makefile.am
View file @
02ff6c5f
...
...
@@ -12,12 +12,13 @@ AM_CFLAGS = \
-DG_LOG_DOMAIN
=
\"
libnice
\"
\
$(ERROR_CFLAGS)
\
$(GLIB_CFLAGS)
\
$(GUPNP_CFLAGS)
\
-I
$(top_srcdir)
\
-I
$(top_srcdir)
/random
\
-I
$(top_srcdir)
/socket
\
-I
$(top_srcdir)
/stun
COMMON_LDADD
=
libagent.la
$(GLIB_LIBS)
COMMON_LDADD
=
libagent.la
$(GLIB_LIBS)
(
GUPNP_LIBS
)
dist_noinst_DATA
=
agent-signals-marshal.list
noinst_LTLIBRARIES
=
libagent.la
...
...
agent/agent-priv.h
View file @
02ff6c5f
...
...
@@ -41,6 +41,13 @@
/* note: this is a private header part of agent.h */
#ifdef HAVE_CONFIG_H
# include <config.h>
#else
#define NICEAPI_EXPORT
#endif
#include
<glib.h>
#include
"agent.h"
...
...
@@ -53,6 +60,10 @@
#include
"stun/usages/turn.h"
#include
"stun/usages/ice.h"
#ifdef HAVE_GUPNP
#include
<libgupnp-igd/gupnp-simple-igd.h>
#endif
/* XXX: starting from ICE ID-18, Ta SHOULD now be set according
* to session bandwidth -> this is not yet implemented in NICE */
...
...
@@ -101,6 +112,13 @@ struct _NiceAgent
GStaticRecMutex
mutex
;
/* Mutex used for thread-safe lib */
NiceCompatibility
compatibility
;
/* property: Compatibility mode */
StunAgent
stun_agent
;
/* STUN agent */
#ifdef HAVE_GUPNP
GUPnPSimpleIgd
*
upnp
;
/* GUPnP Single IGD agent */
gboolean
upnp_enabled
;
/* whether UPnP discovery is enabled */
guint
upnp_timeout
;
/* UPnP discovery timeout */
GSList
*
upnp_mapping
;
/* list of Candidates being mapped */
GSource
*
upnp_timer_source
;
/* source of upnp timeout timer */
#endif
/* XXX: add pointer to internal data struct for ABI-safe extensions */
};
...
...
agent/agent.c
View file @
02ff6c5f
...
...
@@ -94,7 +94,11 @@ enum
PROP_PROXY_IP
,
PROP_PROXY_PORT
,
PROP_PROXY_USERNAME
,
PROP_PROXY_PASSWORD
PROP_PROXY_PASSWORD
,
#ifdef HAVE_GUPNP
PROP_UPNP
,
PROP_UPNP_TIMEOUT
#endif
};
...
...
@@ -116,6 +120,8 @@ static gboolean priv_attach_stream_component (NiceAgent *agent,
Component
*
component
);
static
void
priv_detach_stream_component
(
Stream
*
stream
,
Component
*
component
);
static
void
priv_free_upnp
(
NiceAgent
*
agent
);
StunUsageIceCompatibility
agent_to_ice_compatibility
(
NiceAgent
*
agent
)
{
...
...
@@ -292,7 +298,7 @@ nice_agent_class_init (NiceAgentClass *klass)
"stun-pacing-timer"
,
"STUN pacing timer"
,
"Timer 'Ta' (msecs) used in the IETF ICE specification for pacing candidate gathering and sending of connectivity checks"
,
1
,
0xffffffff
,
1
,
0xffffffff
,
NICE_AGENT_TIMER_TA_DEFAULT
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
));
...
...
@@ -302,7 +308,7 @@ nice_agent_class_init (NiceAgentClass *klass)
"max-connectivity-checks"
,
"Maximum number of connectivity checks"
,
"Upper limit for the total number of connectivity checks performed"
,
0
,
0xffffffff
,
0
,
0xffffffff
,
0
,
/* default set in init */
G_PARAM_READWRITE
));
...
...
@@ -348,6 +354,27 @@ nice_agent_class_init (NiceAgentClass *klass)
NULL
,
G_PARAM_READWRITE
));
#ifdef HAVE_GUPNP
g_object_class_install_property
(
gobject_class
,
PROP_UPNP
,
g_param_spec_boolean
(
"upnp"
,
"Use UPnP"
,
"Whether the agent should use UPnP to open a port in the router and "
"get the external IP"
,
TRUE
,
/* enable UPnP by default */
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
));
g_object_class_install_property
(
gobject_class
,
PROP_UPNP_TIMEOUT
,
g_param_spec_uint
(
"upnp-timeout"
,
"Timeout for UPnP discovery"
,
"The maximum amount of time to wait for UPnP discovery to finish before "
"signaling the candidate-gathering-done signal"
,
100
,
60000
,
2000
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
));
#endif
/* install signals */
/**
...
...
@@ -603,6 +630,16 @@ nice_agent_get_property (
g_value_set_string
(
value
,
agent
->
proxy_password
);
break
;
#ifdef HAVE_GUPNP
case
PROP_UPNP
:
g_value_set_boolean
(
value
,
agent
->
upnp_enabled
);
break
;
case
PROP_UPNP_TIMEOUT
:
g_value_set_uint
(
value
,
agent
->
upnp_timeout
);
break
;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
property_id
,
pspec
);
}
...
...
@@ -698,6 +735,15 @@ nice_agent_set_property (
agent
->
proxy_password
=
g_value_dup_string
(
value
);
break
;
#ifdef HAVE_GUPNP
case
PROP_UPNP_TIMEOUT
:
agent
->
upnp_timeout
=
g_value_get_uint
(
value
);
break
;
case
PROP_UPNP
:
agent
->
upnp_enabled
=
g_value_get_boolean
(
value
);
break
;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
property_id
,
pspec
);
}
...
...
@@ -744,7 +790,10 @@ void agent_gathering_done (NiceAgent *agent)
}
}
agent_signal_gathering_done
(
agent
);
if
(
agent
->
discovery_timer_source
==
NULL
&&
agent
->
upnp_timer_source
==
NULL
)
{
agent_signal_gathering_done
(
agent
);
}
}
void
agent_signal_gathering_done
(
NiceAgent
*
agent
)
...
...
@@ -932,7 +981,6 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
socket
=
nice_http_socket_new
(
socket
,
&
turn
->
server
,
agent
->
proxy_username
,
agent
->
proxy_password
);
}
else
{
/* TODO add HTTP support */
nice_socket_free
(
socket
);
socket
=
NULL
;
}
...
...
@@ -1077,6 +1125,136 @@ nice_agent_set_relay_info(NiceAgent *agent,
return
TRUE
;
}
#ifdef HAVE_GUPNP
static
gboolean
priv_upnp_timeout_cb
(
gpointer
user_data
)
{
NiceAgent
*
agent
=
(
NiceAgent
*
)
user_data
;
GSList
*
i
;
g_static_rec_mutex_lock
(
&
agent
->
mutex
);
nice_debug
(
"Agent %p : UPnP port mapping timed out"
,
agent
);
for
(
i
=
agent
->
upnp_mapping
;
i
;
i
=
i
->
next
)
{
NiceAddress
*
a
=
i
->
data
;
nice_address_free
(
a
);
}
g_slist_free
(
agent
->
upnp_mapping
);
agent
->
upnp_mapping
=
NULL
;
if
(
agent
->
upnp_timer_source
!=
NULL
)
{
g_source_destroy
(
agent
->
upnp_timer_source
);
g_source_unref
(
agent
->
upnp_timer_source
);
agent
->
upnp_timer_source
=
NULL
;
}
agent_gathering_done
(
agent
);
g_static_rec_mutex_unlock
(
&
agent
->
mutex
);
return
FALSE
;
}
static
void
_upnp_mapped_external_port
(
GUPnPSimpleIgd
*
self
,
gchar
*
proto
,
gchar
*
external_ip
,
gchar
*
replaces_external_ip
,
guint
external_port
,
gchar
*
local_ip
,
guint
local_port
,
gchar
*
description
,
gpointer
user_data
)
{
NiceAgent
*
agent
=
(
NiceAgent
*
)
user_data
;
NiceAddress
localaddr
;
NiceAddress
externaddr
;
GSList
*
i
,
*
j
,
*
k
;
g_static_rec_mutex_lock
(
&
agent
->
mutex
);
nice_debug
(
"Agent %p : Sucessfully mapped %s:%d to %s:%d"
,
agent
,
local_ip
,
local_port
,
external_ip
,
external_port
);
nice_address_set_from_string
(
&
localaddr
,
local_ip
);
nice_address_set_port
(
&
localaddr
,
local_port
);
nice_address_set_from_string
(
&
externaddr
,
external_ip
);
nice_address_set_port
(
&
externaddr
,
external_port
);
for
(
i
=
agent
->
upnp_mapping
;
i
;
i
=
i
->
next
)
{
NiceAddress
*
addr
=
i
->
data
;
if
(
nice_address_equal
(
&
localaddr
,
addr
))
{
agent
->
upnp_mapping
=
g_slist_remove
(
agent
->
upnp_mapping
,
addr
);
nice_address_free
(
addr
);
break
;
}
}
for
(
i
=
agent
->
streams
;
i
;
i
=
i
->
next
)
{
Stream
*
stream
=
i
->
data
;
for
(
j
=
stream
->
components
;
j
;
j
=
j
->
next
)
{
Component
*
component
=
j
->
data
;
for
(
k
=
component
->
local_candidates
;
k
;
k
=
k
->
next
)
{
NiceCandidate
*
local_candidate
=
k
->
data
;
if
(
nice_address_equal
(
&
localaddr
,
&
local_candidate
->
base_addr
))
{
discovery_add_server_reflexive_candidate
(
agent
,
stream
->
id
,
component
->
id
,
&
externaddr
,
local_candidate
->
sockptr
);
goto
end
;
}
}
}
}
end:
if
(
g_slist_length
(
agent
->
upnp_mapping
))
{
if
(
agent
->
upnp_timer_source
!=
NULL
)
{
g_source_destroy
(
agent
->
upnp_timer_source
);
g_source_unref
(
agent
->
upnp_timer_source
);
agent
->
upnp_timer_source
=
NULL
;
}
agent_gathering_done
(
agent
);
}
g_static_rec_mutex_unlock
(
&
agent
->
mutex
);
}
static
void
_upnp_error_mapping_port
(
GUPnPSimpleIgd
*
self
,
GError
*
error
,
gchar
*
proto
,
guint
external_port
,
gchar
*
local_ip
,
guint
local_port
,
gchar
*
description
,
gpointer
user_data
)
{
NiceAgent
*
agent
=
(
NiceAgent
*
)
user_data
;
NiceAddress
localaddr
;
GSList
*
i
;
g_static_rec_mutex_lock
(
&
agent
->
mutex
);
nice_debug
(
"Agent %p : Error mapping %s:%d to %d (%d) : %s"
,
agent
,
local_ip
,
local_port
,
external_port
,
error
->
domain
,
error
->
message
);
nice_address_set_from_string
(
&
localaddr
,
local_ip
);
nice_address_set_port
(
&
localaddr
,
local_port
);
for
(
i
=
agent
->
upnp_mapping
;
i
;
i
=
i
->
next
)
{
NiceAddress
*
addr
=
i
->
data
;
if
(
nice_address_equal
(
&
localaddr
,
addr
))
{
agent
->
upnp_mapping
=
g_slist_remove
(
agent
->
upnp_mapping
,
addr
);
nice_address_free
(
addr
);
break
;
}
}
if
(
g_slist_length
(
agent
->
upnp_mapping
))
{
if
(
agent
->
upnp_timer_source
!=
NULL
)
{
g_source_destroy
(
agent
->
upnp_timer_source
);
g_source_unref
(
agent
->
upnp_timer_source
);
agent
->
upnp_timer_source
=
NULL
;
}
agent_gathering_done
(
agent
);
}
g_static_rec_mutex_unlock
(
&
agent
->
mutex
);
}
#endif
NICEAPI_EXPORT
void
nice_agent_gather_candidates
(
...
...
@@ -1097,6 +1275,31 @@ nice_agent_gather_candidates (
nice_debug
(
"Agent %p : In %s mode, starting candidate gathering."
,
agent
,
agent
->
full_mode
?
"ICE-FULL"
:
"ICE-LITE"
);
#ifdef HAVE_GUPNP
priv_free_upnp
(
agent
);
if
(
agent
->
upnp_enabled
)
{
agent
->
upnp
=
gupnp_simple_igd_new
(
agent
->
main_context
);
agent
->
upnp_timer_source
=
agent_timeout_add_with_context
(
agent
,
agent
->
upnp_timeout
,
priv_upnp_timeout_cb
,
agent
);
g_object_set
(
agent
->
upnp
,
"request-timeout"
,
1
,
NULL
);
if
(
agent
->
upnp
)
{
g_signal_connect
(
agent
->
upnp
,
"mapped-external-port"
,
G_CALLBACK
(
_upnp_mapped_external_port
),
agent
);
g_signal_connect
(
agent
->
upnp
,
"error-mapping-port"
,
G_CALLBACK
(
_upnp_error_mapping_port
),
agent
);
}
else
{
nice_debug
(
"Agent %p : Error creating UPnP Simple IGD agent"
,
agent
);
}
}
else
{
nice_debug
(
"Agent %p : UPnP property Disabled"
,
agent
);
}
#else
nice_debug
(
"Agent %p : libnice compiled without UPnP support"
,
agent
);
#endif
/* if no local addresses added, generate them ourselves */
if
(
agent
->
local_addresses
==
NULL
)
{
GList
*
addresses
=
nice_interfaces_get_local_ips
(
FALSE
);
...
...
@@ -1120,6 +1323,11 @@ nice_agent_gather_candidates (
NiceAddress
*
addr
=
i
->
data
;
NiceCandidate
*
host_candidate
;
#ifdef HAVE_GUPNP
gchar
local_ip
[
NICE_ADDRESS_STRING_LEN
];
nice_address_to_string
(
addr
,
local_ip
);
#endif
for
(
n
=
0
;
n
<
stream
->
n_components
;
n
++
)
{
Component
*
component
=
stream_find_component_by_id
(
stream
,
n
+
1
);
host_candidate
=
discovery_add_local_host_candidate
(
agent
,
stream
->
id
,
...
...
@@ -1130,11 +1338,23 @@ nice_agent_gather_candidates (
break
;
}
#ifdef HAVE_GUPNP
if
(
agent
->
upnp_enabled
)
{
NiceAddress
*
addr
=
nice_address_dup
(
&
host_candidate
->
base_addr
);
nice_debug
(
"Agent %p: Adding UPnP port %s:%d"
,
agent
,
local_ip
,
nice_address_get_port
(
&
host_candidate
->
base_addr
));
gupnp_simple_igd_add_port
(
agent
->
upnp
,
"UDP"
,
nice_address_get_port
(
&
host_candidate
->
base_addr
),
local_ip
,
0
,
6000
,
PACKAGE_STRING
);
agent
->
upnp_mapping
=
g_slist_prepend
(
agent
->
upnp_mapping
,
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
))
{
gboolean
res
;
gboolean
res
;
nice_address_set_port
(
&
stun_server
,
agent
->
stun_server_port
);
res
=
...
...
@@ -1191,6 +1411,31 @@ nice_agent_gather_candidates (
g_static_rec_mutex_unlock
(
&
agent
->
mutex
);
}
static
void
priv_free_upnp
(
NiceAgent
*
agent
)
{
GSList
*
i
;
#ifdef HAVE_GUPNP
if
(
agent
->
upnp
)
{
g_object_unref
(
agent
->
upnp
);
agent
->
upnp
=
NULL
;
}
for
(
i
=
agent
->
upnp_mapping
;
i
;
i
=
i
->
next
)
{
NiceAddress
*
a
=
i
->
data
;
nice_address_free
(
a
);
}
g_slist_free
(
agent
->
upnp_mapping
);
agent
->
upnp_mapping
=
NULL
;
if
(
agent
->
upnp_timer_source
!=
NULL
)
{
g_source_destroy
(
agent
->
upnp_timer_source
);
g_source_unref
(
agent
->
upnp_timer_source
);
agent
->
upnp_timer_source
=
NULL
;
}
#endif
}
static
void
priv_remove_keepalive_timer
(
NiceAgent
*
agent
)
{
if
(
agent
->
keepalive_timer_source
!=
NULL
)
{
...
...
@@ -1660,6 +1905,7 @@ nice_agent_restart (
return
res
;
}
static
void
nice_agent_dispose
(
GObject
*
object
)
{
...
...
@@ -1703,6 +1949,8 @@ nice_agent_dispose (GObject *object)
nice_rng_free
(
agent
->
rng
);
agent
->
rng
=
NULL
;
priv_free_upnp
(
agent
);
if
(
G_OBJECT_CLASS
(
nice_agent_parent_class
)
->
dispose
)
G_OBJECT_CLASS
(
nice_agent_parent_class
)
->
dispose
(
object
);
...
...
agent/discovery.c
View file @
02ff6c5f
...
...
@@ -102,7 +102,7 @@ void discovery_free (NiceAgent *agent)
/*
* Prunes the list of discovery processes for items related
* to stream 'stream_id'.
* to stream 'stream_id'.
*
* @return TRUE on success, FALSE on a fatal error
*/
...
...
@@ -316,7 +316,7 @@ static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate)
}
}
}
g_snprintf
(
candidate
->
foundation
,
NICE_CANDIDATE_MAX_FOUNDATION
,
"%u"
,
agent
->
next_candidate_id
++
);
}
...
...
@@ -436,7 +436,7 @@ NiceCandidate *discovery_add_local_host_candidate (
if
(
udp_socket
)
nice_socket_free
(
udp_socket
);
}
return
candidate
;
}
...
...
@@ -446,7 +446,7 @@ NiceCandidate *discovery_add_local_host_candidate (
*
* @return pointer to the created candidate, or NULL on error
*/
NiceCandidate
*
NiceCandidate
*
discovery_add_server_reflexive_candidate
(
NiceAgent
*
agent
,
guint
stream_id
,
...
...
configure.ac
View file @
02ff6c5f
...
...
@@ -66,7 +66,6 @@ AC_CHECK_LIB(rt, clock_gettime, [LIBRT="-lrt"], [LIBRT=""])
AC_CHECK_FUNCS([poll])
AC_SUBST(LIBRT)
PKG_CHECK_MODULES(GLIB, [dnl
glib-2.0 >= 2.10 dnl
gobject-2.0 >= 2.10 dnl
...
...
@@ -102,6 +101,31 @@ AC_SUBST(gstplugindir)
AM_CONDITIONAL(WITH_GSTREAMER, test "$with_gstreamer" = yes)
AC_ARG_ENABLE([gupnp],
AC_HELP_STRING([--disable-gupnp], [Disable GUPnP IGD support]),
[case "${enableval}" in
yes) WANT_GUPNP=yes ;;
no) WANT_GUPNP=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-gupnp) ;;
esac],
WANT_GUPNP=test)
HAVE_GUPNP=no
if test "x$WANT_GUPNP" != "xno"; then
PKG_CHECK_MODULES(GUPNP, [ gupnp-igd-1.0 ],
[ HAVE_GUPNP=yes ],
[ HAVE_GUPNP=no ])
fi
if test "x$WANT_GUPNP" = "xyes" && test "x$HAVE_GUPNP" = "xno"; then
AC_ERROR([Requested GUPnP IGD, but it is not available])
fi
if test "x$HAVE_GUPNP" = "xyes"; then
AC_DEFINE(HAVE_GUPNP,,[Have the GUPnP IGD library])
fi
AC_SUBST(HAVE_GUPNP)
dnl Test coverage
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],
...
...
socket/Makefile.am
View file @
02ff6c5f
...
...
@@ -12,6 +12,7 @@ AM_CFLAGS = \
-DG_LOG_DOMAIN
=
\"
libnice-socket
\"
\
$(ERROR_CFLAGS)
\
$(GLIB_CFLAGS)
\
$(GUPNP_CFLAGS)
\
-I
$(top_srcdir)
/random
\
-I
$(top_srcdir)
/agent
\
-I
$(top_srcdir)
/
...
...
tests/Makefile.am
View file @
02ff6c5f
...
...
@@ -11,13 +11,14 @@ include $(top_srcdir)/common.mk
AM_CFLAGS
=
\
$(ERROR_CFLAGS)
\
$(GLIB_CFLAGS)
\
$(GUPNP_CFLAGS)
\
-I
$(top_srcdir)
\
-I
$(top_srcdir)
/agent
\
-I
$(top_srcdir)
/random
\
-I
$(top_srcdir)
/socket
\
-I
$(top_srcdir)
/stun
COMMON_LDADD
=
$(top_builddir)
/agent/libagent.la
$(top_builddir)
/socket/libsocket.la
$(GLIB_LIBS)
COMMON_LDADD
=
$(top_builddir)
/agent/libagent.la
$(top_builddir)
/socket/libsocket.la
$(GLIB_LIBS)
$(GUPNP_LIBS)
check_PROGRAMS
=
\
test-bsd
\
...
...
tests/test-thread.c
View file @
02ff6c5f
...
...
@@ -214,6 +214,8 @@ int main (void)
g_object_set
(
G_OBJECT
(
lagent
),
"controlling-mode"
,
TRUE
,
NULL
);
g_object_set
(
G_OBJECT
(
ragent
),
"controlling-mode"
,
FALSE
,
NULL
);
g_object_set
(
G_OBJECT
(
lagent
),
"upnp"
,
FALSE
,
NULL
);
g_object_set
(
G_OBJECT
(
ragent
),
"upnp"
,
FALSE
,
NULL
);
/* step: add a timer to catch state changes triggered by signals */
timer_id
=
g_timeout_add
(
30000
,
timer_cb
,
NULL
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment