mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 02:34:26 +08:00
批量替换tab为4个空格
This commit is contained in:
parent
a5c3db4ee1
commit
56d6eb0f28
@ -269,9 +269,9 @@ API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int l
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_input_pcm(mk_media ctx, void *data , int len, uint64_t pts){
|
||||
assert(ctx && data && len > 0);
|
||||
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
|
||||
return (*obj)->getChannel()->inputPCM((char*)data, len, pts);
|
||||
assert(ctx && data && len > 0);
|
||||
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
|
||||
return (*obj)->getChannel()->inputPCM((char*)data, len, pts);
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_input_audio(mk_media ctx, const void* data, int len, uint64_t dts){
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,50 +33,50 @@ using namespace toolkit;
|
||||
namespace RTC
|
||||
{
|
||||
class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
{
|
||||
public:
|
||||
enum class DtlsState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
};
|
||||
{
|
||||
public:
|
||||
enum class DtlsState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
};
|
||||
|
||||
public:
|
||||
enum class Role
|
||||
{
|
||||
NONE = 0,
|
||||
AUTO = 1,
|
||||
CLIENT,
|
||||
SERVER
|
||||
};
|
||||
public:
|
||||
enum class Role
|
||||
{
|
||||
NONE = 0,
|
||||
AUTO = 1,
|
||||
CLIENT,
|
||||
SERVER
|
||||
};
|
||||
|
||||
public:
|
||||
enum class FingerprintAlgorithm
|
||||
{
|
||||
NONE = 0,
|
||||
SHA1 = 1,
|
||||
SHA224,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512
|
||||
};
|
||||
public:
|
||||
enum class FingerprintAlgorithm
|
||||
{
|
||||
NONE = 0,
|
||||
SHA1 = 1,
|
||||
SHA224,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512
|
||||
};
|
||||
|
||||
public:
|
||||
struct Fingerprint
|
||||
{
|
||||
FingerprintAlgorithm algorithm{ FingerprintAlgorithm::NONE };
|
||||
std::string value;
|
||||
};
|
||||
public:
|
||||
struct Fingerprint
|
||||
{
|
||||
FingerprintAlgorithm algorithm{ FingerprintAlgorithm::NONE };
|
||||
std::string value;
|
||||
};
|
||||
|
||||
private:
|
||||
struct SrtpCryptoSuiteMapEntry
|
||||
{
|
||||
RTC::SrtpSession::CryptoSuite cryptoSuite;
|
||||
const char* name;
|
||||
};
|
||||
private:
|
||||
struct SrtpCryptoSuiteMapEntry
|
||||
{
|
||||
RTC::SrtpSession::CryptoSuite cryptoSuite;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
class DtlsEnvironment : public std::enable_shared_from_this<DtlsEnvironment>
|
||||
{
|
||||
@ -99,154 +99,154 @@ namespace RTC
|
||||
std::vector<Fingerprint> localFingerprints;
|
||||
};
|
||||
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
// DTLS is in the process of negotiating a secure connection. Incoming
|
||||
// media can flow through.
|
||||
// NOTE: The caller MUST NOT call any method during this callback.
|
||||
virtual void OnDtlsTransportConnecting(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// DTLS has completed negotiation of a secure connection (including DTLS-SRTP
|
||||
// and remote fingerprint verification). Outgoing media can now flow through.
|
||||
// NOTE: The caller MUST NOT call any method during this callback.
|
||||
virtual void OnDtlsTransportConnected(
|
||||
const RTC::DtlsTransport* dtlsTransport,
|
||||
RTC::SrtpSession::CryptoSuite srtpCryptoSuite,
|
||||
uint8_t* srtpLocalKey,
|
||||
size_t srtpLocalKeyLen,
|
||||
uint8_t* srtpRemoteKey,
|
||||
size_t srtpRemoteKeyLen,
|
||||
std::string& remoteCert) = 0;
|
||||
// The DTLS connection has been closed as the result of an error (such as a
|
||||
// DTLS alert or a failure to validate the remote fingerprint).
|
||||
virtual void OnDtlsTransportFailed(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// The DTLS connection has been closed due to receipt of a close_notify alert.
|
||||
virtual void OnDtlsTransportClosed(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// Need to send DTLS data to the peer.
|
||||
virtual void OnDtlsTransportSendData(
|
||||
const RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) = 0;
|
||||
// DTLS application data received.
|
||||
virtual void OnDtlsTransportApplicationDataReceived(
|
||||
const RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) = 0;
|
||||
};
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
// DTLS is in the process of negotiating a secure connection. Incoming
|
||||
// media can flow through.
|
||||
// NOTE: The caller MUST NOT call any method during this callback.
|
||||
virtual void OnDtlsTransportConnecting(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// DTLS has completed negotiation of a secure connection (including DTLS-SRTP
|
||||
// and remote fingerprint verification). Outgoing media can now flow through.
|
||||
// NOTE: The caller MUST NOT call any method during this callback.
|
||||
virtual void OnDtlsTransportConnected(
|
||||
const RTC::DtlsTransport* dtlsTransport,
|
||||
RTC::SrtpSession::CryptoSuite srtpCryptoSuite,
|
||||
uint8_t* srtpLocalKey,
|
||||
size_t srtpLocalKeyLen,
|
||||
uint8_t* srtpRemoteKey,
|
||||
size_t srtpRemoteKeyLen,
|
||||
std::string& remoteCert) = 0;
|
||||
// The DTLS connection has been closed as the result of an error (such as a
|
||||
// DTLS alert or a failure to validate the remote fingerprint).
|
||||
virtual void OnDtlsTransportFailed(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// The DTLS connection has been closed due to receipt of a close_notify alert.
|
||||
virtual void OnDtlsTransportClosed(const RTC::DtlsTransport* dtlsTransport) = 0;
|
||||
// Need to send DTLS data to the peer.
|
||||
virtual void OnDtlsTransportSendData(
|
||||
const RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) = 0;
|
||||
// DTLS application data received.
|
||||
virtual void OnDtlsTransportApplicationDataReceived(
|
||||
const RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
static Role StringToRole(const std::string& role)
|
||||
{
|
||||
auto it = DtlsTransport::string2Role.find(role);
|
||||
public:
|
||||
static Role StringToRole(const std::string& role)
|
||||
{
|
||||
auto it = DtlsTransport::string2Role.find(role);
|
||||
|
||||
if (it != DtlsTransport::string2Role.end())
|
||||
return it->second;
|
||||
else
|
||||
return DtlsTransport::Role::NONE;
|
||||
}
|
||||
static FingerprintAlgorithm GetFingerprintAlgorithm(const std::string& fingerprint)
|
||||
{
|
||||
auto it = DtlsTransport::string2FingerprintAlgorithm.find(fingerprint);
|
||||
if (it != DtlsTransport::string2Role.end())
|
||||
return it->second;
|
||||
else
|
||||
return DtlsTransport::Role::NONE;
|
||||
}
|
||||
static FingerprintAlgorithm GetFingerprintAlgorithm(const std::string& fingerprint)
|
||||
{
|
||||
auto it = DtlsTransport::string2FingerprintAlgorithm.find(fingerprint);
|
||||
|
||||
if (it != DtlsTransport::string2FingerprintAlgorithm.end())
|
||||
return it->second;
|
||||
else
|
||||
return DtlsTransport::FingerprintAlgorithm::NONE;
|
||||
}
|
||||
static std::string& GetFingerprintAlgorithmString(FingerprintAlgorithm fingerprint)
|
||||
{
|
||||
auto it = DtlsTransport::fingerprintAlgorithm2String.find(fingerprint);
|
||||
if (it != DtlsTransport::string2FingerprintAlgorithm.end())
|
||||
return it->second;
|
||||
else
|
||||
return DtlsTransport::FingerprintAlgorithm::NONE;
|
||||
}
|
||||
static std::string& GetFingerprintAlgorithmString(FingerprintAlgorithm fingerprint)
|
||||
{
|
||||
auto it = DtlsTransport::fingerprintAlgorithm2String.find(fingerprint);
|
||||
|
||||
return it->second;
|
||||
}
|
||||
static bool IsDtls(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
// Minimum DTLS record length is 13 bytes.
|
||||
(len >= 13) &&
|
||||
// DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
|
||||
(data[0] > 19 && data[0] < 64)
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
private:
|
||||
static std::map<std::string, Role> string2Role;
|
||||
static std::map<std::string, FingerprintAlgorithm> string2FingerprintAlgorithm;
|
||||
static std::map<FingerprintAlgorithm, std::string> fingerprintAlgorithm2String;
|
||||
static std::vector<SrtpCryptoSuiteMapEntry> srtpCryptoSuites;
|
||||
|
||||
public:
|
||||
DtlsTransport(EventPoller::Ptr poller, Listener* listener);
|
||||
~DtlsTransport();
|
||||
|
||||
public:
|
||||
void Dump() const;
|
||||
void Run(Role localRole);
|
||||
std::vector<Fingerprint>& GetLocalFingerprints() const
|
||||
{
|
||||
return env->localFingerprints;
|
||||
}
|
||||
bool SetRemoteFingerprint(Fingerprint fingerprint);
|
||||
void ProcessDtlsData(const uint8_t* data, size_t len);
|
||||
DtlsState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
Role GetLocalRole() const
|
||||
{
|
||||
return this->localRole;
|
||||
}
|
||||
void SendApplicationData(const uint8_t* data, size_t len);
|
||||
|
||||
private:
|
||||
bool IsRunning() const
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case DtlsState::NEW:
|
||||
return false;
|
||||
case DtlsState::CONNECTING:
|
||||
case DtlsState::CONNECTED:
|
||||
return true;
|
||||
case DtlsState::FAILED:
|
||||
case DtlsState::CLOSED:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make GCC 4.9 happy.
|
||||
return false;
|
||||
}
|
||||
void Reset();
|
||||
bool CheckStatus(int returnCode);
|
||||
void SendPendingOutgoingDtlsData();
|
||||
bool SetTimeout();
|
||||
bool ProcessHandshake();
|
||||
bool CheckRemoteFingerprint();
|
||||
void ExtractSrtpKeys(RTC::SrtpSession::CryptoSuite srtpCryptoSuite);
|
||||
RTC::SrtpSession::CryptoSuite GetNegotiatedSrtpCryptoSuite();
|
||||
return it->second;
|
||||
}
|
||||
static bool IsDtls(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
// Minimum DTLS record length is 13 bytes.
|
||||
(len >= 13) &&
|
||||
// DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
|
||||
(data[0] > 19 && data[0] < 64)
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
private:
|
||||
void OnSslInfo(int where, int ret);
|
||||
void OnTimer();
|
||||
static std::map<std::string, Role> string2Role;
|
||||
static std::map<std::string, FingerprintAlgorithm> string2FingerprintAlgorithm;
|
||||
static std::map<FingerprintAlgorithm, std::string> fingerprintAlgorithm2String;
|
||||
static std::vector<SrtpCryptoSuiteMapEntry> srtpCryptoSuites;
|
||||
|
||||
private:
|
||||
public:
|
||||
DtlsTransport(EventPoller::Ptr poller, Listener* listener);
|
||||
~DtlsTransport();
|
||||
|
||||
public:
|
||||
void Dump() const;
|
||||
void Run(Role localRole);
|
||||
std::vector<Fingerprint>& GetLocalFingerprints() const
|
||||
{
|
||||
return env->localFingerprints;
|
||||
}
|
||||
bool SetRemoteFingerprint(Fingerprint fingerprint);
|
||||
void ProcessDtlsData(const uint8_t* data, size_t len);
|
||||
DtlsState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
Role GetLocalRole() const
|
||||
{
|
||||
return this->localRole;
|
||||
}
|
||||
void SendApplicationData(const uint8_t* data, size_t len);
|
||||
|
||||
private:
|
||||
bool IsRunning() const
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case DtlsState::NEW:
|
||||
return false;
|
||||
case DtlsState::CONNECTING:
|
||||
case DtlsState::CONNECTED:
|
||||
return true;
|
||||
case DtlsState::FAILED:
|
||||
case DtlsState::CLOSED:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make GCC 4.9 happy.
|
||||
return false;
|
||||
}
|
||||
void Reset();
|
||||
bool CheckStatus(int returnCode);
|
||||
void SendPendingOutgoingDtlsData();
|
||||
bool SetTimeout();
|
||||
bool ProcessHandshake();
|
||||
bool CheckRemoteFingerprint();
|
||||
void ExtractSrtpKeys(RTC::SrtpSession::CryptoSuite srtpCryptoSuite);
|
||||
RTC::SrtpSession::CryptoSuite GetNegotiatedSrtpCryptoSuite();
|
||||
|
||||
private:
|
||||
void OnSslInfo(int where, int ret);
|
||||
void OnTimer();
|
||||
|
||||
private:
|
||||
DtlsEnvironment::Ptr env;
|
||||
EventPoller::Ptr poller;
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
// Allocated by this.
|
||||
SSL* ssl{ nullptr };
|
||||
BIO* sslBioFromNetwork{ nullptr }; // The BIO from which ssl reads.
|
||||
BIO* sslBioToNetwork{ nullptr }; // The BIO in which ssl writes.
|
||||
Timer::Ptr timer;
|
||||
// Others.
|
||||
DtlsState state{ DtlsState::NEW };
|
||||
Role localRole{ Role::NONE };
|
||||
Fingerprint remoteFingerprint;
|
||||
bool handshakeDone{ false };
|
||||
bool handshakeDoneNow{ false };
|
||||
std::string remoteCert;
|
||||
//最大不超过mtu
|
||||
static constexpr int SslReadBufferSize{ 2000 };
|
||||
Listener* listener{ nullptr };
|
||||
// Allocated by this.
|
||||
SSL* ssl{ nullptr };
|
||||
BIO* sslBioFromNetwork{ nullptr }; // The BIO from which ssl reads.
|
||||
BIO* sslBioToNetwork{ nullptr }; // The BIO in which ssl writes.
|
||||
Timer::Ptr timer;
|
||||
// Others.
|
||||
DtlsState state{ DtlsState::NEW };
|
||||
Role localRole{ Role::NONE };
|
||||
Fingerprint remoteFingerprint;
|
||||
bool handshakeDone{ false };
|
||||
bool handshakeDoneNow{ false };
|
||||
std::string remoteCert;
|
||||
//最大不超过mtu
|
||||
static constexpr int SslReadBufferSize{ 2000 };
|
||||
uint8_t sslReadBuffer[SslReadBufferSize];
|
||||
};
|
||||
} // namespace RTC
|
||||
|
@ -24,505 +24,505 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
namespace RTC
|
||||
{
|
||||
/* Static. */
|
||||
/* Instance methods. */
|
||||
/* Static. */
|
||||
/* Instance methods. */
|
||||
|
||||
IceServer::IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password)
|
||||
: listener(listener), usernameFragment(usernameFragment), password(password)
|
||||
{
|
||||
MS_TRACE();
|
||||
}
|
||||
IceServer::IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password)
|
||||
: listener(listener), usernameFragment(usernameFragment), password(password)
|
||||
{
|
||||
MS_TRACE();
|
||||
}
|
||||
|
||||
void IceServer::ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
void IceServer::ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// Must be a Binding method.
|
||||
if (packet->GetMethod() != RTC::StunPacket::Method::BINDING)
|
||||
{
|
||||
if (packet->GetClass() == RTC::StunPacket::Class::REQUEST)
|
||||
{
|
||||
MS_WARN_TAG(
|
||||
ice,
|
||||
"unknown method %#.3x in STUN Request => 400",
|
||||
static_cast<unsigned int>(packet->GetMethod()));
|
||||
// Must be a Binding method.
|
||||
if (packet->GetMethod() != RTC::StunPacket::Method::BINDING)
|
||||
{
|
||||
if (packet->GetClass() == RTC::StunPacket::Class::REQUEST)
|
||||
{
|
||||
MS_WARN_TAG(
|
||||
ice,
|
||||
"unknown method %#.3x in STUN Request => 400",
|
||||
static_cast<unsigned int>(packet->GetMethod()));
|
||||
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_WARN_TAG(
|
||||
ice,
|
||||
"ignoring STUN Indication or Response with unknown method %#.3x",
|
||||
static_cast<unsigned int>(packet->GetMethod()));
|
||||
}
|
||||
delete response;
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_WARN_TAG(
|
||||
ice,
|
||||
"ignoring STUN Indication or Response with unknown method %#.3x",
|
||||
static_cast<unsigned int>(packet->GetMethod()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Must use FINGERPRINT (optional for ICE STUN indications).
|
||||
if (!packet->HasFingerprint() && packet->GetClass() != RTC::StunPacket::Class::INDICATION)
|
||||
{
|
||||
if (packet->GetClass() == RTC::StunPacket::Class::REQUEST)
|
||||
{
|
||||
MS_WARN_TAG(ice, "STUN Binding Request without FINGERPRINT => 400");
|
||||
// Must use FINGERPRINT (optional for ICE STUN indications).
|
||||
if (!packet->HasFingerprint() && packet->GetClass() != RTC::StunPacket::Class::INDICATION)
|
||||
{
|
||||
if (packet->GetClass() == RTC::StunPacket::Class::REQUEST)
|
||||
{
|
||||
MS_WARN_TAG(ice, "STUN Binding Request without FINGERPRINT => 400");
|
||||
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_WARN_TAG(ice, "ignoring STUN Binding Response without FINGERPRINT");
|
||||
}
|
||||
delete response;
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_WARN_TAG(ice, "ignoring STUN Binding Response without FINGERPRINT");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet->GetClass())
|
||||
{
|
||||
case RTC::StunPacket::Class::REQUEST:
|
||||
{
|
||||
// USERNAME, MESSAGE-INTEGRITY and PRIORITY are required.
|
||||
if (!packet->HasMessageIntegrity() || (packet->GetPriority() == 0u) || packet->GetUsername().empty())
|
||||
{
|
||||
MS_WARN_TAG(ice, "mising required attributes in STUN Binding Request => 400");
|
||||
switch (packet->GetClass())
|
||||
{
|
||||
case RTC::StunPacket::Class::REQUEST:
|
||||
{
|
||||
// USERNAME, MESSAGE-INTEGRITY and PRIORITY are required.
|
||||
if (!packet->HasMessageIntegrity() || (packet->GetPriority() == 0u) || packet->GetUsername().empty())
|
||||
{
|
||||
MS_WARN_TAG(ice, "mising required attributes in STUN Binding Request => 400");
|
||||
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
delete response;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check authentication.
|
||||
switch (packet->CheckAuthentication(this->usernameFragment, this->password))
|
||||
{
|
||||
case RTC::StunPacket::Authentication::OK:
|
||||
{
|
||||
if (!this->oldPassword.empty())
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "new ICE credentials applied");
|
||||
// Check authentication.
|
||||
switch (packet->CheckAuthentication(this->usernameFragment, this->password))
|
||||
{
|
||||
case RTC::StunPacket::Authentication::OK:
|
||||
{
|
||||
if (!this->oldPassword.empty())
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "new ICE credentials applied");
|
||||
|
||||
this->oldUsernameFragment.clear();
|
||||
this->oldPassword.clear();
|
||||
}
|
||||
this->oldUsernameFragment.clear();
|
||||
this->oldPassword.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Authentication::UNAUTHORIZED:
|
||||
{
|
||||
// We may have changed our usernameFragment and password, so check
|
||||
// the old ones.
|
||||
// clang-format off
|
||||
if (
|
||||
!this->oldUsernameFragment.empty() &&
|
||||
!this->oldPassword.empty() &&
|
||||
packet->CheckAuthentication(this->oldUsernameFragment, this->oldPassword) == RTC::StunPacket::Authentication::OK
|
||||
)
|
||||
// clang-format on
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "using old ICE credentials");
|
||||
case RTC::StunPacket::Authentication::UNAUTHORIZED:
|
||||
{
|
||||
// We may have changed our usernameFragment and password, so check
|
||||
// the old ones.
|
||||
// clang-format off
|
||||
if (
|
||||
!this->oldUsernameFragment.empty() &&
|
||||
!this->oldPassword.empty() &&
|
||||
packet->CheckAuthentication(this->oldUsernameFragment, this->oldPassword) == RTC::StunPacket::Authentication::OK
|
||||
)
|
||||
// clang-format on
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "using old ICE credentials");
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MS_WARN_TAG(ice, "wrong authentication in STUN Binding Request => 401");
|
||||
MS_WARN_TAG(ice, "wrong authentication in STUN Binding Request => 401");
|
||||
|
||||
// Reply 401.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(401);
|
||||
// Reply 401.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(401);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
delete response;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Authentication::BAD_REQUEST:
|
||||
{
|
||||
MS_WARN_TAG(ice, "cannot check authentication in STUN Binding Request => 400");
|
||||
case RTC::StunPacket::Authentication::BAD_REQUEST:
|
||||
{
|
||||
MS_WARN_TAG(ice, "cannot check authentication in STUN Binding Request => 400");
|
||||
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
// Reply 400.
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(400);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
delete response;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// The remote peer must be ICE controlling.
|
||||
if (packet->GetIceControlled())
|
||||
{
|
||||
MS_WARN_TAG(ice, "peer indicates ICE-CONTROLLED in STUN Binding Request => 487");
|
||||
// The remote peer must be ICE controlling.
|
||||
if (packet->GetIceControlled())
|
||||
{
|
||||
MS_WARN_TAG(ice, "peer indicates ICE-CONTROLLED in STUN Binding Request => 487");
|
||||
|
||||
// Reply 487 (Role Conflict).
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(487);
|
||||
// Reply 487 (Role Conflict).
|
||||
RTC::StunPacket* response = packet->CreateErrorResponse(487);
|
||||
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
delete response;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//MS_DEBUG_DEV(
|
||||
// "processing STUN Binding Request [Priority:%" PRIu32 ", UseCandidate:%s]",
|
||||
// static_cast<uint32_t>(packet->GetPriority()),
|
||||
// packet->HasUseCandidate() ? "true" : "false");
|
||||
//MS_DEBUG_DEV(
|
||||
// "processing STUN Binding Request [Priority:%" PRIu32 ", UseCandidate:%s]",
|
||||
// static_cast<uint32_t>(packet->GetPriority()),
|
||||
// packet->HasUseCandidate() ? "true" : "false");
|
||||
|
||||
// Create a success response.
|
||||
RTC::StunPacket* response = packet->CreateSuccessResponse();
|
||||
// Create a success response.
|
||||
RTC::StunPacket* response = packet->CreateSuccessResponse();
|
||||
|
||||
sockaddr_storage peerAddr;
|
||||
socklen_t addr_len = sizeof(peerAddr);
|
||||
getpeername(tuple->getSock()->rawFD(), (struct sockaddr *)&peerAddr, &addr_len);
|
||||
|
||||
// Add XOR-MAPPED-ADDRESS.
|
||||
response->SetXorMappedAddress((struct sockaddr *)&peerAddr);
|
||||
sockaddr_storage peerAddr;
|
||||
socklen_t addr_len = sizeof(peerAddr);
|
||||
getpeername(tuple->getSock()->rawFD(), (struct sockaddr *)&peerAddr, &addr_len);
|
||||
|
||||
// Add XOR-MAPPED-ADDRESS.
|
||||
response->SetXorMappedAddress((struct sockaddr *)&peerAddr);
|
||||
|
||||
// Authenticate the response.
|
||||
if (this->oldPassword.empty())
|
||||
response->Authenticate(this->password);
|
||||
else
|
||||
response->Authenticate(this->oldPassword);
|
||||
// Authenticate the response.
|
||||
if (this->oldPassword.empty())
|
||||
response->Authenticate(this->password);
|
||||
else
|
||||
response->Authenticate(this->oldPassword);
|
||||
|
||||
// Send back.
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
// Send back.
|
||||
response->Serialize(StunSerializeBuffer);
|
||||
this->listener->OnIceServerSendStunPacket(this, response, tuple);
|
||||
|
||||
delete response;
|
||||
delete response;
|
||||
|
||||
// Handle the tuple.
|
||||
HandleTuple(tuple, packet->HasUseCandidate());
|
||||
// Handle the tuple.
|
||||
HandleTuple(tuple, packet->HasUseCandidate());
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Class::INDICATION:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Indication processed");
|
||||
case RTC::StunPacket::Class::INDICATION:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Indication processed");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Class::SUCCESS_RESPONSE:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Success Response processed");
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Class::SUCCESS_RESPONSE:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Success Response processed");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RTC::StunPacket::Class::ERROR_RESPONSE:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Error Response processed");
|
||||
case RTC::StunPacket::Class::ERROR_RESPONSE:
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "STUN Binding Error Response processed");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IceServer::IsValidTuple(const RTC::TransportTuple* tuple) const
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
return HasTuple(tuple) != nullptr;
|
||||
}
|
||||
|
||||
void IceServer::RemoveTuple(RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
RTC::TransportTuple* removedTuple{ nullptr };
|
||||
|
||||
// Find the removed tuple.
|
||||
auto it = this->tuples.begin();
|
||||
|
||||
for (; it != this->tuples.end(); ++it)
|
||||
{
|
||||
RTC::TransportTuple* storedTuple = *it;
|
||||
|
||||
if (storedTuple == tuple)
|
||||
{
|
||||
removedTuple = storedTuple;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, ignore.
|
||||
if (!removedTuple)
|
||||
return;
|
||||
|
||||
// Remove from the list of tuples.
|
||||
this->tuples.erase(it);
|
||||
|
||||
// If this is not the selected tuple, stop here.
|
||||
if (removedTuple != this->selectedTuple)
|
||||
return;
|
||||
|
||||
// Otherwise this was the selected tuple.
|
||||
this->selectedTuple = nullptr;
|
||||
|
||||
// Mark the first tuple as selected tuple (if any).
|
||||
if (!this->tuples.empty())
|
||||
{
|
||||
SetSelectedTuple(this->tuples.front());
|
||||
}
|
||||
// Or just emit 'disconnected'.
|
||||
else
|
||||
{
|
||||
// Update state.
|
||||
this->state = IceState::DISCONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerDisconnected(this);
|
||||
}
|
||||
}
|
||||
|
||||
void IceServer::ForceSelectedTuple(const RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
MS_ASSERT(
|
||||
this->selectedTuple, "cannot force the selected tuple if there was not a selected tuple");
|
||||
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
MS_ASSERT(
|
||||
storedTuple,
|
||||
"cannot force the selected tuple if the given tuple was not already a valid tuple");
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
}
|
||||
|
||||
void IceServer::HandleTuple(RTC::TransportTuple* tuple, bool hasUseCandidate)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IceState::NEW:
|
||||
{
|
||||
// There should be no tuples.
|
||||
MS_ASSERT(
|
||||
this->tuples.empty(), "state is 'new' but there are %zu tuples", this->tuples.size());
|
||||
|
||||
// There shouldn't be a selected tuple.
|
||||
MS_ASSERT(!this->selectedTuple, "state is 'new' but there is selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'new' to 'connected'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::CONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerConnected(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'new' to 'completed'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::DISCONNECTED:
|
||||
{
|
||||
// There should be no tuples.
|
||||
MS_ASSERT(
|
||||
this->tuples.empty(),
|
||||
"state is 'disconnected' but there are %zu tuples",
|
||||
this->tuples.size());
|
||||
|
||||
// There shouldn't be a selected tuple.
|
||||
MS_ASSERT(!this->selectedTuple, "state is 'disconnected' but there is selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'disconnected' to 'connected'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::CONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerConnected(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'disconnected' to 'completed'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::CONNECTED:
|
||||
{
|
||||
// There should be some tuples.
|
||||
MS_ASSERT(!this->tuples.empty(), "state is 'connected' but there are no tuples");
|
||||
|
||||
// There should be a selected tuple.
|
||||
MS_ASSERT(this->selectedTuple, "state is 'connected' but there is not selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
// If a new tuple store it.
|
||||
if (!HasTuple(tuple))
|
||||
AddTuple(tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'connected' to 'completed'");
|
||||
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
// If a new tuple store it.
|
||||
if (!storedTuple)
|
||||
storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::COMPLETED:
|
||||
{
|
||||
// There should be some tuples.
|
||||
MS_ASSERT(!this->tuples.empty(), "state is 'completed' but there are no tuples");
|
||||
|
||||
// There should be a selected tuple.
|
||||
MS_ASSERT(this->selectedTuple, "state is 'completed' but there is not selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
// If a new tuple store it.
|
||||
if (!HasTuple(tuple))
|
||||
AddTuple(tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
// If a new tuple store it.
|
||||
if (!storedTuple)
|
||||
storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline RTC::TransportTuple* IceServer::AddTuple(RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// Add the new tuple at the beginning of the list.
|
||||
this->tuples.push_front(tuple);
|
||||
|
||||
// Return the address of the inserted tuple.
|
||||
return tuple;
|
||||
}
|
||||
|
||||
inline RTC::TransportTuple* IceServer::HasTuple(const RTC::TransportTuple* tuple) const
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// If there is no selected tuple yet then we know that the tuples list
|
||||
// is empty.
|
||||
if (!this->selectedTuple)
|
||||
return nullptr;
|
||||
|
||||
// Check the current selected tuple.
|
||||
if (selectedTuple == tuple)
|
||||
return this->selectedTuple;
|
||||
|
||||
// Otherwise check other stored tuples.
|
||||
for (const auto& it : this->tuples)
|
||||
{
|
||||
auto& storedTuple = it;
|
||||
if (storedTuple == tuple)
|
||||
return storedTuple;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void IceServer::SetSelectedTuple(RTC::TransportTuple* storedTuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// If already the selected tuple do nothing.
|
||||
if (storedTuple == this->selectedTuple)
|
||||
return;
|
||||
|
||||
this->selectedTuple = storedTuple;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IceServer::IsValidTuple(const RTC::TransportTuple* tuple) const
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
return HasTuple(tuple) != nullptr;
|
||||
}
|
||||
|
||||
void IceServer::RemoveTuple(RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
RTC::TransportTuple* removedTuple{ nullptr };
|
||||
|
||||
// Find the removed tuple.
|
||||
auto it = this->tuples.begin();
|
||||
|
||||
for (; it != this->tuples.end(); ++it)
|
||||
{
|
||||
RTC::TransportTuple* storedTuple = *it;
|
||||
|
||||
if (storedTuple == tuple)
|
||||
{
|
||||
removedTuple = storedTuple;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, ignore.
|
||||
if (!removedTuple)
|
||||
return;
|
||||
|
||||
// Remove from the list of tuples.
|
||||
this->tuples.erase(it);
|
||||
|
||||
// If this is not the selected tuple, stop here.
|
||||
if (removedTuple != this->selectedTuple)
|
||||
return;
|
||||
|
||||
// Otherwise this was the selected tuple.
|
||||
this->selectedTuple = nullptr;
|
||||
|
||||
// Mark the first tuple as selected tuple (if any).
|
||||
if (!this->tuples.empty())
|
||||
{
|
||||
SetSelectedTuple(this->tuples.front());
|
||||
}
|
||||
// Or just emit 'disconnected'.
|
||||
else
|
||||
{
|
||||
// Update state.
|
||||
this->state = IceState::DISCONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerDisconnected(this);
|
||||
}
|
||||
}
|
||||
|
||||
void IceServer::ForceSelectedTuple(const RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
MS_ASSERT(
|
||||
this->selectedTuple, "cannot force the selected tuple if there was not a selected tuple");
|
||||
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
MS_ASSERT(
|
||||
storedTuple,
|
||||
"cannot force the selected tuple if the given tuple was not already a valid tuple");
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
}
|
||||
|
||||
void IceServer::HandleTuple(RTC::TransportTuple* tuple, bool hasUseCandidate)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IceState::NEW:
|
||||
{
|
||||
// There should be no tuples.
|
||||
MS_ASSERT(
|
||||
this->tuples.empty(), "state is 'new' but there are %zu tuples", this->tuples.size());
|
||||
|
||||
// There shouldn't be a selected tuple.
|
||||
MS_ASSERT(!this->selectedTuple, "state is 'new' but there is selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'new' to 'connected'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::CONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerConnected(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'new' to 'completed'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::DISCONNECTED:
|
||||
{
|
||||
// There should be no tuples.
|
||||
MS_ASSERT(
|
||||
this->tuples.empty(),
|
||||
"state is 'disconnected' but there are %zu tuples",
|
||||
this->tuples.size());
|
||||
|
||||
// There shouldn't be a selected tuple.
|
||||
MS_ASSERT(!this->selectedTuple, "state is 'disconnected' but there is selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'disconnected' to 'connected'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::CONNECTED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerConnected(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'disconnected' to 'completed'");
|
||||
|
||||
// Store the tuple.
|
||||
auto* storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::CONNECTED:
|
||||
{
|
||||
// There should be some tuples.
|
||||
MS_ASSERT(!this->tuples.empty(), "state is 'connected' but there are no tuples");
|
||||
|
||||
// There should be a selected tuple.
|
||||
MS_ASSERT(this->selectedTuple, "state is 'connected' but there is not selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
// If a new tuple store it.
|
||||
if (!HasTuple(tuple))
|
||||
AddTuple(tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
MS_DEBUG_TAG(ice, "transition from state 'connected' to 'completed'");
|
||||
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
// If a new tuple store it.
|
||||
if (!storedTuple)
|
||||
storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
// Update state.
|
||||
this->state = IceState::COMPLETED;
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerCompleted(this);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IceState::COMPLETED:
|
||||
{
|
||||
// There should be some tuples.
|
||||
MS_ASSERT(!this->tuples.empty(), "state is 'completed' but there are no tuples");
|
||||
|
||||
// There should be a selected tuple.
|
||||
MS_ASSERT(this->selectedTuple, "state is 'completed' but there is not selected tuple");
|
||||
|
||||
if (!hasUseCandidate)
|
||||
{
|
||||
// If a new tuple store it.
|
||||
if (!HasTuple(tuple))
|
||||
AddTuple(tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* storedTuple = HasTuple(tuple);
|
||||
|
||||
// If a new tuple store it.
|
||||
if (!storedTuple)
|
||||
storedTuple = AddTuple(tuple);
|
||||
|
||||
// Mark it as selected tuple.
|
||||
SetSelectedTuple(storedTuple);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline RTC::TransportTuple* IceServer::AddTuple(RTC::TransportTuple* tuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// Add the new tuple at the beginning of the list.
|
||||
this->tuples.push_front(tuple);
|
||||
|
||||
// Return the address of the inserted tuple.
|
||||
return tuple;
|
||||
}
|
||||
|
||||
inline RTC::TransportTuple* IceServer::HasTuple(const RTC::TransportTuple* tuple) const
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// If there is no selected tuple yet then we know that the tuples list
|
||||
// is empty.
|
||||
if (!this->selectedTuple)
|
||||
return nullptr;
|
||||
|
||||
// Check the current selected tuple.
|
||||
if (selectedTuple == tuple)
|
||||
return this->selectedTuple;
|
||||
|
||||
// Otherwise check other stored tuples.
|
||||
for (const auto& it : this->tuples)
|
||||
{
|
||||
auto& storedTuple = it;
|
||||
if (storedTuple == tuple)
|
||||
return storedTuple;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void IceServer::SetSelectedTuple(RTC::TransportTuple* storedTuple)
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
// If already the selected tuple do nothing.
|
||||
if (storedTuple == this->selectedTuple)
|
||||
return;
|
||||
|
||||
this->selectedTuple = storedTuple;
|
||||
this->lastSelectedTuple = storedTuple->shared_from_this();
|
||||
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerSelectedTuple(this, this->selectedTuple);
|
||||
}
|
||||
// Notify the listener.
|
||||
this->listener->OnIceServerSelectedTuple(this, this->selectedTuple);
|
||||
}
|
||||
} // namespace RTC
|
||||
|
@ -30,109 +30,109 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
namespace RTC
|
||||
{
|
||||
using TransportTuple = toolkit::Session;
|
||||
class IceServer
|
||||
{
|
||||
public:
|
||||
enum class IceState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTED,
|
||||
COMPLETED,
|
||||
DISCONNECTED
|
||||
};
|
||||
using TransportTuple = toolkit::Session;
|
||||
class IceServer
|
||||
{
|
||||
public:
|
||||
enum class IceState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTED,
|
||||
COMPLETED,
|
||||
DISCONNECTED
|
||||
};
|
||||
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual ~Listener() = default;
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual ~Listener() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
* These callbacks are guaranteed to be called before ProcessStunPacket()
|
||||
* returns, so the given pointers are still usable.
|
||||
*/
|
||||
virtual void OnIceServerSendStunPacket(
|
||||
const RTC::IceServer* iceServer, const RTC::StunPacket* packet, RTC::TransportTuple* tuple) = 0;
|
||||
virtual void OnIceServerSelectedTuple(
|
||||
const RTC::IceServer* iceServer, RTC::TransportTuple* tuple) = 0;
|
||||
virtual void OnIceServerConnected(const RTC::IceServer* iceServer) = 0;
|
||||
virtual void OnIceServerCompleted(const RTC::IceServer* iceServer) = 0;
|
||||
virtual void OnIceServerDisconnected(const RTC::IceServer* iceServer) = 0;
|
||||
};
|
||||
public:
|
||||
/**
|
||||
* These callbacks are guaranteed to be called before ProcessStunPacket()
|
||||
* returns, so the given pointers are still usable.
|
||||
*/
|
||||
virtual void OnIceServerSendStunPacket(
|
||||
const RTC::IceServer* iceServer, const RTC::StunPacket* packet, RTC::TransportTuple* tuple) = 0;
|
||||
virtual void OnIceServerSelectedTuple(
|
||||
const RTC::IceServer* iceServer, RTC::TransportTuple* tuple) = 0;
|
||||
virtual void OnIceServerConnected(const RTC::IceServer* iceServer) = 0;
|
||||
virtual void OnIceServerCompleted(const RTC::IceServer* iceServer) = 0;
|
||||
virtual void OnIceServerDisconnected(const RTC::IceServer* iceServer) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password);
|
||||
public:
|
||||
IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password);
|
||||
|
||||
public:
|
||||
void ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple);
|
||||
const std::string& GetUsernameFragment() const
|
||||
{
|
||||
return this->usernameFragment;
|
||||
}
|
||||
const std::string& GetPassword() const
|
||||
{
|
||||
return this->password;
|
||||
}
|
||||
IceState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
RTC::TransportTuple* GetSelectedTuple(bool try_last_tuple = false) const
|
||||
{
|
||||
public:
|
||||
void ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple);
|
||||
const std::string& GetUsernameFragment() const
|
||||
{
|
||||
return this->usernameFragment;
|
||||
}
|
||||
const std::string& GetPassword() const
|
||||
{
|
||||
return this->password;
|
||||
}
|
||||
IceState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
RTC::TransportTuple* GetSelectedTuple(bool try_last_tuple = false) const
|
||||
{
|
||||
return try_last_tuple ? this->lastSelectedTuple.lock().get() : this->selectedTuple;
|
||||
}
|
||||
void SetUsernameFragment(const std::string& usernameFragment)
|
||||
{
|
||||
this->oldUsernameFragment = this->usernameFragment;
|
||||
this->usernameFragment = usernameFragment;
|
||||
}
|
||||
void SetPassword(const std::string& password)
|
||||
{
|
||||
this->oldPassword = this->password;
|
||||
this->password = password;
|
||||
}
|
||||
bool IsValidTuple(const RTC::TransportTuple* tuple) const;
|
||||
void RemoveTuple(RTC::TransportTuple* tuple);
|
||||
// This should be just called in 'connected' or completed' state
|
||||
// and the given tuple must be an already valid tuple.
|
||||
void ForceSelectedTuple(const RTC::TransportTuple* tuple);
|
||||
void SetUsernameFragment(const std::string& usernameFragment)
|
||||
{
|
||||
this->oldUsernameFragment = this->usernameFragment;
|
||||
this->usernameFragment = usernameFragment;
|
||||
}
|
||||
void SetPassword(const std::string& password)
|
||||
{
|
||||
this->oldPassword = this->password;
|
||||
this->password = password;
|
||||
}
|
||||
bool IsValidTuple(const RTC::TransportTuple* tuple) const;
|
||||
void RemoveTuple(RTC::TransportTuple* tuple);
|
||||
// This should be just called in 'connected' or completed' state
|
||||
// and the given tuple must be an already valid tuple.
|
||||
void ForceSelectedTuple(const RTC::TransportTuple* tuple);
|
||||
|
||||
const std::list<RTC::TransportTuple *>& GetTuples() const { return tuples; }
|
||||
|
||||
private:
|
||||
void HandleTuple(RTC::TransportTuple* tuple, bool hasUseCandidate);
|
||||
/**
|
||||
* Store the given tuple and return its stored address.
|
||||
*/
|
||||
RTC::TransportTuple* AddTuple(RTC::TransportTuple* tuple);
|
||||
/**
|
||||
* If the given tuple exists return its stored address, nullptr otherwise.
|
||||
*/
|
||||
RTC::TransportTuple* HasTuple(const RTC::TransportTuple* tuple) const;
|
||||
/**
|
||||
* Set the given tuple as the selected tuple.
|
||||
* NOTE: The given tuple MUST be already stored within the list.
|
||||
*/
|
||||
void SetSelectedTuple(RTC::TransportTuple* storedTuple);
|
||||
void HandleTuple(RTC::TransportTuple* tuple, bool hasUseCandidate);
|
||||
/**
|
||||
* Store the given tuple and return its stored address.
|
||||
*/
|
||||
RTC::TransportTuple* AddTuple(RTC::TransportTuple* tuple);
|
||||
/**
|
||||
* If the given tuple exists return its stored address, nullptr otherwise.
|
||||
*/
|
||||
RTC::TransportTuple* HasTuple(const RTC::TransportTuple* tuple) const;
|
||||
/**
|
||||
* Set the given tuple as the selected tuple.
|
||||
* NOTE: The given tuple MUST be already stored within the list.
|
||||
*/
|
||||
void SetSelectedTuple(RTC::TransportTuple* storedTuple);
|
||||
|
||||
private:
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
// Others.
|
||||
std::string usernameFragment;
|
||||
std::string password;
|
||||
std::string oldUsernameFragment;
|
||||
std::string oldPassword;
|
||||
IceState state{ IceState::NEW };
|
||||
std::list<RTC::TransportTuple *> tuples;
|
||||
private:
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
// Others.
|
||||
std::string usernameFragment;
|
||||
std::string password;
|
||||
std::string oldUsernameFragment;
|
||||
std::string oldPassword;
|
||||
IceState state{ IceState::NEW };
|
||||
std::list<RTC::TransportTuple *> tuples;
|
||||
RTC::TransportTuple *selectedTuple;
|
||||
std::weak_ptr<RTC::TransportTuple> lastSelectedTuple;
|
||||
//最大不超过mtu
|
||||
//最大不超过mtu
|
||||
static constexpr size_t StunSerializeBufferSize{ 1600 };
|
||||
uint8_t StunSerializeBuffer[StunSerializeBufferSize];
|
||||
};
|
||||
};
|
||||
} // namespace RTC
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,104 +18,104 @@ namespace RTC
|
||||
uint16_t maxRetransmits{ 0u };
|
||||
};
|
||||
|
||||
class SctpAssociation
|
||||
{
|
||||
public:
|
||||
enum class SctpState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
};
|
||||
class SctpAssociation
|
||||
{
|
||||
public:
|
||||
enum class SctpState
|
||||
{
|
||||
NEW = 1,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
};
|
||||
|
||||
private:
|
||||
enum class StreamDirection
|
||||
{
|
||||
INCOMING = 1,
|
||||
OUTGOING
|
||||
};
|
||||
private:
|
||||
enum class StreamDirection
|
||||
{
|
||||
INCOMING = 1,
|
||||
OUTGOING
|
||||
};
|
||||
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual void OnSctpAssociationConnecting(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationConnected(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationFailed(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationClosed(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationSendData(
|
||||
RTC::SctpAssociation* sctpAssociation, const uint8_t* data, size_t len) = 0;
|
||||
virtual void OnSctpAssociationMessageReceived(
|
||||
RTC::SctpAssociation* sctpAssociation,
|
||||
uint16_t streamId,
|
||||
uint32_t ppid,
|
||||
const uint8_t* msg,
|
||||
size_t len) = 0;
|
||||
};
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual void OnSctpAssociationConnecting(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationConnected(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationFailed(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationClosed(RTC::SctpAssociation* sctpAssociation) = 0;
|
||||
virtual void OnSctpAssociationSendData(
|
||||
RTC::SctpAssociation* sctpAssociation, const uint8_t* data, size_t len) = 0;
|
||||
virtual void OnSctpAssociationMessageReceived(
|
||||
RTC::SctpAssociation* sctpAssociation,
|
||||
uint16_t streamId,
|
||||
uint32_t ppid,
|
||||
const uint8_t* msg,
|
||||
size_t len) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
static bool IsSctp(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
(len >= 12) &&
|
||||
// Must have Source Port Number and Destination Port Number set to 5000 (hack).
|
||||
(Utils::Byte::Get2Bytes(data, 0) == 5000) &&
|
||||
(Utils::Byte::Get2Bytes(data, 2) == 5000)
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
public:
|
||||
static bool IsSctp(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
(len >= 12) &&
|
||||
// Must have Source Port Number and Destination Port Number set to 5000 (hack).
|
||||
(Utils::Byte::Get2Bytes(data, 0) == 5000) &&
|
||||
(Utils::Byte::Get2Bytes(data, 2) == 5000)
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
public:
|
||||
SctpAssociation(
|
||||
Listener* listener, uint16_t os, uint16_t mis, size_t maxSctpMessageSize, bool isDataChannel);
|
||||
virtual ~SctpAssociation();
|
||||
public:
|
||||
SctpAssociation(
|
||||
Listener* listener, uint16_t os, uint16_t mis, size_t maxSctpMessageSize, bool isDataChannel);
|
||||
virtual ~SctpAssociation();
|
||||
|
||||
public:
|
||||
void TransportConnected();
|
||||
size_t GetMaxSctpMessageSize() const
|
||||
{
|
||||
return this->maxSctpMessageSize;
|
||||
}
|
||||
SctpState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
void ProcessSctpData(const uint8_t* data, size_t len);
|
||||
void SendSctpMessage(const RTC::SctpStreamParameters ¶ms, uint32_t ppid, const uint8_t* msg, size_t len);
|
||||
void HandleDataConsumer(const RTC::SctpStreamParameters ¶ms);
|
||||
void DataProducerClosed(const RTC::SctpStreamParameters ¶ms);
|
||||
void DataConsumerClosed(const RTC::SctpStreamParameters ¶ms);
|
||||
public:
|
||||
void TransportConnected();
|
||||
size_t GetMaxSctpMessageSize() const
|
||||
{
|
||||
return this->maxSctpMessageSize;
|
||||
}
|
||||
SctpState GetState() const
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
void ProcessSctpData(const uint8_t* data, size_t len);
|
||||
void SendSctpMessage(const RTC::SctpStreamParameters ¶ms, uint32_t ppid, const uint8_t* msg, size_t len);
|
||||
void HandleDataConsumer(const RTC::SctpStreamParameters ¶ms);
|
||||
void DataProducerClosed(const RTC::SctpStreamParameters ¶ms);
|
||||
void DataConsumerClosed(const RTC::SctpStreamParameters ¶ms);
|
||||
|
||||
private:
|
||||
void ResetSctpStream(uint16_t streamId, StreamDirection);
|
||||
void AddOutgoingStreams(bool force = false);
|
||||
private:
|
||||
void ResetSctpStream(uint16_t streamId, StreamDirection);
|
||||
void AddOutgoingStreams(bool force = false);
|
||||
|
||||
public:
|
||||
public:
|
||||
/* Callbacks fired by usrsctp events. */
|
||||
virtual void OnUsrSctpSendSctpData(void* buffer, size_t len);
|
||||
virtual void OnUsrSctpReceiveSctpData(uint16_t streamId, uint16_t ssn, uint32_t ppid, int flags, const uint8_t* data, size_t len);
|
||||
virtual void OnUsrSctpReceiveSctpNotification(union sctp_notification* notification, size_t len);
|
||||
|
||||
private:
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
uint16_t os{ 1024u };
|
||||
uint16_t mis{ 1024u };
|
||||
size_t maxSctpMessageSize{ 262144u };
|
||||
bool isDataChannel{ false };
|
||||
// Allocated by this.
|
||||
uint8_t* messageBuffer{ nullptr };
|
||||
// Others.
|
||||
SctpState state{ SctpState::NEW };
|
||||
struct socket* socket{ nullptr };
|
||||
uint16_t desiredOs{ 0u };
|
||||
size_t messageBufferLen{ 0u };
|
||||
uint16_t lastSsnReceived{ 0u }; // Valid for us since no SCTP I-DATA support.
|
||||
private:
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
uint16_t os{ 1024u };
|
||||
uint16_t mis{ 1024u };
|
||||
size_t maxSctpMessageSize{ 262144u };
|
||||
bool isDataChannel{ false };
|
||||
// Allocated by this.
|
||||
uint8_t* messageBuffer{ nullptr };
|
||||
// Others.
|
||||
SctpState state{ SctpState::NEW };
|
||||
struct socket* socket{ nullptr };
|
||||
uint16_t desiredOs{ 0u };
|
||||
size_t messageBufferLen{ 0u };
|
||||
uint16_t lastSsnReceived{ 0u }; // Valid for us since no SCTP I-DATA support.
|
||||
std::shared_ptr<SctpEnv> _env;
|
||||
};
|
||||
};
|
||||
|
||||
//保证线程安全
|
||||
class SctpAssociationImp : public SctpAssociation, public std::enable_shared_from_this<SctpAssociationImp>{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,188 +26,188 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
namespace RTC
|
||||
{
|
||||
class StunPacket
|
||||
{
|
||||
public:
|
||||
// STUN message class.
|
||||
enum class Class : uint16_t
|
||||
{
|
||||
REQUEST = 0,
|
||||
INDICATION = 1,
|
||||
SUCCESS_RESPONSE = 2,
|
||||
ERROR_RESPONSE = 3
|
||||
};
|
||||
class StunPacket
|
||||
{
|
||||
public:
|
||||
// STUN message class.
|
||||
enum class Class : uint16_t
|
||||
{
|
||||
REQUEST = 0,
|
||||
INDICATION = 1,
|
||||
SUCCESS_RESPONSE = 2,
|
||||
ERROR_RESPONSE = 3
|
||||
};
|
||||
|
||||
// STUN message method.
|
||||
enum class Method : uint16_t
|
||||
{
|
||||
BINDING = 1
|
||||
};
|
||||
// STUN message method.
|
||||
enum class Method : uint16_t
|
||||
{
|
||||
BINDING = 1
|
||||
};
|
||||
|
||||
// Attribute type.
|
||||
enum class Attribute : uint16_t
|
||||
{
|
||||
MAPPED_ADDRESS = 0x0001,
|
||||
USERNAME = 0x0006,
|
||||
MESSAGE_INTEGRITY = 0x0008,
|
||||
ERROR_CODE = 0x0009,
|
||||
UNKNOWN_ATTRIBUTES = 0x000A,
|
||||
REALM = 0x0014,
|
||||
NONCE = 0x0015,
|
||||
XOR_MAPPED_ADDRESS = 0x0020,
|
||||
PRIORITY = 0x0024,
|
||||
USE_CANDIDATE = 0x0025,
|
||||
SOFTWARE = 0x8022,
|
||||
ALTERNATE_SERVER = 0x8023,
|
||||
FINGERPRINT = 0x8028,
|
||||
ICE_CONTROLLED = 0x8029,
|
||||
ICE_CONTROLLING = 0x802A
|
||||
};
|
||||
// Attribute type.
|
||||
enum class Attribute : uint16_t
|
||||
{
|
||||
MAPPED_ADDRESS = 0x0001,
|
||||
USERNAME = 0x0006,
|
||||
MESSAGE_INTEGRITY = 0x0008,
|
||||
ERROR_CODE = 0x0009,
|
||||
UNKNOWN_ATTRIBUTES = 0x000A,
|
||||
REALM = 0x0014,
|
||||
NONCE = 0x0015,
|
||||
XOR_MAPPED_ADDRESS = 0x0020,
|
||||
PRIORITY = 0x0024,
|
||||
USE_CANDIDATE = 0x0025,
|
||||
SOFTWARE = 0x8022,
|
||||
ALTERNATE_SERVER = 0x8023,
|
||||
FINGERPRINT = 0x8028,
|
||||
ICE_CONTROLLED = 0x8029,
|
||||
ICE_CONTROLLING = 0x802A
|
||||
};
|
||||
|
||||
// Authentication result.
|
||||
enum class Authentication
|
||||
{
|
||||
OK = 0,
|
||||
UNAUTHORIZED = 1,
|
||||
BAD_REQUEST = 2
|
||||
};
|
||||
// Authentication result.
|
||||
enum class Authentication
|
||||
{
|
||||
OK = 0,
|
||||
UNAUTHORIZED = 1,
|
||||
BAD_REQUEST = 2
|
||||
};
|
||||
|
||||
public:
|
||||
static bool IsStun(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
// STUN headers are 20 bytes.
|
||||
(len >= 20) &&
|
||||
// DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
|
||||
(data[0] < 3) &&
|
||||
// Magic cookie must match.
|
||||
(data[4] == StunPacket::magicCookie[0]) && (data[5] == StunPacket::magicCookie[1]) &&
|
||||
(data[6] == StunPacket::magicCookie[2]) && (data[7] == StunPacket::magicCookie[3])
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
static StunPacket* Parse(const uint8_t* data, size_t len);
|
||||
public:
|
||||
static bool IsStun(const uint8_t* data, size_t len)
|
||||
{
|
||||
// clang-format off
|
||||
return (
|
||||
// STUN headers are 20 bytes.
|
||||
(len >= 20) &&
|
||||
// DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
|
||||
(data[0] < 3) &&
|
||||
// Magic cookie must match.
|
||||
(data[4] == StunPacket::magicCookie[0]) && (data[5] == StunPacket::magicCookie[1]) &&
|
||||
(data[6] == StunPacket::magicCookie[2]) && (data[7] == StunPacket::magicCookie[3])
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
static StunPacket* Parse(const uint8_t* data, size_t len);
|
||||
|
||||
private:
|
||||
static const uint8_t magicCookie[];
|
||||
private:
|
||||
static const uint8_t magicCookie[];
|
||||
|
||||
public:
|
||||
StunPacket(
|
||||
Class klass, Method method, const uint8_t* transactionId, const uint8_t* data, size_t size);
|
||||
~StunPacket();
|
||||
public:
|
||||
StunPacket(
|
||||
Class klass, Method method, const uint8_t* transactionId, const uint8_t* data, size_t size);
|
||||
~StunPacket();
|
||||
|
||||
void Dump() const;
|
||||
Class GetClass() const
|
||||
{
|
||||
return this->klass;
|
||||
}
|
||||
Method GetMethod() const
|
||||
{
|
||||
return this->method;
|
||||
}
|
||||
const uint8_t* GetData() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
size_t GetSize() const
|
||||
{
|
||||
return this->size;
|
||||
}
|
||||
void SetUsername(const char* username, size_t len)
|
||||
{
|
||||
this->username.assign(username, len);
|
||||
}
|
||||
void SetPriority(uint32_t priority)
|
||||
{
|
||||
this->priority = priority;
|
||||
}
|
||||
void SetIceControlling(uint64_t iceControlling)
|
||||
{
|
||||
this->iceControlling = iceControlling;
|
||||
}
|
||||
void SetIceControlled(uint64_t iceControlled)
|
||||
{
|
||||
this->iceControlled = iceControlled;
|
||||
}
|
||||
void SetUseCandidate()
|
||||
{
|
||||
this->hasUseCandidate = true;
|
||||
}
|
||||
void SetXorMappedAddress(const struct sockaddr* xorMappedAddress)
|
||||
{
|
||||
this->xorMappedAddress = xorMappedAddress;
|
||||
}
|
||||
void SetErrorCode(uint16_t errorCode)
|
||||
{
|
||||
this->errorCode = errorCode;
|
||||
}
|
||||
void SetMessageIntegrity(const uint8_t* messageIntegrity)
|
||||
{
|
||||
this->messageIntegrity = messageIntegrity;
|
||||
}
|
||||
void SetFingerprint()
|
||||
{
|
||||
this->hasFingerprint = true;
|
||||
}
|
||||
const std::string& GetUsername() const
|
||||
{
|
||||
return this->username;
|
||||
}
|
||||
uint32_t GetPriority() const
|
||||
{
|
||||
return this->priority;
|
||||
}
|
||||
uint64_t GetIceControlling() const
|
||||
{
|
||||
return this->iceControlling;
|
||||
}
|
||||
uint64_t GetIceControlled() const
|
||||
{
|
||||
return this->iceControlled;
|
||||
}
|
||||
bool HasUseCandidate() const
|
||||
{
|
||||
return this->hasUseCandidate;
|
||||
}
|
||||
uint16_t GetErrorCode() const
|
||||
{
|
||||
return this->errorCode;
|
||||
}
|
||||
bool HasMessageIntegrity() const
|
||||
{
|
||||
return (this->messageIntegrity ? true : false);
|
||||
}
|
||||
bool HasFingerprint() const
|
||||
{
|
||||
return this->hasFingerprint;
|
||||
}
|
||||
Authentication CheckAuthentication(
|
||||
const std::string& localUsername, const std::string& localPassword);
|
||||
StunPacket* CreateSuccessResponse();
|
||||
StunPacket* CreateErrorResponse(uint16_t errorCode);
|
||||
void Authenticate(const std::string& password);
|
||||
void Serialize(uint8_t* buffer);
|
||||
void Dump() const;
|
||||
Class GetClass() const
|
||||
{
|
||||
return this->klass;
|
||||
}
|
||||
Method GetMethod() const
|
||||
{
|
||||
return this->method;
|
||||
}
|
||||
const uint8_t* GetData() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
size_t GetSize() const
|
||||
{
|
||||
return this->size;
|
||||
}
|
||||
void SetUsername(const char* username, size_t len)
|
||||
{
|
||||
this->username.assign(username, len);
|
||||
}
|
||||
void SetPriority(uint32_t priority)
|
||||
{
|
||||
this->priority = priority;
|
||||
}
|
||||
void SetIceControlling(uint64_t iceControlling)
|
||||
{
|
||||
this->iceControlling = iceControlling;
|
||||
}
|
||||
void SetIceControlled(uint64_t iceControlled)
|
||||
{
|
||||
this->iceControlled = iceControlled;
|
||||
}
|
||||
void SetUseCandidate()
|
||||
{
|
||||
this->hasUseCandidate = true;
|
||||
}
|
||||
void SetXorMappedAddress(const struct sockaddr* xorMappedAddress)
|
||||
{
|
||||
this->xorMappedAddress = xorMappedAddress;
|
||||
}
|
||||
void SetErrorCode(uint16_t errorCode)
|
||||
{
|
||||
this->errorCode = errorCode;
|
||||
}
|
||||
void SetMessageIntegrity(const uint8_t* messageIntegrity)
|
||||
{
|
||||
this->messageIntegrity = messageIntegrity;
|
||||
}
|
||||
void SetFingerprint()
|
||||
{
|
||||
this->hasFingerprint = true;
|
||||
}
|
||||
const std::string& GetUsername() const
|
||||
{
|
||||
return this->username;
|
||||
}
|
||||
uint32_t GetPriority() const
|
||||
{
|
||||
return this->priority;
|
||||
}
|
||||
uint64_t GetIceControlling() const
|
||||
{
|
||||
return this->iceControlling;
|
||||
}
|
||||
uint64_t GetIceControlled() const
|
||||
{
|
||||
return this->iceControlled;
|
||||
}
|
||||
bool HasUseCandidate() const
|
||||
{
|
||||
return this->hasUseCandidate;
|
||||
}
|
||||
uint16_t GetErrorCode() const
|
||||
{
|
||||
return this->errorCode;
|
||||
}
|
||||
bool HasMessageIntegrity() const
|
||||
{
|
||||
return (this->messageIntegrity ? true : false);
|
||||
}
|
||||
bool HasFingerprint() const
|
||||
{
|
||||
return this->hasFingerprint;
|
||||
}
|
||||
Authentication CheckAuthentication(
|
||||
const std::string& localUsername, const std::string& localPassword);
|
||||
StunPacket* CreateSuccessResponse();
|
||||
StunPacket* CreateErrorResponse(uint16_t errorCode);
|
||||
void Authenticate(const std::string& password);
|
||||
void Serialize(uint8_t* buffer);
|
||||
|
||||
private:
|
||||
// Passed by argument.
|
||||
Class klass; // 2 bytes.
|
||||
Method method; // 2 bytes.
|
||||
const uint8_t* transactionId{ nullptr }; // 12 bytes.
|
||||
uint8_t* data{ nullptr }; // Pointer to binary data.
|
||||
size_t size{ 0u }; // The full message size (including header).
|
||||
// STUN attributes.
|
||||
std::string username; // Less than 513 bytes.
|
||||
uint32_t priority{ 0u }; // 4 bytes unsigned integer.
|
||||
uint64_t iceControlling{ 0u }; // 8 bytes unsigned integer.
|
||||
uint64_t iceControlled{ 0u }; // 8 bytes unsigned integer.
|
||||
bool hasUseCandidate{ false }; // 0 bytes.
|
||||
const uint8_t* messageIntegrity{ nullptr }; // 20 bytes.
|
||||
bool hasFingerprint{ false }; // 4 bytes.
|
||||
const struct sockaddr* xorMappedAddress{ nullptr }; // 8 or 20 bytes.
|
||||
uint16_t errorCode{ 0u }; // 4 bytes (no reason phrase).
|
||||
std::string password;
|
||||
};
|
||||
private:
|
||||
// Passed by argument.
|
||||
Class klass; // 2 bytes.
|
||||
Method method; // 2 bytes.
|
||||
const uint8_t* transactionId{ nullptr }; // 12 bytes.
|
||||
uint8_t* data{ nullptr }; // Pointer to binary data.
|
||||
size_t size{ 0u }; // The full message size (including header).
|
||||
// STUN attributes.
|
||||
std::string username; // Less than 513 bytes.
|
||||
uint32_t priority{ 0u }; // 4 bytes unsigned integer.
|
||||
uint64_t iceControlling{ 0u }; // 8 bytes unsigned integer.
|
||||
uint64_t iceControlled{ 0u }; // 8 bytes unsigned integer.
|
||||
bool hasUseCandidate{ false }; // 0 bytes.
|
||||
const uint8_t* messageIntegrity{ nullptr }; // 20 bytes.
|
||||
bool hasFingerprint{ false }; // 4 bytes.
|
||||
const struct sockaddr* xorMappedAddress{ nullptr }; // 8 or 20 bytes.
|
||||
uint16_t errorCode{ 0u }; // 4 bytes (no reason phrase).
|
||||
std::string password;
|
||||
};
|
||||
} // namespace RTC
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user