Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Protected Member Functions | Private Types | Private Member Functions | Private Attributes | Friends
nsSocketTransport Class Reference

#include <nsSocketTransport2.h>

Inheritance diagram for nsSocketTransport:
Inheritance graph
[legend]
Collaboration diagram for nsSocketTransport:
Collaboration graph
[legend]

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_NSITRANSPORT
NS_DECL_NSISOCKETTRANSPORT
NS_DECL_NSIDNSLISTENER 
nsSocketTransport ()
nsresult Init (const char **socketTypes, PRUint32 typeCount, const nsACString &host, PRUint16 port, nsIProxyInfo *proxyInfo)
nsresult InitWithConnectedSocket (PRFileDesc *socketFD, const PRNetAddr *addr)
void OnSocketReady (PRFileDesc *, PRInt16 outFlags)
void OnSocketDetached (PRFileDesc *)
void OnSocketEvent (PRUint32 type, nsresult status, nsISupports *param)
PRNetAddr getPeerAddr ()
 Returns the IP address of the socket connection peer.
PRNetAddr getSelfAddr ()
 Returns the IP address of the initiating end.
boolean isAlive ()
 Test if this socket transport is (still) connected.
unsigned long getTimeout (in unsigned long aType)
 Socket timeouts in seconds.
void setTimeout (in unsigned long aType, in unsigned long aValue)
nsIInputStream openInputStream (in unsigned long aFlags, in unsigned long aSegmentSize, in unsigned long aSegmentCount)
 Open an input stream on this transport.
nsIOutputStream openOutputStream (in unsigned long aFlags, in unsigned long aSegmentSize, in unsigned long aSegmentCount)
 Open an output stream on this transport.
void close (in nsresult aReason)
 Close the transport and any open streams.
void setEventSink (in nsITransportEventSink aSink, in nsIEventTarget aEventTarget)
 Set the transport event sink.
void onLookupComplete (in nsICancelable aRequest, in nsIDNSRecord aRecord, in nsresult aStatus)
 called when an asynchronous host lookup completes.

Public Attributes

nsresult mCondition
PRUint16 mPollFlags
PRUint16 mPollTimeout
readonly attribute AUTF8String host
 Get the host for the underlying socket connection.
readonly attribute long port
 Get the port for the underlying socket connection.
readonly attribute nsISupports securityInfo
 Security info object returned from the secure socket provider.
attribute nsIInterfaceRequestor securityCallbacks
 Security notification callbacks passed to the secure socket provider via nsISSLSocketControl at socket creation time.
const unsigned long TIMEOUT_CONNECT = 0
 Values for the aType parameter passed to get/setTimeout.
const unsigned long TIMEOUT_READ_WRITE = 1
const unsigned long STATUS_RESOLVING = 0x804b0003
 nsITransportEventSink status codes.
const unsigned long STATUS_CONNECTING_TO = 0x804b0007
const unsigned long STATUS_CONNECTED_TO = 0x804b0004
const unsigned long STATUS_SENDING_TO = 0x804b0005
const unsigned long STATUS_WAITING_FOR = 0x804b000a
const unsigned long STATUS_RECEIVING_FROM = 0x804b0006
const unsigned long OPEN_BLOCKING = 1<<0
 Open flags.
const unsigned long OPEN_UNBUFFERED = 1<<1
const unsigned long STATUS_READING = 0x804b0008
 Generic nsITransportEventSink status codes.
const unsigned long STATUS_WRITING = 0x804b0009

Protected Member Functions

virtual ~nsSocketTransport ()

Private Types

enum  {
  MSG_ENSURE_CONNECT, MSG_DNS_LOOKUP_COMPLETE, MSG_RETRY_INIT_SOCKET, MSG_TIMEOUT_CHANGED,
  MSG_INPUT_CLOSED, MSG_INPUT_PENDING, MSG_OUTPUT_CLOSED, MSG_OUTPUT_PENDING
}
enum  {
  STATE_CLOSED, STATE_IDLE, STATE_RESOLVING, STATE_CONNECTING,
  STATE_TRANSFERRING
}

Private Member Functions

nsresult PostEvent (PRUint32 type, nsresult status=NS_OK, nsISupports *param=nsnull)
PRUint16 SocketPort ()
const nsCStringSocketHost ()
void SendStatus (nsresult status)
nsresult ResolveHost ()
nsresult BuildSocket (PRFileDesc *&, PRBool &, PRBool &)
nsresult InitiateSocket ()
PRBool RecoverFromError ()
void OnMsgInputPending ()
void OnMsgOutputPending ()
void OnMsgInputClosed (nsresult reason)
void OnMsgOutputClosed (nsresult reason)
void OnSocketConnected ()
PRFileDescGetFD_Locked ()
void ReleaseFD_Locked (PRFileDesc *fd)
void OnInputClosed (nsresult reason)
void OnInputPending ()
void OnOutputClosed (nsresult reason)
void OnOutputPending ()

Private Attributes

char ** mTypes
PRUint32 mTypeCount
nsCString mHost
nsCString mProxyHost
PRUint16 mPort
PRUint16 mProxyPort
PRPackedBool mProxyTransparent
PRPackedBool mProxyTransparentResolvesHost
PRUint32 mState
PRPackedBool mAttached
PRPackedBool mInputClosed
PRPackedBool mOutputClosed
PRPackedBool mResolving
nsCOMPtr< nsICancelablemDNSRequest
nsCOMPtr< nsIDNSRecordmDNSRecord
PRNetAddr mNetAddr
PRLockmLock
PRFileDescmFD
nsrefcnt mFDref
PRBool mFDconnected
nsCOMPtr< nsIInterfaceRequestormCallbacks
nsCOMPtr< nsITransportEventSinkmEventSink
nsCOMPtr< nsISupports > mSecInfo
nsSocketInputStream mInput
nsSocketOutputStream mOutput
PRUint16 mTimeouts [2]

