summaryrefslogtreecommitdiffstats
path: root/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/gmp-clearkey/0.1/ClearKeyPersistence.cpp')
-rw-r--r--media/gmp-clearkey/0.1/ClearKeyPersistence.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
new file mode 100644
index 000000000..2e14d822e
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClearKeyPersistence.h"
+#include "ClearKeyUtils.h"
+#include "ClearKeyStorage.h"
+#include "ClearKeySessionManager.h"
+#include "RefCounted.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <set>
+#include <vector>
+#include <sstream>
+#include <assert.h>
+
+using namespace std;
+
+// Whether we've loaded the persistent session ids from GMPStorage yet.
+enum PersistentKeyState {
+ UNINITIALIZED,
+ LOADING,
+ LOADED
+};
+static PersistentKeyState sPersistentKeyState = UNINITIALIZED;
+
+// Set of session Ids of the persistent sessions created or residing in
+// storage.
+static set<uint32_t> sPersistentSessionIds;
+
+static vector<GMPTask*> sTasksBlockedOnSessionIdLoad;
+
+static void
+ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator,
+ void* aUserArg,
+ GMPErr aStatus)
+{
+ assert(sPersistentKeyState == LOADING);
+ if (GMP_SUCCEEDED(aStatus)) {
+ // Extract the record names which are valid uint32_t's; they're
+ // the persistent session ids.
+ const char* name = nullptr;
+ uint32_t len = 0;
+ while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
+ if (ClearKeyUtils::IsValidSessionId(name, len)) {
+ assert(name[len] == 0);
+ sPersistentSessionIds.insert(atoi(name));
+ }
+ aRecordIterator->NextRecord();
+ }
+ }
+ sPersistentKeyState = LOADED;
+ aRecordIterator->Close();
+
+ for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) {
+ sTasksBlockedOnSessionIdLoad[i]->Run();
+ sTasksBlockedOnSessionIdLoad[i]->Destroy();
+ }
+ sTasksBlockedOnSessionIdLoad.clear();
+}
+
+/* static */ void
+ClearKeyPersistence::EnsureInitialized()
+{
+ if (sPersistentKeyState == UNINITIALIZED) {
+ sPersistentKeyState = LOADING;
+ if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) {
+ sPersistentKeyState = LOADED;
+ }
+ }
+}
+
+/* static */ string
+ClearKeyPersistence::GetNewSessionId(GMPSessionType aSessionType)
+{
+ static uint32_t sNextSessionId = 1;
+
+ // Ensure we don't re-use a session id that was persisted.
+ while (Contains(sPersistentSessionIds, sNextSessionId)) {
+ sNextSessionId++;
+ }
+
+ string sessionId;
+ stringstream ss;
+ ss << sNextSessionId;
+ ss >> sessionId;
+
+ if (aSessionType == kGMPPersistentSession) {
+ sPersistentSessionIds.insert(sNextSessionId);
+ }
+
+ sNextSessionId++;
+
+ return sessionId;
+}
+
+
+class CreateSessionTask : public GMPTask {
+public:
+ CreateSessionTask(ClearKeySessionManager* aTarget,
+ uint32_t aCreateSessionToken,
+ uint32_t aPromiseId,
+ const string& aInitDataType,
+ const uint8_t* aInitData,
+ uint32_t aInitDataSize,
+ GMPSessionType aSessionType)
+ : mTarget(aTarget)
+ , mCreateSessionToken(aCreateSessionToken)
+ , mPromiseId(aPromiseId)
+ , mInitDataType(aInitDataType)
+ , mSessionType(aSessionType)
+ {
+ mInitData.insert(mInitData.end(),
+ aInitData,
+ aInitData + aInitDataSize);
+ }
+ virtual void Run() override {
+ mTarget->CreateSession(mCreateSessionToken,
+ mPromiseId,
+ mInitDataType.c_str(),
+ mInitDataType.size(),
+ &mInitData.front(),
+ mInitData.size(),
+ mSessionType);
+ }
+ virtual void Destroy() override {
+ delete this;
+ }
+private:
+ RefPtr<ClearKeySessionManager> mTarget;
+ uint32_t mCreateSessionToken;
+ uint32_t mPromiseId;
+ const string mInitDataType;
+ vector<uint8_t> mInitData;
+ GMPSessionType mSessionType;
+};
+
+
+/* static */ bool
+ClearKeyPersistence::DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
+ uint32_t aCreateSessionToken,
+ uint32_t aPromiseId,
+ const string& aInitDataType,
+ const uint8_t* aInitData,
+ uint32_t aInitDataSize,
+ GMPSessionType aSessionType)
+{
+ if (sPersistentKeyState >= LOADED) {
+ return false;
+ }
+ GMPTask* t = new CreateSessionTask(aInstance,
+ aCreateSessionToken,
+ aPromiseId,
+ aInitDataType,
+ aInitData,
+ aInitDataSize,
+ aSessionType);
+ sTasksBlockedOnSessionIdLoad.push_back(t);
+ return true;
+}
+
+class LoadSessionTask : public GMPTask {
+public:
+ LoadSessionTask(ClearKeySessionManager* aTarget,
+ uint32_t aPromiseId,
+ const char* aSessionId,
+ uint32_t aSessionIdLength)
+ : mTarget(aTarget)
+ , mPromiseId(aPromiseId)
+ , mSessionId(aSessionId, aSessionId + aSessionIdLength)
+ {
+ }
+ virtual void Run() override {
+ mTarget->LoadSession(mPromiseId,
+ mSessionId.c_str(),
+ mSessionId.size());
+ }
+ virtual void Destroy() override {
+ delete this;
+ }
+private:
+ RefPtr<ClearKeySessionManager> mTarget;
+ uint32_t mPromiseId;
+ string mSessionId;
+};
+
+/* static */ bool
+ClearKeyPersistence::DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
+ uint32_t aPromiseId,
+ const char* aSessionId,
+ uint32_t aSessionIdLength)
+{
+ if (sPersistentKeyState >= LOADED) {
+ return false;
+ }
+ GMPTask* t = new LoadSessionTask(aInstance,
+ aPromiseId,
+ aSessionId,
+ aSessionIdLength);
+ sTasksBlockedOnSessionIdLoad.push_back(t);
+ return true;
+}
+
+/* static */ bool
+ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId)
+{
+ return Contains(sPersistentSessionIds, atoi(aSessionId.c_str()));
+}
+
+class LoadSessionFromKeysTask : public ReadContinuation {
+public:
+ LoadSessionFromKeysTask(ClearKeySessionManager* aTarget,
+ const string& aSessionId,
+ uint32_t aPromiseId)
+ : mTarget(aTarget)
+ , mSessionId(aSessionId)
+ , mPromiseId(aPromiseId)
+ {
+ }
+
+ virtual void ReadComplete(GMPErr aStatus,
+ const uint8_t* aData,
+ uint32_t aLength) override
+ {
+ mTarget->PersistentSessionDataLoaded(aStatus, mPromiseId, mSessionId, aData, aLength);
+ }
+private:
+ RefPtr<ClearKeySessionManager> mTarget;
+ string mSessionId;
+ uint32_t mPromiseId;
+};
+
+/* static */ void
+ClearKeyPersistence::LoadSessionData(ClearKeySessionManager* aInstance,
+ const string& aSid,
+ uint32_t aPromiseId)
+{
+ LoadSessionFromKeysTask* loadTask =
+ new LoadSessionFromKeysTask(aInstance, aSid, aPromiseId);
+ ReadData(aSid, loadTask);
+}
+
+/* static */ void
+ClearKeyPersistence::PersistentSessionRemoved(const string& aSessionId)
+{
+ sPersistentSessionIds.erase(atoi(aSessionId.c_str()));
+}