зеркало из https://github.com/mozilla/pjs.git
First pass at a socket transport implementation...
This commit is contained in:
Родитель
6064f90d77
Коммит
722b00f7fa
|
@ -23,6 +23,7 @@ EXPORTS = \
|
|||
nsICancelable.h \
|
||||
nsIConnectionGroup.h \
|
||||
nsIFileTransportService.h \
|
||||
nsISocketTransportService.h \
|
||||
nsINetService.h \
|
||||
nsIProtocolConnection.h \
|
||||
nsIProtocolHandler.h \
|
||||
|
|
|
@ -23,32 +23,32 @@
|
|||
|
||||
class nsITransport;
|
||||
|
||||
// XXX regenerate:
|
||||
#define NS_ISOCKETTRANSPORTSERVICE_IID \
|
||||
{ /* 2355dca0-ea35-11d2-931b-00104ba0fd40 */ \
|
||||
0x2355dca0, \
|
||||
0xea35, \
|
||||
{ /* 9610f120-ef12-11d2-92b6-00105a1b0d64 */ \
|
||||
0x9610f120, \
|
||||
0xef12, \
|
||||
0x11d2, \
|
||||
{0x93, 0x1b, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
|
||||
{0x92, 0xb6, 0x00, 0x10, 0x5a, 0x1b, 0x0d, 0x64} \
|
||||
}
|
||||
|
||||
// XXX regenerate:
|
||||
#define NS_SOCKETTRANSPORTSERVICE_CID \
|
||||
{ /* 2bb2b250-ea35-11d2-931b-00104ba0fd40 */ \
|
||||
0x2bb2b250, \
|
||||
0xea35, \
|
||||
{ /* c07e81e0-ef12-11d2-92b6-00105a1b0d64 */ \
|
||||
0xc07e81e0, \
|
||||
0xef12, \
|
||||
0x11d2, \
|
||||
{0x93, 0x1b, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
|
||||
{0x92, 0xb6, 0x00, 0x10, 0x5a, 0x1b, 0x0d, 0x64} \
|
||||
}
|
||||
|
||||
|
||||
class nsISocketTransportService : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISOCKETTRANSPORTSERVICE_IID);
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISOCKETTRANSPORTSERVICE_IID);
|
||||
|
||||
NS_IMETHOD CreateTransport(const char* host, PRInt32 port,
|
||||
nsITransport* *result) = 0;
|
||||
NS_IMETHOD CreateTransport(const char* host, PRInt32 port,
|
||||
nsITransport* *result) = 0;
|
||||
|
||||
NS_IMETHOD Shutdown(void) = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define nsIStreamObserver_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "plevent.h"
|
||||
|
||||
class nsIUrl;
|
||||
class nsIString;
|
||||
|
@ -64,6 +65,15 @@ public:
|
|||
|
||||
};
|
||||
|
||||
// An asynchronous stream observer is used to ship data over to another thread specified
|
||||
// by the thread's event queue. The receiver stream observer is then used to receive
|
||||
// the notifications on the other thread.
|
||||
extern nsresult
|
||||
NS_NewAsyncStreamObserver(nsIStreamObserver* *result,
|
||||
PLEventQueue* eventQueue,
|
||||
nsIStreamObserver* receiver);
|
||||
|
||||
|
||||
// Generic status codes for OnStopBinding:
|
||||
#define NS_BINDING_SUCCEEDED NS_OK
|
||||
#define NS_BINDING_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 1)
|
||||
|
|
|
@ -25,6 +25,7 @@ EXPORTS = \
|
|||
nsConnectionGroup.h \
|
||||
nsNetService.h \
|
||||
nsFileTransportService.h \
|
||||
nsSocketTransportService.h \
|
||||
nsUrl.h \
|
||||
$(NULL)
|
||||
|
||||
|
@ -34,6 +35,8 @@ CPP_OBJS = \
|
|||
.\$(OBJDIR)\nsSyncStreamListener.obj \
|
||||
.\$(OBJDIR)\nsFileTransport.obj \
|
||||
.\$(OBJDIR)\nsFileTransportService.obj \
|
||||
.\$(OBJDIR)\nsSocketTransport.obj \
|
||||
.\$(OBJDIR)\nsSocketTransportService.obj \
|
||||
.\$(OBJDIR)\nsNetService.obj \
|
||||
.\$(OBJDIR)\nsUrl.obj \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,672 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "nspr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nscore.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsSocketTransport.h"
|
||||
#include "nsSocketTransportService.h"
|
||||
|
||||
//
|
||||
// This is the State table which maps current state to next state
|
||||
// for each socket operation...
|
||||
//
|
||||
nsSocketState gStateTable[eSocketOperation_Max][eSocketState_Max] = {
|
||||
// eSocketOperation_None:
|
||||
{
|
||||
eSocketState_Error, // Created -> Error
|
||||
eSocketState_Error, // WaitDNS -> Error
|
||||
eSocketState_Error, // Closed -> Error
|
||||
eSocketState_Error, // WaitConnect -> Error
|
||||
eSocketState_Error, // Connected -> Error
|
||||
eSocketState_Error, // WaitRead -> Error
|
||||
eSocketState_Error, // WaitWrite -> Error
|
||||
eSocketState_Error, // Done -> Error
|
||||
eSocketState_Error, // Timeout -> Error
|
||||
eSocketState_Error // Error -> Error
|
||||
},
|
||||
// eSocketOperation_Connect:
|
||||
{
|
||||
eSocketState_WaitDNS, // Created -> WaitDNS
|
||||
eSocketState_Closed, // WaitDNS -> Closed
|
||||
eSocketState_WaitConnect, // Closed -> WaitConnect
|
||||
eSocketState_Connected, // WaitConnect -> Connected
|
||||
eSocketState_Connected, // Connected -> Done
|
||||
eSocketState_Error, // WaitRead -> Error
|
||||
eSocketState_Error, // WaitWrite -> Error
|
||||
eSocketState_Connected, // Done -> Connected
|
||||
eSocketState_Error, // Timeout -> Error
|
||||
eSocketState_Error // Error -> Error
|
||||
},
|
||||
// eSocketOperation_Read:
|
||||
{
|
||||
eSocketState_WaitDNS, // Created -> WaitDNS
|
||||
eSocketState_Closed, // WaitDNS -> Closed
|
||||
eSocketState_WaitConnect, // Closed -> WaitConnect
|
||||
eSocketState_Connected, // WaitConenct -> Connected
|
||||
eSocketState_WaitRead, // Connected -> WaitRead
|
||||
eSocketState_Done, // WaitRead -> Done
|
||||
eSocketState_Error, // WaitWrite -> Error
|
||||
eSocketState_Connected, // Done -> Connected
|
||||
eSocketState_Error, // Timeout -> Error
|
||||
eSocketState_Error // Error -> Error
|
||||
},
|
||||
// eSocketOperation_Write:
|
||||
{
|
||||
eSocketState_WaitDNS, // Created -> WaitDNS
|
||||
eSocketState_Closed, // WaitDNS -> Closed
|
||||
eSocketState_WaitConnect, // Closed -> WaitConnect
|
||||
eSocketState_Connected, // WaitConenct -> Connected
|
||||
eSocketState_WaitWrite, // Connected -> WaitWrite
|
||||
eSocketState_Error, // WaitRead -> Error
|
||||
eSocketState_Done, // WaitWrite -> Done
|
||||
eSocketState_Connected, // Done -> Connected
|
||||
eSocketState_Error, // Timeout -> Error
|
||||
eSocketState_Error // Error -> Error
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the timeout value (in milliseconds) for calls to PR_Connect(...).
|
||||
//
|
||||
// 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 = -1;
|
||||
|
||||
//
|
||||
// This is the global buffer used by all nsSocketTransport instances when
|
||||
// reading from or writing to the network.
|
||||
//
|
||||
#define MAX_IO_BUFFER_SIZE 8192
|
||||
|
||||
static char gIOBuffer[MAX_IO_BUFFER_SIZE];
|
||||
|
||||
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
||||
|
||||
nsSocketTransport::nsSocketTransport()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
PR_INIT_CLIST(this);
|
||||
|
||||
mHostName = nsnull;
|
||||
mPort = 0;
|
||||
mSocketFD = nsnull;
|
||||
|
||||
mCurrentState = eSocketState_Created;
|
||||
mOperation = eSocketOperation_None;
|
||||
mSelectFlags = 0;
|
||||
|
||||
mReadStream = nsnull;
|
||||
mWriteStream = nsnull;
|
||||
mListener = nsnull;
|
||||
mContext = nsnull;
|
||||
mService = nsnull;
|
||||
|
||||
//
|
||||
// Set up Internet defaults...
|
||||
//
|
||||
memset(&mNetAddress, 0, sizeof(mNetAddress));
|
||||
PR_InitializeNetAddr(PR_IpAddrNull, 0, &mNetAddress);
|
||||
|
||||
//
|
||||
// Initialize the global connect timeout value if necessary...
|
||||
//
|
||||
if (0 == gTimeoutIsInitialized) {
|
||||
gConnectTimeout = PR_MillisecondsToInterval(CONNECT_TIMEOUT_IN_MS);
|
||||
gTimeoutIsInitialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsSocketTransport::~nsSocketTransport()
|
||||
{
|
||||
NS_IF_RELEASE(mContext);
|
||||
NS_IF_RELEASE(mListener);
|
||||
NS_IF_RELEASE(mReadStream);
|
||||
NS_IF_RELEASE(mWriteStream);
|
||||
NS_IF_RELEASE(mService);
|
||||
|
||||
if (mHostName) {
|
||||
PR_Free(mHostName);
|
||||
}
|
||||
|
||||
if (mSocketFD) {
|
||||
PR_Close(mSocketFD);
|
||||
mSocketFD = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::Init(nsSocketTransportService* aService,
|
||||
const char* aHost,
|
||||
PRInt32 aPort)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mService = aService;
|
||||
NS_ADDREF(mService);
|
||||
|
||||
mPort = aPort;
|
||||
if (aHost) {
|
||||
// Copy the host name...
|
||||
//
|
||||
// XXX: This is so evil! Since this is a char* it must be freed with
|
||||
// PR_Free(...) NOT delete[] like PRUnichar* buffers...
|
||||
//
|
||||
mHostName = nsCRT::strdup(aHost);
|
||||
if (!mHostName) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
// aHost was nsnull...
|
||||
else {
|
||||
rv = NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
while ((eSocketOperation_None != mOperation) && (rv == NS_OK))
|
||||
{
|
||||
switch (mCurrentState) {
|
||||
case eSocketState_Created:
|
||||
case eSocketState_Closed:
|
||||
break;
|
||||
|
||||
case eSocketState_Connected:
|
||||
if (mListener) {
|
||||
mListener->OnStartBinding(mContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case eSocketState_Done:
|
||||
if (mListener) {
|
||||
mListener->OnStopBinding(mContext, rv, nsnull);
|
||||
}
|
||||
NS_IF_RELEASE(mContext);
|
||||
mCurrentState = gStateTable[mOperation][mCurrentState];
|
||||
mOperation = eSocketOperation_None;
|
||||
continue;
|
||||
|
||||
case eSocketState_WaitDNS:
|
||||
rv = doResolveHost();
|
||||
break;
|
||||
|
||||
case eSocketState_WaitConnect:
|
||||
rv = doConnection(aSelectFlags);
|
||||
break;
|
||||
|
||||
case eSocketState_WaitRead:
|
||||
rv = doRead(aSelectFlags);
|
||||
break;
|
||||
|
||||
case eSocketState_WaitWrite:
|
||||
rv = doWrite(aSelectFlags);
|
||||
break;
|
||||
|
||||
case eSocketState_Timeout:
|
||||
NS_ASSERTION(0, "Unexpected state...");
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
|
||||
case eSocketState_Error:
|
||||
NS_ASSERTION(0, "Unexpected Error...");
|
||||
}
|
||||
//
|
||||
// If the current state has successfully completed, then move to the
|
||||
// next state for the current operation...
|
||||
//
|
||||
if (NS_OK == rv) {
|
||||
mCurrentState = gStateTable[mOperation][mCurrentState];
|
||||
//
|
||||
// Any select flags are *only* valid the first time through the loop...
|
||||
//
|
||||
aSelectFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::doResolveHost(void)
|
||||
{
|
||||
PRStatus status;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(eSocketState_WaitDNS == mCurrentState, "Wrong state.");
|
||||
//
|
||||
// Initialize the port used for the connection...
|
||||
//
|
||||
// XXX: The list of ports must be restricted - see net_bad_ports_table[] in
|
||||
// mozilla/network/main/mkconect.c
|
||||
//
|
||||
mNetAddress.inet.port = PR_htons(mPort);
|
||||
|
||||
//
|
||||
// Resolve the address of the given host...
|
||||
//
|
||||
char dbbuf[PR_NETDB_BUF_SIZE];
|
||||
PRHostEnt hostEnt;
|
||||
|
||||
status = PR_GetHostByName(mHostName, dbbuf, sizeof(dbbuf), &hostEnt);
|
||||
if (PR_SUCCESS == status) {
|
||||
if (hostEnt.h_addr_list) {
|
||||
memcpy(&mNetAddress.inet.ip, hostEnt.h_addr_list[0],
|
||||
sizeof(mNetAddress.inet.ip));
|
||||
} else {
|
||||
// XXX: What should happen here? The GetHostByName(...) succeeded but
|
||||
// there are *no* A records...
|
||||
}
|
||||
}
|
||||
// DNS lookup failed...
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::doConnection(PRInt16 aSelectFlags)
|
||||
{
|
||||
PRStatus status;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(eSocketState_WaitConnect == mCurrentState, "Wrong state.");
|
||||
//
|
||||
// Step 1:
|
||||
// Create a new TCP socket structure (if necessary)...
|
||||
//
|
||||
if (!mSocketFD) {
|
||||
mSocketFD = PR_NewTCPSocket();
|
||||
if (mSocketFD) {
|
||||
PRSocketOptionData opt;
|
||||
|
||||
// Make the socket non-blocking...
|
||||
opt.option = PR_SockOpt_Nonblocking;
|
||||
opt.value.non_blocking = PR_TRUE;
|
||||
status = PR_SetSocketOption(mSocketFD, &opt);
|
||||
if (PR_SUCCESS != status) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// XXX: Is this still necessary?
|
||||
#if defined(XP_WIN16) || (defined(XP_OS2) && !defined(XP_OS2_DOUGSOCK))
|
||||
opt.option = PR_SockOpt_Linger;
|
||||
opt.value.linger.polarity = PR_TRUE;
|
||||
opt.value.linger.linger = PR_INTERVAL_NO_WAIT;
|
||||
PR_SetSocketOption(*sock, &opt);
|
||||
#endif /* XP_WIN16 || XP_OS2*/
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Step 2:
|
||||
// Initiate the connect() to the host...
|
||||
//
|
||||
// This is only done the first time doConnection(...) is called.
|
||||
//
|
||||
if (NS_SUCCEEDED(rv) && (0 == aSelectFlags)) {
|
||||
status = PR_Connect(mSocketFD, &mNetAddress, gConnectTimeout);
|
||||
if (PR_SUCCESS != status) {
|
||||
PRErrorCode code = PR_GetError();
|
||||
//
|
||||
// If the PR_Connect(...) would block, then return WOULD_BLOCK...
|
||||
// It is the callers responsibility to place the transport on the
|
||||
// select list of the transport thread...
|
||||
//
|
||||
if ((PR_WOULD_BLOCK_ERROR == code) ||
|
||||
(PR_IN_PROGRESS_ERROR == code)) {
|
||||
|
||||
// Set up the select flags for connect...
|
||||
mSelectFlags = (PR_POLL_READ | PR_POLL_EXCEPT | PR_POLL_WRITE);
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
//
|
||||
// If the socket is already connected, then return success...
|
||||
//
|
||||
else if (PR_IS_CONNECTED_ERROR == code) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
//
|
||||
// The connection was refused...
|
||||
//
|
||||
else {
|
||||
// Connection refused...
|
||||
// XXX: what should the next state be?
|
||||
mCurrentState = eSocketState_Error;
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Step 3:
|
||||
// Process the flags returned by PR_Poll() if any...
|
||||
//
|
||||
else if (NS_SUCCEEDED(rv) && aSelectFlags) {
|
||||
if (PR_POLL_EXCEPT & aSelectFlags) {
|
||||
// XXX: what should the next state be?
|
||||
mCurrentState = eSocketState_Error;
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
//
|
||||
// The connection was successful...
|
||||
//
|
||||
else if (PR_POLL_WRITE & aSelectFlags) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::doRead(PRInt16 aSelectFlags)
|
||||
{
|
||||
PRUint32 size, bytesWritten, totalBytesWritten;
|
||||
PRInt32 len;
|
||||
PRErrorCode code;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(eSocketState_WaitRead == mCurrentState, "Wrong state.");
|
||||
|
||||
totalBytesWritten = 0;
|
||||
do {
|
||||
//
|
||||
// Determine how much space is available in the input stream...
|
||||
//
|
||||
// Since, the data is being read into a global buffer from the net, unless
|
||||
// it can all be pushed into the stream it will be lost!
|
||||
//
|
||||
mReadStream->GetLength(&size);
|
||||
size = MAX_IO_BUFFER_SIZE - size;
|
||||
if (size > MAX_IO_BUFFER_SIZE) {
|
||||
size = MAX_IO_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
len = PR_Read(mSocketFD, gIOBuffer, size);
|
||||
if (len > 0) {
|
||||
rv = mReadStream->Fill(gIOBuffer, len, &bytesWritten);
|
||||
NS_ASSERTION(bytesWritten == (PRUint32)len, "Data was lost during read.");
|
||||
|
||||
totalBytesWritten += bytesWritten;
|
||||
}
|
||||
//
|
||||
// The read operation has completed...
|
||||
//
|
||||
else if (len == 0) {
|
||||
//
|
||||
// Notify the listener that the read operation has completed...
|
||||
//
|
||||
//mListener->OnStopBinding(mContext, rv, nsnull);
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
// Error...
|
||||
else {
|
||||
code = PR_GetError();
|
||||
|
||||
if (PR_WOULD_BLOCK_ERROR == code) {
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// There is no room in the input stream for more data... Give the
|
||||
// consumer more time to empty the stream...
|
||||
//
|
||||
else {
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
} while (NS_OK == rv);
|
||||
|
||||
if (bytesWritten) {
|
||||
mListener->OnDataAvailable(mContext, mReadStream, bytesWritten);
|
||||
}
|
||||
|
||||
//
|
||||
// Set up the select flags for connect...
|
||||
//
|
||||
if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
|
||||
mSelectFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::doWrite(PRInt16 aSelectFlags)
|
||||
{
|
||||
PRUint32 size, bytesRead;
|
||||
PRInt32 len;
|
||||
PRErrorCode code;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(eSocketState_WaitWrite == mCurrentState, "Wrong state.");
|
||||
|
||||
do {
|
||||
rv = mWriteStream->Read(gIOBuffer, sizeof(gIOBuffer), &bytesRead);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (bytesRead > 0) {
|
||||
len = PR_Write(mSocketFD, gIOBuffer, bytesRead);
|
||||
if (len < 0) {
|
||||
code = PR_GetError();
|
||||
|
||||
if (PR_WOULD_BLOCK_ERROR == code) {
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// The write operation has completed...
|
||||
//
|
||||
else if (bytesRead == 0) {
|
||||
//
|
||||
// Notify the listener that the write operation has completed...
|
||||
//
|
||||
//mListener->OnStopBinding(mContext, rv, nsnull);
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(NS_OK == rv);
|
||||
|
||||
//
|
||||
// Set up the select flags for connect...
|
||||
//
|
||||
if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
|
||||
mSelectFlags = (PR_POLL_WRITE | PR_POLL_EXCEPT);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransport::CloseConnection(void)
|
||||
{
|
||||
PRStatus status;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(mSocketFD, "Socket does not exist");
|
||||
|
||||
status = PR_Close(mSocketFD);
|
||||
if (PR_SUCCESS != status) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
mSocketFD = nsnull;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCurrentState = eSocketState_Closed;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsISupports implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsSocketTransport, nsITransport::GetIID());
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsICancelable implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::Cancel(void)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::Suspend(void)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::Resume(void)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsITransport implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::AsyncRead(nsISupports* aContext,
|
||||
PLEventQueue* aAppEventQueue,
|
||||
nsIStreamListener* aListener)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (eSocketOperation_None != mOperation) {
|
||||
// XXX: This should be NS_ERROR_IN_PROGRESS...
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !mReadStream) {
|
||||
rv = NS_NewByteBufferInputStream(&mReadStream, PR_FALSE,
|
||||
MAX_IO_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_IF_RELEASE(mContext);
|
||||
mContext = aContext;
|
||||
NS_IF_ADDREF(mContext);
|
||||
|
||||
NS_IF_RELEASE(mListener);
|
||||
rv = NS_NewAsyncStreamListener(&mListener, aAppEventQueue, aListener);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mOperation = eSocketOperation_Read;
|
||||
|
||||
mService->AddToWorkQ(this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::AsyncWrite(nsIInputStream* aFromStream,
|
||||
nsISupports* aContext,
|
||||
PLEventQueue* aAppEventQueue,
|
||||
nsIStreamObserver* aObserver)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (eSocketOperation_None != mOperation) {
|
||||
// XXX: This should be NS_ERROR_IN_PROGRESS...
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_IF_RELEASE(mWriteStream);
|
||||
mWriteStream = aFromStream;
|
||||
NS_ADDREF(mWriteStream);
|
||||
|
||||
NS_IF_RELEASE(mContext);
|
||||
mContext = aContext;
|
||||
NS_IF_ADDREF(mContext);
|
||||
|
||||
NS_IF_RELEASE(mListener);
|
||||
nsIStreamObserver* aListener;
|
||||
rv = NS_NewAsyncStreamObserver(&aListener, aAppEventQueue, aObserver);
|
||||
// XXX: This is really evil...
|
||||
mListener = (nsIStreamListener*)aListener;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mOperation = eSocketOperation_Write;
|
||||
mService->AddToWorkQ(this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::OpenInputStream(nsIInputStream* *result)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::OpenOutputStream(nsIOutputStream* *result)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
#ifndef nsSocketTransport_h___
|
||||
#define nsSocketTransport_h___
|
||||
|
||||
#include "prclist.h"
|
||||
#include "prio.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
#include "nsITransport.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
|
||||
enum nsSocketState {
|
||||
eSocketState_Created = 0,
|
||||
eSocketState_WaitDNS = 1,
|
||||
eSocketState_Closed = 2,
|
||||
eSocketState_WaitConnect = 3,
|
||||
eSocketState_Connected = 4,
|
||||
eSocketState_WaitRead = 5,
|
||||
eSocketState_WaitWrite = 6,
|
||||
eSocketState_Done = 7,
|
||||
eSocketState_Timeout = 8,
|
||||
eSocketState_Error = 9,
|
||||
eSocketState_Max = 10
|
||||
};
|
||||
|
||||
enum nsSocketOperation {
|
||||
eSocketOperation_None = 0,
|
||||
eSocketOperation_Connect = 1,
|
||||
eSocketOperation_Read = 2,
|
||||
eSocketOperation_Write = 3,
|
||||
eSocketOperation_Max = 4
|
||||
};
|
||||
|
||||
|
||||
class nsSocketTransportService;
|
||||
|
||||
class nsSocketTransport : public PRCList,
|
||||
public nsITransport
|
||||
{
|
||||
public:
|
||||
// nsISupports methods:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsICancelable methods:
|
||||
NS_IMETHOD Cancel(void);
|
||||
NS_IMETHOD Suspend(void);
|
||||
NS_IMETHOD Resume(void);
|
||||
|
||||
// nsITransport methods:
|
||||
NS_IMETHOD AsyncRead(nsISupports* context,
|
||||
PLEventQueue* appEventQueue,
|
||||
nsIStreamListener* listener);
|
||||
NS_IMETHOD AsyncWrite(nsIInputStream* fromStream,
|
||||
nsISupports* context,
|
||||
PLEventQueue* appEventQueue,
|
||||
nsIStreamObserver* observer);
|
||||
NS_IMETHOD OpenInputStream(nsIInputStream* *result);
|
||||
NS_IMETHOD OpenOutputStream(nsIOutputStream* *result);
|
||||
|
||||
|
||||
// nsSocketTransport methods:
|
||||
nsSocketTransport();
|
||||
virtual ~nsSocketTransport();
|
||||
|
||||
nsresult Init(nsSocketTransportService* aService,
|
||||
const char* aHost,
|
||||
PRInt32 aPort);
|
||||
nsresult Process(PRInt16 aSelectFlags);
|
||||
|
||||
nsresult doConnection(PRInt16 aSelectFlags);
|
||||
nsresult doResolveHost(void);
|
||||
nsresult doRead(PRInt16 aSelectFlags);
|
||||
nsresult doWrite(PRInt16 aSelectFlags);
|
||||
|
||||
nsresult CloseConnection(void);
|
||||
|
||||
PRFileDesc* GetSocket(void) { return mSocketFD; }
|
||||
PRInt16 GetSelectFlags(void) { return mSelectFlags; }
|
||||
|
||||
protected:
|
||||
nsSocketState mCurrentState;
|
||||
nsSocketOperation mOperation;
|
||||
|
||||
PRFileDesc* mSocketFD;
|
||||
PRNetAddr mNetAddress;
|
||||
PRInt16 mSelectFlags;
|
||||
|
||||
char* mHostName;
|
||||
PRInt32 mPort;
|
||||
|
||||
nsISupports* mContext;
|
||||
nsIStreamListener* mListener;
|
||||
nsIByteBufferInputStream* mReadStream;
|
||||
nsIInputStream* mWriteStream;
|
||||
|
||||
nsSocketTransportService* mService;
|
||||
};
|
||||
|
||||
#endif /* nsSocketTransport_h___ */
|
|
@ -0,0 +1,449 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "nsSocketTransportService.h"
|
||||
#include "nsSocketTransport.h"
|
||||
|
||||
|
||||
#define MAX_OPEN_CONNECTIONS 10
|
||||
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
||||
|
||||
nsSocketTransportService::nsSocketTransportService()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
PR_INIT_CLIST(&mWorkQ);
|
||||
|
||||
mThread = nsnull;
|
||||
mThreadEvent = nsnull;
|
||||
mThreadLock = nsnull;
|
||||
|
||||
mSelectFDSet = nsnull;
|
||||
mSelectFDSetCount = 0;
|
||||
|
||||
mActiveTransportList = nsnull;
|
||||
|
||||
mThreadRunning = PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
nsSocketTransportService::~nsSocketTransportService()
|
||||
{
|
||||
//
|
||||
// It is impossible for the nsSocketTransportService to be deleted while
|
||||
// the transport thread is running because it holds a reference to the
|
||||
// nsIRunnable (ie. the nsSocketTransportService instance)...
|
||||
//
|
||||
NS_ASSERTION(!mThread && !mThreadRunning,
|
||||
"The socket transport thread is still running...");
|
||||
|
||||
if (mSelectFDSet) {
|
||||
PR_Free(mSelectFDSet);
|
||||
mSelectFDSet = nsnull;
|
||||
}
|
||||
|
||||
if (mActiveTransportList) {
|
||||
PR_Free(mActiveTransportList);
|
||||
mActiveTransportList = nsnull;
|
||||
}
|
||||
|
||||
if (mThreadEvent) {
|
||||
PR_DestroyPollableEvent(mThreadEvent);
|
||||
mThreadEvent = nsnull;
|
||||
}
|
||||
|
||||
if (mThreadLock) {
|
||||
PR_DestroyLock(mThreadLock);
|
||||
mThreadLock = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransportService::Init(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(!mThread, "Socket transport thread has already been created!.");
|
||||
|
||||
//
|
||||
// Create FDSET list used by PR_Poll(...)
|
||||
//
|
||||
if (!mSelectFDSet) {
|
||||
mSelectFDSet = (PRPollDesc*)PR_Malloc(sizeof(PRPollDesc)*MAX_OPEN_CONNECTIONS);
|
||||
if (mSelectFDSet) {
|
||||
memset(mSelectFDSet, 0, sizeof(PRPollDesc)*MAX_OPEN_CONNECTIONS);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create the list of Active transport objects... This list contains the
|
||||
// nsSocketTransport corresponding to each PRFileDesc* in the mSelectFDSet
|
||||
//
|
||||
if (NS_SUCCEEDED(rv) && !mActiveTransportList) {
|
||||
mActiveTransportList = (nsSocketTransport**)PR_Malloc(sizeof(nsSocketTransport*)*MAX_OPEN_CONNECTIONS);
|
||||
if (mActiveTransportList) {
|
||||
memset(mActiveTransportList, 0, sizeof(nsSocketTransport*)*MAX_OPEN_CONNECTIONS);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create the pollable event used to immediately wake up the transport
|
||||
// thread when it is blocked in PR_Poll(...)
|
||||
//
|
||||
if (NS_SUCCEEDED(rv) && !mThreadEvent) {
|
||||
mThreadEvent = PR_NewPollableEvent();
|
||||
if (!mThreadEvent) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create the synchronization lock for the transport thread...
|
||||
//
|
||||
if (NS_SUCCEEDED(rv) && !mThreadLock) {
|
||||
mThreadLock = PR_NewLock();
|
||||
if (!mThreadLock) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create the transport thread...
|
||||
//
|
||||
if (NS_SUCCEEDED(rv) && !mThread) {
|
||||
mThreadRunning = PR_TRUE;
|
||||
rv = NS_NewThread(&mThread, this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransportService::AddToWorkQ(nsSocketTransport* aTransport)
|
||||
{
|
||||
PRStatus status;
|
||||
PRBool bFireEvent;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ADDREF(aTransport);
|
||||
Lock();
|
||||
bFireEvent = PR_CLIST_IS_EMPTY(&mWorkQ);
|
||||
PR_APPEND_LINK(aTransport, &mWorkQ);
|
||||
Unlock();
|
||||
|
||||
//
|
||||
// Only fire an event if this is the first entry in the workQ. Otherwise,
|
||||
// the event has already been fired and the transport thread will process
|
||||
// all of the entries at once...
|
||||
//
|
||||
if (bFireEvent) {
|
||||
status = PR_SetPollableEvent(mThreadEvent);
|
||||
if (PR_FAILURE == status) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransportService::ProcessWorkQ(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
//
|
||||
// Only process pending operations while there is space available in the
|
||||
// select list...
|
||||
//
|
||||
// XXX: Need a way to restart the ProcessWorkQ(...) when space becomes
|
||||
// available in the select set...
|
||||
//
|
||||
Lock();
|
||||
while (!PR_CLIST_IS_EMPTY(&mWorkQ) &&
|
||||
(MAX_OPEN_CONNECTIONS > mSelectFDSetCount)) {
|
||||
nsSocketTransport* transport;
|
||||
|
||||
// Get the next item off of the workQ...
|
||||
transport = (nsSocketTransport*)PR_LIST_HEAD(&mWorkQ);
|
||||
PR_REMOVE_AND_INIT_LINK(transport);
|
||||
|
||||
// Try to perform the operation...
|
||||
//
|
||||
// Do not pass any select flags...
|
||||
rv = transport->Process(0);
|
||||
//
|
||||
// If the operation would block, then add it to the select list for
|
||||
// later processing when the data arrives...
|
||||
//
|
||||
if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
|
||||
rv = AddToSelectList(transport);
|
||||
}
|
||||
// Release the transport object (since it is no longer on the WorkQ).
|
||||
NS_RELEASE(transport);
|
||||
}
|
||||
Unlock();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsSocketTransportService::AddToSelectList(nsSocketTransport* aTransport)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (aTransport && (MAX_OPEN_CONNECTIONS > mSelectFDSetCount) ) {
|
||||
PRPollDesc* pfd;
|
||||
// Add the FileDesc to the PRPollDesc list...
|
||||
pfd = &mSelectFDSet[mSelectFDSetCount];
|
||||
pfd->fd = aTransport->GetSocket();;
|
||||
pfd->in_flags = aTransport->GetSelectFlags();
|
||||
pfd->out_flags = 0;
|
||||
// Add the transport instance to the corresponding active transport list...
|
||||
NS_ADDREF(aTransport);
|
||||
mActiveTransportList[mSelectFDSetCount] = aTransport;
|
||||
mSelectFDSetCount += 1;
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSocketTransportService::RemoveFromSelectList(nsSocketTransport* aTransport)
|
||||
{
|
||||
int i;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
for (i=1; i<mSelectFDSetCount; i++) {
|
||||
if (mActiveTransportList[i] == aTransport) {
|
||||
int last = mSelectFDSetCount-1;
|
||||
|
||||
NS_RELEASE(mActiveTransportList[i]);
|
||||
|
||||
// Move the last element in the array into the new empty slot...
|
||||
if (i != last) {
|
||||
memcpy(&mSelectFDSet[i], &mSelectFDSet[last], sizeof(mSelectFDSet[0]));
|
||||
mSelectFDSet[last].fd = nsnull;
|
||||
|
||||
mActiveTransportList[i] = mActiveTransportList[last];
|
||||
mActiveTransportList[last] = nsnull;
|
||||
} else {
|
||||
mSelectFDSet[i].fd = nsnull;
|
||||
mActiveTransportList[i] = nsnull;
|
||||
}
|
||||
mSelectFDSetCount -= 1;
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsISupports implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
NS_IMPL_ADDREF(nsSocketTransportService);
|
||||
NS_IMPL_RELEASE(nsSocketTransportService);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::QueryInterface(const nsIID& aIID, void* *aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(nsISocketTransportService::GetIID()) ||
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = NS_STATIC_CAST(nsISocketTransportService*, this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
if (aIID.Equals(nsIRunnable::GetIID())) {
|
||||
*aInstancePtr = NS_STATIC_CAST(nsIRunnable*, this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsIRunnable implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Run(void)
|
||||
{
|
||||
//
|
||||
// Initialize the FDSET used by PR_Poll(...). The first item in the FDSet
|
||||
// is *always* the pollable event (ie. mThreadEvent).
|
||||
//
|
||||
mSelectFDSet[0].fd = mThreadEvent;
|
||||
mSelectFDSet[0].in_flags = PR_POLL_READ;
|
||||
mSelectFDSetCount = 1;
|
||||
|
||||
while (mThreadRunning) {
|
||||
PRInt32 count;
|
||||
nsSocketTransport* transport;
|
||||
|
||||
// XXX: PR_Poll(...) needs a timeout value...
|
||||
count = PR_Poll(mSelectFDSet, mSelectFDSetCount, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
/* One or more sockets has data... */
|
||||
if (count > 0) {
|
||||
nsresult rv;
|
||||
int i;
|
||||
|
||||
/* Process any sockets with data first... */
|
||||
for (i=mSelectFDSetCount-1; i>=1; i--) {
|
||||
PRPollDesc* pfd;
|
||||
PRInt16 out_flags;
|
||||
|
||||
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];
|
||||
NS_ASSERTION(transport, "Null transport in active list...");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process any pending operations on the mWorkQ... */
|
||||
if (mSelectFDSet[0].out_flags) {
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
/* PR_Poll(...) timeout... */
|
||||
else if (count == 0) {
|
||||
}
|
||||
/* PR_Poll(...) error.. */
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// nsISocketTransportService implementation...
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::CreateTransport(const char* aHost,
|
||||
PRInt32 aPort,
|
||||
nsITransport** aResult)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsSocketTransport* transport = nsnull;
|
||||
|
||||
// Parameter validation...
|
||||
NS_ASSERTION(aResult, "aResult == nsnull.");
|
||||
if (!aResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Create and initialize a new connection object...
|
||||
NS_NEWXPCOM(transport, nsSocketTransport);
|
||||
if (transport) {
|
||||
rv = transport->Init(this, aHost, aPort);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete transport;
|
||||
transport = nsnull;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Set the reference count to one...
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(transport);
|
||||
}
|
||||
*aResult = transport;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Shutdown(void)
|
||||
{
|
||||
PRStatus status;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mThread) {
|
||||
//
|
||||
// Clear the running flag and wake up the transport thread...
|
||||
//
|
||||
mThreadRunning = PR_FALSE;
|
||||
status = PR_SetPollableEvent(mThreadEvent);
|
||||
|
||||
// XXX: what should happen if this fails?
|
||||
NS_ASSERTION(PR_SUCCESS == status, "Unable to wake up the transport thread.");
|
||||
|
||||
// Wait for the transport thread to exit nsIRunnable::Run()
|
||||
if (PR_SUCCESS == status) {
|
||||
mThread->Join();
|
||||
}
|
||||
|
||||
NS_RELEASE(mThread);
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
#ifndef nsSocketTransportService_h___
|
||||
#define nsSocketTransportService_h___
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
class nsSocketTransport;
|
||||
|
||||
class nsSocketTransportService : public nsISocketTransportService,
|
||||
public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsISocketTransportService methods:
|
||||
NS_IMETHOD CreateTransport(const char* aHost,
|
||||
PRInt32 aPort,
|
||||
nsITransport** aResult);
|
||||
|
||||
NS_IMETHOD Shutdown(void);
|
||||
|
||||
// nsIRunnable methods:
|
||||
NS_IMETHOD Run(void);
|
||||
|
||||
// nsSocketTransportService methods:
|
||||
nsSocketTransportService();
|
||||
virtual ~nsSocketTransportService();
|
||||
|
||||
nsresult Init(void);
|
||||
|
||||
nsresult AddToWorkQ(nsSocketTransport* aTransport);
|
||||
|
||||
// The following methods are called by the transport thread...
|
||||
nsresult ProcessWorkQ(void);
|
||||
|
||||
nsresult AddToSelectList(nsSocketTransport* aTransport);
|
||||
nsresult RemoveFromSelectList(nsSocketTransport* aTransport);
|
||||
|
||||
protected:
|
||||
// Inline helpers...
|
||||
void Lock (void) { NS_ASSERTION(mThreadLock, "Lock null."); PR_Lock(mThreadLock); }
|
||||
void Unlock(void) { NS_ASSERTION(mThreadLock, "Lock null."); PR_Unlock(mThreadLock); }
|
||||
|
||||
nsIThread* mThread;
|
||||
PRFileDesc* mThreadEvent;
|
||||
PRLock* mThreadLock;
|
||||
PRBool mThreadRunning;
|
||||
|
||||
PRCList mWorkQ;
|
||||
|
||||
PRInt32 mSelectFDSetCount;
|
||||
PRPollDesc* mSelectFDSet;
|
||||
nsSocketTransport** mActiveTransportList;
|
||||
};
|
||||
|
||||
|
||||
#endif /* nsSocketTransportService_h___ */
|
||||
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "stdio.h"
|
||||
#include <windows.h>
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsXPComCIID.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIByteBufferInputStream.h"
|
||||
|
||||
#ifdef XP_PC
|
||||
#define XPCOM_DLL "xpcom32.dll"
|
||||
#else
|
||||
#ifdef XP_MAC
|
||||
#include "nsMacRepository.h"
|
||||
#else
|
||||
#define XPCOM_DLL "libxpcom.so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
static int gKeepRunning = 1;
|
||||
static PLEventQueue* gEventQ = nsnull;
|
||||
|
||||
class InputTestConsumer : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
|
||||
InputTestConsumer();
|
||||
virtual ~InputTestConsumer();
|
||||
|
||||
// ISupports interface...
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// IStreamListener interface...
|
||||
NS_IMETHOD OnStartBinding(nsISupports* context);
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aLength);
|
||||
|
||||
NS_IMETHOD OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg);
|
||||
};
|
||||
|
||||
|
||||
InputTestConsumer::InputTestConsumer()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
InputTestConsumer::~InputTestConsumer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
|
||||
NS_IMPL_ISUPPORTS(InputTestConsumer,kIStreamListenerIID);
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnStartBinding(nsISupports* context)
|
||||
{
|
||||
/// printf("\n+++ InputTestConsumer::OnStartBinding +++\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnDataAvailable(nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
char buf[1025];
|
||||
PRUint32 amt;
|
||||
do {
|
||||
nsresult rv = aIStream->Read(buf, 1024, &amt);
|
||||
buf[amt] = '\0';
|
||||
printf(buf);
|
||||
} while (amt != 0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg)
|
||||
{
|
||||
gKeepRunning = 0;
|
||||
/// printf("\n+++ InputTestConsumer::OnStopBinding +++\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class TestWriteObserver : public nsIStreamObserver
|
||||
{
|
||||
public:
|
||||
|
||||
TestWriteObserver(nsITransport* aTransport);
|
||||
virtual ~TestWriteObserver();
|
||||
|
||||
// ISupports interface...
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// IStreamObserver interface...
|
||||
NS_IMETHOD OnStartBinding(nsISupports* context);
|
||||
|
||||
NS_IMETHOD OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg);
|
||||
protected:
|
||||
nsITransport* mTransport;
|
||||
};
|
||||
|
||||
|
||||
TestWriteObserver::TestWriteObserver(nsITransport* aTransport)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mTransport = aTransport;
|
||||
NS_ADDREF(mTransport);
|
||||
}
|
||||
|
||||
TestWriteObserver::~TestWriteObserver()
|
||||
{
|
||||
NS_RELEASE(mTransport);
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(TestWriteObserver,nsIStreamObserver::GetIID());
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestWriteObserver::OnStartBinding(nsISupports* context)
|
||||
{
|
||||
/// printf("\n+++ TestWriteObserver::OnStartBinding +++\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestWriteObserver::OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg)
|
||||
{
|
||||
/// printf("\n+++ TestWriteObserver::OnStopBinding +++\n");
|
||||
|
||||
mTransport->AsyncRead(nsnull, gEventQ, new InputTestConsumer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: %s <host> <path>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* hostName = argv[1];
|
||||
char* fileName = argv[2];
|
||||
int port = 80;
|
||||
|
||||
// XXX why do I have to do this?!
|
||||
nsComponentManager::RegisterComponent(kEventQueueServiceCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE);
|
||||
rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
"components");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Create the Event Queue for this thread...
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
eventQService->GetThreadEventQueue(PR_CurrentThread(), &gEventQ);
|
||||
|
||||
// Create the Socket transport service...
|
||||
NS_WITH_SERVICE(nsISocketTransportService, sts, kSocketTransportServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Create a stream for the data being written to the server...
|
||||
nsIByteBufferInputStream* stream;
|
||||
PRUint32 bytesWritten;
|
||||
|
||||
rv = NS_NewByteBufferInputStream(&stream);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
char *buffer = PR_smprintf("GET %s HTML/1.0\r\n\r\n", fileName);
|
||||
stream->Fill(buffer, strlen(buffer), &bytesWritten);
|
||||
/// printf("Request is: %s\n", buffer);
|
||||
|
||||
// Create the socket transport...
|
||||
nsITransport* transport;
|
||||
rv = sts->CreateTransport(hostName, port, &transport);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
TestWriteObserver* observer = new TestWriteObserver(transport);
|
||||
|
||||
transport->AsyncWrite(stream, nsnull, gEventQ, observer);
|
||||
|
||||
NS_RELEASE(transport);
|
||||
}
|
||||
|
||||
// Enter the message pump to allow the URL load to proceed.
|
||||
while ( gKeepRunning ) {
|
||||
#ifdef XP_PC
|
||||
MSG msg;
|
||||
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sts->Shutdown();
|
||||
NS_RELEASE(sts);
|
||||
NS_RELEASE(eventQService);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "stdio.h"
|
||||
#include <windows.h>
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsXPComCIID.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
#ifdef XP_PC
|
||||
#define XPCOM_DLL "xpcom32.dll"
|
||||
#else
|
||||
#ifdef XP_MAC
|
||||
#include "nsMacRepository.h"
|
||||
#else
|
||||
#define XPCOM_DLL "libxpcom.so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
static int gKeepRunning = 1;
|
||||
|
||||
class InputTestConsumer : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
|
||||
InputTestConsumer();
|
||||
virtual ~InputTestConsumer();
|
||||
|
||||
// ISupports interface...
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// IStreamListener interface...
|
||||
NS_IMETHOD OnStartBinding(nsISupports* context);
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aLength);
|
||||
|
||||
NS_IMETHOD OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg);
|
||||
};
|
||||
|
||||
|
||||
InputTestConsumer::InputTestConsumer()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
InputTestConsumer::~InputTestConsumer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
|
||||
NS_IMPL_ISUPPORTS(InputTestConsumer,kIStreamListenerIID);
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnStartBinding(nsISupports* context)
|
||||
{
|
||||
printf("+++ OnStartBinding +++\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnDataAvailable(nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
nsresult rv = aIStream->Read(buf, 1024, &amt);
|
||||
buf[amt] = '\0';
|
||||
printf(buf);
|
||||
aLength -= amt;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
InputTestConsumer::OnStopBinding(nsISupports* context,
|
||||
nsresult aStatus,
|
||||
nsIString* aMsg)
|
||||
{
|
||||
gKeepRunning = 0;
|
||||
printf("+++ OnStopBinding +++\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (argc < 1) {
|
||||
printf("usage: %s <host>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int port;
|
||||
char* hostName = argv[1];
|
||||
//nsString portString(argv[2]);
|
||||
|
||||
//port = portString.ToInteger(&rv);
|
||||
port = 13;
|
||||
|
||||
// XXX why do I have to do this?!
|
||||
nsComponentManager::RegisterComponent(kEventQueueServiceCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE);
|
||||
rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
"components");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Create the Event Queue for this thread...
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PLEventQueue* eventQ;
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQ);
|
||||
|
||||
NS_WITH_SERVICE(nsISocketTransportService, sts, kSocketTransportServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsITransport* transport;
|
||||
|
||||
rv = sts->CreateTransport(hostName, port, &transport);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
transport->AsyncRead(nsnull, eventQ, new InputTestConsumer);
|
||||
|
||||
NS_RELEASE(transport);
|
||||
}
|
||||
|
||||
// Enter the message pump to allow the URL load to proceed.
|
||||
while ( gKeepRunning ) {
|
||||
#ifdef XP_PC
|
||||
MSG msg;
|
||||
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sts->Shutdown();
|
||||
NS_RELEASE(sts);
|
||||
NS_RELEASE(eventQService);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -21,7 +21,9 @@ IGNORE_MANIFEST=1
|
|||
|
||||
MAKE_OBJ_TYPE = EXE
|
||||
PROG1 = .\$(OBJDIR)\TestFileInput.exe
|
||||
PROGRAMS = $(PROG1)
|
||||
PROG2 = .\$(OBJDIR)\TestSocketInput.exe
|
||||
PROG3 = .\$(OBJDIR)\TestSocketIO.exe
|
||||
PROGRAMS = $(PROG1) $(PROG2) $(PROG3)
|
||||
|
||||
LCFLAGS=-DUSE_NSREG -GX
|
||||
|
||||
|
@ -68,3 +70,6 @@ clobber::
|
|||
|
||||
$(PROG1): $(OBJDIR) TestFileInput.cpp
|
||||
|
||||
$(PROG2): $(OBJDIR) TestSocketInput.cpp
|
||||
|
||||
$(PROG3): $(OBJDIR) TestSocketIO.cpp
|
||||
|
|
Загрузка…
Ссылка в новой задаче