Fixes bug 66493. nsSocketTransport changes broke in-process PSM.

r=bryner,gagan,brendan,dougt sr=mscott
This commit is contained in:
darin%netscape.com 2001-01-27 01:28:00 +00:00
Родитель 2eccaab14e
Коммит d4b4bf4bce
5 изменённых файлов: 111 добавлений и 28 удалений

Просмотреть файл

@ -65,7 +65,10 @@ public:
NS_DECL_ISUPPORTS
nsSocketInputStream()
: mBytesRead(0), mSocketFD(nsnull) { NS_INIT_ISUPPORTS(); }
: mBytesRead(0),
mSocketFD(nsnull),
mWouldBlock(PR_FALSE)
{ NS_INIT_ISUPPORTS(); }
virtual ~nsSocketInputStream() {}
void SetSocketFD(PRFileDesc *aSocketFD) {
@ -77,6 +80,9 @@ public:
void ZeroBytesRead() {
mBytesRead = 0;
}
PRBool GotWouldBlock() {
return mWouldBlock;
}
//
// nsIInputStream implementation...
@ -98,11 +104,15 @@ public:
NS_PRECONDITION(mSocketFD, "null socket fd");
PRInt32 result = PR_Read(mSocketFD, aBuf, aCount);
LOG(("nsSocketTransport: PR_Read(count=%u) returned %d\n", aCount, result));
mWouldBlock = PR_FALSE;
nsresult rv = NS_OK;
if (result < 0) {
PRErrorCode code = PR_GetError();
if (PR_WOULD_BLOCK_ERROR == code)
if (PR_WOULD_BLOCK_ERROR == code) {
LOG(("nsSocketTransport: PR_Read() failed with PR_WOULD_BLOCK_ERROR\n"));
rv = NS_BASE_STREAM_WOULD_BLOCK;
mWouldBlock = PR_TRUE;
}
else {
LOG(("nsSocketTransport: PR_Read() failed [error=%x, os_error=%x]\n",
code, PR_GetOSError()));
@ -133,6 +143,7 @@ public:
protected:
PRUint32 mBytesRead;
PRFileDesc *mSocketFD;
PRBool mWouldBlock;
};
NS_IMPL_ISUPPORTS1(nsSocketInputStream, nsIInputStream)
@ -148,7 +159,10 @@ public:
NS_DECL_ISUPPORTS
nsSocketOutputStream()
: mBytesWritten(0), mSocketFD(nsnull) { NS_INIT_ISUPPORTS(); }
: mBytesWritten(0),
mSocketFD(nsnull),
mWouldBlock(PR_FALSE)
{ NS_INIT_ISUPPORTS(); }
virtual ~nsSocketOutputStream() {}
void SetSocketFD(PRFileDesc *aSocketFD) {
@ -160,6 +174,9 @@ public:
void ZeroBytesWritten() {
mBytesWritten = 0;
}
PRBool GotWouldBlock() {
return mWouldBlock;
}
//
// nsIInputStream implementation...
@ -174,12 +191,15 @@ public:
NS_PRECONDITION(mSocketFD, "null socket fd");
PRInt32 result = PR_Write(mSocketFD, aBuf, aCount);
LOG(("nsSocketTransport: PR_Write(count=%u) returned %d\n", aCount, result));
mWouldBlock = PR_FALSE;
nsresult rv = NS_OK;
if (result < 0) {
PRErrorCode code = PR_GetError();
if (PR_WOULD_BLOCK_ERROR == code)
if (PR_WOULD_BLOCK_ERROR == code) {
LOG(("nsSocketTransport: PR_Write() failed with PR_WOULD_BLOCK_ERROR\n"));
rv = NS_BASE_STREAM_WOULD_BLOCK;
else {
mWouldBlock = PR_TRUE;
} else {
LOG(("nsSocketTransport: PR_Write() failed [error=%x, os_error=%x]\n",
code, PR_GetOSError()));
rv = NS_ERROR_FAILURE;
@ -216,6 +236,7 @@ public:
protected:
PRUint32 mBytesWritten;
PRFileDesc *mSocketFD;
PRBool mWouldBlock;
};
NS_IMPL_ISUPPORTS1(nsSocketOutputStream, nsIOutputStream)
@ -761,8 +782,9 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
break;
case eSocketState_WaitReadWrite:
LOG(("nsSocketTransport: Transport [host=%s:%d this=%x] is in WaitReadWrite state.\n",
mHostName, mPort, this));
LOG(("nsSocketTransport: Transport [host=%s:%d this=%x] "
"is in WaitReadWrite state [readtype=%x writetype=%x status=%x].\n",
mHostName, mPort, this, GetReadType(), GetWriteType(), mStatus));
// Process the read request...
if (GetReadType() != eSocketRead_None) {
if (mBytesExpected == 0) {
@ -1259,7 +1281,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
//
if (mSelectFlags & PR_POLL_WRITE) {
LOG(("nsSocketTransport: READING [this=%x] busy waiting on read!\n", this));
PR_Sleep(50); // Don't starve the other threads either!!
PR_Sleep(10); // Don't starve the other threads either!!
} else {
LOG(("nsSocketTransport: READING [this=%x] listener would block; suspending self.\n", this));
mSuspendCount++;
@ -1276,7 +1298,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
PRUint32 total = mSocketInputStream->GetBytesRead();
mReadOffset += total;
if (0 == total) {
if ((0 == total) && !mSocketInputStream->GotWouldBlock()) {
LOG(("nsSocketTransport: READING [this=%x] done reading socket.\n", this));
mSelectFlags &= ~PR_POLL_READ;
}
@ -1289,7 +1311,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
rv = NS_BASE_STREAM_WOULD_BLOCK;
}
if (!(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
if (total && !(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
// we don't have content length info at the socket level
// just pass 0 through.
mEventSink->OnProgress(this, mReadContext, mReadOffset, 0);
@ -1442,7 +1464,7 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
//
if (mSelectFlags & PR_POLL_READ) {
LOG(("nsSocketTransport: WRITING [this=%x] busy waiting on write!\n", this));
PR_Sleep(50); // Don't starve the other threads either!!
PR_Sleep(10); // Don't starve the other threads either!!
} else {
LOG(("nsSocketTransport: WRITING [this=%x] provider would block; suspending self.\n", this));
mSuspendCount++;
@ -1459,12 +1481,12 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
PRUint32 total = mSocketOutputStream->GetBytesWritten();
mWriteOffset += total;
if (0 == total) {
LOG(("nsSocketTransport: READING [this=%x] done writing to socket.\n", this));
if ((0 == total) && !mSocketOutputStream->GotWouldBlock()) {
LOG(("nsSocketTransport: WRITING [this=%x] done writing to socket.\n", this));
mSelectFlags &= ~PR_POLL_WRITE;
}
else {
LOG(("nsSocketTransport: READING [this=%x] wrote %u bytes [offset=%u]\n",
LOG(("nsSocketTransport: WRITING [this=%x] wrote %u bytes [offset=%u]\n",
this, total, mWriteOffset));
//
// Stay in the write state
@ -1472,7 +1494,7 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
rv = NS_BASE_STREAM_WOULD_BLOCK;
}
if (!(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
if (total && !(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
// we don't have content length info at the socket level
// just pass 0 through.
mEventSink->OnProgress(this, mWriteContext, mWriteOffset, 0);

Просмотреть файл

@ -286,7 +286,7 @@ nsStreamListenerProxy::OnDataAvailable(nsIChannel *aChannel,
}
else if (bytesWritten == 0) {
LOG(("nsStreamListenerProxy: Copied zero bytes; not posting an event [chan=%x]\n", aChannel));
return NS_BASE_STREAM_CLOSED; // there was no more data to read!
return NS_OK;
}
}

Просмотреть файл

@ -31,14 +31,61 @@
extern PRLogModuleInfo* gFTPLog;
#endif /* PR_LOGGING */
//NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpControlConnection,
// nsIStreamListener,
// nsIStreamObserver);
class nsFtpStreamProvider : public nsIStreamProvider {
public:
NS_DECL_ISUPPORTS
nsFtpStreamProvider() {}
virtual ~nsFtpStreamProvider() {}
//
// nsIStreamObserver implementation ...
//
NS_IMETHODIMP OnStartRequest(nsIChannel *chan, nsISupports *ctxt) { return NS_OK; }
NS_IMETHODIMP OnStopRequest(nsIChannel *chan, nsISupports *ctxt, nsresult status, const PRUnichar *statusText) { return NS_OK; }
//
// nsIStreamProvider implementation ...
//
NS_IMETHODIMP OnDataWritable(nsIChannel *aChannel, nsISupports *aContext,
nsIOutputStream *aOutStream,
PRUint32 aOffset, PRUint32 aCount)
{
NS_ASSERTION(mInStream, "not initialized");
nsresult rv;
PRUint32 avail;
// Write whatever is available in the pipe. If the pipe is empty, then
// return NS_BASE_STREAM_WOULD_BLOCK; we will resume the write when there
// is more data.
rv = mInStream->Available(&avail);
if (NS_FAILED(rv)) return rv;
if (avail == 0) {
NS_STATIC_CAST(nsFtpControlConnection*, aContext)->mSuspendedWrite = PR_TRUE;
return NS_BASE_STREAM_WOULD_BLOCK;
}
PRUint32 bytesWritten;
return aOutStream->WriteFrom(mInStream, PR_MIN(avail, aCount), &bytesWritten);
}
nsCOMPtr<nsIInputStream> mInStream;
};
NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpStreamProvider,
nsIStreamProvider,
nsIStreamObserver)
//
// nsFtpControlConnection implementation ...
//
NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsFtpControlConnection,
nsIStreamListener,
nsIStreamObserver);
nsIStreamObserver)
NS_IMPL_THREADSAFE_ADDREF(nsFtpControlConnection);
nsrefcnt nsFtpControlConnection::Release(void)
@ -99,11 +146,15 @@ nsFtpControlConnection::Connect()
if (NS_FAILED(rv)) return rv;
// so that we can share the nsIStreamObserver implemention, we will be checking the context
// to indicate between the read and the write transport. We will be passing the a non-null
// context for the write, and a null context for the read.
nsCOMPtr<nsIStreamProvider> provider;
NS_NEWXPCOM(provider, nsFtpStreamProvider);
if (!provider) return NS_ERROR_OUT_OF_MEMORY;
rv = NS_AsyncWriteFromStream(mCPipe, inStream, NS_STATIC_CAST(nsIStreamObserver*, this), NS_STATIC_CAST(nsISupports*, this));
// setup the stream provider to get data from the pipe.
NS_STATIC_CAST(nsFtpStreamProvider*,
NS_STATIC_CAST(nsIStreamProvider*, provider))->mInStream = inStream;
rv = mCPipe->AsyncWrite(provider, NS_STATIC_CAST(nsISupports*, this));
if (NS_FAILED(rv)) return rv;
// get the ball rolling by reading on the control socket.
@ -139,8 +190,13 @@ nsFtpControlConnection::Write(nsCString& command)
PRUint32 len = command.Length();
PRUint32 cnt;
nsresult rv = mOutStream->Write(command.GetBuffer(), len, &cnt);
if (NS_SUCCEEDED(rv) && len==cnt)
if (NS_SUCCEEDED(rv) && len==cnt) {
if (mSuspendedWrite) {
mSuspendedWrite = PR_FALSE;
mCPipe->Resume();
}
return NS_OK;
}
return NS_ERROR_FAILURE;

Просмотреть файл

@ -54,6 +54,7 @@ public:
nsCAutoString mCwd; // what dir are we in
PRBool mList; // are we sending LIST or NLST
nsAutoString mPassword;
PRBool mSuspendedWrite;
private:
PRLock* mLock; // protects mListener.

Просмотреть файл

@ -693,6 +693,7 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
rv = reader(this, closure, writeBuf, *writeCount, writeBufLen, &readCount);
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount");
// XXX should not update counters if reader returned WOULD_BLOCK!!
writeBuf += readCount;
writeBufLen -= readCount;
*writeCount += readCount;
@ -703,8 +704,11 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
// call flush to notify the guy downstream, hoping that he'll somehow
// wake up the guy upstream to eventually produce more data for us.
nsresult rv2 = Flush();
if (/*rv2 == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv2))
if (NS_FAILED(rv2)) {
if (rv2 == NS_BASE_STREAM_WOULD_BLOCK)
rv = pipe->mCondition;
goto done;
}
// else we flushed, so go around again
continue;
}