Move ServerSocket code to separate files and into test target

Classes AsyncProxyServerSocket, AsyncSSLServerSocket, and
AsyncSSLServerSocket are used only by test and example code.

Moved to server_socket_adapters.{cc,h}, and to the
rtc_base_tests_utils build target.

In the process, also deleted a few ancient and unattributed TODO
comments.

Bug: webrtc:9798
Change-Id: I21279c92bd8f1354fab7eeaf1f9697fedfc760e1
Reviewed-on: https://webrtc-review.googlesource.com/c/107735
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26039}
This commit is contained in:
Niels Möller 2018-12-17 14:04:05 +01:00 committed by Commit Bot
parent 3d2ed19d95
commit 4415315b52
9 changed files with 279 additions and 223 deletions

View File

@ -214,6 +214,7 @@ rtc_source_set("p2p_server_utils") {
":rtc_p2p", ":rtc_p2p",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base", "../rtc_base:rtc_base",
"../rtc_base:rtc_base_tests_utils",
"../rtc_base/third_party/sigslot", "../rtc_base/third_party/sigslot",
"//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/memory",
] ]

View File

@ -22,7 +22,7 @@
#include "rtc_base/helpers.h" #include "rtc_base/helpers.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/socketadapters.h" #include "rtc_base/server_socket_adapters.h"
namespace cricket { namespace cricket {

View File

@ -15,7 +15,7 @@
#include "p2p/base/relayserver.h" #include "p2p/base/relayserver.h"
#include "rtc_base/asynctcpsocket.h" #include "rtc_base/asynctcpsocket.h"
#include "rtc_base/socketadapters.h" #include "rtc_base/server_socket_adapters.h"
#include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h" #include "rtc_base/thread.h"

View File

@ -1156,6 +1156,8 @@ rtc_source_set("rtc_base_tests_utils") {
"nattypes.h", "nattypes.h",
"proxyserver.cc", "proxyserver.cc",
"proxyserver.h", "proxyserver.h",
"server_socket_adapters.cc",
"server_socket_adapters.h",
"sigslottester.h", "sigslottester.h",
"sigslottester.h.pump", "sigslottester.h.pump",
"socketstream.cc", "socketstream.cc",

View File

@ -15,7 +15,7 @@
#include <memory> #include <memory>
#include "rtc_base/asyncsocket.h" #include "rtc_base/asyncsocket.h"
#include "rtc_base/constructormagic.h" #include "rtc_base/constructormagic.h"
#include "rtc_base/socketadapters.h" #include "rtc_base/server_socket_adapters.h"
#include "rtc_base/socketaddress.h" #include "rtc_base/socketaddress.h"
#include "rtc_base/stream.h" #include "rtc_base/stream.h"

View File

@ -0,0 +1,185 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include "rtc_base/bytebuffer.h"
#include "rtc_base/server_socket_adapters.h"
namespace rtc {
AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
size_t buffer_size)
: BufferedReadAdapter(socket, buffer_size) {}
AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
: BufferedReadAdapter(socket, 1024) {
BufferInput(true);
}
void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
// We only accept client hello messages.
const ArrayView<const uint8_t> client_hello =
AsyncSSLSocket::SslClientHello();
if (*len < client_hello.size()) {
return;
}
if (memcmp(client_hello.data(), data, client_hello.size()) != 0) {
Close();
SignalCloseEvent(this, 0);
return;
}
*len -= client_hello.size();
// Clients should not send more data until the handshake is completed.
RTC_DCHECK(*len == 0);
const ArrayView<const uint8_t> server_hello =
AsyncSSLSocket::SslServerHello();
// Send a server hello back to the client.
DirectSend(server_hello.data(), server_hello.size());
// Handshake completed for us, redirect input to our parent.
BufferInput(false);
}
AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
: AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
BufferInput(true);
}
void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
RTC_DCHECK(state_ < SS_CONNECT_PENDING);
ByteBufferReader response(data, *len);
if (state_ == SS_HELLO) {
HandleHello(&response);
} else if (state_ == SS_AUTH) {
HandleAuth(&response);
} else if (state_ == SS_CONNECT) {
HandleConnect(&response);
}
// Consume parsed data
*len = response.Length();
memmove(data, response.Data(), *len);
}
void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
}
void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
uint8_t ver, num_methods;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
Error(0);
return;
}
if (ver != 5) {
Error(0);
return;
}
// Handle either no-auth (0) or user/pass auth (2)
uint8_t method = 0xFF;
if (num_methods > 0 && !request->ReadUInt8(&method)) {
Error(0);
return;
}
SendHelloReply(method);
if (method == 0) {
state_ = SS_CONNECT;
} else if (method == 2) {
state_ = SS_AUTH;
} else {
state_ = SS_ERROR;
}
}
void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
ByteBufferWriter response;
response.WriteUInt8(5); // Socks Version
response.WriteUInt8(method); // Auth method
DirectSend(response);
}
void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
uint8_t ver, user_len, pass_len;
std::string user, pass;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
!request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
!request->ReadString(&pass, pass_len)) {
Error(0);
return;
}
SendAuthReply(0);
state_ = SS_CONNECT;
}
void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
ByteBufferWriter response;
response.WriteUInt8(1); // Negotiation Version
response.WriteUInt8(result);
DirectSend(response);
}
void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
uint8_t ver, command, reserved, addr_type;
uint32_t ip;
uint16_t port;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
!request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
!request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
Error(0);
return;
}
if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
Error(0);
return;
}
SignalConnectRequest(this, SocketAddress(ip, port));
state_ = SS_CONNECT_PENDING;
}
void AsyncSocksProxyServerSocket::SendConnectResult(int result,
const SocketAddress& addr) {
if (state_ != SS_CONNECT_PENDING)
return;
ByteBufferWriter response;
response.WriteUInt8(5); // Socks version
response.WriteUInt8((result != 0)); // 0x01 is generic error
response.WriteUInt8(0); // reserved
response.WriteUInt8(1); // IPv4 address
response.WriteUInt32(addr.ip());
response.WriteUInt16(addr.port());
DirectSend(response);
BufferInput(false);
state_ = SS_TUNNEL;
}
void AsyncSocksProxyServerSocket::Error(int error) {
state_ = SS_ERROR;
BufferInput(false);
Close();
SetError(SOCKET_EACCES);
SignalCloseEvent(this, error);
}
} // namespace rtc

