compile mqtt module passed on linux

mqttclient compile pass, log and ssl config off
This commit is contained in:
lyon 2022-11-12 00:31:10 +08:00
parent f506721544
commit 8c96721a55
88 changed files with 10972 additions and 3 deletions

148
package/mqtt/MQTTConnect.h Normal file
View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2014, 2017 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - add connack return code definitions
* Xiang Rong - 442039 Add makefile to Embedded C client
* Ian Craggs - fix for issue #64, bit order in connack response
*******************************************************************************/
#ifndef MQTTCONNECT_H_
#define MQTTCONNECT_H_
enum connack_return_codes
{
MQTT_CONNECTION_ACCEPTED = 0,
MQTT_UNNACCEPTABLE_PROTOCOL = 1,
MQTT_CLIENTID_REJECTED = 2,
MQTT_SERVER_UNAVAILABLE = 3,
MQTT_BAD_USERNAME_OR_PASSWORD = 4,
MQTT_NOT_AUTHORIZED = 5,
};
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
typedef union
{
unsigned char all; /**< all connect flags */
#if defined(REVERSED)
struct
{
unsigned int username : 1; /**< 3.1 user name */
unsigned int password : 1; /**< 3.1 password */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
#else
struct
{
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
#endif
} MQTTConnectFlags; /**< connect flags byte */
/**
* Defines the MQTT "Last Will and Testament" (LWT) settings for
* the connect packet.
*/
typedef struct
{
/** The eyecatcher for this structure. must be MQTW. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** The LWT topic to which the LWT message will be published. */
MQTTString topicName;
/** The LWT payload. */
MQTTString message;
/**
* The retained flag for the LWT message (see MQTTAsync_message.retained).
*/
unsigned char retained;
/**
* The quality of service setting for the LWT message (see
* MQTTAsync_message.qos and @ref qos).
*/
char qos;
} MQTTPacket_willOptions;
#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
typedef struct
{
/** The eyecatcher for this structure. must be MQTC. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
*/
unsigned char MQTTVersion;
MQTTString clientID;
unsigned short keepAliveInterval;
unsigned char cleansession;
unsigned char willFlag;
MQTTPacket_willOptions will;
MQTTString username;
MQTTString password;
} MQTTPacket_connectData;
typedef union
{
unsigned char all; /**< all connack flags */
#if defined(REVERSED)
struct
{
unsigned int reserved : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
#else
struct
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int reserved: 7; /**< unused */
} bits;
#endif
} MQTTConnackFlags; /**< connack flags byte */
#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
#endif /* MQTTCONNECT_H_ */

View File

@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
{
int len = 0;
FUNC_ENTRY;
if (options->MQTTVersion == 3)
len = 12; /* variable depending on MQTT or MQIsdp */
else if (options->MQTTVersion == 4)
len = 10;
len += MQTTstrlen(options->clientID)+2;
if (options->willFlag)
len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
if (options->username.cstring || options->username.lenstring.data)
len += MQTTstrlen(options->username)+2;
if (options->password.cstring || options->password.lenstring.data)
len += MQTTstrlen(options->password)+2;
FUNC_EXIT_RC(len);
return len;
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @return serialized length, or error if 0
*/
int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
int len = 0;
int rc = -1;
FUNC_ENTRY;
if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNECT;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
if (options->MQTTVersion == 4)
{
writeCString(&ptr, "MQTT");
writeChar(&ptr, (char) 4);
}
else
{
writeCString(&ptr, "MQIsdp");
writeChar(&ptr, (char) 3);
}
flags.all = 0;
flags.bits.cleansession = options->cleansession;
flags.bits.will = (options->willFlag) ? 1 : 0;
if (flags.bits.will)
{
flags.bits.willQoS = options->will.qos;
flags.bits.willRetain = options->will.retained;
}
if (options->username.cstring || options->username.lenstring.data)
flags.bits.username = 1;
if (options->password.cstring || options->password.lenstring.data)
flags.bits.password = 1;
writeChar(&ptr, flags.all);
writeInt(&ptr, options->keepAliveInterval);
writeMQTTString(&ptr, options->clientID);
if (options->willFlag)
{
writeMQTTString(&ptr, options->will.topicName);
writeMQTTString(&ptr, options->will.message);
}
if (flags.bits.username)
writeMQTTString(&ptr, options->username);
if (flags.bits.password)
writeMQTTString(&ptr, options->password);
rc = ptr - buf;
exit: FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
flags.all = readChar(&curdata);
*sessionPresent = flags.bits.sessionpresent;
*connack_rc = readChar(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @return serialized length, or error if 0
*/
int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = packettype;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, DISCONNECT);
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, PINGREQ);
}

View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? a : b)
/**
* Validates MQTT protocol name and version combinations
* @param protocol the MQTT protocol name as an MQTTString
* @param version the MQTT protocol version number, as in the connect packet
* @return correct MQTT combination? 1 is true, 0 is false
*/
int MQTTPacket_checkVersion(MQTTString* protocol, int version)
{
int rc = 0;
if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
min(6, protocol->lenstring.len)) == 0)
rc = 1;
else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
min(4, protocol->lenstring.len)) == 0)
rc = 1;
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connect data structure
* @param data the connect data structure to be filled out
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
{
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
unsigned char* curdata = buf;
unsigned char* enddata = &buf[len];
int rc = 0;
MQTTString Protocol;
int version;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNECT)
goto exit;
curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
version = (int)readChar(&curdata); /* Protocol version */
/* If we don't recognize the protocol version, we don't parse the connect packet on the
* basis that we don't know what the format will be.
*/
if (MQTTPacket_checkVersion(&Protocol, version))
{
flags.all = readChar(&curdata);
data->cleansession = flags.bits.cleansession;
data->keepAliveInterval = readInt(&curdata);
if (!readMQTTLenString(&data->clientID, &curdata, enddata))
goto exit;
data->willFlag = flags.bits.will;
if (flags.bits.will)
{
data->will.qos = flags.bits.willQoS;
data->will.retained = flags.bits.willRetain;
if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
!readMQTTLenString(&data->will.message, &curdata, enddata))
goto exit;
}
if (flags.bits.username)
{
if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
goto exit; /* username flag set, but no username supplied - invalid */
if (flags.bits.password &&
(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
goto exit; /* password flag set, but no password supplied - invalid */
}
else if (flags.bits.password)
goto exit; /* password flag set without username - invalid */
rc = 1;
}
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the connack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param connack_rc the integer connack return code to be used
* @param sessionPresent the MQTT 3.1.1 sessionPresent flag
* @return serialized length, or error if 0
*/
int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
flags.all = 0;
flags.bits.sessionpresent = sessionPresent;
writeChar(&ptr, flags.all);
writeChar(&ptr, connack_rc);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? 1 : 0)
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned integer - the MQTT dup flag
* @param qos returned integer - the MQTT QoS value
* @param retained returned integer - the MQTT retained flag
* @param packetid returned integer - the MQTT packet identifier
* @param topicName returned MQTTString - the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned integer - the length of the MQTT payload
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success
*/
int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != PUBLISH)
goto exit;
*dup = header.bits.dup;
*qos = header.bits.qos;
*retained = header.bits.retain;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (!readMQTTLenString(topicName, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
if (*qos > 0)
*packetid = readInt(&curdata);
*payloadlen = enddata - curdata;
*payload = curdata;
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into an ack
* @param packettype returned integer - the MQTT packet type
* @param dup returned integer - the MQTT dup flag
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
*dup = header.bits.dup;
*packettype = header.bits.type;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

262
package/mqtt/MQTTFormat.c Normal file
View File

@ -0,0 +1,262 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
const char* MQTTPacket_names[] =
{
"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
"PINGREQ", "PINGRESP", "DISCONNECT"
};
const char* MQTTPacket_getName(unsigned short packetid)
{
return MQTTPacket_names[packetid];
}
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
{
int strindex = 0;
strindex = snprintf(strbuf, strbuflen,
"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
(int)data->cleansession, data->keepAliveInterval);
if (data->willFlag)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
data->will.qos, data->will.retained,
data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
data->will.message.lenstring.len, data->will.message.lenstring.data);
if (data->username.lenstring.data && data->username.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
if (data->password.lenstring.data && data->password.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
return strindex;
}
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
{
int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
return strindex;
}
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
{
int strindex = snprintf(strbuf, strbuflen,
"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
dup, qos, retained, packetid,
(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
return strindex;
}
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
if (dup)
strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
return strindex;
}
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
return snprintf(strbuf, strbuflen,
"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
requestedQoSs[0]);
}
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
{
return snprintf(strbuf, strbuflen,
"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
}
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
return snprintf(strbuf, strbuflen,
"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
}
#if defined(MQTT_CLIENT)
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
int strindex = 0;
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNACK:
{
unsigned char sessionPresent, connack_rc;
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBACK:
{
unsigned short packetid;
int maxcount = 1, count = 0;
int grantedQoSs[1];
if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
}
break;
case UNSUBACK:
{
unsigned short packetid;
if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
return strbuf;
}
#endif
#if defined(MQTT_SERVER)
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
int strindex = 0;
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNECT:
{
MQTTPacket_connectData data;
int rc;
if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
int requestedQoSs[1];
if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
topicFilters, requestedQoSs, buf, buflen) == 1)
strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
}
break;
case UNSUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
strindex = MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
strbuf[strbuflen] = '\0';
return strbuf;
}
#endif

37
package/mqtt/MQTTFormat.h Normal file
View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#if !defined(MQTTFORMAT_H)
#define MQTTFORMAT_H
#include "StackTrace.h"
#include "MQTTPacket.h"
const char* MQTTPacket_getName(unsigned short packetid);
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[]);
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
#endif

412
package/mqtt/MQTTPacket.c Normal file
View File

@ -0,0 +1,412 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Sergio R. Caprile - non-blocking packet read functions for stream transport
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
/**
* Encodes the message length according to the MQTT algorithm
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
* @return the number of bytes written to buffer
*/
int MQTTPacket_encode(unsigned char* buf, int length)
{
int rc = 0;
FUNC_ENTRY;
do
{
char d = length % 128;
length /= 128;
/* if there are more digits to encode, set the top bit of this digit */
if (length > 0)
d |= 0x80;
buf[rc++] = d;
} while (length > 0);
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm
* @param getcharfn pointer to function to read the next character from the data source
* @param value the decoded length returned
* @return the number of bytes read from the socket
*/
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
{
unsigned char c;
int multiplier = 1;
int len = 0;
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
FUNC_ENTRY;
*value = 0;
do
{
int rc = MQTTPACKET_READ_ERROR;
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
{
rc = MQTTPACKET_READ_ERROR; /* bad data */
goto exit;
}
rc = (*getcharfn)(&c, 1);
if (rc != 1)
goto exit;
*value += (c & 127) * multiplier;
multiplier *= 128;
} while ((c & 128) != 0);
exit:
FUNC_EXIT_RC(len);
return len;
}
int MQTTPacket_len(int rem_len)
{
rem_len += 1; /* header byte */
/* now remaining_length field */
if (rem_len < 128)
rem_len += 1;
else if (rem_len < 16384)
rem_len += 2;
else if (rem_len < 2097151)
rem_len += 3;
else
rem_len += 4;
return rem_len;
}
static unsigned char* bufptr;
int bufchar(unsigned char* c, int count)
{
int i;
for (i = 0; i < count; ++i)
*c = *bufptr++;
return count;
}
int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
{
bufptr = buf;
return MQTTPacket_decode(bufchar, value);
}
/**
* Calculates an integer from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the integer value calculated
*/
int readInt(unsigned char** pptr)
{
unsigned char* ptr = *pptr;
int len = 256*(*ptr) + (*(ptr+1));
*pptr += 2;
return len;
}
/**
* Reads one character from the input buffer.
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
char readChar(unsigned char** pptr)
{
char c = **pptr;
(*pptr)++;
return c;
}
/**
* Writes one character to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
void writeChar(unsigned char** pptr, char c)
{
**pptr = c;
(*pptr)++;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writeInt(unsigned char** pptr, int anInt)
{
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param string the C string to write
*/
void writeCString(unsigned char** pptr, const char* string)
{
int len = strlen(string);
writeInt(pptr, len);
memcpy(*pptr, string, len);
*pptr += len;
}
int getLenStringLen(char* ptr)
{
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
return len;
}
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
{
if (mqttstring.lenstring.len > 0)
{
writeInt(pptr, mqttstring.lenstring.len);
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
*pptr += mqttstring.lenstring.len;
}
else if (mqttstring.cstring)
writeCString(pptr, mqttstring.cstring);
else
writeInt(pptr, 0);
}
/**
* @param mqttstring the MQTTString structure into which the data is to be read
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return 1 if successful, 0 if not
*/
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
{
int rc = 0;
FUNC_ENTRY;
/* the first two bytes are the length of the string */
if (enddata - (*pptr) > 1) /* enough length to read the integer? */
{
mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
{
mqttstring->lenstring.data = (char*)*pptr;
*pptr += mqttstring->lenstring.len;
rc = 1;
}
}
mqttstring->cstring = NULL;
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
* @param mqttstring the string to return the length of
* @return the length of the string
*/
int MQTTstrlen(MQTTString mqttstring)
{
int rc = 0;
if (mqttstring.cstring)
rc = strlen(mqttstring.cstring);
else
rc = mqttstring.lenstring.len;
return rc;
}
/**
* Compares an MQTTString to a C string
* @param a the MQTTString to compare
* @param bptr the C string to compare
* @return boolean - equal or not
*/
int MQTTPacket_equals(MQTTString* a, char* bptr)
{
int alen = 0,
blen = 0;
char *aptr;
if (a->cstring)
{
aptr = a->cstring;
alen = strlen(a->cstring);
}
else
{
aptr = a->lenstring.data;
alen = a->lenstring.len;
}
blen = strlen(bptr);
return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
}
/**
* Helper function to read packet data from some source into a buffer
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param getfn pointer to a function which will read any number of bytes from the needed source
* @return integer MQTT packet type, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
{
int rc = -1;
MQTTHeader header = {0};
int len = 0;
int rem_len = 0;
/* 1. read the header byte. This has the packet type in it */
if ((*getfn)(buf, 1) != 1)
goto exit;
len = 1;
/* 2. read the remaining length. This is variable in itself */
MQTTPacket_decode(getfn, &rem_len);
len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
if((rem_len + len) > buflen)
goto exit;
if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
goto exit;
header.byte = buf[0];
rc = header.bits.type;
exit:
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm, non-blocking
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @param value the decoded length returned
* @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
*/
static int MQTTPacket_decodenb(MQTTTransport *trp)
{
unsigned char c;
int rc = MQTTPACKET_READ_ERROR;
FUNC_ENTRY;
if(trp->len == 0){ /* initialize on first call */
trp->multiplier = 1;
trp->rem_len = 0;
}
do {
int frc;
if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
goto exit;
if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
goto exit;
if (frc == 0){
rc = 0;
goto exit;
}
++(trp->len);
trp->rem_len += (c & 127) * trp->multiplier;
trp->multiplier *= 128;
} while ((c & 128) != 0);
rc = trp->len;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Helper function to read packet data from some source into a buffer, non-blocking
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @return integer MQTT packet type, 0 for call again, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
{
int rc = -1, frc;
MQTTHeader header = {0};
switch(trp->state){
default:
trp->state = 0;
/*FALLTHROUGH*/
case 0:
/* read the header byte. This has the packet type in it */
if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->len = 0;
++trp->state;
/*FALLTHROUGH*/
/* read the remaining length. This is variable in itself */
case 1:
if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
goto exit;
if(frc == 0)
return 0;
trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
if((trp->rem_len + trp->len) > buflen)
goto exit;
++trp->state;
/*FALLTHROUGH*/
case 2:
if(trp->rem_len){
/* read the rest of the buffer using a callback to supply the rest of the data */
if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->rem_len -= frc;
trp->len += frc;
if(trp->rem_len)
return 0;
}
header.byte = buf[0];
rc = header.bits.type;
break;
}
exit:
trp->state = 0;
return rc;
}

133
package/mqtt/MQTTPacket.h Normal file
View File

@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPACKET_H_
#define MQTTPACKET_H_
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#if defined(WIN32_DLL) || defined(WIN64_DLL)
#define DLLImport __declspec(dllimport)
#define DLLExport __declspec(dllexport)
#elif defined(LINUX_SO)
#define DLLImport extern
#define DLLExport __attribute__ ((visibility ("default")))
#else
#define DLLImport
#define DLLExport
#endif
enum errors
{
MQTTPACKET_BUFFER_TOO_SHORT = -2,
MQTTPACKET_READ_ERROR = -1,
MQTTPACKET_READ_COMPLETE
};
enum msgTypes
{
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
PINGREQ, PINGRESP, DISCONNECT
};
/**
* Bitfields for the MQTT header byte.
*/
typedef union
{
unsigned char byte; /**< the whole byte */
#if defined(REVERSED)
struct
{
unsigned int type : 4; /**< message type nibble */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int retain : 1; /**< retained flag bit */
} bits;
#else
struct
{
unsigned int retain : 1; /**< retained flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int type : 4; /**< message type nibble */
} bits;
#endif
} MQTTHeader;
typedef struct
{
int len;
char* data;
} MQTTLenString;
typedef struct
{
char* cstring;
MQTTLenString lenstring;
} MQTTString;
#define MQTTString_initializer {NULL, {0, NULL}}
int MQTTstrlen(MQTTString mqttstring);
#include "MQTTConnect.h"
#include "MQTTPublish.h"
#include "MQTTSubscribe.h"
#include "MQTTUnsubscribe.h"
#include "MQTTFormat.h"
DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
int MQTTPacket_len(int rem_len);
DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
int readInt(unsigned char** pptr);
char readChar(unsigned char** pptr);
void writeChar(unsigned char** pptr, char c);
void writeInt(unsigned char** pptr, int anInt);
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
void writeCString(unsigned char** pptr, const char* string);
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
typedef struct {
int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
void *sck; /* pointer to whatever the system may use to identify the transport */
int multiplier;
int rem_len;
int len;
char state;
}MQTTTransport;
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
#endif /* MQTTPACKET_H_ */

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPUBLISH_H_
#define MQTTPUBLISH_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen);
DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
#endif /* MQTTPUBLISH_H_ */

View File

@ -0,0 +1,169 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
* @param topicName the topic name to be used in the publish
* @param payloadlen the length of the payload to be sent
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
{
int len = 0;
len += 2 + MQTTstrlen(topicName) + payloadlen;
if (qos > 0)
len += 2; /* packetid */
return len;
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param qos integer - the MQTT QoS value
* @param retained integer - the MQTT retained flag
* @param packetid integer - the MQTT packet identifier
* @param topicName MQTTString - the MQTT topic in the publish
* @param payload byte buffer - the MQTT publish payload
* @param payloadlen integer - the length of the MQTT payload
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = PUBLISH;
header.bits.dup = dup;
header.bits.qos = qos;
header.bits.retain = retained;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeMQTTString(&ptr, topicName);
if (qos > 0)
writeInt(&ptr, packetid);
memcpy(ptr, payload, payloadlen);
ptr += payloadlen;
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the ack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param type the MQTT packet type
* @param dup the MQTT dup flag
* @param packetid the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 4)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = packettype;
header.bits.dup = dup;
header.bits.qos = (packettype == PUBREL) ? 1 : 0;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a puback packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
}

View File

@ -0,0 +1,46 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 20:15:32
* @LastEditTime: 2019-12-20 20:37:31
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTSUBSCRIBE_H_
#define MQTTSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[], int requestedQoSs[]);
DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
#endif /* MQTTSUBSCRIBE_H_ */

View File

@ -0,0 +1,137 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
return len;
}
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied bufferr
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters and reqQos arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
{
writeMQTTString(&ptr, topicFilters[i]);
writeChar(&ptr, requestedQoSs[i]);
}
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into suback data
* @param packetid returned integer - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the grantedQoSs array
* @param count returned integer - number of members in the grantedQoSs array
* @param grantedQoSs returned array of integers - the granted qualities of service
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (*count > maxcount)
{
rc = -1;
goto exit;
}
grantedQoSs[(*count)++] = readChar(&curdata);
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,112 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into subscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
int requestedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = -1;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
goto exit;
requestedQoSs[*count] = readChar(&curdata);
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied suback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the grantedQoSs array
* @param grantedQoSs - array of granted QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
int i;
FUNC_ENTRY;
if (buflen < 2 + count)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeChar(&ptr, grantedQoSs[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTUNSUBSCRIBE_H_
#define MQTTUNSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
unsigned char* buf, int len);
DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
#endif /* MQTTUNSUBSCRIBE_H_ */

View File

@ -0,0 +1,106 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
return len;
}
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param topicFilters - array of topic filter names
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = -1;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeMQTTString(&ptr, topicFilters[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into unsuback data
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
{
unsigned char type = 0;
unsigned char dup = 0;
int rc = 0;
FUNC_ENTRY;
rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
if (type == UNSUBACK)
rc = 1;
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,102 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into unsubscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
unsigned char* buf, int len)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != UNSUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied unsuback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

78
package/mqtt/StackTrace.h Normal file
View File

@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for bug #434081
*******************************************************************************/
#ifndef STACKTRACE_H_
#define STACKTRACE_H_
#include <stdio.h>
#define NOSTACKTRACE 1
#if defined(NOSTACKTRACE)
#define FUNC_ENTRY
#define FUNC_ENTRY_NOLOG
#define FUNC_ENTRY_MED
#define FUNC_ENTRY_MAX
#define FUNC_EXIT
#define FUNC_EXIT_NOLOG
#define FUNC_EXIT_MED
#define FUNC_EXIT_MAX
#define FUNC_EXIT_RC(x)
#define FUNC_EXIT_MED_RC(x)
#define FUNC_EXIT_MAX_RC(x)
#else
#if defined(WIN32)
#define inline __inline
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
#else
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
void StackTrace_entry(const char* name, int line, int trace);
void StackTrace_exit(const char* name, int line, void* return_value, int trace);
void StackTrace_printStack(FILE* dest);
char* StackTrace_get(unsigned long);
#endif
#endif
#endif /* STACKTRACE_H_ */

View File

@ -0,0 +1,46 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @LastEditTime: 2020-06-17 19:31:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_CONFIG_H_
#define _MQTT_CONFIG_H_
// #define MQTT_LOG_IS_SALOF
#define MQTT_LOG_LEVEL MQTT_LOG_INFO_LEVEL //MQTT_LOG_WARN_LEVEL MQTT_LOG_DEBUG_LEVEL
#ifdef MQTT_LOG_IS_SALOF
#define SALOF_USING_LOG (1U)
#define SALOF_USING_SALOF (1U)
#define SALOF_LOG_LEVEL MQTT_LOG_LEVEL
#define SALOF_OS SALOF_USING_LINUX
#define SALOF_USING_IDLE_HOOK (0U)
#define SALOF_LOG_COLOR (1U)
#define SALOF_LOG_TS (0U)
#define SALOF_LOG_TAR (0U)
#define SALOF_BUFF_SIZE 512
#define SALOF_FIFO_SIZE 4096
#define SALOF_TASK_STACK_SIZE 1024
#define SALOF_TASK_TICK 50
#endif
#define MQTT_MAX_PACKET_ID (0xFFFF - 1)
#define MQTT_TOPIC_LEN_MAX 64
#define MQTT_ACK_HANDLER_NUM_MAX 64
#define MQTT_DEFAULT_BUF_SIZE 1024
#define MQTT_DEFAULT_CMD_TIMEOUT 5000
#define MQTT_MAX_CMD_TIMEOUT 20000
#define MQTT_MIN_CMD_TIMEOUT 1000
#define MQTT_KEEP_ALIVE_INTERVAL 50 // unit: second
#define MQTT_VERSION 4 // 4 is mqtt 3.1.1
#define MQTT_RECONNECT_DEFAULT_DURATION 1000
#define MQTT_THREAD_STACK_SIZE 2048
#define MQTT_THREAD_PRIO 5
#define MQTT_THREAD_TICK 50
#define MQTT_NETWORK_TYPE_NO_TLS
#endif /* _MQTT_CONFIG_H_ */

View File

@ -0,0 +1,88 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 23:22:10
* @FilePath : /mqttclient/mqttclient/mqtt_defconfig.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-02-25 03:36:09
* @LastEditTime: 2020-06-17 19:59:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _DEFCONFIG_H_
#define _DEFCONFIG_H_
#include "mqtt_config.h"
#ifndef MQTT_LOG_LEVEL
#define MQTT_LOG_LEVEL MQTT_LOG_DEBUG_LEVEL //MQTT_LOG_WARN_LEVEL MQTT_LOG_DEBUG_LEVEL
#endif // !MQTT_LOG_LEVEL
#ifndef MQTT_MAX_PACKET_ID
#define MQTT_MAX_PACKET_ID (0xFFFF - 1)
#endif // !MQTT_MAX_PACKET_ID
#ifndef MQTT_TOPIC_LEN_MAX
#define MQTT_TOPIC_LEN_MAX 64
#endif // !MQTT_TOPIC_LEN_MAX
#ifndef MQTT_ACK_HANDLER_NUM_MAX
#define MQTT_ACK_HANDLER_NUM_MAX 64
#endif // !MQTT_ACK_HANDLER_NUM_MAX
#ifndef MQTT_DEFAULT_BUF_SIZE
#define MQTT_DEFAULT_BUF_SIZE 1024
#endif // !MQTT_DEFAULT_BUF_SIZE
#ifndef MQTT_DEFAULT_CMD_TIMEOUT
#define MQTT_DEFAULT_CMD_TIMEOUT 4000
#endif // !MQTT_DEFAULT_CMD_TIMEOUT
#ifndef MQTT_MAX_CMD_TIMEOUT
#define MQTT_MAX_CMD_TIMEOUT 20000
#endif // !MQTT_MAX_CMD_TIMEOUT
#ifndef MQTT_MIN_CMD_TIMEOUT
#define MQTT_MIN_CMD_TIMEOUT 1000
#endif // !MQTT_MIN_CMD_TIMEOUT
#ifndef MQTT_KEEP_ALIVE_INTERVAL
#define MQTT_KEEP_ALIVE_INTERVAL 100 // unit: second
#endif // !MQTT_KEEP_ALIVE_INTERVAL
#ifndef MQTT_VERSION
#define MQTT_VERSION 4 // 4 is mqtt 3.1.1
#endif // !MQTT_VERSION
#ifndef MQTT_RECONNECT_DEFAULT_DURATION
#define MQTT_RECONNECT_DEFAULT_DURATION 1000
#endif // !MQTT_RECONNECT_DEFAULT_DURATION
#ifndef MQTT_THREAD_STACK_SIZE
#define MQTT_THREAD_STACK_SIZE 4096
#endif // !MQTT_THREAD_STACK_SIZE
#ifndef MQTT_THREAD_PRIO
#define MQTT_THREAD_PRIO 5
#endif // !MQTT_THREAD_PRIO
#ifndef MQTT_THREAD_TICK
#define MQTT_THREAD_TICK 50
#endif // !MQTT_THREAD_TICK
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#ifndef MQTT_TLS_HANDSHAKE_TIMEOUT
#define MQTT_TLS_HANDSHAKE_TIMEOUT (5 * 1000)
#endif // !MQTT_TLS_HANDSHAKE_TIMEOUT
#endif /* MQTT_NETWORK_TYPE_NO_TLS */
#endif /* _DEFCONFIG_H_ */

53
package/mqtt/mqtt_error.h Normal file
View File

@ -0,0 +1,53 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 00:42:16
* @LastEditTime: 2020-10-17 14:16:15
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_ERROR_H_
#define _MQTT_ERROR_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum mqtt_error {
MQTT_SSL_CERT_ERROR = -0x001C, /* cetr parse failed */
MQTT_SOCKET_FAILED_ERROR = -0x001B, /* socket fd failed */
MQTT_SOCKET_UNKNOWN_HOST_ERROR = -0x001A, /* socket unknown host ip or domain */
MQTT_SET_PUBLISH_DUP_FAILED_ERROR = -0x0019, /* mqtt publish packet set udp bit failed */
MQTT_CLEAN_SESSION_ERROR = -0x0018, /* mqtt clean session error */
MQTT_ACK_NODE_IS_EXIST_ERROR = -0x0017, /* mqtt ack list is exist ack node */
MQTT_ACK_HANDLER_NUM_TOO_MUCH_ERROR = -0x0016, /* mqtt ack handler number is too much */
MQTT_RESUBSCRIBE_ERROR = -0x0015, /* mqtt resubscribe error */
MQTT_SUBSCRIBE_ERROR = -0x0014, /* mqtt subscribe error */
MQTT_SEND_PACKET_ERROR = -0x0013, /* mqtt send a packet */
MQTT_SERIALIZE_PUBLISH_ACK_PACKET_ERROR = -0x0012, /* mqtt serialize publish ack packet error */
MQTT_PUBLISH_PACKET_ERROR = -0x0011, /* mqtt publish packet error */
MQTT_RECONNECT_TIMEOUT_ERROR = -0x0010, /* mqtt try reconnect, but timeout */
MQTT_SUBSCRIBE_NOT_ACK_ERROR = -0x000F, /* mqtt subscribe, but not ack */
MQTT_NOT_CONNECT_ERROR = -0x000E, /* mqtt not connect */
MQTT_SUBSCRIBE_ACK_PACKET_ERROR = -0x000D, /* mqtt subscribe, but ack packet error */
MQTT_UNSUBSCRIBE_ACK_PACKET_ERROR = -0x000C, /* mqtt unsubscribe, but ack packet error */
MQTT_PUBLISH_ACK_PACKET_ERROR = -0x000B, /* mqtt pubilsh ack packet error */
MQTT_PUBLISH_ACK_TYPE_ERROR = -0x000A, /* mqtt pubilsh ack type error */
MQTT_PUBREC_PACKET_ERROR = -0x0009, /* mqtt pubrec packet error */
MQTT_BUFFER_TOO_SHORT_ERROR = -0x0008, /* mqtt buffer too short */
MQTT_NOTHING_TO_READ_ERROR = -0x0007, /* mqtt nothing to read */
MQTT_SUBSCRIBE_QOS_ERROR = -0x0006, /* mqtt subsrcibe qos error */
MQTT_BUFFER_OVERFLOW_ERROR = -0x0005, /* mqtt buffer overflow */
MQTT_CONNECT_FAILED_ERROR = -0x0004, /* mqtt connect failed */
MQTT_MEM_NOT_ENOUGH_ERROR = -0x0003, /* mqtt memory not enough */
MQTT_NULL_VALUE_ERROR = -0x0002, /* mqtt value is null */
MQTT_FAILED_ERROR = -0x0001, /* failed */
MQTT_SUCCESS_ERROR = 0x0000 /* success */
} mqtt_error_t;
#define RETURN_ERROR(x) { return x; }
#ifdef __cplusplus
}
#endif
#endif

72
package/mqtt/mqtt_list.c Normal file
View File

@ -0,0 +1,72 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-11 22:46:33
* @LastEditTime: 2020-04-27 23:28:12
* @Description: the following code references TencentOS tiny, please keep the author information and source code according to the license.
*/
# include "mqtt_list.h"
static void _mqtt_list_add(mqtt_list_t *node, mqtt_list_t *prev, mqtt_list_t *next)
{
next->prev = node;
node->next = next;
node->prev = prev;
prev->next = node;
}
static void _mqtt_list_del(mqtt_list_t *prev, mqtt_list_t *next)
{
next->prev = prev;
prev->next = next;
}
static void _mqtt_list_del_entry(mqtt_list_t *entry)
{
_mqtt_list_del(entry->prev, entry->next);
}
void mqtt_list_init(mqtt_list_t *list)
{
list->next = list;
list->prev = list;
}
void mqtt_list_add(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_add(node, list, list->next);
}
void mqtt_list_add_tail(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_add(node, list->prev, list);
}
void mqtt_list_del(mqtt_list_t *entry)
{
_mqtt_list_del(entry->prev, entry->next);
}
void mqtt_list_del_init(mqtt_list_t *entry)
{
_mqtt_list_del_entry(entry);
mqtt_list_init(entry);
}
void mqtt_list_move(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_del_entry(node);
mqtt_list_add(node, list);
}
void mqtt_list_move_tail(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_del_entry(node);
mqtt_list_add_tail(node, list);
}
int mqtt_list_is_empty(mqtt_list_t *list)
{
return list->next == list;
}

70
package/mqtt/mqtt_list.h Normal file
View File

@ -0,0 +1,70 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-11 22:47:55
* @LastEditTime: 2020-10-17 14:18:02
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_LIST_H_
#define _MQTT_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mqtt_list_node {
struct mqtt_list_node *next;
struct mqtt_list_node *prev;
} mqtt_list_t;
#define OFFSET_OF_FIELD(type, field) \
((size_t)&(((type *)0)->field))
#define CONTAINER_OF_FIELD(ptr, type, field) \
((type *)((unsigned char *)(ptr) - OFFSET_OF_FIELD(type, field)))
#define LIST_NODE(node) \
{ &(node), &(node) }
#define LIST_DEFINE(list) \
mqtt_list_t list = { &(list), &(list) }
#define LIST_ENTRY(list, type, field) \
CONTAINER_OF_FIELD(list, type, field)
#define LIST_FIRST_ENTRY(list, type, field) \
LIST_ENTRY((list)->next, type, field)
#define LIST_FIRST_ENTRY_OR_NULL(list, type, field) \
(mqtt_list_is_empty(list) ? NULL : LIST_FIRST_ENTRY(list, type, field))
#define LIST_FOR_EACH(curr, list) \
for (curr = (list)->next; curr != (list); curr = curr->next)
#define LIST_FOR_EACH_PREV(curr, list) \
for (curr = (list)->prev; curr != (list); curr = curr->prev)
#define LIST_FOR_EACH_SAFE(curr, next, list) \
for (curr = (list)->next, next = curr->next; curr != (list); \
curr = next, next = curr->next)
#define LIST_FOR_EACH_PREV_SAFE(curr, next, list) \
for (curr = (list)->prev, next = curr->prev; \
curr != (list); \
curr = next, next = curr->prev)
void mqtt_list_init(mqtt_list_t *list);
void mqtt_list_add(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_add_tail(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_del(mqtt_list_t *entry);
void mqtt_list_del_init(mqtt_list_t *entry);
void mqtt_list_move(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_move_tail(mqtt_list_t *node, mqtt_list_t *list);
int mqtt_list_is_empty(mqtt_list_t *list);
#ifdef __cplusplus
}
#endif
#endif /* _LIST_H_ */

71
package/mqtt/mqtt_log.h Normal file
View File

@ -0,0 +1,71 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-27 03:25:58
* @LastEditTime: 2020-10-17 14:15:55
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_LOG_H_
#define _MQTT_LOG_H_
#include "mqtt_defconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MQTT_LOG_BASE_LEVEL (0)
#define MQTT_LOG_ERR_LEVEL (MQTT_LOG_BASE_LEVEL + 1)
#define MQTT_LOG_WARN_LEVEL (MQTT_LOG_ERR_LEVEL + 1)
#define MQTT_LOG_INFO_LEVEL (MQTT_LOG_WARN_LEVEL + 1)
#define MQTT_LOG_DEBUG_LEVEL (MQTT_LOG_INFO_LEVEL + 1)
#ifdef MQTT_LOG_IS_SALOF
#include "salof.h"
#define MQTT_LOG_D(fmt, ...) SALOF_LOG_DEBUG(fmt, ##__VA_ARGS__)
#define MQTT_LOG_I(fmt, ...) SALOF_LOG_INFO(fmt, ##__VA_ARGS__)
#define MQTT_LOG_W(fmt, ...) SALOF_LOG_WARN(fmt, ##__VA_ARGS__)
#define MQTT_LOG_E(fmt, ...) SALOF_LOG_ERR(fmt, ##__VA_ARGS__)
#define mqtt_log_init salof_init
#else
#include <stdio.h>
#if MQTT_LOG_LEVEL < MQTT_LOG_DEBUG_LEVEL
#define MQTT_LOG_D(fmt, ...)
#else
#define MQTT_LOG_D(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_INFO_LEVEL
#define MQTT_LOG_I(fmt, ...)
#else
#define MQTT_LOG_I(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_WARN_LEVEL
#define MQTT_LOG_W(fmt, ...)
#else
#define MQTT_LOG_W(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_ERR_LEVEL
#define MQTT_LOG_E(fmt, ...)
#else
#define MQTT_LOG_E(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_BASE_LEVEL
#define MQTT_LOG(fmt, ...)
#else
#define MQTT_LOG(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#define mqtt_log_init()
#endif
#ifdef __cplusplus
}
#endif
#endif /* _LOG_H_ */

1500
package/mqtt/mqttclient.c Normal file

File diff suppressed because it is too large Load Diff

180
package/mqtt/mqttclient.h Normal file
View File

@ -0,0 +1,180 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:31:25
* @LastEditTime : 2022-06-11 22:45:02
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTTCLIENT_H_
#define _MQTTCLIENT_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "MQTTPacket.h"
#include "mqtt_list.h"
#include "platform_timer.h"
#include "platform_memory.h"
#include "platform_mutex.h"
#include "platform_thread.h"
#include "mqtt_defconfig.h"
#include "network.h"
#include "random.h"
#include "mqtt_error.h"
#include "mqtt_log.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum mqtt_qos {
QOS0 = 0,
QOS1 = 1,
QOS2 = 2,
SUBFAIL = 0x80
} mqtt_qos_t;
typedef enum client_state {
CLIENT_STATE_INVALID = -1,
CLIENT_STATE_INITIALIZED = 0,
CLIENT_STATE_CONNECTED = 1,
CLIENT_STATE_DISCONNECTED = 2,
CLIENT_STATE_CLEAN_SESSION = 3
}client_state_t;
typedef struct mqtt_connack_data {
uint8_t rc;
uint8_t session_present;
} mqtt_connack_data_t;
typedef struct mqtt_message {
mqtt_qos_t qos;
uint8_t retained;
uint8_t dup;
uint16_t id;
size_t payloadlen;
void *payload;
} mqtt_message_t;
typedef struct message_data {
char topic_name[MQTT_TOPIC_LEN_MAX];
mqtt_message_t *message;
} message_data_t;
typedef void (*interceptor_handler_t)(void* client, message_data_t* msg);
typedef void (*message_handler_t)(void* client, message_data_t* msg);
typedef void (*reconnect_handler_t)(void* client, void* reconnect_date);
typedef struct message_handlers {
mqtt_list_t list;
mqtt_qos_t qos;
const char* topic_filter;
message_handler_t handler;
} message_handlers_t;
typedef struct ack_handlers {
mqtt_list_t list;
platform_timer_t timer;
uint32_t type;
uint16_t packet_id;
message_handlers_t *handler;
uint16_t payload_len;
uint8_t *payload;
} ack_handlers_t;
typedef struct mqtt_will_options {
mqtt_qos_t will_qos;
uint8_t will_retained;
char *will_topic;
char *will_message;
} mqtt_will_options_t;
typedef struct mqtt_client {
char *mqtt_client_id;
char *mqtt_user_name;
char *mqtt_password;
char *mqtt_host;
char *mqtt_port;
char *mqtt_ca;
void *mqtt_reconnect_data;
uint8_t *mqtt_read_buf;
uint8_t *mqtt_write_buf;
uint16_t mqtt_keep_alive_interval;
uint16_t mqtt_packet_id;
uint32_t mqtt_will_flag : 1;
uint32_t mqtt_clean_session : 1;
uint32_t mqtt_ping_outstanding : 2;
uint32_t mqtt_version : 4;
uint32_t mqtt_ack_handler_number : 24;
uint32_t mqtt_cmd_timeout;
uint32_t mqtt_read_buf_size;
uint32_t mqtt_write_buf_size;
uint32_t mqtt_reconnect_try_duration;
size_t mqtt_client_id_len;
size_t mqtt_user_name_len;
size_t mqtt_password_len;
mqtt_will_options_t *mqtt_will_options;
client_state_t mqtt_client_state;
platform_mutex_t mqtt_write_lock;
platform_mutex_t mqtt_global_lock;
mqtt_list_t mqtt_msg_handler_list;
mqtt_list_t mqtt_ack_handler_list;
network_t *mqtt_network;
platform_thread_t *mqtt_thread;
platform_timer_t mqtt_last_sent;
platform_timer_t mqtt_last_received;
reconnect_handler_t mqtt_reconnect_handler;
interceptor_handler_t mqtt_interceptor_handler;
} mqtt_client_t;
#define MQTT_ROBUSTNESS_CHECK(item, err) if (!(item)) { \
MQTT_LOG_E("%s:%d %s()... check for error.", __FILE__, __LINE__, __FUNCTION__); \
return err; }
#define MQTT_CLIENT_SET_DEFINE(name, type, res) \
type mqtt_set_##name(mqtt_client_t *c, type t) { \
MQTT_ROBUSTNESS_CHECK((c), res); \
c->mqtt_##name = t; \
return c->mqtt_##name; \
}
#define MQTT_CLIENT_SET_STATEMENT(name, type) \
type mqtt_set_##name(mqtt_client_t *, type);
MQTT_CLIENT_SET_STATEMENT(client_id, char*)
MQTT_CLIENT_SET_STATEMENT(user_name, char*)
MQTT_CLIENT_SET_STATEMENT(password, char*)
MQTT_CLIENT_SET_STATEMENT(host, char*)
MQTT_CLIENT_SET_STATEMENT(port, char*)
MQTT_CLIENT_SET_STATEMENT(ca, char*)
MQTT_CLIENT_SET_STATEMENT(reconnect_data, void*)
MQTT_CLIENT_SET_STATEMENT(keep_alive_interval, uint16_t)
MQTT_CLIENT_SET_STATEMENT(will_flag, uint32_t)
MQTT_CLIENT_SET_STATEMENT(clean_session, uint32_t)
MQTT_CLIENT_SET_STATEMENT(version, uint32_t)
MQTT_CLIENT_SET_STATEMENT(cmd_timeout, uint32_t)
MQTT_CLIENT_SET_STATEMENT(read_buf_size, uint32_t)
MQTT_CLIENT_SET_STATEMENT(write_buf_size, uint32_t)
MQTT_CLIENT_SET_STATEMENT(reconnect_try_duration, uint32_t)
MQTT_CLIENT_SET_STATEMENT(reconnect_handler, reconnect_handler_t)
MQTT_CLIENT_SET_STATEMENT(interceptor_handler, interceptor_handler_t)
void mqtt_sleep_ms(int ms);
mqtt_client_t *mqtt_lease(void);
int mqtt_release(mqtt_client_t* c);
int mqtt_connect(mqtt_client_t* c);
int mqtt_disconnect(mqtt_client_t* c);
int mqtt_keep_alive(mqtt_client_t* c);
int mqtt_subscribe(mqtt_client_t* c, const char* topic_filter, mqtt_qos_t qos, message_handler_t msg_handler);
int mqtt_unsubscribe(mqtt_client_t* c, const char* topic_filter);
int mqtt_publish(mqtt_client_t* c, const char* topic_filter, mqtt_message_t* msg);
int mqtt_list_subscribe_topic(mqtt_client_t* c);
int mqtt_set_will_options(mqtt_client_t* c, char *topic, mqtt_qos_t qos, uint8_t retained, char *message);
#ifdef __cplusplus
}
#endif
#endif /* _MQTTCLIENT_H_ */

