Ver código fonte

Merge pull request #138 from paullouisageneau/reliability-c-api

Add Data Channel reliability to C API
Paul-Louis Ageneau 5 anos atrás
pai
commit
6223967bca
5 arquivos alterados com 113 adições e 24 exclusões
  1. 2 6
      include/rtc/reliability.hpp
  2. 11 0
      include/rtc/rtc.h
  3. 32 15
      src/datachannel.cpp
  4. 66 1
      src/rtc.cpp
  5. 2 2
      src/sctptransport.cpp

+ 2 - 6
include/rtc/reliability.hpp

@@ -27,13 +27,9 @@
 namespace rtc {
 
 struct Reliability {
-	enum Type : uint8_t {
-		TYPE_RELIABLE = 0x00,
-		TYPE_PARTIAL_RELIABLE_REXMIT = 0x01,
-		TYPE_PARTIAL_RELIABLE_TIMED = 0x02,
-	};
+	enum class Type { Reliable = 0, Rexmit, Timed };
 
-	Type type = TYPE_RELIABLE;
+	Type type = Type::Reliable;
 	bool unordered = false;
 	std::variant<int, std::chrono::milliseconds> rexmit = 0;
 };

+ 11 - 0
include/rtc/rtc.h

@@ -78,6 +78,13 @@ typedef struct {
 	uint16_t portRangeEnd;
 } rtcConfiguration;
 
+typedef struct {
+	bool unordered;
+	bool unreliable;
+	unsigned int maxPacketLifeTime; // ignored if reliable
+	unsigned int maxRetransmits;    // ignored if reliable
+} rtcReliability;
+
 typedef void (*rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
 typedef void (*rtcDataChannelCallbackFunc)(int dc, void *ptr);
 typedef void (*rtcDescriptionCallbackFunc)(const char *sdp, const char *type, void *ptr);
@@ -115,9 +122,13 @@ RTC_EXPORT int rtcGetRemoteAddress(int pc, char *buffer, int size);
 
 // DataChannel
 RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
+RTC_EXPORT int rtcCreateDataChannelExt(int pc, const char *label, const char *protocol,
+                                       const rtcReliability *reliability); // returns dc id
 RTC_EXPORT int rtcDeleteDataChannel(int dc);
 
 RTC_EXPORT int rtcGetDataChannelLabel(int dc, char *buffer, int size);
+RTC_EXPORT int rtcGetDataChannelProtocol(int dc, char *buffer, int size);
+RTC_EXPORT int rtcGetDataChannelReliability(int dc, rtcReliability *reliability);
 
 // WebSocket
 #if RTC_ENABLE_WEBSOCKET

+ 32 - 15
src/datachannel.cpp

@@ -31,6 +31,7 @@ namespace rtc {
 
 using std::shared_ptr;
 using std::weak_ptr;
+using std::chrono::milliseconds;
 
 // Messages for the DataChannel establishment protocol
 // See https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09
@@ -43,6 +44,12 @@ enum MessageType : uint8_t {
 	MESSAGE_CLOSE = 0x04
 };
 
+enum ChannelType : uint8_t {
+	CHANNEL_RELIABLE = 0x00,
+	CHANNEL_PARTIAL_RELIABLE_REXMIT = 0x01,
+	CHANNEL_PARTIAL_RELIABLE_TIMED = 0x02
+};
+
 #pragma pack(push, 1)
 struct OpenMessage {
 	uint8_t type = MESSAGE_OPEN;
@@ -168,22 +175,33 @@ size_t DataChannel::availableAmount() const { return mRecvQueue.amount(); }
 void DataChannel::open(shared_ptr<SctpTransport> transport) {
 	mSctpTransport = transport;
 
-	uint8_t channelType = static_cast<uint8_t>(mReliability->type);
-	if (mReliability->unordered)
-		channelType &= 0x80;
-
-	using std::chrono::milliseconds;
-	uint32_t reliabilityParameter = 0;
-	if (mReliability->type == Reliability::TYPE_PARTIAL_RELIABLE_REXMIT)
+	uint8_t channelType;
+	uint32_t reliabilityParameter;
+	switch (mReliability->type) {
+	case Reliability::Type::Rexmit:
+		channelType = CHANNEL_PARTIAL_RELIABLE_REXMIT;
 		reliabilityParameter = uint32_t(std::get<int>(mReliability->rexmit));
-	else if (mReliability->type == Reliability::TYPE_PARTIAL_RELIABLE_TIMED)
+		break;
+
+	case Reliability::Type::Timed:
+		channelType = CHANNEL_PARTIAL_RELIABLE_TIMED;
 		reliabilityParameter = uint32_t(std::get<milliseconds>(mReliability->rexmit).count());
+		break;
+
+	default:
+		channelType = CHANNEL_RELIABLE;
+		reliabilityParameter = 0;
+		break;
+	}
+
+	if (mReliability->unordered)
+		channelType |= 0x80;
 
 	const size_t len = sizeof(OpenMessage) + mLabel.size() + mProtocol.size();
 	binary buffer(len, byte(0));
 	auto &open = *reinterpret_cast<OpenMessage *>(buffer.data());
 	open.type = MESSAGE_OPEN;
-	open.channelType = mReliability->type;
+	open.channelType = channelType;
 	open.priority = htons(0);
 	open.reliabilityParameter = htonl(reliabilityParameter);
 	open.labelLength = htons(uint16_t(mLabel.size()));
@@ -272,19 +290,18 @@ void DataChannel::processOpenMessage(message_ptr message) {
 	mLabel.assign(end, open.labelLength);
 	mProtocol.assign(end + open.labelLength, open.protocolLength);
 
-	using std::chrono::milliseconds;
 	mReliability->unordered = (open.reliabilityParameter & 0x80) != 0;
 	switch (open.channelType & 0x7F) {
-	case Reliability::TYPE_PARTIAL_RELIABLE_REXMIT:
-		mReliability->type = Reliability::TYPE_PARTIAL_RELIABLE_REXMIT;
+	case CHANNEL_PARTIAL_RELIABLE_REXMIT:
+		mReliability->type = Reliability::Type::Rexmit;
 		mReliability->rexmit = int(open.reliabilityParameter);
 		break;
-	case Reliability::TYPE_PARTIAL_RELIABLE_TIMED:
-		mReliability->type = Reliability::TYPE_PARTIAL_RELIABLE_TIMED;
+	case CHANNEL_PARTIAL_RELIABLE_TIMED:
+		mReliability->type = Reliability::Type::Timed;
 		mReliability->rexmit = milliseconds(open.reliabilityParameter);
 		break;
 	default:
-		mReliability->type = Reliability::TYPE_RELIABLE;
+		mReliability->type = Reliability::Type::Reliable;
 		mReliability->rexmit = int(0);
 	}
 

+ 66 - 1
src/rtc.cpp

@@ -29,6 +29,7 @@
 
 #include "plog/Formatters/FuncMessageFormatter.h"
 
+#include <chrono>
 #include <exception>
 #include <mutex>
 #include <type_traits>
@@ -43,6 +44,7 @@
 using namespace rtc;
 using std::shared_ptr;
 using std::string;
+using std::chrono::milliseconds;
 
 namespace {
 
@@ -241,9 +243,30 @@ int rtcDeletePeerConnection(int pc) {
 }
 
 int rtcCreateDataChannel(int pc, const char *label) {
+	return rtcCreateDataChannelExt(pc, label, nullptr, nullptr);
+}
+
+int rtcCreateDataChannelExt(int pc, const char *label, const char *protocol,
+                            const rtcReliability *reliability) {
 	return WRAP({
+		Reliability r = {};
+		if (reliability) {
+			r.unordered = reliability->unordered;
+			if (reliability->unreliable) {
+				if (reliability->maxPacketLifeTime > 0) {
+					r.type = Reliability::Type::Timed;
+					r.rexmit = milliseconds(reliability->maxPacketLifeTime);
+				} else {
+					r.type = Reliability::Type::Rexmit;
+					r.rexmit = int(reliability->maxRetransmits);
+				}
+			} else {
+				r.type = Reliability::Type::Reliable;
+			}
+		}
 		auto peerConnection = getPeerConnection(pc);
-		int dc = emplaceDataChannel(peerConnection->createDataChannel(string(label)));
+		int dc = emplaceDataChannel(peerConnection->createDataChannel(
+		    string(label ? label : ""), string(protocol ? protocol : ""), r));
 		if (auto ptr = getUserPointer(pc))
 			rtcSetUserPointer(dc, *ptr);
 		return dc;
@@ -447,6 +470,48 @@ int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
 	});
 }
 
+int rtcGetDataChannelProtocol(int dc, char *buffer, int size) {
+	return WRAP({
+		auto dataChannel = getDataChannel(dc);
+
+		if (!buffer)
+			throw std::invalid_argument("Unexpected null pointer");
+
+		if (size <= 0)
+			return 0;
+
+		string protocol = dataChannel->protocol();
+		const char *data = protocol.data();
+		size = std::min(size - 1, int(protocol.size()));
+		std::copy(data, data + size, buffer);
+		buffer[size] = '\0';
+		return int(size + 1);
+	});
+}
+
+int rtcGetDataChannelReliability(int dc, rtcReliability *reliability) {
+	return WRAP({
+		auto dataChannel = getDataChannel(dc);
+
+		if (!reliability)
+			throw std::invalid_argument("Unexpected null pointer");
+
+		Reliability r = dataChannel->reliability();
+		std::memset(reliability, sizeof(*reliability), 0);
+		reliability->unordered = r.unordered;
+		if (r.type == Reliability::Type::Timed) {
+			reliability->unreliable = true;
+			reliability->maxPacketLifeTime = std::get<milliseconds>(r.rexmit).count();
+		} else if (r.type == Reliability::Type::Rexmit) {
+			reliability->unreliable = true;
+			reliability->maxRetransmits = unsigned(std::get<int>(r.rexmit));
+		} else {
+			reliability->unreliable = false;
+		}
+		return 0;
+	});
+}
+
 int rtcSetOpenCallback(int id, rtcOpenCallbackFunc cb) {
 	return WRAP({
 		auto channel = getChannel(id);

+ 2 - 2
src/sctptransport.cpp

@@ -372,12 +372,12 @@ bool SctpTransport::trySendMessage(message_ptr message) {
 		spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
 
 	switch (reliability.type) {
-	case Reliability::TYPE_PARTIAL_RELIABLE_REXMIT:
+	case Reliability::Type::Rexmit:
 		spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
 		spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
 		spa.sendv_prinfo.pr_value = uint32_t(std::get<int>(reliability.rexmit));
 		break;
-	case Reliability::TYPE_PARTIAL_RELIABLE_TIMED:
+	case Reliability::Type::Timed:
 		spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
 		spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
 		spa.sendv_prinfo.pr_value = uint32_t(std::get<milliseconds>(reliability.rexmit).count());