View File

@ -0,0 +1,72 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
#define RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
#include "rtc_base/socketadapters.h"
namespace rtc {
// Interface for implementing proxy server sockets.
class AsyncProxyServerSocket : public BufferedReadAdapter {
public:
AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size);
~AsyncProxyServerSocket() override;
sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&>
SignalConnectRequest;
virtual void SendConnectResult(int err, const SocketAddress& addr) = 0;
};
// Implements a socket adapter that performs the server side of a
// fake SSL handshake. Used when implementing a relay server that does "ssltcp".
class AsyncSSLServerSocket : public BufferedReadAdapter {
public:
explicit AsyncSSLServerSocket(AsyncSocket* socket);
protected:
void ProcessInput(char* data, size_t* len) override;
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLServerSocket);
};
// Implements a proxy server socket for the SOCKS protocol.
class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket {
public:
explicit AsyncSocksProxyServerSocket(AsyncSocket* socket);
private:
void ProcessInput(char* data, size_t* len) override;
void DirectSend(const ByteBufferWriter& buf);
void HandleHello(ByteBufferReader* request);
void SendHelloReply(uint8_t method);
void HandleAuth(ByteBufferReader* request);
void SendAuthReply(uint8_t result);
void HandleConnect(ByteBufferReader* request);
void SendConnectResult(int result, const SocketAddress& addr) override;
void Error(int error);
static const int kBufferSize = 1024;
enum State {
SS_HELLO,
SS_AUTH,
SS_CONNECT,
SS_CONNECT_PENDING,
SS_TUNNEL,
SS_ERROR
};
State state_;
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxyServerSocket);
};
} // namespace rtc
#endif // RTC_BASE_SERVER_SOCKET_ADAPTERS_H_

View File