View File

@ -0,0 +1,36 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:38:52
* @LastEditTime: 2020-05-25 10:13:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "nettype_tcp.h"
#include "mqtt_log.h"
#include "platform_net_socket.h"
int nettype_tcp_read(network_t *n, unsigned char *read_buf, int len, int timeout)
{
return platform_net_socket_recv_timeout(n->socket, read_buf, len, timeout);
}
int nettype_tcp_write(network_t *n, unsigned char *write_buf, int len, int timeout)
{
return platform_net_socket_write_timeout(n->socket, write_buf, len, timeout);
}
int nettype_tcp_connect(network_t* n)
{
n->socket = platform_net_socket_connect(n->host, n->port, PLATFORM_NET_PROTO_TCP);
if (n->socket < 0)
RETURN_ERROR(n->socket);
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
void nettype_tcp_disconnect(network_t* n)
{
if (NULL != n)
platform_net_socket_close(n->socket);
n->socket = -1;
}

View File

@ -0,0 +1,27 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:39:00
* @LastEditTime: 2020-10-17 14:17:10
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETTYPE_TCP_H_
#define _NETTYPE_TCP_H_
#include "network.h"
#include "mqtt_error.h"
#ifdef __cplusplus
extern "C" {
#endif
int nettype_tcp_read(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tcp_write(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tcp_connect(network_t* n);
void nettype_tcp_disconnect(network_t* n);
#ifdef __cplusplus
}
#endif
#endif

253
package/mqtt/nettype_tls.c Normal file
View File

@ -0,0 +1,253 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-11 19:45:35
* @LastEditTime: 2020-09-20 14:29:06
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "nettype_tls.h"
#include "platform_net_socket.h"
#include "platform_memory.h"
#include "platform_timer.h"
#include "random.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "mbedtls/platform.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/pk.h"
#if defined(MBEDTLS_X509_CRT_PARSE_C)
static int server_certificate_verify(void *hostname, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
{
if (0 != *flags)
MQTT_LOG_E("%s:%d %s()... server_certificate_verify failed returned 0x%04x\n", __FILE__, __LINE__, __FUNCTION__, *flags);
return *flags;
}
#endif
static int nettype_tls_entropy_source(void *data, uint8_t *output, size_t len, size_t *out_len)
{
uint32_t seed;
(void) data;
seed = random_number();
if (len > sizeof(seed)) {
len = sizeof(seed);
}
memcpy(output, &seed, len);
*out_len = len;
return 0;
}
static int nettype_tls_init(network_t* n, nettype_tls_params_t* nettype_tls_params)
{
int rc = MQTT_SUCCESS_ERROR;
mbedtls_platform_set_calloc_free(platform_memory_calloc, platform_memory_free);
mbedtls_net_init(&(nettype_tls_params->socket_fd));
mbedtls_ssl_init(&(nettype_tls_params->ssl));
mbedtls_ssl_config_init(&(nettype_tls_params->ssl_conf));
mbedtls_ctr_drbg_init(&(nettype_tls_params->ctr_drbg));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt_init(&(nettype_tls_params->ca_cert));
mbedtls_x509_crt_init(&(nettype_tls_params->client_cert));
mbedtls_pk_init(&(nettype_tls_params->private_key));
#endif
mbedtls_entropy_init(&(nettype_tls_params->entropy));
mbedtls_entropy_add_source(&(nettype_tls_params->entropy), nettype_tls_entropy_source, NULL, MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_SOURCE_STRONG);
if ((rc = mbedtls_ctr_drbg_seed(&(nettype_tls_params->ctr_drbg), mbedtls_entropy_func,
&(nettype_tls_params->entropy), NULL, 0)) != 0) {
MQTT_LOG_E("mbedtls_ctr_drbg_seed failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
if ((rc = mbedtls_ssl_config_defaults(&(nettype_tls_params->ssl_conf), MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
MQTT_LOG_E("mbedtls_ssl_config_defaults failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
mbedtls_ssl_conf_rng(&(nettype_tls_params->ssl_conf), mbedtls_ctr_drbg_random, &(nettype_tls_params->ctr_drbg));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if (NULL != n->ca_crt) {
n->ca_crt_len = strlen(n->ca_crt);
if (0 != (rc = (mbedtls_x509_crt_parse(&(nettype_tls_params->ca_cert), (unsigned char *)n->ca_crt,
(n->ca_crt_len + 1))))) {
MQTT_LOG_E("%s:%d %s()... parse ca crt failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
}
mbedtls_ssl_conf_ca_chain(&(nettype_tls_params->ssl_conf), &(nettype_tls_params->ca_cert), NULL);
if ((rc = mbedtls_ssl_conf_own_cert(&(nettype_tls_params->ssl_conf),
&(nettype_tls_params->client_cert), &(nettype_tls_params->private_key))) != 0) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_conf_own_cert failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
mbedtls_ssl_conf_verify(&(nettype_tls_params->ssl_conf), server_certificate_verify, (void *)n->host);
mbedtls_ssl_conf_authmode(&(nettype_tls_params->ssl_conf), MBEDTLS_SSL_VERIFY_REQUIRED);
#endif
mbedtls_ssl_conf_read_timeout(&(nettype_tls_params->ssl_conf), n->timeout_ms);
if ((rc = mbedtls_ssl_setup(&(nettype_tls_params->ssl), &(nettype_tls_params->ssl_conf))) != 0) {
MQTT_LOG_E("mbedtls_ssl_setup failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if ((rc = mbedtls_ssl_set_hostname(&(nettype_tls_params->ssl), n->host)) != 0) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_set_hostname failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
#endif
mbedtls_ssl_set_bio(&(nettype_tls_params->ssl), &(nettype_tls_params->socket_fd), mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
int nettype_tls_connect(network_t* n)
{
int rc;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) platform_memory_alloc(sizeof(nettype_tls_params_t));
if (NULL == nettype_tls_params)
RETURN_ERROR(MQTT_MEM_NOT_ENOUGH_ERROR);
rc = nettype_tls_init(n, nettype_tls_params);
if (MQTT_SUCCESS_ERROR != rc)
goto exit;
if (0 != (rc = mbedtls_net_connect(&(nettype_tls_params->socket_fd), n->host, n->port, MBEDTLS_NET_PROTO_TCP)))
goto exit;
while ((rc = mbedtls_ssl_handshake(&(nettype_tls_params->ssl))) != 0) {
if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) {
MQTT_LOG_E("%s:%d %s()...mbedtls handshake failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if (rc == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
MQTT_LOG_E("%s:%d %s()...unable to verify the server's certificate", __FILE__, __LINE__, __FUNCTION__);
}
#endif
goto exit;
}
}
if ((rc = mbedtls_ssl_get_verify_result(&(nettype_tls_params->ssl))) != 0) {
MQTT_LOG_E("%s:%d %s()...mbedtls_ssl_get_verify_result returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
goto exit;
}
n->nettype_tls_params = nettype_tls_params;
RETURN_ERROR(MQTT_SUCCESS_ERROR)
exit:
platform_memory_free(nettype_tls_params);
RETURN_ERROR(rc);
}
void nettype_tls_disconnect(network_t* n)
{
int rc = 0;
if (NULL == n)
return;
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
do {
rc = mbedtls_ssl_close_notify(&(nettype_tls_params->ssl));
} while (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE);
mbedtls_net_free(&(nettype_tls_params->socket_fd));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt_free(&(nettype_tls_params->client_cert));
mbedtls_x509_crt_free(&(nettype_tls_params->ca_cert));
mbedtls_pk_free(&(nettype_tls_params->private_key));
#endif
mbedtls_ssl_free(&(nettype_tls_params->ssl));
mbedtls_ssl_config_free(&(nettype_tls_params->ssl_conf));
mbedtls_ctr_drbg_free(&(nettype_tls_params->ctr_drbg));
mbedtls_entropy_free(&(nettype_tls_params->entropy));
platform_memory_free(nettype_tls_params);
}
int nettype_tls_write(network_t *n, unsigned char *buf, int len, int timeout)
{
int rc = 0;
int write_len = 0;
platform_timer_t timer;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
platform_timer_cutdown(&timer, timeout);
do {
rc = mbedtls_ssl_write(&(nettype_tls_params->ssl), (unsigned char *)(buf + write_len), len - write_len);
if (rc > 0) {
write_len += rc;
} else if ((rc == 0) || ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_TIMEOUT))) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_write failed: 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
break;
}
} while((!platform_timer_is_expired(&timer)) && (write_len < len));
return write_len;
}
int nettype_tls_read(network_t *n, unsigned char *buf, int len, int timeout)
{
int rc = 0;
int read_len = 0;
platform_timer_t timer;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
platform_timer_cutdown(&timer, timeout);
do {
rc = mbedtls_ssl_read(&(nettype_tls_params->ssl), (unsigned char *)(buf + read_len), len - read_len);
if (rc > 0) {
read_len += rc;
} else if ((rc == 0) || ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_TIMEOUT))) {
// MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_read failed: 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
break;
}
} while((!platform_timer_is_expired(&timer)) && (read_len < len));
return read_len;
}
#endif /* MQTT_NETWORK_TYPE_NO_TLS */

View File

@ -0,0 +1,64 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:48:43
* @FilePath : /mqttclient/network/nettype_tls.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-11 19:45:44
* @LastEditTime: 2020-10-17 14:14:11
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETTYPE_TLS_H_
#define _NETTYPE_TLS_H_
#include "mqtt_defconfig.h"
#include "network.h"
#include "mqtt_error.h"
#include "mqtt_log.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "mbedtls/config.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct nettype_tls_params {
mbedtls_net_context socket_fd; /**< mbed TLS network context. */
mbedtls_entropy_context entropy; /**< mbed TLS entropy. */
mbedtls_ctr_drbg_context ctr_drbg; /**< mbed TLS ctr_drbg. */
mbedtls_ssl_context ssl; /**< mbed TLS control context. */
mbedtls_ssl_config ssl_conf; /**< mbed TLS configuration context. */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt ca_cert; /**< mbed TLS CA certification. */
mbedtls_x509_crt client_cert; /**< mbed TLS Client certification. */
#endif
mbedtls_pk_context private_key; /**< mbed TLS Client key. */
} nettype_tls_params_t;
int nettype_tls_read(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tls_write(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tls_connect(network_t* n);
void nettype_tls_disconnect(network_t* n);
#endif /* MQTT_NETWORK_TYPE_NO_TLS */
#ifdef __cplusplus
}
#endif
#endif

113
package/mqtt/network.c Normal file
View File

@ -0,0 +1,113 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:30:54
* @LastEditTime: 2020-06-05 17:17:48
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include <string.h>
#include "platform_timer.h"
#include "platform_memory.h"
#include "nettype_tcp.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "nettype_tls.h"
#endif
int network_read(network_t *n, unsigned char *buf, int len, int timeout)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_read(n, buf, len, timeout);
#endif
return nettype_tcp_read(n, buf, len, timeout);
}
int network_write(network_t *n, unsigned char *buf, int len, int timeout)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_write(n, buf, len, timeout);
#endif
return nettype_tcp_write(n, buf, len, timeout);
}
int network_connect(network_t *n)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_connect(n);
#endif
return nettype_tcp_connect(n);
}
void network_disconnect(network_t *n)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
nettype_tls_disconnect(n);
else
#endif
nettype_tcp_disconnect(n);
}
int network_init(network_t *n, const char *host, const char *port, const char *ca)
{
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->socket = -1;
n->host = host;
n->port = port;
#ifndef MQTT_NETWORK_TYPE_NO_TLS
n->channel = 0;
if (NULL != ca) {
network_set_ca(n, ca);
}
#endif
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
void network_release(network_t* n)
{
if (n->socket >= 0)
network_disconnect(n);
memset(n, 0, sizeof(network_t));
}
void network_set_channel(network_t *n, int channel)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
n->channel = channel;
#endif
}
int network_set_ca(network_t *n, const char *ca)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if ((NULL == n) || (NULL == ca))
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->ca_crt = ca;
n->ca_crt_len = strlen(ca);
n->channel = NETWORK_CHANNEL_TLS;
n->timeout_ms = MQTT_TLS_HANDSHAKE_TIMEOUT;
#endif
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
int network_set_host_port(network_t* n, char *host, char *port)
{
if (!(n && host && port))
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->host = host;
n->port = port;
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}

47
package/mqtt/network.h Normal file
View File

@ -0,0 +1,47 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:31:02
* @LastEditTime: 2020-10-17 14:14:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include "mqtt_defconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NETWORK_CHANNEL_TCP 0
#define NETWORK_CHANNEL_TLS 1
typedef struct network {
const char *host;
const char *port;
int socket;
#ifndef MQTT_NETWORK_TYPE_NO_TLS
int channel; /* tcp or tls */
const char *ca_crt;
unsigned int ca_crt_len;
unsigned int timeout_ms; // SSL handshake timeout in millisecond
void *nettype_tls_params;
#endif
} network_t;
int network_init(network_t *n, const char *host, const char *port, const char *ca);
int network_set_ca(network_t *n, const char *ca);
void network_set_channel(network_t *n, int channel);
int network_set_host_port(network_t* n, char *host, char *port);
int network_read(network_t* n, unsigned char* buf, int len, int timeout);
int network_write(network_t* n, unsigned char* buf, int len, int timeout);
int network_connect(network_t* n);
void network_disconnect(network_t *n);
void network_release(network_t* n);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,26 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-14 22:02:07
* @LastEditTime: 2020-02-19 20:26:04
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_memory.h"
void *platform_memory_alloc(size_t size)
{
return malloc(size);
}
void *platform_memory_calloc(size_t num, size_t size)
{
return calloc(num, size);
}
void platform_memory_free(void *ptr)
{
free(ptr);
}

View File

@ -0,0 +1,26 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-14 22:06:35
* @LastEditTime: 2020-10-17 14:17:24
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_MEMORY_H_
#define _PLATFORM_MEMORY_H_
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void *platform_memory_alloc(size_t size);
void *platform_memory_calloc(size_t num, size_t size);
void platform_memory_free(void *ptr);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,33 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:27:19
* @LastEditTime: 2020-02-23 15:01:06
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_mutex.h"
int platform_mutex_init(platform_mutex_t* m)
{
return pthread_mutex_init(&(m->mutex), NULL);
}
int platform_mutex_lock(platform_mutex_t* m)
{
return pthread_mutex_lock(&(m->mutex));
}
int platform_mutex_trylock(platform_mutex_t* m)
{
return pthread_mutex_trylock(&(m->mutex));
}
int platform_mutex_unlock(platform_mutex_t* m)
{
return pthread_mutex_unlock(&(m->mutex));
}
int platform_mutex_destroy(platform_mutex_t* m)
{
return pthread_mutex_destroy(&(m->mutex));
}

View File

@ -0,0 +1,30 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:31:33
* @LastEditTime: 2020-10-17 14:17:31
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_MUTEX_H_
#define _PLATFORM_MUTEX_H_
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_mutex {
pthread_mutex_t mutex;
} platform_mutex_t;
int platform_mutex_init(platform_mutex_t* m);
int platform_mutex_lock(platform_mutex_t* m);
int platform_mutex_trylock(platform_mutex_t* m);
int platform_mutex_unlock(platform_mutex_t* m);
int platform_mutex_destroy(platform_mutex_t* m);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,125 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-10 23:45:59
* @LastEditTime: 2020-06-05 17:13:00
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_net_socket.h"
#include "mqtt_error.h"
int platform_net_socket_connect(const char *host, const char *port, int proto)
{
int fd, ret = MQTT_SOCKET_UNKNOWN_HOST_ERROR;
struct addrinfo hints, *addr_list, *cur;
/* Do name resolution with both IPv6 and IPv4 */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = (proto == PLATFORM_NET_PROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol = (proto == PLATFORM_NET_PROTO_UDP) ? IPPROTO_UDP : IPPROTO_TCP;
if (getaddrinfo(host, port, &hints, &addr_list) != 0) {
return ret;
}
for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (fd < 0) {
ret = MQTT_SOCKET_FAILED_ERROR;
continue;
}
if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
ret = fd;
break;
}
close(fd);
ret = MQTT_CONNECT_FAILED_ERROR;
}
freeaddrinfo(addr_list);
return ret;
}
int platform_net_socket_recv(int fd, void *buf, size_t len, int flags)
{
return recv(fd, buf, len, flags);
}
int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout)
{
int nread;
int nleft = len;
unsigned char *ptr;
ptr = buf;
struct timeval tv = {
timeout / 1000,
(timeout % 1000) * 1000
};
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
tv.tv_sec = 0;
tv.tv_usec = 100;
}
platform_net_socket_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
while (nleft > 0) {
nread = platform_net_socket_recv(fd, ptr, nleft, 0);
if (nread < 0) {
return -1;
} else if (nread == 0) {
break;
}
nleft -= nread;
ptr += nread;
}
return len - nleft;
}
int platform_net_socket_write(int fd, void *buf, size_t len)
{
return write(fd, buf, len);
}
int platform_net_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout)
{
struct timeval tv = {
timeout / 1000,
(timeout % 1000) * 1000
};
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
tv.tv_sec = 0;
tv.tv_usec = 100;
}
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
return write(fd, buf, len);
}
int platform_net_socket_close(int fd)
{
return close(fd);
}
int platform_net_socket_set_block(int fd)
{
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, F_GETFL) & ~O_NONBLOCK);
}
int platform_net_socket_set_nonblock(int fd)
{
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, F_GETFL) | O_NONBLOCK);
}
int platform_net_socket_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
return setsockopt(fd, level, optname, optval, optlen);
}

