1 | // Copyright (C) 2017 Witekio. |
2 | // Copyright (C) 2018 The Qt Company Ltd. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
4 | |
5 | #include "qcoapmessage_p.h" |
6 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | QCoapMessagePrivate::QCoapMessagePrivate(QCoapMessage::Type _type) : |
10 | type(_type) |
11 | { |
12 | } |
13 | |
14 | QCoapMessagePrivate::QCoapMessagePrivate(const QCoapMessagePrivate &other) : |
15 | QSharedData(other), |
16 | version(other.version), type(other.type), messageId(other.messageId), |
17 | token(other.token), options(other.options), payload(other.payload) |
18 | { |
19 | } |
20 | |
21 | QCoapMessagePrivate::~QCoapMessagePrivate() |
22 | { |
23 | } |
24 | |
25 | QCoapMessagePrivate *QCoapMessagePrivate::clone() const |
26 | { |
27 | return new QCoapMessagePrivate(*this); |
28 | } |
29 | |
30 | /*! |
31 | \class QCoapMessage |
32 | \inmodule QtCoap |
33 | |
34 | \brief The QCoapMessage class holds information about a CoAP message that |
35 | can be a request or a reply. |
36 | |
37 | \reentrant |
38 | |
39 | It holds information such as the message type, message id, token and other |
40 | ancillary data. |
41 | |
42 | \sa QCoapOption, QCoapReply, QCoapRequest |
43 | */ |
44 | |
45 | /*! |
46 | \enum QCoapMessage::Type |
47 | |
48 | Indicates the type of the message. |
49 | |
50 | \value Confirmable A Confirmable message. The destination |
51 | endpoint needs to acknowledge the |
52 | message. |
53 | \value NonConfirmable A Non-Confirmable message. The |
54 | destination endpoint does not need to |
55 | acknowledge the message. |
56 | \value Acknowledgment An Acknowledgment message. A message |
57 | sent or received in reply to a |
58 | Confirmable message. |
59 | \value Reset A Reset message. This message type is used |
60 | in case of errors or to stop the ongoing |
61 | transmission. (For example, it is used |
62 | to cancel an observation). |
63 | */ |
64 | |
65 | /*! |
66 | \fn void QCoapMessage::swap(QCoapMessage &other) |
67 | |
68 | Swaps this message with \a other. This operation is very fast and never fails. |
69 | */ |
70 | |
71 | /*! |
72 | Constructs a new QCoapMessage. |
73 | */ |
74 | QCoapMessage::QCoapMessage() : |
75 | d_ptr(new QCoapMessagePrivate) |
76 | { |
77 | } |
78 | |
79 | /*! |
80 | Destroys the QCoapMessage. |
81 | */ |
82 | QCoapMessage::~QCoapMessage() |
83 | { |
84 | } |
85 | |
86 | /*! |
87 | Constructs a shallow copy of \a other. |
88 | */ |
89 | QCoapMessage::QCoapMessage(const QCoapMessage &other) : |
90 | d_ptr(other.d_ptr) |
91 | { |
92 | } |
93 | |
94 | /*! |
95 | \internal |
96 | Constructs a new QCoapMessage with \a dd as the d_ptr. |
97 | This constructor must be used internally when subclassing |
98 | the QCoapMessage class. |
99 | */ |
100 | QCoapMessage::QCoapMessage(QCoapMessagePrivate &dd) : |
101 | d_ptr(&dd) |
102 | { |
103 | } |
104 | |
105 | /*! |
106 | \overload |
107 | |
108 | Adds the CoAP option with the given \a name and \a value. |
109 | */ |
110 | void QCoapMessage::addOption(QCoapOption::OptionName name, const QByteArray &value) |
111 | { |
112 | QCoapOption option(name, value); |
113 | addOption(option); |
114 | } |
115 | |
116 | /*! |
117 | Adds the given CoAP \a option. |
118 | */ |
119 | void QCoapMessage::addOption(const QCoapOption &option) |
120 | { |
121 | Q_D(QCoapMessage); |
122 | |
123 | const auto it = std::upper_bound(first: d->options.begin(), last: d->options.end(), val: option, |
124 | comp: [](const QCoapOption &a, const QCoapOption &b) -> bool { |
125 | return a.name() < b.name(); |
126 | }); |
127 | const auto idx = std::distance(first: d->options.begin(), last: it); |
128 | |
129 | // Sort options by ascending order while inserting |
130 | d->options.insert(i: idx, t: option); |
131 | } |
132 | |
133 | /*! |
134 | Removes the given \a option. |
135 | */ |
136 | void QCoapMessage::removeOption(const QCoapOption &option) |
137 | { |
138 | Q_D(QCoapMessage); |
139 | d->options.removeOne(t: option); |
140 | } |
141 | |
142 | /*! |
143 | Removes all options with the given \a name. |
144 | The CoAP protocol allows for the same option to repeat. |
145 | */ |
146 | void QCoapMessage::removeOption(QCoapOption::OptionName name) |
147 | { |
148 | Q_D(QCoapMessage); |
149 | auto namesMatch = [name](const QCoapOption &option) { |
150 | return option.name() == name; |
151 | }; |
152 | |
153 | auto &options = d->options; |
154 | options.erase(abegin: std::remove_if(first: options.begin(), last: options.end(), pred: namesMatch), |
155 | aend: options.end()); |
156 | } |
157 | |
158 | /*! |
159 | Removes all options. |
160 | */ |
161 | void QCoapMessage::clearOptions() |
162 | { |
163 | Q_D(QCoapMessage); |
164 | d->options.clear(); |
165 | } |
166 | |
167 | /*! |
168 | Returns the CoAP version. |
169 | |
170 | \sa setVersion() |
171 | */ |
172 | quint8 QCoapMessage::version() const |
173 | { |
174 | Q_D(const QCoapMessage); |
175 | return d->version; |
176 | } |
177 | |
178 | /*! |
179 | Returns the message type. |
180 | |
181 | \sa setType() |
182 | */ |
183 | QCoapMessage::Type QCoapMessage::type() const |
184 | { |
185 | Q_D(const QCoapMessage); |
186 | return d->type; |
187 | } |
188 | |
189 | /*! |
190 | Returns the message token. |
191 | |
192 | \sa setToken() |
193 | */ |
194 | QByteArray QCoapMessage::token() const |
195 | { |
196 | Q_D(const QCoapMessage); |
197 | return d->token; |
198 | } |
199 | |
200 | /*! |
201 | Returns the token length. |
202 | */ |
203 | quint8 QCoapMessage::tokenLength() const |
204 | { |
205 | Q_D(const QCoapMessage); |
206 | return static_cast<quint8>(d->token.size()); |
207 | } |
208 | |
209 | /*! |
210 | Returns the message id. |
211 | |
212 | \sa setMessageId() |
213 | */ |
214 | quint16 QCoapMessage::messageId() const |
215 | { |
216 | Q_D(const QCoapMessage); |
217 | return d->messageId; |
218 | } |
219 | |
220 | /*! |
221 | Returns the payload. |
222 | |
223 | \sa setPayload() |
224 | */ |
225 | QByteArray QCoapMessage::payload() const |
226 | { |
227 | Q_D(const QCoapMessage); |
228 | return d->payload; |
229 | } |
230 | |
231 | /*! |
232 | Returns the option at \a index position. |
233 | */ |
234 | QCoapOption QCoapMessage::optionAt(int index) const |
235 | { |
236 | Q_D(const QCoapMessage); |
237 | return d->options.at(i: index); |
238 | } |
239 | |
240 | /*! |
241 | Finds and returns the first option with the given \a name. |
242 | If there is no such option, returns an invalid QCoapOption with an empty value. |
243 | */ |
244 | QCoapOption QCoapMessage::option(QCoapOption::OptionName name) const |
245 | { |
246 | Q_D(const QCoapMessage); |
247 | |
248 | auto it = d->findOption(name); |
249 | return it != d->options.end() ? *it : QCoapOption(); |
250 | } |
251 | |
252 | /*! |
253 | \internal |
254 | |
255 | Finds and returns a constant iterator to the first option |
256 | with the given \a name. |
257 | If there is no such option, returns \c d->options.end(). |
258 | */ |
259 | QList<QCoapOption>::const_iterator |
260 | QCoapMessagePrivate::findOption(QCoapOption::OptionName name) const |
261 | { |
262 | return std::find_if(first: options.begin(), last: options.end(), pred: [name](const QCoapOption &option) { |
263 | return option.name() == name; |
264 | }); |
265 | } |
266 | |
267 | /*! |
268 | Returns \c true if the message contains at last one option |
269 | with \a name. |
270 | */ |
271 | bool QCoapMessage::hasOption(QCoapOption::OptionName name) const |
272 | { |
273 | Q_D(const QCoapMessage); |
274 | return d->findOption(name) != d->options.end(); |
275 | } |
276 | |
277 | /*! |
278 | Returns the list of options. |
279 | */ |
280 | const QList<QCoapOption> &QCoapMessage::options() const |
281 | { |
282 | Q_D(const QCoapMessage); |
283 | return d->options; |
284 | } |
285 | |
286 | /*! |
287 | Finds and returns the list of options with the given \a name. |
288 | */ |
289 | QList<QCoapOption> QCoapMessage::options(QCoapOption::OptionName name) const |
290 | { |
291 | Q_D(const QCoapMessage); |
292 | |
293 | QList<QCoapOption> result; |
294 | std::copy_if(first: d->options.cbegin(), last: d->options.cend(), result: std::back_inserter(x&: result), |
295 | pred: [name](const QCoapOption &option) { |
296 | return option.name() == name; |
297 | }); |
298 | return result; |
299 | } |
300 | |
301 | /*! |
302 | Returns the number of options. |
303 | */ |
304 | int QCoapMessage::optionCount() const |
305 | { |
306 | Q_D(const QCoapMessage); |
307 | return d->options.size(); |
308 | } |
309 | |
310 | /*! |
311 | Sets the CoAP version to \a version. |
312 | |
313 | \sa version() |
314 | */ |
315 | void QCoapMessage::setVersion(quint8 version) |
316 | { |
317 | Q_D(QCoapMessage); |
318 | d->version = version; |
319 | } |
320 | |
321 | /*! |
322 | Sets the message type to \a type. |
323 | |
324 | \sa type() |
325 | */ |
326 | void QCoapMessage::setType(const Type &type) |
327 | { |
328 | Q_D(QCoapMessage); |
329 | d->type = type; |
330 | } |
331 | |
332 | /*! |
333 | Sets the message token to \a token. |
334 | |
335 | \sa token() |
336 | */ |
337 | void QCoapMessage::setToken(const QByteArray &token) |
338 | { |
339 | Q_D(QCoapMessage); |
340 | d->token = token; |
341 | } |
342 | |
343 | /*! |
344 | Sets the message ID to \a id. |
345 | |
346 | \sa messageId() |
347 | */ |
348 | void QCoapMessage::setMessageId(quint16 id) |
349 | { |
350 | Q_D(QCoapMessage); |
351 | d->messageId = id; |
352 | } |
353 | |
354 | /*! |
355 | Sets the message payload to \a payload. The payload can be represented in |
356 | one of the content formats defined in \l {CoAP Content-Formats Registry}. |
357 | |
358 | \note CoAP supports common content formats such as XML, JSON, and so on, but |
359 | these are text based and consequently heavy both in payload and in processing. |
360 | One of the recommended content formats to use with CoAP is CBOR, which is |
361 | designed to be used in such contexts. |
362 | |
363 | \sa payload(), QCborStreamWriter, QCborStreamReader |
364 | */ |
365 | void QCoapMessage::setPayload(const QByteArray &payload) |
366 | { |
367 | Q_D(QCoapMessage); |
368 | d->payload = payload; |
369 | } |
370 | |
371 | /*! |
372 | Sets the message options to \a options. |
373 | */ |
374 | void QCoapMessage::setOptions(const QList<QCoapOption> &options) |
375 | { |
376 | Q_D(QCoapMessage); |
377 | d->options = options; |
378 | } |
379 | |
380 | void QCoapMessage::swap(QCoapMessage &other) noexcept |
381 | { |
382 | qSwap(value1&: d_ptr, value2&: other.d_ptr); |
383 | } |
384 | |
385 | /*! |
386 | Move-assignment operator. |
387 | */ |
388 | QCoapMessage &QCoapMessage::operator=(QCoapMessage &&other) noexcept |
389 | { |
390 | swap(other); |
391 | return *this; |
392 | } |
393 | |
394 | /*! |
395 | Copies the contents of \a other into this message. |
396 | Returns a reference to this QCoapMessage. |
397 | */ |
398 | QCoapMessage &QCoapMessage::operator=(const QCoapMessage &other) |
399 | { |
400 | d_ptr = other.d_ptr; |
401 | return *this; |
402 | } |
403 | |
404 | /*! |
405 | \internal |
406 | |
407 | For QSharedDataPointer. |
408 | */ |
409 | QCoapMessagePrivate* QCoapMessage::d_func() |
410 | { |
411 | return d_ptr.data(); |
412 | } |
413 | |
414 | /*! |
415 | \variable QCoapMessage::d_ptr |
416 | \internal |
417 | |
418 | Pointer to private data structure. |
419 | */ |
420 | |
421 | QT_END_NAMESPACE |
422 | |