PRStatus nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, int16_t oflags) { PRStatus status; NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY, "Continuing connection in wrong state!"); LOGDEBUG(("socks: continuing connection to proxy")); status = fd->lower->methods->connectcontinue(fd->lower, oflags); if (status != PR_SUCCESS) { PRErrorCode c = PR_GetError(); if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) { // A connection failure occured, try another address mState = SOCKS_DNS_COMPLETE; return ConnectToProxy(fd); } // We're still connecting return PR_FAILURE; } // Connected now, start SOCKS if (mVersion == 4) return WriteV4ConnectRequest(); return WriteV5AuthRequest(); }
NS_IMETHODIMP nsSOCKSSocketInfo::OnLookupComplete(nsICancelable *aRequest, nsIDNSRecord *aRecord, nsresult aStatus) { NS_ABORT_IF_FALSE(aRequest == mLookup, "wrong DNS query"); mLookup = nullptr; mLookupStatus = aStatus; mDnsRec = aRecord; mState = SOCKS_DNS_COMPLETE; ConnectToProxy(mFD); mFD = nullptr; return NS_OK; }
PRStatus nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, int16_t oflags) { LOGDEBUG(("socks: DoHandshake(), state = %d", mState)); switch (mState) { case SOCKS_INITIAL: return StartDNS(fd); case SOCKS_DNS_IN_PROGRESS: PR_SetError(PR_IN_PROGRESS_ERROR, 0); return PR_FAILURE; case SOCKS_DNS_COMPLETE: return ConnectToProxy(fd); case SOCKS_CONNECTING_TO_PROXY: return ContinueConnectingToProxy(fd, oflags); case SOCKS4_WRITE_CONNECT_REQUEST: if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; WantRead(8); mState = SOCKS4_READ_CONNECT_RESPONSE; return PR_SUCCESS; case SOCKS4_READ_CONNECT_RESPONSE: if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; return ReadV4ConnectResponse(); case SOCKS5_WRITE_AUTH_REQUEST: if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; WantRead(2); mState = SOCKS5_READ_AUTH_RESPONSE; return PR_SUCCESS; case SOCKS5_READ_AUTH_RESPONSE: if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; return ReadV5AuthResponse(); case SOCKS5_WRITE_CONNECT_REQUEST: if (WriteToSocket(fd) != PR_SUCCESS) return PR_FAILURE; // The SOCKS 5 response to the connection request is variable // length. First, we'll read enough to tell how long the response // is, and will read the rest later. WantRead(5); mState = SOCKS5_READ_CONNECT_RESPONSE_TOP; return PR_SUCCESS; case SOCKS5_READ_CONNECT_RESPONSE_TOP: if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; return ReadV5ConnectResponseTop(); case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM: if (ReadFromSocket(fd) != PR_SUCCESS) return PR_FAILURE; return ReadV5ConnectResponseBottom(); case SOCKS_CONNECTED: LOGERROR(("socks: already connected")); HandshakeFinished(PR_IS_CONNECTED_ERROR); return PR_FAILURE; case SOCKS_FAILED: LOGERROR(("socks: already failed")); return PR_FAILURE; } LOGERROR(("socks: executing handshake in invalid state, %d", mState)); HandshakeFinished(PR_INVALID_STATE_ERROR); return PR_FAILURE; }