@ -130,12 +130,6 @@ void BufferedReadAdapter::OnReadEvent(AsyncSocket* socket) {
ProcessInput(buffer_, &data_len_); ProcessInput(buffer_, &data_len_);
} }
AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
size_t buffer_size)
: BufferedReadAdapter(socket, buffer_size) {}
AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// This is a SSL v2 CLIENT_HELLO message. // This is a SSL v2 CLIENT_HELLO message.
@ -157,6 +151,13 @@ static const uint8_t kSslClientHello[] = {
0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea // 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
}; };
// static
ArrayView<const uint8_t> AsyncSSLSocket::SslClientHello() {
// Implicit conversion directly from kSslClientHello to ArrayView fails when
// built with gcc.
return {kSslClientHello, sizeof(kSslClientHello)};
}
// This is a TLSv1 SERVER_HELLO message. // This is a TLSv1 SERVER_HELLO message.
static const uint8_t kSslServerHello[] = { static const uint8_t kSslServerHello[] = {
0x16, // handshake message 0x16, // handshake message
@ -178,6 +179,11 @@ static const uint8_t kSslServerHello[] = {
0x00 // null compression 0x00 // null compression
}; };
// static
ArrayView<const uint8_t> AsyncSSLSocket::SslServerHello() {
return {kSslServerHello, sizeof(kSslServerHello)};
}
AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
: BufferedReadAdapter(socket, 1024) {} : BufferedReadAdapter(socket, 1024) {}
@ -219,35 +225,6 @@ void AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
SignalReadEvent(this); SignalReadEvent(this);
} }
AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
: BufferedReadAdapter(socket, 1024) {
BufferInput(true);
}
void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
// We only accept client hello messages.
if (*len < sizeof(kSslClientHello)) {
return;
}
if (memcmp(kSslClientHello, data, sizeof(kSslClientHello)) != 0) {
Close();
SignalCloseEvent(this, 0);
return;
}
*len -= sizeof(kSslClientHello);
// Clients should not send more data until the handshake is completed.
RTC_DCHECK(*len == 0);
// Send a server hello back to the client.
DirectSend(kSslServerHello, sizeof(kSslServerHello));
// Handshake completed for us, redirect input to our parent.
BufferInput(false);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket, AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
@ -714,135 +691,4 @@ void AsyncSocksProxySocket::Error(int error) {
SignalCloseEvent(this, error); SignalCloseEvent(this, error);
} }
AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
: AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
BufferInput(true);
}
void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
// TODO: See if the whole message has arrived
RTC_DCHECK(state_ < SS_CONNECT_PENDING);
ByteBufferReader response(data, *len);
if (state_ == SS_HELLO) {
HandleHello(&response);
} else if (state_ == SS_AUTH) {
HandleAuth(&response);
} else if (state_ == SS_CONNECT) {
HandleConnect(&response);
}
// Consume parsed data
*len = response.Length();
memmove(data, response.Data(), *len);
}
void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
}
void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
uint8_t ver, num_methods;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
Error(0);
return;
}
if (ver != 5) {
Error(0);
return;
}
// Handle either no-auth (0) or user/pass auth (2)
uint8_t method = 0xFF;
if (num_methods > 0 && !request->ReadUInt8(&method)) {
Error(0);
return;
}
// TODO: Ask the server which method to use.
SendHelloReply(method);
if (method == 0) {
state_ = SS_CONNECT;
} else if (method == 2) {
state_ = SS_AUTH;
} else {
state_ = SS_ERROR;
}
}
void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
ByteBufferWriter response;
response.WriteUInt8(5); // Socks Version
response.WriteUInt8(method); // Auth method
DirectSend(response);
}
void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
uint8_t ver, user_len, pass_len;
std::string user, pass;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
!request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
!request->ReadString(&pass, pass_len)) {
Error(0);
return;
}
// TODO: Allow for checking of credentials.
SendAuthReply(0);
state_ = SS_CONNECT;
}
void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
ByteBufferWriter response;
response.WriteUInt8(1); // Negotiation Version
response.WriteUInt8(result);
DirectSend(response);
}
void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
uint8_t ver, command, reserved, addr_type;
uint32_t ip;
uint16_t port;
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
!request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
!request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
Error(0);
return;
}
if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
Error(0);
return;
}
SignalConnectRequest(this, SocketAddress(ip, port));
state_ = SS_CONNECT_PENDING;
}
void AsyncSocksProxyServerSocket::SendConnectResult(int result,
const SocketAddress& addr) {
if (state_ != SS_CONNECT_PENDING)
return;
ByteBufferWriter response;
response.WriteUInt8(5); // Socks version
response.WriteUInt8((result != 0)); // 0x01 is generic error
response.WriteUInt8(0); // reserved
response.WriteUInt8(1); // IPv4 address
response.WriteUInt32(addr.ip());
response.WriteUInt16(addr.port());
DirectSend(response);
BufferInput(false);
state_ = SS_TUNNEL;
}
void AsyncSocksProxyServerSocket::Error(int error) {
state_ = SS_ERROR;
BufferInput(false);
Close();
SetError(SOCKET_EACCES);
SignalCloseEvent(this, error);
}
} // namespace rtc } // namespace rtc

