Added PeerConnection::close() and revised state machine

This commit is contained in:
Paul-Louis Ageneau
2019-12-16 12:15:59 +01:00
parent e5a19f85ed
commit 1d7d1358be
7 changed files with 66 additions and 26 deletions

View File

@ -11,7 +11,7 @@ LIBS=glib-2.0 gobject-2.0 nice
USRSCTP_DIR=usrsctp USRSCTP_DIR=usrsctp
USE_GNUTLS ?= 0 USE_GNUTLS ?= 0
ifeq ($(USE_GNUTLS), 1) ifneq ($(USE_GNUTLS), 0)
CPPFLAGS+= -DUSE_GNUTLS=1 CPPFLAGS+= -DUSE_GNUTLS=1
LIBS+= gnutls LIBS+= gnutls
else else

View File

@ -66,12 +66,13 @@ public:
Reliability reliability() const; Reliability reliability() const;
private: private:
void remoteClose();
void open(std::shared_ptr<SctpTransport> sctpTransport); void open(std::shared_ptr<SctpTransport> sctpTransport);
bool outgoing(mutable_message_ptr message); bool outgoing(mutable_message_ptr message);
void incoming(message_ptr message); void incoming(message_ptr message);
void processOpenMessage(message_ptr message); void processOpenMessage(message_ptr message);
std::shared_ptr<PeerConnection> mPeerConnection; const std::shared_ptr<PeerConnection> mPeerConnection;
std::shared_ptr<SctpTransport> mSctpTransport; std::shared_ptr<SctpTransport> mSctpTransport;
unsigned int mStream; unsigned int mStream;

View File

