diff --git a/examples/copy-paste-capi/answerer.c b/examples/copy-paste-capi/answerer.c index 0329764c1..fcf277a5e 100644 --- a/examples/copy-paste-capi/answerer.c +++ b/examples/copy-paste-capi/answerer.c @@ -35,6 +35,7 @@ static void RTC_API dataChannelCallback(int pc, int dc, void *ptr); static void RTC_API descriptionCallback(int pc, const char *sdp, const char *type, void *ptr); static void RTC_API candidateCallback(int pc, const char *cand, const char *mid, void *ptr); static void RTC_API stateChangeCallback(int pc, rtcState state, void *ptr); +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr); static void RTC_API gatheringStateCallback(int pc, rtcGatheringState state, void *ptr); static void RTC_API closedCallback(int id, void *ptr); static void RTC_API messageCallback(int id, const char *message, int size, void *ptr); @@ -69,6 +70,7 @@ int main(int argc, char **argv) { rtcSetLocalCandidateCallback(peer->pc, candidateCallback); rtcSetStateChangeCallback(peer->pc, stateChangeCallback); rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback); + rtcSetDtlsHandshakeDoneCallback(peer->pc, DtlsHandshakeDoneCallback); rtcSetDataChannelCallback(peer->pc, dataChannelCallback); @@ -196,6 +198,11 @@ static void RTC_API stateChangeCallback(int pc, rtcState state, void *ptr) { printf("State %s: %s\n", "answerer", state_print(state)); } +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Dtls info version: %s cipher: %s\n", dtlsVersion, cipher); +} + static void RTC_API gatheringStateCallback(int pc, rtcGatheringState state, void *ptr) { Peer *peer = (Peer *)ptr; peer->gatheringState = state; diff --git a/examples/copy-paste-capi/offerer.c b/examples/copy-paste-capi/offerer.c index 343feb647..351751f77 100644 --- a/examples/copy-paste-capi/offerer.c +++ b/examples/copy-paste-capi/offerer.c @@ -34,6 +34,7 @@ typedef struct { static void RTC_API descriptionCallback(int pc, const char *sdp, const char *type, void *ptr); static void RTC_API candidateCallback(int pc, const char *cand, const char *mid, void *ptr); static void RTC_API stateChangeCallback(int pc, rtcState state, void *ptr); +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr); static void RTC_API gatheringStateCallback(int pc, rtcGatheringState state, void *ptr); static void RTC_API openCallback(int id, void *ptr); static void RTC_API closedCallback(int id, void *ptr); @@ -68,6 +69,7 @@ int main(int argc, char **argv) { rtcSetLocalCandidateCallback(peer->pc, candidateCallback); rtcSetStateChangeCallback(peer->pc, stateChangeCallback); rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback); + rtcSetDtlsHandshakeDoneCallback(peer->pc, DtlsHandshakeDoneCallback); // Since we are the offerer, we will create a datachannel peer->dc = rtcCreateDataChannel(peer->pc, "test"); @@ -200,6 +202,11 @@ static void RTC_API stateChangeCallback(int pc, rtcState state, void *ptr) { printf("State %s: %s\n", "offerer", state_print(state)); } +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Dtls info version: %s cipher: %s\n", dtlsVersion, cipher); +} + static void RTC_API gatheringStateCallback(int pc, rtcGatheringState state, void *ptr) { Peer *peer = (Peer *)ptr; peer->gatheringState = state; diff --git a/include/rtc/peerconnection.hpp b/include/rtc/peerconnection.hpp index 0afc2ad56..bb1ad76cb 100644 --- a/include/rtc/peerconnection.hpp +++ b/include/rtc/peerconnection.hpp @@ -110,6 +110,7 @@ class RTC_CPP_EXPORT PeerConnection final : CheshireCat { void onIceStateChange(std::function callback); void onGatheringStateChange(std::function callback); void onSignalingStateChange(std::function callback); + void onDtlsHandshakeDone(std::function callback); void resetCallbacks(); diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index 4750d7798..57643e73a 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -144,6 +144,7 @@ typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const typedef void(RTC_API *rtcCandidateCallbackFunc)(int pc, const char *cand, const char *mid, void *ptr); typedef void(RTC_API *rtcStateChangeCallbackFunc)(int pc, rtcState state, void *ptr); +typedef void(RTC_API *rtcDTLSHandshakeDoneCallbackFunc)(int pc, const char *dtlsVersion, const char* cipher, void *ptr); typedef void(RTC_API *rtcIceStateChangeCallbackFunc)(int pc, rtcIceState state, void *ptr); typedef void(RTC_API *rtcGatheringStateCallbackFunc)(int pc, rtcGatheringState state, void *ptr); typedef void(RTC_API *rtcSignalingStateCallbackFunc)(int pc, rtcSignalingState state, void *ptr); @@ -202,6 +203,8 @@ RTC_C_EXPORT int rtcSetLocalDescription(int pc, const char *type); RTC_C_EXPORT int rtcSetRemoteDescription(int pc, const char *sdp, const char *type); RTC_C_EXPORT int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid); +RTC_C_EXPORT int rtcSetDtlsHandshakeDoneCallback(int pc, rtcDTLSHandshakeDoneCallbackFunc cb); + RTC_C_EXPORT int rtcGetLocalDescription(int pc, char *buffer, int size); RTC_C_EXPORT int rtcGetRemoteDescription(int pc, char *buffer, int size); diff --git a/src/capi.cpp b/src/capi.cpp index 211e3de34..5e7b7c0a9 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -475,6 +475,20 @@ int rtcSetStateChangeCallback(int pc, rtcStateChangeCallbackFunc cb) { }); } +int rtcSetDtlsHandshakeDoneCallback(int pc, rtcDTLSHandshakeDoneCallbackFunc cb) { + return wrap([&] { + auto peerConnection = getPeerConnection(pc); + if (cb) + peerConnection->onDtlsHandshakeDone([pc, cb](const std::string& version, const std::string& cipher) { + if (auto ptr = getUserPointer(pc)) + cb(pc, version.c_str(), cipher.c_str(), *ptr); + }); + else + peerConnection->onDtlsHandshakeDone(nullptr); + return RTC_ERR_SUCCESS; + }); +} + int rtcSetIceStateChangeCallback(int pc, rtcIceStateChangeCallbackFunc cb) { return wrap([&] { auto peerConnection = getPeerConnection(pc); diff --git a/src/impl/dtlstransport.cpp b/src/impl/dtlstransport.cpp index aa5182411..953d6f149 100644 --- a/src/impl/dtlstransport.cpp +++ b/src/impl/dtlstransport.cpp @@ -179,6 +179,20 @@ void DtlsTransport::postHandshake() { // Dummy } +DtlsTransport::DtlsInfo DtlsTransport::getDtlsInfo() { + DtlsInfo info; + { + std::lock_guard lock(mSslMutex); + auto desc = gnutls_session_get_desc(mSession); + if (desc) { + info.version = "gnu"; + info.suite = desc; + gnutls_free(desc); + } + } + return info; +} + void DtlsTransport::doRecv() { std::lock_guard lock(mRecvMutex); --mPendingRecvCount; @@ -519,6 +533,20 @@ void DtlsTransport::postHandshake() { // Dummy } +DtlsTransport::DtlsInfo DtlsTransport::getDtlsInfo() { + DtlsInfo info; + { + std::lock_guard lock(mSslMutex); + auto version = mbedtls_ssl_get_version(&mSsl); + auto suite = mbedtls_ssl_get_ciphersuite(&mSsl); + if (version && suite) { + info.version = version; + info.suite = suite; + } + } + return info; +} + void DtlsTransport::doRecv() { std::lock_guard lock(mRecvMutex); --mPendingRecvCount; @@ -912,6 +940,20 @@ void DtlsTransport::postHandshake() { // Dummy } +DtlsTransport::DtlsInfo DtlsTransport::getDtlsInfo() { + DtlsInfo info; + { + std::lock_guard lock(mSslMutex); + auto version = SSL_get_version(mSsl); + auto suite = SSL_get_cipher(mSsl); + if (version && suite) { + info.version = version; + info.suite = suite; + } + } + return info; +} + void DtlsTransport::doRecv() { std::lock_guard lock(mRecvMutex); --mPendingRecvCount; diff --git a/src/impl/dtlstransport.hpp b/src/impl/dtlstransport.hpp index d84b312e8..06dbd0da8 100644 --- a/src/impl/dtlstransport.hpp +++ b/src/impl/dtlstransport.hpp @@ -41,6 +41,12 @@ class DtlsTransport : public Transport, public std::enable_shared_from_this PeerConnection::initIceTransport() { } } +void PeerConnection::printDtlsInfo() { + auto lower = std::atomic_load(&mDtlsTransport); + if (lower) { + auto info = lower->getDtlsInfo(); + PLOG_INFO << "Connected with DTLS version " << info.version + << ", cipher suite " << info.suite; + if (dtlsHandshakeDoneCallback) { + dtlsHandshakeDoneCallback(info.version, info.suite); + } + } +} + shared_ptr PeerConnection::initDtlsTransport() { try { if (auto transport = std::atomic_load(&mDtlsTransport)) @@ -225,6 +237,7 @@ shared_ptr PeerConnection::initDtlsTransport() { switch (transportState) { case DtlsTransport::State::Connected: + printDtlsInfo(); if (auto remote = remoteDescription(); remote && remote->hasApplication()) initSctpTransport(); else @@ -1266,6 +1279,7 @@ void PeerConnection::resetCallbacks() { iceStateChangeCallback = nullptr; gatheringStateChangeCallback = nullptr; signalingStateChangeCallback = nullptr; + dtlsHandshakeDoneCallback = nullptr; trackCallback = nullptr; } diff --git a/src/impl/peerconnection.hpp b/src/impl/peerconnection.hpp index ad6f41e28..6124531be 100644 --- a/src/impl/peerconnection.hpp +++ b/src/impl/peerconnection.hpp @@ -124,9 +124,11 @@ struct PeerConnection : std::enable_shared_from_this { synchronized_callback iceStateChangeCallback; synchronized_callback gatheringStateChangeCallback; synchronized_callback signalingStateChangeCallback; + synchronized_callback dtlsHandshakeDoneCallback; synchronized_callback> trackCallback; private: + void printDtlsInfo(); void dispatchMedia(message_ptr message); void updateTrackSsrcCache(const Description &description); diff --git a/src/peerconnection.cpp b/src/peerconnection.cpp index 11d585b87..8253c8ab2 100644 --- a/src/peerconnection.cpp +++ b/src/peerconnection.cpp @@ -327,6 +327,10 @@ void PeerConnection::onSignalingStateChange(std::functionsignalingStateChangeCallback = callback; } +void PeerConnection::onDtlsHandshakeDone(std::function callback) { + impl()->dtlsHandshakeDoneCallback = callback; +} + void PeerConnection::resetCallbacks() { impl()->resetCallbacks(); } bool PeerConnection::getSelectedCandidatePair(Candidate *local, Candidate *remote) { diff --git a/test/capi_connectivity.cpp b/test/capi_connectivity.cpp index fd86192e9..3ddf925b1 100644 --- a/test/capi_connectivity.cpp +++ b/test/capi_connectivity.cpp @@ -72,6 +72,11 @@ static void RTC_API signalingStateCallback(int pc, rtcSignalingState state, void printf("Signaling state %d: %d\n", peer == peer1 ? 1 : 2, (int)state); } +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Dtls info version: %s cipher: %s\n", dtlsVersion, cipher); +} + static void RTC_API openCallback(int id, void *ptr) { Peer *peer = (Peer *)ptr; peer->connected = true; @@ -168,6 +173,7 @@ static Peer *createPeer(const rtcConfiguration *config) { rtcSetIceStateChangeCallback(peer->pc, iceStateChangeCallback); rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback); rtcSetSignalingStateChangeCallback(peer->pc, signalingStateCallback); + rtcSetDtlsHandshakeDoneCallback(peer->pc, DtlsHandshakeDoneCallback); return peer; } diff --git a/test/capi_track.cpp b/test/capi_track.cpp index e728a339f..c1b7845cb 100644 --- a/test/capi_track.cpp +++ b/test/capi_track.cpp @@ -54,6 +54,11 @@ static void RTC_API stateChangeCallback(int pc, rtcState state, void *ptr) { printf("State %d: %d\n", peer == peer1 ? 1 : 2, (int)state); } +static void RTC_API DtlsHandshakeDoneCallback(int pc, const char *dtlsVersion, const char* cipher, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Dtls info version: %s cipher: %s\n", dtlsVersion, cipher); +} + static void RTC_API gatheringStateCallback(int pc, rtcGatheringState state, void *ptr) { Peer *peer = (Peer *)ptr; peer->gatheringState = state; @@ -122,6 +127,7 @@ static Peer *createPeer(const rtcConfiguration *config) { rtcSetLocalCandidateCallback(peer->pc, candidateCallback); rtcSetStateChangeCallback(peer->pc, stateChangeCallback); rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback); + rtcSetDtlsHandshakeDoneCallback(peer->pc, DtlsHandshakeDoneCallback); peer->tr = -1; return peer;