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
14 * The Original Code is mozilla.org code.
16 * The Initial Developer of the Original Code is
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
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"
46 extern PRLogModuleInfo
* gPIPNSSLog
;
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
)
68 nsAutoLock
threadLock(ssl_thread_singleton
->mMutex
);
70 if (si
->mThreadData
->mReplacedSSLFileDesc
)
72 return si
->mThreadData
->mReplacedSSLFileDesc
;
76 return si
->mFd
->lower
;
80 PRStatus
nsSSLThread::requestGetsockname(nsNSSSocketInfo
*si
, PRNetAddr
*addr
)
82 PRFileDesc
*fd
= getRealSSLFD(si
);
86 return fd
->methods
->getsockname(fd
, addr
);
89 PRStatus
nsSSLThread::requestGetpeername(nsNSSSocketInfo
*si
, PRNetAddr
*addr
)
91 PRFileDesc
*fd
= getRealSSLFD(si
);
95 return fd
->methods
->getpeername(fd
, addr
);
98 PRStatus
nsSSLThread::requestGetsocketoption(nsNSSSocketInfo
*si
,
99 PRSocketOptionData
*data
)
101 PRFileDesc
*fd
= getRealSSLFD(si
);
105 return fd
->methods
->getsocketoption(fd
, data
);
108 PRStatus
nsSSLThread::requestSetsocketoption(nsNSSSocketInfo
*si
,
109 const PRSocketOptionData
*data
)
111 PRFileDesc
*fd
= getRealSSLFD(si
);
115 return fd
->methods
->setsocketoption(fd
, data
);
118 PRStatus
nsSSLThread::requestConnectcontinue(nsNSSSocketInfo
*si
,
121 PRFileDesc
*fd
= getRealSSLFD(si
);
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);
137 PRFileDesc
*realSSLFD
;
140 nsAutoLock
threadLock(ssl_thread_singleton
->mMutex
);
142 if (si
== ssl_thread_singleton
->mBusySocket
)
144 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
148 switch (si
->mThreadData
->mSSLState
)
150 case nsSSLSocketThreadData::ssl_idle
:
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.
185 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
190 if (si
->mThreadData
->mReplacedSSLFileDesc
)
192 realSSLFD
= si
->mThreadData
->mReplacedSSLFileDesc
;
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
);
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
;
218 PRInt16
nsSSLThread::requestPoll(nsNSSSocketInfo
*si
, PRInt16 in_flags
, PRInt16
*out_flags
)
220 if (!ssl_thread_singleton
|| !si
|| !ssl_thread_singleton
->mThreadHandle
)
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
;
249 case nsSSLSocketThreadData::ssl_reading_done
:
251 if (in_flags
& PR_POLL_READ
)
253 *out_flags
|= PR_POLL_READ
;
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.
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
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
;
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");
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
;
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
);
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
;
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
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
)
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
);
409 if (NS_IsMainThread())
411 requestToCancel
->Cancel(NS_ERROR_ABORT
);
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
;
423 return si
->CloseSocketAndDestroy();
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
)
445 si
->mFd
->lower
= si
->mThreadData
->mReplacedSSLFileDesc
;
446 si
->mThreadData
->mReplacedSSLFileDesc
= nsnull
;
449 nsSSLIOLayerHelpers::mSocketOwningPollableEvent
= nsnull
;
453 PRStatus
nsSSLThread::getRealFDIfBlockingSocket_locked(nsNSSSocketInfo
*si
,
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
)
469 si
->mBlockingState
= sod
.value
.non_blocking
?
470 nsNSSSocketInfo::is_nonblocking_socket
: nsNSSSocketInfo::is_blocking_socket
;
473 if (si
->mBlockingState
== nsNSSSocketInfo::is_blocking_socket
)
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);
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);
503 if (getRealFDIfBlockingSocket_locked(si
, blockingFD
) == PR_FAILURE
) {
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
);
541 // leave this mutex protected scope before the blockingFD handling
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
);
563 // ssl thread is not busy, we'll continue below
567 case nsSSLSocketThreadData::ssl_reading_done
:
568 // there has been a previous request to read, that is now done!
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
;
592 si
->mThreadData
->mSSLRemainingReadResultData
+= return_amount
;
595 return return_amount
;
597 // we never arrive here, see return statement above
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.
621 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
624 // we never arrive here, see return statement above
628 if (si
->isPK11LoggedOut() || si
->isAlreadyShutDown()) {
629 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR
, 0);
633 if (si
->GetCanceled()) {
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);
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
;
701 PR_NotifyAllCondVar(ssl_thread_singleton
->mCond
);
704 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
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);
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);
730 if (getRealFDIfBlockingSocket_locked(si
, blockingFD
) == PR_FAILURE
) {
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
);
768 // leave this mutex protected scope before the blockingFD handling
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
);
790 // ssl thread is not busy, we'll continue below
794 case nsSSLSocketThreadData::ssl_writing_done
:
795 // there has been a previous request to write, that is now done!
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
;
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.
840 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
843 // we never arrive here, see return statement above
847 if (si
->isPK11LoggedOut() || si
->isAlreadyShutDown()) {
848 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR
, 0);
852 if (si
->GetCanceled()) {
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);
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
);
902 void nsSSLThread::Run(void)
904 // Helper variable, we don't want to call destroy
905 // while holding the mutex.
906 nsNSSSocketInfo
*socketToDestroy
= nsnull
;
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
947 PRBool pending_work
= PR_FALSE
;
953 (mBusySocket
->mThreadData
->mSSLState
== nsSSLSocketThreadData::ssl_pending_read
955 mBusySocket
->mThreadData
->mSSLState
== nsSSLSocketThreadData::ssl_pending_write
))
957 pending_work
= PR_TRUE
;
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
)
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
;
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
));
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
;
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
));
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));
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
));
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
);
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
)
1130 return ssl_thread_singleton
->mExitRequested
;
1133 nsSSLThread
*nsSSLThread::ssl_thread_singleton
= nsnull
;