| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/p2p/client/httpportallocator.h" | |
| 12 | |
| 13 #include <algorithm> | |
| 14 #include <map> | |
| 15 | |
| 16 #include "webrtc/base/common.h" | |
| 17 #include "webrtc/base/helpers.h" | |
| 18 #include "webrtc/base/httpcommon.h" | |
| 19 #include "webrtc/base/logging.h" | |
| 20 #include "webrtc/base/nethelpers.h" | |
| 21 #include "webrtc/base/signalthread.h" | |
| 22 #include "webrtc/base/stringencode.h" | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 // Helper routine to remove whitespace from the ends of a string. | |
| 27 void Trim(std::string& str) { | |
| 28 size_t first = str.find_first_not_of(" \t\r\n"); | |
| 29 if (first == std::string::npos) { | |
| 30 str.clear(); | |
| 31 return; | |
| 32 } | |
| 33 | |
| 34 ASSERT(str.find_last_not_of(" \t\r\n") != std::string::npos); | |
| 35 } | |
| 36 | |
| 37 // Parses the lines in the result of the HTTP request that are of the form | |
| 38 // 'a=b' and returns them in a map. | |
| 39 typedef std::map<std::string, std::string> StringMap; | |
| 40 void ParseMap(const std::string& string, StringMap& map) { | |
| 41 size_t start_of_line = 0; | |
| 42 size_t end_of_line = 0; | |
| 43 | |
| 44 for (;;) { // for each line | |
| 45 start_of_line = string.find_first_not_of("\r\n", end_of_line); | |
| 46 if (start_of_line == std::string::npos) | |
| 47 break; | |
| 48 | |
| 49 end_of_line = string.find_first_of("\r\n", start_of_line); | |
| 50 if (end_of_line == std::string::npos) { | |
| 51 end_of_line = string.length(); | |
| 52 } | |
| 53 | |
| 54 size_t equals = string.find('=', start_of_line); | |
| 55 if ((equals >= end_of_line) || (equals == std::string::npos)) | |
| 56 continue; | |
| 57 | |
| 58 std::string key(string, start_of_line, equals - start_of_line); | |
| 59 std::string value(string, equals + 1, end_of_line - equals - 1); | |
| 60 | |
| 61 Trim(key); | |
| 62 Trim(value); | |
| 63 | |
| 64 if ((key.size() > 0) && (value.size() > 0)) | |
| 65 map[key] = value; | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 namespace cricket { | |
| 72 | |
| 73 // HttpPortAllocatorBase | |
| 74 | |
| 75 const int HttpPortAllocatorBase::kNumRetries = 5; | |
| 76 | |
| 77 const char HttpPortAllocatorBase::kCreateSessionURL[] = "/create_session"; | |
| 78 | |
| 79 HttpPortAllocatorBase::HttpPortAllocatorBase( | |
| 80 rtc::NetworkManager* network_manager, | |
| 81 rtc::PacketSocketFactory* socket_factory, | |
| 82 const std::string &user_agent) | |
| 83 : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) { | |
| 84 relay_hosts_.push_back("relay.google.com"); | |
| 85 stun_hosts_.push_back( | |
| 86 rtc::SocketAddress("stun.l.google.com", 19302)); | |
| 87 } | |
| 88 | |
| 89 HttpPortAllocatorBase::HttpPortAllocatorBase( | |
| 90 rtc::NetworkManager* network_manager, | |
| 91 const std::string &user_agent) | |
| 92 : BasicPortAllocator(network_manager), agent_(user_agent) { | |
| 93 relay_hosts_.push_back("relay.google.com"); | |
| 94 stun_hosts_.push_back( | |
| 95 rtc::SocketAddress("stun.l.google.com", 19302)); | |
| 96 } | |
| 97 | |
| 98 HttpPortAllocatorBase::~HttpPortAllocatorBase() { | |
| 99 } | |
| 100 | |
| 101 // HttpPortAllocatorSessionBase | |
| 102 | |
| 103 HttpPortAllocatorSessionBase::HttpPortAllocatorSessionBase( | |
| 104 HttpPortAllocatorBase* allocator, | |
| 105 const std::string& content_name, | |
| 106 int component, | |
| 107 const std::string& ice_ufrag, | |
| 108 const std::string& ice_pwd, | |
| 109 const std::vector<rtc::SocketAddress>& stun_hosts, | |
| 110 const std::vector<std::string>& relay_hosts, | |
| 111 const std::string& relay_token, | |
| 112 const std::string& user_agent) | |
| 113 : BasicPortAllocatorSession(allocator, content_name, component, | |
| 114 ice_ufrag, ice_pwd), | |
| 115 relay_hosts_(relay_hosts), stun_hosts_(stun_hosts), | |
| 116 relay_token_(relay_token), agent_(user_agent), attempts_(0) { | |
| 117 } | |
| 118 | |
| 119 HttpPortAllocatorSessionBase::~HttpPortAllocatorSessionBase() {} | |
| 120 | |
| 121 void HttpPortAllocatorSessionBase::GetPortConfigurations() { | |
| 122 // Creating relay sessions can take time and is done asynchronously. | |
| 123 // Creating stun sessions could also take time and could be done aysnc also, | |
| 124 // but for now is done here and added to the initial config. Note any later | |
| 125 // configs will have unresolved stun ips and will be discarded by the | |
| 126 // AllocationSequence. | |
| 127 ServerAddresses hosts; | |
| 128 for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin(); | |
| 129 it != stun_hosts_.end(); ++it) { | |
| 130 hosts.insert(*it); | |
| 131 } | |
| 132 | |
| 133 PortConfiguration* config = new PortConfiguration(hosts, | |
| 134 username(), | |
| 135 password()); | |
| 136 ConfigReady(config); | |
| 137 TryCreateRelaySession(); | |
| 138 } | |
| 139 | |
| 140 void HttpPortAllocatorSessionBase::TryCreateRelaySession() { | |
| 141 if (allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) { | |
| 142 LOG(LS_VERBOSE) << "HttpPortAllocator: Relay ports disabled, skipping."; | |
| 143 return; | |
| 144 } | |
| 145 | |
| 146 if (attempts_ == HttpPortAllocatorBase::kNumRetries) { | |
| 147 LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; " | |
| 148 << "giving up on relay."; | |
| 149 return; | |
| 150 } | |
| 151 | |
| 152 if (relay_hosts_.size() == 0) { | |
| 153 LOG(LS_ERROR) << "HttpPortAllocator: no relay hosts configured."; | |
| 154 return; | |
| 155 } | |
| 156 | |
| 157 // Choose the next host to try. | |
| 158 std::string host = relay_hosts_[attempts_ % relay_hosts_.size()]; | |
| 159 attempts_++; | |
| 160 LOG(LS_INFO) << "HTTPPortAllocator: sending to relay host " << host; | |
| 161 if (relay_token_.empty()) { | |
| 162 LOG(LS_WARNING) << "No relay auth token found."; | |
| 163 } | |
| 164 | |
| 165 SendSessionRequest(host, rtc::HTTP_SECURE_PORT); | |
| 166 } | |
| 167 | |
| 168 std::string HttpPortAllocatorSessionBase::GetSessionRequestUrl() { | |
| 169 std::string url = std::string(HttpPortAllocatorBase::kCreateSessionURL); | |
| 170 ASSERT(!username().empty()); | |
| 171 ASSERT(!password().empty()); | |
| 172 url = url + "?username=" + rtc::s_url_encode(username()) + | |
| 173 "&password=" + rtc::s_url_encode(password()); | |
| 174 return url; | |
| 175 } | |
| 176 | |
| 177 void HttpPortAllocatorSessionBase::ReceiveSessionResponse( | |
| 178 const std::string& response) { | |
| 179 | |
| 180 StringMap map; | |
| 181 ParseMap(response, map); | |
| 182 | |
| 183 if (!username().empty() && map["username"] != username()) { | |
| 184 LOG(LS_WARNING) << "Received unexpected username value from relay server."; | |
| 185 } | |
| 186 if (!password().empty() && map["password"] != password()) { | |
| 187 LOG(LS_WARNING) << "Received unexpected password value from relay server."; | |
| 188 } | |
| 189 | |
| 190 std::string relay_ip = map["relay.ip"]; | |
| 191 std::string relay_udp_port = map["relay.udp_port"]; | |
| 192 std::string relay_tcp_port = map["relay.tcp_port"]; | |
| 193 std::string relay_ssltcp_port = map["relay.ssltcp_port"]; | |
| 194 | |
| 195 ServerAddresses hosts; | |
| 196 for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin(); | |
| 197 it != stun_hosts_.end(); ++it) { | |
| 198 hosts.insert(*it); | |
| 199 } | |
| 200 | |
| 201 PortConfiguration* config = new PortConfiguration(hosts, | |
| 202 map["username"], | |
| 203 map["password"]); | |
| 204 | |
| 205 RelayServerConfig relay_config(RELAY_GTURN); | |
| 206 if (!relay_udp_port.empty()) { | |
| 207 rtc::SocketAddress address(relay_ip, atoi(relay_udp_port.c_str())); | |
| 208 relay_config.ports.push_back(ProtocolAddress(address, PROTO_UDP)); | |
| 209 } | |
| 210 if (!relay_tcp_port.empty()) { | |
| 211 rtc::SocketAddress address(relay_ip, atoi(relay_tcp_port.c_str())); | |
| 212 relay_config.ports.push_back(ProtocolAddress(address, PROTO_TCP)); | |
| 213 } | |
| 214 if (!relay_ssltcp_port.empty()) { | |
| 215 rtc::SocketAddress address(relay_ip, atoi(relay_ssltcp_port.c_str())); | |
| 216 relay_config.ports.push_back(ProtocolAddress(address, PROTO_SSLTCP)); | |
| 217 } | |
| 218 config->AddRelay(relay_config); | |
| 219 ConfigReady(config); | |
| 220 } | |
| 221 | |
| 222 } // namespace cricket | |
| OLD | NEW |