Source code
Revision control
Copy as Markdown
// Copyright (C) 2017 Witekio.
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qcoapreply_p.h"
#include "qcoapinternalreply_p.h"
#include "qcoapnamespace_p.h"
#include <QtCore/qmath.h>
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
/*!
\internal
Constructor.
*/
QCoapReplyPrivate::QCoapReplyPrivate(const QCoapRequest &req) :
request(req)
{
}
/*!
\internal
Marks the reply as running, and sets the \a token and \a messageId of this
exchange.
\sa isRunning()
*/
void QCoapReplyPrivate::_q_setRunning(const QCoapToken &token, QCoapMessageId messageId)
{
request.setToken(token);
request.setMessageId(messageId);
isRunning = true;
}
/*!
\internal
Sets the reply as finished.
*/
void QCoapReplyPrivate::_q_setObserveCancelled()
{
Q_Q(QCoapReply);
bool alreadyFinished = q->isFinished();
isFinished = true;
isRunning = false;
if (!alreadyFinished)
emit q->finished(q);
}
/*!
\internal
Sets the message and response code of this reply, unless reply is
already finished.
*/
void QCoapReplyPrivate::_q_setContent(const QHostAddress &, const QCoapMessage &msg,
QtCoap::ResponseCode code)
{
Q_Q(QCoapReply);
if (q->isFinished())
return;
message = msg;
responseCode = code;
seekBuffer(0);
if (QtCoap::isError(responseCode))
_q_setError(responseCode);
}
/*!
\internal
For an Observe request, notifies that a new message was received
by emitting the notified() signal. If the reply is finished, no
signal will be emitted.
*/
void QCoapReplyPrivate::_q_setNotified()
{
Q_Q(QCoapReply);
if (!q->isFinished())
emit q->notified(q, message);
}
/*!
\internal
Sets the reply as finished, sending the finished() signal if it wasn't
already.
*/
void QCoapReplyPrivate::_q_setFinished(QtCoap::Error newError)
{
Q_Q(QCoapReply);
if (q->isFinished())
return;
isFinished = true;
isRunning = false;
if (newError != QtCoap::Error::Ok)
_q_setError(newError);
emit q->finished(q);
}
/*!
\internal
Sets the error of the reply.
\sa errorReceived()
*/
void QCoapReplyPrivate::_q_setError(QtCoap::Error newError)
{
Q_Q(QCoapReply);
if (error == newError)
return;
error = newError;
emit q->error(q, error);
}
/*!
\internal
Sets the error of the reply.
*/
void QCoapReplyPrivate::_q_setError(QtCoap::ResponseCode code)
{
_q_setError(QtCoap::errorForResponseCode(code));
}
/*!
\class QCoapReply
\inmodule QtCoap
\brief The QCoapReply class holds the data of a CoAP reply.
\reentrant
The QCoapReply contains data related to a request sent with the
QCoapClient.
The finished() signal is emitted when the response is fully
received or when the request fails.
For \e Observe requests specifically, the notified() signal is emitted
whenever a notification is received.
\sa QCoapClient, QCoapRequest, QCoapResourceDiscoveryReply
*/
/*!
\fn void QCoapReply::finished(QCoapReply* reply)
This signal is emitted whenever the corresponding request finished,
whether successfully or not. When a resource is observed, this signal
will only be emitted once, when the observation ends.
The \a reply parameter is the QCoapReply itself for convenience.
\note If the QCoapReply is deleted while not finished, both aborted() and
finished() signal will be emitted immediately before the QCoapReply is
destroyed. Given the QCoapReply may have been deleted when receiving the
signal, you should not rely on the \a reply to be still valid.
\sa QCoapClient::finished(), isFinished(), notified(), aborted()
*/
/*!
\fn void QCoapReply::notified(QCoapReply* reply, const QCoapMessage &message)
This signal is emitted whenever a notification is received from an observed
resource.
Its \a message parameter is a QCoapMessage containing the payload and the
message details. The \a reply parameter is the QCoapReply itself for
convenience.
\sa QCoapClient::finished(), isFinished(), finished(), aborted()
*/
/*!
\fn void QCoapReply::error(QCoapReply* reply, QtCoap::Error error)
This signal is emitted whenever an error occurs and is followed by the
finished() signal.
Its \a reply parameters is the QCoapReply itself for convenience, and
the \a error parameter is the error received.
\sa finished(), aborted()
*/
/*!
\fn void QCoapReply::aborted(const QCoapToken &token);
This signal is emitted when the request is aborted or the reply is deleted.
Its \a token parameter is the token of the exchange that has been aborted.
\note If the QCoapReply is deleted while not finished, both aborted() and
finished() signal will be emitted immediately before the QCoapReply is
destroyed. Given the QCoapReply may have been deleted when receiving the
signal, you should not rely on the sender() object to be still valid.
\sa finished(), error()
*/
/*!
\internal
Constructs a new CoAP reply with \a dd as the d_ptr.
This constructor must be used when subclassing internally
the QCoapReply class.
*/
QCoapReply::QCoapReply(QCoapReplyPrivate &dd, QObject *parent) :
QIODevice(dd, parent)
{
open(QIODevice::ReadOnly);
}
/*!
Destroys the QCoapReply and aborts the request if its response has
not yet been received.
*/
QCoapReply::~QCoapReply()
{
abortRequest();
}
/*!
\internal
\overload
*/
qint64 QCoapReply::readData(char *data, qint64 maxSize)
{
Q_D(QCoapReply);
QByteArray payload = d->message.payload();
maxSize = qMin(maxSize, qint64(payload.size()) - pos());
if (maxSize <= 0)
return qint64(0);
// Explicitly account for platform size_t limitations
size_t len = static_cast<size_t>(maxSize);
if (sizeof(qint64) > sizeof(size_t)
&& maxSize > static_cast<qint64>(std::numeric_limits<size_t>::max())) {
qCWarning(lcCoapExchange) << "Cannot read more than"
<< std::numeric_limits<size_t>::max()
<< "at a time";
len = std::numeric_limits<size_t>::max();
}
memcpy(data, payload.constData() + pos(), len);
return static_cast<qint64>(len);
}
/*!
\internal
\overload
*/
qint64 QCoapReply::writeData(const char *data, qint64 maxSize)
{
// The user cannot write to the reply
Q_UNUSED(data);
Q_UNUSED(maxSize);
return -1;
}
/*!
Returns the response code of the request.
*/
QtCoap::ResponseCode QCoapReply::responseCode() const
{
Q_D(const QCoapReply);
return d->responseCode;
}
/*!
Returns the contained message.
*/
QCoapMessage QCoapReply::message() const
{
Q_D(const QCoapReply);
return d->message;
}
/*!
Returns the associated request.
*/
QCoapRequest QCoapReply::request() const
{
Q_D(const QCoapReply);
return d->request;
}
/*!
Returns \c true if the request is finished.
\sa finished()
*/
bool QCoapReply::isFinished() const
{
Q_D(const QCoapReply);
return d->isFinished || d->isAborted;
}
/*!
Returns \c true if the request is running.
*/
bool QCoapReply::isRunning() const
{
Q_D(const QCoapReply);
return d->isRunning && !isFinished();
}
/*!
Returns \c true if the request has been aborted.
*/
bool QCoapReply::isAborted() const
{
Q_D(const QCoapReply);
return d->isAborted;
}
/*!
Returns \c true if the request finished with no error.
*/
bool QCoapReply::isSuccessful() const
{
Q_D(const QCoapReply);
return d->isFinished && !QtCoap::isError(d->responseCode)
&& d->error == QtCoap::Error::Ok;
}
/*!
Returns the target uri of the associated request.
*/
QUrl QCoapReply::url() const
{
Q_D(const QCoapReply);
return d->request.url();
}
/*!
Returns the method of the associated request.
*/
QtCoap::Method QCoapReply::method() const
{
Q_D(const QCoapReply);
return d->request.method();
}
/*!
Returns the error of the reply or QCoapReply::NoError if there is no error.
*/
QtCoap::Error QCoapReply::errorReceived() const
{
Q_D(const QCoapReply);
return d->error;
}
/*!
Aborts the request immediately and emits the
\l{QCoapReply::aborted(const QCoapToken &token)}{aborted(const QCoapToken &token)}
signal if the request was not finished.
*/
void QCoapReply::abortRequest()
{
Q_D(QCoapReply);
if (isFinished())
return;
d->isAborted = true;
d->isFinished = true;
d->isRunning = false;
emit aborted(request().token());
emit finished(this);
}
/*!
\internal
Creates a new instance of QCoapReply and returns a pointer to it.
*/
QCoapReply *QCoapReplyPrivate::createCoapReply(const QCoapRequest &request, QObject *parent)
{
return new QCoapReply(*new QCoapReplyPrivate(request), parent);
}
QT_END_NAMESPACE
#include "moc_qcoapreply.cpp"