mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
bug #7428. Added support for connection timeout. Now if a connection cannot be made within 35 seconds, the transport times out.
This commit is contained in:
parent
7a5278d0a4
commit
7d63cbc945
@ -37,7 +37,7 @@
|
||||
#define NS_ERROR_CONNECTION_REFUSED \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 13)
|
||||
|
||||
#define NS_ERROR_TCP_TIMEOUT \
|
||||
#define NS_ERROR_NET_TIMEOUT \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 14)
|
||||
|
||||
#define NS_ERROR_IN_PROGRESS \
|
||||
|
@ -83,14 +83,16 @@ nsSocketState gStateTable[eSocketOperation_Max][eSocketState_Max] = {
|
||||
|
||||
//
|
||||
// This is the timeout value (in milliseconds) for calls to PR_Connect(...).
|
||||
// The socket transport thread will block for this amount of time waiting
|
||||
// for the PR_Connect(...) to complete...
|
||||
//
|
||||
// The gConnectTimeout gets initialized the first time a nsSocketTransport
|
||||
// is created... This interval is then passed to all PR_Connect() calls...
|
||||
//
|
||||
#define CONNECT_TIMEOUT_IN_MS 20
|
||||
|
||||
static int gTimeoutIsInitialized = 0;
|
||||
static PRIntervalTime gConnectTimeout = PR_INTERVAL_NO_TIMEOUT;
|
||||
static PRIntervalTime gConnectTimeout = PR_INTERVAL_NO_WAIT;
|
||||
static PRIntervalTime gTimeoutInterval = PR_INTERVAL_NO_WAIT;
|
||||
|
||||
//
|
||||
// This is the global buffer used by all nsSocketTransport instances when
|
||||
@ -138,6 +140,8 @@ nsSocketTransport::nsSocketTransport():
|
||||
|
||||
PR_INIT_CLIST(&mListLink);
|
||||
|
||||
mLastActiveTime = PR_INTERVAL_NO_WAIT;
|
||||
|
||||
SetReadType (eSocketRead_None);
|
||||
SetWriteType(eSocketWrite_None);
|
||||
|
||||
@ -150,9 +154,8 @@ nsSocketTransport::nsSocketTransport():
|
||||
//
|
||||
// Initialize the global connect timeout value if necessary...
|
||||
//
|
||||
if (0 == gTimeoutIsInitialized) {
|
||||
gConnectTimeout = PR_MillisecondsToInterval(CONNECT_TIMEOUT_IN_MS);
|
||||
gTimeoutIsInitialized = 1;
|
||||
if (PR_INTERVAL_NO_WAIT == gConnectTimeout) {
|
||||
gConnectTimeout = PR_MillisecondsToInterval(CONNECT_TIMEOUT_IN_MS);
|
||||
}
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
@ -290,6 +293,9 @@ nsresult nsSocketTransport::Init(nsSocketTransportService* aService,
|
||||
}
|
||||
}
|
||||
|
||||
// Update the active time for timeout purposes...
|
||||
mLastActiveTime = PR_IntervalNow();
|
||||
|
||||
PR_LOG(gSocketLog, PR_LOG_DEBUG,
|
||||
("Initializing nsSocketTransport [this=%x]. rv = %x. \t"
|
||||
"aHost = %s.\t"
|
||||
@ -300,6 +306,35 @@ nsresult nsSocketTransport::Init(nsSocketTransportService* aService,
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::CheckForTimeout(PRIntervalTime aCurrentTime)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
PRIntervalTime idleInterval;
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoLock aLock(mLock);
|
||||
|
||||
idleInterval = aCurrentTime - mLastActiveTime;
|
||||
|
||||
//
|
||||
// Only timeout if the transport is waiting to connect to the server
|
||||
//
|
||||
if ((eSocketState_WaitConnect == mCurrentState) &&
|
||||
(idleInterval >= gTimeoutInterval)) {
|
||||
PR_LOG(gSocketLog, PR_LOG_ERROR,
|
||||
("nsSocketTransport::CheckForTimeout() [this=%x].\t"
|
||||
"TIMED OUT... Idle interval: %d\n",
|
||||
this, idleInterval));
|
||||
|
||||
// Move the transport into the Timeout state...
|
||||
mCurrentState = eSocketState_Timeout;
|
||||
rv = NS_ERROR_NET_TIMEOUT;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
{
|
||||
PRBool done = PR_FALSE;
|
||||
@ -420,6 +455,10 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
mReadListener = null_nsCOMPtr();
|
||||
mReadContext = null_nsCOMPtr();
|
||||
}
|
||||
// Close the socket transport end of the pipe...
|
||||
if (mReadPipeOut) {
|
||||
mReadPipeOut->Close();
|
||||
}
|
||||
mReadPipeIn = null_nsCOMPtr();
|
||||
mReadPipeOut = null_nsCOMPtr();
|
||||
SetReadType(eSocketRead_None);
|
||||
@ -438,6 +477,10 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
mWriteObserver = null_nsCOMPtr();
|
||||
mWriteContext = null_nsCOMPtr();
|
||||
}
|
||||
// Close the socket transport end of the pipe...
|
||||
if (mWritePipeIn) {
|
||||
mWritePipeIn->Close();
|
||||
}
|
||||
mWritePipeIn = null_nsCOMPtr();
|
||||
mWritePipeOut = null_nsCOMPtr();
|
||||
SetWriteType(eSocketWrite_None);
|
||||
@ -492,8 +535,7 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
break;
|
||||
|
||||
case eSocketState_Timeout:
|
||||
NS_ASSERTION(0, "Unexpected state...");
|
||||
mStatus = NS_ERROR_FAILURE;
|
||||
mStatus = NS_ERROR_NET_TIMEOUT;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -520,6 +562,9 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
aSelectFlags = 0;
|
||||
}
|
||||
|
||||
// Update the active time for timeout purposes...
|
||||
mLastActiveTime = PR_IntervalNow();
|
||||
|
||||
PR_LOG(gSocketLog, PR_LOG_DEBUG,
|
||||
("--- Leaving nsSocketTransport::Process() [this=%x]. mStatus = %x.\t"
|
||||
"CurrentState = %d\n\n",
|
||||
@ -1084,6 +1129,7 @@ nsresult nsSocketTransport::doWriteFromStream(PRUint32 *aCount)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::CloseConnection(PRBool bNow)
|
||||
{
|
||||
PRStatus status;
|
||||
@ -1121,6 +1167,12 @@ nsresult nsSocketTransport::CloseConnection(PRBool bNow)
|
||||
}
|
||||
|
||||
|
||||
void nsSocketTransport::SetSocketTimeout(PRIntervalTime aTimeInterval)
|
||||
{
|
||||
gTimeoutInterval = aTimeInterval;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsISupports implementation...
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "prclist.h"
|
||||
#include "prio.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prinrval.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannel.h"
|
||||
@ -132,6 +133,8 @@ public:
|
||||
|
||||
nsresult Process(PRInt16 aSelectFlags);
|
||||
|
||||
nsresult CheckForTimeout(PRIntervalTime aCurrentTime);
|
||||
|
||||
// Close this socket either right away or once done with the transaction.
|
||||
nsresult CloseConnection(PRBool bNow=PR_TRUE);
|
||||
|
||||
@ -142,8 +145,11 @@ public:
|
||||
|
||||
static nsSocketTransport* GetInstance(PRCList* qp) { return (nsSocketTransport*)((char*)qp - offsetof(nsSocketTransport, mListLink)); }
|
||||
|
||||
static void SetSocketTimeout(PRIntervalTime aTimeoutInterval);
|
||||
|
||||
PRBool CanBeReused(void) { return
|
||||
(mCurrentState != eSocketState_Error) && !mCloseConnectionOnceDone;}
|
||||
|
||||
protected:
|
||||
nsresult doConnection(PRInt16 aSelectFlags);
|
||||
nsresult doResolveHost(void);
|
||||
@ -189,6 +195,7 @@ protected:
|
||||
nsCOMPtr<nsIRequest> mDNSRequest;
|
||||
nsCOMPtr<nsIProgressEventSink> mEventSink;
|
||||
char* mHostName;
|
||||
PRIntervalTime mLastActiveTime;
|
||||
PRCList mListLink;
|
||||
PRUint32 mLoadAttributes;
|
||||
PRLock* mLock;
|
||||
|
@ -18,12 +18,11 @@
|
||||
*/
|
||||
|
||||
#include "nsILoadGroup.h"
|
||||
#include "netCore.h"
|
||||
#include "nsSocketTransportService.h"
|
||||
#include "nsSocketTransport.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#define MAX_OPEN_CONNECTIONS 50
|
||||
|
||||
|
||||
nsSocketTransportService::nsSocketTransportService()
|
||||
{
|
||||
@ -43,6 +42,8 @@ nsSocketTransportService::nsSocketTransportService()
|
||||
mActiveTransportList = nsnull;
|
||||
|
||||
mThreadRunning = PR_FALSE;
|
||||
|
||||
SetSocketTimeoutInterval(PR_MillisecondsToInterval(DEFAULT_SOCKET_TIMEOUT_IN_MS));
|
||||
}
|
||||
|
||||
|
||||
@ -332,6 +333,23 @@ nsresult nsSocketTransportService::RemoveFromSelectList(nsSocketTransport* aTran
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsSocketTransportService::GetSocketTimeoutInterval(PRIntervalTime* aResult)
|
||||
{
|
||||
*aResult = mSocketTimeoutInterval;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketTransportService::SetSocketTimeoutInterval(PRIntervalTime aTime)
|
||||
{
|
||||
mSocketTimeoutInterval = aTime;
|
||||
|
||||
// Update the timeout value in the socket transport...
|
||||
nsSocketTransport::SetSocketTimeout(aTime);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
@ -370,8 +388,7 @@ nsSocketTransportService::QueryInterface(const nsIID& aIID, void* *aInstancePtr)
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Run(void)
|
||||
{
|
||||
PRIntervalTime pollTimeout
|
||||
;
|
||||
PRIntervalTime pollTimeout;
|
||||
#ifdef USE_POLLABLE_EVENT
|
||||
//
|
||||
// Initialize the FDSET used by PR_Poll(...). The first item in the FDSet
|
||||
@ -380,7 +397,7 @@ nsSocketTransportService::Run(void)
|
||||
mSelectFDSet[0].fd = mThreadEvent;
|
||||
mSelectFDSet[0].in_flags = PR_POLL_READ;
|
||||
mSelectFDSetCount = 1;
|
||||
pollTimeout = PR_INTERVAL_NO_TIMEOUT;
|
||||
pollTimeout = mSocketTimeoutInterval;
|
||||
#else
|
||||
//
|
||||
// For now, rather than breaking out of the call to PR_Poll(...) just set
|
||||
@ -396,73 +413,95 @@ nsSocketTransportService::Run(void)
|
||||
while (mThreadRunning) {
|
||||
nsresult rv;
|
||||
PRInt32 count;
|
||||
PRIntervalTime intervalNow;
|
||||
nsSocketTransport* transport;
|
||||
int i;
|
||||
|
||||
// XXX: PR_Poll(...) needs a timeout value...
|
||||
count = PR_Poll(mSelectFDSet, mSelectFDSetCount, pollTimeout);
|
||||
if (-1 == count) {
|
||||
// XXX: PR_Poll failed... What should happen?
|
||||
}
|
||||
|
||||
/* One or more sockets has data... */
|
||||
if (count > 0) {
|
||||
int i;
|
||||
intervalNow = PR_IntervalNow();
|
||||
//
|
||||
// See if any sockets have data...
|
||||
//
|
||||
// Walk the list of active transports backwards to avoid missing
|
||||
// elements when a transport is removed...
|
||||
//
|
||||
for (i=mSelectFDSetCount-1; i>=0; i--) {
|
||||
PRPollDesc* pfd;
|
||||
PRInt16 out_flags;
|
||||
|
||||
transport = mActiveTransportList[i];
|
||||
pfd = &mSelectFDSet[i];
|
||||
|
||||
/* Process any sockets with data first... */
|
||||
for (i=mSelectFDSetCount-1; i>=0; i--) {
|
||||
PRPollDesc* pfd;
|
||||
PRInt16 out_flags;
|
||||
//
|
||||
// XXX: PR_Poll(...) has the unpleasent behavior of ONLY setting the
|
||||
// out_flags if one or more FDs are ready. So, DO NOT look at
|
||||
// the out_flags unless count > 0.
|
||||
//
|
||||
if ((count > 0) && pfd->out_flags) {
|
||||
// Clear the out_flags for next time...
|
||||
out_flags = pfd->out_flags;
|
||||
pfd->out_flags = 0;
|
||||
|
||||
pfd = &mSelectFDSet[i];
|
||||
if (pfd->out_flags) {
|
||||
// Clear the out_flags for next time...
|
||||
out_flags = pfd->out_flags;
|
||||
pfd->out_flags = 0;
|
||||
|
||||
transport = mActiveTransportList[i];
|
||||
if (transport) {
|
||||
rv = transport->Process(out_flags);
|
||||
if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
|
||||
// Update the select flags...
|
||||
pfd->in_flags = transport->GetSelectFlags();
|
||||
}
|
||||
//
|
||||
// If the operation completed, then remove the entry from the
|
||||
// select list...
|
||||
//
|
||||
else {
|
||||
rv = RemoveFromSelectList(transport);
|
||||
}
|
||||
if (transport) {
|
||||
rv = transport->Process(out_flags);
|
||||
if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
|
||||
// Update the select flags...
|
||||
pfd->in_flags = transport->GetSelectFlags();
|
||||
}
|
||||
//
|
||||
// If the operation completed, then remove the entry from the
|
||||
// select list...
|
||||
//
|
||||
else {
|
||||
rv = RemoveFromSelectList(transport);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef USE_POLLABLE_EVENT
|
||||
/* Process any pending operations on the mWorkQ... */
|
||||
NS_ASSERTION(0 == i, "Null transport in active list...");
|
||||
if (0 == i) {
|
||||
//
|
||||
// Clear the pollable event... This call should *never* block since
|
||||
// PR_Poll(...) said that it had been fired...
|
||||
//
|
||||
NS_ASSERTION(!(mSelectFDSet[0].out_flags & PR_POLL_EXCEPT),
|
||||
"Exception on Pollable event.");
|
||||
PR_WaitForPollableEvent(mThreadEvent);
|
||||
/* Process any pending operations on the mWorkQ... */
|
||||
NS_ASSERTION(0 == i, "Null transport in active list...");
|
||||
if (0 == i) {
|
||||
//
|
||||
// Clear the pollable event... This call should *never* block since
|
||||
// PR_Poll(...) said that it had been fired...
|
||||
//
|
||||
NS_ASSERTION(!(mSelectFDSet[0].out_flags & PR_POLL_EXCEPT),
|
||||
"Exception on Pollable event.");
|
||||
PR_WaitForPollableEvent(mThreadEvent);
|
||||
|
||||
rv = ProcessWorkQ();
|
||||
}
|
||||
rv = ProcessWorkQ();
|
||||
}
|
||||
#else
|
||||
//
|
||||
// The pollable event should be the *only* null transport
|
||||
// in the active transport list.
|
||||
//
|
||||
NS_ASSERTION(transport, "Null transport in active list...");
|
||||
//
|
||||
// The pollable event should be the *only* null transport
|
||||
// in the active transport list.
|
||||
//
|
||||
NS_ASSERTION(transport, "Null transport in active list...");
|
||||
#endif /* USE_POLLABLE_EVENT */
|
||||
}
|
||||
//
|
||||
// Check to see if the transport has timed out...
|
||||
//
|
||||
} else {
|
||||
if (transport) {
|
||||
rv = transport->CheckForTimeout(intervalNow);
|
||||
if (NS_ERROR_NET_TIMEOUT == rv) {
|
||||
// Process the timeout...
|
||||
rv = transport->Process(0);
|
||||
//
|
||||
// The operation has completed. Remove the entry from the
|
||||
// select list///
|
||||
//
|
||||
rv = RemoveFromSelectList(transport);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* PR_Poll(...) timeout... */
|
||||
else if (count == 0) {
|
||||
}
|
||||
/* PR_Poll(...) error.. */
|
||||
else {
|
||||
}
|
||||
} // end-for
|
||||
|
||||
#ifndef USE_POLLABLE_EVENT
|
||||
/* Process any pending operations on the mWorkQ... */
|
||||
|
@ -34,6 +34,19 @@
|
||||
#define USE_POLLABLE_EVENT
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is the default timeout value (in milliseconds) for sockets which have
|
||||
// no activity...
|
||||
//
|
||||
#define DEFAULT_SOCKET_TIMEOUT_IN_MS 35*1000
|
||||
|
||||
//
|
||||
// This is the Maximum number of Socket Transport instances that can be active
|
||||
// at once...
|
||||
//
|
||||
#define MAX_OPEN_CONNECTIONS 50
|
||||
|
||||
|
||||
// Forward declarations...
|
||||
class nsSocketTransport;
|
||||
|
||||
@ -56,6 +69,10 @@ public:
|
||||
|
||||
nsresult AddToWorkQ(nsSocketTransport* aTransport);
|
||||
|
||||
// XXX: Should these use intervals or Milliseconds?
|
||||
nsresult GetSocketTimeoutInterval(PRIntervalTime* aResult);
|
||||
nsresult SetSocketTimeoutInterval(PRIntervalTime aTime);
|
||||
|
||||
// The following methods are called by the transport thread...
|
||||
nsresult ProcessWorkQ(void);
|
||||
|
||||
@ -63,18 +80,20 @@ public:
|
||||
nsresult RemoveFromSelectList(nsSocketTransport* aTransport);
|
||||
|
||||
protected:
|
||||
nsIThread* mThread;
|
||||
nsIThread* mThread;
|
||||
#ifdef USE_POLLABLE_EVENT
|
||||
PRFileDesc* mThreadEvent;
|
||||
PRFileDesc* mThreadEvent;
|
||||
#endif /* USE_POLLABLE_EVENT */
|
||||
PRLock* mThreadLock;
|
||||
PRBool mThreadRunning;
|
||||
PRLock* mThreadLock;
|
||||
PRBool mThreadRunning;
|
||||
|
||||
PRCList mWorkQ;
|
||||
PRIntervalTime mSocketTimeoutInterval;
|
||||
|
||||
PRInt32 mSelectFDSetCount;
|
||||
PRPollDesc* mSelectFDSet;
|
||||
nsSocketTransport** mActiveTransportList;
|
||||
PRCList mWorkQ;
|
||||
|
||||
PRInt32 mSelectFDSetCount;
|
||||
PRPollDesc* mSelectFDSet;
|
||||
nsSocketTransport** mActiveTransportList;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user