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 |