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:
@ -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",
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
@ -117,8 +117,6 @@
|
||||
'arraysize.h',
|
||||
'asyncfile.cc',
|
||||
'asyncfile.h',
|
||||
'asynchttprequest.cc',
|
||||
'asynchttprequest.h',
|
||||
'asyncinvoker.cc',
|
||||
'asyncinvoker.h',
|
||||
'asyncinvoker-inl.h',
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
'type': 'none',
|
||||
'direct_dependent_settings': {
|
||||
'sources': [
|
||||
'asynchttprequest_unittest.cc',
|
||||
'atomicops_unittest.cc',
|
||||
'autodetectproxy_unittest.cc',
|
||||
'bandwidthsmoother_unittest.cc',
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
Reference in New Issue
Block a user