Remove AsyncHttpRequest, AutoPortAllocator, ConnectivityChecker, and HttpPortAllocator.

BUG=webrtc:4149, webrtc:4456
R=deadbeef@webrtc.org, pbos@webrtc.org

Review URL: https://codereview.webrtc.org/1311353011 .

Cr-Commit-Position: refs/heads/master@{#9857}
This commit is contained in:
Peter Thatcher
2015-09-04 04:21:07 -07:00
parent 2f9fd5ddb9
commit d415629de7
14 changed files with 13 additions and 1888 deletions

View File

@ -197,8 +197,6 @@ static_library("rtc_base") {
"arraysize.h",
"asyncfile.cc",
"asyncfile.h",
"asynchttprequest.cc",
"asynchttprequest.h",
"asyncinvoker-inl.h",
"asyncinvoker.cc",
"asyncinvoker.h",

View File

@ -1,116 +1,2 @@
/*
* 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 "webrtc/base/asynchttprequest.h"
namespace rtc {
enum {
MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
MSG_LAUNCH_REQUEST
};
static const int kDefaultHTTPTimeout = 30 * 1000; // 30 sec
///////////////////////////////////////////////////////////////////////////////
// AsyncHttpRequest
///////////////////////////////////////////////////////////////////////////////
AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
: start_delay_(0),
firewall_(NULL),
port_(80),
secure_(false),
timeout_(kDefaultHTTPTimeout),
fail_redirect_(false),
factory_(Thread::Current()->socketserver(), user_agent),
pool_(&factory_),
client_(user_agent.c_str(), &pool_),
error_(HE_NONE) {
client_.SignalHttpClientComplete.connect(this,
&AsyncHttpRequest::OnComplete);
}
AsyncHttpRequest::~AsyncHttpRequest() {
}
void AsyncHttpRequest::OnWorkStart() {
if (start_delay_ <= 0) {
LaunchRequest();
} else {
Thread::Current()->PostDelayed(start_delay_, this, MSG_LAUNCH_REQUEST);
}
}
void AsyncHttpRequest::OnWorkStop() {
// worker is already quitting, no need to explicitly quit
LOG(LS_INFO) << "HttpRequest cancelled";
}
void AsyncHttpRequest::OnComplete(HttpClient* client, HttpErrorType error) {
Thread::Current()->Clear(this, MSG_TIMEOUT);
set_error(error);
if (!error) {
LOG(LS_INFO) << "HttpRequest completed successfully";
std::string value;
if (client_.response().hasHeader(HH_LOCATION, &value)) {
response_redirect_ = value.c_str();
}
} else {
LOG(LS_INFO) << "HttpRequest completed with error: " << error;
}
worker()->Quit();
}
void AsyncHttpRequest::OnMessage(Message* message) {
switch (message->message_id) {
case MSG_TIMEOUT:
LOG(LS_INFO) << "HttpRequest timed out";
client_.reset();
worker()->Quit();
break;
case MSG_LAUNCH_REQUEST:
LaunchRequest();
break;
default:
SignalThread::OnMessage(message);
break;
}
}
void AsyncHttpRequest::DoWork() {
// Do nothing while we wait for the request to finish. We only do this so
// that we can be a SignalThread; in the future this class should not be
// a SignalThread, since it does not need to spawn a new thread.
Thread::Current()->ProcessMessages(Thread::kForever);
}
void AsyncHttpRequest::LaunchRequest() {
factory_.SetProxy(proxy_);
if (secure_)
factory_.UseSSL(host_.c_str());
bool transparent_proxy = (port_ == 80) &&
((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
if (transparent_proxy) {
client_.set_proxy(proxy_);
}
client_.set_fail_redirect(fail_redirect_);
client_.set_server(SocketAddress(host_, port_));
LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
client_.start();
}
} // namespace rtc
// TODO(pthatcher): Remove this file once chromium's GYP file doesn't
// refer to it.

View File

@ -1,104 +1,2 @@
/*
* 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 WEBRTC_BASE_ASYNCHTTPREQUEST_H_
#define WEBRTC_BASE_ASYNCHTTPREQUEST_H_
#include <string>
#include "webrtc/base/event.h"
#include "webrtc/base/httpclient.h"
#include "webrtc/base/signalthread.h"
#include "webrtc/base/socketpool.h"
#include "webrtc/base/sslsocketfactory.h"
namespace rtc {
class FirewallManager;
///////////////////////////////////////////////////////////////////////////////
// AsyncHttpRequest
// Performs an HTTP request on a background thread. Notifies on the foreground
// thread once the request is done (successfully or unsuccessfully).
///////////////////////////////////////////////////////////////////////////////
class AsyncHttpRequest : public SignalThread {
public:
explicit AsyncHttpRequest(const std::string &user_agent);
~AsyncHttpRequest() override;
// If start_delay is less than or equal to zero, this starts immediately.
// Start_delay defaults to zero.
int start_delay() const { return start_delay_; }
void set_start_delay(int delay) { start_delay_ = delay; }
const ProxyInfo& proxy() const { return proxy_; }
void set_proxy(const ProxyInfo& proxy) {
proxy_ = proxy;
}
void set_firewall(FirewallManager * firewall) {
firewall_ = firewall;
}
// The DNS name of the host to connect to.
const std::string& host() { return host_; }
void set_host(const std::string& host) { host_ = host; }
// The port to connect to on the target host.
int port() { return port_; }
void set_port(int port) { port_ = port; }
// Whether the request should use SSL.
bool secure() { return secure_; }
void set_secure(bool secure) { secure_ = secure; }
// Time to wait on the download, in ms.
int timeout() { return timeout_; }
void set_timeout(int timeout) { timeout_ = timeout; }
// Fail redirects to allow analysis of redirect urls, etc.
bool fail_redirect() const { return fail_redirect_; }
void set_fail_redirect(bool redirect) { fail_redirect_ = redirect; }
// Returns the redirect when redirection occurs
const std::string& response_redirect() { return response_redirect_; }
HttpRequestData& request() { return client_.request(); }
HttpResponseData& response() { return client_.response(); }
HttpErrorType error() { return error_; }
protected:
void set_error(HttpErrorType error) { error_ = error; }
void OnWorkStart() override;
void OnWorkStop() override;
void OnComplete(HttpClient* client, HttpErrorType error);
void OnMessage(Message* message) override;
void DoWork() override;
private:
void LaunchRequest();
int start_delay_;
ProxyInfo proxy_;
FirewallManager* firewall_;
std::string host_;
int port_;
bool secure_;
int timeout_;
bool fail_redirect_;
SslSocketFactory factory_;
ReuseSocketPool pool_;
HttpClient client_;
HttpErrorType error_;
std::string response_redirect_;
};
} // namespace rtc
#endif // WEBRTC_BASE_ASYNCHTTPREQUEST_H_
// TODO(pthatcher): Remove this file once chromium's GYP file doesn't
// refer to it.

View File

@ -1,234 +0,0 @@
/*
* 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 "webrtc/base/asynchttprequest.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/httpserver.h"
#include "webrtc/base/socketstream.h"
#include "webrtc/base/thread.h"
#include "webrtc/test/testsupport/gtest_disable.h"
namespace rtc {
static const SocketAddress kServerAddr("127.0.0.1", 0);
static const SocketAddress kServerHostnameAddr("localhost", 0);
static const char kServerGetPath[] = "/get";
static const char kServerPostPath[] = "/post";
static const char kServerResponse[] = "This is a test";
class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
public:
TestHttpServer(Thread* thread, const SocketAddress& addr) :
socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
SOCK_STREAM)) {
socket_->Bind(addr);
socket_->Listen(5);
socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
}
SocketAddress address() const { return socket_->GetLocalAddress(); }
void Close() const { socket_->Close(); }
private:
void OnAccept(AsyncSocket* socket) {
AsyncSocket* new_socket = socket_->Accept(NULL);
if (new_socket) {
HandleConnection(new SocketStream(new_socket));
}
}
rtc::scoped_ptr<AsyncSocket> socket_;
};
class AsyncHttpRequestTest : public testing::Test,
public sigslot::has_slots<> {
public:
AsyncHttpRequestTest()
: started_(false),
done_(false),
server_(Thread::Current(), kServerAddr) {
server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
}
bool started() const { return started_; }
bool done() const { return done_; }
AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
const std::string& path) {
rtc::AsyncHttpRequest* request =
new rtc::AsyncHttpRequest("unittest");
request->SignalWorkDone.connect(this,
&AsyncHttpRequestTest::OnRequestDone);
request->request().verb = rtc::HV_GET;
request->set_host(host);
request->set_port(port);
request->request().path = path;
request->response().document.reset(new MemoryStream());
return request;
}
AsyncHttpRequest* CreatePostRequest(const std::string& host, int port,
const std::string& path,
const std::string content_type,
StreamInterface* content) {
rtc::AsyncHttpRequest* request =
new rtc::AsyncHttpRequest("unittest");
request->SignalWorkDone.connect(this,
&AsyncHttpRequestTest::OnRequestDone);
request->request().verb = rtc::HV_POST;
request->set_host(host);
request->set_port(port);
request->request().path = path;
request->request().setContent(content_type, content);
request->response().document.reset(new MemoryStream());
return request;
}
const TestHttpServer& server() const { return server_; }
protected:
void OnRequest(HttpServer* server, HttpServerTransaction* t) {
started_ = true;
if (t->request.path == kServerGetPath) {
t->response.set_success("text/plain", new MemoryStream(kServerResponse));
} else if (t->request.path == kServerPostPath) {
// reverse the data and reply
size_t size;
StreamInterface* in = t->request.document.get();
StreamInterface* out = new MemoryStream();
in->GetSize(&size);
for (size_t i = 0; i < size; ++i) {
char ch;
in->SetPosition(size - i - 1);
in->Read(&ch, 1, NULL, NULL);
out->Write(&ch, 1, NULL, NULL);
}
out->Rewind();
t->response.set_success("text/plain", out);
} else {
t->response.set_error(404);
}
server_.Respond(t);
}
void OnRequestDone(SignalThread* thread) {
done_ = true;
}
private:
bool started_;
bool done_;
TestHttpServer server_;
};
TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
AsyncHttpRequest* req = CreateGetRequest(
kServerHostnameAddr.hostname(), server().address().port(),
kServerGetPath);
EXPECT_FALSE(started());
req->Start();
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
EXPECT_TRUE_WAIT(done(), 5000);
std::string response;
EXPECT_EQ(200U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->Rewind();
req->response().document->ReadLine(&response);
EXPECT_EQ(kServerResponse, response);
req->Release();
}
TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
AsyncHttpRequest* req = CreateGetRequest(
kServerHostnameAddr.hostname(), server().address().port(),
"/bad");
req->Start();
EXPECT_TRUE_WAIT(done(), 5000);
size_t size;
EXPECT_EQ(404U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->GetSize(&size);
EXPECT_EQ(0U, size);
req->Release();
}
TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
AsyncHttpRequest* req = CreateGetRequest(
"127.0.0.1", server().address().port(),
kServerGetPath);
// Stop the server before we send the request.
server().Close();
req->Start();
EXPECT_TRUE_WAIT(done(), 10000);
size_t size;
EXPECT_EQ(500U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->GetSize(&size);
EXPECT_EQ(0U, size);
req->Release();
}
TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
AsyncHttpRequest* req = CreateGetRequest(
"invalid", server().address().port(),
kServerGetPath);
req->Start();
EXPECT_TRUE_WAIT(done(), 5000);
size_t size;
EXPECT_EQ(500U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->GetSize(&size);
EXPECT_EQ(0U, size);
req->Release();
}
TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
AsyncHttpRequest* req = CreatePostRequest(
kServerHostnameAddr.hostname(), server().address().port(),
kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
req->Start();
EXPECT_TRUE_WAIT(done(), 5000);
std::string response;
EXPECT_EQ(200U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->Rewind();
req->response().document->ReadLine(&response);
EXPECT_EQ("4321dcba", response);
req->Release();
}
// Ensure that we shut down properly even if work is outstanding.
TEST_F(AsyncHttpRequestTest, TestCancel) {
AsyncHttpRequest* req = CreateGetRequest(
kServerHostnameAddr.hostname(), server().address().port(),
kServerGetPath);
req->Start();
req->Destroy(true);
}
TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
AsyncHttpRequest* req = CreateGetRequest(
kServerHostnameAddr.hostname(), server().address().port(),
kServerGetPath);
req->set_start_delay(10); // Delay 10ms.
req->Start();
Thread::SleepMs(5);
EXPECT_FALSE(started()); // Should not have started immediately.
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
EXPECT_TRUE_WAIT(done(), 5000);
std::string response;
EXPECT_EQ(200U, req->response().scode);
ASSERT_TRUE(req->response().document);
req->response().document->Rewind();
req->response().document->ReadLine(&response);
EXPECT_EQ(kServerResponse, response);
req->Release();
}
} // namespace rtc

View File

@ -117,8 +117,6 @@
'arraysize.h',
'asyncfile.cc',
'asyncfile.h',
'asynchttprequest.cc',
'asynchttprequest.h',
'asyncinvoker.cc',
'asyncinvoker.h',
'asyncinvoker-inl.h',

View File

@ -44,7 +44,6 @@
'type': 'none',
'direct_dependent_settings': {
'sources': [
'asynchttprequest_unittest.cc',
'atomicops_unittest.cc',
'autodetectproxy_unittest.cc',
'bandwidthsmoother_unittest.cc',

View File

@ -1,529 +0,0 @@
/*
* Copyright 2011 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 "webrtc/p2p/client/connectivitychecker.h"
#include "webrtc/p2p/base/candidate.h"
#include "webrtc/p2p/base/common.h"
#include "webrtc/p2p/base/constants.h"
#include "webrtc/p2p/base/port.h"
#include "webrtc/p2p/base/relayport.h"
#include "webrtc/p2p/base/stunport.h"
#include "webrtc/base/asynchttprequest.h"
#include "webrtc/base/autodetectproxy.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/httpcommon-inl.h"
#include "webrtc/base/httpcommon.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/proxydetect.h"
#include "webrtc/base/thread.h"
namespace cricket {
static const char kDefaultStunHostname[] = "stun.l.google.com";
static const int kDefaultStunPort = 19302;
// Default maximum time in milliseconds we will wait for connections.
static const uint32 kDefaultTimeoutMs = 3000;
enum {
MSG_START = 1,
MSG_STOP = 2,
MSG_TIMEOUT = 3,
MSG_SIGNAL_RESULTS = 4
};
class TestHttpPortAllocator : public HttpPortAllocator {
public:
TestHttpPortAllocator(rtc::NetworkManager* network_manager,
const std::string& user_agent,
const std::string& relay_token) :
HttpPortAllocator(network_manager, user_agent) {
SetRelayToken(relay_token);
}
PortAllocatorSession* CreateSessionInternal(
const std::string& content_name,
int component,
const std::string& ice_ufrag,
const std::string& ice_pwd) {
return new TestHttpPortAllocatorSession(this, content_name, component,
ice_ufrag, ice_pwd,
stun_hosts(), relay_hosts(),
relay_token(), user_agent());
}
};
void TestHttpPortAllocatorSession::ConfigReady(PortConfiguration* config) {
SignalConfigReady(username(), password(), config, proxy_);
delete config;
}
void TestHttpPortAllocatorSession::OnRequestDone(
rtc::SignalThread* data) {
rtc::AsyncHttpRequest* request =
static_cast<rtc::AsyncHttpRequest*>(data);
// Tell the checker that the request is complete.
SignalRequestDone(request);
// Pass on the response to super class.
HttpPortAllocatorSession::OnRequestDone(data);
}
ConnectivityChecker::ConnectivityChecker(
rtc::Thread* worker,
const std::string& jid,
const std::string& session_id,
const std::string& user_agent,
const std::string& relay_token,
const std::string& connection)
: worker_(worker),
jid_(jid),
session_id_(session_id),
user_agent_(user_agent),
relay_token_(relay_token),
connection_(connection),
proxy_detect_(NULL),
timeout_ms_(kDefaultTimeoutMs),
stun_address_(kDefaultStunHostname, kDefaultStunPort),
started_(false) {
}
ConnectivityChecker::~ConnectivityChecker() {
if (started_) {
// We try to clear the TIMEOUT below. But worker may still handle it and
// cause SignalCheckDone to happen on main-thread. So we finally clear any
// pending SIGNAL_RESULTS.
worker_->Clear(this, MSG_TIMEOUT);
worker_->Send(this, MSG_STOP);
nics_.clear();
main_->Clear(this, MSG_SIGNAL_RESULTS);
}
}
bool ConnectivityChecker::Initialize() {
network_manager_.reset(CreateNetworkManager());
socket_factory_.reset(CreateSocketFactory(worker_));
port_allocator_.reset(CreatePortAllocator(network_manager_.get(),
user_agent_, relay_token_));
return true;
}
void ConnectivityChecker::Start() {
main_ = rtc::Thread::Current();
worker_->Post(this, MSG_START);
started_ = true;
}
void ConnectivityChecker::CleanUp() {
ASSERT(worker_ == rtc::Thread::Current());
if (proxy_detect_) {
proxy_detect_->Release();
proxy_detect_ = NULL;
}
for (uint32 i = 0; i < sessions_.size(); ++i) {
delete sessions_[i];
}
sessions_.clear();
for (uint32 i = 0; i < ports_.size(); ++i) {
delete ports_[i];
}
ports_.clear();
}
bool ConnectivityChecker::AddNic(const rtc::IPAddress& ip,
const rtc::SocketAddress& proxy_addr) {
NicMap::iterator i = nics_.find(NicId(ip, proxy_addr));
if (i != nics_.end()) {
// Already have it.
return false;
}
uint32 now = rtc::Time();
NicInfo info;
info.ip = ip;
info.proxy_info = GetProxyInfo();
info.stun.start_time_ms = now;
nics_.insert(std::pair<NicId, NicInfo>(NicId(ip, proxy_addr), info));
return true;
}
void ConnectivityChecker::SetProxyInfo(const rtc::ProxyInfo& proxy_info) {
port_allocator_->set_proxy(user_agent_, proxy_info);
AllocatePorts();
}
rtc::ProxyInfo ConnectivityChecker::GetProxyInfo() const {
rtc::ProxyInfo proxy_info;
if (proxy_detect_) {
proxy_info = proxy_detect_->proxy();
}
return proxy_info;
}
void ConnectivityChecker::CheckNetworks() {
network_manager_->SignalNetworksChanged.connect(
this, &ConnectivityChecker::OnNetworksChanged);
network_manager_->StartUpdating();
}
void ConnectivityChecker::OnMessage(rtc::Message *msg) {
switch (msg->message_id) {
case MSG_START:
ASSERT(worker_ == rtc::Thread::Current());
worker_->PostDelayed(timeout_ms_, this, MSG_TIMEOUT);
CheckNetworks();
break;
case MSG_STOP:
// We're being stopped, free resources.
CleanUp();
break;
case MSG_TIMEOUT:
// We need to signal results on the main thread.
main_->Post(this, MSG_SIGNAL_RESULTS);
break;
case MSG_SIGNAL_RESULTS:
ASSERT(main_ == rtc::Thread::Current());
SignalCheckDone(this);
break;
default:
LOG(LS_ERROR) << "Unknown message: " << msg->message_id;
}
}
void ConnectivityChecker::OnProxyDetect(rtc::SignalThread* thread) {
ASSERT(worker_ == rtc::Thread::Current());
if (proxy_detect_->proxy().type != rtc::PROXY_NONE) {
SetProxyInfo(proxy_detect_->proxy());
}
}
void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) {
ASSERT(worker_ == rtc::Thread::Current());
// Since we don't know what nic were actually used for the http request,
// for now, just use the first one.
std::vector<rtc::Network*> networks;
network_manager_->GetNetworks(&networks);
if (networks.empty()) {
LOG(LS_ERROR) << "No networks while registering http start.";
return;
}
rtc::ProxyInfo proxy_info = request->proxy();
NicMap::iterator i =
nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
if (i != nics_.end()) {
int port = request->port();
uint32 now = rtc::Time();
NicInfo* nic_info = &i->second;
if (port == rtc::HTTP_SECURE_PORT) {
nic_info->https.rtt = now - nic_info->https.start_time_ms;
} else {
LOG(LS_ERROR) << "Got response with unknown port: " << port;
}
} else {
LOG(LS_ERROR) << "No nic info found while receiving response.";
}
}
void ConnectivityChecker::OnConfigReady(
const std::string& username, const std::string& password,
const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
ASSERT(worker_ == rtc::Thread::Current());
// Since we send requests on both HTTP and HTTPS we will get two
// configs per nic. Results from the second will overwrite the
// result from the first.
// TODO: Handle multiple pings on one nic.
CreateRelayPorts(username, password, config, proxy_info);
}
void ConnectivityChecker::OnRelayPortComplete(Port* port) {
ASSERT(worker_ == rtc::Thread::Current());
RelayPort* relay_port = reinterpret_cast<RelayPort*>(port);
const ProtocolAddress* address = relay_port->ServerAddress(0);
rtc::IPAddress ip = port->Network()->GetBestIP();
NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
if (i != nics_.end()) {
// We have it already, add the new information.
NicInfo* nic_info = &i->second;
ConnectInfo* connect_info = NULL;
if (address) {
switch (address->proto) {
case PROTO_UDP:
connect_info = &nic_info->udp;
break;
case PROTO_TCP:
connect_info = &nic_info->tcp;
break;
case PROTO_SSLTCP:
connect_info = &nic_info->ssltcp;
break;
default:
LOG(LS_ERROR) << " relay address with bad protocol added";
}
if (connect_info) {
connect_info->rtt =
rtc::TimeSince(connect_info->start_time_ms);
}
}
} else {
LOG(LS_ERROR) << " got relay address for non-existing nic";
}
}
void ConnectivityChecker::OnStunPortComplete(Port* port) {
ASSERT(worker_ == rtc::Thread::Current());
const std::vector<Candidate> candidates = port->Candidates();
Candidate c = candidates[0];
rtc::IPAddress ip = port->Network()->GetBestIP();
NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
if (i != nics_.end()) {
// We have it already, add the new information.
uint32 now = rtc::Time();
NicInfo* nic_info = &i->second;
nic_info->external_address = c.address();
nic_info->stun_server_addresses =
static_cast<StunPort*>(port)->server_addresses();
nic_info->stun.rtt = now - nic_info->stun.start_time_ms;
} else {
LOG(LS_ERROR) << "Got stun address for non-existing nic";
}
}
void ConnectivityChecker::OnStunPortError(Port* port) {
ASSERT(worker_ == rtc::Thread::Current());
LOG(LS_ERROR) << "Stun address error.";
rtc::IPAddress ip = port->Network()->GetBestIP();
NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
if (i != nics_.end()) {
// We have it already, add the new information.
NicInfo* nic_info = &i->second;
nic_info->stun_server_addresses =
static_cast<StunPort*>(port)->server_addresses();
}
}
void ConnectivityChecker::OnRelayPortError(Port* port) {
ASSERT(worker_ == rtc::Thread::Current());
LOG(LS_ERROR) << "Relay address error.";
}
void ConnectivityChecker::OnNetworksChanged() {
ASSERT(worker_ == rtc::Thread::Current());
std::vector<rtc::Network*> networks;
network_manager_->GetNetworks(&networks);
if (networks.empty()) {
LOG(LS_ERROR) << "Machine has no networks; nothing to do";
return;
}
AllocatePorts();
}
HttpPortAllocator* ConnectivityChecker::CreatePortAllocator(
rtc::NetworkManager* network_manager,
const std::string& user_agent,
const std::string& relay_token) {
return new TestHttpPortAllocator(network_manager, user_agent, relay_token);
}
StunPort* ConnectivityChecker::CreateStunPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network) {
return StunPort::Create(worker_,
socket_factory_.get(),
network,
network->GetBestIP(),
0,
0,
username,
password,
config->stun_servers,
std::string());
}
RelayPort* ConnectivityChecker::CreateRelayPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network) {
return RelayPort::Create(worker_,
socket_factory_.get(),
network,
network->GetBestIP(),
port_allocator_->min_port(),
port_allocator_->max_port(),
username,
password);
}
void ConnectivityChecker::CreateRelayPorts(
const std::string& username, const std::string& password,
const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
PortConfiguration::RelayList::const_iterator relay;
std::vector<rtc::Network*> networks;
network_manager_->GetNetworks(&networks);
if (networks.empty()) {
LOG(LS_ERROR) << "Machine has no networks; no relay ports created.";
return;
}
for (relay = config->relays.begin();
relay != config->relays.end(); ++relay) {
for (uint32 i = 0; i < networks.size(); ++i) {
NicMap::iterator iter =
nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address));
if (iter != nics_.end()) {
// TODO: Now setting the same start time for all protocols.
// This might affect accuracy, but since we are mainly looking for
// connect failures or number that stick out, this is good enough.
uint32 now = rtc::Time();
NicInfo* nic_info = &iter->second;
nic_info->udp.start_time_ms = now;
nic_info->tcp.start_time_ms = now;
nic_info->ssltcp.start_time_ms = now;
// Add the addresses of this protocol.
PortList::const_iterator relay_port;
for (relay_port = relay->ports.begin();
relay_port != relay->ports.end();
++relay_port) {
RelayPort* port = CreateRelayPort(username, password,
config, networks[i]);
port->AddServerAddress(*relay_port);
port->AddExternalAddress(*relay_port);
nic_info->media_server_address = port->ServerAddress(0)->address;
// Listen to network events.
port->SignalPortComplete.connect(
this, &ConnectivityChecker::OnRelayPortComplete);
port->SignalPortError.connect(
this, &ConnectivityChecker::OnRelayPortError);
port->set_proxy(user_agent_, proxy_info);
// Start fetching an address for this port.
port->PrepareAddress();
ports_.push_back(port);
}
} else {
LOG(LS_ERROR) << "Failed to find nic info when creating relay ports.";
}
}
}
}
void ConnectivityChecker::AllocatePorts() {
const std::string username = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
const std::string password = rtc::CreateRandomString(ICE_PWD_LENGTH);
ServerAddresses stun_servers;
stun_servers.insert(stun_address_);
PortConfiguration config(stun_servers, username, password);
std::vector<rtc::Network*> networks;
network_manager_->GetNetworks(&networks);
if (networks.empty()) {
LOG(LS_ERROR) << "Machine has no networks; no ports will be allocated";
return;
}
rtc::ProxyInfo proxy_info = GetProxyInfo();
bool allocate_relay_ports = false;
for (uint32 i = 0; i < networks.size(); ++i) {
if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) {
Port* port = CreateStunPort(username, password, &config, networks[i]);
if (port) {
// Listen to network events.
port->SignalPortComplete.connect(
this, &ConnectivityChecker::OnStunPortComplete);
port->SignalPortError.connect(
this, &ConnectivityChecker::OnStunPortError);
port->set_proxy(user_agent_, proxy_info);
port->PrepareAddress();
ports_.push_back(port);
allocate_relay_ports = true;
}
}
}
// If any new ip/proxy combinations were added, send a relay allocate.
if (allocate_relay_ports) {
AllocateRelayPorts();
}
// Initiate proxy detection.
InitiateProxyDetection();
}
void ConnectivityChecker::InitiateProxyDetection() {
// Only start if we haven't been started before.
if (!proxy_detect_) {
proxy_detect_ = new rtc::AutoDetectProxy(user_agent_);
rtc::Url<char> host_url("/", "relay.google.com",
rtc::HTTP_SECURE_PORT);
host_url.set_secure(true);
proxy_detect_->set_server_url(host_url.url());
proxy_detect_->SignalWorkDone.connect(
this, &ConnectivityChecker::OnProxyDetect);
proxy_detect_->Start();
}
}
void ConnectivityChecker::AllocateRelayPorts() {
// Currently we are using the 'default' nic for http(s) requests.
TestHttpPortAllocatorSession* allocator_session =
reinterpret_cast<TestHttpPortAllocatorSession*>(
port_allocator_->CreateSessionInternal(
"connectivity checker test content",
ICE_CANDIDATE_COMPONENT_RTP,
rtc::CreateRandomString(ICE_UFRAG_LENGTH),
rtc::CreateRandomString(ICE_PWD_LENGTH)));
allocator_session->set_proxy(port_allocator_->proxy());
allocator_session->SignalConfigReady.connect(
this, &ConnectivityChecker::OnConfigReady);
allocator_session->SignalRequestDone.connect(
this, &ConnectivityChecker::OnRequestDone);
// Try https only since using http would result in credentials being sent
// over the network unprotected.
RegisterHttpStart(rtc::HTTP_SECURE_PORT);
allocator_session->SendSessionRequest("relay.l.google.com",
rtc::HTTP_SECURE_PORT);
sessions_.push_back(allocator_session);
}
void ConnectivityChecker::RegisterHttpStart(int port) {
// Since we don't know what nic were actually used for the http request,
// for now, just use the first one.
std::vector<rtc::Network*> networks;
network_manager_->GetNetworks(&networks);
if (networks.empty()) {
LOG(LS_ERROR) << "No networks while registering http start.";
return;
}
rtc::ProxyInfo proxy_info = GetProxyInfo();
NicMap::iterator i =
nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
if (i != nics_.end()) {
uint32 now = rtc::Time();
NicInfo* nic_info = &i->second;
if (port == rtc::HTTP_SECURE_PORT) {
nic_info->https.start_time_ms = now;
} else {
LOG(LS_ERROR) << "Registering start time for unknown port: " << port;
}
} else {
LOG(LS_ERROR) << "Error, no nic info found while registering http start.";
}
}
} // namespace rtc

View File

@ -1,281 +0,0 @@
/*
* Copyright 2011 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 WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_
#define WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_
#include <map>
#include <string>
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/client/httpportallocator.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/messagehandler.h"
#include "webrtc/base/network.h"
#include "webrtc/base/proxyinfo.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/socketaddress.h"
namespace rtc {
class AsyncHttpRequest;
class AutoDetectProxy;
class BasicPacketSocketFactory;
class NetworkManager;
class PacketSocketFactory;
class SignalThread;
class TestHttpPortAllocatorSession;
class Thread;
}
namespace cricket {
class HttpPortAllocator;
class Port;
class PortAllocatorSession;
struct PortConfiguration;
class RelayPort;
class StunPort;
// Contains details about a discovered firewall that are of interest
// when debugging call failures.
struct FirewallInfo {
std::string brand;
std::string model;
// TODO: List of current port mappings.
};
// Contains details about a specific connect attempt.
struct ConnectInfo {
ConnectInfo()
: rtt(-1), error(0) {}
// Time when the connection was initiated. Needed for calculating
// the round trip time.
uint32 start_time_ms;
// Round trip time in milliseconds or -1 for failed connection.
int32 rtt;
// Error code representing low level errors like socket errors.
int error;
};
// Identifier for a network interface and proxy address pair.
struct NicId {
NicId(const rtc::IPAddress& ip,
const rtc::SocketAddress& proxy_address)
: ip(ip),
proxy_address(proxy_address) {
}
rtc::IPAddress ip;
rtc::SocketAddress proxy_address;
};
// Comparator implementation identifying unique network interface and
// proxy address pairs.
class NicIdComparator {
public:
int compare(const NicId &first, const NicId &second) const {
if (first.ip == second.ip) {
// Compare proxy address.
if (first.proxy_address == second.proxy_address) {
return 0;
} else {
return first.proxy_address < second.proxy_address? -1 : 1;
}
}
return first.ip < second.ip ? -1 : 1;
}
bool operator()(const NicId &first, const NicId &second) const {
return (compare(first, second) < 0);
}
};
// Contains information of a network interface and proxy address pair.
struct NicInfo {
NicInfo() {}
rtc::IPAddress ip;
rtc::ProxyInfo proxy_info;
rtc::SocketAddress external_address;
ServerAddresses stun_server_addresses;
rtc::SocketAddress media_server_address;
ConnectInfo stun;
ConnectInfo http;
ConnectInfo https;
ConnectInfo udp;
ConnectInfo tcp;
ConnectInfo ssltcp;
FirewallInfo firewall;
};
// Holds the result of the connectivity check.
class NicMap : public std::map<NicId, NicInfo, NicIdComparator> {
};
class TestHttpPortAllocatorSession : public HttpPortAllocatorSession {
public:
TestHttpPortAllocatorSession(
HttpPortAllocator* allocator,
const std::string& content_name,
int component,
const std::string& ice_ufrag,
const std::string& ice_pwd,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay_token,
const std::string& user_agent)
: HttpPortAllocatorSession(
allocator, content_name, component, ice_ufrag, ice_pwd, stun_hosts,
relay_hosts, relay_token, user_agent) {
}
void set_proxy(const rtc::ProxyInfo& proxy) {
proxy_ = proxy;
}
void ConfigReady(PortConfiguration* config);
void OnRequestDone(rtc::SignalThread* data);
sigslot::signal4<const std::string&, const std::string&,
const PortConfiguration*,
const rtc::ProxyInfo&> SignalConfigReady;
sigslot::signal1<rtc::AsyncHttpRequest*> SignalRequestDone;
private:
rtc::ProxyInfo proxy_;
};
// Runs a request/response check on all network interface and proxy
// address combinations. The check is considered done either when all
// checks has been successful or when the check times out.
class ConnectivityChecker
: public rtc::MessageHandler, public sigslot::has_slots<> {
public:
ConnectivityChecker(rtc::Thread* worker,
const std::string& jid,
const std::string& session_id,
const std::string& user_agent,
const std::string& relay_token,
const std::string& connection);
virtual ~ConnectivityChecker();
// Virtual for gMock.
virtual bool Initialize();
virtual void Start();
// MessageHandler implementation.
virtual void OnMessage(rtc::Message *msg);
// Instruct checker to stop and wait until that's done.
// Virtual for gMock.
virtual void Stop() {
worker_->Stop();
}
const NicMap& GetResults() const {
return nics_;
}
void set_timeout_ms(uint32 timeout) {
timeout_ms_ = timeout;
}
void set_stun_address(const rtc::SocketAddress& stun_address) {
stun_address_ = stun_address;
}
const std::string& connection() const {
return connection_;
}
const std::string& jid() const {
return jid_;
}
const std::string& session_id() const {
return session_id_;
}
// Context: Main Thread. Signalled when the connectivity check is complete.
sigslot::signal1<ConnectivityChecker*> SignalCheckDone;
protected:
// Can be overridden for test.
virtual rtc::NetworkManager* CreateNetworkManager() {
return new rtc::BasicNetworkManager();
}
virtual rtc::BasicPacketSocketFactory* CreateSocketFactory(
rtc::Thread* thread) {
return new rtc::BasicPacketSocketFactory(thread);
}
virtual HttpPortAllocator* CreatePortAllocator(
rtc::NetworkManager* network_manager,
const std::string& user_agent,
const std::string& relay_token);
virtual StunPort* CreateStunPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network);
virtual RelayPort* CreateRelayPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network);
virtual void InitiateProxyDetection();
virtual void SetProxyInfo(const rtc::ProxyInfo& info);
virtual rtc::ProxyInfo GetProxyInfo() const;
rtc::Thread* worker() {
return worker_;
}
private:
bool AddNic(const rtc::IPAddress& ip,
const rtc::SocketAddress& proxy_address);
void AllocatePorts();
void AllocateRelayPorts();
void CheckNetworks();
void CreateRelayPorts(
const std::string& username, const std::string& password,
const PortConfiguration* config, const rtc::ProxyInfo& proxy_info);
// Must be called by the worker thread.
void CleanUp();
void OnRequestDone(rtc::AsyncHttpRequest* request);
void OnRelayPortComplete(Port* port);
void OnStunPortComplete(Port* port);
void OnRelayPortError(Port* port);
void OnStunPortError(Port* port);
void OnNetworksChanged();
void OnProxyDetect(rtc::SignalThread* thread);
void OnConfigReady(
const std::string& username, const std::string& password,
const PortConfiguration* config, const rtc::ProxyInfo& proxy);
void OnConfigWithProxyReady(const PortConfiguration*);
void RegisterHttpStart(int port);
rtc::Thread* worker_;
std::string jid_;
std::string session_id_;
std::string user_agent_;
std::string relay_token_;
std::string connection_;
rtc::AutoDetectProxy* proxy_detect_;
rtc::scoped_ptr<rtc::NetworkManager> network_manager_;
rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory_;
rtc::scoped_ptr<HttpPortAllocator> port_allocator_;
NicMap nics_;
std::vector<Port*> ports_;
std::vector<PortAllocatorSession*> sessions_;
uint32 timeout_ms_;
rtc::SocketAddress stun_address_;
rtc::Thread* main_;
bool started_;
};
} // namespace cricket
#endif // WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_

View File

@ -1,367 +0,0 @@
/*
* Copyright 2011 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 "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/base/relayport.h"
#include "webrtc/p2p/base/stunport.h"
#include "webrtc/p2p/client/connectivitychecker.h"
#include "webrtc/p2p/client/httpportallocator.h"
#include "webrtc/base/asynchttprequest.h"
#include "webrtc/base/fakenetwork.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/socketaddress.h"
namespace cricket {
static const rtc::SocketAddress kClientAddr1("11.11.11.11", 0);
static const rtc::SocketAddress kClientAddr2("22.22.22.22", 0);
static const rtc::SocketAddress kExternalAddr("33.33.33.33", 3333);
static const rtc::SocketAddress kStunAddr("44.44.44.44", 4444);
static const rtc::SocketAddress kRelayAddr("55.55.55.55", 5555);
static const rtc::SocketAddress kProxyAddr("66.66.66.66", 6666);
static const rtc::ProxyType kProxyType = rtc::PROXY_HTTPS;
static const char kRelayHost[] = "relay.google.com";
static const char kRelayToken[] =
"CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6";
static const char kBrowserAgent[] = "browser_test";
static const char kJid[] = "a.b@c";
static const char kUserName[] = "testuser";
static const char kPassword[] = "testpassword";
static const char kMagicCookie[] = "testcookie";
static const char kRelayUdpPort[] = "4444";
static const char kRelayTcpPort[] = "5555";
static const char kRelaySsltcpPort[] = "6666";
static const char kSessionId[] = "testsession";
static const char kConnection[] = "testconnection";
static const int kMinPort = 1000;
static const int kMaxPort = 2000;
// Fake implementation to mock away real network usage.
class FakeRelayPort : public RelayPort {
public:
FakeRelayPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network, const rtc::IPAddress& ip,
int min_port, int max_port,
const std::string& username, const std::string& password)
: RelayPort(thread, factory, network, ip, min_port, max_port,
username, password) {
}
// Just signal that we are done.
virtual void PrepareAddress() {
SignalPortComplete(this);
}
};
// Fake implementation to mock away real network usage.
class FakeStunPort : public StunPort {
public:
FakeStunPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
const rtc::IPAddress& ip,
int min_port, int max_port,
const std::string& username, const std::string& password,
const ServerAddresses& server_addr)
: StunPort(thread, factory, network, ip, min_port, max_port,
username, password, server_addr, std::string()) {
}
// Just set external address and signal that we are done.
virtual void PrepareAddress() {
AddAddress(kExternalAddr, kExternalAddr, rtc::SocketAddress(), "udp", "",
"", STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, true);
SignalPortComplete(this);
}
};
// Fake implementation to mock away real network usage by responding
// to http requests immediately.
class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession {
public:
FakeHttpPortAllocatorSession(
HttpPortAllocator* allocator,
const std::string& content_name,
int component,
const std::string& ice_ufrag, const std::string& ice_pwd,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay_token,
const std::string& agent)
: TestHttpPortAllocatorSession(allocator,
content_name,
component,
ice_ufrag,
ice_pwd,
stun_hosts,
relay_hosts,
relay_token,
agent) {
}
virtual void SendSessionRequest(const std::string& host, int port) {
FakeReceiveSessionResponse(host, port);
}
// Pass results to the real implementation.
void FakeReceiveSessionResponse(const std::string& host, int port) {
rtc::AsyncHttpRequest* response = CreateAsyncHttpResponse(port);
TestHttpPortAllocatorSession::OnRequestDone(response);
response->Destroy(true);
}
private:
// Helper method for creating a response to a relay session request.
rtc::AsyncHttpRequest* CreateAsyncHttpResponse(int port) {
rtc::AsyncHttpRequest* request =
new rtc::AsyncHttpRequest(kBrowserAgent);
std::stringstream ss;
ss << "username=" << kUserName << std::endl
<< "password=" << kPassword << std::endl
<< "magic_cookie=" << kMagicCookie << std::endl
<< "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl
<< "relay.udp_port=" << kRelayUdpPort << std::endl
<< "relay.tcp_port=" << kRelayTcpPort << std::endl
<< "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl;
request->response().document.reset(
new rtc::MemoryStream(ss.str().c_str()));
request->response().set_success();
request->set_port(port);
request->set_secure(port == rtc::HTTP_SECURE_PORT);
return request;
}
};
// Fake implementation for creating fake http sessions.
class FakeHttpPortAllocator : public HttpPortAllocator {
public:
FakeHttpPortAllocator(rtc::NetworkManager* network_manager,
const std::string& user_agent)
: HttpPortAllocator(network_manager, user_agent) {
}
virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name, int component,
const std::string& ice_ufrag, const std::string& ice_pwd) {
std::vector<rtc::SocketAddress> stun_hosts;
stun_hosts.push_back(kStunAddr);
std::vector<std::string> relay_hosts;
relay_hosts.push_back(kRelayHost);
return new FakeHttpPortAllocatorSession(this,
content_name,
component,
ice_ufrag,
ice_pwd,
stun_hosts,
relay_hosts,
kRelayToken,
kBrowserAgent);
}
};
class ConnectivityCheckerForTest : public ConnectivityChecker {
public:
ConnectivityCheckerForTest(rtc::Thread* worker,
const std::string& jid,
const std::string& session_id,
const std::string& user_agent,
const std::string& relay_token,
const std::string& connection)
: ConnectivityChecker(worker,
jid,
session_id,
user_agent,
relay_token,
connection),
proxy_initiated_(false) {
}
rtc::FakeNetworkManager* network_manager() const {
return network_manager_;
}
FakeHttpPortAllocator* port_allocator() const {
return fake_port_allocator_;
}
protected:
// Overridden methods for faking a real network.
virtual rtc::NetworkManager* CreateNetworkManager() {
network_manager_ = new rtc::FakeNetworkManager();
return network_manager_;
}
virtual rtc::BasicPacketSocketFactory* CreateSocketFactory(
rtc::Thread* thread) {
// Create socket factory, for simplicity, let it run on the current thread.
socket_factory_ =
new rtc::BasicPacketSocketFactory(rtc::Thread::Current());
return socket_factory_;
}
virtual HttpPortAllocator* CreatePortAllocator(
rtc::NetworkManager* network_manager,
const std::string& user_agent,
const std::string& relay_token) {
fake_port_allocator_ =
new FakeHttpPortAllocator(network_manager, user_agent);
return fake_port_allocator_;
}
virtual StunPort* CreateStunPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network) {
return new FakeStunPort(worker(),
socket_factory_,
network,
network->GetBestIP(),
kMinPort,
kMaxPort,
username,
password,
config->stun_servers);
}
virtual RelayPort* CreateRelayPort(
const std::string& username, const std::string& password,
const PortConfiguration* config, rtc::Network* network) {
return new FakeRelayPort(worker(),
socket_factory_,
network,
network->GetBestIP(),
kMinPort,
kMaxPort,
username,
password);
}
virtual void InitiateProxyDetection() {
if (!proxy_initiated_) {
proxy_initiated_ = true;
proxy_info_.address = kProxyAddr;
proxy_info_.type = kProxyType;
SetProxyInfo(proxy_info_);
}
}
virtual rtc::ProxyInfo GetProxyInfo() const {
return proxy_info_;
}
private:
rtc::BasicPacketSocketFactory* socket_factory_;
FakeHttpPortAllocator* fake_port_allocator_;
rtc::FakeNetworkManager* network_manager_;
rtc::ProxyInfo proxy_info_;
bool proxy_initiated_;
};
class ConnectivityCheckerTest : public testing::Test {
protected:
void VerifyNic(const NicInfo& info,
const rtc::SocketAddress& local_address) {
// Verify that the external address has been set.
EXPECT_EQ(kExternalAddr, info.external_address);
// Verify that the stun server address has been set.
EXPECT_EQ(1U, info.stun_server_addresses.size());
EXPECT_EQ(kStunAddr, *(info.stun_server_addresses.begin()));
// Verify that the media server address has been set. Don't care
// about port since it is different for different protocols.
EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr());
// Verify that local ip matches.
EXPECT_EQ(local_address.ipaddr(), info.ip);
// Verify that we have received responses for our
// pings. Unsuccessful ping has rtt value -1, successful >= 0.
EXPECT_GE(info.stun.rtt, 0);
EXPECT_GE(info.udp.rtt, 0);
EXPECT_GE(info.tcp.rtt, 0);
EXPECT_GE(info.ssltcp.rtt, 0);
// If proxy has been set, verify address and type.
if (!info.proxy_info.address.IsNil()) {
EXPECT_EQ(kProxyAddr, info.proxy_info.address);
EXPECT_EQ(kProxyType, info.proxy_info.type);
}
}
};
// Tests a configuration with two network interfaces. Verifies that 4
// combinations of ip/proxy are created and that all protocols are
// tested on each combination.
TEST_F(ConnectivityCheckerTest, TestStart) {
ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(),
kJid,
kSessionId,
kBrowserAgent,
kRelayToken,
kConnection);
connectivity_checker.Initialize();
connectivity_checker.set_stun_address(kStunAddr);
connectivity_checker.network_manager()->AddInterface(kClientAddr1);
connectivity_checker.network_manager()->AddInterface(kClientAddr2);
connectivity_checker.Start();
rtc::Thread::Current()->ProcessMessages(1000);
NicMap nics = connectivity_checker.GetResults();
// There should be 4 nics in our map. 2 for each interface added,
// one with proxy set and one without.
EXPECT_EQ(4U, nics.size());
// First verify interfaces without proxy.
rtc::SocketAddress nilAddress;
// First lookup the address of the first nic combined with no proxy.
NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress));
ASSERT(i != nics.end());
NicInfo info = i->second;
VerifyNic(info, kClientAddr1);
// Then make sure the second device has been tested without proxy.
i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress));
ASSERT(i != nics.end());
info = i->second;
VerifyNic(info, kClientAddr2);
// Now verify both interfaces with proxy.
i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr));
ASSERT(i != nics.end());
info = i->second;
VerifyNic(info, kClientAddr1);
i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr));
ASSERT(i != nics.end());
info = i->second;
VerifyNic(info, kClientAddr2);
};
// Tests that nothing bad happens if thera are no network interfaces
// available to check.
TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) {
ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(),
kJid,
kSessionId,
kBrowserAgent,
kRelayToken,
kConnection);
connectivity_checker.Initialize();
connectivity_checker.Start();
rtc::Thread::Current()->ProcessMessages(1000);
NicMap nics = connectivity_checker.GetResults();
// Verify that no nics where checked.
EXPECT_EQ(0U, nics.size());
}
} // namespace cricket

View File

@ -13,10 +13,10 @@
#include <algorithm>
#include <map>
#include "webrtc/base/asynchttprequest.h"
#include "webrtc/base/basicdefs.h"
#include "webrtc/base/common.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/httpcommon.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/nethelpers.h"
#include "webrtc/base/signalthread.h"
@ -144,7 +144,7 @@ void HttpPortAllocatorSessionBase::TryCreateRelaySession() {
return;
}
if (attempts_ == HttpPortAllocator::kNumRetries) {
if (attempts_ == HttpPortAllocatorBase::kNumRetries) {
LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; "
<< "giving up on relay.";
return;
@ -167,7 +167,7 @@ void HttpPortAllocatorSessionBase::TryCreateRelaySession() {
}
std::string HttpPortAllocatorSessionBase::GetSessionRequestUrl() {
std::string url = std::string(HttpPortAllocator::kCreateSessionURL);
std::string url = std::string(HttpPortAllocatorBase::kCreateSessionURL);
ASSERT(!username().empty());
ASSERT(!password().empty());
url = url + "?username=" + rtc::s_url_encode(username()) +
@ -220,105 +220,4 @@ void HttpPortAllocatorSessionBase::ReceiveSessionResponse(
ConfigReady(config);
}
// HttpPortAllocator
HttpPortAllocator::HttpPortAllocator(
rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
const std::string &user_agent)
: HttpPortAllocatorBase(network_manager, socket_factory, user_agent) {
}
HttpPortAllocator::HttpPortAllocator(
rtc::NetworkManager* network_manager,
const std::string &user_agent)
: HttpPortAllocatorBase(network_manager, user_agent) {
}
HttpPortAllocator::~HttpPortAllocator() {}
PortAllocatorSession* HttpPortAllocator::CreateSessionInternal(
const std::string& content_name,
int component,
const std::string& ice_ufrag, const std::string& ice_pwd) {
return new HttpPortAllocatorSession(this, content_name, component,
ice_ufrag, ice_pwd, stun_hosts(),
relay_hosts(), relay_token(),
user_agent());
}
// HttpPortAllocatorSession
HttpPortAllocatorSession::HttpPortAllocatorSession(
HttpPortAllocator* allocator,
const std::string& content_name,
int component,
const std::string& ice_ufrag,
const std::string& ice_pwd,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay,
const std::string& agent)
: HttpPortAllocatorSessionBase(allocator, content_name, component,
ice_ufrag, ice_pwd, stun_hosts,
relay_hosts, relay, agent) {
}
HttpPortAllocatorSession::~HttpPortAllocatorSession() {
for (std::list<rtc::AsyncHttpRequest*>::iterator it = requests_.begin();
it != requests_.end(); ++it) {
(*it)->Destroy(true);
}
}
void HttpPortAllocatorSession::SendSessionRequest(const std::string& host,
int port) {
// Initiate an HTTP request to create a session through the chosen host.
rtc::AsyncHttpRequest* request =
new rtc::AsyncHttpRequest(user_agent());
request->SignalWorkDone.connect(this,
&HttpPortAllocatorSession::OnRequestDone);
request->set_secure(port == rtc::HTTP_SECURE_PORT);
request->set_proxy(allocator()->proxy());
request->response().document.reset(new rtc::MemoryStream);
request->request().verb = rtc::HV_GET;
request->request().path = GetSessionRequestUrl();
request->request().addHeader("X-Talk-Google-Relay-Auth", relay_token(), true);
request->request().addHeader("X-Stream-Type", "video_rtp", true);
request->set_host(host);
request->set_port(port);
request->Start();
request->Release();
requests_.push_back(request);
}
void HttpPortAllocatorSession::OnRequestDone(rtc::SignalThread* data) {
rtc::AsyncHttpRequest* request =
static_cast<rtc::AsyncHttpRequest*>(data);
// Remove the request from the list of active requests.
std::list<rtc::AsyncHttpRequest*>::iterator it =
std::find(requests_.begin(), requests_.end(), request);
if (it != requests_.end()) {
requests_.erase(it);
}
if (request->response().scode != 200) {
LOG(LS_WARNING) << "HTTPPortAllocator: request "
<< " received error " << request->response().scode;
TryCreateRelaySession();
return;
}
LOG(LS_INFO) << "HTTPPortAllocator: request succeeded";
rtc::MemoryStream* stream =
static_cast<rtc::MemoryStream*>(request->response().document.get());
stream->Rewind();
size_t length;
stream->GetSize(&length);
std::string resp = std::string(stream->GetBuffer(), length);
ReceiveSessionResponse(resp);
}
} // namespace cricket

View File

@ -26,6 +26,12 @@ class SignalThread;
namespace cricket {
// TODO(pthatcher): Remove this. It's only used by chromoting, so we
// should just move this code there. It's used in these places in
// chromium:
// src/remoting/protocol/chromium_port_allocator.cc
// src/remoting/client/plugin/pepper_port_allocator.cc
// src/remoting/protocol/libjingle_transport_factory.cc
class HttpPortAllocatorBase : public BasicPortAllocator {
public:
// The number of HTTP requests we should attempt before giving up.
@ -130,44 +136,6 @@ class HttpPortAllocatorSessionBase : public BasicPortAllocatorSession {
int attempts_;
};
class HttpPortAllocator : public HttpPortAllocatorBase {
public:
HttpPortAllocator(rtc::NetworkManager* network_manager,
const std::string& user_agent);
HttpPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
const std::string& user_agent);
virtual ~HttpPortAllocator();
virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name,
int component,
const std::string& ice_ufrag, const std::string& ice_pwd);
};
class HttpPortAllocatorSession : public HttpPortAllocatorSessionBase {
public:
HttpPortAllocatorSession(
HttpPortAllocator* allocator,
const std::string& content_name,
int component,
const std::string& ice_ufrag,
const std::string& ice_pwd,
const std::vector<rtc::SocketAddress>& stun_hosts,
const std::vector<std::string>& relay_hosts,
const std::string& relay,
const std::string& agent);
virtual ~HttpPortAllocatorSession();
virtual void SendSessionRequest(const std::string& host, int port);
protected:
// Protected for diagnostics.
virtual void OnRequestDone(rtc::SignalThread* request);
private:
std::list<rtc::AsyncHttpRequest*> requests_;
};
} // namespace cricket
#endif // WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_

View File

@ -1218,109 +1218,3 @@ TEST_F(PortAllocatorTest, TestEnableIPv6Addresses) {
kClientAddr);
EXPECT_EQ(4U, candidates_.size());
}
// Test that the httpportallocator correctly maintains its lists of stun and
// relay servers, by never allowing an empty list.
TEST(HttpPortAllocatorTest, TestHttpPortAllocatorHostLists) {
rtc::FakeNetworkManager network_manager;
cricket::HttpPortAllocator alloc(&network_manager, "unit test agent");
EXPECT_EQ(1U, alloc.relay_hosts().size());
EXPECT_EQ(1U, alloc.stun_hosts().size());
std::vector<std::string> relay_servers;
std::vector<rtc::SocketAddress> stun_servers;
alloc.SetRelayHosts(relay_servers);
alloc.SetStunHosts(stun_servers);
EXPECT_EQ(1U, alloc.relay_hosts().size());
EXPECT_EQ(1U, alloc.stun_hosts().size());
relay_servers.push_back("1.unittest.corp.google.com");
relay_servers.push_back("2.unittest.corp.google.com");
stun_servers.push_back(
rtc::SocketAddress("1.unittest.corp.google.com", 0));
stun_servers.push_back(
rtc::SocketAddress("2.unittest.corp.google.com", 0));
alloc.SetRelayHosts(relay_servers);
alloc.SetStunHosts(stun_servers);
EXPECT_EQ(2U, alloc.relay_hosts().size());
EXPECT_EQ(2U, alloc.stun_hosts().size());
}
// Test that the HttpPortAllocator uses correct URL to create sessions.
TEST(HttpPortAllocatorTest, TestSessionRequestUrl) {
rtc::FakeNetworkManager network_manager;
cricket::HttpPortAllocator alloc(&network_manager, "unit test agent");
rtc::scoped_ptr<cricket::HttpPortAllocatorSessionBase> session(
static_cast<cricket::HttpPortAllocatorSession*>(
alloc.CreateSessionInternal(
"test content", 0, kIceUfrag0, kIcePwd0)));
std::string url = session->GetSessionRequestUrl();
LOG(LS_INFO) << "url: " << url;
std::vector<std::string> parts;
rtc::split(url, '?', &parts);
ASSERT_EQ(2U, parts.size());
std::vector<std::string> args_parts;
rtc::split(parts[1], '&', &args_parts);
std::map<std::string, std::string> args;
for (std::vector<std::string>::iterator it = args_parts.begin();
it != args_parts.end(); ++it) {
std::vector<std::string> parts;
rtc::split(*it, '=', &parts);
ASSERT_EQ(2U, parts.size());
args[rtc::s_url_decode(parts[0])] = rtc::s_url_decode(parts[1]);
}
EXPECT_EQ(kIceUfrag0, args["username"]);
EXPECT_EQ(kIcePwd0, args["password"]);
}
// Tests that destroying ports with non-shared sockets does not crash.
// b/19074679.
TEST_F(PortAllocatorTest, TestDestroyPortsNonSharedSockets) {
AddInterface(kClientAddr);
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
EXPECT_EQ(4U, ports_.size());
auto it = ports_.begin();
for (; it != ports_.end(); ++it) {
(reinterpret_cast<cricket::Port*>(*it))->Destroy();
}
}
class AllocationSequenceForTest : public cricket::AllocationSequence {
public:
AllocationSequenceForTest(cricket::BasicPortAllocatorSession* session,
rtc::Network* network,
cricket::PortConfiguration* config,
uint32 flags)
: cricket::AllocationSequence(session, network, config, flags) {}
using cricket::AllocationSequence::CreateTurnPort;
};
TEST_F(PortAllocatorTest, TestCreateTurnPortWithNullSocket) {
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
cricket::ServerAddresses stun_servers;
stun_servers.insert(kStunAddr);
cricket::PortConfiguration config(stun_servers, kIceUfrag0, kIcePwd0);
rtc::Network network1("test_eth0", "Test Network Adapter 1",
rtc::IPAddress(0x12345600U), 24);
uint32 flag = cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
AllocationSequenceForTest alloc_sequence(
static_cast<cricket::BasicPortAllocatorSession*>(session_.get()),
&network1, &config, flag);
// This simply tests it will not crash if udp_socket_ in the
// AllocationSequence is null, which is chosen in the constructor.
cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
relay_server.ports.push_back(
cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false));
alloc_sequence.CreateTurnPort(relay_server);
}

View File

@ -78,11 +78,8 @@
'base/turnserver.cc',
'base/turnserver.h',
'base/udpport.h',
'client/autoportallocator.h',
'client/basicportallocator.cc',
'client/basicportallocator.h',
'client/connectivitychecker.cc',
'client/connectivitychecker.h',
'client/httpportallocator.cc',
'client/httpportallocator.h',
'client/socketmonitor.cc',

View File

@ -32,7 +32,6 @@
'base/transport_unittest.cc',
'base/transportdescriptionfactory_unittest.cc',
'base/turnport_unittest.cc',
'client/connectivitychecker_unittest.cc',
'client/fakeportallocator.h',
'client/portallocator_unittest.cc',
'stunprober/stunprober_unittest.cc',