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 22 XmppConnection::Delegate::~Delegate() {} 23 24 namespace { 25 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 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 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 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 130 void XmppConnection::OnInputLog(const char* data, int len) { 131 DCHECK(CalledOnValidThread()); 132 VLOG(2) << "XMPP Input: " << base::StringPiece(data, len); 133 } 134 135 void XmppConnection::OnOutputLog(const char* data, int len) { 136 DCHECK(CalledOnValidThread()); 137 VLOG(2) << "XMPP Output: " << base::StringPiece(data, len); 138 } 139 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