1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "pk11func.h"
40 : #include "nsCOMPtr.h"
41 : #include "nsThreadUtils.h"
42 : #include "nsKeygenThread.h"
43 : #include "nsIObserver.h"
44 : #include "nsNSSShutDown.h"
45 : #include "PSMRunnable.h"
46 :
47 : using namespace mozilla;
48 : using namespace mozilla::psm;
49 :
50 0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenThread, nsIKeygenThread)
51 :
52 :
53 0 : nsKeygenThread::nsKeygenThread()
54 : :mutex("nsKeygenThread.mutex"),
55 : iAmRunning(false),
56 : keygenReady(false),
57 : statusDialogClosed(false),
58 : alreadyReceivedParams(false),
59 : privateKey(nsnull),
60 : publicKey(nsnull),
61 : slot(nsnull),
62 : keyGenMechanism(0),
63 : params(nsnull),
64 : isPerm(false),
65 : isSensitive(false),
66 : wincx(nsnull),
67 0 : threadHandle(nsnull)
68 : {
69 0 : }
70 :
71 0 : nsKeygenThread::~nsKeygenThread()
72 : {
73 0 : }
74 :
75 0 : void nsKeygenThread::SetParams(
76 : PK11SlotInfo *a_slot,
77 : PRUint32 a_keyGenMechanism,
78 : void *a_params,
79 : bool a_isPerm,
80 : bool a_isSensitive,
81 : void *a_wincx )
82 : {
83 0 : nsNSSShutDownPreventionLock locker;
84 0 : MutexAutoLock lock(mutex);
85 :
86 0 : if (!alreadyReceivedParams) {
87 0 : alreadyReceivedParams = true;
88 0 : if (a_slot) {
89 0 : slot = PK11_ReferenceSlot(a_slot);
90 : }
91 : else {
92 0 : slot = nsnull;
93 : }
94 0 : keyGenMechanism = a_keyGenMechanism;
95 0 : params = a_params;
96 0 : isPerm = a_isPerm;
97 0 : isSensitive = a_isSensitive;
98 0 : wincx = a_wincx;
99 : }
100 0 : }
101 :
102 0 : nsresult nsKeygenThread::GetParams(
103 : SECKEYPrivateKey **a_privateKey,
104 : SECKEYPublicKey **a_publicKey)
105 : {
106 0 : if (!a_privateKey || !a_publicKey) {
107 0 : return NS_ERROR_FAILURE;
108 : }
109 :
110 : nsresult rv;
111 :
112 0 : MutexAutoLock lock(mutex);
113 :
114 : // GetParams must not be called until thread creator called
115 : // Join on this thread.
116 0 : NS_ASSERTION(keygenReady, "logic error in nsKeygenThread::GetParams");
117 :
118 0 : if (keygenReady) {
119 0 : *a_privateKey = privateKey;
120 0 : *a_publicKey = publicKey;
121 :
122 0 : privateKey = 0;
123 0 : publicKey = 0;
124 :
125 0 : rv = NS_OK;
126 : }
127 : else {
128 0 : rv = NS_ERROR_FAILURE;
129 : }
130 :
131 0 : return rv;
132 : }
133 :
134 0 : static void PR_CALLBACK nsKeygenThreadRunner(void *arg)
135 : {
136 0 : nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
137 0 : self->Run();
138 0 : }
139 :
140 0 : nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
141 : {
142 0 : if (!NS_IsMainThread()) {
143 0 : NS_ERROR("nsKeygenThread::StartKeyGeneration called off the main thread");
144 0 : return NS_ERROR_NOT_SAME_THREAD;
145 : }
146 :
147 0 : if (!aObserver)
148 0 : return NS_OK;
149 :
150 0 : MutexAutoLock lock(mutex);
151 :
152 0 : if (iAmRunning || keygenReady) {
153 0 : return NS_OK;
154 : }
155 :
156 : // We must AddRef aObserver only here on the main thread, because it
157 : // probably does not implement a thread-safe AddRef.
158 0 : mNotifyObserver = new NotifyObserverRunnable(aObserver, "keygen-finished");
159 :
160 0 : iAmRunning = true;
161 :
162 : threadHandle = PR_CreateThread(PR_USER_THREAD, nsKeygenThreadRunner, static_cast<void*>(this),
163 0 : PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
164 :
165 : // bool thread_started_ok = (threadHandle != nsnull);
166 : // we might want to return "thread started ok" to caller in the future
167 0 : NS_ASSERTION(threadHandle, "Could not create nsKeygenThreadRunner thread\n");
168 :
169 0 : return NS_OK;
170 : }
171 :
172 0 : nsresult nsKeygenThread::UserCanceled(bool *threadAlreadyClosedDialog)
173 : {
174 0 : if (!threadAlreadyClosedDialog)
175 0 : return NS_OK;
176 :
177 0 : *threadAlreadyClosedDialog = false;
178 :
179 0 : MutexAutoLock lock(mutex);
180 :
181 0 : if (keygenReady)
182 0 : *threadAlreadyClosedDialog = statusDialogClosed;
183 :
184 : // User somehow closed the dialog, but we will not cancel.
185 : // Bad luck, we told him not do, and user still has to wait.
186 : // However, we remember that it's closed and will not close
187 : // it again to avoid problems.
188 0 : statusDialogClosed = true;
189 :
190 0 : return NS_OK;
191 : }
192 :
193 0 : void nsKeygenThread::Run(void)
194 : {
195 0 : nsNSSShutDownPreventionLock locker;
196 0 : bool canGenerate = false;
197 :
198 : {
199 0 : MutexAutoLock lock(mutex);
200 0 : if (alreadyReceivedParams) {
201 0 : canGenerate = true;
202 0 : keygenReady = false;
203 : }
204 : }
205 :
206 0 : if (canGenerate)
207 : privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism,
208 : params, &publicKey,
209 0 : isPerm, isSensitive, wincx);
210 :
211 : // This call gave us ownership over privateKey and publicKey.
212 : // But as the params structure is owner by our caller,
213 : // we effectively transferred ownership to the caller.
214 : // As long as key generation can't be canceled, we don't need
215 : // to care for cleaning this up.
216 :
217 0 : nsCOMPtr<nsIRunnable> notifyObserver;
218 : {
219 0 : MutexAutoLock lock(mutex);
220 :
221 0 : keygenReady = true;
222 0 : iAmRunning = false;
223 :
224 : // forget our parameters
225 0 : if (slot) {
226 0 : PK11_FreeSlot(slot);
227 0 : slot = 0;
228 : }
229 0 : keyGenMechanism = 0;
230 0 : params = 0;
231 0 : wincx = 0;
232 :
233 0 : if (!statusDialogClosed && mNotifyObserver)
234 0 : notifyObserver = mNotifyObserver;
235 :
236 0 : mNotifyObserver = nsnull;
237 : }
238 :
239 0 : if (notifyObserver) {
240 0 : nsresult rv = NS_DispatchToMainThread(notifyObserver);
241 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
242 : "failed to dispatch keygen thread observer to main thread");
243 : }
244 0 : }
245 :
246 0 : void nsKeygenThread::Join()
247 : {
248 0 : if (!threadHandle)
249 0 : return;
250 :
251 0 : PR_JoinThread(threadHandle);
252 0 : threadHandle = nsnull;
253 :
254 0 : return;
255 : }
|