Home | History | Annotate | Download | only in base
      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