mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-23 15:48:03 +00:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
e4ab5273fc | |||
bf0b3ce1b9 | |||
655175d21e | |||
c85943e916 | |||
1cc7910bf1 | |||
62b435a4aa | |||
9da756bd12 | |||
f5b584f536 | |||
3eb8ab567e | |||
f1a7afb28e | |||
9a7b672d6e | |||
9da58f4343 | |||
ef2e7c609a | |||
d330738b41 | |||
791e6b1e32 | |||
b5884c84fc |
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(libdatachannel
|
||||
VERSION 0.12.0
|
||||
VERSION 0.12.3
|
||||
LANGUAGES CXX)
|
||||
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
|
||||
|
||||
|
6
DOC.md
6
DOC.md
@ -88,7 +88,7 @@ Arguments:
|
||||
- `iceServersCount` (optional): number of URLs in the array pointed by `iceServers` (0 if unused)
|
||||
- `certificateType` (optional): certificate type, either `RTC_CERTIFICATE_ECDSA` or `RTC_CERTIFICATE_RSA` (0 or `RTC_CERTIFICATE_DEFAULT` if default)
|
||||
- `enableIceTcp`: if true, generate TCP candidates for ICE (ignored with libjuice as ICE backend)
|
||||
- `disableAutoNegociation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description
|
||||
- `disableAutoNegotiation`: if true, the user is responsible for calling `rtcSetLocalDescription` after creating a Data Channel and after setting the remote description
|
||||
- `portRangeBegin` (optional): first port (included) of the allowed local port range (0 if unused)
|
||||
- `portRangeEnd` (optional): last port (included) of the allowed local port (0 if unused)
|
||||
- `mtu` (optional): manually set the Maximum Transfer Unit (MTU) for the connection (0 if automatic)
|
||||
@ -165,7 +165,7 @@ int rtcSetTrackCallback(int pc, rtcTrackCallbackFunc cb)
|
||||
int rtcSetLocalDescription(int pc, const char *type)
|
||||
```
|
||||
|
||||
Initiates the handshake process. Following this call, the local description callback will be called with the local description, which must be sent to the remote peer by the user's method of choice. Note this call is implicit after `rtcSetRemoteDescription` and `rtcCreateDataChannel` if `disableAutoNegociation` was not set on Peer Connection creation.
|
||||
Initiates the handshake process. Following this call, the local description callback will be called with the local description, which must be sent to the remote peer by the user's method of choice. Note this call is implicit after `rtcSetRemoteDescription` and `rtcCreateDataChannel` if `disableAutoNegotiation` was not set on Peer Connection creation.
|
||||
|
||||
Arguments:
|
||||
- `pc`: the Peer Connection identifier
|
||||
@ -326,7 +326,7 @@ If `local`, `remote`, or both, are `NULL`, the corresponding candidate is not co
|
||||
|
||||
### Data Channel
|
||||
|
||||
#### rtcAddDataChannel
|
||||
#### rtcCreateDataChannel
|
||||
|
||||
```
|
||||
int rtcCreateDataChannel(int pc, const char *label)
|
||||
|
9
Jamfile
9
Jamfile
@ -12,9 +12,12 @@ feature.compose <gnutls>on
|
||||
lib libdatachannel
|
||||
: # sources
|
||||
[ glob ./src/*.cpp ]
|
||||
[ glob ./src/impl/*.cpp ]
|
||||
: # requirements
|
||||
<cxxstd>17
|
||||
<include>./include
|
||||
<include>./include/rtc
|
||||
<include>./src
|
||||
<define>RTC_ENABLE_MEDIA=0
|
||||
<define>RTC_ENABLE_WEBSOCKET=0
|
||||
<define>USE_NICE=0
|
||||
@ -143,7 +146,7 @@ rule make_libjuice_openssl ( targets * : sources * : properties * )
|
||||
{
|
||||
# on macOS, default to pick up openssl from the homebrew installation
|
||||
# brew install openssl
|
||||
OPENSSL_INCLUDE = /usr/local/opt/openssl/include ;
|
||||
OPENSSL_INCLUDE = /opt/homebrew/opt/openssl /usr/local/opt/openssl/include ;
|
||||
}
|
||||
|
||||
if $(OPENSSL_INCLUDE) != ""
|
||||
@ -191,7 +194,7 @@ rule openssl-lib-path ( properties * )
|
||||
{
|
||||
# on macOS, default to pick up openssl from the homebrew installation
|
||||
# brew install openssl
|
||||
OPENSSL_LIB = /usr/local/opt/openssl/lib ;
|
||||
OPENSSL_LIB = /opt/homebrew/opt/openssl/lib /usr/local/opt/openssl/lib ;
|
||||
}
|
||||
else if <target-os>windows in $(properties) && $(OPENSSL_LIB) = ""
|
||||
{
|
||||
@ -217,7 +220,7 @@ rule openssl-include-path ( properties * )
|
||||
{
|
||||
# on macOS, default to pick up openssl from the homebrew installation
|
||||
# brew install openssl
|
||||
OPENSSL_INCLUDE = /usr/local/opt/openssl/include ;
|
||||
OPENSSL_INCLUDE = /opt/homebrew/opt/openssl/include /usr/local/opt/openssl/include ;
|
||||
}
|
||||
else if <target-os>windows in $(properties) && $(OPENSSL_INCLUDE) = ""
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
libdatachannel is a standalone implementation of WebRTC Data Channels, WebRTC Media Transport, and WebSockets in C++17 with C bindings for POSIX platforms (including GNU/Linux, Android, and Apple macOS) and Microsoft Windows.
|
||||
|
||||
The library aims at being both straightforward and lightweight with a minimum of external dependencies, to enable direct connectivity between native applications and web browsers without the pain of importing Google's bloated [reference library](https://webrtc.googlesource.com/src/). The interface consists of somewhat simplified versions of the JavaScript WebRTC and WebSocket APIs present in browsers, in order to ease the design of cross-environment applications.
|
||||
The library aims at being both straightforward and lightweight with minimal external dependencies, to enable direct connectivity between native applications and web browsers without the pain of importing Google's bloated [reference library](https://webrtc.googlesource.com/src/). The interface consists of somewhat simplified versions of the JavaScript WebRTC and WebSocket APIs present in browsers, in order to ease the design of cross-environment applications.
|
||||
|
||||
It can be compiled with multiple backends:
|
||||
- The security layer can be provided through [OpenSSL](https://www.openssl.org/) or [GnuTLS](https://www.gnutls.org/).
|
||||
@ -19,7 +19,7 @@ Only [GnuTLS](https://www.gnutls.org/) or [OpenSSL](https://www.openssl.org/) ar
|
||||
Submodules:
|
||||
- libjuice: https://github.com/paullouisageneau/libjuice
|
||||
- usrsctp: https://github.com/sctplab/usrsctp
|
||||
- libsrtp: https://github.com/cisco/libsrtp
|
||||
- libsrtp: https://github.com/cisco/libsrtp (if compiled with media support)
|
||||
|
||||
## Building
|
||||
|
||||
@ -124,6 +124,8 @@ The library implements the following communication protocols:
|
||||
|
||||
### WebRTC Data Channels and Media Transport
|
||||
|
||||
The library implements WebRTC Peer Connections with both Data Channels and Media Transport. Media transport is optional and can be disabled at compile time.
|
||||
|
||||
Protocol stack:
|
||||
- SCTP-based Data Channels ([RFC8831](https://tools.ietf.org/html/rfc8831))
|
||||
- SRTP-based Media Transport ([RFC8834](https://tools.ietf.org/html/rfc8834))
|
||||
|
@ -118,7 +118,7 @@ function createPeerConnection(ws, id) {
|
||||
pc.onconnectionstatechange = () => console.log(`Connection state: ${pc.connectionState}`);
|
||||
pc.onicegatheringstatechange = () => console.log(`Gathering state: ${pc.iceGatheringState}`);
|
||||
pc.onicecandidate = (e) => {
|
||||
if (e.candidate) {
|
||||
if (e.candidate && e.candidate.candidate) {
|
||||
// Send candidate
|
||||
sendLocalCandidate(ws, id, e.candidate);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
#ifndef htonll
|
||||
#define htonll(x) \
|
||||
((uint64_t)htonl(((uint64_t)(x)&0xFFFFFFFF) << 32) | (uint64_t)htonl((uint64_t)(x) >> 32))
|
||||
((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32)))
|
||||
#endif
|
||||
#ifndef ntohll
|
||||
#define ntohll(x) htonll(x)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace rtc {
|
||||
|
||||
@ -32,11 +33,10 @@ template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||
// weak_ptr bind helper
|
||||
template <typename F, typename T, typename... Args> auto weak_bind(F &&f, T *t, Args &&..._args) {
|
||||
return [bound = std::bind(f, t, _args...), weak_this = t->weak_from_this()](auto &&...args) {
|
||||
using result_type = typename decltype(bound)::result_type;
|
||||
if (auto shared_this = weak_this.lock())
|
||||
return bound(args...);
|
||||
else
|
||||
return static_cast<result_type>(false);
|
||||
return static_cast<decltype(bound(args...))>(false);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,7 @@ size_t DataChannel::maxMessageSize() const {
|
||||
}
|
||||
|
||||
void DataChannel::shiftStream() {
|
||||
std::shared_lock lock(mMutex);
|
||||
if (mStream % 2 == 1)
|
||||
mStream -= 1;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ struct PeerConnection;
|
||||
struct DataChannel : Channel, std::enable_shared_from_this<DataChannel> {
|
||||
DataChannel(weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol,
|
||||
Reliability reliability);
|
||||
~DataChannel();
|
||||
virtual ~DataChannel();
|
||||
|
||||
void close();
|
||||
void remoteClose();
|
||||
|
@ -189,7 +189,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
|
||||
auto certificate = mCertificate.get();
|
||||
auto lower = std::atomic_load(&mIceTransport);
|
||||
auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1);
|
||||
auto stateChangeCallback =
|
||||
auto dtlsStateChangeCallback =
|
||||
[this, weak_this = weak_from_this()](DtlsTransport::State transportState) {
|
||||
auto shared_this = weak_this.lock();
|
||||
if (!shared_this)
|
||||
@ -224,7 +224,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
|
||||
// DTLS-SRTP
|
||||
transport = std::make_shared<DtlsSrtpTransport>(
|
||||
lower, certificate, config.mtu, verifierCallback,
|
||||
weak_bind(&PeerConnection::forwardMedia, this, _1), stateChangeCallback);
|
||||
weak_bind(&PeerConnection::forwardMedia, this, _1), dtlsStateChangeCallback);
|
||||
#else
|
||||
PLOG_WARNING << "Ignoring media support (not compiled with media support)";
|
||||
#endif
|
||||
@ -233,7 +233,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
|
||||
if (!transport) {
|
||||
// DTLS only
|
||||
transport = std::make_shared<DtlsTransport>(lower, certificate, config.mtu,
|
||||
verifierCallback, stateChangeCallback);
|
||||
verifierCallback, dtlsStateChangeCallback);
|
||||
}
|
||||
|
||||
std::atomic_store(&mDtlsTransport, transport);
|
||||
@ -262,6 +262,9 @@ shared_ptr<SctpTransport> PeerConnection::initSctpTransport() {
|
||||
if (!remote || !remote->application())
|
||||
throw std::logic_error("Starting SCTP transport without application description");
|
||||
|
||||
// This is the last occasion to ensure the stream numbers are coherent with the role
|
||||
shiftDataChannels();
|
||||
|
||||
uint16_t sctpPort = remote->application()->sctpPort().value_or(DEFAULT_SCTP_PORT);
|
||||
auto lower = std::atomic_load(&mDtlsTransport);
|
||||
auto transport = std::make_shared<SctpTransport>(
|
||||
@ -549,8 +552,7 @@ void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) {
|
||||
channel->triggerBufferedAmount(amount);
|
||||
}
|
||||
|
||||
shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role role, string label,
|
||||
DataChannelInit init) {
|
||||
shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(string label, DataChannelInit init) {
|
||||
std::unique_lock lock(mDataChannelsMutex); // we are going to emplace
|
||||
uint16_t stream;
|
||||
if (init.id) {
|
||||
@ -558,6 +560,13 @@ shared_ptr<DataChannel> PeerConnection::emplaceDataChannel(Description::Role rol
|
||||
if (stream == 65535)
|
||||
throw std::invalid_argument("Invalid DataChannel id");
|
||||
} else {
|
||||
// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
|
||||
// setup:passive. [...] Thus, setup:active is RECOMMENDED.
|
||||
// See https://tools.ietf.org/html/rfc5763#section-5
|
||||
// Therefore, we assume passive role if we are the offerer.
|
||||
auto iceTransport = getIceTransport();
|
||||
auto role = iceTransport ? iceTransport->role() : Description::Role::Passive;
|
||||
|
||||
// RFC 8832: The peer that initiates opening a data channel selects a stream identifier for
|
||||
// which the corresponding incoming and outgoing streams are unused. If the side is acting
|
||||
// as the DTLS client, it MUST choose an even stream identifier; if the side is acting as
|
||||
@ -729,7 +738,7 @@ void PeerConnection::validateRemoteDescription(const Description &description) {
|
||||
}
|
||||
|
||||
void PeerConnection::processLocalDescription(Description description) {
|
||||
const size_t localSctpPort = DEFAULT_SCTP_PORT;
|
||||
const uint16_t localSctpPort = DEFAULT_SCTP_PORT;
|
||||
const size_t localMaxMessageSize =
|
||||
config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
|
||||
|
||||
@ -907,6 +916,10 @@ void PeerConnection::processRemoteDescription(Description description) {
|
||||
auto iceTransport = initIceTransport();
|
||||
iceTransport->setRemoteDescription(std::move(description));
|
||||
|
||||
// Since we assumed passive role during DataChannel creation, we might need to shift the stream
|
||||
// numbers from odd to even.
|
||||
shiftDataChannels();
|
||||
|
||||
if (description.hasApplication()) {
|
||||
auto dtlsTransport = std::atomic_load(&mDtlsTransport);
|
||||
auto sctpTransport = std::atomic_load(&mSctpTransport);
|
||||
|
@ -65,8 +65,7 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
|
||||
void forwardBufferedAmount(uint16_t stream, size_t amount);
|
||||
optional<string> getMidFromSsrc(uint32_t ssrc);
|
||||
|
||||
shared_ptr<DataChannel> emplaceDataChannel(Description::Role role, string label,
|
||||
DataChannelInit init);
|
||||
shared_ptr<DataChannel> emplaceDataChannel(string label, DataChannelInit init);
|
||||
shared_ptr<DataChannel> findDataChannel(uint16_t stream);
|
||||
void shiftDataChannels();
|
||||
void iterateDataChannels(std::function<void(shared_ptr<DataChannel> channel)> func);
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
#ifndef htonll
|
||||
#define htonll(x) \
|
||||
((uint64_t)htonl(((uint64_t)(x)&0xFFFFFFFF) << 32) | (uint64_t)htonl((uint64_t)(x) >> 32))
|
||||
((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32)))
|
||||
#endif
|
||||
#ifndef ntohll
|
||||
#define ntohll(x) htonll(x)
|
||||
|
@ -223,11 +223,6 @@ void PeerConnection::setRemoteDescription(Description description) {
|
||||
// This is an offer, we need to answer
|
||||
if (!impl()->config.disableAutoNegotiation)
|
||||
setLocalDescription(Description::Type::Answer);
|
||||
} else {
|
||||
// This is an answer
|
||||
// Since we assumed passive role during DataChannel creation, we need to shift the
|
||||
// stream numbers by one to shift them from odd to even.
|
||||
impl()->shiftDataChannels();
|
||||
}
|
||||
|
||||
for (const auto &candidate : remoteCandidates)
|
||||
@ -250,14 +245,7 @@ optional<string> PeerConnection::remoteAddress() const {
|
||||
}
|
||||
|
||||
shared_ptr<DataChannel> PeerConnection::createDataChannel(string label, DataChannelInit init) {
|
||||
// RFC 5763: The answerer MUST use either a setup attribute value of setup:active or
|
||||
// setup:passive. [...] Thus, setup:active is RECOMMENDED.
|
||||
// See https://tools.ietf.org/html/rfc5763#section-5
|
||||
// Therefore, we assume passive role when we are the offerer.
|
||||
auto iceTransport = impl()->getIceTransport();
|
||||
auto role = iceTransport ? iceTransport->role() : Description::Role::Passive;
|
||||
|
||||
auto channelImpl = impl()->emplaceDataChannel(role, std::move(label), std::move(init));
|
||||
auto channelImpl = impl()->emplaceDataChannel(std::move(label), std::move(init));
|
||||
auto channel = std::make_shared<DataChannel>(channelImpl);
|
||||
|
||||
if (auto transport = impl()->getSctpTransport())
|
||||
|
Reference in New Issue
Block a user