1 // Copyright (c) 2012 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 #include "jingle/notifier/base/xmpp_connection.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_piece.h"
11 #include "jingle/glue/chrome_async_socket.h"
12 #include "jingle/glue/task_pump.h"
13 #include "jingle/glue/xmpp_client_socket_factory.h"
14 #include "jingle/notifier/base/weak_xmpp_client.h"
15 #include "net/socket/client_socket_factory.h"
16 #include "net/ssl/ssl_config_service.h"
17 #include "net/url_request/url_request_context.h"
18 #include "talk/xmpp/xmppclientsettings.h"
19
20 namespace notifier {
21
~Delegate()22 XmppConnection::Delegate::~Delegate() {}
23
24 namespace {
25
CreateSocket(const buzz::XmppClientSettings & xmpp_client_settings,const scoped_refptr<net::URLRequestContextGetter> & request_context_getter)26 buzz::AsyncSocket* CreateSocket(
27 const buzz::XmppClientSettings& xmpp_client_settings,
28 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
29 bool use_fake_ssl_client_socket =
30 (xmpp_client_settings.protocol() == cricket::PROTO_SSLTCP);
31 // The default SSLConfig is good enough for us for now.
32 const net::SSLConfig ssl_config;
33 // These numbers were taken from similar numbers in
34 // XmppSocketAdapter.
35 const size_t kReadBufSize = 64U * 1024U;
36 const size_t kWriteBufSize = 64U * 1024U;
37 jingle_glue::XmppClientSocketFactory* const client_socket_factory =
38 new jingle_glue::XmppClientSocketFactory(
39 net::ClientSocketFactory::GetDefaultFactory(),
40 ssl_config,
41 request_context_getter,
42 use_fake_ssl_client_socket);
43 return new jingle_glue::ChromeAsyncSocket(client_socket_factory,
44 kReadBufSize, kWriteBufSize);
45 }
46
47 } // namespace
48
XmppConnection(const buzz::XmppClientSettings & xmpp_client_settings,const scoped_refptr<net::URLRequestContextGetter> & request_context_getter,Delegate * delegate,buzz::PreXmppAuth * pre_xmpp_auth)49 XmppConnection::XmppConnection(
50 const buzz::XmppClientSettings& xmpp_client_settings,
51 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
52 Delegate* delegate,
53 buzz::PreXmppAuth* pre_xmpp_auth)
54 : task_pump_(new jingle_glue::TaskPump()),
55 on_connect_called_(false),
56 delegate_(delegate) {
57 DCHECK(delegate_);
58 // Owned by |task_pump_|, but is guaranteed to live at least as long
59 // as this function.
60 WeakXmppClient* weak_xmpp_client = new WeakXmppClient(task_pump_.get());
61 weak_xmpp_client->SignalStateChange.connect(
62 this, &XmppConnection::OnStateChange);
63 weak_xmpp_client->SignalLogInput.connect(
64 this, &XmppConnection::OnInputLog);
65 weak_xmpp_client->SignalLogOutput.connect(
66 this, &XmppConnection::OnOutputLog);
67 const char kLanguage[] = "en";
68 buzz::XmppReturnStatus connect_status =
69 weak_xmpp_client->Connect(xmpp_client_settings, kLanguage,
70 CreateSocket(xmpp_client_settings,
71 request_context_getter),
72 pre_xmpp_auth);
73 // buzz::XmppClient::Connect() should never fail.
74 DCHECK_EQ(connect_status, buzz::XMPP_RETURN_OK);
75 weak_xmpp_client->Start();
76 weak_xmpp_client_ = weak_xmpp_client->AsWeakPtr();
77 }
78
~XmppConnection()79 XmppConnection::~XmppConnection() {
80 DCHECK(CalledOnValidThread());
81 ClearClient();
82 task_pump_->Stop();
83 base::MessageLoop* current_message_loop = base::MessageLoop::current();
84 CHECK(current_message_loop);
85 // We do this because XmppConnection may get destroyed as a result
86 // of a signal from XmppClient. If we delete |task_pump_| here, bad
87 // things happen when the stack pops back up to the XmppClient's
88 // (which is deleted by |task_pump_|) function.
89 current_message_loop->DeleteSoon(FROM_HERE, task_pump_.release());
90 }
91
OnStateChange(buzz::XmppEngine::State state)92 void XmppConnection::OnStateChange(buzz::XmppEngine::State state) {
93 DCHECK(CalledOnValidThread());
94 VLOG(1) << "XmppClient state changed to " << state;
95 if (!weak_xmpp_client_.get()) {
96 LOG(DFATAL) << "weak_xmpp_client_ unexpectedly NULL";
97 return;
98 }
99 if (!delegate_) {
100 LOG(DFATAL) << "delegate_ unexpectedly NULL";
101 return;
102 }
103 switch (state) {
104 case buzz::XmppEngine::STATE_OPEN:
105 if (on_connect_called_) {
106 LOG(DFATAL) << "State changed to STATE_OPEN more than once";
107 } else {
108 delegate_->OnConnect(weak_xmpp_client_);
109 on_connect_called_ = true;
110 }
111 break;
112 case buzz::XmppEngine::STATE_CLOSED: {
113 int subcode = 0;
114 buzz::XmppEngine::Error error =
115 weak_xmpp_client_->GetError(&subcode);
116 const buzz::XmlElement* stream_error =
117 weak_xmpp_client_->GetStreamError();
118 ClearClient();
119 Delegate* delegate = delegate_;
120 delegate_ = NULL;
121 delegate->OnError(error, subcode, stream_error);
122 break;
123 }
124 default:
125 // Do nothing.
126 break;
127 }
128 }
129
OnInputLog(const char * data,int len)130 void XmppConnection::OnInputLog(const char* data, int len) {
131 DCHECK(CalledOnValidThread());
132 VLOG(2) << "XMPP Input: " << base::StringPiece(data, len);
133 }
134
OnOutputLog(const char * data,int len)135 void XmppConnection::OnOutputLog(const char* data, int len) {
136 DCHECK(CalledOnValidThread());
137 VLOG(2) << "XMPP Output: " << base::StringPiece(data, len);
138 }
139
ClearClient()140 void XmppConnection::ClearClient() {
141 if (weak_xmpp_client_.get()) {
142 weak_xmpp_client_->Invalidate();
143 DCHECK(!weak_xmpp_client_.get());
144 }
145 }
146
147 } // namespace notifier
148