1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qcoapconnection_p.h" |
5 | |
6 | #include <QtCore/qloggingcategory.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | Q_LOGGING_CATEGORY(lcCoapConnection, "qt.coap.connection" ) |
11 | |
12 | /*! |
13 | \internal |
14 | |
15 | \class QCoapConnection |
16 | \inmodule QtCoap |
17 | |
18 | \brief The QCoapConnection class defines an interface for |
19 | handling transfers of frames to a server. |
20 | |
21 | It isolates CoAP clients from the transport in use, so that any |
22 | client can be used with any supported transport. |
23 | */ |
24 | |
25 | /*! |
26 | \internal |
27 | |
28 | \enum QCoapConnection::ConnectionState |
29 | |
30 | This enum specifies the state of the underlying transport. |
31 | |
32 | \value Unconnected The underlying transport is not yet ready for data transmission. |
33 | |
34 | \value Bound The underlying transport is ready for data transmission. For example, |
35 | if QUdpSocket is used for the transport, this corresponds to |
36 | QAbstractSocket::BoundState. |
37 | \sa state(), bound() |
38 | */ |
39 | |
40 | /*! |
41 | \internal |
42 | |
43 | \fn void QCoapConnection::error(QAbstractSocket::SocketError error) |
44 | |
45 | This signal is emitted when a connection error occurs. The \a error |
46 | parameter describes the type of error that occurred. |
47 | */ |
48 | |
49 | /*! |
50 | \internal |
51 | |
52 | \fn void QCoapConnection::readyRead(const QByteArray &data, const QHostAddress &sender) |
53 | |
54 | This signal is emitted when a network reply is available. The \a data |
55 | parameter supplies the received data, and the \a sender parameter supplies |
56 | the sender address. |
57 | */ |
58 | |
59 | /*! |
60 | \internal |
61 | |
62 | \fn void QCoapConnection::bound() |
63 | |
64 | This signal is emitted when the underlying transport is ready for data transmission. |
65 | Derived implementations must emit this signal whenever they are ready to start |
66 | transferring data frames to and from the server. |
67 | |
68 | \sa bind() |
69 | */ |
70 | |
71 | /*! |
72 | \fn void QCoapConnection::securityConfigurationChanged() |
73 | |
74 | This signal is emitted when the security configuration is changed. |
75 | */ |
76 | |
77 | /*! |
78 | \internal |
79 | |
80 | \fn void QCoapConnection::bind(const QString &host, quint16 port) |
81 | |
82 | Prepares the underlying transport for data transmission to to the given \a host |
83 | address on \a port. Emits the bound() signal when the transport is ready. |
84 | |
85 | This is a pure virtual method. |
86 | |
87 | \sa bound(), close() |
88 | */ |
89 | |
90 | /*! |
91 | \internal |
92 | |
93 | \fn void QCoapConnection::close() |
94 | |
95 | Closes the open sockets and connections to free the underlying transport. |
96 | This is a pure virtual method. |
97 | |
98 | \sa bind() |
99 | */ |
100 | |
101 | /*! |
102 | \internal |
103 | |
104 | \fn void QCoapConnection::writeData(const QByteArray &data, const QString &host, quint16 port) |
105 | |
106 | Sends the given \a data frame to the host address \a host at port \a port. |
107 | |
108 | This is a pure virtual method. |
109 | */ |
110 | |
111 | QCoapConnectionPrivate::QCoapConnectionPrivate(QtCoap::SecurityMode security) |
112 | : securityMode(security) |
113 | , state(QCoapConnection::ConnectionState::Unconnected) |
114 | {} |
115 | |
116 | /*! |
117 | Constructs a new CoAP connection for the given \a securityMode and |
118 | sets \a parent as its parent. |
119 | */ |
120 | QCoapConnection::QCoapConnection(QtCoap::SecurityMode securityMode, QObject *parent) |
121 | : QCoapConnection(*new QCoapConnectionPrivate(securityMode), parent) |
122 | { |
123 | } |
124 | |
125 | /*! |
126 | \internal |
127 | |
128 | Constructs a new new CoAP connection as a child of \a parent, with \a dd |
129 | as its \c d_ptr. This constructor must be used when internally subclassing |
130 | the QCoapConnection class. |
131 | */ |
132 | QCoapConnection::QCoapConnection(QObjectPrivate &dd, QObject *parent) |
133 | : QObject(dd, parent) |
134 | { |
135 | connect(sender: this, signal: &QCoapConnection::bound, context: this, |
136 | slot: [this]() { |
137 | Q_D(QCoapConnection); |
138 | d->state = ConnectionState::Bound; |
139 | startToSendRequest(); |
140 | }); |
141 | } |
142 | |
143 | /*! |
144 | \internal |
145 | |
146 | Releases any resources held by QCoapConnection. |
147 | */ |
148 | QCoapConnection::~QCoapConnection() |
149 | { |
150 | } |
151 | |
152 | /*! |
153 | \internal |
154 | |
155 | Prepares the underlying transport for data transmission and sends the given |
156 | \a request frame to the given \a host at the given \a port when the transport |
157 | is ready. |
158 | |
159 | The preparation of the transport is done by calling the pure virtual bind() method, |
160 | which needs to be implemented by derived classes. |
161 | */ |
162 | void |
163 | QCoapConnectionPrivate::sendRequest(const QByteArray &request, const QString &host, quint16 port) |
164 | { |
165 | Q_Q(QCoapConnection); |
166 | |
167 | CoapFrame frame(request, host, port); |
168 | framesToSend.enqueue(t: frame); |
169 | |
170 | if (state == QCoapConnection::ConnectionState::Unconnected) |
171 | q->bind(host, port); |
172 | else |
173 | q->startToSendRequest(); |
174 | } |
175 | |
176 | /*! |
177 | \internal |
178 | |
179 | Returns \c true if security is used, returns \c false otherwise. |
180 | */ |
181 | bool QCoapConnection::isSecure() const |
182 | { |
183 | Q_D(const QCoapConnection); |
184 | return d->securityMode != QtCoap::SecurityMode::NoSecurity; |
185 | } |
186 | |
187 | /*! |
188 | \internal |
189 | |
190 | Returns the security mode. |
191 | */ |
192 | QtCoap::SecurityMode QCoapConnection::securityMode() const |
193 | { |
194 | Q_D(const QCoapConnection); |
195 | return d->securityMode; |
196 | } |
197 | |
198 | /*! |
199 | \internal |
200 | |
201 | Returns the connection state. |
202 | */ |
203 | QCoapConnection::ConnectionState QCoapConnection::state() const |
204 | { |
205 | Q_D(const QCoapConnection); |
206 | return d->state; |
207 | } |
208 | |
209 | /*! |
210 | \internal |
211 | |
212 | Sends the last stored frame to the server by calling the pure virtual |
213 | writeData() method. |
214 | */ |
215 | void QCoapConnection::startToSendRequest() |
216 | { |
217 | Q_D(QCoapConnection); |
218 | |
219 | Q_ASSERT(!d->framesToSend.isEmpty()); |
220 | while (!d->framesToSend.isEmpty()) { |
221 | const CoapFrame frame = d->framesToSend.dequeue(); |
222 | writeData(data: frame.currentPdu, host: frame.host, port: frame.port); |
223 | } |
224 | } |
225 | |
226 | /*! |
227 | Sets the security configuration parameters from the \a configuration. |
228 | The security configuration will be ignored if the QtCoap::NoSecurity mode is |
229 | used for connection. |
230 | |
231 | \note This method must be called before the handshake starts. |
232 | */ |
233 | void QCoapConnection::setSecurityConfiguration(const QCoapSecurityConfiguration &configuration) |
234 | { |
235 | Q_D(QCoapConnection); |
236 | |
237 | if (isSecure()) { |
238 | d->securityConfiguration = configuration; |
239 | emit securityConfigurationChanged(); |
240 | } else { |
241 | qCWarning(lcCoapConnection, "Security is disabled, security configuration will be ignored." ); |
242 | } |
243 | } |
244 | |
245 | /*! |
246 | \internal |
247 | |
248 | Returns the security configuration. |
249 | */ |
250 | QCoapSecurityConfiguration QCoapConnection::securityConfiguration() const |
251 | { |
252 | Q_D(const QCoapConnection); |
253 | return d->securityConfiguration; |
254 | } |
255 | |
256 | /*! |
257 | \internal |
258 | |
259 | Closes the open sockets and connections to free the transport and clears |
260 | the connection state. |
261 | */ |
262 | void QCoapConnection::disconnect() |
263 | { |
264 | Q_D(QCoapConnection); |
265 | |
266 | close(); |
267 | |
268 | d->framesToSend.clear(); |
269 | d->state = ConnectionState::Unconnected; |
270 | } |
271 | |
272 | QT_END_NAMESPACE |
273 | |