michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsCertVerificationThread.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsProxyRelease.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: nsCertVerificationThread *nsCertVerificationThread::verification_thread_singleton; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCertVerificationResult, nsICertVerificationResult) michael@0: michael@0: namespace { michael@0: class DispatchCertVerificationResult : public nsRunnable michael@0: { michael@0: public: michael@0: DispatchCertVerificationResult(const nsMainThreadPtrHandle& aListener, michael@0: nsIX509Cert3* aCert, michael@0: nsICertVerificationResult* aResult) michael@0: : mListener(aListener) michael@0: , mCert(aCert) michael@0: , mResult(aResult) michael@0: { } michael@0: michael@0: NS_IMETHOD Run() { michael@0: mListener->Notify(mCert, mResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsMainThreadPtrHandle mListener; michael@0: nsCOMPtr mCert; michael@0: nsCOMPtr mResult; michael@0: }; michael@0: } // anonymous namespace michael@0: michael@0: void nsCertVerificationJob::Run() michael@0: { michael@0: if (!mListener || !mCert) michael@0: return; michael@0: michael@0: uint32_t verified; michael@0: uint32_t count; michael@0: char16_t **usages; michael@0: michael@0: nsCOMPtr ires; michael@0: RefPtr vres(new nsCertVerificationResult); michael@0: if (vres) michael@0: { michael@0: nsresult rv = mCert->GetUsagesArray(false, // do not ignore OCSP michael@0: &verified, michael@0: &count, michael@0: &usages); michael@0: vres->mRV = rv; michael@0: if (NS_SUCCEEDED(rv)) michael@0: { michael@0: vres->mVerified = verified; michael@0: vres->mCount = count; michael@0: vres->mUsages = usages; michael@0: } michael@0: michael@0: ires = vres; michael@0: } michael@0: michael@0: nsCOMPtr c3 = do_QueryInterface(mCert); michael@0: nsCOMPtr r = new DispatchCertVerificationResult(mListener, c3, ires); michael@0: NS_DispatchToMainThread(r); michael@0: } michael@0: michael@0: void nsSMimeVerificationJob::Run() michael@0: { michael@0: if (!mMessage || !mListener) michael@0: return; michael@0: michael@0: nsresult rv; michael@0: michael@0: if (digest_data) michael@0: rv = mMessage->VerifyDetachedSignature(digest_data, digest_len); michael@0: else michael@0: rv = mMessage->VerifySignature(); michael@0: michael@0: nsCOMPtr m2 = do_QueryInterface(mMessage); michael@0: mListener->Notify(m2, rv); michael@0: } michael@0: michael@0: nsCertVerificationThread::nsCertVerificationThread() michael@0: : mJobQ(nullptr) michael@0: { michael@0: NS_ASSERTION(!verification_thread_singleton, michael@0: "nsCertVerificationThread is a singleton, caller attempts" michael@0: " to create another instance!"); michael@0: michael@0: verification_thread_singleton = this; michael@0: } michael@0: michael@0: nsCertVerificationThread::~nsCertVerificationThread() michael@0: { michael@0: verification_thread_singleton = nullptr; michael@0: } michael@0: michael@0: nsresult nsCertVerificationThread::addJob(nsBaseVerificationJob *aJob) michael@0: { michael@0: if (!aJob || !verification_thread_singleton) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!verification_thread_singleton->mThreadHandle) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: MutexAutoLock threadLock(verification_thread_singleton->mMutex); michael@0: michael@0: verification_thread_singleton->mJobQ.Push(aJob); michael@0: verification_thread_singleton->mCond.NotifyAll(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsCertVerificationThread::Run(void) michael@0: { michael@0: while (true) { michael@0: michael@0: nsBaseVerificationJob *job = nullptr; michael@0: michael@0: { michael@0: MutexAutoLock threadLock(verification_thread_singleton->mMutex); michael@0: michael@0: while (!exitRequested(threadLock) && michael@0: 0 == verification_thread_singleton->mJobQ.GetSize()) { michael@0: // no work to do ? let's wait a moment michael@0: michael@0: mCond.Wait(); michael@0: } michael@0: michael@0: if (exitRequested(threadLock)) michael@0: break; michael@0: michael@0: job = static_cast(mJobQ.PopFront()); michael@0: } michael@0: michael@0: if (job) michael@0: { michael@0: job->Run(); michael@0: delete job; michael@0: } michael@0: } michael@0: michael@0: { michael@0: MutexAutoLock threadLock(verification_thread_singleton->mMutex); michael@0: michael@0: while (verification_thread_singleton->mJobQ.GetSize()) { michael@0: nsCertVerificationJob *job = michael@0: static_cast(mJobQ.PopFront()); michael@0: delete job; michael@0: } michael@0: postStoppedEventToMainThread(threadLock); michael@0: } michael@0: } michael@0: michael@0: nsCertVerificationResult::nsCertVerificationResult() michael@0: : mRV(NS_OK), michael@0: mVerified(0), michael@0: mCount(0), michael@0: mUsages(0) michael@0: { michael@0: } michael@0: michael@0: nsCertVerificationResult::~nsCertVerificationResult() michael@0: { michael@0: if (mUsages) michael@0: { michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mUsages); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCertVerificationResult::GetUsagesArrayResult(uint32_t *aVerified, michael@0: uint32_t *aCount, michael@0: char16_t ***aUsages) michael@0: { michael@0: if (NS_FAILED(mRV)) michael@0: return mRV; michael@0: michael@0: // transfer ownership michael@0: michael@0: *aVerified = mVerified; michael@0: *aCount = mCount; michael@0: *aUsages = mUsages; michael@0: michael@0: mVerified = 0; michael@0: mCount = 0; michael@0: mUsages = 0; michael@0: michael@0: nsresult rv = mRV; michael@0: michael@0: mRV = NS_ERROR_FAILURE; // this object works only once... michael@0: michael@0: return rv; michael@0: }