From c48702db3a5f2535eab11758901815c2f180c630 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Wed, 17 Jun 2020 18:26:49 +0200 Subject: [PATCH] add topic matcher --- Makefile | 4 +- mqtttopicmatcher.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ mqtttopicmatcher.h | 6 +++ tests.c | 37 ++++++++++++-- 4 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 mqtttopicmatcher.c create mode 100644 mqtttopicmatcher.h diff --git a/Makefile b/Makefile index 9ef0fa0..3bd6c38 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,10 @@ VERSION:=$(shell cat VERSION) .PHONY: all all: mqttauditing -mqttauditing: mqttauditing.o mqttreceiver.o logging.o ringbuffer.o version.o +mqttauditing: mqttauditing.o mqttreceiver.o mqtttopicmatcher.o logging.o ringbuffer.o version.o $(CC) -o $@ $(LDFLAGS) $^ -tests: tests.o ringbuffer.o +tests: tests.o ringbuffer.o mqtttopicmatcher.o $(CC) -o $@ $(LDFLAGS) -lcunit $^ version.o: version.c VERSION diff --git a/mqtttopicmatcher.c b/mqtttopicmatcher.c new file mode 100644 index 0000000..a219684 --- /dev/null +++ b/mqtttopicmatcher.c @@ -0,0 +1,117 @@ +#include +#include "mqtttopicmatcher.h" + + +int cmpTopicWithWildcard(char *subscribedTopic, char *receivedTopic) { + uint32_t s_idx = 0; + uint32_t r_idx = 0; + char s; + char r; + + enum { e_START, e_PART, e_DELIMITER, e_WAIT_FOR_DELIMITER_IN_S, e_WAIT_FOR_DELIMITER_IN_R, e_OK, e_NOK } state; + state = e_START; + + while (1) { + s = *(subscribedTopic + s_idx); + r = *(receivedTopic + r_idx); + + if ((s == 0) && (r == 0) && (state == e_PART)) { + return 0; + } + + switch (state) { + case e_START: + if (s == '#') { + state = e_OK; + break; + } else if (s == '+') { + state = e_WAIT_FOR_DELIMITER_IN_S; + s_idx++; + r_idx++; + break; + } else if (s == '/') { + state = e_DELIMITER; + s_idx++; + r_idx++; + break; + } else if (s == r) { + state = e_PART; + s_idx++; + r_idx++; + break; + } else { + state = e_NOK; + break; + } + case e_DELIMITER: + if (s == '#') { + state = e_OK; + break; + } else if (s == '+') { + state = e_WAIT_FOR_DELIMITER_IN_S; + s_idx++; + r_idx++; + break; + } else if (s == r) { + state = e_PART; + s_idx++; + r_idx++; + break; + } else { + state = e_NOK; + break; + } + case e_WAIT_FOR_DELIMITER_IN_S: + if (s != '/') { + state = e_NOK; + break; + } else if ((s == '/') && (r == '/')) { + state = e_PART; + s_idx++; + r_idx++; + break; + } else if ((s == '/') && (r != '/')) { + state = e_WAIT_FOR_DELIMITER_IN_R; + r_idx++; + break; + } else { + state = e_NOK; + break; + } + case e_WAIT_FOR_DELIMITER_IN_R: + if (r == '/') { + state = e_PART; + s_idx++; + r_idx++; + break; + } else { + r_idx++; + break; + } + case e_PART: + if (s == '#') { + state = e_OK; + break; + } else if (s == '+') { + state = e_WAIT_FOR_DELIMITER_IN_S; + s_idx++; + r_idx++; + break; + } else if (s == r) { + state = e_PART; + s_idx++; + r_idx++; + break; + } else { + state = e_NOK; + break; + } + } + + if (state == e_OK) { + return 0; + } else if (state == e_NOK) { + return -1; + } + } +} diff --git a/mqtttopicmatcher.h b/mqtttopicmatcher.h new file mode 100644 index 0000000..9c1beca --- /dev/null +++ b/mqtttopicmatcher.h @@ -0,0 +1,6 @@ +#ifndef _MQTTTOPICMATCHER_H_ +#define _MQTTTOPICMATCHER_H_ + +int cmpTopicWithWildcard(char *subscribedTopic, char *receivedTopic); + +#endif // _MQTTTOPICMATCHER_H_ \ No newline at end of file diff --git a/tests.c b/tests.c index 320e8b8..7379754 100644 --- a/tests.c +++ b/tests.c @@ -4,9 +4,9 @@ #include #include #include "ringbuffer.h" +#include "mqtttopicmatcher.h" - -t_ringbuffer rb; +ringbuffer_t rb; int init_suite_ringbuffer(void) @@ -123,6 +123,21 @@ void testRingbuffer4() { } +void testTopicMatcher1() { + CU_ASSERT(cmpTopicWithWildcard("#", "bla") == 0); + CU_ASSERT(cmpTopicWithWildcard("bla/#", "bla/blu") == 0); + CU_ASSERT(cmpTopicWithWildcard("bla/#", "blu/blu") == -1); + CU_ASSERT(cmpTopicWithWildcard("bla/+", "bla/blu") == -1); + CU_ASSERT(cmpTopicWithWildcard("bla/+/blo", "bla/blu/blo") == 0); + CU_ASSERT(cmpTopicWithWildcard("bla/+/blo", "bla/blu/ble") == -1); + CU_ASSERT(cmpTopicWithWildcard("bla/+/blo", "blo/blu/blo") == -1); + CU_ASSERT(cmpTopicWithWildcard("bla/blu/blo", "bla/blu/blo") == 0); + CU_ASSERT(cmpTopicWithWildcard("bla/blu/#", "bla/blu/blo") == 0); + CU_ASSERT(cmpTopicWithWildcard("bla", "") == -1); + CU_ASSERT(cmpTopicWithWildcard("#", "") == 0); + CU_ASSERT(cmpTopicWithWildcard("", "") == 0); + +} int main() { @@ -139,13 +154,25 @@ int main() (NULL == CU_add_test(ringbufferSuite, "test 2 of ringbuffer", testRingbuffer2)) || (NULL == CU_add_test(ringbufferSuite, "test 3 of ringbuffer", testRingbuffer3)) || (NULL == CU_add_test(ringbufferSuite, "test 4 of ringbuffer", testRingbuffer4)) || - 0 - ) - { + 0 ) { CU_cleanup_registry(); return CU_get_error(); } + + CU_pSuite topicMatcherSuite = CU_add_suite("Suite_TopicMatcher", NULL, NULL); + if (NULL == topicMatcherSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ((NULL == CU_add_test(topicMatcherSuite, "test 1 of topicMatcher", testTopicMatcher1)) || + 0 ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CU_cleanup_registry();