Friends

class nsSocketInputStream
class nsSocketOutputStream

Detailed Description

Definition at line 131 of file nsSocketTransport2.h.


Member Enumeration Documentation

anonymous enum [private]
Enumerator:
MSG_ENSURE_CONNECT 
MSG_DNS_LOOKUP_COMPLETE 
MSG_RETRY_INIT_SOCKET 
MSG_TIMEOUT_CHANGED 
MSG_INPUT_CLOSED 
MSG_INPUT_PENDING 
MSG_OUTPUT_CLOSED 
MSG_OUTPUT_PENDING 

Definition at line 168 of file nsSocketTransport2.h.

anonymous enum [private]
Enumerator:
STATE_CLOSED 
STATE_IDLE 
STATE_RESOLVING 
STATE_CONNECTING 
STATE_TRANSFERRING 

Definition at line 180 of file nsSocketTransport2.h.


Constructor & Destructor Documentation

Definition at line 677 of file nsSocketTransport2.cpp.

Here is the call graph for this function:

nsSocketTransport::~nsSocketTransport ( ) [protected, virtual]

Definition at line 704 of file nsSocketTransport2.cpp.

{
    LOG(("destroying nsSocketTransport @%x\n", this));

    // cleanup socket type info
    if (mTypes) {
        PRUint32 i;
        for (i=0; i<mTypeCount; ++i)
            PL_strfree(mTypes[i]);
        free(mTypes);
    }

    if (mLock)
        PR_DestroyLock(mLock);
 
    nsSocketTransportService *serv = gSocketTransportService;
    NS_RELEASE(serv); // nulls argument
}

Here is the call graph for this function:


Member Function Documentation

nsresult nsSocketTransport::BuildSocket ( PRFileDesc *&  fd,
PRBool proxyTransparent,
PRBool usingSSL 
) [private]

Definition at line 940 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::BuildSocket [this=%x]\n", this));

    nsresult rv;

    proxyTransparent = PR_FALSE;
    usingSSL = PR_FALSE;

    if (mTypeCount == 0) {
        fd = PR_OpenTCPSocket(mNetAddr.raw.family);
        rv = fd ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
    }
    else {
        fd = nsnull;

        nsCOMPtr<nsISocketProviderService> spserv =
            do_GetService(kSocketProviderServiceCID, &rv);
        if (NS_FAILED(rv)) return rv;

        const char *host       = mHost.get();
        PRInt32     port       = (PRInt32) mPort;
        const char *proxyHost  = mProxyHost.IsEmpty() ? nsnull : mProxyHost.get();
        PRInt32     proxyPort  = (PRInt32) mProxyPort;
        PRUint32    proxyFlags = 0;

        PRUint32 i;
        for (i=0; i<mTypeCount; ++i) {
            nsCOMPtr<nsISocketProvider> provider;

            LOG(("  pushing io layer [%u:%s]\n", i, mTypes[i]));

            rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
            if (NS_FAILED(rv))
                break;

            if (mProxyTransparentResolvesHost)
                proxyFlags |= nsISocketProvider::PROXY_RESOLVES_HOST;

            nsCOMPtr<nsISupports> secinfo;
            if (i == 0) {
                // if this is the first type, we'll want the 
                // service to allocate a new socket
                rv = provider->NewSocket(mNetAddr.raw.family,
                                         host, port, proxyHost, proxyPort,
                                         proxyFlags, &fd,
                                         getter_AddRefs(secinfo));

                if (NS_SUCCEEDED(rv) && !fd) {
                    NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
                    rv = NS_ERROR_UNEXPECTED;
                }
            }
            else {
                // the socket has already been allocated, 
                // so we just want the service to add itself
                // to the stack (such as pushing an io layer)
                rv = provider->AddToSocket(mNetAddr.raw.family,
                                           host, port, proxyHost, proxyPort,
                                           proxyFlags, fd,
                                           getter_AddRefs(secinfo));
            }
            proxyFlags = 0;
            if (NS_FAILED(rv))
                break;

            // if the service was ssl or starttls, we want to hold onto the socket info
            PRBool isSSL = (strcmp(mTypes[i], "ssl") == 0);
            if (isSSL || (strcmp(mTypes[i], "starttls") == 0)) {
                // remember security info and give notification callbacks to PSM...
                nsCOMPtr<nsIInterfaceRequestor> callbacks;
                {
                    nsAutoLock lock(mLock);
                    mSecInfo = secinfo;
                    callbacks = mCallbacks;
                    LOG(("  [secinfo=%x callbacks=%x]\n", mSecInfo.get(), mCallbacks.get()));
                }
                // don't call into PSM while holding mLock!!
                nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
                if (secCtrl)
                    secCtrl->SetNotificationCallbacks(callbacks);
                // remember if socket type is SSL so we can ProxyStartSSL if need be.
                usingSSL = isSSL;
            }
            else if ((strcmp(mTypes[i], "socks") == 0) ||
                     (strcmp(mTypes[i], "socks4") == 0)) {
                // since socks is transparent, any layers above
                // it do not have to worry about proxy stuff
                proxyHost = nsnull;
                proxyPort = -1;
                proxyTransparent = PR_TRUE;
            }
        }

        if (NS_FAILED(rv)) {
            LOG(("  error pushing io layer [%u:%s rv=%x]\n", i, mTypes[i], rv));
            if (fd)
                PR_Close(fd);
        }
    }

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsITransport::close ( in nsresult  aReason) [inherited]

Close the transport and any open streams.

Parameters:
aReasonthe reason for closing the stream.

Definition at line 1328 of file nsSocketTransport2.cpp.