View File

@ -0,0 +1,49 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:39:00
* @LastEditTime: 2020-10-17 14:17:45
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_NET_SOCKET_H_
#define _PLATFORM_NET_SOCKET_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PLATFORM_NET_PROTO_TCP 0 /**< The TCP transport protocol */
#define PLATFORM_NET_PROTO_UDP 1 /**< The UDP transport protocol */
int platform_net_socket_connect(const char *host, const char *port, int proto);
int platform_net_socket_recv(int fd, void *buf, size_t len, int flags);
int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout);
int platform_net_socket_write(int fd, void *buf, size_t len);
int platform_net_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout);
int platform_net_socket_close(int fd);
int platform_net_socket_set_block(int fd);
int platform_net_socket_set_nonblock(int fd);
int platform_net_socket_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen);
#ifdef __cplusplus
}
#endif
#endif /* _PLATFORM_NET_SOCKET_H_ */

View File

@ -0,0 +1,61 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-23 19:26:27
* @LastEditTime: 2020-02-23 16:19:07
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_thread.h"
#include "platform_memory.h"
platform_thread_t *platform_thread_init( const char *name,
void (*entry)(void *),
void * const param,
unsigned int stack_size,
unsigned int priority,
unsigned int tick)
{
int res;
platform_thread_t *thread;
void *(*thread_entry) (void *);
thread_entry = (void *(*)(void*))entry;
thread = platform_memory_alloc(sizeof(platform_thread_t));
res = pthread_create(&thread->thread, NULL, thread_entry, param);
if(res != 0) {
platform_memory_free(thread);
}
thread->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
thread->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
return thread;
}
void platform_thread_startup(platform_thread_t* thread)
{
(void) thread;
}
void platform_thread_stop(platform_thread_t* thread)
{
pthread_mutex_lock(&(thread->mutex));
pthread_cond_wait(&(thread->cond), &(thread->mutex));
pthread_mutex_unlock(&(thread->mutex));
}
void platform_thread_start(platform_thread_t* thread)
{
pthread_mutex_lock(&(thread->mutex));
pthread_cond_signal(&(thread->cond));
pthread_mutex_unlock(&(thread->mutex));
}
void platform_thread_destroy(platform_thread_t* thread)
{
if (NULL != thread)
pthread_detach(thread->thread);
}

