QXmpp  Version: 1.10.4
QXmppOutgoingClient.h
1 // SPDX-FileCopyrightText: 2010 Manjeet Dahiya <manjeetdahiya@gmail.com>
2 // SPDX-FileCopyrightText: 2010 Jeremy LainĂ© <jeremy.laine@m4x.org>
3 // SPDX-FileCopyrightText: 2020 Linus Jahn <lnj@kaidan.im>
4 //
5 // SPDX-License-Identifier: LGPL-2.1-or-later
6 
7 #ifndef QXMPPOUTGOINGCLIENT_H
8 #define QXMPPOUTGOINGCLIENT_H
9 
10 #include "QXmppAuthenticationError.h"
11 #include "QXmppBindError.h"
12 #include "QXmppClient.h"
13 #include "QXmppPromise.h"
14 #include "QXmppStanza.h"
15 #include "QXmppStreamError.h"
16 
17 #include <QAbstractSocket>
18 
19 class QDomElement;
20 class QSslError;
21 class QSslSocket;
22 
23 class QXmppConfiguration;
24 class QXmppPresence;
25 class QXmppIq;
26 class QXmppMessage;
28 class QXmppOutgoingClientPrivate;
29 class TestClient;
30 
31 namespace QXmpp::Private {
32 class C2sStreamManager;
33 class CarbonManager;
34 class CsiManager;
35 class OutgoingIqManager;
36 class PingManager;
37 class SendDataInterface;
38 class StreamAckManager;
39 class XmppSocket;
40 struct Bind2Request;
41 struct Bind2Bound;
42 struct SmEnabled;
43 struct SmFailed;
44 struct SmResumed;
45 struct StreamErrorElement;
46 
47 enum HandleElementResult {
48  Accepted,
49  Rejected,
50  Finished,
51 };
52 
53 enum class AuthenticationMethod {
54  NonSasl,
55  Sasl,
56  Sasl2,
57 };
58 
59 struct SessionBegin {
60  bool smEnabled;
61  bool smResumed;
62  bool bind2Used;
63  bool fastTokenChanged;
64  AuthenticationMethod authenticationMethod;
65 };
66 
67 struct SessionEnd {
68  bool smCanResume;
69 };
70 } // namespace QXmpp::Private
71 
72 namespace QXmpp::Private::Sasl2 {
73 struct Authenticate;
74 struct StreamFeature;
75 struct Success;
76 } // namespace QXmpp::Private::Sasl2
77 
78 // The QXmppOutgoingClient class represents an outgoing XMPP stream to an XMPP server.
79 class QXMPP_EXPORT QXmppOutgoingClient : public QXmppLoggable
80 {
81  Q_OBJECT
82 
83 public:
84  using IqResult = std::variant<QDomElement, QXmppError>;
85  using ConnectionError = std::variant<QAbstractSocket::SocketError, QXmpp::TimeoutError, QXmpp::StreamError, QXmpp::AuthenticationError, QXmpp::BindError>;
86  static constexpr QStringView TaskName = u"client session";
87 
88  explicit QXmppOutgoingClient(QObject *parent);
89  ~QXmppOutgoingClient() override;
90 
91  void connectToHost();
92  void disconnectFromHost();
93  bool isAuthenticated() const;
94  bool isConnected() const;
95  QXmppTask<IqResult> sendIq(QXmppIq &&);
96 
98  QSslSocket *socket() const;
99  QXmppStanza::Error::Condition xmppStreamError();
100 
101  QXmppConfiguration &configuration();
102 
103  QXmpp::Private::XmppSocket &xmppSocket() const;
104  QXmpp::Private::StreamAckManager &streamAckManager() const;
105  QXmpp::Private::OutgoingIqManager &iqManager() const;
106  QXmpp::Private::C2sStreamManager &c2sStreamManager() const;
107  QXmpp::Private::CarbonManager &carbonManager() const;
108  QXmpp::Private::CsiManager &csiManager() const;
109 
111  Q_SIGNAL void connected(const QXmpp::Private::SessionBegin &);
112 
114  Q_SIGNAL void disconnected(const QXmpp::Private::SessionEnd &);
115 
117  Q_SIGNAL void errorOccurred(const QString &text, const QXmppOutgoingClient::ConnectionError &details, QXmppClient::Error oldError);
118 
120  Q_SIGNAL void elementReceived(const QDomElement &element, bool &handled);
121 
123  Q_SIGNAL void presenceReceived(const QXmppPresence &);
124 
126  Q_SIGNAL void messageReceived(const QXmppMessage &);
127 
130  Q_SIGNAL void iqReceived(const QXmppIq &);
131 
133  Q_SIGNAL void sslErrors(const QList<QSslError> &errors);
134 
135 private:
136  void handleStart();
137  void handleStream(const QDomElement &element);
138  void handlePacketReceived(const QDomElement &element);
139  QXmpp::Private::HandleElementResult handleElement(const QDomElement &nodeRecv);
140  void handleStreamFeatures(const QXmppStreamFeatures &features);
141  void handleStreamError(const QXmpp::Private::StreamErrorElement &streamError);
142  bool handleStanza(const QDomElement &);
143  bool handleStarttls(const QXmppStreamFeatures &features);
144 
145  void _q_socketDisconnected();
146  void socketError(QAbstractSocket::SocketError);
147  void socketSslErrors(const QList<QSslError> &);
148 
149  void startSasl2Auth(const QXmpp::Private::Sasl2::StreamFeature &sasl2Feature);
150  void startNonSaslAuth();
151  void startSmResume();
152  void startSmEnable();
153  void startResourceBinding();
154  void openSession();
155  void closeSession();
156  void setError(const QString &text, ConnectionError &&details);
157  void throwKeepAliveError();
158 
159  // for unit tests, see TestClient
160  void enableStreamManagement(bool resetSequenceNumber);
161  bool handleIqResponse(const QDomElement &);
162 
163  friend class QXmppOutgoingClientPrivate;
164  friend class QXmpp::Private::PingManager;
165  friend class QXmpp::Private::C2sStreamManager;
166  friend class QXmppRegistrationManager;
167  friend class TestClient;
168 
169  const std::unique_ptr<QXmppOutgoingClientPrivate> d;
170 };
171 
172 namespace QXmpp::Private {
173 
174 class C2sStreamManager
175 {
176 public:
177  using Result = std::variant<Success, QXmppError>;
178  static constexpr QStringView TaskName = u"stream management";
179 
180  explicit C2sStreamManager(QXmppOutgoingClient *q);
181 
182  HandleElementResult handleElement(const QDomElement &);
183  bool hasResumeAddress() const { return m_canResume && !m_resumeHost.isEmpty() && m_resumePort; }
184  std::pair<QString, quint16> resumeAddress() const { return { m_resumeHost, m_resumePort }; }
185  void onStreamStart();
186  void onStreamFeatures(const QXmppStreamFeatures &);
187  void onStreamClosed();
188  void onSasl2Authenticate(Sasl2::Authenticate &auth, const Sasl2::StreamFeature &feature);
189  void onSasl2Success(const Sasl2::Success &success);
190  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
191  void onBind2Bound(const Bind2Bound &);
192  bool canResume() const { return m_canResume; }
193  bool enabled() const { return m_enabled; }
194  bool streamResumed() const { return m_streamResumed; }
195  bool canRequestResume() const { return m_smAvailable && !m_enabled && m_canResume; }
196  QXmppTask<void> requestResume();
197  bool canRequestEnable() const { return m_smAvailable && !m_enabled; }
198  QXmppTask<void> requestEnable();
199  bool hasOngoingRequest() const { return !std::holds_alternative<NoRequest>(m_request); }
200 
201 private:
202  friend class ::TestClient;
203 
204  void onEnabled(const SmEnabled &enabled);
205  void onEnableFailed(const SmFailed &failed);
206  void onResumed(const SmResumed &resumed);
207  void onResumeFailed(const SmFailed &failed);
208  bool setResumeAddress(const QString &address);
209  void setEnabled(bool enabled) { m_enabled = enabled; }
210  void setResumed(bool resumed) { m_streamResumed = resumed; }
211 
212  struct NoRequest { };
213  struct ResumeRequest {
215  };
216  struct EnableRequest {
218  };
219 
220  QXmppOutgoingClient *q;
221 
222  std::variant<NoRequest, ResumeRequest, EnableRequest> m_request;
223  bool m_smAvailable = false;
224  QString m_smId;
225  bool m_canResume = false;
226  QString m_resumeHost;
227  quint16 m_resumePort = 0;
228  bool m_enabled = false;
229  bool m_streamResumed = false;
230 };
231 
232 // XEP-0280: Message Carbons
233 class CarbonManager
234 {
235 public:
236  void setEnableViaBind2(bool enable) { m_enableViaBind2 = enable; }
237  bool enabled() const { return m_enabled; }
238  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
239  void onSessionOpened(const SessionBegin &session);
240 
241 private:
242  // whether to enable carbons via bind2 if available
243  bool m_enableViaBind2 = false;
244  // whether carbons have been enabled via bind2
245  bool m_enabled = false;
246  bool m_requested = false;
247 };
248 
249 // XEP-0352: Client State Indication
250 class CsiManager
251 {
252 public:
253  enum State {
254  Active,
255  Inactive,
256  };
257 
258  explicit CsiManager(QXmppOutgoingClient *client);
259 
260  State state() const { return m_state; }
261  void setState(State);
262  void onSessionOpened(const SessionBegin &);
263  void onStreamFeatures(const QXmppStreamFeatures &);
264  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
265 
266 private:
267  void sendState();
268 
269  QXmppOutgoingClient *m_client;
270  State m_state = Active;
271  bool m_synced = true;
272  bool m_featureAvailable = false;
273  bool m_bind2InactiveSet = false;
274 };
275 
276 } // namespace QXmpp::Private
277 
278 #endif // QXMPPOUTGOINGCLIENT_H
The QXmppConfiguration class holds configuration options.
Definition: QXmppConfiguration.h:36
The QXmppStreamFeatures class represents the features returned by an XMPP server or client...
Definition: QXmppStreamFeatures.h:22
The QXmppLoggable class represents a source of logging messages.
Definition: QXmppLogger.h:109
Definition: QXmppTask.h:61
Error
Definition: QXmppClient.h:76
Definition: QXmppSasl_p.h:160
The QXmppPresence class represents an XMPP presence stanza.
Definition: QXmppPresence.h:21
Condition
A detailed condition of the error.
Definition: QXmppStanza.h:110
The QXmppRegistrationManager class manages in-band registration and account management tasks like cha...
Definition: QXmppRegistrationManager.h:224
The QXmppIq class is the base class for all IQs.
Definition: QXmppIq.h:22
The QXmppMessage class represents an XMPP message.
Definition: QXmppMessage.h:63
Definition: Algorithms.h:12