aboutsummaryrefslogtreecommitdiff
path: root/src/notification/xmpp_channel.h
blob: b0a44685c115c68c81b93be7efc732e6263b145e (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2015 The Weave Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIBWEAVE_SRC_NOTIFICATION_XMPP_CHANNEL_H_
#define LIBWEAVE_SRC_NOTIFICATION_XMPP_CHANNEL_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include <base/callback_forward.h>
#include <base/macros.h>
#include <base/memory/weak_ptr.h>
#include <weave/stream.h>

#include "src/backoff_entry.h"
#include "src/notification/notification_channel.h"
#include "src/notification/xmpp_iq_stanza_handler.h"
#include "src/notification/xmpp_stream_parser.h"

namespace weave {

namespace provider {
class Network;
class TaskRunner;
}

// Simple interface to abstract XmppChannel's SendMessage() method.
class XmppChannelInterface {
 public:
  virtual void SendMessage(const std::string& message) = 0;

 protected:
  virtual ~XmppChannelInterface() {}
};

class XmppChannel : public NotificationChannel,
                    public XmppStreamParser::Delegate,
                    public XmppChannelInterface {
 public:
  // |account| is the robot account for buffet and |access_token|
  // it the OAuth token. Note that the OAuth token expires fairly frequently
  // so you will need to reset the XmppClient every time this happens.
  XmppChannel(const std::string& account,
              const std::string& access_token,
              const std::string& xmpp_endpoint,
              provider::TaskRunner* task_runner,
              provider::Network* network);
  ~XmppChannel() override = default;

  // Overrides from NotificationChannel.
  std::string GetName() const override;
  bool IsConnected() const override;
  void AddChannelParameters(base::DictionaryValue* channel_json) override;
  void Start(NotificationDelegate* delegate) override;
  void Stop() override;

  const std::string& jid() const { return jid_; }

  // Internal states for the XMPP stream.
  enum class XmppState {
    kNotStarted,
    kConnecting,
    kConnected,
    kAuthenticationStarted,
    kAuthenticationFailed,
    kStreamRestartedPostAuthentication,
    kBindSent,
    kSessionStarted,
    kSubscribeStarted,
    kSubscribed,
  };

 protected:
  // These methods are internal helpers that can be overloaded by unit tests
  // to help provide unit-test-specific functionality.
  virtual void SchedulePing(base::TimeDelta interval, base::TimeDelta timeout);
  void ScheduleRegularPing();
  void ScheduleFastPing();

 private:
  friend class IqStanzaHandler;
  friend class FakeXmppChannel;

  // Overrides from XmppStreamParser::Delegate.
  void OnStreamStart(const std::string& node_name,
                     std::map<std::string, std::string> attributes) override;
  void OnStreamEnd(const std::string& node_name) override;
  void OnStanza(std::unique_ptr<XmlNode> stanza) override;

  // Overrides from XmppChannelInterface.
  void SendMessage(const std::string& message) override;

  void HandleStanza(std::unique_ptr<XmlNode> stanza);
  void HandleMessageStanza(std::unique_ptr<XmlNode> stanza);
  void RestartXmppStream();

  void CreateSslSocket();
  void OnSslSocketReady(std::unique_ptr<Stream> stream, ErrorPtr error);

  void WaitForMessage();

  void OnMessageRead(size_t size, ErrorPtr error);
  void OnMessageSent(ErrorPtr error);
  void Restart();
  void CloseStream();

  // XMPP connection state machine's state handlers.
  void OnBindCompleted(std::unique_ptr<XmlNode> reply);
  void OnSessionEstablished(std::unique_ptr<XmlNode> reply);
  void OnSubscribed(std::unique_ptr<XmlNode> reply);

  // Sends a ping request to the server to check if the connection is still
  // valid.
  void PingServer(base::TimeDelta timeout);
  void OnPingResponse(base::Time sent_time, std::unique_ptr<XmlNode> reply);
  void OnPingTimeout(base::Time sent_time);

  void OnConnectivityChanged();

  XmppState state_{XmppState::kNotStarted};

  // Robot account name for the device.
  std::string account_;

  // OAuth access token for the account. Expires fairly frequently.
  std::string access_token_;

  // Xmpp endpoint.
  std::string xmpp_endpoint_;

  // Full JID of this device.
  std::string jid_;

  provider::Network* network_{nullptr};
  std::unique_ptr<Stream> stream_;

  // Read buffer for incoming message packets.
  std::vector<char> read_socket_data_;
  // Write buffer for outgoing message packets.
  std::string write_socket_data_;
  std::string queued_write_data_;

  // XMPP server name and port used for connection.
  std::string host_;
  uint16_t port_{0};

  BackoffEntry backoff_entry_;
  NotificationDelegate* delegate_{nullptr};
  provider::TaskRunner* task_runner_{nullptr};
  XmppStreamParser stream_parser_{this};
  bool read_pending_{false};
  bool write_pending_{false};
  std::unique_ptr<IqStanzaHandler> iq_stanza_handler_;

  base::WeakPtrFactory<XmppChannel> ping_ptr_factory_{this};
  base::WeakPtrFactory<XmppChannel> task_ptr_factory_{this};
  base::WeakPtrFactory<XmppChannel> weak_ptr_factory_{this};
  DISALLOW_COPY_AND_ASSIGN(XmppChannel);
};

}  // namespace weave

#endif  // LIBWEAVE_SRC_NOTIFICATION_XMPP_CHANNEL_H_