View File

@ -0,0 +1,38 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:31:44
* @LastEditTime: 2020-10-17 14:15:21
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_THREAD_H_
#define _PLATFORM_THREAD_H_
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_thread {
pthread_t thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
} platform_thread_t;
platform_thread_t *platform_thread_init( const char *name,
void (*entry)(void *),
void * const param,
unsigned int stack_size,
unsigned int priority,
unsigned int tick);
void platform_thread_startup(platform_thread_t* thread);
void platform_thread_stop(platform_thread_t* thread);
void platform_thread_start(platform_thread_t* thread);
void platform_thread_destroy(platform_thread_t* thread);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,48 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-10 22:16:41
* @LastEditTime: 2020-06-05 17:18:48
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_timer.h"
void platform_timer_init(platform_timer_t* timer)
{
timer->time = (struct timeval){0, 0};
}
void platform_timer_cutdown(platform_timer_t* timer, unsigned int timeout)
{
struct timeval now;
gettimeofday(&now, NULL);
struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
timeradd(&now, &interval, &timer->time);
}
char platform_timer_is_expired(platform_timer_t* timer)
{
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->time, &now, &res);
return ((res.tv_sec < 0) || (res.tv_sec == 0 && res.tv_usec <= 0));
}
int platform_timer_remain(platform_timer_t* timer)
{
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->time, &now, &res);
return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
}
unsigned long platform_timer_now(void)
{
return (unsigned long) time(NULL);
}
void platform_timer_usleep(unsigned long usec)
{
usleep(usec);
}

View File

@ -0,0 +1,35 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-10 22:18:32
* @LastEditTime: 2020-10-17 14:17:55
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_TIMER_H_
#define _PLATFORM_TIMER_H_
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_timer {
struct timeval time;
} platform_timer_t;
void platform_timer_init(platform_timer_t* timer);
void platform_timer_cutdown(platform_timer_t* timer, unsigned int timeout);
char platform_timer_is_expired(platform_timer_t* timer);
int platform_timer_remain(platform_timer_t* timer);
unsigned long platform_timer_now(void);
void platform_timer_usleep(unsigned long usec);
#ifdef __cplusplus
}
#endif
#endif

77
package/mqtt/random.c Normal file
View File

@ -0,0 +1,77 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:44:22
* @FilePath : /mqttclient/common/random.c
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
#include <stdlib.h>
#include "random.h"
extern int platform_timer_now();
static unsigned int last_seed = 1;
int __attribute__((weak)) platform_timer_now()
{
return 1;
}
static int do_random(unsigned int seed)
{
srand(seed);
return rand();
}
int random_number(void)
{
unsigned int seed = (unsigned int) platform_timer_now();
last_seed += (seed >> ((seed ^ last_seed) % 3));
return do_random(last_seed ^ seed);
}
// random number range interval [min, max)
int random_number_range(unsigned int min, unsigned int max)
{
return (random_number() % (max - min)) + min;
}
int random_string(char *buffer, int len)
{
unsigned int i, flag, seed, random;
if (NULL == buffer)
return 0;
seed = (unsigned int) random_number();
seed += (unsigned int) ((size_t)buffer ^ seed);
random = (unsigned int)do_random(seed);
for (i = 0; i < len; i++) {
random = do_random(seed ^ random);
flag = (unsigned int)random % 3;
switch (flag) {
case 0:
buffer[i] = 'A' + do_random(random ^ (i & flag)) % 26;
break;
case 1:
buffer[i] = 'a' + do_random(random ^ (i & flag)) % 26;
break;
case 2:
buffer[i] = '0' + do_random(random ^ (i & flag)) % 10;
break;
default:
buffer[i] = 'x';
break;
}
random += ((0xb433e5c6 ^ random) << (i & flag));
}
buffer[len] = '\0';
return len;
}

29
package/mqtt/random.h Normal file
View File

@ -0,0 +1,29 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:40:10
* @FilePath : /mqttclient/common/random.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
#ifndef _RANDOM_H_
#define _RANDOM_H_
#ifdef __cplusplus
extern "C" {
#endif
#define RANDOM_MAX 0x7FFFFFFF
int random_number(void);
int random_number_range(unsigned int min, unsigned int max);
int random_string(char *buffer, int len);
#ifdef __cplusplus
}
#endif
#endif /* _RANDOM_H_ */

View File

@ -72,7 +72,9 @@
"fcntl.h": "c",
"pikastddata_bytearray.h": "c",
"webclient.h": "c",
"platform_socket.h": "c"
"platform_socket.h": "c",
"nettype_tcp.h": "c",
"platform_memory.h": "c"
},
"python.formatting.provider": "autopep8",
"C_Cpp.errorSquiggles": "Disabled"

View File

