adding wamo plugin

This commit is contained in:
Dominik Kuhn 2024-08-18 12:56:58 +02:00
parent 15292b20b0
commit 323a37331c
9 changed files with 539 additions and 1 deletions

57
CMakeSettings.json Normal file
View File

@ -0,0 +1,57 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "clang_cl_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"variables": [
{
"name": "WITH_TLS",
"value": "False",
"type": "BOOL"
},
{
"name": "WITH_CLIENTS",
"value": "False",
"type": "BOOL"
},
{
"name": "WITH_WEBSOCKETS",
"value": "False",
"type": "BOOL"
},
{
"name": "WITH_THREADING",
"value": "False",
"type": "BOOL"
},
{
"name": "DOCUMENTATION",
"value": "False",
"type": "BOOL"
},
{
"name": "CJSON_DIR",
"value": "C:/Users/d.kuhn/Projekte/cJSON/",
"type": "STRING"
},
{
"name": "CJSON_INCLUDE_DIR",
"value": "C:/Users/d.kuhn/Projekte/cJSON/",
"type": "PATH"
},
{
"name": "CJSON_LIBRARY",
"value": "C:/Users/d.kuhn/Projekte/cJSON/cjson/out/build/x64-Debug/cjson.lib",
"type": "FILEPATH"
}
]
}
]
}

View File

@ -67,7 +67,7 @@ WITH_SYSTEMD:=no
WITH_SRV:=no
# Build with websockets support on the broker.
WITH_WEBSOCKETS:=no
WITH_WEBSOCKETS:=yes
# Use elliptic keys in broker
WITH_EC:=yes

View File

@ -902,3 +902,7 @@
# given multiple times, all of the files from the first instance will be
# processed before the next instance. See the man page for examples.
#include_dir
# plugin C:\Users\d.kuhn\Projekte\mosquitto\out\build\x64-Debug\plugins\payload-modification\mosquitto_payload_modification.dll
plugin C:\Users\d.kuhn\Projekte\mosquitto\out\build\x64-Debug\plugins\wamo\wamo.dll

View File

@ -3,3 +3,4 @@ if(NOT WIN32)
add_subdirectory(message-timestamp)
endif(NOT WIN32)
add_subdirectory(payload-modification)
add_subdirectory(wamo)

View File