{
    // mFD is not available to the streams while disconnected.
    if (!mFDconnected)
        return nsnull;

    if (mFD)
        mFDref++;

    return mFD;
}

Returns the IP address of the socket connection peer.

This attribute is defined only once a connection has been established.

Returns the IP address of the initiating end.

This attribute is defined only once a connection has been established.

unsigned long nsISocketTransport::getTimeout ( in unsigned long  aType) [inherited]

Socket timeouts in seconds.

To specify no timeout, pass PR_UINT32_MAX as aValue to setTimeout. The implementation may truncate timeout values to a smaller range of values (e.g., 0 to 0xFFFF).

nsresult nsSocketTransport::Init ( const char **  socketTypes,
PRUint32  typeCount,
const nsACString &  host,
PRUint16  port,
nsIProxyInfo proxyInfo 
)

Definition at line 724 of file nsSocketTransport2.cpp.

{
    if (!mLock)
        return NS_ERROR_OUT_OF_MEMORY;

    nsCOMPtr<nsProxyInfo> proxyInfo;
    if (givenProxyInfo) {
        proxyInfo = do_QueryInterface(givenProxyInfo);
        NS_ENSURE_ARG(proxyInfo);
    }

    // init socket type info

    mPort = port;
    mHost = host;

    const char *proxyType = nsnull;
    if (proxyInfo) {
        mProxyPort = proxyInfo->Port();
        mProxyHost = proxyInfo->Host();
        // grab proxy type (looking for "socks" for example)
        proxyType = proxyInfo->Type();
        if (proxyType && (strcmp(proxyType, "http") == 0 ||
                          strcmp(proxyType, "direct") == 0 ||
                          strcmp(proxyType, "unknown") == 0))
            proxyType = nsnull;
    }

    LOG(("nsSocketTransport::Init [this=%x host=%s:%hu proxy=%s:%hu]\n",
        this, mHost.get(), mPort, mProxyHost.get(), mProxyPort));

    // include proxy type as a socket type if proxy type is not "http"
    mTypeCount = typeCount + (proxyType != nsnull);
    if (!mTypeCount)
        return NS_OK;

    // if we have socket types, then the socket provider service had
    // better exist!
    nsresult rv;
    nsCOMPtr<nsISocketProviderService> spserv =
        do_GetService(kSocketProviderServiceCID, &rv);
    if (NS_FAILED(rv)) return rv;

    mTypes = (char **) malloc(mTypeCount * sizeof(char *));
    if (!mTypes)
        return NS_ERROR_OUT_OF_MEMORY;

    // now verify that each socket type has a registered socket provider.
    for (PRUint32 i = 0, type = 0; i < mTypeCount; ++i) {
        // store socket types
        if (i == 0 && proxyType)
            mTypes[i] = PL_strdup(proxyType);
        else
            mTypes[i] = PL_strdup(types[type++]);

        if (!mTypes[i]) {
            mTypeCount = i;
            return NS_ERROR_OUT_OF_MEMORY;
        }
        nsCOMPtr<nsISocketProvider> provider;
        rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
        if (NS_FAILED(rv)) {
            NS_WARNING("no registered socket provider");
            return rv;
        }

        // note if socket type corresponds to a transparent proxy
        // XXX don't hardcode SOCKS here (use proxy info's flags instead).
        if ((strcmp(mTypes[i], "socks") == 0) ||
            (strcmp(mTypes[i], "socks4") == 0)) {
            mProxyTransparent = PR_TRUE;

            if (proxyInfo->Flags() & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST) {
                // we want the SOCKS layer to send the hostname
                // and port to the proxy and let it do the DNS.
                mProxyTransparentResolvesHost = PR_TRUE;
            }
        }
    }

    return NS_OK;
}

Here is the call graph for this function:

Definition at line 1045 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::InitiateSocket [this=%x]\n", this));

    nsresult rv;

    //
    // find out if it is going to be ok to attach another socket to the STS.
    // if not then we have to wait for the STS to tell us that it is ok.
    // the notification is asynchronous, which means that when we could be
    // in a race to call AttachSocket once notified.  for this reason, when
    // we get notified, we just re-enter this function.  as a result, we are
    // sure to ask again before calling AttachSocket.  in this way we deal
    // with the race condition.  though it isn't the most elegant solution,
    // it is far simpler than trying to build a system that would guarantee
    // FIFO ordering (which wouldn't even be that valuable IMO).  see bug
    // 194402 for more info.
    //
    if (!gSocketTransportService->CanAttachSocket()) {
        PLEvent *event = new nsSocketEvent(this, MSG_RETRY_INIT_SOCKET);
        if (!event)
            return NS_ERROR_OUT_OF_MEMORY;
        rv = gSocketTransportService->NotifyWhenCanAttachSocket(event);
        if (NS_FAILED(rv))
            PL_DestroyEvent(event);
        return rv;
    }

    //
    // if we already have a connected socket, then just attach and return.
    //
    if (mFD) {
        rv = gSocketTransportService->AttachSocket(mFD, this);
        if (NS_SUCCEEDED(rv))
            mAttached = PR_TRUE;
        return rv;
    }

    //
    // create new socket fd, push io layers, etc.
    //
    PRFileDesc *fd;
    PRBool proxyTransparent;
    PRBool usingSSL;

    rv = BuildSocket(fd, proxyTransparent, usingSSL);
    if (NS_FAILED(rv)) {
        LOG(("  BuildSocket failed [rv=%x]\n", rv));
        return rv;
    }

    PRStatus status;

    // Make the socket non-blocking...
    PRSocketOptionData opt;
    opt.option = PR_SockOpt_Nonblocking;
    opt.value.non_blocking = PR_TRUE;
    status = PR_SetSocketOption(fd, &opt);
    NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
    
    // inform socket transport about this newly created socket...
    rv = gSocketTransportService->AttachSocket(fd, this);
    if (NS_FAILED(rv)) {
        PR_Close(fd);
        return rv;
    }
    mAttached = PR_TRUE;

    // assign mFD so that we can properly handle OnSocketDetached before we've
    // established a connection.
    {
        nsAutoLock lock(mLock);
        mFD = fd;
        mFDref = 1;
        mFDconnected = PR_FALSE;
    }

    LOG(("  advancing to STATE_CONNECTING\n"));
    mState = STATE_CONNECTING;
    mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
    SendStatus(STATUS_CONNECTING_TO);

