Merge PR #531: Some fixes in Coap

This commit is contained in:
jenkins 2022-06-30 15:04:35 +02:00
commit 48d5a182c6
4 changed files with 89 additions and 55 deletions

View File

@ -801,16 +801,15 @@ void Coap::hostLookupFinished(const QHostInfo &hostInfo)
void Coap::onReadyRead() void Coap::onReadyRead()
{ {
QHostAddress hostAddress; QHostAddress hostAddress;
QByteArray data;
quint16 port; quint16 port;
while (m_socket->hasPendingDatagrams()) { while (m_socket->hasPendingDatagrams()) {
data.resize(m_socket->pendingDatagramSize()); QByteArray datagram(m_socket->pendingDatagramSize(), 0);
m_socket->readDatagram(data.data(), data.size(), &hostAddress, &port); m_socket->readDatagram(datagram.data(), datagram.size(), &hostAddress, &port);
qCDebug(dcCoap()) << "Datagram received from:" << hostAddress << ":" << datagram;
CoapPdu pdu(datagram);
processResponse(pdu, hostAddress, port);
} }
CoapPdu pdu(data);
processResponse(pdu, hostAddress, port);
} }
void Coap::onReplyTimeout() void Coap::onReplyTimeout()

View File

@ -163,6 +163,10 @@
#include <QMetaEnum> #include <QMetaEnum>
#include <QTime> #include <QTime>
#include <QLoggingCategory>
#include <QDataStream>
Q_DECLARE_LOGGING_CATEGORY(dcCoap)
/*! Constructs a CoapPdu with the given \a parent. */ /*! Constructs a CoapPdu with the given \a parent. */
CoapPdu::CoapPdu(QObject *parent) : CoapPdu::CoapPdu(QObject *parent) :
@ -370,7 +374,7 @@ void CoapPdu::addOption(const CoapOption::Option &option, const QByteArray &data
CoapOption o; CoapOption o;
o.setOption(option); o.setOption(option);
o.setData(data); o.setData(data);
m_options.insert(index + 1, o); m_options.insert(qMin(m_options.length(), index + 1), o);
} }
/*! Returns the block of this \l{CoapPdu}. */ /*! Returns the block of this \l{CoapPdu}. */
@ -504,70 +508,97 @@ QByteArray CoapPdu::pack() const
void CoapPdu::unpack(const QByteArray &data) void CoapPdu::unpack(const QByteArray &data)
{ {
// create a CoapPDU
if (data.length() < 4) { if (data.length() < 4) {
m_error = InvalidPduSizeError; m_error = InvalidPduSizeError;
} }
quint8 *rawData = (quint8 *)data.data(); QDataStream stream(data);
setVersion((rawData[0] & 0xc0) >> 6); quint8 flags;
setMessageType(static_cast<MessageType>((rawData[0] & 0x30) >> 4)); stream >> flags;
quint8 tokenLength = (rawData[0] & 0xf);
setVersion((flags & 0xc0) >> 6);
// qCDebug(dcCoap()) << "Version:" << m_version;
setMessageType(static_cast<MessageType>((flags & 0x30) >> 4));
// qCDebug(dcCoap()) << "Message Type:" << messageType();
quint8 tokenLength = flags & 0x0f;
// qCDebug(dcCoap()) << "Token length:" << tokenLength;
if (tokenLength > 8) { if (tokenLength > 8) {
qCWarning(dcCoap()) << "Inavalid token length" << tokenLength;
m_error = InvalidTokenError; m_error = InvalidTokenError;
return;
} }
setToken(QByteArray((const char *)rawData + 4, tokenLength)); quint8 reqRspCode;
setStatusCode(static_cast<StatusCode>(rawData[1])); stream >> reqRspCode;
setMessageId((qint16)data.mid(2,2).toHex().toUInt(0,16)); setStatusCode(static_cast<StatusCode>(reqRspCode));
// qCDebug(dcCoap()) << "Req/Rsp code:" << statusCode();
// parse options quint16 messageId;
int index = 4 + tokenLength; stream >> messageId;
quint8 optionByte = rawData[index]; setMessageId(messageId);
quint16 delta = 0; // qCDebug(dcCoap()) << "Message ID:" << messageId;
while (QByteArray::number(optionByte, 16) != "ff" && optionByte != 0) { char tokenData[tokenLength];
quint16 optionNumber = ((optionByte & 0xf0) >> 4); if (stream.readRawData(tokenData, tokenLength) != tokenLength) {
qCWarning(dcCoap()) << "Token data not complete.";
m_error = InvalidTokenError;
return;
}
QByteArray token(tokenData, tokenLength);
setToken(token);
// qCDebug(dcCoap()) << "Token:" << token.toHex();
// check option delta
if (optionNumber < 13) { while (!stream.atEnd()) {
delta += optionNumber; quint8 optionByte;
} else if (optionNumber == 13) { stream >> optionByte;
// extended 8 bit option delta // qCDebug(dcCoap()) << "OptionByte:" << optionByte;
delta += (quint8)(rawData[index + 1] + 13);
index += 1; if (optionByte == 0xff) {
} else if (optionNumber == 14) { char payloadData[65507]; // Max UDP datagram size
// extended 16 bit option delta int payloadLength = stream.readRawData(payloadData, 65507);
delta += ((rawData[index + 1] << 8) | rawData[index + 2]) + 269; if (payloadLength > 0) {
index += 2; setPayload(QByteArray(payloadData, payloadLength));
} else if (optionNumber == 15) { }
m_error = InvalidOptionDeltaError; return;
}
quint16 optionDelta;
optionDelta = (optionByte & 0xf0) >> 4;
// qCDebug(dcCoap()) << "Option delta:" << optionDelta;
quint16 optionLength = (optionByte & 0x0f);
// qCDebug(dcCoap()) << "Option length:" << optionLength;
if (optionDelta == 13) {
quint8 optionDeltaExtended;
stream >> optionDeltaExtended;
optionDelta = optionDeltaExtended + 13;
// qCDebug(dcCoap()).nospace() << "Extended option delta (8 bit): " << optionDelta << " (" << optionDeltaExtended << " + 13)";
} else if (optionDelta == 14) {
quint16 optionDeltaExtended;
stream >> optionDeltaExtended;
optionDelta = optionDeltaExtended + 269;
// qCDebug(dcCoap()).nospace() << "Extended option delta (16 bit): " << optionDelta << " (" << optionDeltaExtended << " + 269)";
} }
// check option length
quint16 optionLength = (optionByte & 0xf);
if (optionLength == 13) { if (optionLength == 13) {
// extended 8 bit option length quint8 optionLengthExtended;
optionLength = (quint8)(rawData[index + 1] - 13); stream >> optionLengthExtended;
index += 1; optionLength = optionLengthExtended + 13;
// qCDebug(dcCoap()).nospace() << "Extended option length (8 bit): " << optionLength << " (" << optionLengthExtended << " + 13)";
} else if (optionLength == 14) { } else if (optionLength == 14) {
// extended 16 bit option delta quint16 optionLengthExtended;
optionLength = ((rawData[index + 1] << 8) | rawData[index + 2]) - 269; stream >> optionLengthExtended;
index += 2; optionLength = optionLengthExtended + 269;
} else if (optionLength == 15) { // qCDebug(dcCoap()).nospace() << "Extended option kength (16 bit): " << optionDelta << " (" << optionLengthExtended << " + 269)";
m_error = InvalidOptionLengthError;
} }
QByteArray optionData = QByteArray((const char *)rawData + index + 1, optionLength); char optionData[optionLength];
addOption(static_cast<CoapOption::Option>(delta), optionData); stream.readRawData(optionData, optionLength);
// qCDebug(dcCoap()) << "Option data:" << QByteArray(optionData, optionLength);
index += optionLength + 1; addOption(static_cast<CoapOption::Option>(optionDelta), QByteArray(optionData, optionLength));
optionByte = rawData[index];
if (QByteArray::number(optionByte, 16) == "ff") {
setPayload(data.right(data.length() - index - 1));
break;
}
} }
} }

