Merge PR #531: Some fixes in Coap
This commit is contained in:
commit
48d5a182c6
@ -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()
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user