зеркало из https://github.com/mozilla/gecko-dev.git
Fixes bug 72320. abort on exit (sending "logout" to a closed IMAP socket?).
r=sspitzer,dougt,mscott.
This commit is contained in:
Родитель
2e982313fa
Коммит
c2cf727e40
|
@ -133,18 +133,18 @@ nsSocketTransport::nsSocketTransport():
|
|||
mProxyHost(nsnull),
|
||||
mProxyTransparent(PR_FALSE),
|
||||
mSSLProxy(PR_FALSE),
|
||||
mCloseConnectionOnceDone(PR_FALSE),
|
||||
mClosePending(PR_FALSE),
|
||||
mWasConnected(PR_FALSE),
|
||||
mService(nsnull),
|
||||
mReadWriteState(0),
|
||||
mSelectFlags(0),
|
||||
mStatus(NS_OK),
|
||||
mSocketFD(nsnull),
|
||||
mSocketRef(0),
|
||||
mSocketLock(0),
|
||||
mSocketTypeCount(0),
|
||||
mSocketTypes(nsnull),
|
||||
mBytesExpected(-1),
|
||||
mReuseCount(0),
|
||||
mLastReuseCount(0),
|
||||
mBufferSegmentSize(0),
|
||||
mBufferMaxSize(0),
|
||||
mIdleTimeoutInSeconds(0),
|
||||
|
@ -197,7 +197,10 @@ nsSocketTransport::~nsSocketTransport()
|
|||
mDNSRequest = 0;
|
||||
}
|
||||
|
||||
CloseConnection();
|
||||
if (mSocketFD) {
|
||||
mClosePending = PR_TRUE; // ignore references to the socket
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
if (mService) {
|
||||
PR_AtomicDecrement(&mService->mTotalTransports);
|
||||
|
@ -409,7 +412,7 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
|||
if (mWriteRequest)
|
||||
mWriteRequest->SetStatus(mStatus);
|
||||
|
||||
mCloseConnectionOnceDone = PR_TRUE;
|
||||
mClosePending = PR_TRUE;
|
||||
|
||||
//
|
||||
// Fall into the Done state...
|
||||
|
@ -425,12 +428,12 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
|||
CompleteAsyncWrite();
|
||||
|
||||
// Close connection if expected to do so...
|
||||
if (mCloseConnectionOnceDone)
|
||||
if (mClosePending)
|
||||
CloseConnection();
|
||||
|
||||
mCurrentState = gStateTable[mOperation][mCurrentState];
|
||||
mOperation = eSocketOperation_None;
|
||||
mStatus = NS_OK;
|
||||
//mStatus = NS_OK; // XXX masks errors!!
|
||||
done = PR_TRUE;
|
||||
continue;
|
||||
|
||||
|
@ -527,13 +530,7 @@ nsSocketTransport::CompleteAsyncRead()
|
|||
NS_RELEASE(mReadRequest);
|
||||
mReadRequest = nsnull;
|
||||
|
||||
// From bug 71391:
|
||||
//
|
||||
// If the socket is not to be reused, then make sure it
|
||||
// is closed once we reach eSocketState_Done.
|
||||
//
|
||||
if (mReuseCount == 0)
|
||||
mCloseConnectionOnceDone = PR_TRUE;
|
||||
mSocketRef--;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -551,6 +548,8 @@ nsSocketTransport::CompleteAsyncWrite()
|
|||
mWriteRequest->OnStop();
|
||||
NS_RELEASE(mWriteRequest);
|
||||
mWriteRequest = nsnull;
|
||||
|
||||
mSocketRef--;
|
||||
}
|
||||
|
||||
//-----
|
||||
|
@ -847,6 +846,9 @@ nsresult nsSocketTransport::doConnection(PRInt16 aSelectFlags)
|
|||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// Called while inside the socket transport monitor...
|
||||
//
|
||||
nsresult
|
||||
nsSocketTransport::doBlockingConnection()
|
||||
{
|
||||
|
@ -947,8 +949,11 @@ nsSocketTransport::doReadWrite(PRInt16 aSelectFlags)
|
|||
if (PR_POLL_HUP & aSelectFlags) {
|
||||
LOG(("nsSocketTransport: [this=%x] received PR_POLL_HUP\n", this));
|
||||
// Make sure this socket is closed when we reach eSocketState_Done.
|
||||
mCloseConnectionOnceDone = PR_TRUE;
|
||||
return NS_OK;
|
||||
mClosePending = PR_TRUE;
|
||||
// Some unix platforms (HP-UX) may report a PR_POLL_HUP with PR_POLL_READ,
|
||||
// so we should make sure to read the last of the data before completing.
|
||||
if (!(PR_POLL_READ & aSelectFlags))
|
||||
return NS_OK; // advance to done state
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1042,15 +1047,24 @@ nsSocketTransport::doReadWrite(PRInt16 aSelectFlags)
|
|||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
nsresult nsSocketTransport::CloseConnection(PRBool bNow)
|
||||
//
|
||||
// Called while inside the socket transport monitor...
|
||||
//
|
||||
nsresult nsSocketTransport::CloseConnection()
|
||||
{
|
||||
PRStatus status;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!bNow) { // close connection once done.
|
||||
mCloseConnectionOnceDone = PR_TRUE;
|
||||
|
||||
// can only close the socket if not locked
|
||||
if (mSocketLock) {
|
||||
LOG(("nsSocketTransport::CloseConnection [this=%x] Socket is locked; "
|
||||
"delaying call to PR_Close\n", this));
|
||||
mClosePending = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// allow close only if pending or if the socket is unreferenced
|
||||
NS_ENSURE_TRUE(mClosePending || (mSocketRef == 0), NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (!mSocketFD) {
|
||||
mCurrentState = eSocketState_Closed;
|
||||
|
@ -1114,41 +1128,49 @@ nsSocketTransport::GetPort(PRInt32 *aPort)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetReuseConnection(PRBool *_retval)
|
||||
nsSocketTransport::GetReuseConnection(PRBool *value)
|
||||
{
|
||||
if (_retval == NULL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*_retval = !mCloseConnectionOnceDone;
|
||||
NS_ENSURE_ARG_POINTER(value);
|
||||
PRUint32 count;
|
||||
GetReuseCount(&count);
|
||||
*value = count > 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::SetReuseConnection(PRBool aReuse)
|
||||
nsSocketTransport::SetReuseConnection(PRBool value)
|
||||
{
|
||||
mCloseConnectionOnceDone = !aReuse;
|
||||
|
||||
if (aReuse)
|
||||
mReuseCount++;
|
||||
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
if (value)
|
||||
mSocketRef++;
|
||||
else if (--mSocketRef == 0)
|
||||
CloseConnection(); // close if this is the last reference to the socket
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetReuseCount (PRUint32 * count)
|
||||
nsSocketTransport::GetReuseCount(PRUint32 *count)
|
||||
{
|
||||
if (count == NULL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
NS_ENSURE_ARG_POINTER(count);
|
||||
|
||||
*count = mReuseCount;
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
*count = PRUint32(mSocketRef);
|
||||
if (mReadRequest)
|
||||
(*count)--;
|
||||
if (mWriteRequest)
|
||||
(*count)--;
|
||||
if (mBIS)
|
||||
(*count)--;
|
||||
if (mBOS)
|
||||
(*count)--;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::SetReuseCount (PRUint32 count)
|
||||
{
|
||||
mReuseCount = count;
|
||||
return NS_OK;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1367,11 +1389,11 @@ nsSocketTransport::AsyncRead(nsIStreamListener* aListener,
|
|||
NS_ENSURE_ARG_POINTER(aRequest);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
LOG(("nsSocketTransport: Entering AsyncRead() [host=%s:%d this=%x]\n",
|
||||
mHostName, mPort, this));
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (GetReadType() != eSocketRead_None)
|
||||
rv = NS_ERROR_IN_PROGRESS;
|
||||
|
@ -1410,6 +1432,7 @@ nsSocketTransport::AsyncRead(nsIStreamListener* aListener,
|
|||
mReadRequest->SetContext(aContext);
|
||||
mReadRequest->SetListener(listener);
|
||||
//mReadRequest->SetTransferCount(aCount);
|
||||
mSocketRef++; // this async request gets a reference to the socket
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -1442,11 +1465,11 @@ nsSocketTransport::AsyncWrite(nsIStreamProvider* aProvider,
|
|||
NS_ENSURE_ARG_POINTER(aRequest);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
LOG(("nsSocketTransport: Entering AsyncWrite() [host=%s:%d this=%x]\n",
|
||||
mHostName, mPort, this));
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
// If a write is already in progress then fail...
|
||||
if (GetWriteType() != eSocketWrite_None)
|
||||
|
@ -1486,6 +1509,7 @@ nsSocketTransport::AsyncWrite(nsIStreamProvider* aProvider,
|
|||
mWriteRequest->SetContext(aContext);
|
||||
mWriteRequest->SetProvider(provider);
|
||||
//mWriteRequest->SetTransferCount(aCount);
|
||||
mSocketRef++; // this async request gets a reference to the socket
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -1516,27 +1540,25 @@ nsSocketTransport::OpenInputStream(PRUint32 aOffset,
|
|||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
LOG(("nsSocketTransport: Entering OpenInputStream() [host=%s:%d this=%x].\n",
|
||||
mHostName, mPort, this));
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
// If a read is already in progress then fail...
|
||||
if (GetReadType() != eSocketRead_None)
|
||||
rv = NS_ERROR_IN_PROGRESS;
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = doBlockingConnection();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// the transport holds only a weak reference to the blocking stream
|
||||
NS_NEWXPCOM(mBIS, nsSocketBIS);
|
||||
if (!mBIS)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
NS_ADDREF(mBIS);
|
||||
mBIS->Init();
|
||||
mBIS->SetTransport(this);
|
||||
mBIS->SetSocket(mSocketFD);
|
||||
mSocketRef++; // this blocking stream gets a reference to the socket
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1551,7 +1573,8 @@ nsSocketTransport::OpenInputStream(PRUint32 aOffset,
|
|||
"rv=%x.\n",
|
||||
mHostName, mPort, this, rv));
|
||||
|
||||
NS_IF_ADDREF(*aResult = mBIS);
|
||||
*aResult = mBIS;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1564,27 +1587,25 @@ nsSocketTransport::OpenOutputStream(PRUint32 aOffset,
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
LOG(("nsSocketTransport: Entering OpenOutputStream() [host=%s:%d this=%x].\n",
|
||||
mHostName, mPort, this));
|
||||
|
||||
// Enter the socket transport lock...
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
// If a write is already in progress then fail...
|
||||
if (GetWriteType() != eSocketWrite_None)
|
||||
rv = NS_ERROR_IN_PROGRESS;
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = doBlockingConnection();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// the transport holds only a weak reference to the blocking stream
|
||||
NS_NEWXPCOM(mBOS, nsSocketBOS);
|
||||
if (!mBOS)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
NS_ADDREF(mBOS);
|
||||
mBOS->Init();
|
||||
mBOS->SetTransport(this);
|
||||
mBOS->SetSocket(mSocketFD);
|
||||
mSocketRef++; // this blocking stream gets a reference to the socket
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1599,7 +1620,8 @@ nsSocketTransport::OpenOutputStream(PRUint32 aOffset,
|
|||
"rv = %x.\n",
|
||||
mHostName, mPort, this, rv));
|
||||
|
||||
NS_IF_ADDREF(*aResult = mBOS);
|
||||
*aResult = mBOS;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1742,6 +1764,67 @@ nsSocketTransport::OnStatus(nsresult message)
|
|||
return OnStatus(req, req->Context(), message);
|
||||
}
|
||||
|
||||
PRFileDesc *
|
||||
nsSocketTransport::GetConnectedSocket()
|
||||
{
|
||||
LOG(("nsSocketTransport::GetConnectedSocket [this=%x]\n", this));
|
||||
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
// Don't try to connect if there was an error...
|
||||
//if (NS_FAILED(mStatus)) return nsnull;
|
||||
|
||||
if (!mSocketFD)
|
||||
doBlockingConnection();
|
||||
|
||||
// Don't allow this socket to be closed until the lock count drops
|
||||
// to zero. See ReleaseSocket() below.
|
||||
if (mSocketFD)
|
||||
mSocketLock++;
|
||||
|
||||
return mSocketFD;
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::ReleaseSocket(PRFileDesc *sock)
|
||||
{
|
||||
LOG(("nsSocketTransport::ReleaseSocket [this=%x sock=%x]\n",
|
||||
this, sock));
|
||||
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
NS_ASSERTION(sock == mSocketFD, "invalid pointer");
|
||||
|
||||
// An async request could have discovered an error on the socket.
|
||||
// In this case, a close is pending, and we need to call PR_Close.
|
||||
if ((--mSocketLock == 0) && mClosePending)
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::ClearSocketBS(nsSocketBS *blockingStream)
|
||||
{
|
||||
LOG(("nsSocketTransport::ClearSocketBS [this=%x bs=%x]\n",
|
||||
this, blockingStream));
|
||||
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (mSocketRef == 0) {
|
||||
NS_NOTREACHED("socket ref is already zero");
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockingStream == mBOS)
|
||||
mBOS = nsnull;
|
||||
else {
|
||||
NS_ASSERTION(blockingStream == mBIS, "invalid pointer");
|
||||
mBIS = nsnull;
|
||||
}
|
||||
|
||||
if (--mSocketRef == 0)
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// nsSocketBS
|
||||
|
@ -1750,30 +1833,103 @@ nsSocketTransport::OnStatus(nsresult message)
|
|||
|
||||
nsSocketBS::nsSocketBS()
|
||||
: mTransport(nsnull)
|
||||
, mSock(nsnull)
|
||||
, mTransportLock(nsnull)
|
||||
{ }
|
||||
|
||||
nsSocketBS::~nsSocketBS()
|
||||
{
|
||||
NS_IF_RELEASE(mTransport);
|
||||
}
|
||||
SetTransport(nsnull);
|
||||
|
||||
void
|
||||
nsSocketBS::SetTransport(nsSocketTransport *aTransport)
|
||||
{
|
||||
NS_IF_RELEASE(mTransport);
|
||||
NS_IF_ADDREF(mTransport = aTransport);
|
||||
if (mTransportLock)
|
||||
PR_DestroyLock(mTransportLock);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketBS::Poll(PRInt16 event)
|
||||
nsSocketBS::Init()
|
||||
{
|
||||
mTransportLock = PR_NewLock();
|
||||
if (!mTransportLock)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketBS::SetTransport(nsSocketTransport *transport)
|
||||
{
|
||||
if (!mTransportLock) return;
|
||||
|
||||
LOG(("nsSocketBS::SetTransport [this=%x transport=%x]\n", this, transport));
|
||||
|
||||
PR_Lock(mTransportLock);
|
||||
if (mTransport != transport) {
|
||||
if (!transport) {
|
||||
// notify the socket transport that we are going away
|
||||
nsSocketTransport *trans = mTransport;
|
||||
NS_ADDREF(trans);
|
||||
PR_Unlock(mTransportLock); // avoid nested locks
|
||||
trans->ClearSocketBS(this);
|
||||
PR_Lock(mTransportLock);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
NS_IF_RELEASE(mTransport);
|
||||
mTransport = transport;
|
||||
NS_IF_ADDREF(mTransport);
|
||||
}
|
||||
PR_Unlock(mTransportLock);
|
||||
}
|
||||
|
||||
PRFileDesc *
|
||||
nsSocketBS::GetSocket()
|
||||
{
|
||||
LOG(("nsSocketBS::GetSocket [this=%x]\n", this));
|
||||
|
||||
// Each and every time we need access to the socket, we must
|
||||
// request it from the transport.
|
||||
PRFileDesc *fd = nsnull;
|
||||
nsSocketTransport *transport = nsnull;
|
||||
GetTransport(&transport);
|
||||
if (transport) {
|
||||
fd = transport->GetConnectedSocket(); // may return null
|
||||
NS_RELEASE(transport);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketBS::ReleaseSocket(PRFileDesc *sock)
|
||||
{
|
||||
LOG(("nsSocketBS::ReleaseSocket [this=%x sock=%x]\n", this, sock));
|
||||
|
||||
nsSocketTransport *transport = nsnull;
|
||||
GetTransport(&transport);
|
||||
if (transport)
|
||||
transport->ReleaseSocket(sock);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketBS::GetTransport(nsSocketTransport **transport)
|
||||
{
|
||||
NS_ASSERTION(transport, "null pointer");
|
||||
NS_ENSURE_TRUE(mTransportLock, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
LOG(("nsSocketBS::GetTransport [this=%x mTransport=%x]\n", this, mTransport));
|
||||
|
||||
nsAutoLock lock(mTransportLock);
|
||||
|
||||
*transport = mTransport;
|
||||
NS_IF_ADDREF(*transport);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketBS::Poll(PRFileDesc *sock, PRInt16 event)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
PRIntervalTime pollTimeout = PR_MillisecondsToInterval(DEFAULT_POLL_TIMEOUT_IN_MS);
|
||||
PRPollDesc pd;
|
||||
|
||||
pd.fd = mSock;
|
||||
pd.fd = sock;
|
||||
pd.in_flags = event | PR_POLL_EXCEPT;
|
||||
pd.out_flags = 0;
|
||||
|
||||
|
@ -1813,7 +1969,8 @@ nsSocketBIS::~nsSocketBIS()
|
|||
NS_IMETHODIMP
|
||||
nsSocketBIS::Close()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
SetTransport(nsnull); // release reference to the socket transport
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1825,27 +1982,34 @@ nsSocketBIS::Available(PRUint32 *aCount)
|
|||
NS_IMETHODIMP
|
||||
nsSocketBIS::Read(char *aBuf, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv = NS_OK;
|
||||
PRInt32 total;
|
||||
|
||||
LOG(("nsSocketBIS::Read [this=%x count=%u]\n", this, aCount));
|
||||
|
||||
PRFileDesc *sock = GetSocket();
|
||||
NS_ENSURE_TRUE(sock, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
*aBytesRead = 0;
|
||||
|
||||
tryRead:
|
||||
total = PR_Read(mSock, aBuf, aCount);
|
||||
total = PR_Read(sock, aBuf, aCount);
|
||||
if (total < 0) {
|
||||
if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
|
||||
rv = NS_ErrorAccordingToNSPR();
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
//
|
||||
// Block until the socket is readable and then try again.
|
||||
//
|
||||
rv = Poll(PR_POLL_READ);
|
||||
rv = Poll(sock, PR_POLL_READ);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsSocketBIS::Read [this=%x] Poll failed [rv=%x]\n", this, rv));
|
||||
return rv;
|
||||
goto end;
|
||||
}
|
||||
LOG(("nsSocketBIS::Read [this=%x] Poll succeeded; looping back to PR_Read\n", this));
|
||||
goto tryRead;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
LOG(("nsSocketBIS::Read [this=%x] PR_Read failed [error=%x]\n", this, PR_GetError()));
|
||||
goto end;
|
||||
}
|
||||
/*
|
||||
if (mTransport && total) {
|
||||
|
@ -1854,7 +2018,9 @@ tryRead:
|
|||
}
|
||||
*/
|
||||
*aBytesRead = (PRUint32) total;
|
||||
return NS_OK;
|
||||
end:
|
||||
ReleaseSocket(sock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1901,7 +2067,8 @@ nsSocketBOS::~nsSocketBOS()
|
|||
NS_IMETHODIMP
|
||||
nsSocketBOS::Close()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
SetTransport(nsnull); // release reference to the socket transport
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1919,25 +2086,31 @@ nsSocketBOS::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aBytesWritten)
|
|||
|
||||
LOG(("nsSocketBOS::Write [this=%x count=%u]\n", this, aCount));
|
||||
|
||||
PRFileDesc *sock = GetSocket();
|
||||
NS_ENSURE_TRUE(sock, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
*aBytesWritten = 0;
|
||||
|
||||
tryWrite:
|
||||
written = PR_Write(mSock, aBuf + total, aCount - total);
|
||||
written = PR_Write(sock, aBuf + total, aCount - total);
|
||||
LOG(("nsSocketBOS PR_Write [this=%x] wrote %d of %d\n", this, total, aCount));
|
||||
|
||||
if (written < 0) {
|
||||
if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
|
||||
rv = NS_ErrorAccordingToNSPR();
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
//
|
||||
// Block until the socket is writable and then try again.
|
||||
//
|
||||
rv = Poll(PR_POLL_WRITE);
|
||||
rv = Poll(sock, PR_POLL_WRITE);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsSocketBOS::Write [this=%x] Poll failed [rv=%x]\n", this, rv));
|
||||
return rv;
|
||||
goto end;
|
||||
}
|
||||
LOG(("nsSocketBOS::Write [this=%x] Poll succeeded; looping back to PR_Write\n", this));
|
||||
goto tryWrite;
|
||||
}
|
||||
LOG(("nsSocketBOS::Write [this=%x] Write Failed [rv=%x]\n", this, PR_GetError()));
|
||||
return NS_ERROR_FAILURE;
|
||||
LOG(("nsSocketBOS::Write [this=%x] PR_Write failed [error=%x]\n", this, PR_GetError()));
|
||||
goto end;
|
||||
}
|
||||
|
||||
// up our total count since something was written
|
||||
|
@ -1946,7 +2119,7 @@ tryWrite:
|
|||
// If not all the data has been written loop again. This happens
|
||||
// if this is a non blocking socket and there was a short write.
|
||||
if ((PRUint32)total != aCount)
|
||||
goto tryWrite;
|
||||
goto tryWrite;
|
||||
|
||||
/*
|
||||
if (mTransport && total) {
|
||||
|
@ -1955,7 +2128,9 @@ tryWrite:
|
|||
}
|
||||
*/
|
||||
*aBytesWritten = (PRUint32) total;
|
||||
return NS_OK;
|
||||
end:
|
||||
ReleaseSocket(sock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2216,6 +2391,7 @@ nsSocketRequest::nsSocketRequest()
|
|||
, mSuspendCount(PR_FALSE)
|
||||
, mCanceled(PR_FALSE)
|
||||
, mStartFired(0)
|
||||
, mStopFired(0)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
@ -2255,6 +2431,7 @@ nsSocketRequest::OnStop()
|
|||
}
|
||||
mObserver->OnStopRequest(this, mContext, mStatus, nsnull);
|
||||
mObserver = 0;
|
||||
mStopFired = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2270,8 +2447,7 @@ NS_IMETHODIMP
|
|||
nsSocketRequest::IsPending(PRBool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult =
|
||||
(mTransport ? (mTransport->GetSocket() != nsnull) : nsnull);
|
||||
*aResult = !mStopFired;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2383,23 +2559,27 @@ nsSocketReadRequest::OnRead()
|
|||
nsresult rv;
|
||||
PRUint32 amount, offset = mInputStream->GetOffset();
|
||||
|
||||
#if 0
|
||||
rv = mInputStream->Available(&amount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Hack below:
|
||||
// So, there are two cases that we are worried about:
|
||||
// On the mac, the impl of PR_Poll is a timeout. What this means
|
||||
// for us is that Available might return zero. If we passed zero,
|
||||
// this we may cause read to terminate prematurely.
|
||||
// The other case is SSL which might require PR_Read to be called
|
||||
// even if there were no bytes to read. (for handshaking).
|
||||
// Therefore, we will lie and say that there is data to read when
|
||||
// available return zero. -- dougt/darin
|
||||
// Hack below:
|
||||
// So, there are two cases that we are worried about:
|
||||
// On the mac, the impl of PR_Poll is a timeout. What this means
|
||||
// for us is that Available might return zero. If we passed zero,
|
||||
// this we may cause read to terminate prematurely.
|
||||
// The other case is SSL which might require PR_Read to be called
|
||||
// even if there were no bytes to read. (for handshaking).
|
||||
// Therefore, we will lie and say that there is data to read when
|
||||
// available return zero. -- dougt/darin
|
||||
|
||||
if (amount == 0)
|
||||
amount = MAX_IO_TRANSFER_SIZE;
|
||||
else
|
||||
amount = PR_MIN(amount, MAX_IO_TRANSFER_SIZE);
|
||||
if (amount == 0)
|
||||
amount = MAX_IO_TRANSFER_SIZE;
|
||||
else
|
||||
amount = PR_MIN(amount, MAX_IO_TRANSFER_SIZE);
|
||||
#endif
|
||||
// Allow reads beyond what is available right now.
|
||||
amount = MAX_IO_TRANSFER_SIZE;
|
||||
|
||||
LOG(("nsSocketReadRequest: [this=%x] calling listener [offset=%u, count=%u]\n",
|
||||
this, offset, amount));
|
||||
|
@ -2426,7 +2606,7 @@ nsSocketReadRequest::OnRead()
|
|||
rv = NS_OK; // go to done state
|
||||
}
|
||||
else if (NS_FAILED(rv)) {
|
||||
LOG(("nsSocketReadRequest: [this=%x] error reading socket.\n", this));
|
||||
LOG(("nsSocketReadRequest: [this=%x rv=%x] error reading socket.\n", this, rv));
|
||||
}
|
||||
else {
|
||||
PRUint32 total = mInputStream->GetOffset() - offset;
|
||||
|
|
|
@ -153,8 +153,8 @@ public:
|
|||
|
||||
nsresult CheckForTimeout (PRIntervalTime aCurrentTime);
|
||||
|
||||
// Close this socket either right away or once done with the transaction.
|
||||
nsresult CloseConnection(PRBool bNow=PR_TRUE);
|
||||
// Close this socket
|
||||
nsresult CloseConnection();
|
||||
|
||||
// Access methods used by the socket transport service...
|
||||
PRFileDesc* GetSocket(void) { return mSocketFD; }
|
||||
|
@ -163,8 +163,8 @@ public:
|
|||
|
||||
static nsSocketTransport* GetInstance(PRCList* qp) { return (nsSocketTransport*)((char*)qp - offsetof(nsSocketTransport, mListLink)); }
|
||||
|
||||
PRBool CanBeReused(void) { return
|
||||
(mCurrentState != eSocketState_Error) && !mCloseConnectionOnceDone;}
|
||||
PRBool CanBeReused() { return
|
||||
(mCurrentState != eSocketState_Error) && !mClosePending;}
|
||||
|
||||
//
|
||||
// request helpers
|
||||
|
@ -174,6 +174,13 @@ public:
|
|||
nsresult OnProgress(nsSocketRequest *, nsISupports *ctxt, PRUint32 offset);
|
||||
nsresult OnStatus(nsSocketRequest *, nsISupports *ctxt, nsresult message);
|
||||
|
||||
//
|
||||
// blocking stream helpers
|
||||
//
|
||||
PRFileDesc *GetConnectedSocket(); // do the connection if necessary
|
||||
void ReleaseSocket(PRFileDesc *); // allow the socket to be closed if pending
|
||||
void ClearSocketBS(nsSocketBS *); // clears weak reference to blocking stream
|
||||
|
||||
protected:
|
||||
nsresult doConnection(PRInt16 aSelectFlags);
|
||||
nsresult doBlockingConnection();
|
||||
|
@ -233,7 +240,7 @@ protected:
|
|||
PRPackedBool mSSLProxy;
|
||||
|
||||
/* put all the packed bools together so we save space */
|
||||
PRPackedBool mCloseConnectionOnceDone;
|
||||
PRPackedBool mClosePending;
|
||||
PRPackedBool mWasConnected;
|
||||
|
||||
nsSocketTransportService* mService;
|
||||
|
@ -243,20 +250,20 @@ protected:
|
|||
nsresult mStatus;
|
||||
|
||||
PRFileDesc* mSocketFD;
|
||||
PRUint32 mSocketRef; // if non-zero, keep the socket open unless there is an error
|
||||
PRUint32 mSocketLock; // if non-zero, do not close the socket even if there is an error
|
||||
PRUint32 mSocketTypeCount;
|
||||
char* *mSocketTypes;
|
||||
|
||||
PRInt32 mBytesExpected;
|
||||
PRUint32 mReuseCount;
|
||||
PRUint32 mLastReuseCount;
|
||||
|
||||
PRUint32 mBufferSegmentSize;
|
||||
PRUint32 mBufferMaxSize;
|
||||
|
||||
PRUint32 mIdleTimeoutInSeconds;
|
||||
|
||||
nsSocketBIS *mBIS;
|
||||
nsSocketBOS *mBOS;
|
||||
nsSocketBIS *mBIS; // weak reference
|
||||
nsSocketBOS *mBOS; // weak reference
|
||||
nsSocketReadRequest *mReadRequest;
|
||||
nsSocketWriteRequest *mWriteRequest;
|
||||
};
|
||||
|
@ -270,14 +277,20 @@ public:
|
|||
nsSocketBS();
|
||||
virtual ~nsSocketBS();
|
||||
|
||||
void SetTransport(nsSocketTransport *);
|
||||
void SetSocket(PRFileDesc *aSock) { mSock = aSock; }
|
||||
nsresult Init();
|
||||
|
||||
nsresult Poll(PRInt16 event);
|
||||
void SetTransport(nsSocketTransport *);
|
||||
|
||||
protected:
|
||||
PRFileDesc *GetSocket();
|
||||
void ReleaseSocket(PRFileDesc *);
|
||||
|
||||
nsresult GetTransport(nsSocketTransport **); // get an owning reference to the transport
|
||||
nsresult Poll(PRFileDesc *sock, PRInt16 event);
|
||||
|
||||
protected:
|
||||
nsSocketTransport *mTransport;
|
||||
PRFileDesc *mSock;
|
||||
nsSocketTransport *mTransport; // strong reference
|
||||
PRLock *mTransportLock; // protects access to mTransport
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -396,6 +409,7 @@ protected:
|
|||
PRIntn mSuspendCount;
|
||||
PRPackedBool mCanceled;
|
||||
PRPackedBool mStartFired;
|
||||
PRPackedBool mStopFired;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1135,6 +1135,7 @@ nsresult nsHTTPHandler::RequestTransport(nsIURI* i_Uri,
|
|||
} /* for */
|
||||
} /* count > 0 */
|
||||
}
|
||||
nsCOMPtr<nsISocketTransport> socketTrans;
|
||||
// if we didn't find any from the keep-alive idlelist
|
||||
if (!trans)
|
||||
{
|
||||
|
@ -1188,18 +1189,25 @@ nsresult nsHTTPHandler::RequestTransport(nsIURI* i_Uri,
|
|||
trans->SetNotificationCallbacks(callbacks,
|
||||
(loadFlags & nsIChannel::LOAD_BACKGROUND));
|
||||
|
||||
nsCOMPtr<nsISocketTransport> socketTrans = do_QueryInterface(trans, &rv);
|
||||
socketTrans = do_QueryInterface(trans, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
socketTrans->SetSocketTimeout(mRequestTimeout);
|
||||
socketTrans->SetSocketConnectTimeout(mConnectTimeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
socketTrans = do_QueryInterface(trans);
|
||||
|
||||
// Put it in the table...
|
||||
// XXX this method incorrectly returns a bool
|
||||
rv = mTransportList->AppendElement(trans) ? NS_OK : NS_ERROR_FAILURE;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Ensure a reference to the underlying socket. This is done regardless
|
||||
// of whether or not this socket will be reused.
|
||||
if (socketTrans)
|
||||
socketTrans->SetReuseConnection(PR_TRUE);
|
||||
|
||||
*o_pTrans = trans;
|
||||
NS_IF_ADDREF(*o_pTrans);
|
||||
|
||||
|
@ -1285,11 +1293,17 @@ nsHTTPHandler::ReleaseTransport (nsITransport* i_pTrans ,
|
|||
PRInt32 port = -1;
|
||||
nsXPIDLCString host;
|
||||
|
||||
// Get the address of the socket transport
|
||||
{
|
||||
nsCOMPtr<nsISocketTransport> socketTrans = do_QueryInterface(i_pTrans);
|
||||
socketTrans->GetHost(getter_Copies(host));
|
||||
socketTrans->GetPort(&port);
|
||||
if (socketTrans) {
|
||||
// Get the address of the socket transport
|
||||
socketTrans->GetHost(getter_Copies(host));
|
||||
socketTrans->GetPort(&port);
|
||||
|
||||
// Drop one reference to the underlying socket. If this is NOT a keep-alive
|
||||
// connection, then this will cause the socket to close.
|
||||
socketTrans->SetReuseConnection(PR_FALSE);
|
||||
}
|
||||
}
|
||||
if (port == -1)
|
||||
GetDefaultPort (&port);
|
||||
|
|
Загрузка…
Ссылка в новой задаче