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