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 "chrome/browser/sync/notifier/base/async_dns_lookup.h" |
| 18 #include "chrome/browser/sync/notifier/base/signal_thread_task.h" |
| 19 #include "chrome/browser/sync/notifier/communicator/connection_options.h" |
| 20 #include "chrome/browser/sync/notifier/communicator/connection_settings.h" |
| 21 #include "chrome/browser/sync/notifier/communicator/product_info.h" |
| 22 #include "talk/base/autodetectproxy.h" |
| 23 #include "talk/base/httpcommon.h" |
| 24 #include "talk/base/logging.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(LS_VERBOSE) << "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(LS_VERBOSE) << "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(LS_VERBOSE) << "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 |
| 112 // are generated on demand). |
| 113 UseNextConnection(); |
| 114 } |
| 115 |
| 116 void XmppConnectionGenerator::UseNextConnection() { |
| 117 // Trying to connect |
| 118 |
| 119 // Iterate to the next possible connection |
| 120 settings_index_++; |
| 121 if (settings_index_ < settings_list_->GetCount()) { |
| 122 // We have more connection settings in the settings_list_ to try, kick |
| 123 // off the next one. |
| 124 UseCurrentConnection(); |
| 125 return; |
| 126 } |
| 127 |
| 128 // Iterate to the next possible server |
| 129 server_index_++; |
| 130 if (server_index_ < server_count_) { |
| 131 AsyncDNSLookup* dns_lookup = new AsyncDNSLookup( |
| 132 server_list_[server_index_].server); |
| 133 SignalThreadTask<AsyncDNSLookup>* wrapper_task = |
| 134 new SignalThreadTask<AsyncDNSLookup>(parent_, &dns_lookup); |
| 135 wrapper_task->SignalWorkDone.connect( |
| 136 this, |
| 137 &XmppConnectionGenerator::OnServerDNSResolved); |
| 138 wrapper_task->Start(); |
| 139 return; |
| 140 } |
| 141 |
| 142 // All out of possibilities |
| 143 HandleExhaustedConnections(); |
| 144 } |
| 145 |
| 146 void XmppConnectionGenerator::OnServerDNSResolved( |
| 147 AsyncDNSLookup* dns_lookup) { |
| 148 LOG(LS_VERBOSE) << "XmppConnectionGenerator::OnServerDNSResolved"; |
| 149 |
| 150 // Print logging info |
| 151 LOG(LS_VERBOSE) << " server: " << |
| 152 server_list_[server_index_].server.ToString() << |
| 153 " error: " << dns_lookup->error(); |
| 154 if (first_dns_error_ == 0 && dns_lookup->error() != 0) { |
| 155 first_dns_error_ = dns_lookup->error(); |
| 156 } |
| 157 |
| 158 if (!successfully_resolved_dns_ && dns_lookup->ip_list().size() > 0) { |
| 159 successfully_resolved_dns_ = true; |
| 160 } |
| 161 |
| 162 for (int i = 0; i < static_cast<int>(dns_lookup->ip_list().size()); ++i) { |
| 163 LOG(LS_VERBOSE) |
| 164 << " ip " << i << " : " |
| 165 << talk_base::SocketAddress::IPToString(dns_lookup->ip_list()[i]); |
| 166 } |
| 167 |
| 168 // Build the ip list |
| 169 assert(settings_list_.get()); |
| 170 settings_index_ = -1; |
| 171 settings_list_->ClearPermutations(); |
| 172 settings_list_->AddPermutations( |
| 173 server_list_[server_index_].server.IPAsString(), |
| 174 dns_lookup->ip_list(), |
| 175 server_list_[server_index_].server.port(), |
| 176 server_list_[server_index_].special_port_magic, |
| 177 proxy_only_); |
| 178 |
| 179 UseNextConnection(); |
| 180 } |
| 181 |
| 182 static const char * const PROTO_NAMES[cricket::PROTO_LAST+1] = { |
| 183 "udp", "tcp", "ssltcp" |
| 184 }; |
| 185 |
| 186 static const char* ProtocolToString(cricket::ProtocolType proto) { |
| 187 return PROTO_NAMES[proto]; |
| 188 } |
| 189 |
| 190 void XmppConnectionGenerator::UseCurrentConnection() { |
| 191 LOG(LS_VERBOSE) << "XmppConnectionGenerator::UseCurrentConnection"; |
| 192 |
| 193 ConnectionSettings* settings = settings_list_->GetSettings(settings_index_); |
| 194 LOG(LS_INFO) << "*** Attempting " |
| 195 << ProtocolToString(settings->protocol()) << " connection to " |
| 196 << settings->server().IPAsString() << ":" |
| 197 << settings->server().port() |
| 198 << " (via " << ProxyToString(settings->proxy().type) |
| 199 << " proxy @ " << settings->proxy().address.IPAsString() << ":" |
| 200 << settings->proxy().address.port() << ")"; |
| 201 |
| 202 SignalNewSettings(*settings); |
| 203 } |
| 204 |
| 205 void XmppConnectionGenerator::HandleExhaustedConnections() { |
| 206 LOG_F(LS_VERBOSE) << "(" << buzz::XmppEngine::ERROR_SOCKET |
| 207 << ", " << first_dns_error_ << ")"; |
| 208 SignalExhaustedSettings(successfully_resolved_dns_, first_dns_error_); |
| 209 } |
| 210 } // namespace notifier |
OLD | NEW |