зеркало из https://github.com/mozilla/gecko-dev.git
711 строки
16 KiB
C++
711 строки
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "nsNetStream.h"
|
|
#include "net.h"
|
|
#include "mktrace.h"
|
|
|
|
|
|
/* XXX: Declare NET_PollSockets(...) for the blocking stream hack... */
|
|
extern "C" {
|
|
XP_Bool NET_PollSockets(void);
|
|
};
|
|
|
|
|
|
NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID);
|
|
|
|
#define BUFFER_BLOCK_SIZE 8192
|
|
|
|
|
|
|
|
|
|
nsConnectionInfo::nsConnectionInfo(nsIURL *aURL,
|
|
nsNetlibStream *aStream,
|
|
nsIStreamListener *aNotify)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
pURL = aURL;
|
|
pNetStream = aStream;
|
|
pConsumer = aNotify;
|
|
pContainer = nsnull;
|
|
|
|
if (NULL != pURL) {
|
|
pURL->AddRef();
|
|
}
|
|
|
|
if (NULL != pNetStream) {
|
|
pNetStream->AddRef();
|
|
}
|
|
|
|
if (NULL != pConsumer) {
|
|
pConsumer->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(nsConnectionInfo,kISupportsIID);
|
|
|
|
|
|
nsConnectionInfo::~nsConnectionInfo()
|
|
{
|
|
TRACEMSG(("nsConnectionInfo is being destroyed...\n"));
|
|
|
|
if (NULL != pURL) {
|
|
pURL->Release();
|
|
}
|
|
|
|
if (NULL != pNetStream) {
|
|
pNetStream->Close();
|
|
pNetStream->Release();
|
|
}
|
|
|
|
if (NULL != pConsumer) {
|
|
pConsumer->Release();
|
|
}
|
|
|
|
if (nsnull != pContainer) {
|
|
NS_RELEASE(pContainer);
|
|
}
|
|
|
|
pURL = NULL;
|
|
pNetStream = NULL;
|
|
pConsumer = NULL;
|
|
pContainer = nsnull;
|
|
}
|
|
|
|
|
|
|
|
nsNetlibStream::nsNetlibStream(void)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
m_Lock = PR_NewMonitor();
|
|
m_bIsClosed = PR_FALSE;
|
|
}
|
|
|
|
|
|
NS_IMPL_ADDREF(nsNetlibStream)
|
|
NS_IMPL_RELEASE(nsNetlibStream)
|
|
|
|
nsresult nsNetlibStream::QueryInterface(const nsIID &aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID);
|
|
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
|
|
if (aIID.Equals(kIInputStreamIID)) {
|
|
*aInstancePtr = (void*) ((nsIInputStream*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kIOutputStreamIID)) {
|
|
*aInstancePtr = (void*) ((nsIOutputStream*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = ((nsISupports *)(nsIInputStream *)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
|
|
nsNetlibStream::~nsNetlibStream()
|
|
{
|
|
if (m_Lock) {
|
|
PR_DestroyMonitor(m_Lock);
|
|
m_Lock = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
nsresult nsNetlibStream::Close()
|
|
{
|
|
LockStream();
|
|
m_bIsClosed = PR_TRUE;
|
|
UnlockStream();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
nsBufferedStream::nsBufferedStream(void)
|
|
{
|
|
m_BufferLength = BUFFER_BLOCK_SIZE;
|
|
|
|
m_Buffer = new char[m_BufferLength];
|
|
/* If the allocation failed, mark the stream as closed... */
|
|
if (NULL == m_Buffer) {
|
|
m_bIsClosed = PR_TRUE;
|
|
m_BufferLength = 0;
|
|
}
|
|
|
|
m_DataLength = 0;
|
|
m_ReadOffset = m_WriteOffset = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
nsBufferedStream::~nsBufferedStream()
|
|
{
|
|
TRACEMSG(("nsBufferedStream is being destroyed...\n"));
|
|
|
|
if (m_Buffer) {
|
|
free(m_Buffer);
|
|
m_Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
PRInt32 nsBufferedStream::GetAvailableSpace(PRInt32 *aErrorCode)
|
|
{
|
|
PRInt32 size = 0;
|
|
|
|
if (m_bIsClosed) {
|
|
*aErrorCode = NS_BASE_STREAM_EOF;
|
|
} else {
|
|
*aErrorCode = NS_OK;
|
|
|
|
LockStream();
|
|
size = m_BufferLength - m_WriteOffset;
|
|
UnlockStream();
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
nsresult nsBufferedStream::GetLength(PRInt32 *aLength)
|
|
{
|
|
LockStream();
|
|
*aLength = m_WriteOffset;
|
|
UnlockStream();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsBufferedStream::Write(const char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aLen,
|
|
PRInt32 *aWriteCount)
|
|
{
|
|
PRInt32 bytesFree;
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
NS_PRECONDITION((m_WriteOffset >= m_ReadOffset), "Read past the end of buffer.");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
goto done;
|
|
} else if (m_bIsClosed) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
goto done;
|
|
}
|
|
|
|
if (!m_bIsClosed && aBuf) {
|
|
/* Grow the buffer if necessary */
|
|
bytesFree = m_BufferLength - m_WriteOffset;
|
|
if (aLen > bytesFree) {
|
|
char *newBuffer;
|
|
|
|
m_BufferLength += (((aLen - bytesFree) / BUFFER_BLOCK_SIZE)+1) * BUFFER_BLOCK_SIZE;
|
|
newBuffer = (char *)realloc(m_Buffer, m_BufferLength);
|
|
/* If the allocation failed, close the stream and free the buffer... */
|
|
if (NULL == newBuffer) {
|
|
m_bIsClosed = PR_TRUE;
|
|
free(m_Buffer);
|
|
m_Buffer = NULL;
|
|
m_BufferLength = 0;
|
|
|
|
goto done;
|
|
} else {
|
|
m_Buffer = newBuffer;
|
|
}
|
|
}
|
|
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
memcpy(&m_Buffer[m_WriteOffset], aBuf, aLen);
|
|
m_WriteOffset += aLen;
|
|
|
|
*aWriteCount = aLen;
|
|
m_DataLength += aLen;
|
|
}
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult nsBufferedStream::Read(char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aCount,
|
|
PRInt32 *aReadCount)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
NS_PRECONDITION((m_WriteOffset >= m_ReadOffset), "Read past the end of buffer.");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
*aReadCount = 0;
|
|
goto done;
|
|
} else if (m_bIsClosed && (0 == m_DataLength)) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
*aReadCount = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (m_Buffer && m_DataLength) {
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
/* Do not read more data than there is available... */
|
|
if (aCount > m_DataLength) {
|
|
aCount = m_DataLength;
|
|
}
|
|
|
|
memcpy(aBuf, &m_Buffer[m_ReadOffset], aCount);
|
|
m_ReadOffset += aCount;
|
|
|
|
*aReadCount = aCount;
|
|
m_DataLength -= aCount;
|
|
}
|
|
else
|
|
*aReadCount = 0;
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsAsyncStream::nsAsyncStream(PRInt32 buffer_size)
|
|
{
|
|
m_BufferLength = buffer_size;
|
|
|
|
m_Buffer = (char *)malloc(m_BufferLength);
|
|
/* If the allocation failed, mark the stream as closed... */
|
|
if (NULL == m_Buffer) {
|
|
m_bIsClosed = PR_TRUE;
|
|
m_BufferLength = 0;
|
|
}
|
|
|
|
m_DataLength = 0;
|
|
m_ReadOffset = m_WriteOffset = 0;
|
|
}
|
|
|
|
|
|
nsAsyncStream::~nsAsyncStream()
|
|
{
|
|
TRACEMSG(("nsAsyncStream is being destroyed...\n"));
|
|
|
|
if (m_Buffer) {
|
|
free(m_Buffer);
|
|
m_Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
PRInt32 nsAsyncStream::GetAvailableSpace(PRInt32 *aErrorCode)
|
|
{
|
|
PRInt32 size = 0;
|
|
|
|
if (m_bIsClosed) {
|
|
*aErrorCode = NS_BASE_STREAM_EOF;
|
|
} else {
|
|
*aErrorCode = NS_OK;
|
|
|
|
LockStream();
|
|
size = m_BufferLength - m_DataLength;
|
|
UnlockStream();
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
nsresult nsAsyncStream::GetLength(PRInt32 *aLength)
|
|
{
|
|
LockStream();
|
|
*aLength = m_DataLength;
|
|
UnlockStream();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsAsyncStream::Write(const char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aLen,
|
|
PRInt32 *aWriteCount)
|
|
{
|
|
PRInt32 bytesFree;
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
goto done;
|
|
} else if (m_bIsClosed) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
goto done;
|
|
}
|
|
|
|
if (!m_bIsClosed && aBuf) {
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
/* Do not store more data than there is space for... */
|
|
bytesFree = m_BufferLength - m_DataLength;
|
|
if (aLen > bytesFree) {
|
|
aLen = bytesFree;
|
|
}
|
|
|
|
/* Storing the data will cause m_WriteOffset to wrap */
|
|
if (m_WriteOffset + aLen > m_BufferLength) {
|
|
PRInt32 delta;
|
|
|
|
/* Store the first chunk through the end of the buffer */
|
|
delta = m_BufferLength - m_WriteOffset;
|
|
memcpy(&m_Buffer[m_WriteOffset], aBuf, delta);
|
|
|
|
/* Store the second chunk from the beginning of the buffer */
|
|
m_WriteOffset = aLen-delta;
|
|
memcpy(m_Buffer, &aBuf[delta], m_WriteOffset);
|
|
} else {
|
|
memcpy(&m_Buffer[m_WriteOffset], aBuf, aLen);
|
|
m_WriteOffset += aLen;
|
|
}
|
|
|
|
*aWriteCount = aLen;
|
|
m_DataLength += aLen;
|
|
}
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult nsAsyncStream::Read(char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aCount,
|
|
PRInt32 *aReadCount)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
*aReadCount = 0;
|
|
goto done;
|
|
} else if (m_bIsClosed && (0 == m_DataLength)) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
*aReadCount = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (m_Buffer && m_DataLength) {
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
/* Do not read more data than there is available... */
|
|
if (aCount > m_DataLength) {
|
|
aCount = m_DataLength;
|
|
}
|
|
|
|
/* Reading the data will cause m_ReadOffset to wrap */
|
|
if (m_ReadOffset + aCount > m_BufferLength) {
|
|
PRInt32 delta;
|
|
|
|
/* Read the first chunk through the end of the buffer */
|
|
delta = m_BufferLength - m_ReadOffset;
|
|
memcpy(aBuf, &m_Buffer[m_ReadOffset], delta);
|
|
|
|
/* Read the second chunk from the beginning of the buffer */
|
|
m_ReadOffset = aCount-delta;
|
|
memcpy(&aBuf[delta], m_Buffer, m_ReadOffset);
|
|
} else {
|
|
memcpy(aBuf, &m_Buffer[m_ReadOffset], aCount);
|
|
m_ReadOffset += aCount;
|
|
}
|
|
|
|
*aReadCount = aCount;
|
|
m_DataLength -= aCount;
|
|
}
|
|
else
|
|
*aReadCount = 0;
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nsBlockingStream::nsBlockingStream()
|
|
{
|
|
m_BufferLength = BUFFER_BLOCK_SIZE;
|
|
|
|
m_Buffer = (char *)malloc(m_BufferLength);
|
|
/* If the allocation failed, mark the stream as closed... */
|
|
if (NULL == m_Buffer) {
|
|
m_bIsClosed = PR_TRUE;
|
|
m_BufferLength = 0;
|
|
}
|
|
|
|
m_DataLength = 0;
|
|
m_ReadOffset = m_WriteOffset = 0;
|
|
}
|
|
|
|
|
|
nsBlockingStream::~nsBlockingStream()
|
|
{
|
|
TRACEMSG(("nsBlockingStream is being destroyed...\n"));
|
|
|
|
if (m_Buffer) {
|
|
free(m_Buffer);
|
|
m_Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
PRInt32 nsBlockingStream::GetAvailableSpace(PRInt32 *aErrorCode)
|
|
{
|
|
PRInt32 size = 0;
|
|
|
|
if (m_bIsClosed) {
|
|
*aErrorCode = NS_BASE_STREAM_EOF;
|
|
} else {
|
|
*aErrorCode = NS_OK;
|
|
|
|
LockStream();
|
|
size = m_BufferLength - m_DataLength;
|
|
UnlockStream();
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
nsresult nsBlockingStream::GetLength(PRInt32 *aLength)
|
|
{
|
|
LockStream();
|
|
*aLength = m_DataLength;
|
|
UnlockStream();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsBlockingStream::Write(const char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aLen,
|
|
PRInt32 *aWriteCount)
|
|
{
|
|
PRInt32 bytesFree;
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
goto done;
|
|
} else if (m_bIsClosed) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
goto done;
|
|
}
|
|
|
|
if (!m_bIsClosed && aBuf) {
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
/* Do not store more data than there is space for... */
|
|
bytesFree = m_BufferLength - m_DataLength;
|
|
if (aLen > bytesFree) {
|
|
aLen = bytesFree;
|
|
}
|
|
|
|
/* Storing the data will cause m_WriteOffset to wrap */
|
|
if (m_WriteOffset + aLen > m_BufferLength) {
|
|
PRInt32 delta;
|
|
|
|
/* Store the first chunk through the end of the buffer */
|
|
delta = m_BufferLength - m_WriteOffset;
|
|
memcpy(&m_Buffer[m_WriteOffset], aBuf, delta);
|
|
|
|
/* Store the second chunk from the beginning of the buffer */
|
|
m_WriteOffset = aLen-delta;
|
|
memcpy(m_Buffer, &aBuf[delta], m_WriteOffset);
|
|
} else {
|
|
memcpy(&m_Buffer[m_WriteOffset], aBuf, aLen);
|
|
m_WriteOffset += aLen;
|
|
}
|
|
|
|
*aWriteCount = aLen;
|
|
m_DataLength += aLen;
|
|
}
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult nsBlockingStream::Read(char *aBuf,
|
|
PRInt32 aOffset,
|
|
PRInt32 aCount,
|
|
PRInt32 *aReadCount)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
LockStream();
|
|
|
|
*aReadCount = 0;
|
|
|
|
NS_PRECONDITION((m_Buffer || m_bIsClosed), "m_Buffer is NULL!");
|
|
|
|
/* Check for initial error conditions... */
|
|
if (NULL == aBuf) {
|
|
rv = NS_BASE_STREAM_ILLEGAL_ARGS;
|
|
goto done;
|
|
} else if (m_bIsClosed && (0 == m_DataLength)) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
goto done;
|
|
}
|
|
|
|
if (m_Buffer) {
|
|
/* Skip the appropriate number of bytes in the input buffer... */
|
|
if (aOffset) {
|
|
aBuf += aOffset;
|
|
}
|
|
|
|
/* Not enough data is available... Must block. */
|
|
if (aCount > m_DataLength) {
|
|
UnlockStream();
|
|
do {
|
|
NET_PollSockets();
|
|
*aReadCount += ReadBuffer(aBuf + *aReadCount, aCount - *aReadCount);
|
|
/* XXX m_bIsClosed is checked outside of the lock! */
|
|
} while ((aCount > *aReadCount) && !m_bIsClosed);
|
|
LockStream();
|
|
/*
|
|
* It is possible that the stream was closed during
|
|
* NET_PollSockets(...)... In this case, return EOF if no data
|
|
* is available...
|
|
*/
|
|
if ((0 == *aReadCount) && m_bIsClosed) {
|
|
rv = NS_BASE_STREAM_EOF;
|
|
}
|
|
} else {
|
|
*aReadCount = ReadBuffer(aBuf, aCount);
|
|
}
|
|
}
|
|
|
|
done:
|
|
UnlockStream();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
PRInt32 nsBlockingStream::ReadBuffer(char *aBuf, PRInt32 aCount)
|
|
{
|
|
PRInt32 bytesRead = 0;
|
|
|
|
LockStream();
|
|
|
|
/* Do not read more data than there is available... */
|
|
if (aCount > m_DataLength) {
|
|
aCount = m_DataLength;
|
|
}
|
|
|
|
/* Reading the data will cause m_ReadOffset to wrap */
|
|
if (m_ReadOffset + aCount > m_BufferLength) {
|
|
PRInt32 delta;
|
|
|
|
/* Read the first chunk through the end of the buffer */
|
|
delta = m_BufferLength - m_ReadOffset;
|
|
memcpy(aBuf, &m_Buffer[m_ReadOffset], delta);
|
|
|
|
/* Read the second chunk from the beginning of the buffer */
|
|
m_ReadOffset = aCount-delta;
|
|
memcpy(&aBuf[delta], m_Buffer, m_ReadOffset);
|
|
} else {
|
|
memcpy(aBuf, &m_Buffer[m_ReadOffset], aCount);
|
|
m_ReadOffset += aCount;
|
|
}
|
|
|
|
bytesRead = aCount;
|
|
m_DataLength -= aCount;
|
|
|
|
UnlockStream();
|
|
|
|
return bytesRead;
|
|
}
|
|
|