summaryrefslogtreecommitdiff
path: root/libs/libmosquitto/src/util_topic.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libmosquitto/src/util_topic.c')
-rw-r--r--libs/libmosquitto/src/util_topic.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/libs/libmosquitto/src/util_topic.c b/libs/libmosquitto/src/util_topic.c
new file mode 100644
index 0000000000..67b78782ef
--- /dev/null
+++ b/libs/libmosquitto/src/util_topic.c
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
+
+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:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <aclapi.h>
+# include <io.h>
+# include <lmcons.h>
+#else
+# include <sys/stat.h>
+#endif
+
+
+#ifdef WITH_BROKER
+#include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "tls_mosq.h"
+#include "util_mosq.h"
+
+/* Check that a topic used for publishing is valid.
+ * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found.
+ * Also returns MOSQ_ERR_INVAL if the topic string is too long.
+ * Returns MOSQ_ERR_SUCCESS if everything is fine.
+ */
+int mosquitto_pub_topic_check(const char *str)
+{
+ int len = 0;
+ while(str && str[0]){
+ if(str[0] == '+' || str[0] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ len++;
+ str = &str[1];
+ }
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_pub_topic_check2(const char *str, size_t len)
+{
+ size_t i;
+
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<len; i++){
+ if(str[i] == '+' || str[i] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+/* Check that a topic used for subscriptions is valid.
+ * Search for + or # in a topic, check they aren't in invalid positions such as
+ * foo/#/bar, foo/+bar or foo/bar#.
+ * Return MOSQ_ERR_INVAL if invalid position found.
+ * Also returns MOSQ_ERR_INVAL if the topic string is too long.
+ * Returns MOSQ_ERR_SUCCESS if everything is fine.
+ */
+int mosquitto_sub_topic_check(const char *str)
+{
+ char c = '\0';
+ int len = 0;
+ while(str && str[0]){
+ if(str[0] == '+'){
+ if((c != '\0' && c != '/') || (str[1] != '\0' && str[1] != '/')){
+ return MOSQ_ERR_INVAL;
+ }
+ }else if(str[0] == '#'){
+ if((c != '\0' && c != '/') || str[1] != '\0'){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+ len++;
+ c = str[0];
+ str = &str[1];
+ }
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_sub_topic_check2(const char *str, size_t len)
+{
+ char c = '\0';
+ size_t i;
+
+ if(len > 65535) return MOSQ_ERR_INVAL;
+
+ for(i=0; i<len; i++){
+ if(str[i] == '+'){
+ if((c != '\0' && c != '/') || (i<len-1 && str[i+1] != '/')){
+ return MOSQ_ERR_INVAL;
+ }
+ }else if(str[i] == '#'){
+ if((c != '\0' && c != '/') || i<len-1){
+ return MOSQ_ERR_INVAL;
+ }
+ }
+ c = str[i];
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
+{
+ return mosquitto_topic_matches_sub2(sub, 0, topic, 0, result);
+}
+
+/* Does a topic match a subscription? */
+int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result)
+{
+ size_t spos;
+
+ UNUSED(sublen);
+ UNUSED(topiclen);
+
+ if(!result) return MOSQ_ERR_INVAL;
+ *result = false;
+
+ if(!sub || !topic || sub[0] == 0 || topic[0] == 0){
+ return MOSQ_ERR_INVAL;
+ }
+
+ if((sub[0] == '$' && topic[0] != '$')
+ || (topic[0] == '$' && sub[0] != '$')){
+
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ spos = 0;
+
+ while(sub[0] != 0){
+ if(topic[0] == '+' || topic[0] == '#'){
+ return MOSQ_ERR_INVAL;
+ }
+ if(sub[0] != topic[0] || topic[0] == 0){ /* Check for wildcard matches */
+ if(sub[0] == '+'){
+ /* Check for bad "+foo" or "a/+foo" subscription */
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ /* Check for bad "foo+" or "foo+/a" subscription */
+ if(sub[1] != 0 && sub[1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ while(topic[0] != 0 && topic[0] != '/'){
+ topic++;
+ }
+ if(topic[0] == 0 && sub[0] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else if(sub[0] == '#'){
+ /* Check for bad "foo#" subscription */
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ /* Check for # not the final character of the sub, e.g. "#foo" */
+ if(sub[1] != 0){
+ return MOSQ_ERR_INVAL;
+ }else{
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else{
+ /* Check for e.g. foo/bar matching foo/+/# */
+ if(topic[0] == 0
+ && spos > 0
+ && sub[-1] == '+'
+ && sub[0] == '/'
+ && sub[1] == '#')
+ {
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+
+ /* There is no match at this point, but is the sub invalid? */
+ while(sub[0] != 0){
+ if(sub[0] == '#' && sub[1] != 0){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ }
+
+ /* Valid input, but no match */
+ return MOSQ_ERR_SUCCESS;
+ }
+ }else{
+ /* sub[spos] == topic[tpos] */
+ if(topic[1] == 0){
+ /* Check for e.g. foo matching foo/# */
+ if(sub[1] == '/'
+ && sub[2] == '#'
+ && sub[3] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ spos++;
+ sub++;
+ topic++;
+ if(sub[0] == 0 && topic[0] == 0){
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }else if(topic[0] == 0 && sub[0] == '+' && sub[1] == 0){
+ if(spos > 0 && sub[-1] != '/'){
+ return MOSQ_ERR_INVAL;
+ }
+ spos++;
+ sub++;
+ *result = true;
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ }
+ if((topic[0] != 0 || sub[0] != 0)){
+ *result = false;
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}