summaryrefslogtreecommitdiff
path: root/chromium/jingle/notifier/base/xmpp_connection.cc
blob: 08a8ee370a2fdcc520e9adbb287b4e4a61e75338 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) 2012 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 "jingle/notifier/base/xmpp_connection.h"

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_piece.h"
#include "jingle/glue/chrome_async_socket.h"
#include "jingle/glue/task_pump.h"
#include "jingle/glue/xmpp_client_socket_factory.h"
#include "jingle/notifier/base/weak_xmpp_client.h"
#include "net/socket/client_socket_factory.h"
#include "net/ssl/ssl_config_service.h"
#include "net/url_request/url_request_context.h"
#include "talk/xmpp/xmppclientsettings.h"

namespace notifier {

XmppConnection::Delegate::~Delegate() {}

namespace {

buzz::AsyncSocket* CreateSocket(
    const buzz::XmppClientSettings& xmpp_client_settings,
    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
  bool use_fake_ssl_client_socket =
      (xmpp_client_settings.protocol() == cricket::PROTO_SSLTCP);
  // The default SSLConfig is good enough for us for now.
  const net::SSLConfig ssl_config;
  // These numbers were taken from similar numbers in
  // XmppSocketAdapter.
  const size_t kReadBufSize = 64U * 1024U;
  const size_t kWriteBufSize = 64U * 1024U;
  jingle_glue::XmppClientSocketFactory* const client_socket_factory =
      new jingle_glue::XmppClientSocketFactory(
          net::ClientSocketFactory::GetDefaultFactory(),
          ssl_config,
          request_context_getter,
          use_fake_ssl_client_socket);
  return new jingle_glue::ChromeAsyncSocket(client_socket_factory,
                                            kReadBufSize, kWriteBufSize);
}

}  // namespace

XmppConnection::XmppConnection(
    const buzz::XmppClientSettings& xmpp_client_settings,
    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
    Delegate* delegate,
    buzz::PreXmppAuth* pre_xmpp_auth)
    : task_pump_(new jingle_glue::TaskPump()),
      on_connect_called_(false),
      delegate_(delegate) {
  DCHECK(delegate_);
  // Owned by |task_pump_|, but is guaranteed to live at least as long
  // as this function.
  WeakXmppClient* weak_xmpp_client = new WeakXmppClient(task_pump_.get());
  weak_xmpp_client->SignalStateChange.connect(
      this, &XmppConnection::OnStateChange);
  weak_xmpp_client->SignalLogInput.connect(
      this, &XmppConnection::OnInputLog);
  weak_xmpp_client->SignalLogOutput.connect(
      this, &XmppConnection::OnOutputLog);
  const char kLanguage[] = "en";
  buzz::XmppReturnStatus connect_status =
      weak_xmpp_client->Connect(xmpp_client_settings, kLanguage,
                                CreateSocket(xmpp_client_settings,
                                             request_context_getter),
                                pre_xmpp_auth);
  // buzz::XmppClient::Connect() should never fail.
  DCHECK_EQ(connect_status, buzz::XMPP_RETURN_OK);
  weak_xmpp_client->Start();
  weak_xmpp_client_ = weak_xmpp_client->AsWeakPtr();
}

XmppConnection::~XmppConnection() {
  DCHECK(CalledOnValidThread());
  ClearClient();
  task_pump_->Stop();
  base::MessageLoop* current_message_loop = base::MessageLoop::current();
  CHECK(current_message_loop);
  // We do this because XmppConnection may get destroyed as a result
  // of a signal from XmppClient.  If we delete |task_pump_| here, bad
  // things happen when the stack pops back up to the XmppClient's
  // (which is deleted by |task_pump_|) function.
  current_message_loop->DeleteSoon(FROM_HERE, task_pump_.release());
}

void XmppConnection::OnStateChange(buzz::XmppEngine::State state) {
  DCHECK(CalledOnValidThread());
  VLOG(1) << "XmppClient state changed to " << state;
  if (!weak_xmpp_client_.get()) {
    LOG(DFATAL) << "weak_xmpp_client_ unexpectedly NULL";
    return;
  }
  if (!delegate_) {
    LOG(DFATAL) << "delegate_ unexpectedly NULL";
    return;
  }
  switch (state) {
    case buzz::XmppEngine::STATE_OPEN:
      if (on_connect_called_) {
        LOG(DFATAL) << "State changed to STATE_OPEN more than once";
      } else {
        delegate_->OnConnect(weak_xmpp_client_);
        on_connect_called_ = true;
      }
      break;
    case buzz::XmppEngine::STATE_CLOSED: {
      int subcode = 0;
      buzz::XmppEngine::Error error =
          weak_xmpp_client_->GetError(&subcode);
      const buzz::XmlElement* stream_error =
          weak_xmpp_client_->GetStreamError();
      ClearClient();
      Delegate* delegate = delegate_;
      delegate_ = NULL;
      delegate->OnError(error, subcode, stream_error);
      break;
    }
    default:
      // Do nothing.
      break;
  }
}

void XmppConnection::OnInputLog(const char* data, int len) {
  DCHECK(CalledOnValidThread());
  VLOG(2) << "XMPP Input: " << base::StringPiece(data, len);
}

void XmppConnection::OnOutputLog(const char* data, int len) {
  DCHECK(CalledOnValidThread());
  VLOG(2) << "XMPP Output: " << base::StringPiece(data, len);
}

void XmppConnection::ClearClient() {
  if (weak_xmpp_client_.get()) {
    weak_xmpp_client_->Invalidate();
    DCHECK(!weak_xmpp_client_.get());
  }
}

}  // namespace notifier