@ -50,7 +50,8 @@ public:
Connected = RTC_CONNECTED, Connected = RTC_CONNECTED,
Disconnected = RTC_DISCONNECTED, Disconnected = RTC_DISCONNECTED,
Failed = RTC_FAILED, Failed = RTC_FAILED,
Closed = RTC_CLOSED Closed = RTC_CLOSED,
Destroying = RTC_DESTROYING
}; };
enum class GatheringState : int { enum class GatheringState : int {
@ -63,6 +64,8 @@ public:
PeerConnection(const Configuration &config); PeerConnection(const Configuration &config);
~PeerConnection(); ~PeerConnection();
void close();
const Configuration *config() const; const Configuration *config() const;
State state() const; State state() const;
GatheringState gatheringState() const; GatheringState gatheringState() const;
@ -94,6 +97,7 @@ private:
void iterateDataChannels(std::function<void(std::shared_ptr<DataChannel> channel)> func); void iterateDataChannels(std::function<void(std::shared_ptr<DataChannel> channel)> func);
void openDataChannels(); void openDataChannels();
void closeDataChannels(); void closeDataChannels();
void remoteCloseDataChannels();
void processLocalDescription(Description description); void processLocalDescription(Description description);
void processLocalCandidate(Candidate candidate); void processLocalCandidate(Candidate candidate);

View File

@ -31,7 +31,8 @@ typedef enum {
RTC_CONNECTED = 2, RTC_CONNECTED = 2,
RTC_DISCONNECTED = 3, RTC_DISCONNECTED = 3,
RTC_FAILED = 4, RTC_FAILED = 4,
RTC_CLOSED = 5 RTC_CLOSED = 5,
RTC_DESTROYING = 6 // internal
} rtc_state_t; } rtc_state_t;
typedef enum { typedef enum {

View File

@ -73,18 +73,23 @@ DataChannel::DataChannel(shared_ptr<PeerConnection> pc, shared_ptr<SctpTransport
mReliability(std::make_shared<Reliability>()), mReliability(std::make_shared<Reliability>()),
mRecvQueue(RECV_QUEUE_LIMIT, message_size_func) {} mRecvQueue(RECV_QUEUE_LIMIT, message_size_func) {}
DataChannel::~DataChannel() { close(); } DataChannel::~DataChannel() {
close();
}
void DataChannel::close() { void DataChannel::close() {
mIsOpen = false; mIsClosed = true;
if (!mIsClosed.exchange(true)) { if (mIsOpen.exchange(false))
if (mSctpTransport) if (mSctpTransport)
mSctpTransport->reset(mStream); mSctpTransport->reset(mStream);
}
// Reset mSctpTransport first so SctpTransport is never alive without PeerConnection
mSctpTransport.reset(); mSctpTransport.reset();
mPeerConnection.reset(); }
void DataChannel::remoteClose() {
mIsOpen = false;
if (!mIsClosed.exchange(true))
triggerClosed();
} }
bool DataChannel::send(const std::variant<binary, string> &data) { bool DataChannel::send(const std::variant<binary, string> &data) {
@ -108,12 +113,8 @@ std::optional<std::variant<binary, string>> DataChannel::receive() {
switch (message->type) { switch (message->type) {
case Message::Control: { case Message::Control: {
auto raw = reinterpret_cast<const uint8_t *>(message->data()); auto raw = reinterpret_cast<const uint8_t *>(message->data());
if (raw[0] == MESSAGE_CLOSE) { if (raw[0] == MESSAGE_CLOSE)
if (mIsOpen) { remoteClose();
close();
triggerClosed();
}
}
break; break;
} }
case Message::String: case Message::String:

View File

@ -38,6 +38,19 @@ PeerConnection::PeerConnection(const Configuration &config)
: mConfig(config), mCertificate(make_certificate("libdatachannel")), mState(State::New) {} : mConfig(config), mCertificate(make_certificate("libdatachannel")), mState(State::New) {}
PeerConnection::~PeerConnection() { PeerConnection::~PeerConnection() {
changeState(State::Destroying);
close();
mSctpTransport.reset();
mDtlsTransport.reset();
mIceTransport.reset();
}
void PeerConnection::close() {
// Close DataChannels
closeDataChannels();
mDataChannels.clear();
// Close Transports
if (auto transport = std::atomic_load(&mIceTransport)) if (auto transport = std::atomic_load(&mIceTransport))
transport->stop(); transport->stop();
if (auto transport = std::atomic_load(&mDtlsTransport)) if (auto transport = std::atomic_load(&mDtlsTransport))
@ -45,9 +58,8 @@ PeerConnection::~PeerConnection() {
if (auto transport = std::atomic_load(&mSctpTransport)) if (auto transport = std::atomic_load(&mSctpTransport))
transport->stop(); transport->stop();
mSctpTransport.reset(); // Change state
mDtlsTransport.reset(); changeState(State::Closed);
mIceTransport.reset();
} }
const Configuration *PeerConnection::config() const { return &mConfig; } const Configuration *PeerConnection::config() const { return &mConfig; }
@ -210,6 +222,9 @@ shared_ptr<IceTransport> PeerConnection::initIceTransport(Description::Role role
case IceTransport::State::Connected: case IceTransport::State::Connected:
initDtlsTransport(); initDtlsTransport();
break; break;
case IceTransport::State::Disconnected:
changeState(State::Disconnected);
break;
default: default:
// Ignore // Ignore
break; break;
@ -246,6 +261,9 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
case DtlsTransport::State::Failed: case DtlsTransport::State::Failed:
changeState(State::Failed); changeState(State::Failed);
break; break;
case DtlsTransport::State::Disconnected:
changeState(State::Disconnected);
break;
default: default:
// Ignore // Ignore
break; break;
@ -293,7 +311,7 @@ bool PeerConnection::checkFingerprint(const std::string &fingerprint) const {
void PeerConnection::forwardMessage(message_ptr message) { void PeerConnection::forwardMessage(message_ptr message) {
if (!message) { if (!message) {
closeDataChannels(); remoteCloseDataChannels();
return; return;
} }
@ -368,6 +386,10 @@ void PeerConnection::closeDataChannels() {
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->close(); }); iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->close(); });
} }
void PeerConnection::remoteCloseDataChannels() {
iterateDataChannels([&](shared_ptr<DataChannel> channel) { channel->remoteClose(); });
}
void PeerConnection::processLocalDescription(Description description) { void PeerConnection::processLocalDescription(Description description) {
std::optional<uint16_t> remoteSctpPort; std::optional<uint16_t> remoteSctpPort;
if (auto remote = remoteDescription()) if (auto remote = remoteDescription())
@ -401,7 +423,14 @@ void PeerConnection::triggerDataChannel(weak_ptr<DataChannel> weakDataChannel) {
} }
void PeerConnection::changeState(State state) { void PeerConnection::changeState(State state) {
if (mState.exchange(state) != state) State current;
do {
current = mState.load();
if (current == state || current == State::Destroying)
return;
} while (!mState.compare_exchange_weak(current, state));
if (state != State::Destroying)
mStateChangeCallback(state); mStateChangeCallback(state);
} }
@ -431,6 +460,12 @@ std::ostream &operator<<(std::ostream &out, const rtc::PeerConnection::State &st
case State::Failed: case State::Failed:
str = "failed"; str = "failed";
break; break;
case State::Closed:
str = "closed";
break;
case State::Destroying:
str = "destroying";
break;
default: default:
str = "unknown"; str = "unknown";
break; break;

View File

@ -145,12 +145,10 @@ SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
SctpTransport::~SctpTransport() { SctpTransport::~SctpTransport() {
stop(); stop();
if (mSock) {
usrsctp_shutdown(mSock, SHUT_RDWR); usrsctp_shutdown(mSock, SHUT_RDWR);
usrsctp_close(mSock); usrsctp_close(mSock);
}
usrsctp_deregister_address(this); usrsctp_deregister_address(this);
GlobalCleanup(); GlobalCleanup();
} }