From 6d594cc227f153364b91e8310d59a07d7d6ce5f6 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Tue, 2 Apr 2013 15:56:49 -0700 Subject: [PATCH] Bug 3875: Use Optimistic Data SOCKS variant. This patch alters Firefox's SOCKS handshake to preemptively send data before it is actually connected. This allows us to save a round trip during connection setup. See: https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/181-optimistic-data-client.txt --- netwerk/base/nsSocketTransport2.cpp | 44 +++++++++++++++++++++++------ netwerk/base/nsSocketTransport2.h | 4 ++- netwerk/socket/nsSOCKSIOLayer.cpp | 3 +- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index 1bfd1fc915255..4399465fe5347 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -1983,7 +1983,26 @@ nsSocketTransport::OnSocketReady(PRFileDesc *fd, int16_t outFlags) // Update poll timeout in case it was changed mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE]; } - else if ((mState == STATE_CONNECTING) && !gIOService->IsNetTearingDown()) { + // Tor 3875: Use optimistic data with SOCKS. + // To accomplish this, two new states were added that are only used with + // SOCKS connections: + // STATE_SENDINGGET - The SOCKS handshake has proceeded to the + // "sent connect" state; now it is okay to + // optimistically send some application data (e.g., + // an HTTP GET request). + // STATE_SENTGET - Optimistic data has been sent; make a second call + // to PR_ConnectContinue() to allow the SOCKS + // handshake to finish. + else if (mState == STATE_SENDINGGET) { + if ((mPollFlags & PR_POLL_WRITE) && (outFlags & ~PR_POLL_READ)) { + mOutput.OnSocketReady(NS_OK); // Allow application data to be sent. + } + mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE]; + mPollFlags = (PR_POLL_EXCEPT | PR_POLL_READ); + mState = STATE_SENTGET; // Wait for SOCKS handshake response. + } + else if (((mState == STATE_CONNECTING) || (mState = STATE_SENTGET)) && + !gIOService->IsNetTearingDown()) { // We do not need to do PR_ConnectContinue when we are already // shutting down. @@ -2007,7 +2026,14 @@ nsSocketTransport::OnSocketReady(PRFileDesc *fd, int16_t outFlags) Telemetry::PRCONNECTCONTINUE_BLOCKING_TIME_OFFLINE); } - if (status == PR_SUCCESS) { + bool isUsingSocks = mProxyTransparent && !mProxyHost.IsEmpty(); + if (status == PR_SUCCESS && mState == STATE_CONNECTING) { + OnSocketConnected(); + if (isUsingSocks) { + mState = STATE_SENDINGGET; + } + } + else if (status == PR_SUCCESS && mState == STATE_SENTGET) { // // we are connected! // @@ -2034,17 +2060,17 @@ nsSocketTransport::OnSocketReady(PRFileDesc *fd, int16_t outFlags) // 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]; + if (mState != STATE_SENTGET) { + // 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]; + } } // // The SOCKS proxy rejected our request. Find out why. // - else if (PR_UNKNOWN_ERROR == code && - mProxyTransparent && - !mProxyHost.IsEmpty()) { + else if (PR_UNKNOWN_ERROR == code && isUsingSocks) { code = PR_GetOSError(); mCondition = ErrorAccordingToNSPR(code); } diff --git a/netwerk/base/nsSocketTransport2.h b/netwerk/base/nsSocketTransport2.h index 7c85ccdc409f2..b4baed233ff1b 100644 --- a/netwerk/base/nsSocketTransport2.h +++ b/netwerk/base/nsSocketTransport2.h @@ -201,7 +201,9 @@ private: STATE_IDLE, STATE_RESOLVING, STATE_CONNECTING, - STATE_TRANSFERRING + STATE_TRANSFERRING, + STATE_SENDINGGET, + STATE_SENTGET }; // Safer way to get and automatically release PRFileDesc objects. diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp index 22f5751fbe963..41699e47ef77b 100644 --- a/netwerk/socket/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/nsSOCKSIOLayer.cpp @@ -83,7 +83,8 @@ public: void SetConnectTimeout(PRIntervalTime to); PRStatus DoHandshake(PRFileDesc *fd, int16_t oflags = -1); int16_t GetPollFlags() const; - bool IsConnected() const { return mState == SOCKS_CONNECTED; } + bool IsConnected() const { return (mState == SOCKS_CONNECTED || + mState == SOCKS5_READ_CONNECT_RESPONSE_TOP); } void ForgetFD() { mFD = nullptr; } void SetNamedPipeFD(PRFileDesc *fd) { mFD = fd; } -- GitLab