@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.0.0)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-sign-conversion -Wno-write-strings -Wno-implicit-fallthrough
-Wno-unused-function)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-sign-conversion -Wno-write-strings -Wno-implicit-fallthrough -Wno-sign-compare -Wno-cast-function-type -Wno-unused-function)
OPTION(PIKA_CONFIG_ENABLE "pika config enable" OFF)
IF(PIKA_CONFIG_ENABLE)
ADD_DEFINITIONS(-DPIKA_CONFIG_ENABLE)

View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2014, 2017 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - add connack return code definitions
* Xiang Rong - 442039 Add makefile to Embedded C client
* Ian Craggs - fix for issue #64, bit order in connack response
*******************************************************************************/
#ifndef MQTTCONNECT_H_
#define MQTTCONNECT_H_
enum connack_return_codes
{
MQTT_CONNECTION_ACCEPTED = 0,
MQTT_UNNACCEPTABLE_PROTOCOL = 1,
MQTT_CLIENTID_REJECTED = 2,
MQTT_SERVER_UNAVAILABLE = 3,
MQTT_BAD_USERNAME_OR_PASSWORD = 4,
MQTT_NOT_AUTHORIZED = 5,
};
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
typedef union
{
unsigned char all; /**< all connect flags */
#if defined(REVERSED)
struct
{
unsigned int username : 1; /**< 3.1 user name */
unsigned int password : 1; /**< 3.1 password */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
#else
struct
{
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
#endif
} MQTTConnectFlags; /**< connect flags byte */
/**
* Defines the MQTT "Last Will and Testament" (LWT) settings for
* the connect packet.
*/
typedef struct
{
/** The eyecatcher for this structure. must be MQTW. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** The LWT topic to which the LWT message will be published. */
MQTTString topicName;
/** The LWT payload. */
MQTTString message;
/**
* The retained flag for the LWT message (see MQTTAsync_message.retained).
*/
unsigned char retained;
/**
* The quality of service setting for the LWT message (see
* MQTTAsync_message.qos and @ref qos).
*/
char qos;
} MQTTPacket_willOptions;
#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
typedef struct
{
/** The eyecatcher for this structure. must be MQTC. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
*/
unsigned char MQTTVersion;
MQTTString clientID;
unsigned short keepAliveInterval;
unsigned char cleansession;
unsigned char willFlag;
MQTTPacket_willOptions will;
MQTTString username;
MQTTString password;
} MQTTPacket_connectData;
typedef union
{
unsigned char all; /**< all connack flags */
#if defined(REVERSED)
struct
{
unsigned int reserved : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
#else
struct
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int reserved: 7; /**< unused */
} bits;
#endif
} MQTTConnackFlags; /**< connack flags byte */
#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
#endif /* MQTTCONNECT_H_ */

View File

@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
{
int len = 0;
FUNC_ENTRY;
if (options->MQTTVersion == 3)
len = 12; /* variable depending on MQTT or MQIsdp */
else if (options->MQTTVersion == 4)
len = 10;
len += MQTTstrlen(options->clientID)+2;
if (options->willFlag)
len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
if (options->username.cstring || options->username.lenstring.data)
len += MQTTstrlen(options->username)+2;
if (options->password.cstring || options->password.lenstring.data)
len += MQTTstrlen(options->password)+2;
FUNC_EXIT_RC(len);
return len;
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @return serialized length, or error if 0
*/
int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
int len = 0;
int rc = -1;
FUNC_ENTRY;
if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNECT;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
if (options->MQTTVersion == 4)
{
writeCString(&ptr, "MQTT");
writeChar(&ptr, (char) 4);
}
else
{
writeCString(&ptr, "MQIsdp");
writeChar(&ptr, (char) 3);
}
flags.all = 0;
flags.bits.cleansession = options->cleansession;
flags.bits.will = (options->willFlag) ? 1 : 0;
if (flags.bits.will)
{
flags.bits.willQoS = options->will.qos;
flags.bits.willRetain = options->will.retained;
}
if (options->username.cstring || options->username.lenstring.data)
flags.bits.username = 1;
if (options->password.cstring || options->password.lenstring.data)
flags.bits.password = 1;
writeChar(&ptr, flags.all);
writeInt(&ptr, options->keepAliveInterval);
writeMQTTString(&ptr, options->clientID);
if (options->willFlag)
{
writeMQTTString(&ptr, options->will.topicName);
writeMQTTString(&ptr, options->will.message);
}
if (flags.bits.username)
writeMQTTString(&ptr, options->username);
if (flags.bits.password)
writeMQTTString(&ptr, options->password);
rc = ptr - buf;
exit: FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
flags.all = readChar(&curdata);
*sessionPresent = flags.bits.sessionpresent;
*connack_rc = readChar(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @return serialized length, or error if 0
*/
int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = packettype;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, DISCONNECT);
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, PINGREQ);
}

View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? a : b)
/**
* Validates MQTT protocol name and version combinations
* @param protocol the MQTT protocol name as an MQTTString
* @param version the MQTT protocol version number, as in the connect packet
* @return correct MQTT combination? 1 is true, 0 is false
*/
int MQTTPacket_checkVersion(MQTTString* protocol, int version)
{
int rc = 0;
if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
min(6, protocol->lenstring.len)) == 0)
rc = 1;
else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
min(4, protocol->lenstring.len)) == 0)
rc = 1;
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connect data structure
* @param data the connect data structure to be filled out
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
{
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
unsigned char* curdata = buf;
unsigned char* enddata = &buf[len];
int rc = 0;
MQTTString Protocol;
int version;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNECT)
goto exit;
curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
version = (int)readChar(&curdata); /* Protocol version */
/* If we don't recognize the protocol version, we don't parse the connect packet on the
* basis that we don't know what the format will be.
*/
if (MQTTPacket_checkVersion(&Protocol, version))
{
flags.all = readChar(&curdata);
data->cleansession = flags.bits.cleansession;
data->keepAliveInterval = readInt(&curdata);
if (!readMQTTLenString(&data->clientID, &curdata, enddata))
goto exit;
data->willFlag = flags.bits.will;
if (flags.bits.will)
{
data->will.qos = flags.bits.willQoS;
data->will.retained = flags.bits.willRetain;
if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
!readMQTTLenString(&data->will.message, &curdata, enddata))
goto exit;
}
if (flags.bits.username)
{
if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
goto exit; /* username flag set, but no username supplied - invalid */
if (flags.bits.password &&
(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
goto exit; /* password flag set, but no password supplied - invalid */
}
else if (flags.bits.password)
goto exit; /* password flag set without username - invalid */
rc = 1;
}
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the connack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param connack_rc the integer connack return code to be used
* @param sessionPresent the MQTT 3.1.1 sessionPresent flag
* @return serialized length, or error if 0
*/
int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
flags.all = 0;
flags.bits.sessionpresent = sessionPresent;
writeChar(&ptr, flags.all);
writeChar(&ptr, connack_rc);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? 1 : 0)
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned integer - the MQTT dup flag
* @param qos returned integer - the MQTT QoS value
* @param retained returned integer - the MQTT retained flag
* @param packetid returned integer - the MQTT packet identifier
* @param topicName returned MQTTString - the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned integer - the length of the MQTT payload
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success
*/
int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != PUBLISH)
goto exit;
*dup = header.bits.dup;
*qos = header.bits.qos;
*retained = header.bits.retain;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (!readMQTTLenString(topicName, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
if (*qos > 0)
*packetid = readInt(&curdata);
*payloadlen = enddata - curdata;
*payload = curdata;
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into an ack
* @param packettype returned integer - the MQTT packet type
* @param dup returned integer - the MQTT dup flag
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
*dup = header.bits.dup;
*packettype = header.bits.type;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,262 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
const char* MQTTPacket_names[] =
{
"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
"PINGREQ", "PINGRESP", "DISCONNECT"
};
const char* MQTTPacket_getName(unsigned short packetid)
{
return MQTTPacket_names[packetid];
}
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
{
int strindex = 0;
strindex = snprintf(strbuf, strbuflen,
"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
(int)data->cleansession, data->keepAliveInterval);
if (data->willFlag)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
data->will.qos, data->will.retained,
data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
data->will.message.lenstring.len, data->will.message.lenstring.data);
if (data->username.lenstring.data && data->username.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
if (data->password.lenstring.data && data->password.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
return strindex;
}
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
{
int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
return strindex;
}
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
{
int strindex = snprintf(strbuf, strbuflen,
"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
dup, qos, retained, packetid,
(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
return strindex;
}
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
if (dup)
strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
return strindex;
}
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
return snprintf(strbuf, strbuflen,
"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
requestedQoSs[0]);
}
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
{
return snprintf(strbuf, strbuflen,
"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
}
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
return snprintf(strbuf, strbuflen,
"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
}
#if defined(MQTT_CLIENT)
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
int strindex = 0;
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNACK:
{
unsigned char sessionPresent, connack_rc;
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBACK:
{
unsigned short packetid;
int maxcount = 1, count = 0;
int grantedQoSs[1];
if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
}
break;
case UNSUBACK:
{
unsigned short packetid;
if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
return strbuf;
}
#endif
#if defined(MQTT_SERVER)
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
int strindex = 0;
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNECT:
{
MQTTPacket_connectData data;
int rc;
if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
int requestedQoSs[1];
if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
topicFilters, requestedQoSs, buf, buflen) == 1)
strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
}
break;
case UNSUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
strindex = MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
strbuf[strbuflen] = '\0';
return strbuf;
}
#endif

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#if !defined(MQTTFORMAT_H)
#define MQTTFORMAT_H
#include "StackTrace.h"
#include "MQTTPacket.h"
const char* MQTTPacket_getName(unsigned short packetid);
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[]);
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
#endif

View File

@ -0,0 +1,412 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Sergio R. Caprile - non-blocking packet read functions for stream transport
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
/**
* Encodes the message length according to the MQTT algorithm
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
* @return the number of bytes written to buffer
*/
int MQTTPacket_encode(unsigned char* buf, int length)
{
int rc = 0;
FUNC_ENTRY;
do
{
char d = length % 128;
length /= 128;
/* if there are more digits to encode, set the top bit of this digit */
if (length > 0)
d |= 0x80;
buf[rc++] = d;
} while (length > 0);
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm
* @param getcharfn pointer to function to read the next character from the data source
* @param value the decoded length returned
* @return the number of bytes read from the socket
*/
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
{
unsigned char c;
int multiplier = 1;
int len = 0;
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
FUNC_ENTRY;
*value = 0;
do
{
int rc = MQTTPACKET_READ_ERROR;
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
{
rc = MQTTPACKET_READ_ERROR; /* bad data */
goto exit;
}
rc = (*getcharfn)(&c, 1);
if (rc != 1)
goto exit;
*value += (c & 127) * multiplier;
multiplier *= 128;
} while ((c & 128) != 0);
exit:
FUNC_EXIT_RC(len);
return len;
}
int MQTTPacket_len(int rem_len)
{
rem_len += 1; /* header byte */
/* now remaining_length field */
if (rem_len < 128)
rem_len += 1;
else if (rem_len < 16384)
rem_len += 2;
else if (rem_len < 2097151)
rem_len += 3;
else
rem_len += 4;
return rem_len;
}
static unsigned char* bufptr;
int bufchar(unsigned char* c, int count)
{
int i;
for (i = 0; i < count; ++i)
*c = *bufptr++;
return count;
}
int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
{
bufptr = buf;
return MQTTPacket_decode(bufchar, value);
}
/**
* Calculates an integer from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the integer value calculated
*/
int readInt(unsigned char** pptr)
{
unsigned char* ptr = *pptr;
int len = 256*(*ptr) + (*(ptr+1));
*pptr += 2;
return len;
}
/**
* Reads one character from the input buffer.
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
char readChar(unsigned char** pptr)
{
char c = **pptr;
(*pptr)++;
return c;
}
/**
* Writes one character to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
void writeChar(unsigned char** pptr, char c)
{
**pptr = c;
(*pptr)++;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writeInt(unsigned char** pptr, int anInt)
{
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param string the C string to write
*/
void writeCString(unsigned char** pptr, const char* string)
{
int len = strlen(string);
writeInt(pptr, len);
memcpy(*pptr, string, len);
*pptr += len;
}
int getLenStringLen(char* ptr)
{
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
return len;
}
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
{
if (mqttstring.lenstring.len > 0)
{
writeInt(pptr, mqttstring.lenstring.len);
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
*pptr += mqttstring.lenstring.len;
}
else if (mqttstring.cstring)
writeCString(pptr, mqttstring.cstring);
else
writeInt(pptr, 0);
}
/**
* @param mqttstring the MQTTString structure into which the data is to be read
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return 1 if successful, 0 if not
*/
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
{
int rc = 0;
FUNC_ENTRY;
/* the first two bytes are the length of the string */
if (enddata - (*pptr) > 1) /* enough length to read the integer? */
{
mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
{
mqttstring->lenstring.data = (char*)*pptr;
*pptr += mqttstring->lenstring.len;
rc = 1;
}
}
mqttstring->cstring = NULL;
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
* @param mqttstring the string to return the length of
* @return the length of the string
*/
int MQTTstrlen(MQTTString mqttstring)
{
int rc = 0;
if (mqttstring.cstring)
rc = strlen(mqttstring.cstring);
else
rc = mqttstring.lenstring.len;
return rc;
}
/**
* Compares an MQTTString to a C string
* @param a the MQTTString to compare
* @param bptr the C string to compare
* @return boolean - equal or not
*/
int MQTTPacket_equals(MQTTString* a, char* bptr)
{
int alen = 0,
blen = 0;
char *aptr;
if (a->cstring)
{
aptr = a->cstring;
alen = strlen(a->cstring);
}
else
{
aptr = a->lenstring.data;
alen = a->lenstring.len;
}
blen = strlen(bptr);
return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
}
/**
* Helper function to read packet data from some source into a buffer
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param getfn pointer to a function which will read any number of bytes from the needed source
* @return integer MQTT packet type, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
{
int rc = -1;
MQTTHeader header = {0};
int len = 0;
int rem_len = 0;
/* 1. read the header byte. This has the packet type in it */
if ((*getfn)(buf, 1) != 1)
goto exit;
len = 1;
/* 2. read the remaining length. This is variable in itself */
MQTTPacket_decode(getfn, &rem_len);
len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
if((rem_len + len) > buflen)
goto exit;
if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
goto exit;
header.byte = buf[0];
rc = header.bits.type;
exit:
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm, non-blocking
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @param value the decoded length returned
* @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
*/
static int MQTTPacket_decodenb(MQTTTransport *trp)
{
unsigned char c;
int rc = MQTTPACKET_READ_ERROR;
FUNC_ENTRY;
if(trp->len == 0){ /* initialize on first call */
trp->multiplier = 1;
trp->rem_len = 0;
}
do {
int frc;
if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
goto exit;
if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
goto exit;
if (frc == 0){
rc = 0;
goto exit;
}
++(trp->len);
trp->rem_len += (c & 127) * trp->multiplier;
trp->multiplier *= 128;
} while ((c & 128) != 0);
rc = trp->len;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Helper function to read packet data from some source into a buffer, non-blocking
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @return integer MQTT packet type, 0 for call again, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
{
int rc = -1, frc;
MQTTHeader header = {0};
switch(trp->state){
default:
trp->state = 0;
/*FALLTHROUGH*/
case 0:
/* read the header byte. This has the packet type in it */
if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->len = 0;
++trp->state;
/*FALLTHROUGH*/
/* read the remaining length. This is variable in itself */
case 1:
if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
goto exit;
if(frc == 0)
return 0;
trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
if((trp->rem_len + trp->len) > buflen)
goto exit;
++trp->state;
/*FALLTHROUGH*/
case 2:
if(trp->rem_len){
/* read the rest of the buffer using a callback to supply the rest of the data */
if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->rem_len -= frc;
trp->len += frc;
if(trp->rem_len)
return 0;
}
header.byte = buf[0];
rc = header.bits.type;
break;
}
exit:
trp->state = 0;
return rc;
}

View File

@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPACKET_H_
#define MQTTPACKET_H_
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#if defined(WIN32_DLL) || defined(WIN64_DLL)
#define DLLImport __declspec(dllimport)
#define DLLExport __declspec(dllexport)
#elif defined(LINUX_SO)
#define DLLImport extern
#define DLLExport __attribute__ ((visibility ("default")))
#else
#define DLLImport
#define DLLExport
#endif
enum errors
{
MQTTPACKET_BUFFER_TOO_SHORT = -2,
MQTTPACKET_READ_ERROR = -1,
MQTTPACKET_READ_COMPLETE
};
enum msgTypes
{
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
PINGREQ, PINGRESP, DISCONNECT
};
/**
* Bitfields for the MQTT header byte.
*/
typedef union
{
unsigned char byte; /**< the whole byte */
#if defined(REVERSED)
struct
{
unsigned int type : 4; /**< message type nibble */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int retain : 1; /**< retained flag bit */
} bits;
#else
struct
{
unsigned int retain : 1; /**< retained flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int type : 4; /**< message type nibble */
} bits;
#endif
} MQTTHeader;
typedef struct
{
int len;
char* data;
} MQTTLenString;
typedef struct
{
char* cstring;
MQTTLenString lenstring;
} MQTTString;
#define MQTTString_initializer {NULL, {0, NULL}}
int MQTTstrlen(MQTTString mqttstring);
#include "MQTTConnect.h"
#include "MQTTPublish.h"
#include "MQTTSubscribe.h"
#include "MQTTUnsubscribe.h"
#include "MQTTFormat.h"
DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
int MQTTPacket_len(int rem_len);
DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
int readInt(unsigned char** pptr);
char readChar(unsigned char** pptr);
void writeChar(unsigned char** pptr, char c);
void writeInt(unsigned char** pptr, int anInt);
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
void writeCString(unsigned char** pptr, const char* string);
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
typedef struct {
int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
void *sck; /* pointer to whatever the system may use to identify the transport */
int multiplier;
int rem_len;
int len;
char state;
}MQTTTransport;
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
#endif /* MQTTPACKET_H_ */

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPUBLISH_H_
#define MQTTPUBLISH_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen);
DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
#endif /* MQTTPUBLISH_H_ */

View File

@ -0,0 +1,169 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
* @param topicName the topic name to be used in the publish
* @param payloadlen the length of the payload to be sent
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
{
int len = 0;
len += 2 + MQTTstrlen(topicName) + payloadlen;
if (qos > 0)
len += 2; /* packetid */
return len;
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param qos integer - the MQTT QoS value
* @param retained integer - the MQTT retained flag
* @param packetid integer - the MQTT packet identifier
* @param topicName MQTTString - the MQTT topic in the publish
* @param payload byte buffer - the MQTT publish payload
* @param payloadlen integer - the length of the MQTT payload
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = PUBLISH;
header.bits.dup = dup;
header.bits.qos = qos;
header.bits.retain = retained;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeMQTTString(&ptr, topicName);
if (qos > 0)
writeInt(&ptr, packetid);
memcpy(ptr, payload, payloadlen);
ptr += payloadlen;
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the ack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param type the MQTT packet type
* @param dup the MQTT dup flag
* @param packetid the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 4)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = packettype;
header.bits.dup = dup;
header.bits.qos = (packettype == PUBREL) ? 1 : 0;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a puback packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
}

View File

@ -0,0 +1,46 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 20:15:32
* @LastEditTime: 2019-12-20 20:37:31
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTSUBSCRIBE_H_
#define MQTTSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[], int requestedQoSs[]);
DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
#endif /* MQTTSUBSCRIBE_H_ */

View File

@ -0,0 +1,137 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
return len;
}
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied bufferr
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters and reqQos arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
{
writeMQTTString(&ptr, topicFilters[i]);
writeChar(&ptr, requestedQoSs[i]);
}
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into suback data
* @param packetid returned integer - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the grantedQoSs array
* @param count returned integer - number of members in the grantedQoSs array
* @param grantedQoSs returned array of integers - the granted qualities of service
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (*count > maxcount)
{
rc = -1;
goto exit;
}
grantedQoSs[(*count)++] = readChar(&curdata);
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,112 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into subscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
int requestedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = -1;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
goto exit;
requestedQoSs[*count] = readChar(&curdata);
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied suback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the grantedQoSs array
* @param grantedQoSs - array of granted QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
int i;
FUNC_ENTRY;
if (buflen < 2 + count)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeChar(&ptr, grantedQoSs[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTUNSUBSCRIBE_H_
#define MQTTUNSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
unsigned char* buf, int len);
DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
#endif /* MQTTUNSUBSCRIBE_H_ */

View File

@ -0,0 +1,106 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
return len;
}
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param topicFilters - array of topic filter names
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = -1;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeMQTTString(&ptr, topicFilters[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into unsuback data
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
{
unsigned char type = 0;
unsigned char dup = 0;
int rc = 0;
FUNC_ENTRY;
rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
if (type == UNSUBACK)
rc = 1;
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,102 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into unsubscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
unsigned char* buf, int len)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != UNSUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied unsuback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for bug #434081
*******************************************************************************/
#ifndef STACKTRACE_H_
#define STACKTRACE_H_
#include <stdio.h>
#define NOSTACKTRACE 1
#if defined(NOSTACKTRACE)
#define FUNC_ENTRY
#define FUNC_ENTRY_NOLOG
#define FUNC_ENTRY_MED
#define FUNC_ENTRY_MAX
#define FUNC_EXIT
#define FUNC_EXIT_NOLOG
#define FUNC_EXIT_MED
#define FUNC_EXIT_MAX
#define FUNC_EXIT_RC(x)
#define FUNC_EXIT_MED_RC(x)
#define FUNC_EXIT_MAX_RC(x)
#else
#if defined(WIN32)
#define inline __inline
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
#else
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
void StackTrace_entry(const char* name, int line, int trace);
void StackTrace_exit(const char* name, int line, void* return_value, int trace);
void StackTrace_printStack(FILE* dest);
char* StackTrace_get(unsigned long);
#endif
#endif
#endif /* STACKTRACE_H_ */

View File

@ -0,0 +1,46 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @LastEditTime: 2020-06-17 19:31:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_CONFIG_H_
#define _MQTT_CONFIG_H_
// #define MQTT_LOG_IS_SALOF
#define MQTT_LOG_LEVEL MQTT_LOG_INFO_LEVEL //MQTT_LOG_WARN_LEVEL MQTT_LOG_DEBUG_LEVEL
#ifdef MQTT_LOG_IS_SALOF
#define SALOF_USING_LOG (1U)
#define SALOF_USING_SALOF (1U)
#define SALOF_LOG_LEVEL MQTT_LOG_LEVEL
#define SALOF_OS SALOF_USING_LINUX
#define SALOF_USING_IDLE_HOOK (0U)
#define SALOF_LOG_COLOR (1U)
#define SALOF_LOG_TS (0U)
#define SALOF_LOG_TAR (0U)
#define SALOF_BUFF_SIZE 512
#define SALOF_FIFO_SIZE 4096
#define SALOF_TASK_STACK_SIZE 1024
#define SALOF_TASK_TICK 50
#endif
#define MQTT_MAX_PACKET_ID (0xFFFF - 1)
#define MQTT_TOPIC_LEN_MAX 64
#define MQTT_ACK_HANDLER_NUM_MAX 64
#define MQTT_DEFAULT_BUF_SIZE 1024
#define MQTT_DEFAULT_CMD_TIMEOUT 5000
#define MQTT_MAX_CMD_TIMEOUT 20000
#define MQTT_MIN_CMD_TIMEOUT 1000
#define MQTT_KEEP_ALIVE_INTERVAL 50 // unit: second
#define MQTT_VERSION 4 // 4 is mqtt 3.1.1
#define MQTT_RECONNECT_DEFAULT_DURATION 1000
#define MQTT_THREAD_STACK_SIZE 2048
#define MQTT_THREAD_PRIO 5
#define MQTT_THREAD_TICK 50
#define MQTT_NETWORK_TYPE_NO_TLS
#endif /* _MQTT_CONFIG_H_ */

View File

@ -0,0 +1,88 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 23:22:10
* @FilePath : /mqttclient/mqttclient/mqtt_defconfig.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-02-25 03:36:09
* @LastEditTime: 2020-06-17 19:59:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _DEFCONFIG_H_
#define _DEFCONFIG_H_
#include "mqtt_config.h"
#ifndef MQTT_LOG_LEVEL
#define MQTT_LOG_LEVEL MQTT_LOG_DEBUG_LEVEL //MQTT_LOG_WARN_LEVEL MQTT_LOG_DEBUG_LEVEL
#endif // !MQTT_LOG_LEVEL
#ifndef MQTT_MAX_PACKET_ID
#define MQTT_MAX_PACKET_ID (0xFFFF - 1)
#endif // !MQTT_MAX_PACKET_ID
#ifndef MQTT_TOPIC_LEN_MAX
#define MQTT_TOPIC_LEN_MAX 64
#endif // !MQTT_TOPIC_LEN_MAX
#ifndef MQTT_ACK_HANDLER_NUM_MAX
#define MQTT_ACK_HANDLER_NUM_MAX 64
#endif // !MQTT_ACK_HANDLER_NUM_MAX
#ifndef MQTT_DEFAULT_BUF_SIZE
#define MQTT_DEFAULT_BUF_SIZE 1024
#endif // !MQTT_DEFAULT_BUF_SIZE
#ifndef MQTT_DEFAULT_CMD_TIMEOUT
#define MQTT_DEFAULT_CMD_TIMEOUT 4000
#endif // !MQTT_DEFAULT_CMD_TIMEOUT
#ifndef MQTT_MAX_CMD_TIMEOUT
#define MQTT_MAX_CMD_TIMEOUT 20000
#endif // !MQTT_MAX_CMD_TIMEOUT
#ifndef MQTT_MIN_CMD_TIMEOUT
#define MQTT_MIN_CMD_TIMEOUT 1000
#endif // !MQTT_MIN_CMD_TIMEOUT
#ifndef MQTT_KEEP_ALIVE_INTERVAL
#define MQTT_KEEP_ALIVE_INTERVAL 100 // unit: second
#endif // !MQTT_KEEP_ALIVE_INTERVAL
#ifndef MQTT_VERSION
#define MQTT_VERSION 4 // 4 is mqtt 3.1.1
#endif // !MQTT_VERSION
#ifndef MQTT_RECONNECT_DEFAULT_DURATION
#define MQTT_RECONNECT_DEFAULT_DURATION 1000
#endif // !MQTT_RECONNECT_DEFAULT_DURATION
#ifndef MQTT_THREAD_STACK_SIZE
#define MQTT_THREAD_STACK_SIZE 4096
#endif // !MQTT_THREAD_STACK_SIZE
#ifndef MQTT_THREAD_PRIO
#define MQTT_THREAD_PRIO 5
#endif // !MQTT_THREAD_PRIO
#ifndef MQTT_THREAD_TICK
#define MQTT_THREAD_TICK 50
#endif // !MQTT_THREAD_TICK
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#ifndef MQTT_TLS_HANDSHAKE_TIMEOUT
#define MQTT_TLS_HANDSHAKE_TIMEOUT (5 * 1000)
#endif // !MQTT_TLS_HANDSHAKE_TIMEOUT
#endif /* MQTT_NETWORK_TYPE_NO_TLS */
#endif /* _DEFCONFIG_H_ */

View File

@ -0,0 +1,53 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 00:42:16
* @LastEditTime: 2020-10-17 14:16:15
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_ERROR_H_
#define _MQTT_ERROR_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum mqtt_error {
MQTT_SSL_CERT_ERROR = -0x001C, /* cetr parse failed */
MQTT_SOCKET_FAILED_ERROR = -0x001B, /* socket fd failed */
MQTT_SOCKET_UNKNOWN_HOST_ERROR = -0x001A, /* socket unknown host ip or domain */
MQTT_SET_PUBLISH_DUP_FAILED_ERROR = -0x0019, /* mqtt publish packet set udp bit failed */
MQTT_CLEAN_SESSION_ERROR = -0x0018, /* mqtt clean session error */
MQTT_ACK_NODE_IS_EXIST_ERROR = -0x0017, /* mqtt ack list is exist ack node */
MQTT_ACK_HANDLER_NUM_TOO_MUCH_ERROR = -0x0016, /* mqtt ack handler number is too much */
MQTT_RESUBSCRIBE_ERROR = -0x0015, /* mqtt resubscribe error */
MQTT_SUBSCRIBE_ERROR = -0x0014, /* mqtt subscribe error */
MQTT_SEND_PACKET_ERROR = -0x0013, /* mqtt send a packet */
MQTT_SERIALIZE_PUBLISH_ACK_PACKET_ERROR = -0x0012, /* mqtt serialize publish ack packet error */
MQTT_PUBLISH_PACKET_ERROR = -0x0011, /* mqtt publish packet error */
MQTT_RECONNECT_TIMEOUT_ERROR = -0x0010, /* mqtt try reconnect, but timeout */
MQTT_SUBSCRIBE_NOT_ACK_ERROR = -0x000F, /* mqtt subscribe, but not ack */
MQTT_NOT_CONNECT_ERROR = -0x000E, /* mqtt not connect */
MQTT_SUBSCRIBE_ACK_PACKET_ERROR = -0x000D, /* mqtt subscribe, but ack packet error */
MQTT_UNSUBSCRIBE_ACK_PACKET_ERROR = -0x000C, /* mqtt unsubscribe, but ack packet error */
MQTT_PUBLISH_ACK_PACKET_ERROR = -0x000B, /* mqtt pubilsh ack packet error */
MQTT_PUBLISH_ACK_TYPE_ERROR = -0x000A, /* mqtt pubilsh ack type error */
MQTT_PUBREC_PACKET_ERROR = -0x0009, /* mqtt pubrec packet error */
MQTT_BUFFER_TOO_SHORT_ERROR = -0x0008, /* mqtt buffer too short */
MQTT_NOTHING_TO_READ_ERROR = -0x0007, /* mqtt nothing to read */
MQTT_SUBSCRIBE_QOS_ERROR = -0x0006, /* mqtt subsrcibe qos error */
MQTT_BUFFER_OVERFLOW_ERROR = -0x0005, /* mqtt buffer overflow */
MQTT_CONNECT_FAILED_ERROR = -0x0004, /* mqtt connect failed */
MQTT_MEM_NOT_ENOUGH_ERROR = -0x0003, /* mqtt memory not enough */
MQTT_NULL_VALUE_ERROR = -0x0002, /* mqtt value is null */
MQTT_FAILED_ERROR = -0x0001, /* failed */
MQTT_SUCCESS_ERROR = 0x0000 /* success */
} mqtt_error_t;
#define RETURN_ERROR(x) { return x; }
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,72 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-11 22:46:33
* @LastEditTime: 2020-04-27 23:28:12
* @Description: the following code references TencentOS tiny, please keep the author information and source code according to the license.
*/
# include "mqtt_list.h"
static void _mqtt_list_add(mqtt_list_t *node, mqtt_list_t *prev, mqtt_list_t *next)
{
next->prev = node;
node->next = next;
node->prev = prev;
prev->next = node;
}
static void _mqtt_list_del(mqtt_list_t *prev, mqtt_list_t *next)
{
next->prev = prev;
prev->next = next;
}
static void _mqtt_list_del_entry(mqtt_list_t *entry)
{
_mqtt_list_del(entry->prev, entry->next);
}
void mqtt_list_init(mqtt_list_t *list)
{
list->next = list;
list->prev = list;
}
void mqtt_list_add(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_add(node, list, list->next);
}
void mqtt_list_add_tail(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_add(node, list->prev, list);
}
void mqtt_list_del(mqtt_list_t *entry)
{
_mqtt_list_del(entry->prev, entry->next);
}
void mqtt_list_del_init(mqtt_list_t *entry)
{
_mqtt_list_del_entry(entry);
mqtt_list_init(entry);
}
void mqtt_list_move(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_del_entry(node);
mqtt_list_add(node, list);
}
void mqtt_list_move_tail(mqtt_list_t *node, mqtt_list_t *list)
{
_mqtt_list_del_entry(node);
mqtt_list_add_tail(node, list);
}
int mqtt_list_is_empty(mqtt_list_t *list)
{
return list->next == list;
}

View File

@ -0,0 +1,70 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-11 22:47:55
* @LastEditTime: 2020-10-17 14:18:02
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_LIST_H_
#define _MQTT_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mqtt_list_node {
struct mqtt_list_node *next;
struct mqtt_list_node *prev;
} mqtt_list_t;
#define OFFSET_OF_FIELD(type, field) \
((size_t)&(((type *)0)->field))
#define CONTAINER_OF_FIELD(ptr, type, field) \
((type *)((unsigned char *)(ptr) - OFFSET_OF_FIELD(type, field)))
#define LIST_NODE(node) \
{ &(node), &(node) }
#define LIST_DEFINE(list) \
mqtt_list_t list = { &(list), &(list) }
#define LIST_ENTRY(list, type, field) \
CONTAINER_OF_FIELD(list, type, field)
#define LIST_FIRST_ENTRY(list, type, field) \
LIST_ENTRY((list)->next, type, field)
#define LIST_FIRST_ENTRY_OR_NULL(list, type, field) \
(mqtt_list_is_empty(list) ? NULL : LIST_FIRST_ENTRY(list, type, field))
#define LIST_FOR_EACH(curr, list) \
for (curr = (list)->next; curr != (list); curr = curr->next)
#define LIST_FOR_EACH_PREV(curr, list) \
for (curr = (list)->prev; curr != (list); curr = curr->prev)
#define LIST_FOR_EACH_SAFE(curr, next, list) \
for (curr = (list)->next, next = curr->next; curr != (list); \
curr = next, next = curr->next)
#define LIST_FOR_EACH_PREV_SAFE(curr, next, list) \
for (curr = (list)->prev, next = curr->prev; \
curr != (list); \
curr = next, next = curr->prev)
void mqtt_list_init(mqtt_list_t *list);
void mqtt_list_add(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_add_tail(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_del(mqtt_list_t *entry);
void mqtt_list_del_init(mqtt_list_t *entry);
void mqtt_list_move(mqtt_list_t *node, mqtt_list_t *list);
void mqtt_list_move_tail(mqtt_list_t *node, mqtt_list_t *list);
int mqtt_list_is_empty(mqtt_list_t *list);
#ifdef __cplusplus
}
#endif
#endif /* _LIST_H_ */

View File

@ -0,0 +1,71 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-27 03:25:58
* @LastEditTime: 2020-10-17 14:15:55
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTT_LOG_H_
#define _MQTT_LOG_H_
#include "mqtt_defconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MQTT_LOG_BASE_LEVEL (0)
#define MQTT_LOG_ERR_LEVEL (MQTT_LOG_BASE_LEVEL + 1)
#define MQTT_LOG_WARN_LEVEL (MQTT_LOG_ERR_LEVEL + 1)
#define MQTT_LOG_INFO_LEVEL (MQTT_LOG_WARN_LEVEL + 1)
#define MQTT_LOG_DEBUG_LEVEL (MQTT_LOG_INFO_LEVEL + 1)
#ifdef MQTT_LOG_IS_SALOF
#include "salof.h"
#define MQTT_LOG_D(fmt, ...) SALOF_LOG_DEBUG(fmt, ##__VA_ARGS__)
#define MQTT_LOG_I(fmt, ...) SALOF_LOG_INFO(fmt, ##__VA_ARGS__)
#define MQTT_LOG_W(fmt, ...) SALOF_LOG_WARN(fmt, ##__VA_ARGS__)
#define MQTT_LOG_E(fmt, ...) SALOF_LOG_ERR(fmt, ##__VA_ARGS__)
#define mqtt_log_init salof_init
#else
#include <stdio.h>
#if MQTT_LOG_LEVEL < MQTT_LOG_DEBUG_LEVEL
#define MQTT_LOG_D(fmt, ...)
#else
#define MQTT_LOG_D(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_INFO_LEVEL
#define MQTT_LOG_I(fmt, ...)
#else
#define MQTT_LOG_I(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_WARN_LEVEL
#define MQTT_LOG_W(fmt, ...)
#else
#define MQTT_LOG_W(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_ERR_LEVEL
#define MQTT_LOG_E(fmt, ...)
#else
#define MQTT_LOG_E(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#if MQTT_LOG_LEVEL < MQTT_LOG_BASE_LEVEL
#define MQTT_LOG(fmt, ...)
#else
#define MQTT_LOG(fmt, ...) { printf(fmt, ##__VA_ARGS__); printf("\n");}
#endif
#define mqtt_log_init()
#endif
#ifdef __cplusplus
}
#endif
#endif /* _LOG_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,180 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:31:25
* @LastEditTime : 2022-06-11 22:45:02
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _MQTTCLIENT_H_
#define _MQTTCLIENT_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "MQTTPacket.h"
#include "mqtt_list.h"
#include "platform_timer.h"
#include "platform_memory.h"
#include "platform_mutex.h"
#include "platform_thread.h"
#include "mqtt_defconfig.h"
#include "network.h"
#include "random.h"
#include "mqtt_error.h"
#include "mqtt_log.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum mqtt_qos {
QOS0 = 0,
QOS1 = 1,
QOS2 = 2,
SUBFAIL = 0x80
} mqtt_qos_t;
typedef enum client_state {
CLIENT_STATE_INVALID = -1,
CLIENT_STATE_INITIALIZED = 0,
CLIENT_STATE_CONNECTED = 1,
CLIENT_STATE_DISCONNECTED = 2,
CLIENT_STATE_CLEAN_SESSION = 3
}client_state_t;
typedef struct mqtt_connack_data {
uint8_t rc;
uint8_t session_present;
} mqtt_connack_data_t;
typedef struct mqtt_message {
mqtt_qos_t qos;
uint8_t retained;
uint8_t dup;
uint16_t id;
size_t payloadlen;
void *payload;
} mqtt_message_t;
typedef struct message_data {
char topic_name[MQTT_TOPIC_LEN_MAX];
mqtt_message_t *message;
} message_data_t;
typedef void (*interceptor_handler_t)(void* client, message_data_t* msg);
typedef void (*message_handler_t)(void* client, message_data_t* msg);
typedef void (*reconnect_handler_t)(void* client, void* reconnect_date);
typedef struct message_handlers {
mqtt_list_t list;
mqtt_qos_t qos;
const char* topic_filter;
message_handler_t handler;
} message_handlers_t;
typedef struct ack_handlers {
mqtt_list_t list;
platform_timer_t timer;
uint32_t type;
uint16_t packet_id;
message_handlers_t *handler;
uint16_t payload_len;
uint8_t *payload;
} ack_handlers_t;
typedef struct mqtt_will_options {
mqtt_qos_t will_qos;
uint8_t will_retained;
char *will_topic;
char *will_message;
} mqtt_will_options_t;
typedef struct mqtt_client {
char *mqtt_client_id;
char *mqtt_user_name;
char *mqtt_password;
char *mqtt_host;
char *mqtt_port;
char *mqtt_ca;
void *mqtt_reconnect_data;
uint8_t *mqtt_read_buf;
uint8_t *mqtt_write_buf;
uint16_t mqtt_keep_alive_interval;
uint16_t mqtt_packet_id;
uint32_t mqtt_will_flag : 1;
uint32_t mqtt_clean_session : 1;
uint32_t mqtt_ping_outstanding : 2;
uint32_t mqtt_version : 4;
uint32_t mqtt_ack_handler_number : 24;
uint32_t mqtt_cmd_timeout;
uint32_t mqtt_read_buf_size;
uint32_t mqtt_write_buf_size;
uint32_t mqtt_reconnect_try_duration;
size_t mqtt_client_id_len;
size_t mqtt_user_name_len;
size_t mqtt_password_len;
mqtt_will_options_t *mqtt_will_options;
client_state_t mqtt_client_state;
platform_mutex_t mqtt_write_lock;
platform_mutex_t mqtt_global_lock;
mqtt_list_t mqtt_msg_handler_list;
mqtt_list_t mqtt_ack_handler_list;
network_t *mqtt_network;
platform_thread_t *mqtt_thread;
platform_timer_t mqtt_last_sent;
platform_timer_t mqtt_last_received;
reconnect_handler_t mqtt_reconnect_handler;
interceptor_handler_t mqtt_interceptor_handler;
} mqtt_client_t;
#define MQTT_ROBUSTNESS_CHECK(item, err) if (!(item)) { \
MQTT_LOG_E("%s:%d %s()... check for error.", __FILE__, __LINE__, __FUNCTION__); \
return err; }
#define MQTT_CLIENT_SET_DEFINE(name, type, res) \
type mqtt_set_##name(mqtt_client_t *c, type t) { \
MQTT_ROBUSTNESS_CHECK((c), res); \
c->mqtt_##name = t; \
return c->mqtt_##name; \
}
#define MQTT_CLIENT_SET_STATEMENT(name, type) \
type mqtt_set_##name(mqtt_client_t *, type);
MQTT_CLIENT_SET_STATEMENT(client_id, char*)
MQTT_CLIENT_SET_STATEMENT(user_name, char*)
MQTT_CLIENT_SET_STATEMENT(password, char*)
MQTT_CLIENT_SET_STATEMENT(host, char*)
MQTT_CLIENT_SET_STATEMENT(port, char*)
MQTT_CLIENT_SET_STATEMENT(ca, char*)
MQTT_CLIENT_SET_STATEMENT(reconnect_data, void*)
MQTT_CLIENT_SET_STATEMENT(keep_alive_interval, uint16_t)
MQTT_CLIENT_SET_STATEMENT(will_flag, uint32_t)
MQTT_CLIENT_SET_STATEMENT(clean_session, uint32_t)
MQTT_CLIENT_SET_STATEMENT(version, uint32_t)
MQTT_CLIENT_SET_STATEMENT(cmd_timeout, uint32_t)
MQTT_CLIENT_SET_STATEMENT(read_buf_size, uint32_t)
MQTT_CLIENT_SET_STATEMENT(write_buf_size, uint32_t)
MQTT_CLIENT_SET_STATEMENT(reconnect_try_duration, uint32_t)
MQTT_CLIENT_SET_STATEMENT(reconnect_handler, reconnect_handler_t)
MQTT_CLIENT_SET_STATEMENT(interceptor_handler, interceptor_handler_t)
void mqtt_sleep_ms(int ms);
mqtt_client_t *mqtt_lease(void);
int mqtt_release(mqtt_client_t* c);
int mqtt_connect(mqtt_client_t* c);
int mqtt_disconnect(mqtt_client_t* c);
int mqtt_keep_alive(mqtt_client_t* c);
int mqtt_subscribe(mqtt_client_t* c, const char* topic_filter, mqtt_qos_t qos, message_handler_t msg_handler);
int mqtt_unsubscribe(mqtt_client_t* c, const char* topic_filter);
int mqtt_publish(mqtt_client_t* c, const char* topic_filter, mqtt_message_t* msg);
int mqtt_list_subscribe_topic(mqtt_client_t* c);
int mqtt_set_will_options(mqtt_client_t* c, char *topic, mqtt_qos_t qos, uint8_t retained, char *message);
#ifdef __cplusplus
}
#endif
#endif /* _MQTTCLIENT_H_ */

