blob: 3088f6eff37e10ffc7b2debc2f3e39d5a1739202 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <cstddef>
#include <string>
#include <vector>
#include "jingle/notifier/communicator/single_login_attempt.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "jingle/notifier/base/const_communicator.h"
#include "jingle/notifier/base/gaia_token_pre_xmpp_auth.h"
#include "jingle/notifier/communicator/connection_options.h"
#include "jingle/notifier/communicator/connection_settings.h"
#include "jingle/notifier/communicator/login_settings.h"
#include "jingle/notifier/listener/xml_element_util.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "talk/xmllite/xmlelement.h"
#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
#include "talk/xmpp/constants.h"
namespace net {
class NetLog;
} // namespace net
namespace notifier {
SingleLoginAttempt::SingleLoginAttempt(LoginSettings* login_settings,
Delegate* delegate)
: login_settings_(login_settings),
delegate_(delegate),
connection_generator_(
ALLOW_THIS_IN_INITIALIZER_LIST(this),
login_settings_->request_context_getter()->GetURLRequestContext()->
host_resolver(),
&login_settings_->connection_options(),
login_settings_->try_ssltcp_first(),
login_settings_->servers()) {
// DNS resolution will happen at a lower layer (we are using the socket
// pools).
connection_generator_.SetShouldResolveDNS(false);
connection_generator_.StartGenerating();
}
SingleLoginAttempt::~SingleLoginAttempt() {}
void SingleLoginAttempt::OnConnect(
base::WeakPtr<buzz::XmppTaskParentInterface> base_task) {
delegate_->OnConnect(base_task);
}
void SingleLoginAttempt::OnError(buzz::XmppEngine::Error error, int subcode,
const buzz::XmlElement* stream_error) {
VLOG(1) << "Error: " << error << ", subcode: " << subcode;
if (stream_error) {
DCHECK_EQ(error, buzz::XmppEngine::ERROR_STREAM);
VLOG(1) << "Stream error: " << XmlElementToString(*stream_error);
}
// Check for redirection.
if (stream_error) {
const buzz::XmlElement* other =
stream_error->FirstNamed(buzz::QN_XSTREAM_SEE_OTHER_HOST);
if (other) {
const buzz::XmlElement* text =
stream_error->FirstNamed(buzz::QN_XSTREAM_TEXT);
if (text) {
// Yep, its a "stream:error" with "see-other-host" text,
// let's parse out the server:port, and then reconnect
// with that.
const std::string& redirect = text->BodyText();
size_t colon = redirect.find(":");
int redirect_port = kDefaultXmppPort;
std::string redirect_server;
if (colon == std::string::npos) {
redirect_server = redirect;
} else {
redirect_server = redirect.substr(0, colon);
const std::string& port_text = redirect.substr(colon + 1);
std::istringstream ist(port_text);
ist >> redirect_port;
}
// We never allow a redirect to port 0.
if (redirect_port == 0) {
redirect_port = kDefaultXmppPort;
}
delegate_->OnRedirect(redirect_server, redirect_port);
// May be deleted at this point.
return;
}
}
}
// Iterate to the next possible connection (still trying to connect).
connection_generator_.UseNextConnection();
}
void SingleLoginAttempt::OnNewSettings(
const ConnectionSettings& connection_settings) {
buzz::XmppClientSettings client_settings =
login_settings_->user_settings();
// Fill in the rest of the client settings.
connection_settings.FillXmppClientSettings(&client_settings);
buzz::Jid jid(client_settings.user(), client_settings.host(),
buzz::STR_EMPTY);
buzz::PreXmppAuth* pre_xmpp_auth =
new GaiaTokenPreXmppAuth(
jid.Str(), client_settings.auth_cookie(),
client_settings.token_service(),
login_settings_->auth_mechanism());
xmpp_connection_.reset(
new XmppConnection(client_settings,
login_settings_->request_context_getter(),
this, pre_xmpp_auth));
}
void SingleLoginAttempt::OnExhaustedSettings(
bool successfully_resolved_dns,
int first_dns_error) {
if (!successfully_resolved_dns)
VLOG(1) << "Could not resolve DNS: " << first_dns_error;
VLOG(1) << "Could not connect to any XMPP server";
delegate_->OnNeedReconnect();
}
} // namespace notifier