#if defined(PR_LOGGING)
    if (LOG_ENABLED()) {
        char buf[64];
        PR_NetAddrToString(&mNetAddr, buf, sizeof(buf));
        LOG(("  trying address: %s\n", buf));
    }
#endif

    // 
    // Initiate the connect() to the host...  
    //
    status = PR_Connect(fd, &mNetAddr, NS_SOCKET_CONNECT_TIMEOUT);
    if (status == PR_SUCCESS) {
        // 
        // we are connected!
        //
        OnSocketConnected();
    }
    else {
        PRErrorCode code = PR_GetError();
#if defined(TEST_CONNECT_ERRORS)
        code = RandomizeConnectError(code);
#endif
        //
        // If the PR_Connect(...) would block, then poll for a connection.
        //
        if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code))
            mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
        //
        // If the socket is already connected, then return success...
        //
        else if (PR_IS_CONNECTED_ERROR == code) {
            //
            // we are connected!
            //
            OnSocketConnected();

            if (mSecInfo && !mProxyHost.IsEmpty() && proxyTransparent && usingSSL) {
                // if the connection phase is finished, and the ssl layer has
                // been pushed, and we were proxying (transparently; ie. nothing
                // has to happen in the protocol layer above us), it's time for
                // the ssl to start doing it's thing.
                nsCOMPtr<nsISSLSocketControl> secCtrl =
                    do_QueryInterface(mSecInfo);
                if (secCtrl) {
                    LOG(("  calling ProxyStartSSL()\n"));
                    secCtrl->ProxyStartSSL();
                }
                // XXX what if we were forced to poll on the socket for a successful
                // connection... wouldn't we need to call ProxyStartSSL after a call
                // to PR_ConnectContinue indicates that we are connected?
                //
                // XXX this appears to be what the old socket transport did.  why
                // isn't this broken?
            }
        }
        //
        // The connection was refused...
        //
        else {
            rv = ErrorAccordingToNSPR(code);
            if ((rv == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
                rv = NS_ERROR_PROXY_CONNECTION_REFUSED;
        }
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 810 of file nsSocketTransport2.cpp.

{
    if (!mLock)
        return NS_ERROR_OUT_OF_MEMORY;

    NS_ASSERTION(!mFD, "already initialized");

    char buf[64];
    PR_NetAddrToString(addr, buf, sizeof(buf));
    mHost.Assign(buf);

    PRUint16 port;
    if (addr->raw.family == PR_AF_INET)
        port = addr->inet.port;
    else
        port = addr->ipv6.port;
    mPort = PR_ntohs(port);

    memcpy(&mNetAddr, addr, sizeof(PRNetAddr));

    mPollFlags = (PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT);
    mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
    mState = STATE_TRANSFERRING;

    mFD = fd;
    mFDref = 1;
    mFDconnected = 1;

    // make sure new socket is non-blocking
    PRSocketOptionData opt;
    opt.option = PR_SockOpt_Nonblocking;
    opt.value.non_blocking = PR_TRUE;
    PR_SetSocketOption(mFD, &opt);

    LOG(("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n",
        this, mHost.get(), mPort));

    // jump to InitiateSocket to get ourselves attached to the STS poll list.
    return PostEvent(MSG_RETRY_INIT_SOCKET);
}

Here is the call graph for this function:

Test if this socket transport is (still) connected.

void nsSocketTransport::OnInputClosed ( nsresult  reason) [inline, private]

Definition at line 280 of file nsSocketTransport2.h.

    {
        // no need to post an event if called on the socket thread
        if (PR_GetCurrentThread() == gSocketThread)
            OnMsgInputClosed(reason);
        else
            PostEvent(MSG_INPUT_CLOSED, reason);
    }

Here is the call graph for this function:

void nsSocketTransport::OnInputPending ( ) [inline, private]

Definition at line 288 of file nsSocketTransport2.h.

    {
        // no need to post an event if called on the socket thread
        if (PR_GetCurrentThread() == gSocketThread)
            OnMsgInputPending();
        else
            PostEvent(MSG_INPUT_PENDING);
    }

Here is the call graph for this function:

void nsIDNSListener::onLookupComplete ( in nsICancelable  aRequest,
in nsIDNSRecord  aRecord,
in nsresult  aStatus 
) [inherited]

called when an asynchronous host lookup completes.

Parameters:
aRequestthe value returned from asyncResolve.
aRecordthe DNS record corresponding to the hostname that was resolved. this parameter is null if there was an error.
aStatusif the lookup failed, this parameter gives the reason.

Definition at line 1264 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::OnMsgInputClosed [this=%x reason=%x]\n",
        this, reason));

    NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");

    mInputClosed = PR_TRUE;
    // check if event should affect entire transport
    if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
        mCondition = reason;                // XXX except if NS_FAILED(mCondition), right??
    else if (mOutputClosed)
        mCondition = NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
    else {
        if (mState == STATE_TRANSFERRING)
            mPollFlags &= ~PR_POLL_READ;
        mInput.OnSocketReady(reason);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 233 of file nsSocketTransport2.h.

Here is the caller graph for this function:

Definition at line 1286 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::OnMsgOutputClosed [this=%x reason=%x]\n",
        this, reason));

    NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");

    mOutputClosed = PR_TRUE;
    // check if event should affect entire transport
    if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
        mCondition = reason;                // XXX except if NS_FAILED(mCondition), right??
    else if (mInputClosed)
        mCondition = NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
    else {
        if (mState == STATE_TRANSFERRING)
            mPollFlags &= ~PR_POLL_WRITE;
        mOutput.OnSocketReady(reason);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 238 of file nsSocketTransport2.h.

Here is the caller graph for this function:

void nsSocketTransport::OnOutputClosed ( nsresult  reason) [inline, private]

Definition at line 296 of file nsSocketTransport2.h.

    {
        // no need to post an event if called on the socket thread
        if (PR_GetCurrentThread() == gSocketThread)
            OnMsgOutputClosed(reason); // XXX need to not be inside lock!
        else
            PostEvent(MSG_OUTPUT_CLOSED, reason);
    }

Here is the call graph for this function:

Definition at line 304 of file nsSocketTransport2.h.

    {
        // no need to post an event if called on the socket thread
        if (PR_GetCurrentThread() == gSocketThread)
            OnMsgOutputPending();
        else
            PostEvent(MSG_OUTPUT_PENDING);
    }

Here is the call graph for this function:

Definition at line 1307 of file nsSocketTransport2.cpp.

{
    LOG(("  advancing to STATE_TRANSFERRING\n"));

    mPollFlags = (PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT);
    mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
    mState = STATE_TRANSFERRING;

    SendStatus(STATUS_CONNECTED_TO);

    // assign mFD (must do this within the transport lock), but take care not
    // to trample over mFDref if mFD is already set.
    {
        nsAutoLock lock(mLock);
        NS_ASSERTION(mFD, "no socket");
        NS_ASSERTION(mFDref == 1, "wrong socket ref count");
        mFDconnected = PR_TRUE;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Implements nsASocketHandler.

Definition at line 1527 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::OnSocketDetached [this=%x cond=%x]\n",
        this, mCondition));

    NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");

    // if we didn't initiate this detach, then be sure to pass an error
    // condition up to our consumers.  (e.g., STS is shutting down.)
    if (NS_SUCCEEDED(mCondition))
        mCondition = NS_ERROR_ABORT;

    if (RecoverFromError())
        mCondition = NS_OK;
    else {
        mState = STATE_CLOSED;

        // make sure there isn't any pending DNS request
        if (mDNSRequest) {
            mDNSRequest->Cancel(NS_ERROR_ABORT);
            mDNSRequest = 0;
        }

        //
        // notify input/output streams
        //
        mInput.OnSocketReady(mCondition);
        mOutput.OnSocketReady(mCondition);
    }

    // break any potential reference cycle between the security info object
    // and ourselves by resetting its notification callbacks object.  see
    // bug 285991 for details.
    nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
    if (secCtrl)
        secCtrl->SetNotificationCallbacks(nsnull);

    // finally, release our reference to the socket (must do this within
    // the transport lock) possibly closing the socket.
    {
        nsAutoLock lock(mLock);
        if (mFD) {
            ReleaseFD_Locked(mFD);
            // flag mFD as unusable; this prevents other consumers from 
            // acquiring a reference to mFD.
            mFDconnected = PR_FALSE;
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSocketTransport::OnSocketEvent ( PRUint32  type,
nsresult  status,
nsISupports *  param 
)

Definition at line 1356 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::OnSocketEvent [this=%p type=%u status=%x param=%p]\n",
        this, type, status, param));

    if (NS_FAILED(mCondition)) {
        // block event since we're apparently already dead.
        LOG(("  blocking event [condition=%x]\n", mCondition));
        //
        // notify input/output streams in case either has a pending notify.
        //
        mInput.OnSocketReady(mCondition);
        mOutput.OnSocketReady(mCondition);
        return;
    }

    switch (type) {
    case MSG_ENSURE_CONNECT:
        LOG(("  MSG_ENSURE_CONNECT\n"));
        //
        // ensure that we have created a socket, attached it, and have a
        // connection.
        //
        if (mState == STATE_CLOSED)
            mCondition = ResolveHost();
        else
            LOG(("  ignoring redundant event\n"));
        break;

    case MSG_DNS_LOOKUP_COMPLETE:
        LOG(("  MSG_DNS_LOOKUP_COMPLETE\n"));
        mDNSRequest = 0;
        if (param) {
            mDNSRecord = NS_STATIC_CAST(nsIDNSRecord *, param);
            mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
        }
        // status contains DNS lookup status
        if (NS_FAILED(status)) {
            // When using a HTTP proxy, NS_ERROR_UNKNOWN_HOST means the HTTP 
            // proxy host is not found, so we fixup the error code.
            // For SOCKS proxies (mProxyTransparent == true), the socket 
            // transport resolves the real host here, so there's no fixup 
            // (see bug 226943).
            if ((status == NS_ERROR_UNKNOWN_HOST) && !mProxyTransparent &&
                !mProxyHost.IsEmpty())
                mCondition = NS_ERROR_UNKNOWN_PROXY_HOST;
            else
                mCondition = status;
        }
        else if (mState == STATE_RESOLVING)
            mCondition = InitiateSocket();
        break;

    case MSG_RETRY_INIT_SOCKET:
        mCondition = InitiateSocket();
        break;

    case MSG_INPUT_CLOSED:
        LOG(("  MSG_INPUT_CLOSED\n"));
        OnMsgInputClosed(status);
        break;

    case MSG_INPUT_PENDING:
        LOG(("  MSG_INPUT_PENDING\n"));
        OnMsgInputPending();
        break;

    case MSG_OUTPUT_CLOSED:
        LOG(("  MSG_OUTPUT_CLOSED\n"));
        OnMsgOutputClosed(status);
        break;

    case MSG_OUTPUT_PENDING:
        LOG(("  MSG_OUTPUT_PENDING\n"));
        OnMsgOutputPending();
        break;
    case MSG_TIMEOUT_CHANGED:
        LOG(("  MSG_TIMEOUT_CHANGED\n"));
        mPollTimeout = mTimeouts[(mState == STATE_TRANSFERRING)
          ? TIMEOUT_READ_WRITE : TIMEOUT_CONNECT];
        break;
    default:
        LOG(("  unhandled event!\n"));
    }
    
    if (NS_FAILED(mCondition)) {
        LOG(("  after event [this=%x cond=%x]\n", this, mCondition));
        if (!mAttached) // need to process this error ourselves...
            OnSocketDetached(nsnull);
    }
    else if (mPollFlags == PR_POLL_EXCEPT)
        mPollFlags = 0; // make idle
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSocketTransport::OnSocketReady ( PRFileDesc fd,
PRInt16  outFlags 
) [virtual]

Implements nsASocketHandler.

Definition at line 1454 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::OnSocketReady [this=%x outFlags=%hd]\n",
        this, outFlags));

    if (outFlags == -1) {
        LOG(("socket timeout expired\n"));
        mCondition = NS_ERROR_NET_TIMEOUT;
        return;
    }

    if (mState == STATE_TRANSFERRING) {
        // if waiting to write and socket is writable or hit an exception.
        if ((mPollFlags & PR_POLL_WRITE) && (outFlags & ~PR_POLL_READ)) {
            // assume that we won't need to poll any longer (the stream will
            // request that we poll again if it is still pending).
            mPollFlags &= ~PR_POLL_WRITE;
            mOutput.OnSocketReady(NS_OK);
        }
        // if waiting to read and socket is readable or hit an exception.
        if ((mPollFlags & PR_POLL_READ) && (outFlags & ~PR_POLL_WRITE)) {
            // assume that we won't need to poll any longer (the stream will
            // request that we poll again if it is still pending).
            mPollFlags &= ~PR_POLL_READ;
            mInput.OnSocketReady(NS_OK);
        }
        // Update poll timeout in case it was changed
        mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
    }
    else if (mState == STATE_CONNECTING) {
        PRStatus status = PR_ConnectContinue(fd, outFlags);
        if (status == PR_SUCCESS) {
            //
            // we are connected!
            //
            OnSocketConnected();
        }
        else {
            PRErrorCode code = PR_GetError();
#if defined(TEST_CONNECT_ERRORS)
            code = RandomizeConnectError(code);
#endif
            //
            // If the connect is still not ready, then continue polling...
            //
            if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code)) {
                // Set up the select flags for connect...
                mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
                // Update poll timeout in case it was changed
                mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
            } 
            else {
                //
                // else, the connection failed...
                //
                mCondition = ErrorAccordingToNSPR(code);
                if ((mCondition == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
                    mCondition = NS_ERROR_PROXY_CONNECTION_REFUSED;
                LOG(("  connection failed! [reason=%x]\n", mCondition));
            }
        }
    }
    else {
        NS_ERROR("unexpected socket state");
        mCondition = NS_ERROR_UNEXPECTED;
    }

    if (mPollFlags == PR_POLL_EXCEPT)
        mPollFlags = 0; // make idle
}

