Add mosquitto_kick_client_by_clientid() and mosquitto_kick_client_by_username()

These can be used by plugins to disconnect clients.
This commit is contained in:
Roger A. Light 2020-09-07 13:49:42 +01:00
parent 3f1515e337
commit f0862e26ec
7 changed files with 114 additions and 1 deletions

View File

@ -18,6 +18,8 @@ Broker:
plugins to determine which version of MQTT a client has connected with.
- Send DISCONNECT with `malformed-packet` reason code on invalid PUBLISH,
SUBSCRIBE, and UNSUBSCRIBE packets.
- Add `mosquitto_kick_client_by_clientid()` and `mosquitto_kick_client_by_username()`
functions, which can be used by plugins to disconnect clients.
Client library:
- Client no longer generates random client ids for v3.1.1 clients, these are

View File

@ -101,6 +101,7 @@ enum mosq_err_t {
MOSQ_ERR_TIMEOUT = 27,
MOSQ_ERR_RETAIN_NOT_SUPPORTED = 28,
MOSQ_ERR_TOPIC_ALIAS_INVALID = 29,
MOSQ_ERR_ADMINISTRATIVE_ACTION = 30,
};
/* Option values */

View File

@ -9,6 +9,8 @@ _mosquitto_client_protocol
_mosquitto_client_protocol_version
_mosquitto_client_sub_count
_mosquitto_client_username
_mosquitto_kick_client_by_clientid
_mosquitto_kick_client_by_username
_mosquitto_log_printf
_mosquitto_property_add_binary
_mosquitto_property_add_byte

View File

@ -10,6 +10,8 @@
mosquitto_client_protocol_version;
mosquitto_client_sub_count;
mosquitto_client_username;
mosquitto_kick_client_by_clientid;
mosquitto_kick_client_by_username;
mosquitto_log_printf;
mosquitto_plugin_publish;
mosquitto_property_add_binary;

View File

@ -300,12 +300,19 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context, int reaso
case MOSQ_ERR_KEEPALIVE:
log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", id);
break;
case MOSQ_ERR_ADMINISTRATIVE_ACTION:
log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s been disconnected by administrative action.", id);
break;
default:
log__printf(NULL, MOSQ_LOG_NOTICE, "Socket error on client %s, disconnecting.", id);
break;
}
}else{
log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s disconnected.", id);
if(reason == MOSQ_ERR_ADMINISTRATIVE_ACTION){
log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s been disconnected by administrative action.", id);
}else{
log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s disconnected.", id);
}
}
}
mux__delete(db, context);

View File

@ -179,6 +179,46 @@ const char *mosquitto_client_username(const struct mosquitto *client);
int mosquitto_set_username(struct mosquitto *client, const char *username);
/* =========================================================================
*
* Client control
*
* ========================================================================= */
/* Function: mosquitto_kick_client_by_clientid
*
* Forcefully disconnect a client from the broker.
*
* If clientid != NULL, then the client with the matching client id is
* disconnected from the broker.
* If clientid == NULL, then all clients are disconnected from the broker.
*
* If with_will == true, then if the client has a Last Will and Testament
* defined then this will be sent. If false, the LWT will not be sent.
*/
int mosquitto_kick_client_by_clientid(const char *clientid, bool with_will);
/* Function: mosquitto_kick_client_by_username
*
* Forcefully disconnect a client from the broker.
*
* If username != NULL, then all clients with a matching username are kicked
* from the broker.
* If username == NULL, then all clients that do not have a username are
* kicked.
*
* If with_will == true, then if the client has a Last Will and Testament
* defined then this will be sent. If false, the LWT will not be sent.
*/
int mosquitto_kick_client_by_username(const char *username, bool with_will);
/* =========================================================================
*
* Publishing functions
*
* ========================================================================= */
/* Function: mosquitto_broker_publish
*
* Publish a message from within a plugin.

View File

@ -20,6 +20,9 @@ Contributors:
#include "mosquitto_internal.h"
#include "mosquitto_broker.h"
#include "memory_mosq.h"
#include "mqtt_protocol.h"
#include "send_mosq.h"
#include "util_mosq.h"
#include "utlist.h"
#ifdef WITH_TLS
@ -230,3 +233,59 @@ int mosquitto_set_username(struct mosquitto *client, const char *username)
}
}
static void disconnect_client(struct mosquitto_db *db, struct mosquitto *context, bool with_will)
{
if(context->protocol == mosq_p_mqtt5){
send__disconnect(context, MQTT_RC_ADMINISTRATIVE_ACTION, NULL);
}
if(with_will == false){
mosquitto__set_state(context, mosq_cs_disconnecting);
}
do_disconnect(db, context, MOSQ_ERR_ADMINISTRATIVE_ACTION);
}
int mosquitto_kick_client_by_clientid(const char *clientid, bool with_will)
{
struct mosquitto_db *db;
struct mosquitto *ctxt, *ctxt_tmp;
db = mosquitto__get_db();
if(clientid == NULL){
HASH_ITER(hh_sock, db->contexts_by_sock, ctxt, ctxt_tmp){
disconnect_client(db, ctxt, with_will);
}
return MOSQ_ERR_SUCCESS;
}else{
HASH_FIND(hh_id, db->contexts_by_id, clientid, strlen(clientid), ctxt);
if(ctxt){
disconnect_client(db, ctxt, with_will);
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOT_FOUND;
}
}
}
int mosquitto_kick_client_by_username(const char *username, bool with_will)
{
struct mosquitto_db *db;
struct mosquitto *ctxt, *ctxt_tmp;
db = mosquitto__get_db();
if(username == NULL){
HASH_ITER(hh_sock, db->contexts_by_sock, ctxt, ctxt_tmp){
if(ctxt->username == NULL){
disconnect_client(db, ctxt, with_will);
}
}
}else{
HASH_ITER(hh_sock, db->contexts_by_sock, ctxt, ctxt_tmp){
if(ctxt->username != NULL && !strcmp(ctxt->username, username)){
disconnect_client(db, ctxt, with_will);
}
}
}
return MOSQ_ERR_SUCCESS;
}