Greenbone Vulnerability Management Libraries 22.8.0
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
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
70{
71 return mqtt_initialized;
72}
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 *
92{
93 return global_server_uri;
94}
95
101static void
102mqtt_set_global_username (const char *username)
103{
104 global_username = username;
105}
106
110static const char *
112{
113 return global_username;
114}
115
121static void
122mqtt_set_global_password (const char *password)
123{
124 global_password = password;
125}
126
130static const char *
132{
133 return global_password;
134}
135
141static mqtt_t *
143{
144 return global_mqtt_client;
145}
146
150static void
152{
153 global_mqtt_client = mqtt;
154}
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 == NULL)
189 return;
190
191 MQTTClient client;
192 client = (MQTTClient) mqtt->client;
193
194 if (client != NULL)
195 {
196 MQTTClient_destroy (&client);
197 client = NULL;
198 }
199
200 return;
201}
202
208static void
210{
211 g_free ((*mqtt)->client_id);
212 g_free (*mqtt);
213 *mqtt = NULL;
214}
215
219void
221{
222 g_debug ("%s: start", __func__);
224
225 if (mqtt == NULL)
226 return;
227
228 mqtt_client_destroy (mqtt);
230
232
233 g_debug ("%s: end", __func__);
234 return;
235}
236
245static MQTTClient
246mqtt_create (mqtt_t *mqtt, const char *address)
247{
248 MQTTClient client;
249 MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer;
250 create_opts.MQTTVersion = MQTTVERSION_5;
251
252 if (mqtt == NULL || mqtt->client_id == NULL)
253 return NULL;
254
255 int rc = MQTTClient_createWithOptions (&client, address, mqtt->client_id,
256 MQTTCLIENT_PERSISTENCE_NONE, NULL,
257 &create_opts);
258
259 if (rc != MQTTCLIENT_SUCCESS)
260 {
261 g_warning ("%s: Error creating MQTTClient: %s", __func__,
262 MQTTClient_strerror (rc));
263 MQTTClient_destroy (&client);
264 return NULL;
265 }
266 return client;
267}
268
276static char *
278{
279 if (mqtt == NULL)
280 return NULL;
281
282 char *uuid;
283
284 uuid = gvm_uuid_make ();
285 mqtt->client_id = uuid;
286
287 return uuid;
288}
289
295static int
296mqtt_set_client (mqtt_t *mqtt, MQTTClient client)
297{
298 if (mqtt == NULL)
299 {
300 return -1;
301 }
302 mqtt->client = client;
303 return 0;
304}
305
316static int
317mqtt_connect (mqtt_t *mqtt, const char *server_uri, const char *username,
318 const char *password)
319{
320 int rc;
321 MQTTClient client;
322 MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer5;
323 MQTTProperties connect_properties = MQTTProperties_initializer;
324 MQTTResponse resp;
325
326 if (mqtt == NULL)
327 return -1;
328
329 client = mqtt_create (mqtt, server_uri);
330 if (!client)
331 return -2;
332
333 conn_opts.keepAliveInterval = 0;
334 conn_opts.cleanstart = 1;
335 conn_opts.MQTTVersion = MQTTVERSION_5;
336
337 if (username != NULL && password != NULL)
338 {
339 conn_opts.username = username;
340 conn_opts.password = password;
341 }
342
343 resp = MQTTClient_connect5 (client, &conn_opts, &connect_properties, NULL);
344 rc = resp.reasonCode;
345 MQTTProperties_free (&connect_properties);
346 if (rc != MQTTCLIENT_SUCCESS)
347 {
348 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
349 "%s: mqtt connection error to %s: %s", __func__, server_uri,
350 MQTTClient_strerror (rc));
351 MQTTResponse_free (resp);
352 return -3;
353 }
354
355 mqtt_set_client (mqtt, client);
356
357 return 0;
358}
359
367int
368mqtt_init (const char *server_uri)
369{
370 return mqtt_init_auth (server_uri, NULL, NULL);
371}
381int
382mqtt_init_auth (const char *server_uri, const char *username,
383 const char *password)
384{
385 mqtt_t *mqtt = NULL;
386 const char *g_server_uri;
387 const char *g_username;
388 const char *g_password;
389
390 g_debug ("%s: start", __func__);
391
392 mqtt = g_malloc0 (sizeof (mqtt_t));
393 // Set random uuid as client id
394 if (mqtt_set_client_id (mqtt) == NULL)
395 {
396 g_warning ("%s: Could not set client id.", __func__);
397 g_free (mqtt);
398 mqtt = NULL;
399 return -1;
400 }
401 g_debug ("%s: client id set: %s", __func__, mqtt->client_id);
402 g_server_uri = mqtt_get_global_server_uri ();
403 if (g_server_uri == NULL)
404 mqtt_set_global_server_uri (server_uri);
405
406 g_username = mqtt_get_global_username ();
407 if (g_username == NULL)
408 mqtt_set_global_username (username);
409
410 g_password = mqtt_get_global_password ();
411 if (g_password == NULL)
412 mqtt_set_global_password (password);
413
414 if (mqtt_connect (mqtt, server_uri, username, password))
415 {
416 g_warning ("%s: Unable to connect to MQTT broker.", __func__);
417 g_free (mqtt);
418 mqtt = NULL;
419 return -1;
420 }
421
424
425 g_debug ("%s: end", __func__);
426 return 0;
427}
428
433static void
435{
436 const char *server_uri;
437 const char *username;
438 const char *password;
439
440 server_uri = mqtt_get_global_server_uri ();
441 if (server_uri == NULL)
442 {
443 g_warning ("%s: mqtt_init() has to be called once at program start "
444 "else the server URI is not set. ",
445 __func__);
446 }
447 username = mqtt_get_global_username ();
448 password = mqtt_get_global_password ();
449 mqtt_init_auth (server_uri, username, password);
450}
451
461static int
462mqtt_client_publish (mqtt_t *mqtt, const char *topic, const char *msg)
463{
464 MQTTClient client;
465 MQTTClient_message pubmsg = MQTTClient_message_initializer;
466 MQTTClient_deliveryToken token;
467 MQTTResponse resp;
468 int rc;
469
470 client = mqtt->client;
471 if (client == NULL)
472 {
473 return -1;
474 }
475
476 pubmsg.payload = (char *) msg;
477 pubmsg.payloadlen = (int) strlen (msg);
478 pubmsg.qos = QOS;
479 pubmsg.retained = 0;
480
481 resp = MQTTClient_publishMessage5 (client, topic, &pubmsg, &token);
482 rc = resp.reasonCode;
483 if (rc != MQTTCLIENT_SUCCESS)
484 {
485 g_warning ("Failed to connect: %s", MQTTClient_strerror (rc));
486 MQTTResponse_free (resp);
487 return -2;
488 }
489
490 if ((rc = MQTTClient_waitForCompletion (client, token, TIMEOUT))
491 != MQTTCLIENT_SUCCESS)
492 {
493 g_debug ("Message '%s' with delivery token %d could not be "
494 "published on topic %s",
495 msg, token, topic);
496 }
497
498 return rc;
499}
500
509int
510mqtt_publish (const char *topic, const char *msg)
511{
512 mqtt_t *mqtt = NULL;
513 int rc = 0;
514
515 if ((mqtt_get_global_client ()) == NULL)
516 mqtt_reinit ();
517 mqtt = mqtt_get_global_client ();
518
519 rc = mqtt_client_publish (mqtt, topic, msg);
520
521 return rc;
522}
523
538int
539mqtt_publish_single_message (const char *server_uri_in, const char *topic,
540 const char *msg)
541{
542 return mqtt_publish_single_message_auth (server_uri_in, NULL, NULL, topic,
543 msg);
544}
561int
562mqtt_publish_single_message_auth (const char *server_uri_in,
563 const char *username_in,
564 const char *passwd_in, const char *topic,
565 const char *msg)
566{
567 const char *server_uri;
568 const char *username = NULL;
569 const char *password = NULL;
570 mqtt_t *mqtt = NULL;
571 int ret = 0;
572
573 // If server_uri is NULL try to get global
574 if (server_uri_in == NULL)
575 {
576 server_uri = mqtt_get_global_server_uri ();
577 if (server_uri == NULL)
578 {
579 g_warning (
580 "%s: No server URI provided and no global server URI available.",
581 __func__);
582 return -1;
583 }
584 }
585 else
586 {
587 server_uri = server_uri_in;
588 }
589
590 if (username_in == NULL || passwd_in == NULL)
591 {
592 username = mqtt_get_global_username ();
593 password = mqtt_get_global_password ();
594 }
595 else
596 {
597 username = username_in;
598 password = passwd_in;
599 }
600
601 mqtt = g_malloc0 (sizeof (mqtt_t));
602 // Set random uuid as client id
603 if (mqtt_set_client_id (mqtt) == NULL)
604 {
605 g_warning ("%s: Could not set client id.", __func__);
606 g_free (mqtt);
607 return -2;
608 }
609
610 mqtt_connect (mqtt, server_uri, username, password);
611 mqtt_client_publish (mqtt, topic, msg);
612
613 mqtt_disconnect (mqtt);
614 mqtt_client_destroy (mqtt);
616
617 return ret;
618}
619
636static int
637mqtt_subscribe_r (mqtt_t *mqtt, int qos, const char *topic)
638{
639 if (mqtt == NULL || mqtt->client == NULL)
640 {
641 return -1;
642 }
643 MQTTSubscribe_options opts = MQTTSubscribe_options_initializer;
644 MQTTProperties props = MQTTProperties_initializer;
645 MQTTResponse resp =
646 MQTTClient_subscribe5 (mqtt->client, topic, qos, &opts, &props);
647 if (resp.reasonCode != MQTTREASONCODE_GRANTED_QOS_1)
648 {
649 return -2;
650 }
651 return 0;
652}
653
669int
670mqtt_subscribe (const char *topic)
671{
672 if ((mqtt_get_global_client ()) == NULL)
673 mqtt_reinit ();
674 return mqtt_subscribe_r (mqtt_get_global_client (), QOS, topic);
675}
676
688static int
689mqtt_unsubscribe_r (mqtt_t *mqtt, const char *topic)
690{
691 if (mqtt == NULL || mqtt->client == NULL)
692 {
693 return -1;
694 }
695
696 if (MQTTClient_unsubscribe (mqtt->client, topic) != MQTTCLIENT_SUCCESS)
697 {
698 return -2;
699 }
700
701 return 0;
702}
703
714int
715mqtt_unsubscribe (const char *topic)
716{
718}
719
744static int
745mqtt_retrieve_message_r (mqtt_t *mqtt, char **topic, int *topic_len,
746 char **payload, int *payload_len,
747 const unsigned int timeout)
748{
749 int rc = -1;
750 char *tmp = NULL;
751 MQTTClient_message *message = NULL;
752 if (mqtt == NULL || mqtt->client == NULL)
753 {
754 g_warning ("mqtt is not initialized.");
755 goto exit;
756 }
757 // copy from tmp into topic to make free work as usual and don't force the
758 // user to double check topic_len and topic
759 rc = MQTTClient_receive (mqtt->client, &tmp, topic_len, &message, timeout);
760 if (rc == MQTTCLIENT_SUCCESS || rc == MQTTCLIENT_TOPICNAME_TRUNCATED)
761 {
762 if (message)
763 {
764 g_debug ("%s: got message %s (%d) on topic %s (%d) \n", __func__,
765 (char *) message->payload, message->payloadlen, tmp,
766 *topic_len);
767
768 if ((*topic = calloc (1, *topic_len)) == NULL)
769 {
770 goto exit;
771 }
772 rc = 0;
773 if ((memcpy (*topic, tmp, *topic_len)) == NULL)
774 {
775 g_warning ("unable to copy topic");
776 rc = -1;
777 goto exit;
778 }
779
780 *payload_len = message->payloadlen;
781 *payload = calloc (1, message->payloadlen);
782 if ((memcpy (*payload, (char *) message->payload,
783 message->payloadlen))
784 == NULL)
785 {
786 g_warning ("unable to copy payload");
787 rc = -1;
788 goto exit;
789 }
790 }
791 else
792 {
793 rc = 1;
794 *payload = NULL;
795 *payload_len = 0;
796 *topic = NULL;
797 *topic_len = 0;
798 }
799 }
800 else
801 {
802 rc = -1;
803 }
804
805exit:
806 if (message != NULL)
807 MQTTClient_freeMessage (&message);
808 if (tmp != NULL)
809 MQTTClient_free (tmp);
810
811 return rc;
812}
813
837int
838mqtt_retrieve_message (char **topic, int *topic_len, char **payload,
839 int *payload_len, const unsigned int timeout)
840{
841 return mqtt_retrieve_message_r (mqtt_get_global_client (), topic, topic_len,
842 payload, payload_len, timeout);
843}
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:562
#define G_LOG_DOMAIN
Definition: mqtt.c:35
#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:317
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:689
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:296
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:382
int mqtt_publish_single_message(const char *server_uri_in, const char *topic, const char *msg)
Send a single message.
Definition: mqtt.c:539
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:838
int mqtt_unsubscribe(const char *topic)
unsubscribe a single topic.
Definition: mqtt.c:715
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:510
void mqtt_reset()
Destroy MQTTClient handle and free mqtt_t.
Definition: mqtt.c:220
static void mqtt_reinit()
Reinitializes communication after mqtt_reset was used.
Definition: mqtt.c:434
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:368
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:745
static MQTTClient mqtt_create(mqtt_t *mqtt, const char *address)
Create a new mqtt client.
Definition: mqtt.c:246
static char * mqtt_set_client_id(mqtt_t *mqtt)
Set a random client ID.
Definition: mqtt.c:277
static int mqtt_subscribe_r(mqtt_t *mqtt, int qos, const char *topic)
subscribes to a single topic.
Definition: mqtt.c:637
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:670
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:462
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:209
Protos for MQTT handling.
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.