Here is the call graph for this function:

nsIInputStream nsITransport::openInputStream ( in unsigned long  aFlags,
in unsigned long  aSegmentSize,
in unsigned long  aSegmentCount 
) [inherited]

Open an input stream on this transport.

Flags have the following meaning:

OPEN_BLOCKING If specified, then the resulting stream will have blocking stream semantics. This means that if the stream has no data and is not closed, then reading from it will block the calling thread until at least one byte is available or until the stream is closed. If this flag is NOT specified, then the stream has non-blocking stream semantics. This means that if the stream has no data and is not closed, then reading from it returns NS_BASE_STREAM_WOULD_BLOCK. In addition, in non-blocking mode, the stream is guaranteed to support nsIAsyncInputStream. This interface allows the consumer of the stream to be notified when the stream can again be read.

OPEN_UNBUFFERED If specified, the resulting stream may not support ReadSegments. ReadSegments is only gauranteed to be implemented when this flag is NOT specified.

Parameters:
aFlagsoptional transport specific flags.
aSegmentSizeif OPEN_UNBUFFERED is not set, then this parameter specifies the size of each buffer segment (pass 0 to use default value).
aSegmentCountif OPEN_UNBUFFERED is not set, then this parameter specifies the maximum number of buffer segments (pass 0 to use default value).
nsIOutputStream nsITransport::openOutputStream ( in unsigned long  aFlags,
in unsigned long  aSegmentSize,
in unsigned long  aSegmentCount 
) [inherited]

