diff --git a/daemon/contrib/src/opendht/rules.mak b/daemon/contrib/src/opendht/rules.mak index 475576169faeea87f265f5a66857aa0b5cb8a8bd..d5877138b54883d2aac836f5d126ab0fc20c833a 100644 --- a/daemon/contrib/src/opendht/rules.mak +++ b/daemon/contrib/src/opendht/rules.mak @@ -1,6 +1,6 @@ # OPENDHT -OPENDHT_VERSION := 1789a5680e1e50bc593b9aa715a7f0a655d044fe -OPENDHT_URL := https://github.com/aberaud/opendht/archive/$(OPENDHT_VERSION).tar.gz +OPENDHT_VERSION := fde26fef5b2dfbcb5960fb91a75f86a83b5b1f3c +OPENDHT_URL := https://github.com/savoirfairelinux/opendht/archive/$(OPENDHT_VERSION).tar.gz PKGS += opendht ifeq ($(call need_pkg,'opendht'),) diff --git a/daemon/contrib/src/pjproject/rules.mak b/daemon/contrib/src/pjproject/rules.mak index 947bf8e44101d12d139576968e8ef229be548bf0..a4e1d79618d8c38c899975841218767195608d0f 100644 --- a/daemon/contrib/src/pjproject/rules.mak +++ b/daemon/contrib/src/pjproject/rules.mak @@ -24,7 +24,7 @@ ifdef HAVE_ANDROID PJPROJECT_OPTIONS += --with-ssl=$(PREFIX) endif -PJPROJECT_EXTRA_CFLAGS = -DPJ_ICE_MAX_CHECKS=150 +PJPROJECT_EXTRA_CFLAGS = -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 PKGS += pjproject # FIXME: nominally 2.2.0 is enough, but it has to be patched for gnutls diff --git a/daemon/src/ringdht/ringaccount.cpp b/daemon/src/ringdht/ringaccount.cpp index ad06cfe858e6fee078b5be7d3a17c4fa4a9da78f..32f807ddb53a7963ab308b37949d697b64bf4d74 100644 --- a/daemon/src/ringdht/ringaccount.cpp +++ b/daemon/src/ringdht/ringaccount.cpp @@ -40,6 +40,9 @@ #include "sip/sipcall.h" #include "sip/sip_utils.h" +#include "sip_transport_ice.h" +#include "ice_transport.h" + #include <opendht/securedht.h> #include "array_size.h" @@ -69,13 +72,18 @@ #include <sstream> #include <cstdlib> +static constexpr int ICE_COMPONENTS {5}; +static constexpr int ICE_COMP_SIP_TRANSPORT {4}; +static constexpr int ICE_INIT_TIMEOUT {5}; +static constexpr int ICE_NEGOTIATION_TIMEOUT {60}; + constexpr const char * const RingAccount::ACCOUNT_TYPE; RingAccount::RingAccount(const std::string& accountID, bool /* presenceEnabled */) : SIPAccountBase(accountID), tlsSetting_(), via_addr_() { fileutils::check_dir(fileutils::get_cache_dir().c_str()); - nodePath_ = fileutils::get_cache_dir()+DIR_SEPARATOR_STR+getAccountID(); + cachePath_ = fileutils::get_cache_dir()+DIR_SEPARATOR_STR+getAccountID(); /* ~/.local/{appname} */ fileutils::check_dir(fileutils::get_data_dir().c_str()); @@ -104,71 +112,113 @@ RingAccount::~RingAccount() } std::shared_ptr<SIPCall> -RingAccount::newIncomingCall(const std::string& id) +RingAccount::newIncomingCall(const std::string& from) { - return Manager::instance().callFactory.newCall<SIPCall, RingAccount>(*this, id, Call::INCOMING); + for (auto& c : pendingCalls_) { + if (c->getPeerNumber() == from) { + SFL_WARN("Found matching call for %s", from.c_str()); + return c; + } + } + SFL_ERR("Can't find matching call for %s", from.c_str()); + return nullptr; } template <> std::shared_ptr<SIPCall> RingAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) { - auto call = Manager::instance().callFactory.newCall<SIPCall, RingAccount>(*this, id, Call::OUTGOING); auto dhtf = toUrl.find("ring:"); dhtf = (dhtf == std::string::npos) ? 0 : dhtf+5; + if (toUrl.length() - dhtf < 40) + throw std::invalid_argument("id must be a ring infohash"); const std::string toUri = toUrl.substr(dhtf, 40); SFL_DBG("Calling DHT peer %s", toUri.c_str()); + + auto call = Manager::instance().callFactory.newCall<SIPCall, RingAccount>(*this, id, Call::OUTGOING); call->setIPToIP(true); + call->initIceTransport(true, ICE_COMPONENTS); + call->waitForIceInitialization(ICE_INIT_TIMEOUT); + auto ice = call->getIceTransport(); + if (not ice or not ice->isInitialized()) { + call->setConnectionState(Call::DISCONNECTED); + call->setState(Call::MERROR); + return call; + } - auto resolved = std::make_shared<bool>(false); - dht_.get(dht::InfoHash(toUri), - [this,call,toUri,resolved](const std::vector<std::shared_ptr<dht::Value>>& values) { - if (*resolved) - return false; - for (const auto& v : values) { - SFL_DBG("Resolved value : %s", v->toString().c_str()); - IpAddr peer; - try { - peer = IpAddr{ dht::ServiceAnnouncement(v->data).getPeerAddr() }; - } catch (const std::exception& e) { - SFL_ERR("Exception while reading value : %s", e.what()); + call->setConnectionState(Call::TRYING); + + auto shared = shared_from_this(); + const auto callkey = dht::InfoHash::get("callto:"+toUri); + + const dht::Value::Id callvid = std::uniform_int_distribution<dht::Value::Id>{}(rand_); + const dht::Value::Id replyvid = callvid+1; + dht_.putEncrypted( + callkey, + dht::InfoHash(toUri), + dht::Value { + ICE_ANNOUCEMENT_TYPE.id, + ice->getLocalAttributesAndCandidates(), + callvid + }, + [callkey, callvid, call, shared](bool ok){ + auto& this_ = *std::static_pointer_cast<RingAccount>(shared).get(); + this_.dht_.cancelPut(callkey, callvid); + if (ok) + call->setConnectionState(Call::PROGRESSING); + else + call->setConnectionState(Call::DISCONNECTED); + } + ); + + dht_.listen( + callkey, + [shared, call, callkey, ice, toUri, replyvid] (const std::vector<std::shared_ptr<dht::Value>>& vals) { + SFL_WARN("Got a DHT reply from %s !", toUri.c_str()); + auto& this_ = *std::static_pointer_cast<RingAccount>(shared).get(); + for (const auto& v : vals) { + if (v->recipient != this_.dht_.getId() || v->type != this_.ICE_ANNOUCEMENT_TYPE.id) { + SFL_WARN("Ignoring non encrypted or bad type value %s.", v->toString().c_str()); continue; } - *resolved = true; - std::string toip = getToUri(toUri+"@"+peer.toString(true, true)); - SFL_DBG("Got DHT peer IP: %s", toip.c_str()); - createOutgoingCall(call, toUri, toip, peer); + if (v->id != replyvid) { + SFL_WARN("Ignoring value ID %llx (expected %llx)", v->id, replyvid); + continue; + } + SFL_WARN("Performing ICE negotiation."); + ice->start(v->data); + if (call->waitForIceNegotiation(ICE_NEGOTIATION_TIMEOUT) <= 0) { + call->setConnectionState(Call::DISCONNECTED); + return false; + } + call->setConnectionState(Call::PROGRESSING); + this_.createOutgoingCall(call, toUri, ice->getRemoteAddress(0)); return false; } return true; - }, - [call,resolved] (bool /*ok*/){ - if (not *resolved) { - call->setConnectionState(Call::DISCONNECTED); - call->setState(Call::MERROR); - } - }, - dht::Value::TypeFilter(dht::ServiceAnnouncement::TYPE)); + } + ); + return call; } void -RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& to, const std::string& toUri, const IpAddr& peer) +RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& to_id, IpAddr target) { - SFL_WARN("RingAccount::createOutgoingCall to: %s toUri: %s tlsListener: %d", to.c_str(), toUri.c_str(), tlsListener_?1:0); - std::shared_ptr<SipTransport> t = link_->sipTransport->getTlsTransport(tlsListener_, getToUri(peer.toString(true, true))); + SFL_WARN("RingAccount::createOutgoingCall to: %s target: %s tlsListener: %d", to_id.c_str(), target.toString(true).c_str(), tlsListener_?1:0); + auto t = link_->sipTransport->getIceTransport(call->getIceTransport(), ICE_COMP_SIP_TRANSPORT); setTransport(t); call->setTransport(t); call->setIPToIP(true); - call->setPeerNumber(toUri); - call->initRecFilename(to); + call->setPeerNumber(getToUri(to_id+"@"+target.toString(true).c_str())); + call->initRecFilename(to_id); - const auto localAddress = ip_utils::getInterfaceAddr(getLocalInterface(), peer.getFamily()); - call->setCallMediaLocal(localAddress); + //const auto localAddress = ip_utils::getInterfaceAddr(getLocalInterface(), peer.getFamily()); + call->setCallMediaLocal(call->getIceTransport()->getDefaultLocalAddress()); // May use the published address as well - const auto addrSdp = isStunEnabled() or (not getPublishedSameasLocal()) ? - getPublishedIpAddress() : localAddress; + //const auto 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 @@ -198,14 +248,15 @@ RingAccount::createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std: // Building the local SDP offer auto& sdp = call->getSDP(); - if (getPublishedSameasLocal()) + /*if (getPublishedSameasLocal()) sdp.setPublishedIP(addrSdp); else sdp.setPublishedIP(getPublishedAddress()); - +*/ + sdp.setPublishedIP(ip_utils::getInterfaceAddr(getLocalInterface())); const bool created = sdp.createOffer(getActiveAudioCodecs(), getActiveVideoCodecs()); - if (not created or not SIPStartCall(call)) + if (not created or not SIPStartCall(call, target)) throw VoipLinkException("Could not send outgoing INVITE request for new call"); } @@ -216,7 +267,7 @@ RingAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) } bool -RingAccount::SIPStartCall(const std::shared_ptr<SIPCall>& call) +RingAccount::SIPStartCall(const std::shared_ptr<SIPCall>& call, IpAddr target) { std::string toUri(call->getPeerNumber()); // expecting a fully well formed sip uri @@ -226,19 +277,20 @@ RingAccount::SIPStartCall(const std::shared_ptr<SIPCall>& call) std::string from(getFromUri()); pj_str_t pjFrom = pj_str((char*) from.c_str()); + std::string targetStr = getToUri(target.toString(true)/*+";transport=ICE"*/); + pj_str_t pjTarget = pj_str((char*) targetStr.c_str()); + pj_str_t pjContact; { auto transport = call->getTransport(); pjContact = getContactHeader(transport ? transport->get() : nullptr); } - const std::string debugContactHeader(pj_strbuf(&pjContact), pj_strlen(&pjContact)); - SFL_DBG("contact header: %s / %s -> %s", - debugContactHeader.c_str(), from.c_str(), toUri.c_str()); + SFL_DBG("contact header: %.*s / %s -> %s / %.*s", + pjContact.slen, pjContact.ptr, from.c_str(), toUri.c_str(), pjTarget.slen, pjTarget.ptr); pjsip_dialog *dialog = NULL; - - if (pjsip_dlg_create_uac(pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, NULL, &dialog) != PJ_SUCCESS) { + if (pjsip_dlg_create_uac(pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, &pjTarget, &dialog) != PJ_SUCCESS) { SFL_ERR("Unable to create SIP dialogs for user agent client when " "calling %s", toUri.c_str()); return false; @@ -276,7 +328,8 @@ RingAccount::SIPStartCall(const std::shared_ptr<SIPCall>& call) return false; } - const pjsip_tpselector tp_sel = getTransportSelector(); + //const pjsip_tpselector tp_sel = getTransportSelector(); + const pjsip_tpselector tp_sel = {PJSIP_TPSELECTOR_TRANSPORT, {call->getTransport()->get()}}; if (pjsip_dlg_set_transport(dialog, &tp_sel) != PJ_SUCCESS) { SFL_ERR("Unable to associate transport for invite session dialog"); return false; @@ -333,7 +386,7 @@ RingAccount::checkIdentityPath() return; const auto idPath = fileutils::get_data_dir()+DIR_SEPARATOR_STR+getAccountID(); - privkeyPath_ = idPath + DIR_SEPARATOR_STR "dht.pem"; + privkeyPath_ = idPath + DIR_SEPARATOR_STR "dht.key"; certPath_ = idPath + DIR_SEPARATOR_STR "dht.crt"; cacertPath_ = idPath + DIR_SEPARATOR_STR "ca.crt"; } @@ -398,7 +451,7 @@ RingAccount::loadIdentity() saveIdentity(id, idPath_ + DIR_SEPARATOR_STR "dht"); certPath_ = idPath_ + DIR_SEPARATOR_STR "dht.crt"; - privkeyPath_ = idPath_ + DIR_SEPARATOR_STR "dht.pem"; + privkeyPath_ = idPath_ + DIR_SEPARATOR_STR "dht.key"; return {ca.second, id}; } @@ -416,7 +469,7 @@ void RingAccount::saveIdentity(const dht::crypto::Identity id, const std::string& path) const { if (id.first) - fileutils::saveFile(path + ".pem", id.first->serialize()); + fileutils::saveFile(path + ".key", id.first->serialize()); if (id.second) fileutils::saveFile(path + ".crt", id.second->getPacked()); } @@ -464,6 +517,7 @@ void RingAccount::doRegister() } try { + loadTreatedCalls(); if (dht_.isRunning()) { SFL_ERR("DHT already running (stopping it first)."); dht_.join(); @@ -476,7 +530,7 @@ void RingAccount::doRegister() case dht::Dht::Status::Connecting: case dht::Dht::Status::Connected: setRegistrationState(status == dht::Dht::Status::Connected ? RegistrationState::REGISTERED : RegistrationState::TRYING); - if (!tlsListener_) { + /*if (!tlsListener_) { initTlsConfiguration(); tlsListener_ = link_->sipTransport->getTlsListener( SipTransportDescr {getTransportType(), getTlsListenerPort(), getLocalInterface()}, @@ -486,7 +540,7 @@ void RingAccount::doRegister() SFL_ERR("Error creating TLS listener."); return; } - } + }*/ break; case dht::Dht::Status::Disconnected: default: @@ -496,11 +550,13 @@ void RingAccount::doRegister() } }); +#if 0 dht_.setLoggers( [](char const* m, va_list args){ vlogger(LOG_ERR, m, args); }, [](char const* m, va_list args){ vlogger(LOG_WARNING, m, args); }, [](char const* m, va_list args){ vlogger(LOG_DEBUG, m, args); } ); +#endif dht_.registerType(USER_PROFILE_TYPE); dht_.registerType(ICE_ANNOUCEMENT_TYPE); @@ -510,15 +566,8 @@ void RingAccount::doRegister() // Publish our own CA dht_.put(identity.first->getPublicKey().getId(), dht::Value { dht::CERTIFICATE_TYPE, - *identity.first - }); - - // Publish the SIP service announcement - dht_.put(dht_.getId(), dht::Value { - dht::ServiceAnnouncement::TYPE, - dht::ServiceAnnouncement(getTlsListenerPort()) - }, [](bool ok) { - SFL_DBG("Peer announce callback ! %d", ok); + *identity.first, + 1 }); username_ = dht_.getId().toString(); @@ -551,6 +600,76 @@ void RingAccount::doRegister() SFL_DBG("Bootstrap node: %s", IpAddr(ip).toString(true).c_str()); dht_.bootstrap(bootstrap); } + + // Listen for incoming calls + auto shared = shared_from_this(); + auto listenKey = "callto:"+dht_.getId().toString(); + SFL_WARN("Listening on %s : %s", listenKey.c_str(), dht::InfoHash::get(listenKey).toString().c_str()); + dht_.listen ( + listenKey, + [shared,listenKey] (const std::vector<std::shared_ptr<dht::Value>>& vals) { + auto& this_ = *std::static_pointer_cast<RingAccount>(shared).get(); + for (const auto& v : vals) { + try { + if (v->recipient != this_.dht_.getId() || v->type != this_.ICE_ANNOUCEMENT_TYPE.id) { + SFL_WARN("Ignoring non encrypted or bad type value %s.", v->toString().c_str()); + continue; + } + if (v->owner.getId() == this_.dht_.getId()) + continue; + auto res = this_.treatedCalls_.insert(v->id); + this_.saveTreatedCalls(); + if (!res.second) { + SFL_DBG("Ignoring already treated incomming call"); + continue; + } + auto from = v->owner.getId().toString(); + auto from_vid = v->id; + auto reply_vid = from_vid+1; + SFL_WARN("Received incomming DHT call request from %s (vid %llx) !!", from.c_str(), from_vid); + auto call = Manager::instance().callFactory.newCall<SIPCall, RingAccount>(this_, Manager::instance().getNewCallID(), Call::INCOMING); + call->initIceTransport(false, ICE_COMPONENTS); + if (call->waitForIceInitialization(ICE_INIT_TIMEOUT) <= 0) + throw std::runtime_error("Can't initialize ICE.."); + this_.dht_.putEncrypted( + listenKey, + v->owner.getId(), + dht::Value { + this_.ICE_ANNOUCEMENT_TYPE.id, + call->getIceTransport()->getLocalAttributesAndCandidates(), + reply_vid + }, + [call,shared,listenKey,reply_vid](bool ok) { + SFL_WARN("ICE exchange put %d", ok); + auto& this_ = *std::static_pointer_cast<RingAccount>(shared).get(); + this_.dht_.cancelPut(listenKey, reply_vid); + SFL_WARN("waitForIceNegociation"); + if (!ok || call->waitForIceNegotiation(ICE_NEGOTIATION_TIMEOUT) <= 0) { + SFL_WARN("nego failed"); + call->setConnectionState(Call::DISCONNECTED); + } else { + SFL_WARN("nego succeeded"); + call->setConnectionState(Call::PROGRESSING); + auto t = this_.link_->sipTransport->getIceTransport(call->getIceTransport(), ICE_COMP_SIP_TRANSPORT); + this_.setTransport(t); + call->setTransport(t); + } + } + ); + call->getIceTransport()->start(v->data); + call->setPeerNumber(from); + call->initRecFilename(from); + SFL_WARN("Pushing pending call with peer %s", from.c_str()); + this_.pendingCalls_.push_back(call); + return true; + } catch (const std::exception& e) { + SFL_ERR("ICE/DHT error: %s", e.what()); + } + } + return true; + } + ); + } catch (const std::exception& e) { SFL_ERR("Error registering DHT account: %s", e.what()); @@ -561,6 +680,7 @@ void RingAccount::doRegister() void RingAccount::doUnregister(std::function<void(bool)> released_cb) { + pendingCalls_.clear(); Manager::instance().unregisterEventHandler((uintptr_t)this); saveNodes(dht_.exportNodes()); saveValues(dht_.exportValues()); @@ -592,6 +712,42 @@ RingAccount::unregisterCA(const dht::InfoHash& crt_id) return deleted; } +void +RingAccount::loadTreatedCalls() +{ + std::string treatedcallPath = cachePath_+DIR_SEPARATOR_STR "treatedCalls"; + { + std::ifstream file(treatedcallPath); + if (!file.is_open()) { + SFL_WARN("Could not load treated calls from %s", treatedcallPath.c_str()); + return; + } + std::string line; + while (std::getline(file, line)) { + std::istringstream iss(line); + dht::Value::Id vid; + if (!(iss >> std::hex >> vid)) { break; } + treatedCalls_.insert(vid); + } + } +} + +void +RingAccount::saveTreatedCalls() const +{ + fileutils::check_dir(cachePath_.c_str()); + std::string treatedcallPath = cachePath_+DIR_SEPARATOR_STR "treatedCalls"; + { + std::ofstream file(treatedcallPath, std::ios::trunc); + if (!file.is_open()) { + SFL_ERR("Could not save treated calls to %s", treatedcallPath.c_str()); + return; + } + for (auto& c : treatedCalls_) + file << std::hex << c << "\n"; + } +} + std::vector<std::string> RingAccount::getRegistredCAs() { @@ -603,7 +759,7 @@ RingAccount::regenerateCAList() { std::ofstream list(caListPath_, std::ios::trunc | std::ios::binary); if (!list.is_open()) { - SFL_ERR("Could open CA list"); + SFL_ERR("Could write CA list"); return; } auto cas = getRegistredCAs(); @@ -623,8 +779,8 @@ void RingAccount::saveNodes(const std::vector<dht::Dht::NodeExport>& nodes) cons { if (nodes.empty()) return; - fileutils::check_dir(nodePath_.c_str()); - std::string nodesPath = nodePath_+DIR_SEPARATOR_STR "nodes"; + fileutils::check_dir(cachePath_.c_str()); + std::string nodesPath = cachePath_+DIR_SEPARATOR_STR "nodes"; { std::ofstream file(nodesPath, std::ios::trunc); if (!file.is_open()) { @@ -650,7 +806,7 @@ std::vector<dht::Dht::NodeExport> RingAccount::loadNodes() const { std::vector<dht::Dht::NodeExport> nodes; - std::string nodesPath = nodePath_+DIR_SEPARATOR_STR "nodes"; + std::string nodesPath = cachePath_+DIR_SEPARATOR_STR "nodes"; { std::ifstream file(nodesPath); if (!file.is_open()) { @@ -717,31 +873,29 @@ void RingAccount::loadConfig() transportType_ = PJSIP_TRANSPORT_TLS; } -bool RingAccount::userMatch(const std::string& username) const -{ - return !username.empty() and username == dht_.getId().toString(); -} - MatchRank -RingAccount::matches(const std::string &userName, const std::string &/*server*/) const +RingAccount::matches(const std::string &userName, const std::string &server) const { - if (userMatch(userName)) { + auto dhtId = dht_.getId().toString(); + if (userName == dhtId || server == dhtId) { SFL_DBG("Matching account id in request with username %s", userName.c_str()); return MatchRank::FULL; } else { + SFL_DBG("No match for account %s in request with username %s", dht_.getId().toString().c_str(), userName.c_str()); return MatchRank::NONE; } } std::string RingAccount::getFromUri() const { - return "ring:" + dht_.getId().toString() + "@ring.dht"; + return "<sip:" + dht_.getId().toString() + "@ring.dht>"; } std::string RingAccount::getToUri(const std::string& to) const { const std::string transport {pjsip_transport_get_type_name(transportType_)}; - return "<sips:" + to + ";transport=" + transport + ">"; + return "<sip:" + to + ">"; + //return "<sips:" + to + ";transport=" + transport + ">"; } pj_str_t @@ -749,36 +903,54 @@ RingAccount::getContactHeader(pjsip_transport* t) { if (!t && transport_) t = transport_->get(); - if (!t) + if (!t) { SFL_ERR("Transport not created yet"); + pj_cstr(&contact_, "<sip:>"); + return contact_; + } + + auto ice = reinterpret_cast<SipIceTransport*>(t)->getIceTransport(); // The transport type must be specified, in our case START_OTHER refers to stun transport - pjsip_transport_type_e transportType = transportType_; + /*pjsip_transport_type_e transportType = transportType_; if (transportType == PJSIP_TRANSPORT_START_OTHER) - transportType = PJSIP_TRANSPORT_UDP; + transportType = PJSIP_TRANSPORT_UDP;*/ // Else we determine this infor based on transport information - std::string address = "ring.dht"; - pj_uint16_t port = getTlsListenerPort(); - - link_->sipTransport->findLocalAddressFromTransport(t, transportType, hostname_, address, port); - + //std::string address = "ring.dht"; + //pj_uint16_t port = getTlsListenerPort(); + + //link_->sipTransport->findLocalAddressFromTransport(t, transportType, hostname_, address, port); + auto address = ice->getDefaultLocalAddress(); + /*if (addr) { + address = addr; + port = + }*/ + /*auto ports = ice->getLocalPorts(); + if (not ports.empty()) + port = ports[0];*/ +/* #if HAVE_IPV6 - /* Enclose IPv6 address in square brackets */ + // Enclose IPv6 address in square brackets if (IpAddr::isIpv6(address)) { - address = IpAddr(address).toString(false, true); + address = IpAddr(address);//.toString(false, true); } #endif - - SFL_WARN("getContactHeader %s@%s:%d", username_.c_str(), address.c_str(), port); +*/ + SFL_WARN("getContactHeader %s@%s", username_.c_str(), address.toString(true).c_str()); + contact_.slen = pj_ansi_snprintf(contact_.ptr, PJSIP_MAX_URL_SIZE, + "<sip:%s%s%s>", + username_.c_str(), + (username_.empty() ? "" : "@"), + address.toString(true).c_str()); /* contact_.slen = pj_ansi_snprintf(contact_.ptr, PJSIP_MAX_URL_SIZE, "<sips:%s%s%s:%d;transport=%s>", username_.c_str(), (username_.empty() ? "" : "@"), address.c_str(), port, - pjsip_transport_get_type_name(transportType)); + pjsip_transport_get_type_name(transportType));*/ return contact_; } diff --git a/daemon/src/ringdht/ringaccount.h b/daemon/src/ringdht/ringaccount.h index 6eb77fcc2db3b4e06c0c12553bd02ce33625ce4f..72d59d920481c66cfd29008768634d67505c9c2d 100644 --- a/daemon/src/ringdht/ringaccount.h +++ b/daemon/src/ringdht/ringaccount.h @@ -230,14 +230,14 @@ class RingAccount : public SIPAccountBase { * This type can be any base class of SIPCall class (included). */ virtual std::shared_ptr<SIPCall> - newIncomingCall(const std::string& id); + newIncomingCall(const std::string& from = {}); virtual bool isTlsEnabled() const { - return true; + return false; } virtual bool getSrtpEnabled() const { - return true; + return false; } virtual std::string getSrtpKeyExchange() const { @@ -257,7 +257,7 @@ class RingAccount : public SIPAccountBase { const dht::ValueType USER_PROFILE_TYPE = {9, "User profile", 60 * 60 * 24 * 7}; const dht::ValueType ICE_ANNOUCEMENT_TYPE = {10, "ICE descriptors", 15 * 60}; - void createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& to, const std::string& toUrl, const IpAddr& peer); + void createOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& to_id, IpAddr target); /** * Set the internal state for this account, mainly used to manage account details from the client application. @@ -272,9 +272,7 @@ class RingAccount : public SIPAccountBase { * @param call The current call * @return true if all is correct */ - bool SIPStartCall(const std::shared_ptr<SIPCall>& call); - - bool userMatch(const std::string &username) const; + bool SIPStartCall(const std::shared_ptr<SIPCall>& call, IpAddr target); void regenerateCAList(); @@ -289,12 +287,18 @@ class RingAccount : public SIPAccountBase { dht::DhtRunner dht_ {}; + /** + * Incomming DHT calls that are not yet actual SIP calls. + */ + std::vector<std::shared_ptr<SIPCall>> pendingCalls_ {}; + std::set<dht::Value::Id> treatedCalls_ {}; + std::string cacertPath_ {}; std::string privkeyPath_ {}; std::string certPath_ {}; std::string idPath_ {}; - std::string nodePath_ {}; + std::string cachePath_ {}; std::string dataPath_ {}; std::string caPath_ {}; std::string caListPath_ {}; @@ -309,6 +313,9 @@ class RingAccount : public SIPAccountBase { void saveNodes(const std::vector<dht::Dht::NodeExport>&) const; void saveValues(const std::vector<dht::Dht::ValuesExport>&) const; + void loadTreatedCalls(); + void saveTreatedCalls() const; + /** * If privkeyPath_ is a valid private key file (PEM or DER), * and certPath_ a valid certificate file, load and returns them. diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index 0ccc54d006182921b32289d09d0cc7443285f172..aa255f6c9013f3f8db00373c2b0379cf961436aa 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -162,9 +162,10 @@ SIPAccount::~SIPAccount() } std::shared_ptr<SIPCall> -SIPAccount::newIncomingCall(const std::string& id) +SIPAccount::newIncomingCall(const std::string&) { - return Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::INCOMING); + auto& manager = Manager::instance(); + return manager.callFactory.newCall<SIPCall, SIPAccount>(*this, manager.getNewCallID(), Call::INCOMING); } template <> diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index ccedc00d8f213e1087662678830401200ea23f51..26fcfee0f958d759de0f839ae1b17eb535a51c11 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -482,7 +482,7 @@ class SIPAccount : public SIPAccountBase { * This type can be any base class of SIPCall class (included). */ std::shared_ptr<SIPCall> - newIncomingCall(const std::string& id); + newIncomingCall(const std::string&); void onRegister(pjsip_regc_cbparam *param); diff --git a/daemon/src/sip/sipaccountbase.h b/daemon/src/sip/sipaccountbase.h index 98c1a3a0decd458629403228c7a3fdd7184bbc4b..d800ff1191abf5116433d4a53a6be3057d3ea911 100644 --- a/daemon/src/sip/sipaccountbase.h +++ b/daemon/src/sip/sipaccountbase.h @@ -125,7 +125,7 @@ public: * This type can be any base class of SIPCall class (included). */ virtual std::shared_ptr<SIPCall> - newIncomingCall(const std::string& id) = 0; + newIncomingCall(const std::string& from) = 0; virtual bool isStunEnabled() const { return false; diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp index eabc34e7d43646a9f2f95289a591be493e84c4e9..96467faa84078bcecc6f88bc76b6c01cb0e9e9fa 100644 --- a/daemon/src/sip/siptransport.cpp +++ b/daemon/src/sip/siptransport.cpp @@ -379,10 +379,10 @@ SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l, const #if HAVE_DHT std::shared_ptr<SipTransport> -SipTransportBroker::getIceTransport(const std::shared_ptr<sfl::IceTransport>& ice) +SipTransportBroker::getIceTransport(const std::shared_ptr<sfl::IceTransport>& ice, unsigned comp_id) { std::unique_lock<std::mutex> lock(iceMutex_); - iceTransports_.emplace_front(endpt_, pool_, ice_pj_transport_type_, ice, 0); + iceTransports_.emplace_front(endpt_, pool_, ice_pj_transport_type_, ice, comp_id); auto& sip_ice_tr = iceTransports_.front(); auto ret = std::make_shared<SipTransport>(&sip_ice_tr.base); { diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h index 6301d4d0e2256b40bc4e2da6d6eff7415abf1faa..93e7b97877c15f20c3a660a53e4ae14c8b3af4c1 100644 --- a/daemon/src/sip/siptransport.h +++ b/daemon/src/sip/siptransport.h @@ -179,7 +179,7 @@ public: #endif #if HAVE_DHT - std::shared_ptr<SipTransport> getIceTransport(const std::shared_ptr<sfl::IceTransport>&); + std::shared_ptr<SipTransport> getIceTransport(const std::shared_ptr<sfl::IceTransport>&, unsigned comp_id); #endif std::shared_ptr<SipTransport> findTransport(pjsip_transport*); diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index 4bf5c4e232d74bb9f023a450d8eed13a296c0863..7bea74cee8bb2bdf88f8f45e370804d5dfc853c5 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -289,7 +289,10 @@ transaction_request_cb(pjsip_rx_data *rdata) Manager::instance().hookPreference.runHook(rdata->msg_info.msg); - auto call = account->newIncomingCall(Manager::instance().getNewCallID()); + auto call = account->newIncomingCall(remote_user); + if (!call) { + return PJ_FALSE; + } // FIXME : for now, use the same address family as the SIP transport auto family = pjsip_transport_type_get_af(account->getTransportType()); @@ -320,6 +323,7 @@ transaction_request_cb(pjsip_rx_data *rdata) SFL_WARN("Using transport from account."); } } + call->setTransport(transport); call->setConnectionState(Call::PROGRESSING); call->setPeerNumber(peerNumber); @@ -329,10 +333,6 @@ transaction_request_cb(pjsip_rx_data *rdata) call->getSDP().setPublishedIP(addrSdp); #if USE_CCRTP call->getAudioRtp().initConfig(); -#endif - call->setTransport(transport); - -#if USE_CCRTP try { call->getAudioRtp().initSession(); } catch (const ost::Socket::Error &err) { @@ -379,7 +379,10 @@ transaction_request_cb(pjsip_rx_data *rdata) #endif call->getSDP().receiveOffer(r_sdp, account->getActiveAudioCodecs(), account->getActiveVideoCodecs()); - call->initIceTransport(false); + if (not call->getIceTransport()) { + SFL_DBG("Initializing ICE transport"); + call->initIceTransport(false); + } call->setupLocalSDPFromIce(); sfl::AudioCodec* ac = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW); @@ -398,6 +401,7 @@ transaction_request_cb(pjsip_rx_data *rdata) pjsip_dialog *dialog = 0; if (pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, nullptr, &dialog) != PJ_SUCCESS) { + SFL_ERR("Could not create uas"); call.reset(); try_respond_stateless(endpt_, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, nullptr, nullptr, nullptr); return PJ_FALSE;