View File

@ -68,6 +68,7 @@ public:
Acknowledgement = 0x02, Acknowledgement = 0x02,
Reset = 0x03 Reset = 0x03
}; };
Q_ENUM(MessageType)
// Methods: https://tools.ietf.org/html/rfc7252#section-5.8 // Methods: https://tools.ietf.org/html/rfc7252#section-5.8
// Respond codes: https://tools.ietf.org/html/rfc7252#section-12.1.2 // Respond codes: https://tools.ietf.org/html/rfc7252#section-12.1.2
@ -101,6 +102,7 @@ public:
GatewayTimeout = 0xa4, // 5.04 GatewayTimeout = 0xa4, // 5.04
ProxyingNotSupported = 0xa5 // 5.05 ProxyingNotSupported = 0xa5 // 5.05
}; };
Q_ENUM(StatusCode)
// https://tools.ietf.org/html/rfc7252#section-12.3 // https://tools.ietf.org/html/rfc7252#section-12.3
enum ContentType { enum ContentType {
@ -111,6 +113,7 @@ public:
ApplicationExi = 47, ApplicationExi = 47,
ApplicationJson = 50 ApplicationJson = 50
}; };
Q_ENUM(ContentType)
enum Error { enum Error {
NoError, NoError,
@ -120,6 +123,7 @@ public:
InvalidOptionLengthError, InvalidOptionLengthError,
UnknownOptionError UnknownOptionError
}; };
Q_ENUM(Error)
CoapPdu(QObject *parent = 0); CoapPdu(QObject *parent = 0);
CoapPdu(const QByteArray &data, QObject *parent = 0); CoapPdu(const QByteArray &data, QObject *parent = 0);

View File

@ -132,8 +132,8 @@ private:
int m_messageId; int m_messageId;
QByteArray m_messageToken; QByteArray m_messageToken;
bool m_observation; bool m_observation = false;
bool m_observationEnable; bool m_observationEnable = false;
signals: signals:
void timeout(); void timeout();