Property reading, and tests for byte properties.

This commit is contained in:
Roger A. Light 2018-10-04 17:18:57 +01:00
parent 34c8c28e9d
commit f4b2838574
14 changed files with 650 additions and 175 deletions

View File

@ -23,6 +23,7 @@ MOSQ_OBJS=mosquitto.o \
options.o \
packet_datatypes.o \
packet_mosq.o \
property_mosq.o \
read_handle.o \
send_connect.o \
send_disconnect.o \
@ -143,6 +144,9 @@ packet_datatypes.o : packet_datatypes.c packet_mosq.h
packet_mosq.o : packet_mosq.c packet_mosq.h
${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
property_mosq.o : property_mosq.c property_mosq.h
${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@
read_handle.o : read_handle.c read_handle.h
${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@

View File

@ -87,6 +87,7 @@ enum mosq_err_t {
MOSQ_ERR_MALFORMED_UTF8 = 18,
MOSQ_ERR_KEEPALIVE = 19,
MOSQ_ERR_LOOKUP = 20,
MOSQ_ERR_MALFORMED_PACKET = 19,
};
/* Error values */

View File

@ -88,7 +88,7 @@ void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, ui
}
int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length)
int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length)
{
uint16_t slen;
int rc;
@ -118,7 +118,7 @@ int packet__read_string(struct mosquitto__packet *packet, char **str, int *lengt
int rc;
int len;
rc = packet__read_binary(packet, (void **)str, &len);
rc = packet__read_binary(packet, (uint8_t **)str, &len);
if(rc) return rc;
if(mosquitto_validate_utf8(*str, len)){

View File

@ -29,7 +29,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet);
int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte);
int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count);
int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length);
int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length);
int packet__read_string(struct mosquitto__packet *packet, char **str, int *length);
int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word);
int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word);

View File

