Greenbone Vulnerability Management Libraries 22.18.1
mqtt.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021-2023 Greenbone AG
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
26
27#include "mqtt.h"
28
29#include "uuidutils.h" /* gvm_uuid_make */
30
31#include <stdlib.h>
32#include <string.h>
33
34#undef G_LOG_DOMAIN
35#define G_LOG_DOMAIN "libgvm util"
36
37#define QOS 1
38#define TIMEOUT 10000L
39
40typedef struct
41{
42 void *client;
43 char *client_id;
44} mqtt_t;
45
46static const char *global_server_uri = NULL;
47static const char *global_username = NULL;
48static const char *global_password = NULL;
50static gboolean mqtt_initialized = FALSE;
51
57static void
59{
60 mqtt_initialized = status;
61}
62
68gboolean
73
79static void
80mqtt_set_global_server_uri (const char *server_uri_in)
81{
82 global_server_uri = server_uri_in;
83}
84
90static const char *
95
101static void
102mqtt_set_global_username (const char *username)
103{
104 global_username = username;
105}
106
110static const char *
115
121static void
122mqtt_set_global_password (const char *password)
123{
124 global_password = password;
125}
126
130static const char *
135
141static mqtt_t *
146
150static void
155
163static int
165{
166 int rc;
167
168 rc = MQTTClient_disconnect5 (mqtt->client, 200,
169 MQTTREASONCODE_NORMAL_DISCONNECTION, NULL);
170 if (rc != MQTTCLIENT_SUCCESS)
171 {
172 g_warning ("Failed to disconnect: %s", MQTTClient_strerror (rc));
173 return -1;
174 }
175
176 return 0;
177}
178
185static void
187{
188 if (mqtt && mqtt->client)
189 {
190 MQTTClient_destroy (&mqtt->client);
191 mqtt->client = NULL;
192 }
193}
194
200static void
202{
203 g_free ((*mqtt)->client_id);
204 g_free (*mqtt);
205 *mqtt = NULL;
206}
207
211void
213{
214 g_debug ("%s: start", __func__);
216
217 if (mqtt == NULL)
218 return;
219
220 mqtt_client_destroy (mqtt);
222
224
225 g_debug ("%s: end", __func__);
226 return;
227}
228
237static MQTTClient
238mqtt_create (mqtt_t *mqtt, const char *address)
239{
240 MQTTClient client;
241 MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer;
242 create_opts.MQTTVersion = MQTTVERSION_5;
243
244 if (mqtt == NULL || mqtt->client_id == NULL)
245 return NULL;
246
247 int rc = MQTTClient_createWithOptions (&client, address, mqtt->client_id,
248 MQTTCLIENT_PERSISTENCE_NONE, NULL,
249 &create_opts);
250
251 if (rc != MQTTCLIENT_SUCCESS)
252 {
253 g_warning ("%s: Error creating MQTTClient: %s", __func__,
254 MQTTClient_strerror (rc));
255 MQTTClient_destroy (&client);
256 return NULL;
257 }
258 return client;
259}
260
268static char *
270{
271 if (mqtt == NULL)
272 return NULL;
273
274 char *uuid;
275
276 uuid = gvm_uuid_make ();
277 mqtt->client_id = uuid;
278
279 return uuid;
280}
281
287static int
288mqtt_set_client (mqtt_t *mqtt, MQTTClient client)
289{
290 if (mqtt == NULL)
291 {
292 return -1;
293 }
294 mqtt->client = client;
295 return 0;
296}
297
308static int
309mqtt_connect (mqtt_t *mqtt, const char *server_uri, const char *username,
310 const char *password)
311{
312 int rc;
313 MQTTClient client;
314 MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer5;
315 MQTTProperties connect_properties = MQTTProperties_initializer;
316 MQTTResponse resp;
317
318 if (mqtt == NULL)
319 return -1;
320
321 client = mqtt_create (mqtt, server_uri);
322 if (!client)
323 return -2;
324
325 conn_opts.keepAliveInterval = 0;
326 conn_opts.cleanstart = 1;
327 conn_opts.MQTTVersion = MQTTVERSION_5;
328
329 if (username != NULL && password != NULL)
330 {
331 conn_opts.username = username;
332 conn_opts.password = password;
333 }
334
335 resp = MQTTClient_connect5 (client, &conn_opts, &connect_properties, NULL);
336 rc = resp.reasonCode;
337 MQTTProperties_free (&connect_properties);
338 if (rc != MQTTCLIENT_SUCCESS)
339 {
340 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
341 "%s: mqtt connection error to %s: %s", __func__, server_uri,
342 MQTTClient_strerror (rc));
343 MQTTResponse_free (resp);
344 return -3;
345 }
346
347 mqtt_set_client (mqtt, client);
348
349 MQTTResponse_free (resp);
350 return 0;
351}
352
360int
361mqtt_init (const char *server_uri)
362{
363 return mqtt_init_auth (server_uri, NULL, NULL);
364}
365
374int
375mqtt_init_auth (const char *server_uri, const char *username,
376 const char *password)
377{
378 mqtt_t *mqtt = NULL;
379
380 g_debug ("%s: start", __func__);
381
382 mqtt = g_malloc0 (sizeof (mqtt_t));
383 // Set random uuid as client id
384 if (mqtt_set_client_id (mqtt) == NULL)
385 {
386 g_warning ("%s: Could not set client id.", __func__);
387 g_free (mqtt);
388 mqtt = NULL;
389 return -1;
390 }
391 g_debug ("%s: client id set: %s", __func__, mqtt->client_id);
392 if (mqtt_get_global_server_uri () == NULL)
393 mqtt_set_global_server_uri (server_uri);
394
395 if (mqtt_get_global_username () == NULL)
396 mqtt_set_global_username (username);
397
398 if (mqtt_get_global_password () == NULL)
399 mqtt_set_global_password (password);
400
401 if (mqtt_connect (mqtt, server_uri, username, password))
402 {
403 g_warning ("%s: Unable to connect to MQTT broker.", __func__);
404 g_free (mqtt);
405 mqtt = NULL;
406 return -1;
407 }
408
411
412 g_debug ("%s: end", __func__);
413 return 0;
414}
415
420static void
422{
423 const char *server_uri;
424 const char *username;
425 const char *password;
426
427 server_uri = mqtt_get_global_server_uri ();
428 if (server_uri == NULL)
429 {
430 g_warning ("%s: mqtt_init() has to be called once at program start "
431 "else the server URI is not set. ",
432 __func__);
433 }
434 username = mqtt_get_global_username ();
435 password = mqtt_get_global_password ();
436 mqtt_init_auth (server_uri, username, password);
437}
438
448static int
449mqtt_client_publish (mqtt_t *mqtt, const char *topic, const char *msg)
450{
451 MQTTClient client;
452 MQTTClient_message pubmsg = MQTTClient_message_initializer;
453 MQTTClient_deliveryToken token;
454 MQTTResponse resp;
455 int rc;
456
457 client = mqtt->client;
458 if (client == NULL)
459 {
460 return -1;
461 }
462
463 pubmsg.payload = (char *) msg;
464 pubmsg.payloadlen = (int) strlen (msg);
465 pubmsg.qos = QOS;
466 pubmsg.retained = 0;
467
468 resp = MQTTClient_publishMessage5 (client, topic, &pubmsg, &token);
469 rc = resp.reasonCode;
470 if (rc != MQTTCLIENT_SUCCESS)
471 {
472 g_warning ("Failed to connect: %s", MQTTClient_strerror (rc));
473 MQTTResponse_free (resp);
474 return -2;
475 }
476
477 rc = MQTTClient_waitForCompletion (client, token, TIMEOUT);
478 if (rc != MQTTCLIENT_SUCCESS)
479 {
480 g_debug ("Message '%s' with delivery token %d could not be "
481 "published on topic %s",
482 msg, token, topic);
483 }
484
485 MQTTResponse_free (resp);
486 return rc;
487}
488
497int
498mqtt_publish (const char *topic, const char *msg)
499{
500 mqtt_t *mqtt = NULL;
501 int rc = 0;
502
503 if ((mqtt_get_global_client ()) == NULL)
504 mqtt_reinit ();
505 mqtt = mqtt_get_global_client ();
506
507 rc = mqtt_client_publish (mqtt, topic, msg);
508
509 return rc;
510}
511
526int
527mqtt_publish_single_message (const char *server_uri_in, const char *topic,
528 const char *msg)
529{
530 return mqtt_publish_single_message_auth (server_uri_in, NULL, NULL, topic,
531 msg);
532}
533
549int
550mqtt_publish_single_message_auth (const char *server_uri_in,
551 const char *username_in,
552 const char *passwd_in, const char *topic,
553 const char *msg)
554{
555 const char *server_uri;
556 const char *username = NULL;
557 const char *password = NULL;
558 mqtt_t *mqtt = NULL;
559 int ret = 0;
560
561 // If server_uri is NULL try to get global
562 if (server_uri_in == NULL)
563 {
564 server_uri = mqtt_get_global_server_uri ();
565 if (server_uri == NULL)
566 {
567 g_warning (
568 "%s: No server URI provided and no global server URI available.",
569 __func__);
570 return -1;
571 }
572 }
573 else
574 {
575 server_uri = server_uri_in;
576 }
577
578 if (username_in == NULL || passwd_in == NULL)
579 {
580 username = mqtt_get_global_username ();
581 password = mqtt_get_global_password ();
582 }
583 else
584 {
585 username = username_in;
586 password = passwd_in;
587 }
588
589 mqtt = g_malloc0 (sizeof (mqtt_t));
590 // Set random uuid as client id
591 if (mqtt_set_client_id (mqtt) == NULL)
592 {
593 g_warning ("%s: Could not set client id.", __func__);
594 g_free (mqtt);
595 return -2;
596 }
597
598 mqtt_connect (mqtt, server_uri, username, password);
599 mqtt_client_publish (mqtt, topic, msg);
600
601 mqtt_disconnect (mqtt);
602 mqtt_client_destroy (mqtt);
604
605 return ret;
606}
607
624static int
625mqtt_subscribe_r (mqtt_t *mqtt, int qos, const char *topic)
626{
627 if (mqtt == NULL || mqtt->client == NULL)
628 {
629 return -1;
630 }
631 MQTTSubscribe_options opts = MQTTSubscribe_options_initializer;
632 MQTTProperties props = MQTTProperties_initializer;
633 MQTTResponse resp =
634 MQTTClient_subscribe5 (mqtt->client, topic, qos, &opts, &props);
635 if (resp.reasonCode != MQTTREASONCODE_GRANTED_QOS_1)
636 {
637 MQTTResponse_free (resp);
638 return -2;
639 }
640 MQTTResponse_free (resp);
641 return 0;
642}
643
659int
660mqtt_subscribe (const char *topic)
661{
662 if ((mqtt_get_global_client ()) == NULL)
663 mqtt_reinit ();
664 return mqtt_subscribe_r (mqtt_get_global_client (), QOS, topic);
665}
666
678static int
679mqtt_unsubscribe_r (mqtt_t *mqtt, const char *topic)
680{
681 if (mqtt == NULL || mqtt->client == NULL)
682 {
683 return -1;
684 }
685
686 if (MQTTClient_unsubscribe (mqtt->client, topic) != MQTTCLIENT_SUCCESS)
687 {
688 return -2;
689 }
690
691 return 0;
692}
693
704int
705mqtt_unsubscribe (const char *topic)
706{
708}
709
738static int
739mqtt_retrieve_message_r (mqtt_t *mqtt, char **topic, int *topic_len,
740 char **payload, int *payload_len,
741 const unsigned int timeout)
742{
743 int rc = -1;
744 char *tmp = NULL;
745 MQTTClient_message *message = NULL;
746 if (mqtt == NULL || mqtt->client == NULL)
747 {
748 g_warning ("mqtt is not initialized.");
749 goto exit;
750 }
751 // copy from tmp into topic to make free work as usual and don't force the
752 // user to double check topic_len and topic
753 rc = MQTTClient_receive (mqtt->client, &tmp, topic_len, &message, timeout);
754 if (rc == MQTTCLIENT_SUCCESS || rc == MQTTCLIENT_TOPICNAME_TRUNCATED)
755 {
756 if (message)
757 {
758 g_debug ("%s: got message %s (%d) on topic %s (%d) \n", __func__,
759 (char *) message->payload, message->payloadlen, tmp,
760 *topic_len);
761
762 *topic = calloc (1, *topic_len);
763 if (*topic == NULL)
764 {
765 goto exit;
766 }
767 rc = 0;
768 if ((memcpy (*topic, tmp, *topic_len)) == NULL)
769 {
770 g_warning ("unable to copy topic");
771 rc = -1;
772 goto exit;
773 }
774
775 *payload_len = message->payloadlen;
776 *payload = calloc (1, message->payloadlen);
777 if ((memcpy (*payload, (char *) message->payload,
778 message->payloadlen))
779 == NULL)
780 {
781 g_warning ("unable to copy payload");
782 rc = -1;
783 goto exit;
784 }
785 }
786 else
787 {
788 rc = 1;
789 *payload = NULL;
790 *payload_len = 0;
791 *topic = NULL;
792 *topic_len = 0;
793 }
794 }
795 else
796 {
797 rc = -1;
798 }
799
800exit:
801 if (message != NULL)
802 MQTTClient_freeMessage (&message);
803 if (tmp != NULL)
804 MQTTClient_free (tmp);
805
806 return rc;
807}
808
836int
837mqtt_retrieve_message (char **topic, int *topic_len, char **payload,
838 int *payload_len, const unsigned int timeout)
839{
840 return mqtt_retrieve_message_r (mqtt_get_global_client (), topic, topic_len,
841 payload, payload_len, timeout);
842}
#define G_LOG_DOMAIN
GLib log domain.
Definition array.c:17
int mqtt_publish_single_message_auth(const char *server_uri_in, const char *username_in, const char *passwd_in, const char *topic, const char *msg)
Send a single message with credentials.
Definition mqtt.c:550
#define QOS
Definition mqtt.c:37
static int mqtt_connect(mqtt_t *mqtt, const char *server_uri, const char *username, const char *password)
Make new client and connect to mqtt broker.
Definition mqtt.c:309
static const char * mqtt_get_global_server_uri()
Get global server URI.
Definition mqtt.c:91
static int mqtt_unsubscribe_r(mqtt_t *mqtt, const char *topic)
unsubscribe a single topic.
Definition mqtt.c:679
static void mqtt_set_global_password(const char *password)
Set the global mqtt password.
Definition mqtt.c:122
static void mqtt_set_global_client(mqtt_t *mqtt)
Set global client.
Definition mqtt.c:151
static const char * global_password
Definition mqtt.c:48
static int mqtt_set_client(mqtt_t *mqtt, MQTTClient client)
Set MQTTClient of mqtt_t.
Definition mqtt.c:288
static int mqtt_disconnect(mqtt_t *mqtt)
Disconnect from the Broker.
Definition mqtt.c:164
#define TIMEOUT
Definition mqtt.c:38
static void mqtt_set_initialized_status(gboolean status)
Set the global init status.
Definition mqtt.c:58
int mqtt_init_auth(const char *server_uri, const char *username, const char *password)
Init MQTT communication.
Definition mqtt.c:375
int mqtt_publish_single_message(const char *server_uri_in, const char *topic, const char *msg)
Send a single message.
Definition mqtt.c:527
static const char * mqtt_get_global_password()
Get global password.
Definition mqtt.c:131
gboolean mqtt_is_initialized()
Get the global init status.
Definition mqtt.c:69
int mqtt_retrieve_message(char **topic, int *topic_len, char **payload, int *payload_len, const unsigned int timeout)
wait for a given timeout in ms to retrieve any message of subscribed topics
Definition mqtt.c:837
int mqtt_unsubscribe(const char *topic)
unsubscribe a single topic.
Definition mqtt.c:705
static const char * global_server_uri
Definition mqtt.c:46
int mqtt_publish(const char *topic, const char *msg)
Publish a message on topic using the global client.
Definition mqtt.c:498
void mqtt_reset()
Destroy MQTTClient handle and free mqtt_t.
Definition mqtt.c:212
static void mqtt_reinit()
Reinitializes communication after mqtt_reset was used.
Definition mqtt.c:421
static void mqtt_client_destroy(mqtt_t *mqtt)
Destroy the MQTTClient client of the mqtt_t.
Definition mqtt.c:186
static void mqtt_set_global_username(const char *username)
Set the global mqtt username.
Definition mqtt.c:102
static mqtt_t * global_mqtt_client
Definition mqtt.c:49
int mqtt_init(const char *server_uri)
Init MQTT communication.
Definition mqtt.c:361
static mqtt_t * mqtt_get_global_client()
Definition mqtt.c:142
static int mqtt_retrieve_message_r(mqtt_t *mqtt, char **topic, int *topic_len, char **payload, int *payload_len, const unsigned int timeout)
wait for a given timeout in ms to retrieve any message of subscribed topics
Definition mqtt.c:739
static MQTTClient mqtt_create(mqtt_t *mqtt, const char *address)
Create a new mqtt client.
Definition mqtt.c:238
static char * mqtt_set_client_id(mqtt_t *mqtt)
Set a random client ID.
Definition mqtt.c:269
static int mqtt_subscribe_r(mqtt_t *mqtt, int qos, const char *topic)
subscribes to a single topic.
Definition mqtt.c:625
static void mqtt_set_global_server_uri(const char *server_uri_in)
Set the global mqtt server URI.
Definition mqtt.c:80
int mqtt_subscribe(const char *topic)
subscribes to a single topic.
Definition mqtt.c:660
static gboolean mqtt_initialized
Definition mqtt.c:50
static int mqtt_client_publish(mqtt_t *mqtt, const char *topic, const char *msg)
Use the provided client to publish message on a topic.
Definition mqtt.c:449
static const char * mqtt_get_global_username()
Get global username.
Definition mqtt.c:111
static const char * global_username
Definition mqtt.c:47
static void mqtt_client_data_destroy(mqtt_t **mqtt)
Destroy the mqtt_t data.
Definition mqtt.c:201
Protos for MQTT handling.
void MQTTClient_destroy(MQTTClient *client)
Definition mqtt_tests.c:15
Definition mqtt.c:41
char * client_id
Definition mqtt.c:43
void * client
Definition mqtt.c:42
char * gvm_uuid_make(void)
Make a new universal identifier.
Definition uuidutils.c:30
UUID creation.