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
7QT_BEGIN_NAMESPACE
8
9QCoapMessagePrivate::QCoapMessagePrivate(QCoapMessage::Type _type) :
10 type(_type)
11{
12}
13
14QCoapMessagePrivate::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
21QCoapMessagePrivate::~QCoapMessagePrivate()
22{
23}
24
25QCoapMessagePrivate *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*/
74QCoapMessage::QCoapMessage() :
75 d_ptr(new QCoapMessagePrivate)
76{
77}
78
79/*!
80 Destroys the QCoapMessage.
81*/
82QCoapMessage::~QCoapMessage()
83{
84}
85
86/*!
87 Constructs a shallow copy of \a other.
88*/
89QCoapMessage::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*/
100QCoapMessage::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*/
110void 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*/
119void 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*/
136void 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*/
146void 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*/
161void QCoapMessage::clearOptions()
162{
163 Q_D(QCoapMessage);
164 d->options.clear();
165}
166
167/*!
168 Returns the CoAP version.
169
170 \sa setVersion()
171*/
172quint8 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*/
183QCoapMessage::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*/
194QByteArray QCoapMessage::token() const
195{
196 Q_D(const QCoapMessage);
197 return d->token;
198}
199
200/*!
201 Returns the token length.
202*/
203quint8 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*/
214quint16 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*/
225QByteArray 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*/
234QCoapOption 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*/
244QCoapOption 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*/
259QList<QCoapOption>::const_iterator
260QCoapMessagePrivate::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*/
271bool 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*/
280const 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*/
289QList<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*/
304int 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*/
315void 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*/
326void 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*/
337void 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*/
348void 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*/
365void 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*/
374void QCoapMessage::setOptions(const QList<QCoapOption> &options)
375{
376 Q_D(QCoapMessage);
377 d->options = options;
378}
379
380void QCoapMessage::swap(QCoapMessage &other) noexcept
381{
382 qSwap(value1&: d_ptr, value2&: other.d_ptr);
383}
384
385/*!
386 Move-assignment operator.
387 */
388QCoapMessage &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 */
398QCoapMessage &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*/
409QCoapMessagePrivate* 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
421QT_END_NAMESPACE
422

source code of qtcoap/src/coap/qcoapmessage.cpp