diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index 4ecdbcce67782de2d2919d39702fe394c431ddbc..9db5816406b6e3b457ec29eb8aff34040e057aab 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -26,8 +26,10 @@ #include "upnp/upnp_control.h" #include <pjlib.h> +#include <msgpack.hpp> #include <utility> +#include <tuple> #include <algorithm> #include <sstream> #include <chrono> @@ -438,56 +440,48 @@ IceTransport::start(const Attribute& rem_attrs, return true; } -std::string -IceTransport::unpackLine(std::vector<uint8_t>::const_iterator& begin, - std::vector<uint8_t>::const_iterator& end) -{ - if (std::distance(begin, end) <= 0) - return {}; - - // Search for EOL - std::vector<uint8_t>::const_iterator line_end(begin); - while (line_end != end && *line_end != NEW_LINE && *line_end) - ++line_end; - - if (std::distance(begin, line_end) <= 0) - return {}; - - std::string str(begin, line_end); - - // Consume the new line character - if (std::distance(line_end, end) > 0) - ++line_end; - - begin = line_end; - return str; -} - bool IceTransport::start(const std::vector<uint8_t>& rem_data) { - auto begin = rem_data.cbegin(); - auto end = rem_data.cend(); - auto rem_ufrag = unpackLine(begin, end); - auto rem_pwd = unpackLine(begin, end); - if (rem_pwd.empty() or rem_pwd.empty()) { - RING_ERR("ICE remote attributes parsing error"); - return false; - } + std::string rem_ufrag; + std::string rem_pwd; std::vector<IceCandidate> rem_candidates; + + auto data = reinterpret_cast<const char*>(rem_data.data()); + auto size = rem_data.size(); + try { - while (true) { - IceCandidate candidate; - const auto line = unpackLine(begin, end); - if (line.empty()) - break; - if (getCandidateFromSDP(line, candidate)) - rem_candidates.push_back(candidate); + std::size_t offset = 0; + auto result = msgpack::unpack(data, size, offset); + auto version = result.get().as<uint8_t>(); + RING_DBG("[ice:%p] rx msg v%u", this, version); + if (version == 1) { + result = msgpack::unpack(data, size, offset); + std::tie(rem_ufrag, rem_pwd) = result.get().as<std::pair<std::string, std::string>>(); + result = msgpack::unpack(data, size, offset); + auto comp_cnt = result.get().as<uint8_t>(); + while (comp_cnt-- > 0) { + result = msgpack::unpack(data, size, offset); + IceCandidate cand; + for (const auto& line : result.get().as<std::vector<std::string>>()) { + if (getCandidateFromSDP(line, cand)) + rem_candidates.emplace_back(std::move(cand)); + } + } + } else { + RING_ERR("[ice:%p] invalid msg version", this); + return false; } - } catch (std::exception& e) { - RING_ERR("ICE remote candidates parsing error"); + } catch (const msgpack::unpack_error& e) { + RING_ERR("[ice:%p] remote msg unpack error: %s", this, e.what()); return false; } + + if (rem_pwd.empty() or rem_pwd.empty() or rem_candidates.empty()) { + RING_ERR("[ice:%p] invalid remote attributes", this); + return false; + } + return start({rem_ufrag, rem_pwd}, rem_candidates); } @@ -773,19 +767,20 @@ IceTransport::selectUPnPIceCandidates() } std::vector<uint8_t> -IceTransport::getLocalAttributesAndCandidates() const +IceTransport::packIceMsg() const { + static constexpr uint8_t ICE_MSG_VERSION = 1; + if (not isInitialized()) return {}; std::stringstream ss; - ss << local_ufrag_ << NEW_LINE; - ss << local_pwd_ << NEW_LINE; - for (unsigned i=0; i<component_count_; i++) { - const auto& candidates = getLocalCandidates(i); - for (const auto& c : candidates) - ss << c << NEW_LINE; - } + msgpack::pack(ss, ICE_MSG_VERSION); + msgpack::pack(ss, std::make_pair(local_ufrag_, local_pwd_)); + msgpack::pack(ss, static_cast<uint8_t>(component_count_)); + for (unsigned i=0; i<component_count_; i++) + msgpack::pack(ss, getLocalCandidates(i)); + auto str(ss.str()); return std::vector<uint8_t>(str.begin(), str.end()); } diff --git a/src/ice_transport.h b/src/ice_transport.h index dd3b1aaa2562dd27598c92266d87b3ce06e01353..8a9a6c7b632871a5de3afc20c25ed422759d235f 100644 --- a/src/ice_transport.h +++ b/src/ice_transport.h @@ -188,7 +188,7 @@ class IceTransport { /** * Returns serialized ICE attributes and candidates. */ - std::vector<uint8_t> getLocalAttributesAndCandidates() const; + std::vector<uint8_t> packIceMsg() const; bool getCandidateFromSDP(const std::string& line, IceCandidate& cand); @@ -226,9 +226,6 @@ class IceTransport { pj_ice_strans_op op, pj_status_t status); - static std::string unpackLine(std::vector<uint8_t>::const_iterator& begin, - std::vector<uint8_t>::const_iterator& end); - struct IceSTransDeleter { void operator ()(pj_ice_strans* ptr) { pj_ice_strans_stop_ice(ptr); diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 72362202592fe10e10f9b0ba844ed1e44247e22e..a72a5d0faa1dc5c146a4bdf2f89b425df4127a71 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -325,7 +325,7 @@ RingAccount::startOutgoingCall(std::shared_ptr<SIPCall>& call, const std::string const dht::Value::Id callvid = udist(sthis->rand_); const dht::Value::Id vid = udist(sthis->rand_); const auto callkey = dht::InfoHash::get("callto:" + dev.dev.toString()); - dht::Value val { dht::IceCandidates(callvid, ice->getLocalAttributesAndCandidates()) }; + dht::Value val { dht::IceCandidates(callvid, ice->packIceMsg()) }; val.id = vid; sthis->dht_.putEncrypted( @@ -1842,7 +1842,7 @@ RingAccount::replyToIncomingIceMsg(std::shared_ptr<SIPCall> call, registerDhtAddress(*ice); const auto vid = udist(rand_); - dht::Value val { dht::IceCandidates(peer_ice_msg.id, ice->getLocalAttributesAndCandidates()) }; + dht::Value val { dht::IceCandidates(peer_ice_msg.id, ice->packIceMsg()) }; val.id = vid; std::weak_ptr<SIPCall> wcall = call;