Source release v3.3.0
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
|
||||
#include "cdm.h"
|
||||
#include "cdm_test_printers.h"
|
||||
#include "config_test_env.h"
|
||||
#include "decryption_test_data.h"
|
||||
#include "default_service_certificate.h"
|
||||
#include "license_request.h"
|
||||
#include "log.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
@@ -37,14 +37,10 @@ const Cdm::SessionType kBogusSessionType = static_cast<Cdm::SessionType>(-1);
|
||||
const Cdm::InitDataType kBogusInitDataType = static_cast<Cdm::InitDataType>(-1);
|
||||
const std::string kBogusSessionId = "asdf";
|
||||
|
||||
const std::string kProvisioningServerUrl =
|
||||
"https://www.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
|
||||
const std::string kLicenseServerAppspot =
|
||||
"http://widevine-proxy.appspot.com/proxy";
|
||||
const std::string kLicenseServerUat = "https://proxy.uat.widevine.com/proxy";
|
||||
std::string g_provisioning_server;
|
||||
std::string g_provisioning_service_certificate;
|
||||
std::string g_license_server;
|
||||
std::string g_license_service_certificate;
|
||||
|
||||
const std::string kCencInitData = a2bs_hex(
|
||||
"00000042" // blob size
|
||||
@@ -85,11 +81,11 @@ const std::string kHlsInitData =
|
||||
"yI6IFsNCiAgICAgICI5Yjc1OTA0MDMyMWE0MDhhNWM3NzY4YjQ1MTEyODdhNiINCiAgIF0NCn0"
|
||||
"=\",IV=0x75537a79fa41abc7b598ea72aba0c26f";
|
||||
|
||||
// This Key ID must match the key retrieved from kLicenseServerAppspot by
|
||||
// This Key ID must match the key retrieved from the license server by
|
||||
// kCencInitData.
|
||||
const std::vector<uint8_t> kKeyIdCtr = a2b_hex(
|
||||
"371ea35e1a985d75d198a7f41020dc23");
|
||||
// This Key ID must match the key retrieved from kLicenseServerUat by
|
||||
// This Key ID must match the key retrieved from the license server by
|
||||
// kHlsInitData.
|
||||
const std::vector<uint8_t> kKeyIdCbc = a2b_hex(
|
||||
"9b759040321a408a5c7768b4511287a6");
|
||||
@@ -133,6 +129,15 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
|
||||
protected:
|
||||
virtual void SetUp() OVERRIDE {
|
||||
|
||||
ConfigTestEnv config(kContentProtectionStagingPlusProv30);
|
||||
|
||||
g_provisioning_service_certificate.assign(
|
||||
config.provisioning_service_certificate());
|
||||
g_license_service_certificate.assign(config.license_service_certificate());
|
||||
g_provisioning_server.assign(config.provisioning_server());
|
||||
g_license_server.assign(config.license_server());
|
||||
|
||||
// Clear anything stored, load default device cert.
|
||||
g_host->Reset();
|
||||
|
||||
@@ -162,9 +167,14 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
usleep(500 * 1000);
|
||||
}
|
||||
|
||||
virtual void Provision() {
|
||||
cdm_->removeProvisioning();
|
||||
cdm_->setServiceCertificate(g_provisioning_service_certificate);
|
||||
}
|
||||
|
||||
void RecreateCdm(bool privacy_mode) {
|
||||
CreateAdditionalCdm(privacy_mode, &cdm_);
|
||||
cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
}
|
||||
|
||||
void CreateAdditionalCdm(bool privacy_mode, scoped_ptr<Cdm>* cdm) {
|
||||
@@ -203,7 +213,11 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
} else {
|
||||
*response = http_response;
|
||||
}
|
||||
LOGV("Reply body: %s", b2a_hex(*response).c_str());
|
||||
LOGV("Reply body(hex): \n%s\n", b2a_hex(*response).c_str());
|
||||
LOGV("Reply body(b64): \n%s\n",
|
||||
Base64SafeEncode(
|
||||
std::vector<uint8_t>(response->begin(),
|
||||
response->end())).c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -228,7 +242,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
void FetchLicenseFailure(const std::string& message,
|
||||
int expected_status_code) {
|
||||
int status_code;
|
||||
bool ok = Fetch(kLicenseServerAppspot, message, NULL, &status_code);
|
||||
bool ok = Fetch(g_license_server, message, NULL, &status_code);
|
||||
ASSERT_TRUE(ok);
|
||||
if (ok) ASSERT_EQ(expected_status_code, status_code);
|
||||
}
|
||||
@@ -238,7 +252,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
std::string* session_id,
|
||||
std::string* message) {
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
status = cdm_->createSession(session_type, session_id);
|
||||
@@ -276,9 +290,9 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
|
||||
std::string license_server;
|
||||
if (init_data_type == Cdm::kCenc) {
|
||||
license_server = kLicenseServerAppspot;
|
||||
license_server = g_license_server;
|
||||
} else if (init_data_type == Cdm::kHls) {
|
||||
license_server = kLicenseServerUat;
|
||||
license_server = g_license_server;
|
||||
}
|
||||
ASSERT_FALSE(license_server.empty());
|
||||
FetchLicense(license_server, message, response);
|
||||
@@ -301,7 +315,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
// Acquire a license.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// This license should be accepted, but the keys are not expected to change.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
@@ -465,19 +479,24 @@ TEST_F(CdmTest, Initialize) {
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, GetServiceCertificateRequest) {
|
||||
// Set a server certificate with privacy mode disabled - should work.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
|
||||
std::string message;
|
||||
Cdm::Status status = cdm_->getServiceCertificateRequest(&message);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, SetServiceCertificate) {
|
||||
// Set a server certificate with privacy mode disabled - should work.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
|
||||
Cdm::Status status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
Cdm::Status status =
|
||||
cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Can set a server certificate if privacy mode is enabled.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Setting an empty cert is allowed.
|
||||
status = cdm_->setServiceCertificate("");
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// It is invalid to set a malformed cert.
|
||||
@@ -515,7 +534,7 @@ TEST_F(CdmTest, CreateSession) {
|
||||
TEST_F(CdmTest, GenerateRequest) {
|
||||
std::string session_id;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
@@ -608,7 +627,7 @@ TEST_F(CdmTest, Update) {
|
||||
std::string session_id;
|
||||
std::string message;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndGenerateRequest(
|
||||
@@ -617,7 +636,7 @@ TEST_F(CdmTest, Update) {
|
||||
// Acquire a license.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
@@ -669,7 +688,7 @@ TEST_F(CdmTest, LoadTemporary) {
|
||||
std::string session_id;
|
||||
std::string response;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
@@ -772,7 +791,7 @@ TEST_F(CdmTest, PerOriginLoadPersistent) {
|
||||
scoped_ptr<Cdm> other_cdm(
|
||||
Cdm::create(this, &other_host, /* privacy_mode */ true));
|
||||
ASSERT_TRUE(other_cdm.get());
|
||||
status = other_cdm->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = other_cdm->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Should not be able to load from another origin.
|
||||
@@ -785,6 +804,7 @@ TEST_F(CdmTest, PerOriginLoadPersistent) {
|
||||
TEST_F(CdmTest, LoadUsageRecord) {
|
||||
std::string session_id;
|
||||
std::string response;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
@@ -824,6 +844,114 @@ TEST_F(CdmTest, LoadUsageRecord) {
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, DestroyUsageRecord) {
|
||||
std::string session_id;
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after closing it.
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->deleteUsageRecord(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, DestroyAllUsageRecords) {
|
||||
std::string session_id;
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after closing it.
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->deleteAllUsageRecords();
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, ListUsageRecords) {
|
||||
std::string session_id;
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after closing it.
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
|
||||
std::vector<std::string> ksids;
|
||||
status = cdm_->listUsageRecords(&ksids);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_EQ(ksids.size(), 1UL);
|
||||
if (ksids.size() > 0UL) {
|
||||
EXPECT_TRUE(ksids[0] == session_id);
|
||||
}
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, LoadBogus) {
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(_)).Times(0);
|
||||
Cdm::Status status = cdm_->load(kBogusSessionId);
|
||||
@@ -921,7 +1049,7 @@ TEST_F(CdmTest, Remove) {
|
||||
// Post the release message to the license server.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
@@ -975,7 +1103,7 @@ TEST_F(CdmTest, RemoveUsageRecord) {
|
||||
// Post the release message to the license server.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
@@ -1037,7 +1165,7 @@ TEST_F(CdmTest, RemoveIncomplete) {
|
||||
// Post the release message to the license server.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
@@ -1108,7 +1236,7 @@ TEST_F(CdmTest, RemoveUsageRecordIncomplete) {
|
||||
// Post the release message to the license server.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
@@ -1141,7 +1269,7 @@ TEST_F(CdmTest, RequestPersistentLicenseWithWrongInitData) {
|
||||
// persistent content init data.
|
||||
std::string session_id;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->createSession(Cdm::kPersistentLicense, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1161,7 +1289,7 @@ TEST_F(CdmTest, RequestTemporaryLicenseWithWrongInitData) {
|
||||
// Generate a request for a temporary license using persistent init data.
|
||||
std::string session_id;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1177,7 +1305,7 @@ TEST_F(CdmTest, RequestTemporaryLicenseWithWrongInitData) {
|
||||
// Acquire a license.
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &response));
|
||||
g_license_server, message, &response));
|
||||
|
||||
// This license should not be accepted.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
@@ -1408,11 +1536,19 @@ class CdmIndividualizationTest : public CdmTest {
|
||||
|
||||
std::string GetProvisioningResponse(const std::string& message) {
|
||||
std::string reply;
|
||||
std::string uri = kProvisioningServerUrl;
|
||||
std::string uri = g_provisioning_server;
|
||||
|
||||
LOGV("GetProvisioningResponse: URI: %s", uri.c_str());
|
||||
LOGV("GetProvisioningResponse: message:\n%s\n", message.c_str());
|
||||
|
||||
uri += "&signedRequest=" + message;
|
||||
FetchCertificate(uri, &reply);
|
||||
if (HasFatalFailure())
|
||||
if (HasFatalFailure()) {
|
||||
LOGE("GetProvisioningResponse: Failed.");
|
||||
return "";
|
||||
}
|
||||
|
||||
LOGV("GetProvisioningResponse: response:\n%s\n", reply.c_str());
|
||||
return reply;
|
||||
}
|
||||
};
|
||||
@@ -1426,7 +1562,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
|
||||
// Creating a session should succeed.
|
||||
std::string session_id;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1454,7 +1590,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
|
||||
|
||||
// Acquire a license and update the session.
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
kLicenseServerAppspot, message, &reply));
|
||||
g_license_server, message, &reply));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, reply);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
@@ -36,8 +36,8 @@ class TestHost : public widevine::Cdm::IStorage,
|
||||
|
||||
private:
|
||||
struct Timer {
|
||||
Timer(int64_t expiry_time, IClient* client, void* context)
|
||||
: expiry_time(expiry_time), client(client), context(context) {}
|
||||
Timer(int64_t expiry_time_, IClient* client_, void* context_)
|
||||
: expiry_time(expiry_time_), client(client_), context(context_) {}
|
||||
|
||||
bool operator<(const Timer& other) const {
|
||||
// We want to reverse the order so that the smallest expiry times go to
|
||||
|
||||
Reference in New Issue
Block a user