aboutsummaryrefslogtreecommitdiff
path: root/webrtc/p2p/client/httpportallocator.cc
diff options
context:
space:
mode:
authorhenrike@webrtc.org <henrike@webrtc.org>2014-10-28 22:20:11 +0000
committerhenrike@webrtc.org <henrike@webrtc.org>2014-10-28 22:20:11 +0000
commit269fb4bc90b79bebbb8311da0110ccd6803fd0a8 (patch)
tree10a2757e3f36579d9ee4209c904532f53552404a /webrtc/p2p/client/httpportallocator.cc
parent8b1b23f8f82c3ae2bc4e4d0ce93c81ebe15789c9 (diff)
downloadwebrtc-269fb4bc90b79bebbb8311da0110ccd6803fd0a8.tar.gz
move xmpp and p2p to webrtc
Create a copy of talk/xmpp and talk/p2p under webrtc/libjingle/xmpp and webrtc/p2p. Also makes libjingle use those version instead of the one in the talk folder. BUG=3379 Review URL: https://webrtc-codereview.appspot.com/26999004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7549 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'webrtc/p2p/client/httpportallocator.cc')
-rw-r--r--webrtc/p2p/client/httpportallocator.cc326
1 files changed, 326 insertions, 0 deletions
diff --git a/webrtc/p2p/client/httpportallocator.cc b/webrtc/p2p/client/httpportallocator.cc
new file mode 100644
index 0000000000..c072da27e1
--- /dev/null
+++ b/webrtc/p2p/client/httpportallocator.cc
@@ -0,0 +1,326 @@
+/*
+ * 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/p2p/client/httpportallocator.h"
+
+#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/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/signalthread.h"
+#include "webrtc/base/stringencode.h"
+
+namespace {
+
+// Helper routine to remove whitespace from the ends of a string.
+void Trim(std::string& str) {
+ size_t first = str.find_first_not_of(" \t\r\n");
+ if (first == std::string::npos) {
+ str.clear();
+ return;
+ }
+
+ ASSERT(str.find_last_not_of(" \t\r\n") != std::string::npos);
+}
+
+// Parses the lines in the result of the HTTP request that are of the form
+// 'a=b' and returns them in a map.
+typedef std::map<std::string, std::string> StringMap;
+void ParseMap(const std::string& string, StringMap& map) {
+ size_t start_of_line = 0;
+ size_t end_of_line = 0;
+
+ for (;;) { // for each line
+ start_of_line = string.find_first_not_of("\r\n", end_of_line);
+ if (start_of_line == std::string::npos)
+ break;
+
+ end_of_line = string.find_first_of("\r\n", start_of_line);
+ if (end_of_line == std::string::npos) {
+ end_of_line = string.length();
+ }
+
+ size_t equals = string.find('=', start_of_line);
+ if ((equals >= end_of_line) || (equals == std::string::npos))
+ continue;
+
+ std::string key(string, start_of_line, equals - start_of_line);
+ std::string value(string, equals + 1, end_of_line - equals - 1);
+
+ Trim(key);
+ Trim(value);
+
+ if ((key.size() > 0) && (value.size() > 0))
+ map[key] = value;
+ }
+}
+
+} // namespace
+
+namespace cricket {
+
+// HttpPortAllocatorBase
+
+const int HttpPortAllocatorBase::kNumRetries = 5;
+
+const char HttpPortAllocatorBase::kCreateSessionURL[] = "/create_session";
+
+HttpPortAllocatorBase::HttpPortAllocatorBase(
+ rtc::NetworkManager* network_manager,
+ rtc::PacketSocketFactory* socket_factory,
+ const std::string &user_agent)
+ : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) {
+ relay_hosts_.push_back("relay.google.com");
+ stun_hosts_.push_back(
+ rtc::SocketAddress("stun.l.google.com", 19302));
+}
+
+HttpPortAllocatorBase::HttpPortAllocatorBase(
+ rtc::NetworkManager* network_manager,
+ const std::string &user_agent)
+ : BasicPortAllocator(network_manager), agent_(user_agent) {
+ relay_hosts_.push_back("relay.google.com");
+ stun_hosts_.push_back(
+ rtc::SocketAddress("stun.l.google.com", 19302));
+}
+
+HttpPortAllocatorBase::~HttpPortAllocatorBase() {
+}
+
+// HttpPortAllocatorSessionBase
+
+HttpPortAllocatorSessionBase::HttpPortAllocatorSessionBase(
+ HttpPortAllocatorBase* 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)
+ : BasicPortAllocatorSession(allocator, content_name, component,
+ ice_ufrag, ice_pwd),
+ relay_hosts_(relay_hosts), stun_hosts_(stun_hosts),
+ relay_token_(relay_token), agent_(user_agent), attempts_(0) {
+}
+
+HttpPortAllocatorSessionBase::~HttpPortAllocatorSessionBase() {}
+
+void HttpPortAllocatorSessionBase::GetPortConfigurations() {
+ // Creating relay sessions can take time and is done asynchronously.
+ // Creating stun sessions could also take time and could be done aysnc also,
+ // but for now is done here and added to the initial config. Note any later
+ // configs will have unresolved stun ips and will be discarded by the
+ // AllocationSequence.
+ ServerAddresses hosts;
+ for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin();
+ it != stun_hosts_.end(); ++it) {
+ hosts.insert(*it);
+ }
+
+ PortConfiguration* config = new PortConfiguration(hosts,
+ username(),
+ password());
+ ConfigReady(config);
+ TryCreateRelaySession();
+}
+
+void HttpPortAllocatorSessionBase::TryCreateRelaySession() {
+ if (allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) {
+ LOG(LS_VERBOSE) << "HttpPortAllocator: Relay ports disabled, skipping.";
+ return;
+ }
+
+ if (attempts_ == HttpPortAllocator::kNumRetries) {
+ LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; "
+ << "giving up on relay.";
+ return;
+ }
+
+ if (relay_hosts_.size() == 0) {
+ LOG(LS_ERROR) << "HttpPortAllocator: no relay hosts configured.";
+ return;
+ }
+
+ // Choose the next host to try.
+ std::string host = relay_hosts_[attempts_ % relay_hosts_.size()];
+ attempts_++;
+ LOG(LS_INFO) << "HTTPPortAllocator: sending to relay host " << host;
+ if (relay_token_.empty()) {
+ LOG(LS_WARNING) << "No relay auth token found.";
+ }
+
+ SendSessionRequest(host, rtc::HTTP_SECURE_PORT);
+}
+
+std::string HttpPortAllocatorSessionBase::GetSessionRequestUrl() {
+ std::string url = std::string(HttpPortAllocator::kCreateSessionURL);
+ if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHARED_UFRAG) {
+ ASSERT(!username().empty());
+ ASSERT(!password().empty());
+ url = url + "?username=" + rtc::s_url_encode(username()) +
+ "&password=" + rtc::s_url_encode(password());
+ }
+ return url;
+}
+
+void HttpPortAllocatorSessionBase::ReceiveSessionResponse(
+ const std::string& response) {
+
+ StringMap map;
+ ParseMap(response, map);
+
+ if (!username().empty() && map["username"] != username()) {
+ LOG(LS_WARNING) << "Received unexpected username value from relay server.";
+ }
+ if (!password().empty() && map["password"] != password()) {
+ LOG(LS_WARNING) << "Received unexpected password value from relay server.";
+ }
+
+ std::string relay_ip = map["relay.ip"];
+ std::string relay_udp_port = map["relay.udp_port"];
+ std::string relay_tcp_port = map["relay.tcp_port"];
+ std::string relay_ssltcp_port = map["relay.ssltcp_port"];
+
+ ServerAddresses hosts;
+ for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin();
+ it != stun_hosts_.end(); ++it) {
+ hosts.insert(*it);
+ }
+
+ PortConfiguration* config = new PortConfiguration(hosts,
+ map["username"],
+ map["password"]);
+
+ RelayServerConfig relay_config(RELAY_GTURN);
+ if (!relay_udp_port.empty()) {
+ rtc::SocketAddress address(relay_ip, atoi(relay_udp_port.c_str()));
+ relay_config.ports.push_back(ProtocolAddress(address, PROTO_UDP));
+ }
+ if (!relay_tcp_port.empty()) {
+ rtc::SocketAddress address(relay_ip, atoi(relay_tcp_port.c_str()));
+ relay_config.ports.push_back(ProtocolAddress(address, PROTO_TCP));
+ }
+ if (!relay_ssltcp_port.empty()) {
+ rtc::SocketAddress address(relay_ip, atoi(relay_ssltcp_port.c_str()));
+ relay_config.ports.push_back(ProtocolAddress(address, PROTO_SSLTCP));
+ }
+ config->AddRelay(relay_config);
+ 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