View File

@ -0,0 +1,36 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:38:52
* @LastEditTime: 2020-05-25 10:13:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "nettype_tcp.h"
#include "mqtt_log.h"
#include "platform_net_socket.h"
int nettype_tcp_read(network_t *n, unsigned char *read_buf, int len, int timeout)
{
return platform_net_socket_recv_timeout(n->socket, read_buf, len, timeout);
}
int nettype_tcp_write(network_t *n, unsigned char *write_buf, int len, int timeout)
{
return platform_net_socket_write_timeout(n->socket, write_buf, len, timeout);
}
int nettype_tcp_connect(network_t* n)
{
n->socket = platform_net_socket_connect(n->host, n->port, PLATFORM_NET_PROTO_TCP);
if (n->socket < 0)
RETURN_ERROR(n->socket);
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
void nettype_tcp_disconnect(network_t* n)
{
if (NULL != n)
platform_net_socket_close(n->socket);
n->socket = -1;
}

View File

@ -0,0 +1,27 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:39:00
* @LastEditTime: 2020-10-17 14:17:10
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETTYPE_TCP_H_
#define _NETTYPE_TCP_H_
#include "network.h"
#include "mqtt_error.h"
#ifdef __cplusplus
extern "C" {
#endif
int nettype_tcp_read(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tcp_write(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tcp_connect(network_t* n);
void nettype_tcp_disconnect(network_t* n);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,253 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-11 19:45:35
* @LastEditTime: 2020-09-20 14:29:06
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "nettype_tls.h"
#include "platform_net_socket.h"
#include "platform_memory.h"
#include "platform_timer.h"
#include "random.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "mbedtls/platform.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/pk.h"
#if defined(MBEDTLS_X509_CRT_PARSE_C)
static int server_certificate_verify(void *hostname, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
{
if (0 != *flags)
MQTT_LOG_E("%s:%d %s()... server_certificate_verify failed returned 0x%04x\n", __FILE__, __LINE__, __FUNCTION__, *flags);
return *flags;
}
#endif
static int nettype_tls_entropy_source(void *data, uint8_t *output, size_t len, size_t *out_len)
{
uint32_t seed;
(void) data;
seed = random_number();
if (len > sizeof(seed)) {
len = sizeof(seed);
}
memcpy(output, &seed, len);
*out_len = len;
return 0;
}
static int nettype_tls_init(network_t* n, nettype_tls_params_t* nettype_tls_params)
{
int rc = MQTT_SUCCESS_ERROR;
mbedtls_platform_set_calloc_free(platform_memory_calloc, platform_memory_free);
mbedtls_net_init(&(nettype_tls_params->socket_fd));
mbedtls_ssl_init(&(nettype_tls_params->ssl));
mbedtls_ssl_config_init(&(nettype_tls_params->ssl_conf));
mbedtls_ctr_drbg_init(&(nettype_tls_params->ctr_drbg));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt_init(&(nettype_tls_params->ca_cert));
mbedtls_x509_crt_init(&(nettype_tls_params->client_cert));
mbedtls_pk_init(&(nettype_tls_params->private_key));
#endif
mbedtls_entropy_init(&(nettype_tls_params->entropy));
mbedtls_entropy_add_source(&(nettype_tls_params->entropy), nettype_tls_entropy_source, NULL, MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_SOURCE_STRONG);
if ((rc = mbedtls_ctr_drbg_seed(&(nettype_tls_params->ctr_drbg), mbedtls_entropy_func,
&(nettype_tls_params->entropy), NULL, 0)) != 0) {
MQTT_LOG_E("mbedtls_ctr_drbg_seed failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
if ((rc = mbedtls_ssl_config_defaults(&(nettype_tls_params->ssl_conf), MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
MQTT_LOG_E("mbedtls_ssl_config_defaults failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
mbedtls_ssl_conf_rng(&(nettype_tls_params->ssl_conf), mbedtls_ctr_drbg_random, &(nettype_tls_params->ctr_drbg));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if (NULL != n->ca_crt) {
n->ca_crt_len = strlen(n->ca_crt);
if (0 != (rc = (mbedtls_x509_crt_parse(&(nettype_tls_params->ca_cert), (unsigned char *)n->ca_crt,
(n->ca_crt_len + 1))))) {
MQTT_LOG_E("%s:%d %s()... parse ca crt failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
}
mbedtls_ssl_conf_ca_chain(&(nettype_tls_params->ssl_conf), &(nettype_tls_params->ca_cert), NULL);
if ((rc = mbedtls_ssl_conf_own_cert(&(nettype_tls_params->ssl_conf),
&(nettype_tls_params->client_cert), &(nettype_tls_params->private_key))) != 0) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_conf_own_cert failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
mbedtls_ssl_conf_verify(&(nettype_tls_params->ssl_conf), server_certificate_verify, (void *)n->host);
mbedtls_ssl_conf_authmode(&(nettype_tls_params->ssl_conf), MBEDTLS_SSL_VERIFY_REQUIRED);
#endif
mbedtls_ssl_conf_read_timeout(&(nettype_tls_params->ssl_conf), n->timeout_ms);
if ((rc = mbedtls_ssl_setup(&(nettype_tls_params->ssl), &(nettype_tls_params->ssl_conf))) != 0) {
MQTT_LOG_E("mbedtls_ssl_setup failed returned 0x%04x", (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if ((rc = mbedtls_ssl_set_hostname(&(nettype_tls_params->ssl), n->host)) != 0) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_set_hostname failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
RETURN_ERROR(rc);
}
#endif
mbedtls_ssl_set_bio(&(nettype_tls_params->ssl), &(nettype_tls_params->socket_fd), mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
int nettype_tls_connect(network_t* n)
{
int rc;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) platform_memory_alloc(sizeof(nettype_tls_params_t));
if (NULL == nettype_tls_params)
RETURN_ERROR(MQTT_MEM_NOT_ENOUGH_ERROR);
rc = nettype_tls_init(n, nettype_tls_params);
if (MQTT_SUCCESS_ERROR != rc)
goto exit;
if (0 != (rc = mbedtls_net_connect(&(nettype_tls_params->socket_fd), n->host, n->port, MBEDTLS_NET_PROTO_TCP)))
goto exit;
while ((rc = mbedtls_ssl_handshake(&(nettype_tls_params->ssl))) != 0) {
if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) {
MQTT_LOG_E("%s:%d %s()...mbedtls handshake failed returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if (rc == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
MQTT_LOG_E("%s:%d %s()...unable to verify the server's certificate", __FILE__, __LINE__, __FUNCTION__);
}
#endif
goto exit;
}
}
if ((rc = mbedtls_ssl_get_verify_result(&(nettype_tls_params->ssl))) != 0) {
MQTT_LOG_E("%s:%d %s()...mbedtls_ssl_get_verify_result returned 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
goto exit;
}
n->nettype_tls_params = nettype_tls_params;
RETURN_ERROR(MQTT_SUCCESS_ERROR)
exit:
platform_memory_free(nettype_tls_params);
RETURN_ERROR(rc);
}
void nettype_tls_disconnect(network_t* n)
{
int rc = 0;
if (NULL == n)
return;
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
do {
rc = mbedtls_ssl_close_notify(&(nettype_tls_params->ssl));
} while (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE);
mbedtls_net_free(&(nettype_tls_params->socket_fd));
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt_free(&(nettype_tls_params->client_cert));
mbedtls_x509_crt_free(&(nettype_tls_params->ca_cert));
mbedtls_pk_free(&(nettype_tls_params->private_key));
#endif
mbedtls_ssl_free(&(nettype_tls_params->ssl));
mbedtls_ssl_config_free(&(nettype_tls_params->ssl_conf));
mbedtls_ctr_drbg_free(&(nettype_tls_params->ctr_drbg));
mbedtls_entropy_free(&(nettype_tls_params->entropy));
platform_memory_free(nettype_tls_params);
}
int nettype_tls_write(network_t *n, unsigned char *buf, int len, int timeout)
{
int rc = 0;
int write_len = 0;
platform_timer_t timer;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
platform_timer_cutdown(&timer, timeout);
do {
rc = mbedtls_ssl_write(&(nettype_tls_params->ssl), (unsigned char *)(buf + write_len), len - write_len);
if (rc > 0) {
write_len += rc;
} else if ((rc == 0) || ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_TIMEOUT))) {
MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_write failed: 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
break;
}
} while((!platform_timer_is_expired(&timer)) && (write_len < len));
return write_len;
}
int nettype_tls_read(network_t *n, unsigned char *buf, int len, int timeout)
{
int rc = 0;
int read_len = 0;
platform_timer_t timer;
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
nettype_tls_params_t *nettype_tls_params = (nettype_tls_params_t *) n->nettype_tls_params;
platform_timer_cutdown(&timer, timeout);
do {
rc = mbedtls_ssl_read(&(nettype_tls_params->ssl), (unsigned char *)(buf + read_len), len - read_len);
if (rc > 0) {
read_len += rc;
} else if ((rc == 0) || ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_TIMEOUT))) {
// MQTT_LOG_E("%s:%d %s()... mbedtls_ssl_read failed: 0x%04x", __FILE__, __LINE__, __FUNCTION__, (rc < 0 )? -rc : rc);
break;
}
} while((!platform_timer_is_expired(&timer)) && (read_len < len));
return read_len;
}
#endif /* MQTT_NETWORK_TYPE_NO_TLS */

View File

@ -0,0 +1,64 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:48:43
* @FilePath : /mqttclient/network/nettype_tls.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-11 19:45:44
* @LastEditTime: 2020-10-17 14:14:11
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETTYPE_TLS_H_
#define _NETTYPE_TLS_H_
#include "mqtt_defconfig.h"
#include "network.h"
#include "mqtt_error.h"
#include "mqtt_log.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "mbedtls/config.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct nettype_tls_params {
mbedtls_net_context socket_fd; /**< mbed TLS network context. */
mbedtls_entropy_context entropy; /**< mbed TLS entropy. */
mbedtls_ctr_drbg_context ctr_drbg; /**< mbed TLS ctr_drbg. */
mbedtls_ssl_context ssl; /**< mbed TLS control context. */
mbedtls_ssl_config ssl_conf; /**< mbed TLS configuration context. */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt ca_cert; /**< mbed TLS CA certification. */
mbedtls_x509_crt client_cert; /**< mbed TLS Client certification. */
#endif
mbedtls_pk_context private_key; /**< mbed TLS Client key. */
} nettype_tls_params_t;
int nettype_tls_read(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tls_write(network_t *n, unsigned char *buf, int len, int timeout);
int nettype_tls_connect(network_t* n);
void nettype_tls_disconnect(network_t* n);
#endif /* MQTT_NETWORK_TYPE_NO_TLS */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,113 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:30:54
* @LastEditTime: 2020-06-05 17:17:48
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include <string.h>
#include "platform_timer.h"
#include "platform_memory.h"
#include "nettype_tcp.h"
#ifndef MQTT_NETWORK_TYPE_NO_TLS
#include "nettype_tls.h"
#endif
int network_read(network_t *n, unsigned char *buf, int len, int timeout)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_read(n, buf, len, timeout);
#endif
return nettype_tcp_read(n, buf, len, timeout);
}
int network_write(network_t *n, unsigned char *buf, int len, int timeout)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_write(n, buf, len, timeout);
#endif
return nettype_tcp_write(n, buf, len, timeout);
}
int network_connect(network_t *n)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
return nettype_tls_connect(n);
#endif
return nettype_tcp_connect(n);
}
void network_disconnect(network_t *n)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if (n->channel)
nettype_tls_disconnect(n);
else
#endif
nettype_tcp_disconnect(n);
}
int network_init(network_t *n, const char *host, const char *port, const char *ca)
{
if (NULL == n)
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->socket = -1;
n->host = host;
n->port = port;
#ifndef MQTT_NETWORK_TYPE_NO_TLS
n->channel = 0;
if (NULL != ca) {
network_set_ca(n, ca);
}
#endif
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
void network_release(network_t* n)
{
if (n->socket >= 0)
network_disconnect(n);
memset(n, 0, sizeof(network_t));
}
void network_set_channel(network_t *n, int channel)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
n->channel = channel;
#endif
}
int network_set_ca(network_t *n, const char *ca)
{
#ifndef MQTT_NETWORK_TYPE_NO_TLS
if ((NULL == n) || (NULL == ca))
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->ca_crt = ca;
n->ca_crt_len = strlen(ca);
n->channel = NETWORK_CHANNEL_TLS;
n->timeout_ms = MQTT_TLS_HANDSHAKE_TIMEOUT;
#endif
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}
int network_set_host_port(network_t* n, char *host, char *port)
{
if (!(n && host && port))
RETURN_ERROR(MQTT_NULL_VALUE_ERROR);
n->host = host;
n->port = port;
RETURN_ERROR(MQTT_SUCCESS_ERROR);
}

View File

@ -0,0 +1,47 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-09 21:31:02
* @LastEditTime: 2020-10-17 14:14:41
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include "mqtt_defconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NETWORK_CHANNEL_TCP 0
#define NETWORK_CHANNEL_TLS 1
typedef struct network {
const char *host;
const char *port;
int socket;
#ifndef MQTT_NETWORK_TYPE_NO_TLS
int channel; /* tcp or tls */
const char *ca_crt;
unsigned int ca_crt_len;
unsigned int timeout_ms; // SSL handshake timeout in millisecond
void *nettype_tls_params;
#endif
} network_t;
int network_init(network_t *n, const char *host, const char *port, const char *ca);
int network_set_ca(network_t *n, const char *ca);
void network_set_channel(network_t *n, int channel);
int network_set_host_port(network_t* n, char *host, char *port);
int network_read(network_t* n, unsigned char* buf, int len, int timeout);
int network_write(network_t* n, unsigned char* buf, int len, int timeout);
int network_connect(network_t* n);
void network_disconnect(network_t *n);
void network_release(network_t* n);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,26 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-14 22:02:07
* @LastEditTime: 2020-02-19 20:26:04
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_memory.h"
void *platform_memory_alloc(size_t size)
{
return malloc(size);
}
void *platform_memory_calloc(size_t num, size_t size)
{
return calloc(num, size);
}
void platform_memory_free(void *ptr)
{
free(ptr);
}

View File

@ -0,0 +1,26 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-14 22:06:35
* @LastEditTime: 2020-10-17 14:17:24
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_MEMORY_H_
#define _PLATFORM_MEMORY_H_
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void *platform_memory_alloc(size_t size);
void *platform_memory_calloc(size_t num, size_t size);
void platform_memory_free(void *ptr);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,33 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:27:19
* @LastEditTime: 2020-02-23 15:01:06
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_mutex.h"
int platform_mutex_init(platform_mutex_t* m)
{
return pthread_mutex_init(&(m->mutex), NULL);
}
int platform_mutex_lock(platform_mutex_t* m)
{
return pthread_mutex_lock(&(m->mutex));
}
int platform_mutex_trylock(platform_mutex_t* m)
{
return pthread_mutex_trylock(&(m->mutex));
}
int platform_mutex_unlock(platform_mutex_t* m)
{
return pthread_mutex_unlock(&(m->mutex));
}
int platform_mutex_destroy(platform_mutex_t* m)
{
return pthread_mutex_destroy(&(m->mutex));
}

View File

@ -0,0 +1,30 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:31:33
* @LastEditTime: 2020-10-17 14:17:31
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_MUTEX_H_
#define _PLATFORM_MUTEX_H_
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_mutex {
pthread_mutex_t mutex;
} platform_mutex_t;
int platform_mutex_init(platform_mutex_t* m);
int platform_mutex_lock(platform_mutex_t* m);
int platform_mutex_trylock(platform_mutex_t* m);
int platform_mutex_unlock(platform_mutex_t* m);
int platform_mutex_destroy(platform_mutex_t* m);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,125 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2020-01-10 23:45:59
* @LastEditTime: 2020-06-05 17:13:00
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_net_socket.h"
#include "mqtt_error.h"
int platform_net_socket_connect(const char *host, const char *port, int proto)
{
int fd, ret = MQTT_SOCKET_UNKNOWN_HOST_ERROR;
struct addrinfo hints, *addr_list, *cur;
/* Do name resolution with both IPv6 and IPv4 */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = (proto == PLATFORM_NET_PROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol = (proto == PLATFORM_NET_PROTO_UDP) ? IPPROTO_UDP : IPPROTO_TCP;
if (getaddrinfo(host, port, &hints, &addr_list) != 0) {
return ret;
}
for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (fd < 0) {
ret = MQTT_SOCKET_FAILED_ERROR;
continue;
}
if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
ret = fd;
break;
}
close(fd);
ret = MQTT_CONNECT_FAILED_ERROR;
}
freeaddrinfo(addr_list);
return ret;
}
int platform_net_socket_recv(int fd, void *buf, size_t len, int flags)
{
return recv(fd, buf, len, flags);
}
int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout)
{
int nread;
int nleft = len;
unsigned char *ptr;
ptr = buf;
struct timeval tv = {
timeout / 1000,
(timeout % 1000) * 1000
};
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
tv.tv_sec = 0;
tv.tv_usec = 100;
}
platform_net_socket_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
while (nleft > 0) {
nread = platform_net_socket_recv(fd, ptr, nleft, 0);
if (nread < 0) {
return -1;
} else if (nread == 0) {
break;
}
nleft -= nread;
ptr += nread;
}
return len - nleft;
}
int platform_net_socket_write(int fd, void *buf, size_t len)
{
return write(fd, buf, len);
}
int platform_net_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout)
{
struct timeval tv = {
timeout / 1000,
(timeout % 1000) * 1000
};
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
tv.tv_sec = 0;
tv.tv_usec = 100;
}
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
return write(fd, buf, len);
}
int platform_net_socket_close(int fd)
{
return close(fd);
}
int platform_net_socket_set_block(int fd)
{
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, F_GETFL) & ~O_NONBLOCK);
}
int platform_net_socket_set_nonblock(int fd)
{
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, F_GETFL) | O_NONBLOCK);
}
int platform_net_socket_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
return setsockopt(fd, level, optname, optval, optlen);
}

