2021-12-11 23:37:41 +01:00
/*
Copyright ( c ) 2021 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 .
*/
# include "config.h"
# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/stat.h>
2022-07-21 16:51:52 +02:00
# ifdef WIN32
# include <direct.h>
# endif
2021-12-11 23:37:41 +01:00
# include "mosquitto.h"
2023-12-23 13:59:58 +01:00
# include "mosquitto/broker.h"
# include "mosquitto/broker_plugin.h"
# include "mosquitto/mqtt_protocol.h"
2021-12-11 23:37:41 +01:00
# include "persist_sqlite.h"
2022-05-18 16:11:13 +02:00
MOSQUITTO_PLUGIN_DECLARE_VERSION ( 5 ) ;
2021-12-11 23:37:41 +01:00
static mosquitto_plugin_id_t * plg_id = NULL ;
static struct mosquitto_sqlite plg_data ;
2025-07-07 12:33:16 +02:00
static int conf_parse_uint ( const char * in , const char * name , unsigned int * value , int min_value )
2022-04-29 07:35:47 +02:00
{
int v = atoi ( in ) ;
2025-07-07 12:33:16 +02:00
if ( v < min_value ) {
mosquitto_log_printf ( MOSQ_LOG_ERR , " Error: Invalid '%s' value %d in configuration. " , name , v ) ;
2022-04-29 07:35:47 +02:00
return MOSQ_ERR_INVAL ;
}
2022-04-29 23:12:55 +02:00
* value = ( unsigned int ) v ;
2022-04-29 07:35:47 +02:00
return MOSQ_ERR_SUCCESS ;
}
static void set_defaults ( void )
{
/* "normal" synchronous mode. */
plg_data . synchronous = 1 ;
/* 5 seconds */
plg_data . flush_period = 5 ;
plg_data . page_size = 4 * 1024 ;
}
2022-05-18 16:11:13 +02:00
static int get_db_file ( struct mosquitto_opt * options , int option_count )
2021-12-11 23:37:41 +01:00
{
2022-05-18 16:11:13 +02:00
const char * persistence_location ;
2021-12-11 23:37:41 +01:00
int i ;
2022-05-18 16:11:13 +02:00
persistence_location = mosquitto_persistence_location ( ) ;
if ( persistence_location ) {
2022-07-21 16:51:52 +02:00
# ifdef WIN32
( void ) mkdir ( persistence_location ) ;
# else
2022-08-02 00:06:23 +02:00
( void ) mkdir ( persistence_location , 0770 ) ;
2022-07-21 16:51:52 +02:00
# endif
2022-05-18 16:11:13 +02:00
plg_data . db_file = malloc ( strlen ( persistence_location ) + 1 + strlen ( " /mosquitto.sqlite3 " ) ) ;
if ( ! plg_data . db_file ) {
mosquitto_log_printf ( MOSQ_LOG_INFO , " Sqlite persistence: Out of memory. " ) ;
return MOSQ_ERR_NOMEM ;
}
sprintf ( plg_data . db_file , " %s/mosquitto.sqlite3 " , persistence_location ) ;
} else {
for ( i = 0 ; i < option_count ; i + + ) {
if ( ! strcasecmp ( options [ i ] . key , " db_file " ) ) {
plg_data . db_file = mosquitto_strdup ( options [ i ] . value ) ;
if ( plg_data . db_file = = NULL ) {
return MOSQ_ERR_NOMEM ;
}
}
2021-12-11 23:37:41 +01:00
}
}
2022-05-18 16:11:13 +02:00
return MOSQ_ERR_SUCCESS ;
2021-12-11 23:37:41 +01:00
}
int mosquitto_plugin_init ( mosquitto_plugin_id_t * identifier , void * * user_data , struct mosquitto_opt * options , int option_count )
{
int i ;
int rc ;
UNUSED ( user_data ) ;
memset ( & plg_data , 0 , sizeof ( struct mosquitto_sqlite ) ) ;
2022-04-29 07:35:47 +02:00
set_defaults ( ) ;
2021-12-11 23:37:41 +01:00
2022-05-18 16:11:13 +02:00
if ( get_db_file ( options , option_count ) ) {
return MOSQ_ERR_UNKNOWN ;
}
2021-12-11 23:37:41 +01:00
for ( i = 0 ; i < option_count ; i + + ) {
2022-05-18 16:11:13 +02:00
if ( ! strcasecmp ( options [ i ] . key , " sync " ) ) {
2021-12-11 23:37:41 +01:00
if ( ! strcasecmp ( options [ i ] . value , " extra " ) ) {
plg_data . synchronous = 3 ;
} else if ( ! strcasecmp ( options [ i ] . value , " full " ) ) {
plg_data . synchronous = 2 ;
} else if ( ! strcasecmp ( options [ i ] . value , " normal " ) ) {
plg_data . synchronous = 1 ;
} else if ( ! strcasecmp ( options [ i ] . value , " off " ) ) {
plg_data . synchronous = 0 ;
} else {
mosquitto_log_printf ( MOSQ_LOG_ERR , " Sqlite persistence: Invalid plugin_opt_sync value '%s'. " , options [ i ] . value ) ;
return MOSQ_ERR_INVAL ;
}
2022-04-29 07:35:47 +02:00
} else if ( ! strcasecmp ( options [ i ] . key , " flush_period " ) ) {
2025-07-07 12:33:16 +02:00
rc = conf_parse_uint ( options [ i ] . value , " flush_period " , & plg_data . flush_period , 0 ) ;
2022-04-29 07:35:47 +02:00
if ( rc ) return rc ;
} else if ( ! strcasecmp ( options [ i ] . key , " page_size " ) ) {
2025-07-07 12:33:16 +02:00
rc = conf_parse_uint ( options [ i ] . value , " page_size " , & plg_data . page_size , 1 ) ;
2022-04-29 07:35:47 +02:00
if ( rc ) return rc ;
2021-12-11 23:37:41 +01:00
}
}
if ( plg_data . db_file = = NULL ) {
mosquitto_log_printf ( MOSQ_LOG_WARNING , " Warning: Sqlite persistence plugin has no plugin_opt_db_file defined. The plugin will not be activated. " ) ;
return MOSQ_ERR_SUCCESS ;
}
rc = persist_sqlite__init ( & plg_data ) ;
if ( rc ) return rc ;
plg_id = identifier ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_RESTORE , persist_sqlite__restore_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
2022-02-22 17:57:24 +01:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_BASE_MSG_ADD , persist_sqlite__base_msg_add_cb , NULL , & plg_data ) ;
2021-12-11 23:37:41 +01:00
if ( rc ) goto fail ;
2022-02-22 17:57:24 +01:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_BASE_MSG_DELETE , persist_sqlite__base_msg_remove_cb , NULL , & plg_data ) ;
2021-12-11 23:37:41 +01:00
if ( rc ) goto fail ;
2022-03-01 21:30:26 +01:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_RETAIN_MSG_SET , persist_sqlite__retain_msg_set_cb , NULL , & plg_data ) ;
2021-12-11 23:37:41 +01:00
if ( rc ) goto fail ;
2022-02-22 17:57:24 +01:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_RETAIN_MSG_DELETE , persist_sqlite__retain_msg_remove_cb , NULL , & plg_data ) ;
2021-12-11 23:37:41 +01:00
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_ADD , persist_sqlite__client_add_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_DELETE , persist_sqlite__client_remove_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_UPDATE , persist_sqlite__client_update_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_SUBSCRIPTION_ADD , persist_sqlite__subscription_add_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_SUBSCRIPTION_DELETE , persist_sqlite__subscription_remove_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_ADD , persist_sqlite__client_msg_add_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_DELETE , persist_sqlite__client_msg_remove_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_UPDATE , persist_sqlite__client_msg_update_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
2025-07-07 12:33:16 +02:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_WILL_ADD , persist_sqlite__will_add_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_PERSIST_WILL_DELETE , persist_sqlite__will_remove_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
2022-02-12 00:38:50 +01:00
rc = mosquitto_callback_register ( plg_id , MOSQ_EVT_TICK , persist_sqlite__tick_cb , NULL , & plg_data ) ;
if ( rc ) goto fail ;
2021-12-11 23:37:41 +01:00
return MOSQ_ERR_SUCCESS ;
fail :
if ( rc = = MOSQ_ERR_NOT_SUPPORTED ) {
mosquitto_log_printf ( MOSQ_LOG_ERR , " Sqlite persistence: Unable to register plugin: broker doesn't support persistence plugins, please upgrade to 2.1 or higher " ) ;
} else if ( rc = = MOSQ_ERR_NOMEM ) {
mosquitto_log_printf ( MOSQ_LOG_ERR , " Sqlite persistence: Unable to register plugin: out of memory " ) ;
} else {
mosquitto_log_printf ( MOSQ_LOG_ERR , " Sqlite persistence: Unable to register plugin (%d) " , rc ) ;
}
mosquitto_plugin_cleanup ( NULL , NULL , 0 ) ;
return rc ;
}
int mosquitto_plugin_cleanup ( void * user_data , struct mosquitto_opt * options , int option_count )
{
UNUSED ( user_data ) ;
UNUSED ( options ) ;
UNUSED ( option_count ) ;
if ( plg_id ) {
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_RESTORE , persist_sqlite__restore_cb , NULL ) ;
2022-02-22 17:57:24 +01:00
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_BASE_MSG_ADD , persist_sqlite__base_msg_add_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_BASE_MSG_DELETE , persist_sqlite__base_msg_remove_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_RETAIN_MSG_DELETE , persist_sqlite__retain_msg_remove_cb , NULL ) ;
2021-12-11 23:37:41 +01:00
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_CLIENT_ADD , persist_sqlite__client_add_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_CLIENT_DELETE , persist_sqlite__client_remove_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_SUBSCRIPTION_ADD , persist_sqlite__subscription_add_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_SUBSCRIPTION_DELETE , persist_sqlite__subscription_remove_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_ADD , persist_sqlite__client_msg_add_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_DELETE , persist_sqlite__client_msg_remove_cb , NULL ) ;
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_PERSIST_CLIENT_MSG_UPDATE , persist_sqlite__client_msg_update_cb , NULL ) ;
2022-02-12 00:38:50 +01:00
mosquitto_callback_unregister ( plg_id , MOSQ_EVT_TICK , persist_sqlite__tick_cb , NULL ) ;
2021-12-11 23:37:41 +01:00
}
mosquitto_free ( plg_data . db_file ) ;
persist_sqlite__cleanup ( & plg_data ) ;
memset ( & plg_data , 0 , sizeof ( struct mosquitto_sqlite ) ) ;
return MOSQ_ERR_SUCCESS ;
}