Commit 7649d5be authored by Stepan Salenikovich's avatar Stepan Salenikovich

daemon: add upnp support

New settings in daemon preferences to use UPnP, default false.
Currently opens ports for SIP and ip2ip accounts and their calls.
Opens ports negotiated by SDP sesssion.
Tries to open ports for ICE candidates and adds ICE candidates
with the public IP to help ICE negotiation.
Added miniupnpc to contrib and patched to be able to generate just
a static lib.
Supports multiple clients on the same UPnP router. Will select a
different port at random if the desired port is already taken by
another client.

Refs #63247
Refs #63303

Change-Id: I00ae79bc3a24d3e54513a6d299fd9b6a70bcc3c2
parent e7e98661
......@@ -537,6 +537,60 @@ 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)
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" )
# DOXYGEN
# required dependency(ies): doxygen
......@@ -592,6 +646,7 @@ AC_CONFIG_FILES([Makefile \
src/media/video/Makefile \
src/media/video/v4l2/Makefile \
src/media/video/test/Makefile \
src/upnp/Makefile \
test/Makefile \
ringtones/Makefile \
man/Makefile \
......
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 $@
--- a/pjnath/include/pjnath/ice_strans.h
+++ b/pjnath/include/pjnath/ice_strans.h
@@ -845,6 +845,8 @@ PJ_DECL(pj_status_t) pj_ice_strans_sendt
int dst_addr_len);
+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess(pj_ice_strans *ice_st);
+
/**
* @}
*/
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -1243,6 +1243,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto
return PJ_EINVALIDOP;
}
+PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess( pj_ice_strans *ice_st )
+{
+ return ice_st->ice;
+}
+
......@@ -58,6 +58,7 @@ endif
$(APPLY) $(SRC)/pjproject/ipv6.patch
$(APPLY) $(SRC)/pjproject/ice_config.patch
$(APPLY) $(SRC)/pjproject/multiple_listeners.patch
$(APPLY) $(SRC)/pjproject/pj_ice_sess.patch
$(UPDATE_AUTOCONFIG)
$(MOVE)
......
......@@ -34,7 +34,7 @@ TLS_LIB = @GNUTLS_LIBS@
TLS_CFLAGS = @GNUTLS_CFLAGS@
endif
SUBDIRS = client media config hooks history sip $(IAX_SUBDIR) $(RINGACC_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(RING_VIDEO_SUBDIR)
SUBDIRS = client media config hooks history sip upnp $(IAX_SUBDIR) $(RINGACC_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(RING_VIDEO_SUBDIR)
# libring
......@@ -47,6 +47,7 @@ libring_la_LIBADD = \
./config/libconfig.la \
./hooks/libhooks.la \
./history/libhistory.la \
./upnp/libupnp.la \
$(RINGACC_LIBA) \
$(IAX_LIBA) \
$(IM_LIBA) \
......
......@@ -35,8 +35,10 @@
#include "config.h"
#endif
#include "account.h"
#include <algorithm>
#include <iterator>
#include <mutex>
#ifdef RING_VIDEO
#include "libav_utils.h"
......@@ -52,6 +54,9 @@
#include <yaml-cpp/yaml.h>
#include "upnp/upnp.h"
#include "ip_utils.h"
namespace ring {
const char * const Account::AUDIO_CODECS_KEY = "audioCodecs"; // 0/9/110/111/112/
......@@ -454,4 +459,26 @@ Account::parseBool(const std::map<std::string, std::string> &details, const char
#undef find_iter
void
Account::setUseUPnP(bool useUPnP)
{
std::unique_lock<std::mutex> lk(upnp_mtx);
if (useUPnP == static_cast<bool>(upnp_))
return;
if (useUPnP){
upnp_.reset(new upnp::Controller());
upnpIp_ = upnp_->getExternalIP();
} else
upnp_.reset();
}
bool
Account::getUseUPnP() const
{
std::unique_lock<std::mutex> lk(upnp_mtx);
return static_cast<bool>(upnp_);
}
} // namespace ring
......@@ -33,9 +33,14 @@
#ifndef ACCOUNT_H
#define ACCOUNT_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "noncopyable.h"
#include "config/serializable.h"
#include "registration_states.h"
#include "ip_utils.h"
#include <functional>
#include <string>
......@@ -45,6 +50,12 @@
#include <set>
#include <random>
#include <stdexcept>
#include <atomic>
#include <mutex>
namespace ring { namespace upnp {
class Controller;
}}
namespace YAML {
class Emitter;
......@@ -243,6 +254,26 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
static const char * const VIDEO_CODEC_PARAMETERS;
static const char * const VIDEO_CODEC_BITRATE;
/**
* Set whether or not to use UPnP
*/
void setUseUPnP(bool useUPnP);
/**
* Get whether UPnP is used.
* @return bool Flag which determines if UPnP is used or not.
*/
bool getUseUPnP() 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_;
}
private:
NON_COPYABLE(Account);
......@@ -375,6 +406,14 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
* Random generator engine
*/
std::mt19937_64 rand_ {};
/**
* UPnP IP address (external router address),
* used only if use UPnP is set to true
*/
IpAddr upnpIp_ {};
std::unique_ptr<ring::upnp::Controller> upnp_;
mutable std::mutex upnp_mtx {};
};
} // 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);
master, account_.getUseUPnP());
}
int
......
......@@ -132,6 +132,13 @@ class IAXAccount : public Account {
std::shared_ptr<enable_if_base_of<T, IAXCall> >
newIncomingCall(const std::string& id);
/**
* Set whether or not to use UPnP
*/
void setUseUPnP(bool) {
/* do nothing for now as UPnP isn't implemented for IAX */
}
private:
void setAccountDetails(const std::map<std::string, std::string> &details);
......
......@@ -32,6 +32,7 @@
#include "logger.h"
#include "sip/sip_utils.h"
#include "manager.h"
#include "upnp/upnp.h"
#include <pjlib.h>
#include <utility>
......@@ -94,7 +95,7 @@ IceTransport::cb_on_ice_complete(pj_ice_strans* ice_st,
}
IceTransport::IceTransport(const char* name, int component_count,
bool master,
bool master, bool upnp_enabled,
IceTransportCompleteCb on_initdone_cb,
IceTransportCompleteCb on_negodone_cb)
: pool_(nullptr, pj_pool_release)
......@@ -104,6 +105,9 @@ IceTransport::IceTransport(const char* name, int component_count,
, compIO_(component_count)
, initiator_session_(master)
{
if (upnp_enabled)
upnp_.reset(new upnp::Controller());
auto& iceTransportFactory = Manager::instance().getIceTransportFactory();
pool_.reset(pj_pool_create(iceTransportFactory.getPoolFactory(),
......@@ -125,6 +129,8 @@ IceTransport::IceTransport(const char* name, int component_count,
throw std::runtime_error("pj_ice_strans_create() failed");
}
IceTransport::~IceTransport() = default;
void
IceTransport::onComplete(pj_ice_strans* ice_st, pj_ice_strans_op op,
pj_status_t status)
......@@ -156,6 +162,8 @@ IceTransport::onComplete(pj_ice_strans* ice_st, pj_ice_strans_op op,
}
if (on_initdone_cb_)
on_initdone_cb_(*this, done);
if (iceTransportInitDone_)
selectUPnPIceCandidates();
} else if (op == PJ_ICE_STRANS_OP_NEGOTIATION) {
iceTransportNegoDone_ = done;
if (on_negodone_cb_)
......@@ -406,6 +414,80 @@ IceTransport::getLocalCandidates(unsigned comp_id) const
return res;
}
std::vector<IpAddr>
IceTransport::getLocalCandidatesAddr(unsigned comp_id) const
{
std::vector<IpAddr> cand_addrs;
pj_ice_sess_cand cand[PJ_ARRAY_SIZE(cand_)];
unsigned cand_cnt = PJ_ARRAY_SIZE(cand);
if (pj_ice_strans_enum_cands(icest_.get(), comp_id+1, &cand_cnt, cand) != PJ_SUCCESS) {
RING_ERR("pj_ice_strans_enum_cands() failed");
return cand_addrs;
}
for (unsigned i=0; i<cand_cnt; ++i) {
cand_addrs.push_back(cand[i].addr);
}
}
void
IceTransport::addCandidate(int comp_id, const IpAddr& addr)
{
pj_ice_sess_cand cand;
cand.type = PJ_ICE_CAND_TYPE_HOST;
cand.status = PJ_SUCCESS;
cand.comp_id = comp_id + 1; /* starts at 1, not 0 */
cand.transport_id = 1; /* 1 = STUN */
cand.local_pref = 65535; /* host */
/* cand.foundation = ? */
/* cand.prio = calculated by ice session */
/* make base and addr the same since we're not going through a server */
pj_sockaddr_cp(&cand.base_addr, addr.pjPtr());
pj_sockaddr_cp(&cand.addr, addr.pjPtr());
pj_bzero(&cand.rel_addr, sizeof(cand.rel_addr)); /* not usring rel_addr */
pj_ice_calc_foundation(pool_.get(), &cand.foundation, cand.type, &cand.base_addr);
pj_ice_sess_add_cand(pj_ice_strans_get_ice_sess(icest_.get()),
cand.comp_id,
cand.transport_id,
cand.type,
cand.local_pref,
&cand.foundation,
&cand.addr,
&cand.base_addr,
&cand.rel_addr,
pj_sockaddr_get_len(&cand.addr),
NULL);
}
void
IceTransport::selectUPnPIceCandidates()
{
/* use upnp to open ports and add the proper candidates */
if (upnp_) {
/* for every component, get the candidate(s)
* create a port mapping either with that port, or with an available port
* add candidate with that port and public IP
*/
IpAddr publicIP = upnp_->getExternalIP();
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);
std::vector<IpAddr> candidates = getLocalCandidatesAddr(comp_id);
for(IpAddr addr : candidates) {
uint16_t port = addr.getPort();
uint16_t port_used;
if (upnp_->addAnyMapping(port, upnp::PortType::UDP, true, &port_used)) {
publicIP.setPort(port_used);
addCandidate(comp_id, publicIP);
} else
RING_WARN("UPnP : Could not create a port mapping for the ICE candidae.");
}
}
}
}
std::vector<uint8_t>
IceTransport::getLocalAttributesAndCandidates() const
{
......@@ -713,10 +795,11 @@ std::shared_ptr<IceTransport>
IceTransportFactory::createTransport(const char* name,
int component_count,
bool master,
bool upnp_enabled,
IceTransportCompleteCb&& on_initdone_cb,
IceTransportCompleteCb&& on_negodone_cb)
{
return std::make_shared<IceTransport>(name, component_count, master,
return std::make_shared<IceTransport>(name, component_count, master, upnp_enabled,
std::forward<IceTransportCompleteCb>(on_initdone_cb),
std::forward<IceTransportCompleteCb>(on_negodone_cb));
}
......
......@@ -48,6 +48,10 @@
namespace ring {
namespace upnp {
class Controller;
}
class IceTransport;
using IceTransportCompleteCb = std::function<void(IceTransport&, bool)>;
......@@ -66,9 +70,15 @@ class IceTransport {
*/
IceTransport(const char* name, int component_count,
bool master,
bool upnp_enabled = false,
IceTransportCompleteCb on_initdone_cb={},
IceTransportCompleteCb on_negodone_cb={});
/**
* Destructor
*/
~IceTransport();
/**
* Set/change transport role as initiator.
* Should be called before start method.
......@@ -147,6 +157,8 @@ class IceTransport {
ssize_t waitForData(int comp_id, unsigned int timeout);
unsigned getComponentCount() const {return component_count_;};
private:
static constexpr int MAX_CANDIDATES {32};
......@@ -212,6 +224,23 @@ class IceTransport {
std::vector<ComponentIO> compIO_;
bool initiator_session_ {true};
/**
* Returns the IP of each candidate for a given component in the ICE session
*/
std::vector<IpAddr> getLocalCandidatesAddr(unsigned comp_id) const;
/**
* Adds candidate to ICE session
*/
void addCandidate(int comp_id, const IpAddr& addr);
/**
* Creates UPnP port mappings and adds ICE candidates based on those mappings
*/
void selectUPnPIceCandidates();
std::unique_ptr<upnp::Controller> upnp_;
};
class IceTransportFactory {
......@@ -222,6 +251,7 @@ class IceTransportFactory {
std::shared_ptr<IceTransport> createTransport(const char* name,
int component_count,
bool master,
bool upnp_enabled = false,
IceTransportCompleteCb&& on_initdone_cb={},
IceTransportCompleteCb&& on_negodone_cb={});
......
......@@ -133,6 +133,10 @@ public:
return ss;
}
inline const pj_sockaddr* pjPtr() const {
return &addr;
}
inline pj_sockaddr* pjPtr() {
return &addr;
}
......
......@@ -81,6 +81,8 @@
#include "conference.h"
#include "ice_transport.h"
#include "upnp/upnp.h"
#include <cerrno>
#include <algorithm>
#include <ctime>
......@@ -240,6 +242,12 @@ ManagerImpl::init(const std::string &config_file)
}
history_.load(preferences.getHistoryLimit());
if (preferences.getUseUPnP()) {
RING_DBG("Remove any old UPnP mappings for RING mapped to this IP");
upnp::Controller().removeMappingsByLocalIPAndDescription();
}
registerAccounts();
}
......@@ -286,6 +294,11 @@ ManagerImpl::finish()
} catch (const VoipLinkException &err) {
RING_ERR("%s", err.what());
}
if (preferences.getUseUPnP()) {
RING_DBG("Remove any remaning ports mapped to this client for RING");
upnp::Controller().removeMappingsByLocalIPAndDescription();
}
}
bool
......@@ -2393,9 +2406,10 @@ ManagerImpl::setAccountDetails(const std::string& accountID,
// Serialize configuration to disk once it is done
saveConfig();
if (account->isEnabled())
if (account->isEnabled()) {
account->setUseUPnP(preferences.getUseUPnP());
account->doRegister();
else
} else
account->doUnregister();
// Update account details to the client side
......@@ -2440,6 +2454,8 @@ ManagerImpl::addAccount(const std::map<std::string, std::string>& details)
preferences.addAccount(newAccountID);
newAccount->setUseUPnP(preferences.getUseUPnP());
newAccount->doRegister();
saveConfig();
......@@ -2698,8 +2714,10 @@ ManagerImpl::registerAccounts()
a->loadConfig();
if (a->isEnabled())
if (a->isEnabled()) {
a->setUseUPnP(preferences.getUseUPnP());
a->doRegister();
}
}
}
......@@ -2724,9 +2742,10 @@ ManagerImpl::sendRegister(const std::string& accountID, bool enable)
Manager::instance().saveConfig();
if (acc->isEnabled())
if (acc->isEnabled()) {
acc->setUseUPnP(preferences.getUseUPnP());
acc->doRegister();
else
} else
acc->doUnregister();
}
......
......@@ -77,6 +77,7 @@ static const char * const ZONE_TONE_CHOICE_KEY = "zoneToneChoice";
static const char * const PORT_NUM_KEY = "portNum";
static const char * const SEARCH_BAR_DISPLAY_KEY = "searchBarDisplay";
static const char * const MD5_HASH_KEY = "md5Hash";
static const char * const USE_UPNP = "useUPnP";
// voip preferences
constexpr const char * const VoipPreference::CONFIG_LABEL;
......@@ -137,6 +138,7 @@ Preferences::Preferences() :
, portNum_(5060)
, searchBarDisplay_(true)
, md5Hash_(false)
, useUPnP_(false)
{}
void Preferences::verifyAccountOrder(const std::vector<std::string> &accountIDs)
......@@ -195,6 +197,7 @@ void Preferences::serialize(YAML::Emitter &out)
out << YAML::Key << REGISTRATION_EXPIRE_KEY << YAML::Value << registrationExpire_;
out << YAML::Key << SEARCH_BAR_DISPLAY_KEY << YAML::Value << searchBarDisplay_;
out << YAML::Key << ZONE_TONE_CHOICE_KEY << YAML::Value << zoneToneChoice_;
out << YAML::Key << USE_UPNP << YAML::Value << useUPnP_;
out << YAML::EndMap;
}
......@@ -210,6 +213,7 @@ void Preferences::unserialize(const YAML::Node &in)
parseValue(node, PORT_NUM_KEY, portNum_);
parseValue(node, SEARCH_BAR_DISPLAY_KEY, searchBarDisplay_);
parseValue(node, MD5_HASH_KEY, md5Hash_);
parseValue(node, USE_UPNP, useUPnP_);
}
VoipPreference::VoipPreference() :
......
......@@ -126,6 +126,13 @@ class Preferences : public Serializable {
md5Hash_ = md5;
}
bool getUseUPnP() const {
return useUPnP_;
}
void setUseUPnP(bool upnp) {
useUPnP_ = upnp;
}
private:
std::string accountOrder_;
int historyLimit_;
......@@ -135,6 +142,7 @@ class Preferences : public Serializable {
int portNum_;
bool searchBarDisplay_;
bool md5Hash_;
bool useUPnP_;
constexpr static const char * const CONFIG_LABEL = "preferences";
};
......
......@@ -61,6 +61,8 @@
#include "config/yamlparser.h"
#include <yaml-cpp/yaml.h>
#include "upnp/upnp.h"
#include <algorithm>
#include <array>
#include <memory>
......@@ -154,7 +156,8 @@ RingAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
auto ice = iceTransportFactory.createTransport(
("sip:"+call->getCallId()).c_str(),
ICE_COMPONENTS,
true
true,
getUseUPnP()
);
if (not ice or ice->waitForInitialization(ICE_INIT_TIMEOUT) <= 0) {
call->setConnectionState(Call::DISCONNECTED);
......@@ -224,12 +227,18 @@ RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:
call->setPeerNumber(getToUri(to_id+"@"+target.toString(true).c_str()));
call->initRecFilename(to_id);
//const auto localAddress = ip_utils::getInterfaceAddr(getLocalInterface(), peer.getFamily());
const auto localAddress = ip_utils::getInterfaceAddr(getLocalInterface());
call->setCallMediaLocal(call->getIceTransport()->getDefaultLocalAddress());
// May use the published address as well
//const auto addrSdp = isStunEnabled() or (not getPublishedSameasLocal()) ? getPublishedIpAddress() : localAddress;
IpAddr addrSdp;
if (getUseUPnP()) {
/* use UPnP addr, or published addr if its set */
addrSdp = getPublishedSameasLocal() ?
getUPnPIpAddress() : getPublishedIpAddress();
} else {
addrSdp = isStunEnabled() or (not getPublishedSameasLocal()) ?
getPublishedIpAddress() : localAddress;
}
// Initialize the session using ULAW as default codec in case of early media
// The session should be ready to receive media once the first INVITE is sent, before
......@@ -244,12 +253,7 @@ RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:
// Building the local SDP offer
auto& sdp = call->getSDP();
/*if (getPublishedSameasLocal())
sdp.setPublishedIP(addrSdp);
else
sdp.setPublishedIP(getPublishedAddress());
*/
sdp.setPublishedIP(ip_utils::getInterfaceAddr(getLocalInterface()));
sdp.setPublishedIP(addrSdp);
const bool created = sdp.createOffer(getActiveAudioCodecs(), getActiveVideoCodecs());
if (not created or not SIPStartCall(call, target))
......@@ -369,6 +373,7 @@ void RingAccount::unserialize(const YAML::Node &node)
in_port_t port {DHT_DEFAULT_PORT};
parseValue(node, Conf::DHT_PORT_KEY, port);
dhtPort_ = port ? port : DHT_DEFAULT_PORT;
dhtPortUsed_ = dhtPort_;
parseValue(node, Conf::DHT_PRIVKEY_PATH_KEY, privkeyPath_);
parseValue(node, Conf::DHT_CERT_PATH_KEY, certPath_);
parseValue(node, Conf::DHT_CA_CERT_PATH_KEY, cacertPath_);
......@@ -490,6 +495,7 @@ void RingAccount::setAccountDetails(const std::map<std::string, std::string> &de
parseInt(details, Conf::CONFIG_DHT_PORT, dhtPort_);
if (dhtPort_ == 0)
dhtPort_ = DHT_DEFAULT_PORT;
dhtPortUsed_ = dhtPort_;
parseString(details, Conf::CONFIG_DHT_PRIVKEY_PATH, privkeyPath_);
parseString(details, Conf::CONFIG_DHT_CERT_PATH, certPath_);
checkIdentityPath();
......@@ -541,6 +547,32 @@ RingAccount::handleEvents()
}
}
bool RingAccount::mapPortUPnP()
{
if (getUseUPnP()) {
/* 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
*
* if the desired port is taken by another client, then it will try to map
* a different port, if succesfull, then we have to use that port for DHT
*/
uint16_t port_used;
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);
dhtPortUsed_ = port_used;
return true;
} else {