View File

@ -0,0 +1,49 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 13:39:00
* @LastEditTime: 2020-10-17 14:17:45
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_NET_SOCKET_H_
#define _PLATFORM_NET_SOCKET_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PLATFORM_NET_PROTO_TCP 0 /**< The TCP transport protocol */
#define PLATFORM_NET_PROTO_UDP 1 /**< The UDP transport protocol */
int platform_net_socket_connect(const char *host, const char *port, int proto);
int platform_net_socket_recv(int fd, void *buf, size_t len, int flags);
int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout);
int platform_net_socket_write(int fd, void *buf, size_t len);
int platform_net_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout);
int platform_net_socket_close(int fd);
int platform_net_socket_set_block(int fd);
int platform_net_socket_set_nonblock(int fd);
int platform_net_socket_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen);
#ifdef __cplusplus
}
#endif
#endif /* _PLATFORM_NET_SOCKET_H_ */

View File

@ -0,0 +1,61 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-23 19:26:27
* @LastEditTime: 2020-02-23 16:19:07
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_thread.h"
#include "platform_memory.h"
platform_thread_t *platform_thread_init( const char *name,
void (*entry)(void *),
void * const param,
unsigned int stack_size,
unsigned int priority,
unsigned int tick)
{
int res;
platform_thread_t *thread;
void *(*thread_entry) (void *);
thread_entry = (void *(*)(void*))entry;
thread = platform_memory_alloc(sizeof(platform_thread_t));
res = pthread_create(&thread->thread, NULL, thread_entry, param);
if(res != 0) {
platform_memory_free(thread);
}
thread->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
thread->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
return thread;
}
void platform_thread_startup(platform_thread_t* thread)
{
(void) thread;
}
void platform_thread_stop(platform_thread_t* thread)
{
pthread_mutex_lock(&(thread->mutex));
pthread_cond_wait(&(thread->cond), &(thread->mutex));
pthread_mutex_unlock(&(thread->mutex));
}
void platform_thread_start(platform_thread_t* thread)
{
pthread_mutex_lock(&(thread->mutex));
pthread_cond_signal(&(thread->cond));
pthread_mutex_unlock(&(thread->mutex));
}
void platform_thread_destroy(platform_thread_t* thread)
{
if (NULL != thread)
pthread_detach(thread->thread);
}

