Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ bool ContentProtectionFirebolt::AcquireLicenseOpenOrUpdate( std::string clientId
do
{
std::string drmSession;
// reset per attempt so a stale transport error is not re-interpreted
errorCode = CONTENT_SECURITY_MANAGER_DRM_GEN_ERR_NONE;
if (!IsActive())
{
MW_LOG_ERR("Firebolt is not active (or) channel couldn't be opened");
Expand Down Expand Up @@ -349,6 +351,13 @@ bool ContentProtectionFirebolt::AcquireLicenseOpenOrUpdate( std::string clientId
if (newSession.isSessionValid() && !session.isSessionValid())
{
session = newSession;
/*
* A session is now established. Any subsequent retry must reuse it
* via updateDrmSession; re-invoking openDrmSession would create a
* second server-side session and orphan this client-side handle.
*/
update = true;
apiName = "UpdateDrmSession";
}

}
Expand Down Expand Up @@ -388,7 +397,29 @@ bool ContentProtectionFirebolt::AcquireLicenseOpenOrUpdate( std::string clientId
}
else if( errorCode != CONTENT_SECURITY_MANAGER_DRM_GEN_ERR_NONE)
{
getContentProtectionAsVerboseErrorCode(errorCode,*statusCode,*reasonCode);
/*
* errorCode carries a Firebolt transport error here, not a CPS plugin error.
* A transport-level failure (e.g. Timedout when the response is lost after
* SecManager already completed the license transaction, or NotConnected when
* the channel is down) is transient, so map it onto the retryable SecManager
* reasons instead of the non-retryable default 200:1.
*/
if (errorCode == static_cast<int32_t>(Firebolt::Error::Timedout))
{
*statusCode = CONTENT_SECURITY_MANAGER_DRM_FAILURE;
*reasonCode = CONTENT_SECURITY_MANAGER_SERVICE_TIMEOUT;
MW_LOG_ERR("ContentProtection %s Firebolt transport timeout, treating as retryable license timeout", apiName);
}
else if (errorCode == static_cast<int32_t>(Firebolt::Error::NotConnected))
{
*statusCode = CONTENT_SECURITY_MANAGER_DRM_FAILURE;
*reasonCode = CONTENT_SECURITY_MANAGER_SERVICE_CON_FAILURE;
MW_LOG_ERR("ContentProtection %s Firebolt transport not connected, treating as retryable connection failure", apiName);
}
else
{
getContentProtectionAsVerboseErrorCode(errorCode,*statusCode,*reasonCode);
}
}
if(!ret)
{
Expand Down Expand Up @@ -581,9 +612,24 @@ bool ContentProtectionFirebolt::OpenDrmSession(std::string& clientId, std::strin
if (drmSession)
{
MW_LOG_WARN("DRM session opened successfully with sessionId: '%s' with Response %s", drmSession->sessionId.c_str(), drmSession->openSessionResponse.c_str());
response = drmSession->openSessionResponse;
sessionId = std::stoll(drmSession->sessionId);
ret = true;
try
{
sessionId = std::stoll(drmSession->sessionId);
response = drmSession->openSessionResponse;
ret = true;
}
catch (const std::exception& e)
{
/*
* Malformed sessionId in a transport-level successful response. Without a
* usable ID the session lifetime cannot be managed client-side, and building
* a session object from an uninitialized ID would poison the retry loop with
* a bogus updateDrmSession target. Drop the payload so the caller treats this
* as a failed call and fails cleanly instead of crashing on the exception.
*/
errorCode = static_cast<int>(Firebolt::Error::General);
MW_LOG_ERR("openDrmSession: malformed sessionId '%s': %s", drmSession->sessionId.c_str(), e.what());
}
}
else
{
Expand Down
25 changes: 24 additions & 1 deletion externals/contentsecuritymanager/SecManagerThunder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,34 @@ bool SecManagerThunder::AcquireLicenseOpenOrUpdate( std::string clientId, std::s
if (newSession.isSessionValid() && !session.isSessionValid())
{
session = newSession;
/*
* A session is now established. Any subsequent retry must reuse it
* via updatePlaybackSession; re-invoking openPlaybackSession would
* create a second server-side session and orphan this client-side
* handle. sessionId must also be added to the request params since
* they were built for the open call.
*/
apiName = "updatePlaybackSession";
param["sessionId"] = session.getSessionID();
}

}
else
{
/*
* JSON-RPC transport failure or timeout: no response was received,
* so there is no secManagerResultContext to parse. SecManager may
* still have completed the transaction server-side. Treat this as a
* retryable connection failure rather than the non-retryable
* default 200:1, so a transient transport hiccup does not hard-fail
* the tune.
*/
*statusCode = CONTENT_SECURITY_MANAGER_DRM_FAILURE;
*reasonCode = CONTENT_SECURITY_MANAGER_SERVICE_CON_FAILURE;
MW_LOG_ERR("SecManager %s JSON-RPC call failed, treating as retryable connection failure", apiName);
}
// TODO: Sort these values out for backward compatibility
if(response.HasLabel("secManagerResultContext"))
if(rpcResult && response.HasLabel("secManagerResultContext"))
Comment thread
rekhap2kandhavelan marked this conversation as resolved.
Resolved
{
JsonObject resultContext = response["secManagerResultContext"].Object();

Expand Down
Loading