Update includes and BUILD

This commit is contained in:
Lu Chen
2020-02-05 11:21:51 -08:00
parent 5c42bf9b7f
commit ac564bb46f
50 changed files with 510 additions and 377 deletions

View File

@@ -26,13 +26,11 @@ cc_library(
hdrs = ["ecm.h"],
deps = [
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//common:aes_cbc_util",
"//common:status",
"//common:string_util",
"//media_cas_packager_sdk/public:wv_cas_types",
"//protos/public:media_cas_cc_proto",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -44,8 +42,6 @@ cc_test(
deps = [
":ecm",
"//testing:gunit_main",
"//common:status",
"//media_cas_packager_sdk/public:wv_cas_types",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -57,7 +53,6 @@ cc_library(
deps = [
":ecm",
"//base",
"@abseil_repo//absl/base:core_headers",
"//common:status",
],
)
@@ -91,15 +86,12 @@ cc_library(
":simulcrypt_util",
":util",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/container:node_hash_map",
"@abseil_repo//absl/memory",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/strings:str_format",
"//common:crypto_util",
"//common:random_util",
"//common:status",
"//example:constants",
"//media_cas_packager_sdk/public:wv_cas_ecm",
"//media_cas_packager_sdk/public:wv_cas_key_fetcher",
"//media_cas_packager_sdk/public:wv_cas_types",
@@ -132,12 +124,13 @@ cc_library(
],
deps = [
":simulcrypt_util",
":ts_packet",
":util",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/strings:str_format",
"//common:status",
"//example:test_emmg_messages",
"//protos/public:media_cas_cc_proto",
],
)
@@ -182,10 +175,7 @@ cc_library(
hdrs = [
"mpeg2ts.h",
],
deps = [
"//base",
"@abseil_repo//absl/base:core_headers",
],
deps = ["//base"],
)
cc_library(
@@ -198,8 +188,6 @@ cc_library(
deps = [
":util",
"//base",
"@abseil_repo//absl/base:core_headers",
"//common:status",
],
)
@@ -215,7 +203,6 @@ cc_library(
deps = [
":mpeg2ts",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//common:status",
"//common:string_util",
@@ -227,7 +214,6 @@ cc_test(
size = "small",
srcs = ["ts_packet_test.cc"],
deps = [
":mpeg2ts",
":ts_packet",
"//base",
"//testing:gunit_main",
@@ -245,7 +231,6 @@ cc_library(
":mpeg2ts",
":ts_packet",
"//base",
"@abseil_repo//absl/base:core_headers",
"//common:status",
],
)
@@ -258,6 +243,8 @@ cc_test(
],
deps = [
":util",
"//base",
"//testing:gunit_main",
"//common:status",
],
)

View File

@@ -8,14 +8,13 @@
#include "media_cas_packager_sdk/internal/ecm.h"
#include <stddef.h>
#include <bitset>
#include <utility>
#include <vector>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "common/aes_cbc_util.h"
#include "common/status.h"
#include "common/string_util.h"
#include "protos/public/media_cas_encryption.pb.h"

View File

@@ -16,9 +16,9 @@
#include <utility>
#include <vector>
#include <cstdint>
#include "common/status.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
#include "protos/public/media_cas.pb.h"
namespace widevine {
namespace cas {

View File

@@ -8,9 +8,6 @@
#include "media_cas_packager_sdk/internal/ecm_generator.h"
#include <memory>
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"

View File

@@ -8,14 +8,8 @@
#include "media_cas_packager_sdk/internal/ecm.h"
#include <stddef.h>
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/status.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
#include "protos/public/media_cas_encryption.pb.h"
using ::testing::Return;

View File

@@ -8,22 +8,13 @@
#include "media_cas_packager_sdk/internal/ecmg_client_handler.h"
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "common/crypto_util.h"
#include "common/random_util.h"
#include "common/status.h"
#include "example/constants.h"
#include "media_cas_packager_sdk/internal/ecmg_constants.h"
#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
@@ -32,7 +23,6 @@
#include "media_cas_packager_sdk/internal/util.h"
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
// CA System ID for Widevine.
static constexpr uint16_t kWidevineSystemId = 0x4AD4;
@@ -96,7 +86,7 @@ Status ProcessPrivateParameters(const char* const request, uint16_t param_type,
break;
case AGE_RESTRICTION:
if (param_length != AGE_RESTRICTION_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -106,7 +96,7 @@ Status ProcessPrivateParameters(const char* const request, uint16_t param_type,
case ENTITLEMENT_ID_KEY_COMBINATION: {
if (param_length !=
kEntitlementKeyIdSizeBytes + kEntitlementKeyValueSizeBytes) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -185,7 +175,7 @@ Status HandleParameters(const char* const request, size_t request_length,
}
case CP_DURATION:
if (param_length != CP_DURATION_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -194,7 +184,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case CP_NUMBER:
if (param_length != CP_NUMBER_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -208,7 +198,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case ECM_CHANNEL_ID:
if (param_length != ECM_CHANNEL_ID_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -217,7 +207,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case ECM_ID:
if (param_length != ECM_ID_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -226,7 +216,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case ECM_STREAM_ID:
if (param_length != ECM_STREAM_ID_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -235,7 +225,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case NOMINAL_CP_DURATION:
if (param_length != NOMINAL_CP_DURATION_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -244,7 +234,7 @@ Status HandleParameters(const char* const request, size_t request_length,
break;
case SUPER_CAS_ID:
if (param_length != SUPER_CAS_ID_SIZE) {
return Status(error::INVALID_ARGUMENT,
return Status(error::FAILED_PRECONDITION,
absl::StrCat("Invalid parameter length ", param_length,
" for parameter type ", param_type));
}
@@ -357,10 +347,14 @@ uint16_t StatusToDvbErrorCode(const Status& status) {
return 0;
}
switch (status.error_code()) {
case error::FAILED_PRECONDITION:
return INCONSISTENT_LENGTH_FOR_DVB_PARAMETER;
case error::INVALID_ARGUMENT:
return INVALID_VALUE_FOR_DVB_PARAMETER;
case error::NOT_FOUND:
return MISSING_MANDATORY_DVB_PARAMETER;
case error::UNIMPLEMENTED:
return UNKNOWN_PARAMETER_TYPE_VALUE;
case error::INTERNAL:
default:
return UNKNOWN_ERROR;
@@ -454,22 +448,8 @@ void EcmgClientHandler::HandleRequest(const char* const request, char* response,
Status status = HandleParameters(request + offset, request_length, &params);
if (!status.ok()) {
LOG(ERROR) << status.ToString();
switch (status.error_code()) {
case error::INVALID_ARGUMENT:
// TODO(user): Should use INCONSISTENT_LENGTH_FOR_DVB_PARAMETER in most
// cases.
BuildChannelError(params.ecm_channel_id,
INVALID_VALUE_FOR_DVB_PARAMETER,
status.error_message(), response, response_length);
break;
case error::UNIMPLEMENTED:
BuildChannelError(params.ecm_channel_id, UNKNOWN_PARAMETER_TYPE_VALUE,
status.error_message(), response, response_length);
break;
default:
BuildChannelError(params.ecm_channel_id, UNKNOWN_ERROR,
status.error_message(), response, response_length);
}
BuildChannelError(params.ecm_channel_id, StatusToDvbErrorCode(status),
status.error_message(), response, response_length);
return;
}
switch (request_type) {
@@ -535,7 +515,7 @@ void EcmgClientHandler::HandleChannelSetup(const EcmgParameters& params,
channel_id_ = params.ecm_channel_id;
channel_id_set_ = true;
Status status = UpdatePrivateParameters(params, false);
Status status = UpdateChannelPrivateParameters(params);
if (!status.ok()) {
LOG(ERROR) << status.ToString();
BuildChannelError(params.ecm_channel_id, StatusToDvbErrorCode(status),
@@ -595,7 +575,7 @@ void EcmgClientHandler::HandleStreamSetup(const EcmgParameters& params,
streams_info_[params.ecm_stream_id] = absl::make_unique<EcmgStreamInfo>();
streams_info_[params.ecm_stream_id]->ecm_id = params.ecm_id;
Status status = UpdatePrivateParameters(params, true);
Status status = UpdateStreamPrivateParameters(params);
if (!status.ok()) {
LOG(ERROR) << status.ToString();
BuildStreamError(params.ecm_channel_id, params.ecm_stream_id,
@@ -684,7 +664,7 @@ void EcmgClientHandler::HandleCwProvision(const EcmgParameters& params,
}
// Update private parameters based on access_criteria if any.
Status status = UpdatePrivateParameters(params, true);
Status status = UpdateStreamPrivateParameters(params);
if (!status.ok()) {
LOG(ERROR) << status.ToString();
BuildStreamError(params.ecm_channel_id, params.ecm_stream_id,
@@ -721,47 +701,23 @@ void EcmgClientHandler::HandleCwProvision(const EcmgParameters& params,
params.cp_number, ecm_datagram, response, response_length);
}
Status EcmgClientHandler::UpdatePrivateParameters(const EcmgParameters& params,
bool stream_specific) {
EcmgStreamInfo* stream_info =
stream_specific ? streams_info_[params.ecm_stream_id].get() : nullptr;
Status EcmgClientHandler::UpdateCommonPrivateParameters(
const EcmgParameters& params) {
if (params.age_restriction != 0xff) {
if (params.age_restriction > kMaxAllowedAgeRestriction) {
return {error::INVALID_ARGUMENT, "Age restriction too large."};
}
age_restriction_ = params.age_restriction;
}
if (!params.crypto_mode.empty()) {
if (!StringToCryptoMode(params.crypto_mode,
stream_specific ? &stream_info->crypto_mode
: &ecmg_config_->crypto_mode)) {
return {error::INVALID_ARGUMENT,
absl::StrCat("Unknown crypto mode: ", params.crypto_mode, ".")};
}
}
if (!params.track_types.empty()) {
track_types_.assign(params.track_types.begin(), params.track_types.end());
}
if (!params.stream_track_type.empty()) {
if (stream_specific) {
stream_info->track_type = params.stream_track_type;
} else {
LOG(WARNING) << "Ignoring stream track type received in channel config.";
}
}
if (!params.content_id.empty()) {
content_id_ = params.content_id;
}
if (!params.content_provider.empty()) {
content_provider_ = params.content_provider;
}
if (!params.content_ivs.empty()) {
if (params.content_ivs.size() < ecmg_config_->number_of_content_keys) {
return {error::INVALID_ARGUMENT,
@@ -778,19 +734,54 @@ Status EcmgClientHandler::UpdatePrivateParameters(const EcmgParameters& params,
return {error::INVALID_ARGUMENT, "Size of content ivs must match."};
}
}
if (stream_specific) {
stream_info->content_ivs.assign(params.content_ivs.begin(),
params.content_ivs.end());
} else {
content_ivs_.assign(params.content_ivs.begin(), params.content_ivs.end());
}
}
if (!params.entitlement_comb.empty()) {
entitlement_comb_.assign(params.entitlement_comb.begin(),
params.entitlement_comb.end());
}
return OkStatus();
}
Status EcmgClientHandler::UpdateChannelPrivateParameters(
const EcmgParameters& params) {
Status status = UpdateCommonPrivateParameters(params);
if (!status.ok()) {
return status;
}
if (!params.crypto_mode.empty()) {
if (!StringToCryptoMode(params.crypto_mode, &ecmg_config_->crypto_mode)) {
return {error::INVALID_ARGUMENT,
absl::StrCat("Unknown crypto mode: ", params.crypto_mode, ".")};
}
}
if (!params.content_ivs.empty()) {
content_ivs_.assign(params.content_ivs.begin(), params.content_ivs.end());
}
return OkStatus();
}
Status EcmgClientHandler::UpdateStreamPrivateParameters(
const EcmgParameters& params) {
DCHECK(streams_info_.contains(params.ecm_stream_id));
EcmgStreamInfo* stream_info = streams_info_[params.ecm_stream_id].get();
Status status = UpdateCommonPrivateParameters(params);
if (!status.ok()) {
return status;
}
if (!params.crypto_mode.empty()) {
if (!StringToCryptoMode(params.crypto_mode, &stream_info->crypto_mode)) {
return {error::INVALID_ARGUMENT,
absl::StrCat("Unknown crypto mode: ", params.crypto_mode, ".")};
}
}
if (!params.stream_track_type.empty()) {
stream_info->track_type = params.stream_track_type;
}
if (!params.content_ivs.empty()) {
stream_info->content_ivs.assign(params.content_ivs.begin(),
params.content_ivs.end());
}
return OkStatus();
}

View File

@@ -10,13 +10,8 @@
#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CLIENT_HANDLER_H_
#include <cstddef>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cstdint>
@@ -116,12 +111,12 @@ class EcmgClientHandler {
size_t* response_length);
void HandleCwProvision(const EcmgParameters& params, char* response,
size_t* response_length);
// Update private paprameters using |params|. |stream_specific| indicates if
// |params| is for a single stream or the whole channel. If |stream_specific|
// is true, |params| will only affect values of this stream. If it is false,
// |param| will affect all streams of the channel.
Status UpdatePrivateParameters(const EcmgParameters& params,
bool stream_specific);
// Update private parameters using |params|.
Status UpdateChannelPrivateParameters(const EcmgParameters& params);
Status UpdateStreamPrivateParameters(const EcmgParameters& params);
Status UpdateCommonPrivateParameters(const EcmgParameters& params);
// Check if all required parameters have been set. If so, initialize |ecm_| by
// fetching entitlement keys.
Status CheckAndInitializeEcm(const EcmgParameters& params);

View File

@@ -8,9 +8,10 @@
#include "media_cas_packager_sdk/internal/ecmg_client_handler.h"
#include <string>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
@@ -455,6 +456,81 @@ TEST_F(EcmgClientHandlerTest, WrongParameterChannelId) {
CheckStreamError(UNKNOWN_ECM_CHANNEL_ID_VALUE, response_, response_len_);
}
TEST_F(EcmgClientHandlerTest, WrongParameterCryptoMode) {
BuildChannelSetupRequest(kChannelId, kSuperCasId, kAgeRestriction,
"someCryptoMode", {kTrackTypesHD, kTrackTypesSD},
kContentId, kContentProvider, /*entitlements*/ {},
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
CheckChannelError(INVALID_VALUE_FOR_DVB_PARAMETER, response_, response_len_);
}
TEST_F(EcmgClientHandlerTest, WrongParameterLengthSuperCasId) {
// Setup a channel with an unexpected super cas id length (2 instead of 4).
handler_->HandleRequest(kTestEcmgChannelSetupWrongParameterLength, response_,
&response_len_);
CheckChannelError(INCONSISTENT_LENGTH_FOR_DVB_PARAMETER, response_,
response_len_);
}
TEST_F(EcmgClientHandlerTest, NoEntitlementsNoContentIdProvider) {
BuildChannelSetupRequest(kChannelId, kSuperCasId, kAgeRestriction,
kCryptoMode, {kTrackTypesHD, kTrackTypesSD},
/*ContentId*/ "", /*ContentProvider*/ "",
/*entitlements*/ {}, request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
EXPECT_EQ(sizeof(kTestEcmgChannelStatus), response_len_);
EXPECT_EQ(0, memcmp(kTestEcmgChannelStatus, response_, response_len_));
BuildStreamSetupRequest(kChannelId, kStreamId, kEcmId, kNominalCpDuration,
kTrackTypesSD, {kContentKeyEven, kContentKeyEven},
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
EXPECT_EQ(sizeof(kTestEcmgStreamStatus), response_len_);
EXPECT_EQ(0, memcmp(kTestEcmgStreamStatus, response_, response_len_));
const std::vector<EcmgCpCwCombination> cp_cw_combination = {
{kCpNumber, kContentKeyEven}, {kCpNumber + 1, kContentKeyOdd}};
BuildCwProvisionRequest(kChannelId, kStreamId, kCpNumber, cp_cw_combination,
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
CheckStreamError(MISSING_MANDATORY_DVB_PARAMETER, response_, response_len_);
}
TEST_F(EcmgClientHandlerTest, NotEnoughInjectedEntitlements) {
BuildChannelSetupRequest(
kChannelId, kSuperCasId, kAgeRestriction, kCryptoMode,
{kTrackTypesHD, kTrackTypesSD},
/*ContentId*/ "", /*ContentProvider*/ "",
{absl::StrCat(kEntitlementKeyIdEven, kEntitlementKeyValueEven),
absl::StrCat(kEntitlementKeyIdOdd, kEntitlementKeyValueOdd)},
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
EXPECT_EQ(sizeof(kTestEcmgChannelStatus), response_len_);
EXPECT_EQ(0, memcmp(kTestEcmgChannelStatus, response_, response_len_));
BuildStreamSetupRequest(kChannelId, kStreamId, kEcmId, kNominalCpDuration,
kTrackTypesSD, {kContentKeyEven, kContentKeyEven},
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
EXPECT_EQ(sizeof(kTestEcmgStreamStatus), response_len_);
EXPECT_EQ(0, memcmp(kTestEcmgStreamStatus, response_, response_len_));
const std::vector<EcmgCpCwCombination> cp_cw_combination = {
{kCpNumber, kContentKeyEven}, {kCpNumber + 1, kContentKeyOdd}};
BuildCwProvisionRequest(kChannelId, kStreamId, kCpNumber, cp_cw_combination,
request_, &request_len_);
handler_->HandleRequest(request_, response_, &response_len_);
CheckStreamError(MISSING_MANDATORY_DVB_PARAMETER, response_, response_len_);
}
TEST_F(EcmgClientHandlerTest, WrongMessageLength) {
// Setup a channel with a wrong message length specified (too large).
handler_->HandleRequest(kTestEcmgChannelSetupWrongMessageLength, response_,
&response_len_);
CheckChannelError(UNKNOWN_PARAMETER_TYPE_VALUE, response_, response_len_);
}
} // namespace
} // namespace cas
} // namespace widevine

View File

@@ -10,18 +10,19 @@
#include <sys/socket.h>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iostream>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "example/test_emmg_messages.h"
#include "media_cas_packager_sdk/internal/emmg_constants.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
#include "media_cas_packager_sdk/internal/simulcrypt_constants.h"
#include "media_cas_packager_sdk/internal/simulcrypt_util.h"
#include "media_cas_packager_sdk/internal/ts_packet.h"
#include "media_cas_packager_sdk/internal/util.h"
#include "protos/public/media_cas.pb.h"
namespace widevine {
namespace cas {
@@ -125,6 +126,36 @@ void Emmg::BuildStreamSetup() {
Host16ToBigEndian(request_ + 3, &total_param_length);
}
Status Emmg::GeneratePrivateData(const std::string& content_provider,
const std::string& content_id, uint8_t* buffer) {
DCHECK(buffer);
// Generate payload.
CaDescriptorPrivateData private_data;
private_data.set_provider(content_provider);
private_data.set_content_id(content_id);
std::string private_data_str = private_data.SerializeAsString();
std::string payload_filler(kMaxTsPayloadSize - private_data_str.size(), 0);
// Wrap the data with a TS header.
TsPacket ecm_packet;
ecm_packet.set_payload_unit_start_indicator(true);
ecm_packet.set_pid(0);
ecm_packet.set_payload(absl::StrCat(private_data_str, payload_filler));
ecm_packet.set_adaptation_field_control(TsPacket::kPayloadOnly);
ecm_packet.set_continuity_counter(continuity_counter_);
continuity_counter_ = ++continuity_counter_ & 0xf;
// And write the packet.
std::string ecm_ts_packet;
Status status = ecm_packet.Write(&ecm_ts_packet);
if (!status.ok()) {
LOG(ERROR) << status.ToString();
return status;
}
memcpy(buffer, ecm_ts_packet.data(), ecm_ts_packet.size());
return OkStatus();
}
void Emmg::BuildDataProvision() {
bzero(request_, BUFFER_SIZE);
request_length_ = 0;
@@ -142,15 +173,11 @@ void Emmg::BuildDataProvision() {
simulcrypt_util::AddUint16Param(EMMG_DATA_ID, emmg_config_->data_id, request_,
&request_length_);
// Add a fake TS packet.
uint16_t datagram_type = EMMG_DATAGRAM;
Host16ToBigEndian(request_ + request_length_, &datagram_type);
request_length_ += 2;
uint16_t param_length = sizeof(kTestEmmgTsPacket); // Should be 188.
Host16ToBigEndian(request_ + request_length_, &param_length);
request_length_ += 2;
memcpy(request_ + request_length_, kTestEmmgTsPacket, param_length);
request_length_ += param_length;
uint8_t datagram[kTsPacketSize];
GeneratePrivateData(emmg_config_->content_provider, emmg_config_->content_id,
datagram);
simulcrypt_util::AddParam(EMMG_DATAGRAM, datagram, kTsPacketSize, request_,
&request_length_);
uint16_t total_param_length = request_length_ - 5;
Host16ToBigEndian(request_ + 3, &total_param_length);

View File

@@ -10,13 +10,9 @@
#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_EMMG_H_
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <cstdint>
#include "glog/logging.h"
#include "common/status.h"
#define BUFFER_SIZE (1024)
@@ -32,6 +28,8 @@ struct EmmgConfig {
uint16_t data_stream_id;
uint16_t data_id;
uint8_t data_type;
std::string content_provider;
std::string content_id;
};
// A class that sends EMMG/PDG message to the MUX server.
@@ -62,6 +60,8 @@ class Emmg {
void SendStreamCloseRequest();
void SendChannelClose();
Status GeneratePrivateData(const std::string& content_provider,
const std::string& content_id, uint8_t* buffer);
void ReceiveResponseAndVerify(uint16_t expected_type);
void Send(uint16_t message_type);
@@ -72,6 +72,8 @@ class Emmg {
// |server_socket_fd| is a file descriptor we can use to communicate
// with the MUX server.
int server_socket_fd_;
// |continuity_counter| is incremented each time private data is generated.
int continuity_counter_ = 0;
};
} // namespace cas

View File

@@ -8,6 +8,12 @@
#include "media_cas_packager_sdk/internal/emmg.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <memory>
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
@@ -38,6 +44,8 @@ class EmmgTest : public ::testing::Test {
config_.data_stream_id = 0x0001;
config_.data_id = 0x0001;
config_.data_type = 0x01;
config_.content_provider = "widevine_test";
config_.content_id = "CasTsFake";
emmg_ = absl::make_unique<TestableEmmg>(&config_);
}

View File

@@ -8,7 +8,6 @@
#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h"
#include "common/status.h"
#include "protos/public/media_cas_encryption.pb.h"
namespace widevine {

View File

@@ -9,6 +9,9 @@
#ifndef MEDIA_CAS_PACKAGER_SDK_INTERNAL_FIXED_KEY_FETCHER_H_
#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_FIXED_KEY_FETCHER_H_
#include <string>
#include "common/status.h"
#include "media_cas_packager_sdk/internal/key_fetcher.h"
namespace widevine {

View File

@@ -13,7 +13,6 @@
#include <cstddef>
#include <cstdint>
#include "base/macros.h"
namespace widevine {
namespace cas {

View File

@@ -8,7 +8,6 @@
#include "media_cas_packager_sdk/internal/simulcrypt_util.h"
#include <cstddef>
#include <cstring>
#include "glog/logging.h"

View File

@@ -12,13 +12,8 @@
#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_SIMULCRYPT_UTIL_H_
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <cstdint>
#include "common/status.h"
namespace widevine {
namespace cas {

View File

@@ -12,7 +12,6 @@
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "common/status.h"
#include "common/string_util.h"
namespace widevine {

View File

@@ -33,11 +33,9 @@
#ifndef MEDIA_CAS_PACKAGER_SDK_INTERNAL_TS_PACKET_H_
#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_TS_PACKET_H_
#include <memory>
#include <string>
#include <cstdint>
#include "base/macros.h"
#include "absl/strings/string_view.h"
#include "common/status.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"

View File

@@ -8,12 +8,9 @@
#include "media_cas_packager_sdk/internal/ts_packet.h"
#include <string>
#include "base/macros.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
namespace widevine {
namespace cas {

View File

@@ -9,6 +9,7 @@
#include "media_cas_packager_sdk/internal/util.h"
#include <netinet/in.h>
#include <cstddef>
#include <cstring>

View File

@@ -60,7 +60,6 @@ cc_library(
deps = [
":wv_cas_types",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//common:status",
"//common:string_util",
@@ -77,7 +76,6 @@ cc_test(
srcs = ["wv_cas_ca_descriptor_test.cc"],
deps = [
":wv_cas_ca_descriptor",
":wv_cas_types",
"//testing:gunit_main",
"//protos/public:media_cas_cc_proto",
],
@@ -113,7 +111,6 @@ cc_test(
srcs = ["wv_cas_ecm_test.cc"],
deps = [
":wv_cas_ecm",
":wv_cas_types",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
"//media_cas_packager_sdk/internal:mpeg2ts",
@@ -131,10 +128,9 @@ cc_library(
deps = [
"//base",
"//external:protobuf",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/flags:flag",
"@abseil_repo//absl/strings",
"@curl_repo//:curl",
"//util:error_space",
"//common:signature_util",
"//common:status",
"//media_cas_packager_sdk/internal:key_fetcher",
@@ -153,7 +149,9 @@ cc_test(
"//base",
"//external:protobuf",
"//testing:gunit_main",
"@abseil_repo//absl/flags:flag",
"@abseil_repo//absl/strings",
"//common:status",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -189,8 +187,8 @@ cc_binary(
deps = [
":wv_cas_types",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/flags:flag",
"@abseil_repo//absl/flags:parse",
"//media_cas_packager_sdk/internal:ecmg_client_handler",
],
)
@@ -200,6 +198,8 @@ cc_binary(
srcs = ["wv_emmg.cc"],
deps = [
"//base",
"@abseil_repo//absl/flags:flag",
"@abseil_repo//absl/flags:parse",
"//media_cas_packager_sdk/internal:emmg",
],
)

View File

@@ -14,7 +14,6 @@
#include "absl/strings/str_cat.h"
#include "common/status.h"
#include "common/string_util.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
#include "protos/public/media_cas.pb.h"
namespace widevine {

View File

@@ -10,8 +10,10 @@
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CA_DESCRIPTOR_H_
#include <stddef.h>
#include <string>
#include <cstdint>
#include "media_cas_packager_sdk/public/wv_cas_types.h"
namespace widevine {

View File

@@ -8,10 +8,7 @@
#include "media_cas_packager_sdk/public/wv_cas_ca_descriptor.h"
#include <string>
#include "testing/gunit.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
#include "protos/public/media_cas.pb.h"
using ::testing::Test;

View File

@@ -8,13 +8,15 @@
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <memory>
#include <utility>
#include <vector>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "common/crypto_util.h"
#include "common/status.h"
#include "example/constants.h"
@@ -22,7 +24,6 @@
#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
#include "media_cas_packager_sdk/internal/util.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
namespace widevine {
namespace cas {

View File

@@ -9,13 +9,9 @@
#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
#include <cstddef>
#include <list>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <cstdint>
#include "media_cas_packager_sdk/public/wv_cas_types.h"
namespace widevine {

View File

@@ -8,11 +8,11 @@
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
#include <string.h>
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
using ::testing::Test;

View File

@@ -10,32 +10,32 @@
#include <stddef.h>
#include <string.h>
#include <string>
#include "gflags/gflags.h"
#include <cstdint>
#include "glog/logging.h"
#include "google/protobuf/util/json_util.h"
#include "absl/flags/flag.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "curl/curl.h"
#include "curl/easy.h"
#include "common/signature_util.h"
#include "common/status.h"
#include "protos/public/media_cas_encryption.pb.h"
using google::protobuf::util::JsonPrintOptions;
using google::protobuf::util::JsonStringToMessage;
using google::protobuf::util::MessageToJsonString;
DEFINE_string(
license_server, "",
"HTTP URL to the license server for making CAS encryption request");
DEFINE_string(signing_provider, "",
"Name of the provider signing the CAS encryption request");
DEFINE_string(signing_key, "",
"AES key (in hex) for signing the CAS encryption request");
DEFINE_string(signing_iv, "",
"AES iv (in hex) for signing the CAS encryption request");
ABSL_FLAG(std::string, license_server, "",
"HTTP URL to the license server for making CAS encryption request.");
ABSL_FLAG(std::string, signing_provider, "",
"Name of the provider signing the CAS encryption request.");
ABSL_FLAG(std::string, signing_key, "",
"AES key (in hex) for signing the CAS encryption request.");
ABSL_FLAG(std::string, signing_iv, "",
"AES iv (in hex) for signing the CAS encryption request.");
namespace widevine {
namespace cas {
@@ -43,8 +43,9 @@ namespace cas {
Status WvCasKeyFetcher::RequestEntitlementKey(
const std::string& request_string,
std::string* signed_response_string) const {
if (FLAGS_signing_provider.empty() || FLAGS_signing_key.empty() ||
FLAGS_signing_iv.empty()) {
if (absl::GetFlag(FLAGS_signing_provider).empty() ||
absl::GetFlag(FLAGS_signing_key).empty() ||
absl::GetFlag(FLAGS_signing_iv).empty()) {
return Status(
error::INVALID_ARGUMENT,
"Flag 'signing_provider', 'signing_key' or 'signing_iv' is empty");
@@ -73,13 +74,14 @@ Status WvCasKeyFetcher::RequestEntitlementKey(
signed_request.set_request(request_json);
std::string signature;
if (!signature_util::GenerateAesSignature(
request_json, absl::HexStringToBytes(FLAGS_signing_key),
absl::HexStringToBytes(FLAGS_signing_iv), &signature)
request_json,
absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_key)),
absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_iv)), &signature)
.ok()) {
return Status(error::INTERNAL, "Failed to sign the request.");
}
signed_request.set_signature(signature);
signed_request.set_signer(FLAGS_signing_provider);
signed_request.set_signer(absl::GetFlag(FLAGS_signing_provider));
std::string signed_request_json;
// NOTE: MessageToJsonString will automatically converts the 'request' and
// 'signature' fields in SignedCasEncryptionRequest to base64, because they
@@ -126,14 +128,15 @@ size_t AppendToString(void* ptr, size_t size, size_t count,
Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json,
std::string* http_response_json) const {
CHECK(http_response_json);
if (FLAGS_license_server.empty()) {
if (absl::GetFlag(FLAGS_license_server).empty()) {
return Status(error::INVALID_ARGUMENT, "Flag 'license_server' is empty");
}
CURL* curl;
CURLcode curl_code;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, FLAGS_license_server.c_str());
curl_easy_setopt(curl, CURLOPT_URL,
absl::GetFlag(FLAGS_license_server).c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, signed_request_json.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response_json);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &AppendToString);

View File

@@ -11,14 +11,10 @@
#include <string>
#include "gflags/gflags.h"
#include "absl/flags/declare.h"
#include "common/status.h"
#include "media_cas_packager_sdk/internal/key_fetcher.h"
DECLARE_string(license_server);
DECLARE_string(signing_provider);
DECLARE_string(signing_key);
DECLARE_string(signing_iv);
namespace widevine {
namespace cas {
@@ -55,4 +51,10 @@ class WvCasKeyFetcher : public KeyFetcher {
} // namespace cas
} // namespace widevine
// Exposed for testing and example.
ABSL_DECLARE_FLAG(std::string, license_server);
ABSL_DECLARE_FLAG(std::string, signing_provider);
ABSL_DECLARE_FLAG(std::string, signing_key);
ABSL_DECLARE_FLAG(std::string, signing_iv);
#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_KEY_FETCHER_H_

View File

@@ -8,12 +8,13 @@
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "google/protobuf/text_format.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/flags/flag.h"
#include "absl/strings/escaping.h"
#include "common/status.h"
#include "protos/public/media_cas_encryption.pb.h"
using testing::_;
@@ -63,9 +64,9 @@ class WvCasKeyFetcherTest : public ::testing::Test {
public:
WvCasKeyFetcherTest() {}
void SetUp() override {
FLAGS_signing_provider = kSigningProvider;
FLAGS_signing_key = kSingingKey;
FLAGS_signing_iv = kSingingIv;
absl::SetFlag(&FLAGS_signing_provider, kSigningProvider);
absl::SetFlag(&FLAGS_signing_key, kSingingKey);
absl::SetFlag(&FLAGS_signing_iv, kSingingIv);
CHECK(
google::protobuf::TextFormat::ParseFromString(kCasEncryptionRequest, &request_));

View File

@@ -8,7 +8,6 @@
#include "media_cas_packager_sdk/public/wv_cas_types.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace widevine {

View File

@@ -9,6 +9,7 @@
// Widevine MediaCAS ECMG server.
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -19,54 +20,37 @@
#include <iostream>
#include <string>
#include "gflags/gflags.h"
#include <cstdint>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "media_cas_packager_sdk/internal/ecmg_client_handler.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
static constexpr int32_t kDefaultDelayStart = 200;
static constexpr int32_t kDefaultDelayStop = 200;
static constexpr int32_t kDefaultEcmRepPeriod = 100;
static constexpr int32_t kDefaultMaxCompTime = 100;
static constexpr int32_t kAccessCriteriaTransferMode = 0;
static constexpr int32_t kNumberOfContentKeys = 2;
static constexpr char kDefaultCryptoMode[] = "AesCtr";
static constexpr bool kDefaultUseFixedFetcher = false;
DEFINE_int32(port, 0, "Server port number");
ABSL_FLAG(int32_t, port, 1234, "Server port number.");
// ECMG related flags.
// TODO(user): Consider adding flags 'ac_delay_start', 'ac_delay_stop',
// 'transition_delay_start', 'transition_delay_stop'.
DEFINE_int32(
delay_start, kDefaultDelayStart,
"This flag sets the DVB SimulCrypt delay_start parameter, in milliseconds");
DEFINE_int32(
delay_stop, kDefaultDelayStop,
"This flag sets the DVB SimulCrypt delay_stop parameter, in milliseconds");
DEFINE_int32(
ecm_rep_period, kDefaultEcmRepPeriod,
"It sets the DVB SimulCrypt parameter ECM_rep_period, in milliseconds");
DEFINE_int32(
max_comp_time, kDefaultMaxCompTime,
"It sets the DVB SimulCrypt parameter max_comp_time, in milliseconds.");
DEFINE_int32(
access_criteria_transfer_mode, kAccessCriteriaTransferMode,
ABSL_FLAG(int32_t, delay_start, 200, "delay_start, in milliseconds.");
ABSL_FLAG(int32_t, delay_stop, 200, "delay_stop, in milliseconds.");
ABSL_FLAG(int32_t, ecm_rep_period, 100, "ECM_rep_period, in milliseconds.");
ABSL_FLAG(int32_t, max_comp_time, 100, "max_comp_time, in milliseconds.");
ABSL_FLAG(
int32_t, access_criteria_transfer_mode, 0,
"If it equals 0, it indicates that the access_criteria parameter is "
"required in the CW_provision message only when the contents of this "
"parameter change. If it equals 1, it indicates that the ECMG requires the "
"access_criteria parameter be present in each CW_provision message.");
DEFINE_int32(number_of_content_keys, kNumberOfContentKeys,
"It sets the number of content keys (CwPerMsg). Must be 1 (single "
"key) or 2 (key rotation enabled). It also sets LeadCw as "
"number_of_content_keys - 1.");
DEFINE_string(crypto_mode, kDefaultCryptoMode,
"Encryption mode. Choices are \"AesCtr\", \"AesCbc\", "
"\"DvbCsa2\", \"DvbCsa3\", \"AesOfb\", \"AesScte\".");
DEFINE_bool(use_fixed_fetcher, kDefaultUseFixedFetcher,
"Use fixed fetcher to fetch mocked entitlement licenses for "
"testing purposes.");
ABSL_FLAG(int32_t, number_of_content_keys, 2,
"It sets the number of content keys (CwPerMsg). Must be 1 (single "
"key) or 2 (key rotation enabled). It also sets LeadCw as "
"number_of_content_keys - 1.");
ABSL_FLAG(std::string, crypto_mode, "AesCtr",
"Encryption mode. Choices are \"AesCtr\", \"AesCbc\", "
"\"DvbCsa2\", \"DvbCsa3\", \"AesOfb\", \"AesScte\".");
ABSL_FLAG(bool, use_fixed_fetcher, false,
"If set, use fixed fetcher to fetch mocked entitlement licenses when "
"needed for testing purposes.");
#define LISTEN_QUEUE_SIZE (20)
#define BUFFER_SIZE (1024)
@@ -76,15 +60,20 @@ using widevine::cas::EcmgConfig;
void BuildEcmgConfig(EcmgConfig* config) {
DCHECK(config);
config->delay_start = FLAGS_delay_start;
config->delay_stop = FLAGS_delay_stop;
config->ecm_rep_period = FLAGS_ecm_rep_period;
config->max_comp_time = FLAGS_max_comp_time;
config->access_criteria_transfer_mode = FLAGS_access_criteria_transfer_mode;
config->number_of_content_keys = FLAGS_number_of_content_keys;
CHECK(StringToCryptoMode(FLAGS_crypto_mode, &config->crypto_mode))
config->delay_start = absl::GetFlag(FLAGS_delay_start);
config->delay_stop = absl::GetFlag(FLAGS_delay_stop);
config->ecm_rep_period = absl::GetFlag(FLAGS_ecm_rep_period);
config->max_comp_time = absl::GetFlag(FLAGS_max_comp_time);
config->access_criteria_transfer_mode =
absl::GetFlag(FLAGS_access_criteria_transfer_mode);
CHECK(absl::GetFlag(FLAGS_number_of_content_keys) == 1 ||
absl::GetFlag(FLAGS_number_of_content_keys) == 2)
<< "--number_of_content_keys must be 1 or 2.";
config->number_of_content_keys = absl::GetFlag(FLAGS_number_of_content_keys);
CHECK(StringToCryptoMode(absl::GetFlag(FLAGS_crypto_mode),
&config->crypto_mode))
<< "Unknown crypto mode.";
config->use_fixed_fetcher = FLAGS_use_fixed_fetcher;
config->use_fixed_fetcher = absl::GetFlag(FLAGS_use_fixed_fetcher);
}
void PrintMessage(const std::string& description, const char* const message,
@@ -126,11 +115,7 @@ void ServeClient(int socket_fd, EcmgClientHandler* ecmg) {
}
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK(FLAGS_port != 0) << "need --port";
CHECK(FLAGS_number_of_content_keys == 1 || FLAGS_number_of_content_keys == 2)
<< "--number_of_content_keys must be 1 or 2.";
absl::ParseCommandLine(argc, argv);
EcmgConfig ecmg_config;
BuildEcmgConfig(&ecmg_config);
@@ -139,7 +124,7 @@ int main(int argc, char** argv) {
bzero(reinterpret_cast<char*>(&server_address), sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(FLAGS_port);
server_address.sin_port = htons(absl::GetFlag(FLAGS_port));
// Create a listening socket.
int listen_socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0);

View File

@@ -12,54 +12,69 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include "gflags/gflags.h"
#include <cstring>
#include <string>
#include <cstdint>
#include "glog/logging.h"
#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "media_cas_packager_sdk/internal/emmg.h"
DEFINE_string(mux_address, "", "Mux server address");
DEFINE_int32(mux_port, 0, "Mux server port number");
// EMMG specfic configs.
DEFINE_int32(client_id, 0, "EMMG client_id");
DEFINE_int32(section_tspkt_flag, 1, "EMMG section_tspkt_flag");
DEFINE_int32(data_channel_id, 0, "EMMG data_channel_id");
DEFINE_int32(data_stream_id, 0, "EMMG data_stream_id");
DEFINE_int32(data_id, 0, "EMMG data_id");
ABSL_FLAG(std::string, mux_address, "", "Mux server address.");
ABSL_FLAG(int32_t, mux_port, 0, "Mux server port number.");
// EMMG specific configs.
// To facilitate uniqueness of client_id, the following rules apply:
// in the case of EMMs or other CA related data, the two first bytes of the
// client_id should be equal to the two bytes of the corresponding CA_system_id.
ABSL_FLAG(int32_t, client_id, 0x4AD40000, "EMMG client_id.");
// TODO(user): Currently it can only support section_tspkt_flag = 1.
ABSL_FLAG(int32_t, section_tspkt_flag, 1,
"EMMG section_tspkt_flag. Currently it can only be set to 1.");
ABSL_FLAG(int32_t, data_channel_id, 0, "EMMG data_channel_id.");
ABSL_FLAG(int32_t, data_stream_id, 0, "EMMG data_stream_id.");
ABSL_FLAG(int32_t, data_id, 0, "EMMG data_id.");
// data_type: type of data carried in the datagram in the stream:
// 0x00: EMM;
// 0x01: private data;
// 0x02: DVB reserved (ECM);
// other values: DVB reserved.
DEFINE_int32(data_type, 0, "EMMG data_type");
ABSL_FLAG(int32_t, data_type, 1, "EMMG data_type");
ABSL_FLAG(std::string, content_provider, "", "Content provider");
ABSL_FLAG(std::string, content_id, "", "Content id");
#define BUFFER_SIZE (1024)
void BuildEmmgConfig(widevine::cas::EmmgConfig *config) {
CHECK(config);
config->client_id = FLAGS_client_id;
config->section_tspkt_flag = FLAGS_section_tspkt_flag;
config->data_channel_id = FLAGS_data_channel_id;
config->data_stream_id = FLAGS_data_stream_id;
config->data_id = FLAGS_data_id;
config->data_type = FLAGS_data_type;
config->client_id = absl::GetFlag(FLAGS_client_id);
config->section_tspkt_flag = absl::GetFlag(FLAGS_section_tspkt_flag);
config->data_channel_id = absl::GetFlag(FLAGS_data_channel_id);
config->data_stream_id = absl::GetFlag(FLAGS_data_stream_id);
config->data_id = absl::GetFlag(FLAGS_data_id);
config->data_type = absl::GetFlag(FLAGS_data_type);
config->content_provider = absl::GetFlag(FLAGS_content_provider);
config->content_id = absl::GetFlag(FLAGS_content_id);
}
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_mux_address.empty()) << "flag --mux_address is required";
CHECK(FLAGS_mux_port != 0) << "flag --mux_port is required";
absl::ParseCommandLine(argc, argv);
CHECK(!absl::GetFlag(FLAGS_mux_address).empty())
<< "flag --mux_address is required";
CHECK(absl::GetFlag(FLAGS_mux_port) != 0) << "flag --mux_port is required";
// Create server address.
struct hostent ret;
struct hostent *server;
char buffer[BUFFER_SIZE];
int h_errnop = 0;
int return_val = gethostbyname_r(FLAGS_mux_address.c_str(), &ret, buffer,
sizeof(buffer), &server, &h_errnop);
int return_val =
gethostbyname_r(absl::GetFlag(FLAGS_mux_address).c_str(), &ret, buffer,
sizeof(buffer), &server, &h_errnop);
if (return_val != 0 || server == nullptr) {
LOG(FATAL) << "gethostbyname_r failed for " << FLAGS_mux_address;
LOG(FATAL) << "gethostbyname_r failed for "
<< absl::GetFlag(FLAGS_mux_address);
}
struct sockaddr_in server_address;
bzero(reinterpret_cast<char *>(&server_address), sizeof(server_address));
@@ -67,7 +82,7 @@ int main(int argc, char **argv) {
bcopy(server->h_addr,
reinterpret_cast<char *>(&server_address.sin_addr.s_addr),
server->h_length);
server_address.sin_port = htons(FLAGS_mux_port);
server_address.sin_port = htons(absl::GetFlag(FLAGS_mux_port));
// Connect to server.
int server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);