From c7290c6837e92af5f02bc0a12ee595ab2a6a575f Mon Sep 17 00:00:00 2001 From: martin-ger Date: Tue, 15 Dec 2020 23:08:51 +0100 Subject: [PATCH] Methods for infos on clients/onDisconnect callback --- README.md | 25 ++++++++++-- .../uMQTTBrokerSampleOOFull.ino | 25 ++++++++++-- src/mqtt/mqtt_server.h | 7 +++- src/mqtt_server.c | 33 +++++++++++++++- src/uMQTTBroker.cpp | 38 +++++++++++++++++-- src/uMQTTBroker.h | 29 ++++++++++++-- 6 files changed, 142 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index faa91c4..d4ead14 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,28 @@ public: void init(); +// Callbacks on client actions + virtual bool onConnect(IPAddress addr, uint16_t client_count); - virtual bool onAuth(String username, String password); + virtual void onDisconnect(IPAddress addr, String client_id); + virtual bool onAuth(String username, String password, String client_id); virtual void onData(String topic, const char *data, uint32_t length); +// Infos on currently connected clients + + virtual uint16_t getClientCount(); + virtual bool getClientId(uint16_t index, String &client_id); + virtual bool getClientAddr(uint16_t index, IPAddress& addr); + +// Interaction with the local broker + virtual bool publish(String topic, uint8_t* data, uint16_t data_length, uint8_t qos=0, uint8_t retain=0); virtual bool publish(String topic, String data, uint8_t qos=0, uint8_t retain=0); virtual bool subscribe(String topic, uint8_t qos=0); virtual bool unsubscribe(String topic); +// Cleanup all clients on Wifi connection loss + void cleanupClientConnections(); }; ``` @@ -77,19 +90,25 @@ With these functions you can publish and subscribe topics as a local client like Username/password authentication is provided with the following interface: ```c -typedef bool (*MqttAuthCallback)(const char* username, const char *password, struct espconn *pesp_conn); +typedef bool (*MqttAuthCallback)(const char* username, const char *password, const char *client_id, struct espconn *pesp_conn); void MQTT_server_onAuth(MqttAuthCallback authCb); typedef bool (*MqttConnectCallback)(struct espconn *pesp_conn, uint16_t client_count); void MQTT_server_onConnect(MqttConnectCallback connectCb); + +typedef void (*MqttDisconnectCallback)(struct espconn *pesp_conn, const char *client_id); + +void MQTT_server_onDisconnect(MqttDisconnectCallback disconnectCb); ``` -If an *MqttAuthCallback* function is registered with MQTT_server_onAuth(), it is called on each connect request. Based on username, password, and optionally the connection info (e.g. the IP address) the function has to return *true* for authenticated or *false* for rejected. If a request provides no username and/or password these parameter strings are empty. If no *MqttAuthCallback* function is set, each request will be admitted. +If an *MqttAuthCallback* function is registered with MQTT_server_onAuth(), it is called on each connect request. Based on username, password, and optionally the connection info (the client Id and the IP address) the function has to return *true* for authenticated or *false* for rejected. If a request provides no username and/or password these parameter strings are empty. If no *MqttAuthCallback* function is set, each request will be admitted. The *MqttConnectCallback* function does a similar check for the connection, but it is called right after the connect request before the MQTT connect request is processed. This is done in order to reject requests from unautorized clients in an early stage. The number of currently connected clients (incl. the current one) is given in the *client_count* paramater. With this info you can reject too many concurrent connections. +The *MqttDisconnectCallback* is called each time a client disconnects from the server. + If you want to force a cleanup when the broker as a WiFi client (WIFI_STA mode) has lost connectivity to the AP, call: ```c void MQTT_server_cleanupClientCons(); diff --git a/examples/uMQTTBrokerSampleOOFull/uMQTTBrokerSampleOOFull.ino b/examples/uMQTTBrokerSampleOOFull/uMQTTBrokerSampleOOFull.ino index 5456ea7..6a7c369 100644 --- a/examples/uMQTTBrokerSampleOOFull/uMQTTBrokerSampleOOFull.ino +++ b/examples/uMQTTBrokerSampleOOFull/uMQTTBrokerSampleOOFull.ino @@ -26,9 +26,13 @@ public: Serial.println(addr.toString()+" connected"); return true; } - - virtual bool onAuth(String username, String password) { - Serial.println("Username/Password: "+username+"/"+password); + + virtual void onDisconnect(IPAddress addr, String client_id) { + Serial.println(addr.toString()+" ("+client_id+") disconnected"); + } + + virtual bool onAuth(String username, String password, String client_id) { + Serial.println("Username/Password/ClientId: "+username+"/"+password+"/"+client_id); return true; } @@ -38,6 +42,20 @@ public: data_str[length] = '\0'; Serial.println("received topic '"+topic+"' with data '"+(String)data_str+"'"); + //printClients(); + } + + // Sample for the usage of the client info methods + + virtual void printClients() { + for (int i = 0; i < getClientCount(); i++) { + IPAddress addr; + String client_id; + + getClientAddr(i, addr); + getClientId(i, client_id); + Serial.println("Client "+client_id+" on addr: "+addr.toString()); + } } }; @@ -104,4 +122,3 @@ void loop() // wait a second delay(1000); } - diff --git a/src/mqtt/mqtt_server.h b/src/mqtt/mqtt_server.h index 1dbe99b..a950f15 100644 --- a/src/mqtt/mqtt_server.h +++ b/src/mqtt/mqtt_server.h @@ -14,8 +14,9 @@ #define LOCAL_MQTT_CLIENT ((void*)-1) -typedef bool (*MqttAuthCallback)(const char* username, const char *password, struct espconn *pesp_conn); +typedef bool (*MqttAuthCallback)(const char* username, const char *password, const char* client_id, struct espconn *pesp_conn); typedef bool (*MqttConnectCallback)(struct espconn *pesp_conn, uint16_t client_count); +typedef bool (*MqttDisconnectCallback)(struct espconn *pesp_conn, const char* client_id); typedef struct _MQTT_ClientCon { struct espconn *pCon; @@ -42,12 +43,16 @@ typedef struct _MQTT_ClientCon { extern MQTT_ClientCon *clientcon_list; uint16_t MQTT_server_countClientCon(); +const char* MQTT_server_getClientId(uint16_t index); +const struct espconn* MQTT_server_getClientPcon(uint16_t index); + void MQTT_server_disconnectClientCon(MQTT_ClientCon *mqttClientCon); bool MQTT_server_deleteClientCon(MQTT_ClientCon *mqttClientCon); void MQTT_server_cleanupClientCons(); bool MQTT_server_start(uint16_t portno, uint16_t max_subscriptions, uint16_t max_retained_topics); void MQTT_server_onConnect(MqttConnectCallback connectCb); +void MQTT_server_onDisconnect(MqttDisconnectCallback connectCb); void MQTT_server_onAuth(MqttAuthCallback authCb); void MQTT_server_onData(MqttDataCallback dataCb); diff --git a/src/mqtt_server.c b/src/mqtt_server.c index 933098f..66d0ccf 100644 --- a/src/mqtt_server.c +++ b/src/mqtt_server.c @@ -35,6 +35,7 @@ LOCAL uint8_t zero_len_id[2] = { 0, 0 }; MQTT_ClientCon *clientcon_list; LOCAL MqttDataCallback local_data_cb = NULL; LOCAL MqttConnectCallback local_connect_cb = NULL; +LOCAL MqttDisconnectCallback local_disconnect_cb = NULL; LOCAL MqttAuthCallback local_auth_cb = NULL; MQTT_ClientCon dummy_clientcon; @@ -149,6 +150,28 @@ uint16_t ICACHE_FLASH_ATTR MQTT_server_countClientCon() { return count; } +const char* ICACHE_FLASH_ATTR MQTT_server_getClientId(uint16_t index) { + MQTT_ClientCon *p; + uint16_t count = 0; + for (p = clientcon_list; p != NULL; p = p->next, count++) { + if (count == index) { + return p->connect_info.client_id; + } + } + return NULL; +} + +const struct espconn* ICACHE_FLASH_ATTR MQTT_server_getClientPcon(uint16_t index) { + MQTT_ClientCon *p; + uint16_t count = 0; + for (p = clientcon_list; p != NULL; p = p->next, count++) { + if (count == index) { + return p->pCon; + } + } + return NULL; +} + bool ICACHE_FLASH_ATTR MQTT_server_deleteClientCon(MQTT_ClientCon * mqttClientCon) { MQTT_INFO("MQTT: DeleteClientCon\r\n"); @@ -196,7 +219,10 @@ bool ICACHE_FLASH_ATTR MQTT_server_deleteClientCon(MQTT_ClientCon * mqttClientCo if (mqttClientCon->connect_info.client_id != NULL) { /* Don't attempt to free if it's the zero_len array */ if (((uint8_t *) mqttClientCon->connect_info.client_id) != zero_len_id) - os_free(mqttClientCon->connect_info.client_id); + if (local_disconnect_cb != NULL) { + local_disconnect_cb(mqttClientCon->pCon, mqttClientCon->connect_info.client_id); + } + os_free(mqttClientCon->connect_info.client_id); mqttClientCon->connect_info.client_id = NULL; } @@ -564,6 +590,7 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns if ((local_auth_cb != NULL) && local_auth_cb(clientcon->connect_info.username==NULL?"":clientcon->connect_info.username, clientcon->connect_info.password==NULL?"":clientcon->connect_info.password, + clientcon->connect_info.client_id, clientcon->pCon) == false) { MQTT_WARNING("MQTT: Authorization failed\r\n"); @@ -977,6 +1004,10 @@ void ICACHE_FLASH_ATTR MQTT_server_onConnect(MqttConnectCallback connectCb) { local_connect_cb = connectCb; } +void ICACHE_FLASH_ATTR MQTT_server_onDisconnect(MqttDisconnectCallback disconnectCb) { + local_disconnect_cb = disconnectCb; +} + void ICACHE_FLASH_ATTR MQTT_server_onAuth(MqttAuthCallback authCb) { local_auth_cb = authCb; } diff --git a/src/uMQTTBroker.cpp b/src/uMQTTBroker.cpp index e29c15d..f076fa8 100644 --- a/src/uMQTTBroker.cpp +++ b/src/uMQTTBroker.cpp @@ -11,8 +11,15 @@ uMQTTBroker *uMQTTBroker::TheBroker; return TheBroker->onConnect(connAddr, client_count); } - bool uMQTTBroker::_onAuth(const char* username, const char *password, struct espconn *pesp_conn) { - return TheBroker->onAuth((String)username, (String)password); + void uMQTTBroker::_onDisconnect(struct espconn *pesp_conn, const char *client_id) { + IPAddress connAddr(pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1], + pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3]); + + TheBroker->onDisconnect(connAddr, (String)client_id); + } + + bool uMQTTBroker::_onAuth(const char* username, const char *password, const char* client_id, struct espconn *pesp_conn) { + return TheBroker->onAuth((String)username, (String)password, (String)client_id); } void uMQTTBroker::_onData(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t length) { @@ -30,6 +37,7 @@ uMQTTBroker *uMQTTBroker::TheBroker; _max_retained_topics = max_retained_topics; MQTT_server_onConnect(_onConnect); + MQTT_server_onDisconnect(_onDisconnect); MQTT_server_onAuth(_onAuth); MQTT_server_onData(_onData); } @@ -42,7 +50,11 @@ uMQTTBroker *uMQTTBroker::TheBroker; return true; } - bool uMQTTBroker::onAuth(String username, String password) { + void uMQTTBroker::onDisconnect(IPAddress addr, String client_id) { + return; + } + + bool uMQTTBroker::onAuth(String username, String password, String client_id) { return true; } @@ -53,6 +65,26 @@ uMQTTBroker *uMQTTBroker::TheBroker; return MQTT_local_publish((uint8_t*)topic.c_str(), data, data_length, qos, retain); } + uint16_t uMQTTBroker::getClientCount() { + return MQTT_server_countClientCon(); + } + + bool uMQTTBroker::getClientId(uint16_t index, String &client_id) { + const char *c = MQTT_server_getClientId(index); + if (c == NULL) + return false; + client_id = c; + return true; + } + + bool uMQTTBroker::getClientAddr(uint16_t index, IPAddress& addr) { + const struct espconn* pesp_conn = MQTT_server_getClientPcon(index); + if (pesp_conn == NULL) + return false; + addr = pesp_conn->proto.tcp->remote_ip; + return true; + } + bool uMQTTBroker::publish(String topic, String data, uint8_t qos, uint8_t retain) { return MQTT_local_publish((uint8_t*)topic.c_str(), (uint8_t*)data.c_str(), data.length(), qos, retain); } diff --git a/src/uMQTTBroker.h b/src/uMQTTBroker.h index 4de41d8..6b6c41f 100644 --- a/src/uMQTTBroker.h +++ b/src/uMQTTBroker.h @@ -18,12 +18,14 @@ bool MQTT_server_start(uint16_t portno, uint16_t max_subscriptions, uint16_t max // Callbacks for message reception, username/password authentication, and client connection typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh); -typedef bool (*MqttAuthCallback)(const char* username, const char *password, struct espconn *pesp_conn); +typedef bool (*MqttAuthCallback)(const char* username, const char *password, const char *client_id, struct espconn *pesp_conn); typedef bool (*MqttConnectCallback)(struct espconn *pesp_conn, uint16_t client_count); +typedef void (*MqttDisconnectCallback)(struct espconn *pesp_conn, const char *client_id); void MQTT_server_onData(MqttDataCallback dataCb); void MQTT_server_onAuth(MqttAuthCallback authCb); void MQTT_server_onConnect(MqttConnectCallback connectCb); +void MQTT_server_onDisconnect(MqttDisconnectCallback disconnectCb); // Interface for local pub/sub interaction with the broker @@ -42,6 +44,13 @@ void MQTT_server_cleanupClientCons(); void clear_retainedtopics(); int serialize_retainedtopics(char *buf, int len); bool deserialize_retainedtopics(char *buf, int len); + +// Interface for getting some infos on the currently connected clients +// MQTT_server_getClientId() and MQTT_server_getClientPcon() return NULL on invalid indices + +uint16_t MQTT_server_countClientCon(); +const char* MQTT_server_getClientId(uint16_t index); +const struct espconn* MQTT_server_getClientPcon(uint16_t index); } class uMQTTBroker @@ -53,7 +62,8 @@ private: uint16_t _max_retained_topics; static bool _onConnect(struct espconn *pesp_conn, uint16_t client_count); - static bool _onAuth(const char* username, const char *password, struct espconn *pesp_conn); + static void _onDisconnect(struct espconn *pesp_conn, const char *client_id); + static bool _onAuth(const char* username, const char *password, const char *client_id, struct espconn *pesp_conn); static void _onData(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t length); public: @@ -61,15 +71,28 @@ public: void init(); +// Callbacks on client actions + virtual bool onConnect(IPAddress addr, uint16_t client_count); - virtual bool onAuth(String username, String password); + virtual void onDisconnect(IPAddress addr, String client_id); + virtual bool onAuth(String username, String password, String client_id); virtual void onData(String topic, const char *data, uint32_t length); +// Infos on currently connected clients + + virtual uint16_t getClientCount(); + virtual bool getClientId(uint16_t index, String &client_id); + virtual bool getClientAddr(uint16_t index, IPAddress& addr); + +// Interaction with the local broker + virtual bool publish(String topic, uint8_t* data, uint16_t data_length, uint8_t qos=0, uint8_t retain=0); virtual bool publish(String topic, String data, uint8_t qos=0, uint8_t retain=0); virtual bool subscribe(String topic, uint8_t qos=0); virtual bool unsubscribe(String topic); +// Cleanup all clients on Wifi connection loss + void cleanupClientConnections(); };