@ -26,7 +26,7 @@ Contributors:
#include "packet_mosq.h"
#include "property_mosq.h"
int property__read(struct mosquitto__packet *packet, int32_t *len)
int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5__property *property)
{
int rc;
int32_t property_identifier;
@ -35,230 +35,261 @@ int property__read(struct mosquitto__packet *packet, int32_t *len)
uint16_t uint16;
uint32_t uint32;
int32_t varint;
char *str;
int slen;
*len -= 14;
char *str1, *str2;
int slen1, slen2;
rc = packet__read_varint(packet, &property_identifier, NULL);
if(rc) return rc;
*len -= 1;
memset(property, 0, sizeof(struct mqtt5__property));
property->identifier = property_identifier;
switch(property_identifier){
case PROP_PAYLOAD_FORMAT_INDICATOR:
case PROP_REQUEST_PROBLEM_INFO:
case PROP_REQUEST_RESPONSE_INFO:
case PROP_MAXIMUM_QOS:
case PROP_RETAIN_AVAILABLE:
case PROP_WILDCARD_SUB_AVAILABLE:
case PROP_SUBSCRIPTION_ID_AVAILABLE:
case PROP_SHARED_SUB_AVAILABLE:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Payload format indicator: %d", byte);
property->value.i8 = byte;
break;
case PROP_SERVER_KEEP_ALIVE:
case PROP_RECEIVE_MAXIMUM:
case PROP_TOPIC_ALIAS_MAXIMUM:
case PROP_TOPIC_ALIAS:
rc = packet__read_uint16(packet, &uint16);
if(rc) return rc;
*len -= 2; /* uint16 */
property->value.i16 = uint16;
break;
case PROP_MESSAGE_EXPIRY_INTERVAL:
case PROP_SESSION_EXPIRY_INTERVAL:
case PROP_WILL_DELAY_INTERVAL:
case PROP_MAXIMUM_PACKET_SIZE:
rc = packet__read_uint32(packet, &uint32);
if(rc) return rc;
*len -= 4; /* uint32 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Message expiry: %d", uint32);
break;
case PROP_CONTENT_TYPE:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Content type: %s", str);
break;
case PROP_RESPONSE_TOPIC:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Response topic: %s", str);
break;
case PROP_CORRELATION_DATA:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Correlation data: %s", str);
property->value.i32 = uint32;
break;
case PROP_SUBSCRIPTION_IDENTIFIER:
rc = packet__read_varint(packet, &varint, &byte_count);
if(rc) return rc;
*len -= byte_count;
log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", varint);
break;
case PROP_SESSION_EXPIRY_INTERVAL:
rc = packet__read_uint32(packet, &uint32);
if(rc) return rc;
*len -= 4; /* uint32 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint32);
property->value.varint = varint;
break;
case PROP_CONTENT_TYPE:
case PROP_RESPONSE_TOPIC:
case PROP_ASSIGNED_CLIENT_IDENTIFIER:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Assigned client identifier: %s", str);
break;
case PROP_SERVER_KEEP_ALIVE:
rc = packet__read_uint16(packet, &uint16);
if(rc) return rc;
*len -= 2; /* uint16 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint16);
break;
case PROP_AUTHENTICATION_METHOD:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication method: %s", str);
break;
case PROP_AUTHENTICATION_DATA:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication data: %s", str);
break;
case PROP_REQUEST_PROBLEM_INFO:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Request problem information: %d", byte);
break;
case PROP_WILL_DELAY_INTERVAL:
rc = packet__read_uint32(packet, &uint32);
if(rc) return rc;
*len -= 4; /* uint32 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", uint32);
break;
case PROP_REQUEST_RESPONSE_INFO:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Request response information: %d", byte);
break;
case PROP_RESPONSE_INFO:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Response information: %s", str);
break;
case PROP_SERVER_REFERENCE:
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Server reference: %s", str);
break;
case PROP_REASON_STRING:
rc = packet__read_string(packet, &str, &slen);
rc = packet__read_string(packet, &str1, &slen1);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "Reason string: %s", str);
*len -= 2 - slen1; /* uint16, string len */
property->value.s.v = str1;
property->value.s.len = slen1;
break;
case PROP_RECEIVE_MAXIMUM:
rc = packet__read_uint16(packet, &uint16);
case PROP_CORRELATION_DATA:
rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1);
if(rc) return rc;
*len -= 2; /* uint16 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", uint16);
break;
case PROP_TOPIC_ALIAS_MAXIMUM:
rc = packet__read_uint16(packet, &uint16);
if(rc) return rc;
*len -= 2; /* uint16 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias maximum: %d", uint16);
break;
case PROP_TOPIC_ALIAS:
rc = packet__read_uint16(packet, &uint16);
if(rc) return rc;
*len -= 2; /* uint16 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias: %d", uint16);
break;
case PROP_MAXIMUM_QOS:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum QoS: %d", byte);
break;
case PROP_RETAIN_AVAILABLE:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Retain available: %d", byte);
*len -= 2 - slen1; /* uint16, binary len */
property->value.bin.v = str1;
property->value.bin.len = slen1;
break;
case PROP_USER_PROPERTY:
rc = packet__read_string(packet, &str, &slen);
rc = packet__read_string(packet, &str1, &slen1);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "User property name: %s", str);
*len -= 2 - slen1; /* uint16, string len */
rc = packet__read_string(packet, &str, &slen);
if(rc) return rc;
*len -= 2 - slen; /* uint16, string len */
log__printf(NULL, MOSQ_LOG_DEBUG, "User property value: %s", str);
break;
rc = packet__read_string(packet, &str2, &slen2);
if(rc){
mosquitto__free(str1);
return rc;
}
*len -= 2 - slen2; /* uint16, string len */
case PROP_MAXIMUM_PACKET_SIZE:
rc = packet__read_uint32(packet, &uint32);
if(rc) return rc;
*len -= 4; /* uint32 */
log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum packet size: %d", uint32);
break;
case PROP_WILDCARD_SUB_AVAILABLE:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Wildcard subscription available: %d", byte);
break;
case PROP_SUBSCRIPTION_ID_AVAILABLE:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier available: %d", byte);
break;
case PROP_SHARED_SUB_AVAILABLE:
rc = packet__read_byte(packet, &byte);
if(rc) return rc;
*len -= 1; /* byte */
log__printf(NULL, MOSQ_LOG_DEBUG, "Shared subscription available: %d", byte);
property->name.v = str1;
property->name.len = slen1;
property->value.s.v = str2;
property->value.s.len = slen2;
break;
default:
log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", byte);
return 1;
return MOSQ_ERR_MALFORMED_PACKET;
}
return MOSQ_ERR_SUCCESS;
}
int property__read_all(struct mosquitto__packet *packet)
int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **properties)
{
int rc;
int32_t proplen;
struct mqtt5__property *p, *last = NULL;
bool have_payload_format_indicator = false;
bool have_request_problem_info = false;
bool have_request_response_info = false;
bool have_maximum_qos = false;
bool have_retain_available = false;
bool have_wildcard_sub_available = false;
bool have_subscription_id_available = false;
bool have_shared_sub_available = false;
rc = packet__read_varint(packet, &proplen, NULL);
if(rc) return rc;
*properties = NULL;
/* The order of properties must be preserved for some types, so keep the
* same order for all */
while(proplen > 0){
rc = property__read(packet, &proplen);
if(rc) return rc;
p = mosquitto__calloc(1, sizeof(struct mqtt5__property));
rc = property__read(packet, &proplen, p);
if(rc){
mosquitto__free(p);
property__free_all(properties);
return rc;
}
if(!(*properties)){
*properties = p;
}else{
last->next = p;
}
last = p;
/* Validity checks */
if(p->identifier == PROP_PAYLOAD_FORMAT_INDICATOR){
if(have_payload_format_indicator){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_payload_format_indicator = true;
}else if(p->identifier == PROP_REQUEST_PROBLEM_INFO){
if(have_request_problem_info || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_request_problem_info = true;
}else if(p->identifier == PROP_REQUEST_RESPONSE_INFO){
if(have_request_response_info || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_request_response_info = true;
}else if(p->identifier == PROP_MAXIMUM_QOS){
if(have_maximum_qos || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_maximum_qos = true;
}else if(p->identifier == PROP_RETAIN_AVAILABLE){
if(have_retain_available || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_retain_available = true;
}else if(p->identifier == PROP_WILDCARD_SUB_AVAILABLE){
if(have_wildcard_sub_available || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_wildcard_sub_available = true;
}else if(p->identifier == PROP_SUBSCRIPTION_ID_AVAILABLE){
if(have_subscription_id_available || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_subscription_id_available = true;
}else if(p->identifier == PROP_SHARED_SUB_AVAILABLE){
if(have_shared_sub_available || p->value.i8 > 1){
property__free_all(properties);
return MOSQ_ERR_PROTOCOL;
}
have_shared_sub_available = true;
}
}
return MOSQ_ERR_SUCCESS;
}
void property__free(struct mqtt5__property **property)
{
if(!property || !(*property)) return;
switch((*property)->identifier){
case PROP_CONTENT_TYPE:
case PROP_RESPONSE_TOPIC:
case PROP_CORRELATION_DATA:
case PROP_ASSIGNED_CLIENT_IDENTIFIER:
case PROP_AUTHENTICATION_METHOD:
case PROP_AUTHENTICATION_DATA:
case PROP_RESPONSE_INFO:
case PROP_SERVER_REFERENCE:
case PROP_REASON_STRING:
mosquitto__free((*property)->value.s.v);
break;
case PROP_USER_PROPERTY:
mosquitto__free((*property)->name.v);
mosquitto__free((*property)->value.s.v);
break;
case PROP_PAYLOAD_FORMAT_INDICATOR:
case PROP_MESSAGE_EXPIRY_INTERVAL:
case PROP_SUBSCRIPTION_IDENTIFIER:
case PROP_SESSION_EXPIRY_INTERVAL:
case PROP_SERVER_KEEP_ALIVE:
case PROP_REQUEST_PROBLEM_INFO:
case PROP_WILL_DELAY_INTERVAL:
case PROP_REQUEST_RESPONSE_INFO:
case PROP_RECEIVE_MAXIMUM:
case PROP_TOPIC_ALIAS_MAXIMUM:
case PROP_TOPIC_ALIAS:
case PROP_MAXIMUM_QOS:
case PROP_RETAIN_AVAILABLE:
case PROP_MAXIMUM_PACKET_SIZE:
case PROP_WILDCARD_SUB_AVAILABLE:
case PROP_SUBSCRIPTION_ID_AVAILABLE:
case PROP_SHARED_SUB_AVAILABLE:
/* Nothing to free */
break;
}
free(*property);
*property = NULL;
}
void property__free_all(struct mqtt5__property **property)
{
struct mqtt5__property *p, *next;
p = *property;
while(p){
next = p->next;
property__free(&p);
p = next;
}
*property = NULL;
}

View File

@ -19,6 +19,28 @@ Contributors:
#include "mosquitto_internal.h"
#include "mosquitto.h"
int property__read_all(struct mosquitto__packet *packet);
struct mqtt__string {
char *v;
int len;
};
struct mqtt5__property {
struct mqtt5__property *next;
union {
uint8_t i8;
uint16_t i16;
uint32_t i32;
uint32_t varint;
struct mqtt__string bin;
struct mqtt__string s;
} value;
struct mqtt__string name;
int32_t identifier;
};
int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **property);
void property__free(struct mqtt5__property **property);
void property__free_all(struct mqtt5__property **property);
#endif

View File

@ -131,6 +131,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
struct mosquitto__subleaf *leaf;
int i;
struct mosquitto__security_options *security_opts;
struct mqtt5__property *properties;
#ifdef WITH_TLS
X509 *client_cert = NULL;
X509_NAME *name;
@ -241,8 +242,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
}
if(protocol_version == PROTOCOL_VERSION_v5){
rc = property__read_all(&context->in_packet);
rc = property__read_all(&context->in_packet, &properties);
if(rc) return rc;
property__free_all(&properties);
}
if(packet__read_string(&context->in_packet, &client_id, &slen)){

View File

@ -45,6 +45,8 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
int len;
int slen;
char *topic_mount;
struct mqtt5__property *properties;
#ifdef WITH_BRIDGE
char *topic_temp;
int i;
@ -132,8 +134,9 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
}
if(context->protocol == mosq_p_mqtt5){
rc = property__read_all(&context->in_packet);
rc = property__read_all(&context->in_packet, &properties);
if(rc) return rc;
property__free_all(&properties);
}
payloadlen = context->in_packet.remaining_length - context->in_packet.pos;

View File

@ -5,9 +5,21 @@ include ../../config.mk
CFLAGS=-I../.. -I../../lib -coverage -Wall -ggdb
TEST_LDFLAGS=-lcunit -coverage
TEST_OBJS = test.o \
datatype_read.o \
datatype_write.o \
property_read.o \
stubs.o \
utf8.o
LIB_OBJS = memory_mosq.o \
packet_datatypes.o \
property_mosq.o \
utf8_mosq.o
all : test
mosq_test : test.o datatype_read.o datatype_write.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o
mosq_test : ${TEST_OBJS} ${LIB_OBJS}
$(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS}
memory_mosq.o : ../../lib/memory_mosq.c
@ -16,6 +28,9 @@ memory_mosq.o : ../../lib/memory_mosq.c
packet_datatypes.o : ../../lib/packet_datatypes.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
property_mosq.o : ../../lib/property_mosq.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
utf8_mosq.o : ../../lib/utf8_mosq.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^

View File

@ -97,7 +97,7 @@ static void binary_read_helper(
memset(&packet, 0, sizeof(struct mosquitto__packet));
packet.payload = payload;
packet.remaining_length = remaining_length;
rc = packet__read_binary(&packet, (void **)&value, &length);
rc = packet__read_binary(&packet, (uint8_t **)&value, &length);
CU_ASSERT_EQUAL(rc, rc_expected);
if(value_expected){
/* FIXME - this should be a memcmp */

View File

@ -104,7 +104,6 @@ static void TEST_string_write(void)
{
uint8_t payload[100];
struct mosquitto__packet packet;
int i;
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, 100);

390
test/unit/property_read.c Normal file
View File

@ -0,0 +1,390 @@
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
#include "mqtt_protocol.h"
#include "property_mosq.h"
#include "packet_mosq.h"
static void byte_prop_read_helper(
uint8_t *payload,
int remaining_length,
int rc_expected,
int identifier,
uint8_t value_expected)
{
struct mosquitto__packet packet;
struct mqtt5__property *properties;
int rc;
memset(&packet, 0, sizeof(struct mosquitto__packet));
packet.payload = payload;
packet.remaining_length = remaining_length;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, rc_expected);
CU_ASSERT_EQUAL(packet.pos, remaining_length);
if(properties){
CU_ASSERT_EQUAL(properties->identifier, identifier);
CU_ASSERT_EQUAL(properties->value.i8, value_expected);
CU_ASSERT_PTR_EQUAL(properties->next, NULL);
property__free_all(&properties);
}
CU_ASSERT_PTR_EQUAL(properties, NULL);
}
static void duplicate_byte_helper(int identifier)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 4; /* Proplen = (Identifier + byte)*2 */
payload[1] = identifier;
payload[2] = 1;
payload[3] = identifier;
payload[4] = 0;
byte_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, identifier, 1);
}
static void bad_byte_helper(int identifier)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = identifier;
payload[2] = 2; /* 0, 1 are only valid values */
byte_prop_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, identifier, 0);
}
/* ========================================================================
* NO PROPERTIES
* ======================================================================== */
static void TEST_no_properties(void)
{
struct mosquitto__packet packet;
struct mqtt5__property *properties = NULL;
uint8_t payload[5];
int rc;
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
packet.payload = payload;
packet.remaining_length = 1;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 1);
}
static void TEST_truncated(void)
{
struct mosquitto__packet packet;
struct mqtt5__property *properties = NULL;
uint8_t payload[5];
int rc;
/* Zero length packet */
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
packet.payload = payload;
packet.remaining_length = 0;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 0);
/* Proplen > 0 but not enough data */
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
payload[0] = 2;
packet.payload = payload;
packet.remaining_length = 1;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 1);
/* Proplen > 0 but not enough data */
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
payload[0] = 4;
payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR;
packet.payload = payload;
packet.remaining_length = 2;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 2);
}
/* ========================================================================
* INVALID PROPERTY ID
* ======================================================================== */
static void TEST_invalid_property_id(void)
{
struct mosquitto__packet packet;
struct mqtt5__property *properties = NULL;
uint8_t payload[5];
int rc;
/* ID = 0 */
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
payload[0] = 4;
packet.payload = payload;
packet.remaining_length = 2;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 2);
/* ID = 4 */
memset(&packet, 0, sizeof(struct mosquitto__packet));
memset(payload, 0, sizeof(payload));
payload[0] = 4;
payload[1] = 4;
packet.payload = payload;
packet.remaining_length = 2;
rc = property__read_all(&packet, &properties);
CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET);
CU_ASSERT_PTR_EQUAL(properties, NULL);
CU_ASSERT_EQUAL(packet.pos, 2);
}
/* ========================================================================
* SINGLE PROPERTIES
* ======================================================================== */
static void TEST_single_payload_format_indicator(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1);
}
static void TEST_single_request_problem_information(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_REQUEST_PROBLEM_INFO;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1);
}
static void TEST_single_request_response_information(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_REQUEST_RESPONSE_INFO;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1);
}
static void TEST_single_maximum_qos(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_MAXIMUM_QOS;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1);
}
static void TEST_single_retain_available(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_RETAIN_AVAILABLE;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1);
}
static void TEST_single_wildcard_subscription_available(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_WILDCARD_SUB_AVAILABLE;
payload[2] = 0;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0);
}
static void TEST_single_subscription_identifier_available(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_SUBSCRIPTION_ID_AVAILABLE;
payload[2] = 0;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0);
}
static void TEST_single_shared_subscription_available(void)
{
uint8_t payload[20];
memset(&payload, 0, sizeof(payload));
payload[0] = 2; /* Proplen = Identifier + byte */
payload[1] = PROP_SHARED_SUB_AVAILABLE;
payload[2] = 1;
byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1);
}
/* ========================================================================
* DUPLICATE PROPERTIES
* ======================================================================== */
static void TEST_duplicate_payload_format_indicator(void)
{
duplicate_byte_helper(PROP_PAYLOAD_FORMAT_INDICATOR);
}
static void TEST_duplicate_request_problem_information(void)
{
duplicate_byte_helper(PROP_REQUEST_PROBLEM_INFO);
}
static void TEST_duplicate_request_response_information(void)
{
duplicate_byte_helper(PROP_REQUEST_RESPONSE_INFO);
}
static void TEST_duplicate_maximum_qos(void)
{
duplicate_byte_helper(PROP_MAXIMUM_QOS);
}
static void TEST_duplicate_retain_available(void)
{
duplicate_byte_helper(PROP_RETAIN_AVAILABLE);
}
static void TEST_duplicate_wildcard_subscription_available(void)
{
duplicate_byte_helper(PROP_WILDCARD_SUB_AVAILABLE);
}
static void TEST_duplicate_subscription_identifier_available(void)
{
duplicate_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE);
}
static void TEST_duplicate_shared_subscription_available(void)
{
duplicate_byte_helper(PROP_SHARED_SUB_AVAILABLE);
}
/* ========================================================================
* BAD PROPERTY VALUES
* ======================================================================== */
static void TEST_bad_request_problem_information(void)
{
bad_byte_helper(PROP_REQUEST_PROBLEM_INFO);
}
static void TEST_bad_request_response_information(void)
{
bad_byte_helper(PROP_REQUEST_RESPONSE_INFO);
}
static void TEST_bad_maximum_qos(void)
{
bad_byte_helper(PROP_MAXIMUM_QOS);
}
static void TEST_bad_retain_available(void)
{
bad_byte_helper(PROP_RETAIN_AVAILABLE);
}
static void TEST_bad_wildcard_sub_available(void)
{
bad_byte_helper(PROP_WILDCARD_SUB_AVAILABLE);
}
static void TEST_bad_subscription_id_available(void)
{
bad_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE);
}
static void TEST_bad_shared_sub_available(void)
{
bad_byte_helper(PROP_SHARED_SUB_AVAILABLE);
}
/* ========================================================================
* TEST SUITE SETUP
* ======================================================================== */
int init_property_read_tests(void)
{
CU_pSuite test_suite = NULL;
test_suite = CU_add_suite("Property read", NULL, NULL);
if(!test_suite){
printf("Error adding CUnit Property read test suite.\n");
return 1;
}
if(0
|| !CU_add_test(test_suite, "Truncated packet", TEST_truncated)
|| !CU_add_test(test_suite, "Invalid property ID", TEST_invalid_property_id)
|| !CU_add_test(test_suite, "No properties", TEST_no_properties)
|| !CU_add_test(test_suite, "Single Payload Format Indicator", TEST_single_payload_format_indicator)
|| !CU_add_test(test_suite, "Single Request Problem Information", TEST_single_request_problem_information)
|| !CU_add_test(test_suite, "Single Request Response Information", TEST_single_request_response_information)
|| !CU_add_test(test_suite, "Single Maximum QoS", TEST_single_maximum_qos)
|| !CU_add_test(test_suite, "Single Retain Available", TEST_single_retain_available)
|| !CU_add_test(test_suite, "Single Wildcard Subscription Available", TEST_single_wildcard_subscription_available)
|| !CU_add_test(test_suite, "Single Subscription Identifier Available", TEST_single_subscription_identifier_available)
|| !CU_add_test(test_suite, "Single Shared Subscription Available", TEST_single_shared_subscription_available)
|| !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator)
|| !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information)
|| !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information)
|| !CU_add_test(test_suite, "Duplicate Maximum QoS", TEST_duplicate_maximum_qos)
|| !CU_add_test(test_suite, "Duplicate Retain Available", TEST_duplicate_retain_available)
|| !CU_add_test(test_suite, "Duplicate Wildcard Subscription Available", TEST_duplicate_wildcard_subscription_available)
|| !CU_add_test(test_suite, "Duplicate Subscription Identifier Available", TEST_duplicate_subscription_identifier_available)
|| !CU_add_test(test_suite, "Duplicate Shared Subscription Available", TEST_duplicate_shared_subscription_available)
|| !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information)
|| !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information)
|| !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos)
|| !CU_add_test(test_suite, "Bad Retain Available", TEST_bad_retain_available)
|| !CU_add_test(test_suite, "Bad Wildcard Subscription Available", TEST_bad_wildcard_sub_available)
|| !CU_add_test(test_suite, "Bad Subscription Identifier Available", TEST_bad_subscription_id_available)
|| !CU_add_test(test_suite, "Bad Shared Subscription Available", TEST_bad_shared_sub_available)
){
printf("Error adding Property read CUnit tests.\n");
return 1;
}
return 0;
}

6
test/unit/stubs.c Normal file
View File

@ -0,0 +1,6 @@
#include <logging_mosq.h>
int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...)
{
return 0;
}

View File

@ -5,6 +5,7 @@
int init_datatype_read_tests(void);
int init_datatype_write_tests(void);
int init_property_read_tests(void);
int init_utf8_tests(void);
int main(int argc, char *argv[])
@ -19,6 +20,7 @@ int main(int argc, char *argv[])
|| init_utf8_tests()
|| init_datatype_read_tests()
|| init_datatype_write_tests()
|| init_property_read_tests()
){
CU_cleanup_registry();