Open an output stream on this transport.

Flags have the following meaning:

OPEN_BLOCKING If specified, then the resulting stream will have blocking stream semantics. This means that if the stream is full and is not closed, then writing to it will block the calling thread until ALL of the data can be written or until the stream is closed. If this flag is NOT specified, then the stream has non-blocking stream semantics. This means that if the stream is full and is not closed, then writing to it returns NS_BASE_STREAM_WOULD_BLOCK. In addition, in non- blocking mode, the stream is guaranteed to support nsIAsyncOutputStream. This interface allows the consumer of the stream to be notified when the stream can again accept more data.

OPEN_UNBUFFERED If specified, the resulting stream may not support WriteSegments and WriteFrom. WriteSegments and WriteFrom are only gauranteed to be implemented when this flag is NOT specified.

Parameters:
aFlagsoptional transport specific flags.
aSegmentSizeif OPEN_UNBUFFERED is not set, then this parameter specifies the size of each buffer segment (pass 0 to use default value).
aSegmentCountif OPEN_UNBUFFERED is not set, then this parameter specifies the maximum number of buffer segments (pass 0 to use default value).
nsresult nsSocketTransport::PostEvent ( PRUint32  type,
nsresult  status = NS_OK,
nsISupports *  param = nsnull 
) [private]

