Browse Source

Added proper ice-options attribute handling in description

Paul-Louis Ageneau 3 years ago
parent
commit
4d7750e4b4

+ 2 - 0
CMakeLists.txt

@@ -116,6 +116,7 @@ set(LIBDATACHANNEL_IMPL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/threadpool.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/tls.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/track.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/utils.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/processor.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/base64.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sha.cpp
@@ -147,6 +148,7 @@ set(LIBDATACHANNEL_IMPL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/threadpool.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/tls.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/track.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/utils.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/processor.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/base64.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/sha.hpp

+ 3 - 0
include/rtc/description.hpp

@@ -58,6 +58,7 @@ public:
 	string typeString() const;
 	Role role() const;
 	string bundleMid() const;
+	std::vector<string> iceOptions() const;
 	optional<string> iceUfrag() const;
 	optional<string> icePwd() const;
 	optional<string> fingerprint() const;
@@ -65,6 +66,7 @@ public:
 
 	void hintType(Type type);
 	void setFingerprint(string fingerprint);
+	void addIceOption(string option);
 
 	bool hasCandidate(const Candidate &candidate) const;
 	void addCandidate(Candidate candidate);
@@ -274,6 +276,7 @@ private:
 	Role mRole;
 	string mUsername;
 	string mSessionId;
+	std::vector<string> mIceOptions;
 	optional<string> mIceUfrag, mIcePwd;
 	optional<string> mFingerprint;
 

+ 16 - 4
src/description.cpp

@@ -20,6 +20,7 @@
 #include "description.hpp"
 
 #include "impl/internals.hpp"
+#include "impl/utils.hpp"
 
 #include <algorithm>
 #include <array>
@@ -93,6 +94,8 @@ inline bool is_sha256_fingerprint(string_view f) {
 
 namespace rtc {
 
+namespace utils = impl::utils;
+
 Description::Description(const string &sdp, Type type, Role role)
     : mType(Type::Unspec), mRole(role) {
 	hintType(type);
@@ -138,6 +141,8 @@ Description::Description(const string &sdp, Type type, Role role)
 				mIceUfrag = value;
 			} else if (key == "ice-pwd") {
 				mIcePwd = value;
+			} else if (key == "ice-options") {
+				mIceOptions = utils::explode(string(value), ',');
 			} else if (key == "candidate") {
 				addCandidate(Candidate(attr, bundleMid()));
 			} else if (key == "end-of-candidates") {
@@ -179,6 +184,8 @@ string Description::bundleMid() const {
 
 optional<string> Description::iceUfrag() const { return mIceUfrag; }
 
+std::vector<string> Description::iceOptions() const { return mIceOptions; }
+
 optional<string> Description::icePwd() const { return mIcePwd; }
 
 optional<string> Description::fingerprint() const { return mFingerprint; }
@@ -202,6 +209,11 @@ void Description::setFingerprint(string fingerprint) {
 	mFingerprint.emplace(std::move(fingerprint));
 }
 
+void Description::addIceOption(string option) {
+	if (std::find(mIceOptions.begin(), mIceOptions.end(), option) == mIceOptions.end())
+		mIceOptions.emplace_back(std::move(option));
+}
+
 bool Description::hasCandidate(const Candidate &candidate) const {
 	for (const Candidate &other : mCandidates)
 		if (candidate == other)
@@ -269,8 +281,8 @@ string Description::generateSdp(string_view eol) const {
 		sdp << "a=ice-ufrag:" << *mIceUfrag << eol;
 	if (mIcePwd)
 		sdp << "a=ice-pwd:" << *mIcePwd << eol;
-	if (!mEnded)
-		sdp << "a=ice-options:trickle" << eol;
+	if (!mIceOptions.empty())
+		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 	if (mFingerprint)
 		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
 
@@ -329,8 +341,8 @@ string Description::generateApplicationSdp(string_view eol) const {
 		sdp << "a=ice-ufrag:" << *mIceUfrag << eol;
 	if (mIcePwd)
 		sdp << "a=ice-pwd:" << *mIcePwd << eol;
-	if (!mEnded)
-		sdp << "a=ice-options:trickle" << eol;
+	if (!mIceOptions.empty())
+		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 	if (mFingerprint)
 		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
 

+ 6 - 2
src/impl/icetransport.cpp

@@ -166,8 +166,10 @@ Description IceTransport::getLocalDescription(Description::Type type) const {
 	// RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
 	// setup:actpass.
 	// See https://tools.ietf.org/html/rfc5763#section-5
-	return Description(string(sdp), type,
+	Description desc(string(sdp), type,
 	                   type == Description::Type::Offer ? Description::Role::ActPass : mRole);
+	desc.addIceOption("trickle");
+	return desc;
 }
 
 void IceTransport::setRemoteDescription(const Description &description) {
@@ -573,8 +575,10 @@ Description IceTransport::getLocalDescription(Description::Type type) const {
 	// RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
 	// setup:actpass.
 	// See https://tools.ietf.org/html/rfc5763#section-5
-	return Description(string(sdp.get()), type,
+	Description desc(string(sdp.get()), type,
 	                   type == Description::Type::Offer ? Description::Role::ActPass : mRole);
+	desc.addIceOption("trickle");
+	return desc;
 }
 
 void IceTransport::setRemoteDescription(const Description &description) {

+ 47 - 0
src/impl/utils.cpp

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2020-2022 Paul-Louis Ageneau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "utils.hpp"
+
+#include <iterator>
+#include <sstream>
+
+namespace rtc::impl::utils {
+
+std::vector<string> explode(const string &str, char delim) {
+	std::vector<std::string> result;
+	std::istringstream ss(str);
+	string token;
+	while (std::getline(ss, token, delim))
+		result.push_back(token);
+
+	return result;
+}
+
+string implode(const std::vector<string> &tokens, char delim) {
+	string sdelim(1, delim);
+	std::ostringstream ss;
+	std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<string>(ss, sdelim.c_str()));
+	string result = ss.str();
+	if (result.size() > 0)
+		result.resize(result.size() - 1);
+
+	return result;
+}
+
+} // namespace rtc::impl::utils

+ 33 - 0
src/impl/utils.hpp

@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2020-2022 Paul-Louis Ageneau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RTC_IMPL_UTILS_H
+#define RTC_IMPL_UTILS_H
+
+#include "common.hpp"
+
+#include <vector>
+
+namespace rtc::impl::utils {
+
+std::vector<string> explode(const string &str, char delim);
+string implode(const std::vector<string> &tokens, char delim);
+
+} // namespace rtc::impl
+
+#endif

+ 3 - 28
src/impl/wshandshake.cpp

@@ -20,6 +20,7 @@
 #include "base64.hpp"
 #include "internals.hpp"
 #include "sha.hpp"
+#include "utils.hpp"
 
 #if RTC_ENABLE_WEBSOCKET
 
@@ -27,37 +28,11 @@
 #include <chrono>
 #include <climits>
 #include <iostream>
-#include <iterator>
 #include <random>
 #include <sstream>
 
 using std::string;
 
-namespace {
-
-std::vector<string> explode(const string &str, char delim) {
-	std::vector<std::string> result;
-	std::istringstream ss(str);
-	string token;
-	while (std::getline(ss, token, delim))
-		result.push_back(token);
-
-	return result;
-}
-
-string implode(const std::vector<string> &tokens, char delim) {
-	string sdelim(1, delim);
-	std::ostringstream ss;
-	std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<string>(ss, sdelim.c_str()));
-	string result = ss.str();
-	if (result.size() > 0)
-		result.resize(result.size() - 1);
-
-	return result;
-}
-
-} // namespace
-
 namespace rtc::impl {
 
 using std::to_string;
@@ -108,7 +83,7 @@ string WsHandshake::generateHttpRequest() {
 	             mKey + "\r\n";
 
 	if (!mProtocols.empty())
-		out += "Sec-WebSocket-Protocol: " + implode(mProtocols, ',') + "\r\n";
+		out += "Sec-WebSocket-Protocol: " + utils::implode(mProtocols, ',') + "\r\n";
 
 	out += "\r\n";
 
@@ -215,7 +190,7 @@ size_t WsHandshake::parseHttpRequest(const byte *buffer, size_t size) {
 
 	h = headers.find("sec-websocket-protocol");
 	if (h != headers.end())
-		mProtocols = explode(h->second, ',');
+		mProtocols = utils::explode(h->second, ',');
 
 	return length;
 }

+ 1 - 0
src/impl/wshandshake.hpp

@@ -25,6 +25,7 @@
 
 #include <list>
 #include <map>
+#include <vector>
 
 namespace rtc::impl {