Bug 452390 Tracemonkey will crash if the compiler doesn't have FASTCALL r=danderson
[wine-gecko.git] / security / manager / ssl / src / nsSSLThread.cpp
blob8c5ccc3aa8905bf2820e2745cbde13d88a7ad26b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is mozilla.org code.
16 * The Initial Developer of the Original Code is
17 * Red Hat, Inc.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Kai Engert <kengert@redhat.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsThreadUtils.h"
39 #include "nsSSLThread.h"
40 #include "nsAutoLock.h"
41 #include "nsNSSIOLayer.h"
43 #include "ssl.h"
45 #ifdef PR_LOGGING
46 extern PRLogModuleInfo* gPIPNSSLog;
47 #endif
49 nsSSLThread::nsSSLThread()
50 : mBusySocket(nsnull),
51 mSocketScheduledToBeDestroyed(nsnull)
53 NS_ASSERTION(!ssl_thread_singleton, "nsSSLThread is a singleton, caller attempts to create another instance!");
55 ssl_thread_singleton = this;
58 nsSSLThread::~nsSSLThread()
60 ssl_thread_singleton = nsnull;
63 PRFileDesc *nsSSLThread::getRealSSLFD(nsNSSSocketInfo *si)
65 if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
66 return nsnull;
68 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
70 if (si->mThreadData->mReplacedSSLFileDesc)
72 return si->mThreadData->mReplacedSSLFileDesc;
74 else
76 return si->mFd->lower;
80 PRStatus nsSSLThread::requestGetsockname(nsNSSSocketInfo *si, PRNetAddr *addr)
82 PRFileDesc *fd = getRealSSLFD(si);
83 if (!fd)
84 return PR_FAILURE;
86 return fd->methods->getsockname(fd, addr);
89 PRStatus nsSSLThread::requestGetpeername(nsNSSSocketInfo *si, PRNetAddr *addr)
91 PRFileDesc *fd = getRealSSLFD(si);
92 if (!fd)
93 return PR_FAILURE;
95 return fd->methods->getpeername(fd, addr);
98 PRStatus nsSSLThread::requestGetsocketoption(nsNSSSocketInfo *si,
99 PRSocketOptionData *data)
101 PRFileDesc *fd = getRealSSLFD(si);
102 if (!fd)
103 return PR_FAILURE;
105 return fd->methods->getsocketoption(fd, data);
108 PRStatus nsSSLThread::requestSetsocketoption(nsNSSSocketInfo *si,
109 const PRSocketOptionData *data)
111 PRFileDesc *fd = getRealSSLFD(si);
112 if (!fd)
113 return PR_FAILURE;
115 return fd->methods->setsocketoption(fd, data);
118 PRStatus nsSSLThread::requestConnectcontinue(nsNSSSocketInfo *si,
119 PRInt16 out_flags)
121 PRFileDesc *fd = getRealSSLFD(si);
122 if (!fd)
123 return PR_FAILURE;
125 return fd->methods->connectcontinue(fd, out_flags);
128 PRInt32 nsSSLThread::requestRecvMsgPeek(nsNSSSocketInfo *si, void *buf, PRInt32 amount,
129 PRIntn flags, PRIntervalTime timeout)
131 if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
133 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
134 return -1;
137 PRFileDesc *realSSLFD;
140 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
142 if (si == ssl_thread_singleton->mBusySocket)
144 PORT_SetError(PR_WOULD_BLOCK_ERROR);
145 return -1;
148 switch (si->mThreadData->mSSLState)
150 case nsSSLSocketThreadData::ssl_idle:
151 break;
153 case nsSSLSocketThreadData::ssl_reading_done:
155 // we have data available that we can return
157 // if there was a failure, just return the failure,
158 // but do not yet clear our state, that should happen
159 // in the call to "read".
161 if (si->mThreadData->mSSLResultRemainingBytes < 0) {
162 if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
163 PR_SetError(si->mThreadData->mPRErrorCode, 0);
166 return si->mThreadData->mSSLResultRemainingBytes;
169 PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
171 memcpy(buf, si->mThreadData->mSSLRemainingReadResultData, return_amount);
173 return return_amount;
176 case nsSSLSocketThreadData::ssl_writing_done:
177 case nsSSLSocketThreadData::ssl_pending_write:
178 case nsSSLSocketThreadData::ssl_pending_read:
180 // for safety reasons, also return would_block on any other state,
181 // although this switch statement should be complete and list
182 // the appropriate behaviour for each state.
183 default:
185 PORT_SetError(PR_WOULD_BLOCK_ERROR);
186 return -1;
190 if (si->mThreadData->mReplacedSSLFileDesc)
192 realSSLFD = si->mThreadData->mReplacedSSLFileDesc;
194 else
196 realSSLFD = si->mFd->lower;
200 return realSSLFD->methods->recv(realSSLFD, buf, amount, flags, timeout);
203 nsresult nsSSLThread::requestActivateSSL(nsNSSSocketInfo *si)
205 PRFileDesc *fd = getRealSSLFD(si);
206 if (!fd)
207 return NS_ERROR_FAILURE;
209 if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, PR_TRUE))
210 return NS_ERROR_FAILURE;
212 if (SECSuccess != SSL_ResetHandshake(fd, PR_FALSE))
213 return NS_ERROR_FAILURE;
215 return NS_OK;
218 PRInt16 nsSSLThread::requestPoll(nsNSSSocketInfo *si, PRInt16 in_flags, PRInt16 *out_flags)
220 if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
221 return 0;
223 *out_flags = 0;
225 PRBool want_sleep_and_wakeup_on_any_socket_activity = PR_FALSE;
226 PRBool handshake_timeout = PR_FALSE;
229 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
231 if (ssl_thread_singleton->mBusySocket)
233 // If there is currently any socket busy on the SSL thread,
234 // use our own poll method implementation.
236 switch (si->mThreadData->mSSLState)
238 case nsSSLSocketThreadData::ssl_writing_done:
240 if (in_flags & PR_POLL_WRITE)
242 *out_flags |= PR_POLL_WRITE;
245 return in_flags;
247 break;
249 case nsSSLSocketThreadData::ssl_reading_done:
251 if (in_flags & PR_POLL_READ)
253 *out_flags |= PR_POLL_READ;
256 return in_flags;
258 break;
260 case nsSSLSocketThreadData::ssl_pending_write:
261 case nsSSLSocketThreadData::ssl_pending_read:
263 if (si == ssl_thread_singleton->mBusySocket)
265 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
267 // The lower layer of the socket is currently the pollable event,
268 // which signals the readable state.
270 return PR_POLL_READ;
272 else
274 // Unfortunately we do not have a pollable event
275 // that we could use to wake up the caller, as soon
276 // as the previously requested I/O operation has completed.
277 // Therefore we must use a kind of busy wait,
278 // we want the caller to check again, whenever any
279 // activity is detected on the associated socket.
280 // Unfortunately this could mean, the caller will detect
281 // activity very often, until we are finally done with
282 // the previously requested action and are able to
283 // return the buffered result.
284 // As our real I/O activity is happening on the other thread
285 // let's sleep some cycles, in order to not waste all CPU
286 // resources.
287 // But let's make sure we do not hold our shared mutex
288 // while waiting, so let's leave this block first.
290 want_sleep_and_wakeup_on_any_socket_activity = PR_TRUE;
291 break;
294 else
296 // We should never get here, well, at least not with the current
297 // implementation of SSL thread, where we have one worker only.
298 // While another socket is busy, this socket "si"
299 // can not be marked with pending I/O at the same time.
301 NS_NOTREACHED("Socket not busy on SSL thread marked as pending");
302 return 0;
305 break;
307 case nsSSLSocketThreadData::ssl_idle:
309 if (si->mThreadData->mOneBytePendingFromEarlierWrite)
311 if (in_flags & PR_POLL_WRITE)
313 // In this scenario we always want the caller to immediately
314 // try a write again, because it might not wake up otherwise.
315 *out_flags |= PR_POLL_WRITE;
316 return in_flags;
320 handshake_timeout = si->HandshakeTimeout();
322 if (si != ssl_thread_singleton->mBusySocket)
324 // Some other socket is currently busy on the SSL thread.
325 // It is possible that busy socket is currently blocked (e.g. by UI).
326 // Therefore we should not report "si" as being readable/writeable,
327 // regardless whether it is.
328 // (Because if we did report readable/writeable to the caller,
329 // the caller would repeatedly request us to do I/O,
330 // although our read/write function would not be able to fulfil
331 // the request, because our single worker is blocked).
332 // To avoid the unnecessary busy loop in that scenario,
333 // for socket "si" we report "not ready" to the caller.
334 // We do this by faking our caller did not ask for neither
335 // readable nor writeable when querying the lower layer.
336 // (this will leave querying for exceptions enabled)
338 in_flags &= ~(PR_POLL_READ | PR_POLL_WRITE);
341 break;
343 default:
344 break;
347 else
349 handshake_timeout = si->HandshakeTimeout();
352 if (handshake_timeout)
354 NS_ASSERTION(in_flags & PR_POLL_EXCEPT, "nsSSLThread::requestPoll handshake timeout, but caller did not poll for EXCEPT");
356 *out_flags |= PR_POLL_EXCEPT;
357 return in_flags;
361 if (want_sleep_and_wakeup_on_any_socket_activity)
363 // This is where we wait for any socket activity,
364 // because we do not have a pollable event.
365 // XXX Will this really cause us to wake up
366 // whatever happens?
368 PR_Sleep( PR_MillisecondsToInterval(1) );
369 return PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
372 return si->mFd->lower->methods->poll(si->mFd->lower, in_flags, out_flags);
375 PRStatus nsSSLThread::requestClose(nsNSSSocketInfo *si)
377 if (!ssl_thread_singleton || !si)
378 return PR_FAILURE;
380 PRBool close_later = PR_FALSE;
381 nsCOMPtr<nsIRequest> requestToCancel;
384 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
386 if (ssl_thread_singleton->mBusySocket == si) {
388 // That's tricky, SSL thread is currently busy with this socket,
389 // and might even be blocked on it (UI or OCSP).
390 // We should not close the socket directly, but rather
391 // schedule closing it, at the time the SSL thread is done.
392 // If there is indeed a depending OCSP request pending,
393 // we should cancel it now.
395 if (ssl_thread_singleton->mPendingHTTPRequest)
397 requestToCancel.swap(ssl_thread_singleton->mPendingHTTPRequest);
400 close_later = PR_TRUE;
401 ssl_thread_singleton->mSocketScheduledToBeDestroyed = si;
403 PR_NotifyAllCondVar(ssl_thread_singleton->mCond);
407 if (requestToCancel)
409 if (NS_IsMainThread())
411 requestToCancel->Cancel(NS_ERROR_ABORT);
413 else
415 NS_WARNING("Attempt to close SSL socket from a thread that is not the main thread. Can not cancel pending HTTP request from NSS");
418 requestToCancel = nsnull;
421 if (!close_later)
423 return si->CloseSocketAndDestroy();
426 return PR_SUCCESS;
429 void nsSSLThread::restoreOriginalSocket_locked(nsNSSSocketInfo *si)
431 if (si->mThreadData->mReplacedSSLFileDesc)
433 if (nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
435 nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
436 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
438 PR_WaitForPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
442 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
444 // need to restore
445 si->mFd->lower = si->mThreadData->mReplacedSSLFileDesc;
446 si->mThreadData->mReplacedSSLFileDesc = nsnull;
449 nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
453 PRStatus nsSSLThread::getRealFDIfBlockingSocket_locked(nsNSSSocketInfo *si,
454 PRFileDesc *&out_fd)
456 out_fd = nsnull;
458 PRFileDesc *realFD =
459 (si->mThreadData->mReplacedSSLFileDesc) ?
460 si->mThreadData->mReplacedSSLFileDesc : si->mFd->lower;
462 if (si->mBlockingState == nsNSSSocketInfo::blocking_state_unknown)
464 PRSocketOptionData sod;
465 sod.option = PR_SockOpt_Nonblocking;
466 if (PR_GetSocketOption(realFD, &sod) == PR_FAILURE)
467 return PR_FAILURE;
469 si->mBlockingState = sod.value.non_blocking ?
470 nsNSSSocketInfo::is_nonblocking_socket : nsNSSSocketInfo::is_blocking_socket;
473 if (si->mBlockingState == nsNSSSocketInfo::is_blocking_socket)
475 out_fd = realFD;
478 return PR_SUCCESS;
481 PRInt32 nsSSLThread::requestRead(nsNSSSocketInfo *si, void *buf, PRInt32 amount,
482 PRIntervalTime timeout)
484 if (!ssl_thread_singleton || !si || !buf || !amount || !ssl_thread_singleton->mThreadHandle)
486 PR_SetError(PR_UNKNOWN_ERROR, 0);
487 return -1;
490 PRBool this_socket_is_busy = PR_FALSE;
491 PRBool some_other_socket_is_busy = PR_FALSE;
492 nsSSLSocketThreadData::ssl_state my_ssl_state = nsSSLSocketThreadData::ssl_invalid;
493 PRFileDesc *blockingFD = nsnull;
496 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
498 if (ssl_thread_singleton->mExitRequested) {
499 PR_SetError(PR_UNKNOWN_ERROR, 0);
500 return -1;
503 if (getRealFDIfBlockingSocket_locked(si, blockingFD) == PR_FAILURE) {
504 return -1;
507 if (!blockingFD)
509 my_ssl_state = si->mThreadData->mSSLState;
511 if (ssl_thread_singleton->mBusySocket == si)
513 this_socket_is_busy = PR_TRUE;
515 if (my_ssl_state == nsSSLSocketThreadData::ssl_reading_done)
517 // we will now care for the data that's ready,
518 // the socket is no longer busy on the ssl thread
520 restoreOriginalSocket_locked(si);
522 ssl_thread_singleton->mBusySocket = nsnull;
524 // We'll handle the results further down,
525 // while not holding the lock.
528 else if (ssl_thread_singleton->mBusySocket)
530 some_other_socket_is_busy = PR_TRUE;
533 if (!this_socket_is_busy && si->HandshakeTimeout())
535 restoreOriginalSocket_locked(si);
536 PR_SetError(PR_CONNECT_RESET_ERROR, 0);
537 checkHandshake(-1, PR_TRUE, si->mFd->lower, si);
538 return -1;
541 // leave this mutex protected scope before the blockingFD handling
544 if (blockingFD)
546 // this is an exception, we do not use our SSL thread at all,
547 // just pass the call through to libssl.
548 return blockingFD->methods->recv(blockingFD, buf, amount, 0, timeout);
551 switch (my_ssl_state)
553 case nsSSLSocketThreadData::ssl_idle:
555 NS_ASSERTION(!this_socket_is_busy, "oops, unexpected incosistency");
557 if (some_other_socket_is_busy)
559 PORT_SetError(PR_WOULD_BLOCK_ERROR);
560 return -1;
563 // ssl thread is not busy, we'll continue below
565 break;
567 case nsSSLSocketThreadData::ssl_reading_done:
568 // there has been a previous request to read, that is now done!
570 // failure ?
571 if (si->mThreadData->mSSLResultRemainingBytes < 0) {
572 if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
573 PR_SetError(si->mThreadData->mPRErrorCode, 0);
574 si->mThreadData->mPRErrorCode = PR_SUCCESS;
577 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
578 return si->mThreadData->mSSLResultRemainingBytes;
581 PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
583 memcpy(buf, si->mThreadData->mSSLRemainingReadResultData, return_amount);
585 si->mThreadData->mSSLResultRemainingBytes -= return_amount;
587 if (!si->mThreadData->mSSLResultRemainingBytes) {
588 si->mThreadData->mSSLRemainingReadResultData = nsnull;
589 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
591 else {
592 si->mThreadData->mSSLRemainingReadResultData += return_amount;
595 return return_amount;
597 // we never arrive here, see return statement above
598 break;
601 // We should not see the following events here,
602 // because we have not yet signaled Necko that we are
603 // readable/writable again, so if we end up here,
604 // it means that Necko decided to try read/write again,
605 // for whatever reason. No problem, just return would_block,
606 case nsSSLSocketThreadData::ssl_pending_write:
607 case nsSSLSocketThreadData::ssl_pending_read:
609 // We should not see this state here, because Necko has previously
610 // requested us to write, Necko is not yet aware that it's done,
611 // (although it meanwhile is), but Necko now tries to read?
612 // If that ever happens, it's confusing, but not a problem,
613 // just let Necko know we can not do that now and return would_block.
614 case nsSSLSocketThreadData::ssl_writing_done:
616 // for safety reasons, also return would_block on any other state,
617 // although this switch statement should be complete and list
618 // the appropriate behaviour for each state.
619 default:
621 PORT_SetError(PR_WOULD_BLOCK_ERROR);
622 return -1;
624 // we never arrive here, see return statement above
625 break;
628 if (si->isPK11LoggedOut() || si->isAlreadyShutDown()) {
629 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
630 return -1;
633 if (si->GetCanceled()) {
634 return PR_FAILURE;
637 // si is idle and good, and no other socket is currently busy,
638 // so it's fine to continue with the request.
640 if (!si->mThreadData->ensure_buffer_size(amount))
642 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
643 return -1;
646 si->mThreadData->mSSLRequestedTransferAmount = amount;
647 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_pending_read;
649 // Remember we are operating on a layered file descriptor, that consists of
650 // a PSM code layer (nsNSSIOLayer), a NSS code layer (SSL protocol logic),
651 // and the raw socket at the bottommost layer.
653 // We don't want to call the SSL layer read/write directly on this thread,
654 // because it might block, should a callback to UI (for user confirmation)
655 // or Necko (for retrieving OCSP verification data) be necessary.
656 // As Necko is single threaded, it is currently waiting for this
657 // function to return, and a callback into Necko from NSS couldn't succeed.
659 // Therefore we must defer the request to read/write to a separate SSL thread.
660 // We will return WOULD_BLOCK to Necko, and will return the real results
661 // once the I/O operation on the SSL thread is ready.
663 // The tricky part is to wake up Necko, as soon as the I/O operation
664 // on the SSL thread is done.
666 // In order to achieve that, we manipulate the layering of the file
667 // descriptor. Usually the PSM layer points to the SSL layer as its lower
668 // layer. We change that to a pollable event file descriptor.
670 // Once we return from this original read/write function, Necko will
671 // poll/select on the file descriptor. As result data is not yet ready, we will
672 // instruct Necko to select on the bottommost file descriptor
673 // (by using appropriate flags in PSM's layer implementation of the
674 // poll method), which is the pollable event.
676 // Once the SSL thread is done with the call to the SSL layer, it will
677 // "set" the pollable event, causing Necko to wake up on the file descriptor
678 // and call read/write again. Now that the file descriptor is in the done state,
679 // we'll arrive in this read/write function again. We'll detect the socket is
680 // in the done state, and restore the original SSL level file descriptor.
681 // Finally, we return the data obtained on the SSL thread back to our caller.
684 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
686 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
688 NS_ASSERTION(!nsSSLIOLayerHelpers::mSocketOwningPollableEvent,
689 "oops, some other socket still owns our shared pollable event");
691 NS_ASSERTION(!si->mThreadData->mReplacedSSLFileDesc, "oops");
693 si->mThreadData->mReplacedSSLFileDesc = si->mFd->lower;
694 si->mFd->lower = nsSSLIOLayerHelpers::mSharedPollableEvent;
697 nsSSLIOLayerHelpers::mSocketOwningPollableEvent = si;
698 ssl_thread_singleton->mBusySocket = si;
700 // notify the thread
701 PR_NotifyAllCondVar(ssl_thread_singleton->mCond);
704 PORT_SetError(PR_WOULD_BLOCK_ERROR);
705 return -1;
708 PRInt32 nsSSLThread::requestWrite(nsNSSSocketInfo *si, const void *buf, PRInt32 amount,
709 PRIntervalTime timeout)
711 if (!ssl_thread_singleton || !si || !buf || !amount || !ssl_thread_singleton->mThreadHandle)
713 PR_SetError(PR_UNKNOWN_ERROR, 0);
714 return -1;
717 PRBool this_socket_is_busy = PR_FALSE;
718 PRBool some_other_socket_is_busy = PR_FALSE;
719 nsSSLSocketThreadData::ssl_state my_ssl_state = nsSSLSocketThreadData::ssl_invalid;
720 PRFileDesc *blockingFD = nsnull;
723 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
725 if (ssl_thread_singleton->mExitRequested) {
726 PR_SetError(PR_UNKNOWN_ERROR, 0);
727 return -1;
730 if (getRealFDIfBlockingSocket_locked(si, blockingFD) == PR_FAILURE) {
731 return -1;
734 if (!blockingFD)
736 my_ssl_state = si->mThreadData->mSSLState;
738 if (ssl_thread_singleton->mBusySocket == si)
740 this_socket_is_busy = PR_TRUE;
742 if (my_ssl_state == nsSSLSocketThreadData::ssl_writing_done)
744 // we will now care for the data that's ready,
745 // the socket is no longer busy on the ssl thread
747 restoreOriginalSocket_locked(si);
749 ssl_thread_singleton->mBusySocket = nsnull;
751 // We'll handle the results further down,
752 // while not holding the lock.
755 else if (ssl_thread_singleton->mBusySocket)
757 some_other_socket_is_busy = PR_TRUE;
760 if (!this_socket_is_busy && si->HandshakeTimeout())
762 restoreOriginalSocket_locked(si);
763 PR_SetError(PR_CONNECT_RESET_ERROR, 0);
764 checkHandshake(-1, PR_FALSE, si->mFd->lower, si);
765 return -1;
768 // leave this mutex protected scope before the blockingFD handling
771 if (blockingFD)
773 // this is an exception, we do not use our SSL thread at all,
774 // just pass the call through to libssl.
775 return blockingFD->methods->send(blockingFD, buf, amount, 0, timeout);
778 switch (my_ssl_state)
780 case nsSSLSocketThreadData::ssl_idle:
782 NS_ASSERTION(!this_socket_is_busy, "oops, unexpected incosistency");
784 if (some_other_socket_is_busy)
786 PORT_SetError(PR_WOULD_BLOCK_ERROR);
787 return -1;
790 // ssl thread is not busy, we'll continue below
792 break;
794 case nsSSLSocketThreadData::ssl_writing_done:
795 // there has been a previous request to write, that is now done!
797 // failure ?
798 if (si->mThreadData->mSSLResultRemainingBytes < 0) {
799 if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
800 PR_SetError(si->mThreadData->mPRErrorCode, 0);
801 si->mThreadData->mPRErrorCode = PR_SUCCESS;
804 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
805 return si->mThreadData->mSSLResultRemainingBytes;
808 PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
810 si->mThreadData->mSSLResultRemainingBytes -= return_amount;
812 if (!si->mThreadData->mSSLResultRemainingBytes) {
813 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
816 return return_amount;
818 break;
820 // We should not see the following events here,
821 // because we have not yet signaled Necko that we are
822 // readable/writable again, so if we end up here,
823 // it means that Necko decided to try read/write again,
824 // for whatever reason. No problem, just return would_block,
825 case nsSSLSocketThreadData::ssl_pending_write:
826 case nsSSLSocketThreadData::ssl_pending_read:
828 // We should not see this state here, because Necko has previously
829 // requested us to read, Necko is not yet aware that it's done,
830 // (although it meanwhile is), but Necko now tries to write?
831 // If that ever happens, it's confusing, but not a problem,
832 // just let Necko know we can not do that now and return would_block.
833 case nsSSLSocketThreadData::ssl_reading_done:
835 // for safety reasons, also return would_block on any other state,
836 // although this switch statement should be complete and list
837 // the appropriate behaviour for each state.
838 default:
840 PORT_SetError(PR_WOULD_BLOCK_ERROR);
841 return -1;
843 // we never arrive here, see return statement above
844 break;
847 if (si->isPK11LoggedOut() || si->isAlreadyShutDown()) {
848 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
849 return -1;
852 if (si->GetCanceled()) {
853 return PR_FAILURE;
856 // si is idle and good, and no other socket is currently busy,
857 // so it's fine to continue with the request.
859 // However, use special handling for the
860 // mOneBytePendingFromEarlierWrite
861 // scenario, where we will not change any of our buffers at this point,
862 // as we are waiting for completion of the earlier write.
864 if (!si->mThreadData->mOneBytePendingFromEarlierWrite)
866 if (!si->mThreadData->ensure_buffer_size(amount))
868 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
869 return -1;
872 memcpy(si->mThreadData->mSSLDataBuffer, buf, amount);
873 si->mThreadData->mSSLRequestedTransferAmount = amount;
876 si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_pending_write;
879 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
881 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
883 NS_ASSERTION(!nsSSLIOLayerHelpers::mSocketOwningPollableEvent,
884 "oops, some other socket still owns our shared pollable event");
886 NS_ASSERTION(!si->mThreadData->mReplacedSSLFileDesc, "oops");
888 si->mThreadData->mReplacedSSLFileDesc = si->mFd->lower;
889 si->mFd->lower = nsSSLIOLayerHelpers::mSharedPollableEvent;
892 nsSSLIOLayerHelpers::mSocketOwningPollableEvent = si;
893 ssl_thread_singleton->mBusySocket = si;
895 PR_NotifyAllCondVar(ssl_thread_singleton->mCond);
898 PORT_SetError(PR_WOULD_BLOCK_ERROR);
899 return -1;
902 void nsSSLThread::Run(void)
904 // Helper variable, we don't want to call destroy
905 // while holding the mutex.
906 nsNSSSocketInfo *socketToDestroy = nsnull;
908 while (PR_TRUE)
910 if (socketToDestroy)
912 socketToDestroy->CloseSocketAndDestroy();
913 socketToDestroy = nsnull;
916 // remember whether we'll write or read
917 nsSSLSocketThreadData::ssl_state busy_socket_ssl_state;
920 // In this scope we need mutex protection,
921 // as we find out what needs to be done.
923 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
925 if (mSocketScheduledToBeDestroyed)
927 if (mBusySocket == mSocketScheduledToBeDestroyed)
929 // That's rare, but it happens.
930 // We have received a request to close the socket,
931 // although I/O results have not yet been consumed.
933 restoreOriginalSocket_locked(mBusySocket);
935 mBusySocket->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
936 mBusySocket = nsnull;
939 socketToDestroy = mSocketScheduledToBeDestroyed;
940 mSocketScheduledToBeDestroyed = nsnull;
941 continue; // go back and finally destroy it, before doing anything else
944 if (mExitRequested)
945 break;
947 PRBool pending_work = PR_FALSE;
951 if (mBusySocket
953 (mBusySocket->mThreadData->mSSLState == nsSSLSocketThreadData::ssl_pending_read
955 mBusySocket->mThreadData->mSSLState == nsSSLSocketThreadData::ssl_pending_write))
957 pending_work = PR_TRUE;
960 if (!pending_work)
962 // no work to do ? let's wait a moment
964 PR_WaitCondVar(mCond, PR_INTERVAL_NO_TIMEOUT);
967 } while (!pending_work && !mExitRequested && !mSocketScheduledToBeDestroyed);
969 if (mSocketScheduledToBeDestroyed)
970 continue;
972 if (mExitRequested)
973 break;
975 if (!pending_work)
976 continue;
978 busy_socket_ssl_state = mBusySocket->mThreadData->mSSLState;
982 // In this scope we need to make sure NSS does not go away
983 // while we are busy.
984 nsNSSShutDownPreventionLock locker;
986 // Reference for shorter code and to avoid multiple dereferencing.
987 nsSSLSocketThreadData &bstd = *mBusySocket->mThreadData;
989 PRFileDesc *realFileDesc = bstd.mReplacedSSLFileDesc;
990 if (!realFileDesc)
992 realFileDesc = mBusySocket->mFd->lower;
995 if (nsSSLSocketThreadData::ssl_pending_write == busy_socket_ssl_state)
997 PRInt32 bytesWritten = 0;
999 if (bstd.mOneBytePendingFromEarlierWrite)
1001 // Let's try to flush the final pending byte (that libSSL might already have
1002 // processed). Let's be correct and send the final byte from our buffer.
1003 bytesWritten = realFileDesc->methods
1004 ->write(realFileDesc, &bstd.mThePendingByte, 1);
1006 #ifdef DEBUG_SSL_VERBOSE
1007 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n", (void*)realFileDesc, bytesWritten));
1008 #endif
1010 bytesWritten = checkHandshake(bytesWritten, PR_FALSE, realFileDesc, mBusySocket);
1011 if (bytesWritten < 0) {
1012 // give the error back to caller
1013 bstd.mPRErrorCode = PR_GetError();
1015 else if (bytesWritten == 1) {
1016 // Cool, all flushed now. We can exit the one-byte-pending mode,
1017 // and report the full amount back to the caller.
1018 bytesWritten = bstd.mOriginalRequestedTransferAmount;
1019 bstd.mOriginalRequestedTransferAmount = 0;
1020 bstd.mOneBytePendingFromEarlierWrite = PR_FALSE;
1023 else
1025 // standard code, try to write the buffer we've been given just now
1026 bytesWritten = realFileDesc->methods
1027 ->write(realFileDesc,
1028 bstd.mSSLDataBuffer,
1029 bstd.mSSLRequestedTransferAmount);
1031 #ifdef DEBUG_SSL_VERBOSE
1032 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes (out of %d)\n",
1033 (void*)realFileDesc, bytesWritten, bstd.mSSLRequestedTransferAmount));
1034 #endif
1036 bytesWritten = checkHandshake(bytesWritten, PR_FALSE, realFileDesc, mBusySocket);
1037 if (bytesWritten < 0) {
1038 // give the error back to caller
1039 bstd.mPRErrorCode = PR_GetError();
1041 else if (bstd.mSSLRequestedTransferAmount > 1 &&
1042 bytesWritten == (bstd.mSSLRequestedTransferAmount - 1)) {
1043 // libSSL signaled us a short write.
1044 // While libSSL accepted all data, not all bytes were flushed to the OS socket.
1045 bstd.mThePendingByte = *(bstd.mSSLDataBuffer + (bstd.mSSLRequestedTransferAmount-1));
1046 bytesWritten = -1;
1047 bstd.mPRErrorCode = PR_WOULD_BLOCK_ERROR;
1048 bstd.mOneBytePendingFromEarlierWrite = PR_TRUE;
1049 bstd.mOriginalRequestedTransferAmount = bstd.mSSLRequestedTransferAmount;
1053 bstd.mSSLResultRemainingBytes = bytesWritten;
1054 busy_socket_ssl_state = nsSSLSocketThreadData::ssl_writing_done;
1056 else if (nsSSLSocketThreadData::ssl_pending_read == busy_socket_ssl_state)
1058 PRInt32 bytesRead = realFileDesc->methods
1059 ->read(realFileDesc,
1060 bstd.mSSLDataBuffer,
1061 bstd.mSSLRequestedTransferAmount);
1063 #ifdef DEBUG_SSL_VERBOSE
1064 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*)realFileDesc, bytesRead));
1065 #endif
1066 bytesRead = checkHandshake(bytesRead, PR_TRUE, realFileDesc, mBusySocket);
1067 if (bytesRead < 0) {
1068 // give the error back to caller
1069 bstd.mPRErrorCode = PR_GetError();
1072 bstd.mSSLResultRemainingBytes = bytesRead;
1073 bstd.mSSLRemainingReadResultData = bstd.mSSLDataBuffer;
1074 busy_socket_ssl_state = nsSSLSocketThreadData::ssl_reading_done;
1078 // avoid setting event repeatedly
1079 PRBool needToSetPollableEvent = PR_FALSE;
1082 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
1084 mBusySocket->mThreadData->mSSLState = busy_socket_ssl_state;
1086 if (!nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
1088 needToSetPollableEvent = PR_TRUE;
1089 nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_TRUE;
1093 if (needToSetPollableEvent && nsSSLIOLayerHelpers::mSharedPollableEvent)
1095 // Wake up the file descriptor on the Necko thread,
1096 // so it can fetch the results from the SSL I/O call
1097 // that we just completed.
1098 PR_SetPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
1100 // if we don't have a pollable event, we'll have to wake up
1101 // the caller by other means.
1106 nsAutoLock threadLock(ssl_thread_singleton->mMutex);
1107 if (mBusySocket)
1109 restoreOriginalSocket_locked(mBusySocket);
1110 mBusySocket = nsnull;
1112 if (!nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
1114 nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_TRUE;
1115 if (nsSSLIOLayerHelpers::mSharedPollableEvent)
1117 PR_SetPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
1123 PRBool nsSSLThread::exitRequested()
1125 if (!ssl_thread_singleton)
1126 return PR_FALSE;
1128 // no lock
1130 return ssl_thread_singleton->mExitRequested;
1133 nsSSLThread *nsSSLThread::ssl_thread_singleton = nsnull;