View File

@ -0,0 +1,38 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-15 18:31:44
* @LastEditTime: 2020-10-17 14:15:21
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_THREAD_H_
#define _PLATFORM_THREAD_H_
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_thread {
pthread_t thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
} platform_thread_t;
platform_thread_t *platform_thread_init( const char *name,
void (*entry)(void *),
void * const param,
unsigned int stack_size,
unsigned int priority,
unsigned int tick);
void platform_thread_startup(platform_thread_t* thread);
void platform_thread_stop(platform_thread_t* thread);
void platform_thread_start(platform_thread_t* thread);
void platform_thread_destroy(platform_thread_t* thread);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,48 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-10 22:16:41
* @LastEditTime: 2020-06-05 17:18:48
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include "platform_timer.h"
void platform_timer_init(platform_timer_t* timer)
{
timer->time = (struct timeval){0, 0};
}
void platform_timer_cutdown(platform_timer_t* timer, unsigned int timeout)
{
struct timeval now;
gettimeofday(&now, NULL);
struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
timeradd(&now, &interval, &timer->time);
}
char platform_timer_is_expired(platform_timer_t* timer)
{
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->time, &now, &res);
return ((res.tv_sec < 0) || (res.tv_sec == 0 && res.tv_usec <= 0));
}
int platform_timer_remain(platform_timer_t* timer)
{
struct timeval now, res;
gettimeofday(&now, NULL);
timersub(&timer->time, &now, &res);
return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
}
unsigned long platform_timer_now(void)
{
return (unsigned long) time(NULL);
}
void platform_timer_usleep(unsigned long usec)
{
usleep(usec);
}

View File

@ -0,0 +1,35 @@
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-10 22:18:32
* @LastEditTime: 2020-10-17 14:17:55
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#ifndef _PLATFORM_TIMER_H_
#define _PLATFORM_TIMER_H_
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct platform_timer {
struct timeval time;
} platform_timer_t;
void platform_timer_init(platform_timer_t* timer);
void platform_timer_cutdown(platform_timer_t* timer, unsigned int timeout);
char platform_timer_is_expired(platform_timer_t* timer);
int platform_timer_remain(platform_timer_t* timer);
unsigned long platform_timer_now(void);
void platform_timer_usleep(unsigned long usec);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,77 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:44:22
* @FilePath : /mqttclient/common/random.c
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
#include <stdlib.h>
#include "random.h"
extern int platform_timer_now();
static unsigned int last_seed = 1;
int __attribute__((weak)) platform_timer_now()
{
return 1;
}
static int do_random(unsigned int seed)
{
srand(seed);
return rand();
}
int random_number(void)
{
unsigned int seed = (unsigned int) platform_timer_now();
last_seed += (seed >> ((seed ^ last_seed) % 3));
return do_random(last_seed ^ seed);
}
// random number range interval [min, max)
int random_number_range(unsigned int min, unsigned int max)
{
return (random_number() % (max - min)) + min;
}
int random_string(char *buffer, int len)
{
unsigned int i, flag, seed, random;
if (NULL == buffer)
return 0;
seed = (unsigned int) random_number();
seed += (unsigned int) ((size_t)buffer ^ seed);
random = (unsigned int)do_random(seed);
for (i = 0; i < len; i++) {
random = do_random(seed ^ random);
flag = (unsigned int)random % 3;
switch (flag) {
case 0:
buffer[i] = 'A' + do_random(random ^ (i & flag)) % 26;
break;
case 1:
buffer[i] = 'a' + do_random(random ^ (i & flag)) % 26;
break;
case 2:
buffer[i] = '0' + do_random(random ^ (i & flag)) % 10;
break;
default:
buffer[i] = 'x';
break;
}
random += ((0xb433e5c6 ^ random) << (i & flag));
}
buffer[len] = '\0';
return len;
}

View File

@ -0,0 +1,29 @@
/*
* @Author : jiejie
* @GitHub : https://github.com/jiejieTop
* @Date : 2021-02-26 12:00:24
* @LastEditors : jiejie
* @LastEditTime : 2022-06-15 19:40:10
* @FilePath : /mqttclient/common/random.h
* Copyright (c) 2022 jiejie, All Rights Reserved. Please keep the author information and source code according to the license.
*/
#ifndef _RANDOM_H_
#define _RANDOM_H_
#ifdef __cplusplus
extern "C" {
#endif
#define RANDOM_MAX 0x7FFFFFFF
int random_number(void);
int random_number_range(unsigned int min, unsigned int max);
int random_string(char *buffer, int len);
#ifdef __cplusplus
}
#endif
#endif /* _RANDOM_H_ */