| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 // | |
| 5 // XmppConnectionGenerator does the following algorithm: | |
| 6 // proxy = ResolveProxyInformation(connection_options) | |
| 7 // for server in server_list | |
| 8 // get dns_addresses for server | |
| 9 // connection_list = (dns_addresses X connection methods X proxy).shuffle() | |
| 10 // for connection in connection_list | |
| 11 // yield connection | |
| 12 | |
| 13 #include "chrome/browser/sync/notifier/communicator/xmpp_connection_generator.h" | |
| 14 | |
| 15 #include <vector> | |
| 16 | |
| 17 #include "base/logging.h" | |
| 18 #include "chrome/browser/sync/notifier/base/async_dns_lookup.h" | |
| 19 #include "chrome/browser/sync/notifier/base/signal_thread_task.h" | |
| 20 #include "chrome/browser/sync/notifier/communicator/connection_options.h" | |
| 21 #include "chrome/browser/sync/notifier/communicator/connection_settings.h" | |
| 22 #include "chrome/browser/sync/notifier/communicator/product_info.h" | |
| 23 #include "talk/base/autodetectproxy.h" | |
| 24 #include "talk/base/httpcommon-inl.h" | |
| 25 #include "talk/base/task.h" | |
| 26 #include "talk/base/thread.h" | |
| 27 #include "talk/xmpp/prexmppauth.h" | |
| 28 #include "talk/xmpp/xmppclientsettings.h" | |
| 29 #include "talk/xmpp/xmppengine.h" | |
| 30 | |
| 31 namespace notifier { | |
| 32 | |
| 33 XmppConnectionGenerator::XmppConnectionGenerator( | |
| 34 talk_base::Task* parent, | |
| 35 const ConnectionOptions* options, | |
| 36 bool proxy_only, | |
| 37 const ServerInformation* server_list, | |
| 38 int server_count) | |
| 39 : settings_list_(new ConnectionSettingsList()), | |
| 40 settings_index_(0), | |
| 41 server_list_(new ServerInformation[server_count]), | |
| 42 server_count_(server_count), | |
| 43 server_index_(-1), | |
| 44 proxy_only_(proxy_only), | |
| 45 successfully_resolved_dns_(false), | |
| 46 first_dns_error_(0), | |
| 47 options_(options), | |
| 48 parent_(parent) { | |
| 49 assert(parent); | |
| 50 assert(options); | |
| 51 assert(server_count_ > 0); | |
| 52 for (int i = 0; i < server_count_; ++i) { | |
| 53 server_list_[i] = server_list[i]; | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 XmppConnectionGenerator::~XmppConnectionGenerator() { | |
| 58 LOG(INFO) << "XmppConnectionGenerator::~XmppConnectionGenerator"; | |
| 59 } | |
| 60 | |
| 61 const talk_base::ProxyInfo& XmppConnectionGenerator::proxy() const { | |
| 62 assert(settings_list_.get()); | |
| 63 if (settings_index_ >= settings_list_->GetCount()) { | |
| 64 return settings_list_->proxy(); | |
| 65 } | |
| 66 | |
| 67 ConnectionSettings* settings = settings_list_->GetSettings(settings_index_); | |
| 68 return settings->proxy(); | |
| 69 } | |
| 70 | |
| 71 // Starts resolving proxy information. | |
| 72 void XmppConnectionGenerator::StartGenerating() { | |
| 73 LOG(INFO) << "XmppConnectionGenerator::StartGenerating"; | |
| 74 | |
| 75 talk_base::AutoDetectProxy* proxy_detect = | |
| 76 new talk_base::AutoDetectProxy(GetUserAgentString()); | |
| 77 | |
| 78 if (options_->autodetect_proxy()) { | |
| 79 // Pretend the xmpp server is https, when detecting whether a proxy is | |
| 80 // required to connect. | |
| 81 talk_base::Url<char> host_url("/", | |
| 82 server_list_[0].server.IPAsString().c_str(), | |
| 83 server_list_[0].server.port()); | |
| 84 host_url.set_secure(true); | |
| 85 proxy_detect->set_server_url(host_url.url()); | |
| 86 } else if (options_->proxy_host().length()) { | |
| 87 talk_base::SocketAddress proxy(options_->proxy_host(), | |
| 88 options_->proxy_port()); | |
| 89 proxy_detect->set_proxy(proxy); | |
| 90 } | |
| 91 proxy_detect->set_auth_info(options_->use_proxy_auth(), | |
| 92 options_->auth_user(), | |
| 93 talk_base::CryptString(options_->auth_pass())); | |
| 94 | |
| 95 SignalThreadTask<talk_base::AutoDetectProxy>* wrapper_task = | |
| 96 new SignalThreadTask<talk_base::AutoDetectProxy>(parent_, &proxy_detect); | |
| 97 wrapper_task->SignalWorkDone.connect( | |
| 98 this, | |
| 99 &XmppConnectionGenerator::OnProxyDetect); | |
| 100 wrapper_task->Start(); | |
| 101 } | |
| 102 | |
| 103 void XmppConnectionGenerator::OnProxyDetect( | |
| 104 talk_base::AutoDetectProxy* proxy_detect) { | |
| 105 LOG(INFO) << "XmppConnectionGenerator::OnProxyDetect"; | |
| 106 | |
| 107 ASSERT(settings_list_.get()); | |
| 108 ASSERT(proxy_detect); | |
| 109 settings_list_->SetProxy(proxy_detect->proxy()); | |
| 110 | |
| 111 // Start iterating through the connections (which are generated on demand). | |
| 112 UseNextConnection(); | |
| 113 } | |
| 114 | |
| 115 void XmppConnectionGenerator::UseNextConnection() { | |
| 116 // Trying to connect. | |
| 117 | |
| 118 // Iterate to the next possible connection. | |
| 119 settings_index_++; | |
| 120 if (settings_index_ < settings_list_->GetCount()) { | |
| 121 // We have more connection settings in the settings_list_ to try, kick off | |
| 122 // the next one. | |
| 123 UseCurrentConnection(); | |
| 124 return; | |
| 125 } | |
| 126 | |
| 127 // Iterate to the next possible server. | |
| 128 server_index_++; | |
| 129 if (server_index_ < server_count_) { | |
| 130 AsyncDNSLookup* dns_lookup = new AsyncDNSLookup( | |
| 131 server_list_[server_index_].server); | |
| 132 SignalThreadTask<AsyncDNSLookup>* wrapper_task = | |
| 133 new SignalThreadTask<AsyncDNSLookup>(parent_, &dns_lookup); | |
| 134 wrapper_task->SignalWorkDone.connect( | |
| 135 this, | |
| 136 &XmppConnectionGenerator::OnServerDNSResolved); | |
| 137 wrapper_task->Start(); | |
| 138 return; | |
| 139 } | |
| 140 | |
| 141 // All out of possibilities. | |
| 142 HandleExhaustedConnections(); | |
| 143 } | |
| 144 | |
| 145 void XmppConnectionGenerator::OnServerDNSResolved( | |
| 146 AsyncDNSLookup* dns_lookup) { | |
| 147 LOG(INFO) << "XmppConnectionGenerator::OnServerDNSResolved"; | |
| 148 | |
| 149 // Print logging info. | |
| 150 LOG(INFO) << " server: " << | |
| 151 server_list_[server_index_].server.ToString() << | |
| 152 " error: " << dns_lookup->error(); | |
| 153 if (first_dns_error_ == 0 && dns_lookup->error() != 0) { | |
| 154 first_dns_error_ = dns_lookup->error(); | |
| 155 } | |
| 156 | |
| 157 if (!successfully_resolved_dns_ && dns_lookup->ip_list().size() > 0) { | |
| 158 successfully_resolved_dns_ = true; | |
| 159 } | |
| 160 | |
| 161 for (int i = 0; i < static_cast<int>(dns_lookup->ip_list().size()); ++i) { | |
| 162 LOG(INFO) | |
| 163 << " ip " << i << " : " | |
| 164 << talk_base::SocketAddress::IPToString(dns_lookup->ip_list()[i]); | |
| 165 } | |
| 166 | |
| 167 // Build the ip list. | |
| 168 assert(settings_list_.get()); | |
| 169 settings_index_ = -1; | |
| 170 settings_list_->ClearPermutations(); | |
| 171 settings_list_->AddPermutations( | |
| 172 server_list_[server_index_].server.IPAsString(), | |
| 173 dns_lookup->ip_list(), | |
| 174 server_list_[server_index_].server.port(), | |
| 175 server_list_[server_index_].special_port_magic, | |
| 176 proxy_only_); | |
| 177 | |
| 178 UseNextConnection(); | |
| 179 } | |
| 180 | |
| 181 static const char* const PROTO_NAMES[cricket::PROTO_LAST + 1] = { | |
| 182 "udp", "tcp", "ssltcp" | |
| 183 }; | |
| 184 | |
| 185 static const char* ProtocolToString(cricket::ProtocolType proto) { | |
| 186 return PROTO_NAMES[proto]; | |
| 187 } | |
| 188 | |
| 189 void XmppConnectionGenerator::UseCurrentConnection() { | |
| 190 LOG(INFO) << "XmppConnectionGenerator::UseCurrentConnection"; | |
| 191 | |
| 192 ConnectionSettings* settings = settings_list_->GetSettings(settings_index_); | |
| 193 LOG(INFO) << "*** Attempting " | |
| 194 << ProtocolToString(settings->protocol()) << " connection to " | |
| 195 << settings->server().IPAsString() << ":" | |
| 196 << settings->server().port() | |
| 197 << " (via " << ProxyToString(settings->proxy().type) | |
| 198 << " proxy @ " << settings->proxy().address.IPAsString() << ":" | |
| 199 << settings->proxy().address.port() << ")"; | |
| 200 | |
| 201 SignalNewSettings(*settings); | |
| 202 } | |
| 203 | |
| 204 void XmppConnectionGenerator::HandleExhaustedConnections() { | |
| 205 LOG(INFO) << "(" << buzz::XmppEngine::ERROR_SOCKET | |
| 206 << ", " << first_dns_error_ << ")"; | |
| 207 SignalExhaustedSettings(successfully_resolved_dns_, first_dns_error_); | |
| 208 } | |
| 209 | |
| 210 } // namespace notifier | |
| OLD | NEW |