@ -0,0 +1,51 @@
# include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/include
# ${OPENSSL_INCLUDE_DIR} ${STDBOOL_H_PATH} ${STDINT_H_PATH})
# link_directories(${mosquitto_SOURCE_DIR})
#
# add_library(wamo MODULE wamo.c "json_help.c" "json_help.h")
# set_target_properties(wamo PROPERTIES
# POSITION_INDEPENDENT_CODE 1
# )
# set_target_properties(wamo PROPERTIES PREFIX "")
# if(WIN32)
# target_link_libraries(wamo mosquitto ${CJSON_LIBRARIES})
# endif(WIN32)
# Don't install, these are example plugins only.
#install(TARGETS wamo RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
if (CJSON_FOUND )
add_definitions("-DWITH_CJSON")
set( CLIENT_INC ${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/include
${STDBOOL_H_PATH} ${STDINT_H_PATH} ${mosquitto_SOURCE_DIR}/deps
${mosquitto_SOURCE_DIR}/src ${CJSON_INCLUDE_DIRS} )
set( CLIENT_DIR ${mosquitto_BINARY_DIR}/lib ${CJSON_DIR})
include_directories(${CLIENT_INC})
link_directories(${CLIENT_DIR} ${mosquitto_SOURCE_DIR})
add_library(wamo MODULE
json_help.c
json_help.h
wamo.c)
set_target_properties(wamo PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
set_target_properties(wamo PROPERTIES PREFIX "")
target_link_libraries(wamo ${CJSON_LIBRARIES})
if(WIN32)
target_link_libraries(wamo mosquitto)
install(TARGETS wamo
DESTINATION "${CMAKE_INSTALL_BINDIR}")
else()
install(TARGETS wamo
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
endif()
endif()

53
plugins/wamo/Makefile Normal file
View File

@ -0,0 +1,53 @@
include ../../config.mk
.PHONY : all binary check clean reallyclean test install uninstall
PLUGIN_NAME=wamo
LOCAL_CPPFLAGS=-I../../src/ -DWITH_CJSON
OBJS= \
json_help.o \
wamo.o
ifeq ($(WITH_CJSON),yes)
ALL_DEPS:= binary
else
ALL_DEPS:=
endif
else
ALL_DEPS:=
endif
all : ${ALL_DEPS}
binary : ${PLUGIN_NAME}.so
${PLUGIN_NAME}.so : ${OBJS}
${CROSS_COMPILE}${CC} $(PLUGIN_LDFLAGS) -fPIC -shared $^ -o $@ -lcjson
json_help.o : json_help.c
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
wamo.o : wamo.c
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
reallyclean : clean
clean:
-rm -f *.o ${PLUGIN_NAME}.so *.gcda *.gcno
check: test
test:
install: all
ifeq ($(WITH_CJSON),yes)
$(INSTALL) -d "${DESTDIR}$(libdir)"
$(INSTALL) ${STRIP_OPTS} ${PLUGIN_NAME}.so "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"
endif
endif
uninstall :
-rm -f "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"

182
plugins/wamo/json_help.c Normal file
View File

@ -0,0 +1,182 @@
/*
Contributors:
Dominik Kuhn - initial implementation and documentation.
*/
#include "config.h"
#include <cjson/cJSON.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "json_help.h"
#include "mosquitto.h"
#include "mosquitto_broker.h"
int json_create_array(cJSON* json, const char* name) {
cJSON* jtmp;
jtmp = cJSON_GetObjectItem(json, name);
if (jtmp) {
if (cJSON_IsArray(jtmp) == true) {
return MOSQ_ERR_INVAL;
}
else {
cJSON_AddArrayToObject(json, name);
}
}
else {
cJSON_AddArrayToObject(json, name);
}
return MOSQ_ERR_SUCCESS;
}
int json_add_id_to_array(cJSON* json, const char* name, const char * id)
{
cJSON* jtmp;
cJSON* tid;
jtmp = cJSON_GetObjectItem(json, name);
if (jtmp) {
if (cJSON_IsArray(jtmp) == true) {
tid = cJSON_CreateString(id);
cJSON_AddItemToArray(jtmp, tid);
}
else {
return MOSQ_ERR_INVAL;
}
}
else {
return MOSQ_ERR_INVAL;
}
return MOSQ_ERR_SUCCESS;
}
int json_del_id_from_array(cJSON* json, const char* name, const char* id)
{
cJSON* jtmp = NULL;
cJSON* tid = NULL;
cJSON* detached_item = NULL;
int array_index = 0;
jtmp = cJSON_GetObjectItem(json, name);
if (jtmp) {
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: deleting item from array .. debug 1");
if (cJSON_IsArray(jtmp) == true) {
// cJSON_DeleteItemFromObject(json, name);
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: deleting item from array .. debug 2");
cJSON_ArrayForEach(tid, jtmp)
{
if ( strcmp( cJSON_GetStringValue(tid),id) == 0)
{
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: deleting item from array .. debug 3");
detached_item = cJSON_DetachItemFromArray(jtmp, array_index);
}
else
{
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: deleting item from array .. debug 4");
}
array_index++;
}
// cJSON_ReplaceItemInObject(json, name, jtmp);
// cJSON_AddItemToObject(json, id, jtmp);
}
else {
return MOSQ_ERR_INVAL;
}
}
else {
return MOSQ_ERR_INVAL;
}
return MOSQ_ERR_SUCCESS;
}
int json_get_bool(cJSON *json, const char *name, bool *value, bool optional, bool default_value)
{
cJSON *jtmp;
if(optional == true){
*value = default_value;
}
jtmp = cJSON_GetObjectItem(json, name);
if(jtmp){
if(cJSON_IsBool(jtmp) == false){
return MOSQ_ERR_INVAL;
}
*value = cJSON_IsTrue(jtmp);
}else{
if(optional == false){
return MOSQ_ERR_INVAL;
}
}
return MOSQ_ERR_SUCCESS;
}
int json_get_int(cJSON *json, const char *name, int *value, bool optional, int default_value)
{
cJSON *jtmp;
if(optional == true){
*value = default_value;
}
jtmp = cJSON_GetObjectItem(json, name);
if(jtmp){
if(cJSON_IsNumber(jtmp) == false){
return MOSQ_ERR_INVAL;
}
*value = jtmp->valueint;
}else{
if(optional == false){
return MOSQ_ERR_INVAL;
}
}
return MOSQ_ERR_SUCCESS;
}
int json_get_string(cJSON *json, const char *name, char **value, bool optional)
{
cJSON *jtmp;
*value = NULL;
jtmp = cJSON_GetObjectItem(json, name);
if(jtmp){
if(cJSON_IsString(jtmp) == false){
return MOSQ_ERR_INVAL;
}
*value = jtmp->valuestring;
}else{
if(optional == false){
return MOSQ_ERR_INVAL;
}
}
return MOSQ_ERR_SUCCESS;
}
cJSON *cJSON_AddIntToObject(cJSON * const object, const char * const name, int number)
{
char buf[30];
snprintf(buf, sizeof(buf), "%d", number);
return cJSON_AddRawToObject(object, name, buf);
}

23
plugins/wamo/json_help.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef JSON_HELP_H
#define JSON_HELP_H
/*
Contributors:
Dominik Kuhn Light - initial implementation and documentation.
*/
#include <cjson/cJSON.h>
#include <stdbool.h>
int json_create_array(cJSON* json, const char* name);
int json_add_id_to_array(cJSON* json, const char* name, const char* id);
int json_del_id_from_array(cJSON* json, const char* name, const char* id);
/* "optional==false" can also be taken to mean "only return success if the key exists and is valid" */
int json_get_bool(cJSON *json, const char *name, bool *value, bool optional, bool default_value);
int json_get_int(cJSON *json, const char *name, int *value, bool optional, int default_value);
int json_get_string(cJSON *json, const char *name, char **value, bool optional);
cJSON *cJSON_AddIntToObject(cJSON * const object, const char * const name, int number);
cJSON *cJSON_CreateInt(int num);
#endif

167
plugins/wamo/wamo.c Normal file
View File

@ -0,0 +1,167 @@
/*
Copyright (c) 2020 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 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
/*
* This is an *example* plugin which demonstrates how to modify the payload of
* a message after it is received by the broker and before it is sent on to
* other clients.
*
* You should be very sure of what you are doing before making use of this feature.
*
* Compile with:
* gcc -I<path to mosquitto-repo/include> -fPIC -shared mosquitto_payload_modification.c -o mosquitto_payload_modification.so
*
* Use in config with:
*
* plugin /path/to/mosquitto_payload_modification.so
*
* Note that this only works on Mosquitto 2.0 or later.
*/
#include <stdio.h>
#include <string.h>
#include "mosquitto_broker.h"
#include "mosquitto_plugin.h"
#include "mosquitto.h"
#include "mqtt_protocol.h"
#include "json_help.h"
#define UNUSED(A) (void)(A)
static mosquitto_plugin_id_t* mosq_pid = NULL;
static cJSON* subscribedTopics = NULL;
static int callback_control(int event, void* event_data, void* userdata)
{
struct mosquitto_evt_acl_check* ed = event_data;
UNUSED(event);
UNUSED(userdata);
const char * client_id = mosquitto_client_id(ed->client);
const char* topic = ed->topic;
const int access = ed->access;
if (access == MOSQ_ACL_SUBSCRIBE) {
json_create_array(subscribedTopics, topic);
json_add_id_to_array(subscribedTopics, topic, client_id);
char* json_string = cJSON_Print(subscribedTopics);
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: client with id %s subscribed to topic %s", client_id, topic);
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: subscribed topics %s", json_string);
}
else if (access == MOSQ_ACL_UNSUBSCRIBE) {
json_del_id_from_array(subscribedTopics, topic, client_id);
char* json_string = cJSON_Print(subscribedTopics);
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: client with id %s unscribed to topic %s", client_id, topic);
mosquitto_log_printf(MOSQ_LOG_INFO, "wamo: subscribed topics %s", json_string);
}
return MOSQ_ERR_SUCCESS;
}
static int callback_message(int event, void* event_data, void* userdata)
{
struct mosquitto_evt_message* ed = event_data;
char* new_payload;
uint32_t new_payloadlen;
UNUSED(event);
UNUSED(userdata);
/* This simply adds "hello " to the front of every payload. You can of
* course do much more complicated message processing if needed. */
/* Calculate the length of our new payload */
new_payloadlen = ed->payloadlen + (uint32_t)strlen("hello ") + 1;
/* Allocate some memory - use
* mosquitto_calloc/mosquitto_malloc/mosquitto_strdup when allocating, to
* allow the broker to track memory usage */
new_payload = mosquitto_calloc(1, new_payloadlen);
if (new_payload == NULL) {
return MOSQ_ERR_NOMEM;
}
/* Print "hello " to the payload */
snprintf(new_payload, new_payloadlen, "hello ");
memcpy(new_payload + (uint32_t)strlen("hello "), ed->payload, ed->payloadlen);
/* Assign the new payload and payloadlen to the event data structure. You
* must *not* free the original payload, it will be handled by the
* broker. */
ed->payload = new_payload;
ed->payloadlen = new_payloadlen;
return MOSQ_ERR_SUCCESS;
}
int mosquitto_plugin_version(int supported_version_count, const int* supported_versions)
{
int i;
for (i = 0; i < supported_version_count; i++) {
if (supported_versions[i] == 5) {
return 5;
}
}
return -1;
}
int mosquitto_plugin_init(mosquitto_plugin_id_t* identifier, void** user_data, struct mosquitto_opt* opts, int opt_count)
{
int rc;
UNUSED(user_data);
mosq_pid = identifier;
subscribedTopics = cJSON_CreateObject();
rc = mosquitto_callback_register(mosq_pid, MOSQ_EVT_ACL_CHECK, callback_control, NULL, NULL);
if (rc == MOSQ_ERR_ALREADY_EXISTS) {
mosquitto_log_printf(MOSQ_LOG_ERR, "Error: WaMo plugin can currently only be loaded once.");
mosquitto_log_printf(MOSQ_LOG_ERR, "Note that this was previously incorrectly allowed but could cause problems with duplicate entries in the config.");
return rc;
}
else if (rc == MOSQ_ERR_NOMEM) {
mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
return rc;
}
else if (rc != MOSQ_ERR_SUCCESS) {
return rc;
}
return MOSQ_ERR_SUCCESS;
}
int mosquitto_plugin_cleanup(void* user_data, struct mosquitto_opt* opts, int opt_count)
{
UNUSED(user_data);
UNUSED(opts);
UNUSED(opt_count);
return mosquitto_callback_unregister(mosq_pid, MOSQ_EVT_ACL_CHECK, callback_control, NULL);
}