View File

@ -13,6 +13,7 @@
#include <string> #include <string>
#include "api/array_view.h"
#include "rtc_base/asyncsocket.h" #include "rtc_base/asyncsocket.h"
#include "rtc_base/constructormagic.h" #include "rtc_base/constructormagic.h"
#include "rtc_base/cryptstring.h" #include "rtc_base/cryptstring.h"
@ -55,22 +56,13 @@ class BufferedReadAdapter : public AsyncSocketAdapter {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Interface for implementing proxy server sockets.
class AsyncProxyServerSocket : public BufferedReadAdapter {
public:
AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size);
~AsyncProxyServerSocket() override;
sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&>
SignalConnectRequest;
virtual void SendConnectResult(int err, const SocketAddress& addr) = 0;
};
///////////////////////////////////////////////////////////////////////////////
// Implements a socket adapter that performs the client side of a // Implements a socket adapter that performs the client side of a
// fake SSL handshake. Used for "ssltcp" P2P functionality. // fake SSL handshake. Used for "ssltcp" P2P functionality.
class AsyncSSLSocket : public BufferedReadAdapter { class AsyncSSLSocket : public BufferedReadAdapter {
public: public:
static ArrayView<const uint8_t> SslClientHello();
static ArrayView<const uint8_t> SslServerHello();
explicit AsyncSSLSocket(AsyncSocket* socket); explicit AsyncSSLSocket(AsyncSocket* socket);
int Connect(const SocketAddress& addr) override; int Connect(const SocketAddress& addr) override;
@ -81,17 +73,6 @@ class AsyncSSLSocket : public BufferedReadAdapter {
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLSocket); RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLSocket);
}; };
// Implements a socket adapter that performs the server side of a
// fake SSL handshake. Used when implementing a relay server that does "ssltcp".
class AsyncSSLServerSocket : public BufferedReadAdapter {
public:
explicit AsyncSSLServerSocket(AsyncSocket* socket);
protected:
void ProcessInput(char* data, size_t* len) override;
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLServerSocket);
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Implements a socket adapter that speaks the HTTP/S proxy protocol. // Implements a socket adapter that speaks the HTTP/S proxy protocol.
@ -184,37 +165,6 @@ class AsyncSocksProxySocket : public BufferedReadAdapter {
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxySocket); RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxySocket);
}; };
// Implements a proxy server socket for the SOCKS protocol.
class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket {
public:
explicit AsyncSocksProxyServerSocket(AsyncSocket* socket);
private:
void ProcessInput(char* data, size_t* len) override;
void DirectSend(const ByteBufferWriter& buf);
void HandleHello(ByteBufferReader* request);
void SendHelloReply(uint8_t method);
void HandleAuth(ByteBufferReader* request);
void SendAuthReply(uint8_t result);
void HandleConnect(ByteBufferReader* request);
void SendConnectResult(int result, const SocketAddress& addr) override;
void Error(int error);
static const int kBufferSize = 1024;
enum State {
SS_HELLO,
SS_AUTH,
SS_CONNECT,
SS_CONNECT_PENDING,
SS_TUNNEL,
SS_ERROR
};
State state_;
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxyServerSocket);
};
} // namespace rtc } // namespace rtc
#endif // RTC_BASE_SOCKETADAPTERS_H_ #endif // RTC_BASE_SOCKETADAPTERS_H_