Definition at line 852 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::PostEvent [this=%p type=%u status=%x param=%p]\n",
        this, type, status, param));

    PLEvent *event = new nsSocketEvent(this, type, status, param);
    if (!event)
        return NS_ERROR_OUT_OF_MEMORY;

    nsresult rv = gSocketTransportService->PostEvent(event);
    if (NS_FAILED(rv))
        PL_DestroyEvent(event);

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1196 of file nsSocketTransport2.cpp.

{
    NS_ASSERTION(NS_FAILED(mCondition), "there should be something wrong");

    LOG(("nsSocketTransport::RecoverFromError [this=%x state=%x cond=%x]\n",
        this, mState, mCondition));

    // can only recover from errors in these states
    if (mState != STATE_RESOLVING && mState != STATE_CONNECTING)
        return PR_FALSE;

    // OK to check this outside mLock
    NS_ASSERTION(!mFDconnected, "socket should not be connected");

    // can only recover from these errors
    if (mCondition != NS_ERROR_CONNECTION_REFUSED &&
        mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
        mCondition != NS_ERROR_NET_TIMEOUT &&
        mCondition != NS_ERROR_UNKNOWN_HOST &&
        mCondition != NS_ERROR_UNKNOWN_PROXY_HOST)
        return PR_FALSE;

    PRBool tryAgain = PR_FALSE;

    // try next ip address only if past the resolver stage...
    if (mState == STATE_CONNECTING && mDNSRecord) {
        nsresult rv = mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
        if (NS_SUCCEEDED(rv)) {
            LOG(("  trying again with next ip address\n"));
            tryAgain = PR_TRUE;
        }
    }

#if defined(XP_WIN)
    // If not trying next address, try to make a connection using dialup. 
    // Retry if that connection is made.
    if (!tryAgain) {
        PRBool autodialEnabled;
        gSocketTransportService->GetAutodialEnabled(&autodialEnabled);
        if (autodialEnabled)
            tryAgain = nsNativeConnectionHelper::OnConnectionFailed(SocketHost().get());
    }
#endif

    // prepare to try again.
    if (tryAgain) {
        nsresult rv;
        PRUint32 msg;

        if (mState == STATE_CONNECTING) {
            mState = STATE_RESOLVING;
            msg = MSG_DNS_LOOKUP_COMPLETE;
        }
        else {
            mState = STATE_CLOSED;
            msg = MSG_ENSURE_CONNECT;
        }

        rv = PostEvent(msg, NS_OK);
        if (NS_FAILED(rv))
            tryAgain = PR_FALSE;
    }

    return tryAgain;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1341 of file nsSocketTransport2.cpp.

{
    NS_ASSERTION(mFD == fd, "wrong fd");

    if (--mFDref == 0) {
        LOG(("nsSocketTransport: calling PR_Close [this=%x]\n", this));
        PR_Close(mFD);
        mFD = nsnull;
    }
}

Here is the caller graph for this function:

Definition at line 895 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::ResolveHost [this=%x]\n", this));

    nsresult rv;

    if (!mProxyHost.IsEmpty()) {
        if (!mProxyTransparent || mProxyTransparentResolvesHost) {
            // When not resolving mHost locally, we still want to ensure that
            // it only contains valid characters.  See bug 304904 for details.
            if (!net_IsValidHostName(mHost))
                return NS_ERROR_UNKNOWN_HOST;
        }
        if (mProxyTransparentResolvesHost) {
            // Name resolution is done on the server side.  Just pretend
            // client resolution is complete, this will get picked up later.
            // since we don't need to do DNS now, we bypass the resolving
            // step by initializing mNetAddr to an empty address, but we
            // must keep the port. The SOCKS IO layer will use the hostname
            // we send it when it's created, rather than the empty address
            // we send with the connect call.
            mState = STATE_RESOLVING;
            PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, SocketPort(), &mNetAddr);
            return PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nsnull);
        }
    }

    nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
    if (NS_FAILED(rv)) return rv;

    mResolving = PR_TRUE;

    rv = dns->AsyncResolve(SocketHost(), 0, this, nsnull,
                           getter_AddRefs(mDNSRequest));
    if (NS_SUCCEEDED(rv)) {
        LOG(("  advancing to STATE_RESOLVING\n"));
        mState = STATE_RESOLVING;
        // only report that we are resolving if we are still resolving...
        if (mResolving)
            SendStatus(STATUS_RESOLVING);
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 869 of file nsSocketTransport2.cpp.

{
    LOG(("nsSocketTransport::SendStatus [this=%x status=%x]\n", this, status));

    nsCOMPtr<nsITransportEventSink> sink;
    PRUint64 progress;
    {
        nsAutoLock lock(mLock);
        sink = mEventSink;
        switch (status) {
        case STATUS_SENDING_TO:
            progress = mOutput.ByteCount();
            break;
        case STATUS_RECEIVING_FROM:
            progress = mInput.ByteCount();
            break;
        default:
            progress = 0;
            break;
        }
    }
    if (sink)
        sink->OnTransportStatus(this, status, progress, LL_MAXUINT);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsITransport::setEventSink ( in nsITransportEventSink  aSink,
in nsIEventTarget  aEventTarget 
) [inherited]

Set the transport event sink.

Parameters:
aSinkreceives transport layer notifications
aEventTargetindicates the event target to which the notifications should be delivered. if NULL, then the notifications may occur on any thread.
void nsISocketTransport::setTimeout ( in unsigned long  aType,
in unsigned long  aValue 
) [inherited]

Definition at line 204 of file nsSocketTransport2.h.

{ return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }

Here is the caller graph for this function:

PRUint16 nsSocketTransport::SocketPort ( ) [inline, private]

Definition at line 203 of file nsSocketTransport2.h.

{ return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }

Here is the caller graph for this function:


Friends And Related Function Documentation

friend class nsSocketInputStream [friend]

Definition at line 265 of file nsSocketTransport2.h.

friend class nsSocketOutputStream [friend]

Definition at line 266 of file nsSocketTransport2.h.


Member Data Documentation

readonly attribute AUTF8String nsISocketTransport::host [inherited]

Get the host for the underlying socket connection.

Definition at line 57 of file nsISocketTransport.idl.

Definition at line 213 of file nsSocketTransport2.h.

Definition at line 258 of file nsSocketTransport2.h.

Definition at line 84 of file nsSocketTransportService2.h.

Definition at line 222 of file nsSocketTransport2.h.

Definition at line 221 of file nsSocketTransport2.h.

Definition at line 259 of file nsSocketTransport2.h.

Definition at line 254 of file nsSocketTransport2.h.

Definition at line 256 of file nsSocketTransport2.h.

Definition at line 255 of file nsSocketTransport2.h.

Definition at line 196 of file nsSocketTransport2.h.

Definition at line 262 of file nsSocketTransport2.h.

Definition at line 214 of file nsSocketTransport2.h.

Definition at line 253 of file nsSocketTransport2.h.

Definition at line 223 of file nsSocketTransport2.h.

Definition at line 263 of file nsSocketTransport2.h.

Definition at line 215 of file nsSocketTransport2.h.

Definition at line 91 of file nsSocketTransportService2.h.

Definition at line 102 of file nsSocketTransportService2.h.

Definition at line 198 of file nsSocketTransport2.h.

Definition at line 197 of file nsSocketTransport2.h.

Definition at line 199 of file nsSocketTransport2.h.

Definition at line 200 of file nsSocketTransport2.h.

Definition at line 201 of file nsSocketTransport2.h.

Definition at line 219 of file nsSocketTransport2.h.

nsCOMPtr<nsISupports> nsSocketTransport::mSecInfo [private]

Definition at line 260 of file nsSocketTransport2.h.

Definition at line 212 of file nsSocketTransport2.h.

Definition at line 269 of file nsSocketTransport2.h.

Definition at line 195 of file nsSocketTransport2.h.

char** nsSocketTransport::mTypes [private]

Definition at line 194 of file nsSocketTransport2.h.

const unsigned long nsITransport::OPEN_BLOCKING = 1<<0 [inherited]

Open flags.

Definition at line 66 of file nsITransport.idl.

const unsigned long nsITransport::OPEN_UNBUFFERED = 1<<1 [inherited]

Definition at line 67 of file nsITransport.idl.

readonly attribute long nsISocketTransport::port [inherited]

Get the port for the underlying socket connection.

Definition at line 62 of file nsISocketTransport.idl.

Security notification callbacks passed to the secure socket provider via nsISSLSocketControl at socket creation time.

NOTE: this attribute cannot be changed once a stream has been opened.

Definition at line 89 of file nsISocketTransport.idl.

readonly attribute nsISupports nsISocketTransport::securityInfo [inherited]

Security info object returned from the secure socket provider.

This object supports nsISSLSocketControl, nsITransportSecurityInfo, and possibly other interfaces.

Definition at line 81 of file nsISocketTransport.idl.

const unsigned long nsISocketTransport::STATUS_CONNECTED_TO = 0x804b0004 [inherited]

Definition at line 128 of file nsISocketTransport.idl.

const unsigned long nsISocketTransport::STATUS_CONNECTING_TO = 0x804b0007 [inherited]

Definition at line 127 of file nsISocketTransport.idl.

const unsigned long nsITransport::STATUS_READING = 0x804b0008 [inherited]

Generic nsITransportEventSink status codes.

nsITransport implementations may override these status codes with their own more specific status codes (e.g., see nsISocketTransport).

Definition at line 165 of file nsITransport.idl.

const unsigned long nsISocketTransport::STATUS_RECEIVING_FROM = 0x804b0006 [inherited]

Definition at line 131 of file nsISocketTransport.idl.

const unsigned long nsISocketTransport::STATUS_RESOLVING = 0x804b0003 [inherited]

nsITransportEventSink status codes.

Although these look like XPCOM error codes and are passed in an nsresult variable, they are not error codes. Note that while they do overlap with existing error codes in Necko, these status codes are confined within a very limited context where no error codes may appear, so there is no ambiguity.

The values of these status codes must never change.

The status codes appear in near-chronological order (not in numeric order). STATUS_RESOLVING may be skipped if the host does not need to be resolved. STATUS_WAITING_FOR is an optional status code, which the impl of this interface may choose not to generate.

Definition at line 126 of file nsISocketTransport.idl.

const unsigned long nsISocketTransport::STATUS_SENDING_TO = 0x804b0005 [inherited]

Definition at line 129 of file nsISocketTransport.idl.

const unsigned long nsISocketTransport::STATUS_WAITING_FOR = 0x804b000a [inherited]

Definition at line 130 of file nsISocketTransport.idl.

const unsigned long nsITransport::STATUS_WRITING = 0x804b0009 [inherited]

Definition at line 166 of file nsITransport.idl.

Values for the aType parameter passed to get/setTimeout.

Definition at line 107 of file nsISocketTransport.idl.

Definition at line 108 of file nsISocketTransport.idl.


The documentation for this class was generated from the following files: