Commit 59d38c8c authored by Stepan Salenikovich's avatar Stepan Salenikovich

upnp: migrate to libupnp

Removes libminiupnpc as a dependency.
Adds libupnp into the contrib system.
Accounts with upnp enabled asynchronously wait to
find an IGD (or timeout) before completing
registration.

Refs #65376
Refs #65382

Change-Id: I44376e49c078a0e33a8bb92ee2ca8e4df09f6fec
parent d9ec86a6
......@@ -531,60 +531,17 @@ AC_ARG_ENABLE([ipv6], AS_HELP_STRING([--enable-ipv6], [Enable IPv6 support]))
AC_DEFINE_UNQUOTED([HAVE_IPV6], `if test "x$enable_ipv6" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have IPv6])
AM_CONDITIONAL(BUILD_IPV6, test "x$enable_ipv6" = "xyes" )
# miniupnpc
# required dependency(ies): libminiupc
dnl check for libminiupnpc (doesn't use pkg-config)
# LIBUPNP
dnl check for libupnp
AC_ARG_WITH([upnp], [AS_HELP_STRING([--without-upnp],
[disable support for upnp])], [], [with_upnp=yes])
LIBMINIUPNPC=
AS_IF([test "x$with_upnp" != xno],
[AC_CHECK_HEADER([miniupnpc/miniupnpc.h], , AC_MSG_FAILURE([Unable to find libminiupnpc headers (you may need to install the dev package). You may use --without-upnp to compile without upnp support.]))]
[AC_CHECK_LIB([miniupnpc], [simpleUPnPcommand], [
UPNP_LIBS=-lminiupnpc
AC_SUBST(UPNP_LIBS)
miniupnp_version="unknown"],
[AC_MSG_FAILURE([libminiupnpc link test failed. You may use --without-upnp to compile without upnp support.])
miniupnp_version="none"
AC_DEFINE([HAVE_UPNP], 0, [Define if you have miniupnpc])]
)],
[AC_DEFINE([HAVE_UPNP], 0, [Define if you have miniupnpc])])
dnl need to determine API version
dnl if libminiupnpc is v1.7 or higher, then the API version should be defined
if test "x$miniupnp_version" = "xunknown" ; then
AC_MSG_CHECKING("if libminiupnpc is v1.7 or higher to determine API version")
AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[#include <stdlib.h>
#include <miniupnpc/miniupnpc.h>],
[#ifdef MINIUPNPC_API_VERSION
return EXIT_SUCCESS;
#else
return EXIT_FAILURE;
#endif]
)],
[miniupnp_version=">= 1.7"
AC_MSG_RESULT("found v1.7 or higher")
AC_DEFINE([HAVE_UPNP], 1, [Define if you have miniupnpc])],
[AC_MSG_RESULT("found v1.6 or lower")])
fi
dnl otherwise it must be v1.6 or lower; we don't support lower than v1.6, which is API v8
dnl v1.6 introduced IPv6 commands, so we check for one of them
if test "x$miniupnp_version" = "xunknown" ; then
AC_MSG_CHECKING("if libminiupnpc is at least v1.6")
AC_CHECK_LIB([miniupnpc], [UPNP_GetFirewallStatus],[
miniupnp_version="1.6"
AC_DEFINE(MINIUPNPC_API_VERSION, 8, [libminiupnpc 1.6 has API version 8])
AC_MSG_RESULT("detected libminiupnpc is v1.6")
AC_DEFINE([HAVE_UPNP], 1, [Define if you have miniupnpc])],
[AC_DEFINE([HAVE_UPNP], 0, [Define if you have miniupnpc])
AC_MSG_RESULT("detected libminiupnpc is lower than v1.6")
AC_MSG_FAILURE([libminiupnpc less than v1.6 is not supported])])
fi
AM_CONDITIONAL(BUILD_UPNP, test "x$with_upnp" = "xyes" )
AS_IF([test "x$with_upnp" = "xyes"],
[PKG_CHECK_MODULES(LIBUPNP, [libupnp],
[AC_DEFINE([HAVE_LIBUPNP], 1, [Define if you have libupnp])],
[AC_MSG_WARN([Missing libupnp development files])
AC_DEFINE([HAVE_LIBUPNP], 0, [Define if you have libupnp])])
])
# DOXYGEN
# required dependency(ies): doxygen
......
7994749fa92e6478285dada191f4ad0d15fdce6cf281ee4d1d3d5615548338d68be3b9ce96a04ef4b81c697589689398060cc6f610101fa1d0e6f9e24b7850a9 miniupnpc-1.9.tar.gz
--- a/Makefile 2015-01-05 15:45:40.426809962 -0500
+++ b/Makefile 2015-01-05 15:48:24.470817044 -0500
@@ -212,6 +212,13 @@
endif
endif
+install-static: updateversion $(FILESTOINSTALL)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
+ $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
+ $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
cleaninstall:
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
# miniupnpc
MINIUPNPC_VERSION := 1.9
MINIUPNPC_URL := http://miniupnp.free.fr/files/download.php?file=miniupnpc-$(MINIUPNPC_VERSION).tar.gz
PKGS += miniupnpc
ifeq ($(call need_pkg,"miniupnpc >= 1.6"),)
PKGS_FOUND += miniupnpc
endif
$(TARBALLS)/miniupnpc-$(MINIUPNPC_VERSION).tar.gz:
$(call download,$(MINIUPNPC_URL))
.sum-miniupnpc: miniupnpc-$(MINIUPNPC_VERSION).tar.gz
$(warning $@ not implemented)
touch $@
miniupnpc: miniupnpc-$(MINIUPNPC_VERSION).tar.gz .sum-miniupnpc
$(UNPACK)
$(APPLY) $(SRC)/miniupnpc/makefile.patch
$(UPDATE_AUTOCONFIG) && cd $(UNPACK_DIR)
$(MOVE)
.miniupnpc: miniupnpc
cd $< && INSTALLPREFIX=$(PREFIX) $(MAKE) install-static
touch $@
97af62a7483cc19cfe80157cbc3383c1b4b7c9c39b848f4ed063784b74df0b9b0527f7b467e01451e0a44dbf9e8a9eab510619146a6ee1e3dce46f3e4af6e661 libupnp-1.6.19.tar.bz2
--- libupnp/configure.ac.orig 2011-02-09 00:55:44.000000000 +0100
+++ libupnp/configure.ac 2011-02-10 23:39:44.154929678 +0100
@@ -397,7 +397,6 @@
AC_PROG_MAKE_SET
AC_PROG_EGREP
-#
# Default compilation flags
#
echo "--------------------- Default compilation flags -------------------------------"
@@ -531,39 +530,46 @@
# Checks for POSIX Threads
#
echo "--------------------------- pthread stuff -------------------------------------"
-ACX_PTHREAD(
- [],
- [AC_MSG_ERROR([POSIX threads are required to build this program])])
+#ACX_PTHREAD(
+# [],
+# [AC_MSG_ERROR([POSIX threads are required to build this program])])
#
+PTHREAD_LIBS=" -lpthreadGC2 -lws2_32"
+PTHREAD_CFLAGS=" -DPTW32_STATIC_LIB -DUPNP_STATIC_LIB"
# Update environment variables for pthreads
#
-CC="$PTHREAD_CC"
+#CC="$PTHREAD_CC"
CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
#
# Determine if pthread_rwlock_t is available
#
-echo "----------------------- pthread_rwlock_t stuff --------------------------------"
-AC_MSG_CHECKING([if pthread_rwlock_t is available])
-AC_LANG([C])
-AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM(
- [#include <pthread.h>],
- [pthread_rwlock_t *x;])],
- [AC_DEFINE([UPNP_USE_RWLOCK], [1], [Use pthread_rwlock_t])
- AC_MSG_RESULT([yes, supported without any options])],
- [AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM(
- [#define _GNU_SOURCE
- #include <pthread.h>],
- [pthread_rwlock_t *x;])],
- [AC_DEFINE([UPNP_USE_RWLOCK], [1], [Use pthread_rwlock_t])
- CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
- AC_MSG_RESULT([yes, definition of _GNU_SOURCE required])],
- [AC_DEFINE([UPNP_USE_RWLOCK], [0], [Do not use pthread_rwlock_t])
- AC_MSG_RESULT([no, needs to fallback to pthread_mutex])
- AC_MSG_ERROR([pthread_rwlock_t not available])])])
-echo "-------------------------------------------------------------------------------"
+#echo "----------------------- pthread_rwlock_t stuff --------------------------------"
+#AC_MSG_CHECKING([if pthread_rwlock_t is available])
+#AC_LANG([C])
+#AC_COMPILE_IFELSE(
+# [AC_LANG_PROGRAM(
+# [#include <pthread.h>],
+# [pthread_rwlock_t *x;])],
+# [AC_DEFINE([UPNP_USE_RWLOCK], [1], [Use pthread_rwlock_t])
+# AC_MSG_RESULT([yes, supported without any options])],
+# [AC_COMPILE_IFELSE(
+# [AC_LANG_PROGRAM(
+# [#define _GNU_SOURCE
+# #include <pthread.h>],
+# [pthread_rwlock_t *x;])],
+# [AC_DEFINE([UPNP_USE_RWLOCK], [1], [Use pthread_rwlock_t])
+# CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+# AC_MSG_RESULT([yes, definition of _GNU_SOURCE required])],
+# [AC_DEFINE([UPNP_USE_RWLOCK], [0], [Do not use pthread_rwlock_t])
+# AC_MSG_RESULT([no, needs to fallback to pthread_mutex])
+# AC_MSG_ERROR([pthread_rwlock_t not available])])])
+#echo "-------------------------------------------------------------------------------"
AC_CONFIG_FILES([
From 438ace99538713fb1370411188e0f370069a1818 Mon Sep 17 00:00:00 2001
From: Konstantin Pavlov <thresh@videolan.org>
Date: Tue, 29 May 2012 10:18:40 +0400
Subject: [PATCH] Fix compile under mingw with IPv6 enabled.
---
upnp/src/genlib/miniserver/miniserver.c | 7 +++++++
upnp/src/ssdp/ssdp_server.c | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/upnp/src/genlib/miniserver/miniserver.c b/upnp/src/genlib/miniserver/miniserver.c
index af310ca..1ae422f 100644
--- a/upnp/src/genlib/miniserver/miniserver.c
+++ b/upnp/src/genlib/miniserver/miniserver.c
@@ -68,6 +68,13 @@
/*! . */
#define APPLICATION_LISTENING_PORT 49152
+/* IPV6_V6ONLY is missing from MinGW, hack taken from
+ * http://svn.apache.org/repos/asf/apr/apr/trunk/network_io/win32/sockopt.c
+ */
+#ifndef IPV6_V6ONLY
+#define IPV6_V6ONLY 27
+#endif
+
struct mserv_request_t {
/*! Connection handle. */
SOCKET connfd;
diff --git a/upnp/src/ssdp/ssdp_server.c b/upnp/src/ssdp/ssdp_server.c
index 231c2c5..6a9c27f 100644
--- a/upnp/src/ssdp/ssdp_server.c
+++ b/upnp/src/ssdp/ssdp_server.c
@@ -69,6 +69,13 @@
#endif /* UPNP_ENABLE_IPV6 */
#endif /* INCLUDE_CLIENT_APIS */
+/* IPV6_V6ONLY is missing from MinGW, hack taken from
+ * http://svn.apache.org/repos/asf/apr/apr/trunk/network_io/win32/sockopt.c
+ */
+#ifndef IPV6_V6ONLY
+#define IPV6_V6ONLY 27
+#endif
+
void RequestHandler();
enum Listener {
--
1.7.9.7
--- libupnp/configure.ac.orig 2011-02-10 23:53:25.000000000 +0100
+++ libupnp/configure.ac 2011-02-10 23:54:23.574454501 +0100
@@ -546,6 +546,7 @@
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
+AC_DEFINE([_WIN32_WINNT], 0x0501, [Define to '0x0500' for Windows 2000 APIs.])
#
# Determine if pthread_rwlock_t is available
#
--- libupnp/libupnp.pc.in 2010-12-23 21:24:05.000000000 +0100
+++ libupnp.new/libupnp.pc.in 2011-02-13 11:27:23.000000000 +0100
@@ -6,6 +6,6 @@
Name: libupnp
Description: Linux SDK for UPnP Devices
Version: @VERSION@
-Libs: @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ -L${libdir} -lupnp -lthreadutil -lixml
+Libs: @PTHREAD_CFLAGS@ -L${libdir} -lupnp -lthreadutil -lixml -liphlpapi @PTHREAD_LIBS@
Cflags: @PTHREAD_CFLAGS@ -I${includedir}/upnp
--- libupnp/upnp/src/inc/upnputil.h 2010-12-23 21:24:06.000000000 +0100
+++ libupnp.new/upnp/src/inc/upnputil.h 2011-02-13 08:24:24.000000000 +0100
@@ -125,7 +125,7 @@
#define strncasecmp strnicmp
#define sleep(a) Sleep((a)*1000)
#define usleep(a) Sleep((a)/1000)
- #define strerror_r(a,b,c) (strerror_s((b),(c),(a)))
+ #define strerror_r(a,b,c) strncpy( b, strerror(a), c)
#else
#define max(a, b) (((a)>(b))? (a):(b))
#define min(a, b) (((a)<(b))? (a):(b))
--- upnp/upnp/inc/UpnpInet.h 2011-04-03 04:50:36.000000000 +0200
+++ upnp.neww/upnp/inc/UpnpInet.h 2011-11-18 01:54:45.418529337 +0100
@@ -15,11 +15,6 @@
#ifdef WIN32
#include <stdarg.h>
- #ifndef UPNP_USE_MSVCPP
- /* Removed: not required (and cause compilation issues) */
- #include <winbase.h>
- #include <windef.h>
- #endif
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
--- libupnp/threadutil/inc/ThreadPool.h 2011-01-20 07:46:57.000000000 +0100
+++ libupnp.new/threadutil/inc/ThreadPool.h 2011-09-23 01:36:12.000000000 +0200
@@ -45,6 +45,7 @@
#include <errno.h>
#ifdef WIN32
+ #ifndef _TIMEZONE_DEFINED
#include <time.h>
struct timezone
{
@@ -52,6 +53,7 @@
int tz_dsttime; /* type of dst correction */
};
int gettimeofday(struct timeval *tv, struct timezone *tz);
+ #endif
#else /* WIN32 */
#include <sys/param.h>
#include <sys/time.h> /* for gettimeofday() */
--- libupnp-1.6.16/upnp/inc/upnp.h.orig 2012-03-22 00:15:38.000000000 +0100
+++ libupnp-1.6.16/upnp/inc/upnp.h 2012-03-28 18:58:55.043642000 +0200
@@ -61,6 +61,20 @@
/* Other systems ??? */
#endif
+# if defined( __MINGW32__ )
+# if !defined( _OFF_T_ )
+ typedef long long _off_t;
+ typedef _off_t off_t;
+# define _OFF_T_
+# else
+# ifdef off_t
+# undef off_t
+# endif
+# define off_t long long
+# endif
+# endif
+
+
#define LINE_SIZE (size_t)180
#define NAME_SIZE (size_t)256
#define MNFT_NAME_SIZE 64
--- upnp/upnp/src/api/upnpapi.c.orig 2013-04-08 00:23:46.000000000 +0200
+++ upnp/upnp/src/api/upnpapi.c 2013-04-08 00:25:49.000000000 +0200
@@ -358,13 +358,13 @@
return retVal;
}
+#ifdef INTERNAL_WEB_SERVER
#ifdef INCLUDE_DEVICE_APIS
#if EXCLUDE_SOAP == 0
SetSoapCallback(soap_device_callback);
#endif
#endif /* INCLUDE_DEVICE_APIS */
-#ifdef INTERNAL_WEB_SERVER
#if EXCLUDE_GENA == 0
SetGenaCallback(genaCallback);
#endif
# UPNP
UPNP_VERSION := 1.6.19
UPNP_URL := http://sourceforge.net/projects/pupnp/files/pupnp/libUPnP%20$(UPNP_VERSION)/libupnp-$(UPNP_VERSION).tar.bz2/download
PKGS += upnp
ifeq ($(call need_pkg,'libupnp'),)
PKGS_FOUND += upnp
endif
$(TARBALLS)/libupnp-$(UPNP_VERSION).tar.bz2:
$(call download,$(UPNP_URL))
.sum-upnp: libupnp-$(UPNP_VERSION).tar.bz2
ifdef HAVE_WIN32
DEPS_upnp += pthreads $(DEPS_pthreads)
LIBUPNP_ECFLAGS = -DPTW32_STATIC_LIB
endif
upnp: libupnp-$(UPNP_VERSION).tar.bz2 .sum-upnp
$(UNPACK)
ifdef HAVE_WIN32
$(APPLY) $(SRC)/upnp/libupnp-configure.patch
$(APPLY) $(SRC)/upnp/libupnp-win32.patch
$(APPLY) $(SRC)/upnp/libupnp-win64.patch
endif
$(APPLY) $(SRC)/upnp/libupnp-ipv6.patch
$(APPLY) $(SRC)/upnp/miniserver.patch
$(UPDATE_AUTOCONFIG) && cd $(UNPACK_DIR) && mv config.guess config.sub build-aux/
$(MOVE)
.upnp: upnp
ifdef HAVE_WIN32
$(RECONF)
endif
cd $< && $(HOSTVARS) CFLAGS="$(CFLAGS) -DUPNP_STATIC_LIB $(LIBUPNP_ECFLAGS)" ./configure --disable-samples --without-documentation --disable-blocking_tcp_connections $(HOSTCONF)
cd $< && $(MAKE) install
touch $@
......@@ -48,7 +48,7 @@ libring_la_LIBADD = \
./config/libconfig.la \
./hooks/libhooks.la \
./history/libhistory.la \
./upnp/libupnp.la \
./upnp/libupnpcontrol.la \
$(RINGACC_LIBA) \
$(IAX_LIBA) \
$(IM_LIBA) \
......
......@@ -54,7 +54,7 @@
#include <yaml-cpp/yaml.h>
#include "upnp/upnp.h"
#include "upnp/upnp_control.h"
#include "ip_utils.h"
namespace ring {
......@@ -107,7 +107,7 @@ Account::Account(const string &accountID)
, userAgent_(DEFAULT_USER_AGENT)
, hasCustomUserAgent_(false)
, mailBox_()
, upnpEnabled_(false)
, upnp_(new upnp::Controller())
{
std::random_device rdev;
std::seed_seq seed {rdev(), rdev()};
......@@ -222,7 +222,9 @@ void Account::unserialize(const YAML::Node &node)
parseValue(node, RINGTONE_PATH_KEY, ringtonePath_);
parseValue(node, RINGTONE_ENABLED_KEY, ringtoneEnabled_);
parseValue(node, UPNP_ENABLED_KEY, upnpEnabled_);
bool enabled;
parseValue(node, UPNP_ENABLED_KEY, enabled);
upnpEnabled_.store(enabled);
}
void Account::setAccountDetails(const std::map<std::string, std::string> &details)
......@@ -242,7 +244,9 @@ void Account::setAccountDetails(const std::map<std::string, std::string> &detail
parseString(details, Conf::CONFIG_ACCOUNT_USERAGENT, userAgent_);
else
userAgent_ = DEFAULT_USER_AGENT;
parseBool(details, Conf::CONFIG_UPNP_ENABLED, upnpEnabled_);
bool enabled;
parseBool(details, Conf::CONFIG_UPNP_ENABLED, enabled);
upnpEnabled_.store(enabled);
}
std::map<std::string, std::string> Account::getAccountDetails() const
......@@ -467,40 +471,30 @@ Account::parseBool(const std::map<std::string, std::string> &details, const char
#undef find_iter
/**
* Checks whether the upnp settings is enabled in the account.
* If so, tries to get a controller with a valid IGD.
* If not, destroys the controller.
*
* Returns whether or not there is a controller with a valid IGD to use.
* Get the UPnP IP (external router) address.
* If use UPnP is set to false, the address will be empty.
*/
bool
Account::checkUPnP()
{
std::unique_lock<std::mutex> lk(upnp_mtx);
if (upnpEnabled_ != (bool)upnp_) {
if (upnpEnabled_){
upnp_.reset(new upnp::Controller());
if (upnp_->hasValidIGD())
upnpIp_ = upnp_->getExternalIP();
} else {
upnp_.reset();
upnpIp_ = IpAddr{};
}
}
IpAddr
Account::getUPnPIpAddress() const {
std::lock_guard<std::mutex> lk(upnp_mtx);
if (not upnpEnabled_)
return {};
return upnp_ and upnp_->hasValidIGD();
return upnp_->getExternalIP();
}
/**
* Returns whether or not the upnp controller has a valid IGD
* with which to make port mappings
* returns whether or not UPnP is enabled and active_
* ie: if it is able to make port mappings
*/
bool
Account::getUseUPnP() const
Account::getUPnPActive() const
{
std::unique_lock<std::mutex> lk(upnp_mtx);
return upnp_ and upnp_->hasValidIGD();
std::lock_guard<std::mutex> lk(upnp_mtx);
if (not upnpEnabled_)
return false;
return upnp_->hasValidIGD();
}
} // namespace ring
......@@ -255,18 +255,16 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
static const char * const VIDEO_CODEC_BITRATE;
/**
* @return bool Flag which determines if UPnP is used or not.
* returns whether or not UPnP is enabled and active
* ie: if it is able to make port mappings
*/
bool getUseUPnP() const;
bool getUPnPActive() const;
/**
* Get the UPnP IP (external router) address.
* If use UPnP is set to false, the address will be empty.
*/
IpAddr getUPnPIpAddress() const {
std::unique_lock<std::mutex> lk(upnp_mtx);
return upnpIp_;
}
IpAddr getUPnPIpAddress() const;
private:
NON_COPYABLE(Account);
......@@ -403,29 +401,15 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
std::mt19937_64 rand_ {};
/**
* UPnP IP address (external router address),
* used only if use UPnP is set to true
* UPnP IGD controller and the mutex to access it
*/
IpAddr upnpIp_ {};
std::unique_ptr<ring::upnp::Controller> upnp_;
mutable std::mutex upnp_mtx {};
/**
* Whether or not UPnP is enabled for this account
* Note that this is only used to store the account setting,
* getUseUPnP() should be used to check if UPnP is being use
* ie: if the UPnP controller has been initialized
*/
bool upnpEnabled_;
/**
* Checks whether the upnp settings is enabled in the account.
* If so, tries to get a controller with a valid IGD.
* If not, destroys the controller.
*
* Returns whether or not there is a controller with a valid IGD to use.
* flag which determines if this account is set to use UPnP.
*/
bool checkUPnP();
std::atomic_bool upnpEnabled_ {false};
};
} // namespace ring
......
......@@ -308,7 +308,7 @@ Call::initIceTransport(bool master, unsigned channel_num)
{
auto& iceTransportFactory = Manager::instance().getIceTransportFactory();
iceTransport_ = iceTransportFactory.createTransport(getCallId().c_str(), channel_num,
master, account_.getUseUPnP());
master, account_.getUPnPActive());
}
int
......
......@@ -32,7 +32,7 @@
#include "logger.h"
#include "sip/sip_utils.h"
#include "manager.h"
#include "upnp/upnp.h"
#include "upnp/upnp_control.h"
#include <pjlib.h>
#include <utility>
......@@ -477,7 +477,7 @@ IceTransport::selectUPnPIceCandidates()
IpAddr publicIP = upnp_->getExternalIP();
if (publicIP) {
for(unsigned comp_id = 0; comp_id < component_count_; comp_id++) {
RING_DBG("UPnP : Opening port(s) for Ice comp %d and adding candidate with public IP.", comp_id);
RING_DBG("UPnP: Opening port(s) for Ice comp %d and adding candidate with public IP.", comp_id);
std::vector<IpAddr> candidates = getLocalCandidatesAddr(comp_id);
for(IpAddr addr : candidates) {
uint16_t port = addr.getPort();
......@@ -486,11 +486,11 @@ IceTransport::selectUPnPIceCandidates()
publicIP.setPort(port_used);
addCandidate(comp_id, publicIP);
} else
RING_WARN("UPnP : Could not create a port mapping for the ICE candidae.");
RING_WARN("UPnP: Could not create a port mapping for the ICE candidae.");
}
}
} else {
RING_WARN("UPnP : Could not determine public IP for ICE candidates.");
RING_WARN("UPnP: Could not determine public IP for ICE candidates.");
}
}
}
......
......@@ -61,7 +61,7 @@
#include "config/yamlparser.h"
#include <yaml-cpp/yaml.h>
#include "upnp/upnp.h"
#include "upnp/upnp_control.h"
#include <algorithm>
#include <array>
......@@ -160,7 +160,7 @@ RingAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
("sip:"+call->getCallId()).c_str(),
ICE_COMPONENTS,
true,
getUseUPnP()
getUPnPActive()
);
if (not ice or ice->waitForInitialization(ICE_INIT_TIMEOUT) <= 0) {
call->setConnectionState(Call::DISCONNECTED);
......@@ -241,7 +241,7 @@ RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:
call->setCallMediaLocal(call->getIceTransport()->getDefaultLocalAddress());
IpAddr addrSdp;
if (getUseUPnP()) {
if (getUPnPActive()) {
/* use UPnP addr, or published addr if its set */
addrSdp = getPublishedSameasLocal() ?
getUPnPIpAddress() : getPublishedIpAddress();
......@@ -572,7 +572,7 @@ RingAccount::handleEvents()
bool RingAccount::mapPortUPnP()
{
if (getUseUPnP()) {
if (getUPnPActive()) {
/* create port mapping from published port to local port to the local IP
* note that since different RING accounts can use the same port,
* it may already be open, thats OK
......@@ -581,6 +581,7 @@ bool RingAccount::mapPortUPnP()
* a different port, if succesfull, then we have to use that port for DHT
*/
uint16_t port_used;
std::lock_guard<std::mutex> lock(upnp_mtx);
if (upnp_->addAnyMapping(dhtPort_, ring::upnp::PortType::UDP, false, &port_used)) {
if (port_used != dhtPort_)
RING_DBG("UPnP could not map port %u for DHT, using %u instead", dhtPort_, port_used);
......@@ -603,11 +604,23 @@ void RingAccount::doRegister()
return;
}
/* check UPnP to see if the account setting is enabled and try to get a
* UPnP controller; if this succeeds then try to map the account port */
if (not (checkUPnP() and mapPortUPnP()) )
RING_WARN("Could not successfully map DHT port with UPnP, continuing with account registration anyways.");
/* if UPnP is enabled, then wait for IGD to complete registration */
if ( upnpEnabled_ ) {
auto shared = shared_from_this();
RING_DBG("UPnP: waiting for IGD to register RING account");
setRegistrationState(RegistrationState::TRYING);
std::thread{ [shared] {
auto this_ = std::static_pointer_cast<RingAccount>(shared).get();
if ( not this_->mapPortUPnP())
RING_WARN("UPnP: Could not successfully map DHT port with UPnP, continuing with account registration anyways.");
this_->doRegister_();
}}.detach();
} else
doRegister_();
}
void RingAccount::doRegister_()
{
try {
loadTreatedCalls();
if (dht_.isRunning()) {
......@@ -724,7 +737,7 @@ void RingAccount::doRegister()
("sip:"+call->getCallId()).c_str(),
ICE_COMPONENTS,
false,
this_.getUseUPnP()
this_.getUPnPActive()
);
if (ice->waitForInitialization(ICE_INIT_TIMEOUT) <= 0)
throw std::runtime_error("Can't initialize ICE..");
......@@ -787,10 +800,8 @@ void RingAccount::doUnregister(std::function<void(bool)> released_cb)
pendingSipCalls_.clear();
}
if (getUseUPnP()) {
RING_DBG("UPnP : removing port mapping for DHT account.");
upnp_->removeMappings();
}
/* RING_DBG("UPnP: removing port mapping for DHT account."); */
upnp_->removeMappings();
Manager::instance().unregisterEventHandler((uintptr_t)this);
saveNodes(dht_.exportNodes());
......
......@@ -256,6 +256,8 @@ class RingAccount : public SIPAccountBase {
private:
void doRegister_();
const dht::ValueType USER_PROFILE_TYPE = {9, "User profile", std::chrono::hours(24 * 7)};
const dht::ValueType ICE_ANNOUCEMENT_TYPE = {10, "ICE descriptors", std::chrono::minutes(3)};
......
......@@ -70,7 +70,7 @@
#include <sstream>
#include <cstdlib>
#include "upnp/upnp.h"
#include "upnp/upnp_control.h"
#include "ip_utils.h"
namespace ring {
......@@ -231,7 +231,7 @@ SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
call->setCallMediaLocal(localAddress);
IpAddr addrSdp;
if (getUseUPnP()) {
if (getUPnPActive()) {
/* use UPnP addr, or published addr if its set */
addrSdp = getPublishedSameasLocal() ?
getUPnPIpAddress() : getPublishedIpAddress();
......@@ -712,7 +712,7 @@ std::map<std::string, std::string> SIPAccount::getVolatileAccountDetails() const
bool SIPAccount::mapPortUPnP()
{
if (getUseUPnP()) {
if (getUPnPActive()) {
/* create port mapping from published port to local port to the local IP
* note that since different accounts can use the same port,
* it may already be open, thats OK
......@@ -745,13 +745,39 @@ void SIPAccount::doRegister()
RING_DBG("doRegister %s", hostname_.c_str());
/* check UPnP to see if the account setting is enabled and try to get a
* UPnP controller; if this succeeds then try to map the account port */
if (not (checkUPnP() and mapPortUPnP()) )
RING_WARN("Could not successfully map SIP port with UPnP, continuing with account registration anyways.");
/* if UPnP is enabled, then wait for IGD to complete registration */
if ( upnpEnabled_ ) {
RING_DBG("UPnP: waiting for IGD to register SIP account");
setRegistrationState(RegistrationState::TRYING);
auto shared = shared_from_this();
RING_DBG("UPnP: waiting for IGD to register RING account");