Back to index

lightning-sunbird  0.9+nobinonly
nsKeygenThread.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "pk11func.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsProxiedService.h"
00042 #include "nsKeygenThread.h"
00043 #include "nsIObserver.h"
00044 #include "nsNSSShutDown.h"
00045 
00046 NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenThread, nsIKeygenThread)
00047 
00048 
00049 nsKeygenThread::nsKeygenThread()
00050 :mutex(nsnull),
00051  iAmRunning(PR_FALSE),
00052  keygenReady(PR_FALSE),
00053  statusDialogClosed(PR_FALSE),
00054  alreadyReceivedParams(PR_FALSE),
00055  privateKey(nsnull),
00056  publicKey(nsnull),
00057  slot(nsnull),
00058  keyGenMechanism(0),
00059  params(nsnull),
00060  isPerm(PR_FALSE),
00061  isSensitive(PR_FALSE),
00062  wincx(nsnull),
00063  threadHandle(nsnull)
00064 {
00065   mutex = PR_NewLock();
00066 }
00067 
00068 nsKeygenThread::~nsKeygenThread()
00069 {
00070   if (mutex) {
00071     PR_DestroyLock(mutex);
00072   }
00073 }
00074 
00075 void nsKeygenThread::SetParams(
00076     PK11SlotInfo *a_slot,
00077     PRUint32 a_keyGenMechanism,
00078     void *a_params,
00079     PRBool a_isPerm,
00080     PRBool a_isSensitive,
00081     void *a_wincx )
00082 {
00083   nsNSSShutDownPreventionLock locker;
00084   PR_Lock(mutex);
00085  
00086     if (!alreadyReceivedParams) {
00087       alreadyReceivedParams = PR_TRUE;
00088       if (a_slot) {
00089         slot = PK11_ReferenceSlot(a_slot);
00090       }
00091       else {
00092         slot = nsnull;
00093       }
00094       keyGenMechanism = a_keyGenMechanism;
00095       params = a_params;
00096       isPerm = a_isPerm;
00097       isSensitive = a_isSensitive;
00098       wincx = a_wincx;
00099     }
00100 
00101   PR_Unlock(mutex);
00102 }
00103 
00104 nsresult nsKeygenThread::GetParams(
00105     SECKEYPrivateKey **a_privateKey,
00106     SECKEYPublicKey **a_publicKey)
00107 {
00108   if (!a_privateKey || !a_publicKey) {
00109     return NS_ERROR_FAILURE;
00110   }
00111 
00112   nsresult rv;
00113   
00114   PR_Lock(mutex);
00115   
00116     // GetParams must not be called until thread creator called
00117     // Join on this thread.
00118     NS_ASSERTION(keygenReady, "logic error in nsKeygenThread::GetParams");
00119 
00120     if (keygenReady) {
00121       *a_privateKey = privateKey;
00122       *a_publicKey = publicKey;
00123 
00124       privateKey = 0;
00125       publicKey = 0;
00126       
00127       rv = NS_OK;
00128     }
00129     else {
00130       rv = NS_ERROR_FAILURE;
00131     }
00132   
00133   PR_Unlock(mutex);
00134   
00135   return rv;
00136 }
00137 
00138 static void PR_CALLBACK nsKeygenThreadRunner(void *arg)
00139 {
00140   nsKeygenThread *self = NS_STATIC_CAST(nsKeygenThread *, arg);
00141   self->Run();
00142 }
00143 
00144 nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
00145 {
00146   if (!mutex)
00147     return NS_OK;
00148 
00149   if (!aObserver)
00150     return NS_OK;
00151 
00152   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00153   if (!proxyman)
00154     return NS_OK;
00155 
00156   nsCOMPtr<nsIObserver> obs;
00157   proxyman->GetProxyForObject( NS_UI_THREAD_EVENTQ,
00158                                NS_GET_IID(nsIObserver),
00159                                aObserver,
00160                                PROXY_SYNC | PROXY_ALWAYS,
00161                                getter_AddRefs(obs));
00162 
00163   PR_Lock(mutex);
00164 
00165     if (iAmRunning || keygenReady) {
00166       PR_Unlock(mutex);
00167       return NS_OK;
00168     }
00169 
00170     observer.swap(obs);
00171 
00172     iAmRunning = PR_TRUE;
00173 
00174     threadHandle = PR_CreateThread(PR_USER_THREAD, nsKeygenThreadRunner, NS_STATIC_CAST(void*, this), 
00175       PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
00176 
00177     // bool thread_started_ok = (threadHandle != nsnull);
00178     // we might want to return "thread started ok" to caller in the future
00179     NS_ASSERTION(threadHandle, "Could not create nsKeygenThreadRunner thread\n");
00180 
00181   PR_Unlock(mutex);
00182   
00183   return NS_OK;
00184 }
00185 
00186 nsresult nsKeygenThread::UserCanceled(PRBool *threadAlreadyClosedDialog)
00187 {
00188   if (!threadAlreadyClosedDialog)
00189     return NS_OK;
00190 
00191   *threadAlreadyClosedDialog = PR_FALSE;
00192 
00193   if (!mutex)
00194     return NS_OK;
00195 
00196   PR_Lock(mutex);
00197   
00198     if (keygenReady)
00199       *threadAlreadyClosedDialog = statusDialogClosed;
00200 
00201     // User somehow closed the dialog, but we will not cancel.
00202     // Bad luck, we told him not do, and user still has to wait.
00203     // However, we remember that it's closed and will not close
00204     // it again to avoid problems.
00205     statusDialogClosed = PR_TRUE;
00206 
00207   PR_Unlock(mutex);
00208 
00209   return NS_OK;
00210 }
00211 
00212 void nsKeygenThread::Run(void)
00213 {
00214   nsNSSShutDownPreventionLock locker;
00215   PRBool canGenerate = PR_FALSE;
00216 
00217   PR_Lock(mutex);
00218 
00219     if (alreadyReceivedParams) {
00220       canGenerate = PR_TRUE;
00221       keygenReady = PR_FALSE;
00222     }
00223 
00224   PR_Unlock(mutex);
00225 
00226   if (canGenerate)
00227     privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism,
00228                                          params, &publicKey,
00229                                          isPerm, isSensitive, wincx);
00230   
00231   // This call gave us ownership over privateKey and publicKey.
00232   // But as the params structure is owner by our caller,
00233   // we effectively transferred ownership to the caller.
00234   // As long as key generation can't be canceled, we don't need 
00235   // to care for cleaning this up.
00236 
00237   nsCOMPtr<nsIObserver> obs;
00238   PR_Lock(mutex);
00239 
00240     keygenReady = PR_TRUE;
00241     iAmRunning = PR_FALSE;
00242 
00243     // forget our parameters
00244     if (slot) {
00245       PK11_FreeSlot(slot);
00246       slot = 0;
00247     }
00248     keyGenMechanism = 0;
00249     params = 0;
00250     wincx = 0;
00251 
00252     if (!statusDialogClosed)
00253       obs = observer;
00254 
00255     observer = nsnull;
00256 
00257   PR_Unlock(mutex);
00258 
00259   if (obs)
00260     obs->Observe(nsnull, "keygen-finished", nsnull);
00261 }
00262 
00263 void nsKeygenThread::Join()
00264 {
00265   if (!threadHandle)
00266     return;
00267   
00268   PR_JoinThread(threadHandle);
00269   threadHandle = nsnull;
00270 
00271   return;
00272 }