How can I add the functions for username and password to authen mqtt broker.
The original file has not section for authentication. How can I adding function for username and password in authentication mqtt server?
This file has mqtt.h that is sitting parameters (such as hotsname, port, etc.). and I have added parameter for username and password in mqtt.h following this
struct mqtt_handle_s {
// Public members
char *host;
int port;
char *username;
char *password;
char *client_id;
mqtt_on_connect_t on_connect;
mqtt_on_message_t on_message;
// Private members
struct mosquitto *client;
char *topic_list;
size_t topic_size;
};
and then how can I adding the function for running that parameter to using in mqtt server authentication?
the main code is following..
#mqtt.c full code.
#if defined(_WIN32)
#include <windows.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "app_log.h"
#include "mqtt.h"
// Check if libmosquitto version is at least 1.5.7
#if LIBMOSQUITTO_VERSION_NUMBER < 1005007
#warning Untested libmosquitto version!
#endif
#define QOS 1
#define KEEPALIVE_INTERVAL_SEC 30
#define LOOP_TIMEOUT_MS 1
#define LOG_MASK MOSQ_LOG_NONE
static void mqtt_on_connect(struct mosquitto *mosq, void *obj, int rc);
static void mqtt_on_disconnect(struct mosquitto *mosq, void *obj, int rc);
static void mqtt_on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message);
static void mqtt_on_log(struct mosquitto *mosq, void *obj, int level, const char *str);
static const char * mqtt_err2str(int rc);
mqtt_status_t mqtt_init(mqtt_handle_t *handle)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc = MOSQ_ERR_ERRNO; // return code if mosquitto_new() fails
struct mosquitto *mosq;
mosquitto_lib_init();
mosq = mosquitto_new(handle->client_id, true, handle);
if (mosq != NULL) {
mosquitto_connect_callback_set(mosq, mqtt_on_connect);
mosquitto_disconnect_callback_set(mosq, mqtt_on_disconnect);
mosquitto_message_callback_set(mosq, mqtt_on_message);
mosquitto_log_callback_set(mosq, mqtt_on_log);
rc = mosquitto_connect(mosq, handle->host, handle->port, KEEPALIVE_INTERVAL_SEC);
}
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT init failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_CONNECT;
handle->client = NULL;
if (mosq != NULL) {
mosquitto_destroy(mosq);
}
} else {
handle->client = mosq;
}
handle->topic_list = NULL;
handle->topic_size = 0;
return ret;
}
mqtt_status_t mqtt_publish(mqtt_handle_t *handle, const char *topic, const char *payload)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
int mid;
if (handle->client != NULL) {
rc = mosquitto_publish(handle->client, &mid, topic, strlen(payload), payload, QOS, false);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT publish attempt failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_PUBLISH;
}
} else {
ret = MQTT_ERROR_PUBLISH;
}
return ret;
}
mqtt_status_t mqtt_step(mqtt_handle_t *handle)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
if (handle->client != NULL) {
rc = mosquitto_loop(handle->client, LOOP_TIMEOUT_MS, 1);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT loop failed: '%s'\n", mqtt_err2str(rc));
ret = MQTT_ERROR_STEP;
}
} else {
ret = MQTT_ERROR_STEP;
}
return ret;
}
mqtt_status_t mqtt_subscribe(mqtt_handle_t *handle, const char *topic)
{
mqtt_status_t ret = MQTT_SUCCESS;
int rc;
size_t topic_size;
if (handle->client != NULL) {
// Try to subscribe to topic.
rc = mosquitto_subscribe(handle->client, NULL, topic, QOS);
if ((rc != MOSQ_ERR_SUCCESS) && (rc != MOSQ_ERR_NO_CONN)) {
app_log("MQTT subscribe attempt failed to topic '%s': '%s'\n", topic, mqtt_err2str(rc));
ret = MQTT_ERROR_SUBSCRIBE;
}
// Append topic to topic list.
topic_size = strlen(topic) + 1;
handle->topic_list = realloc(handle->topic_list, handle->topic_size + topic_size);
if (handle->topic_list == NULL) {
app_log("MQTT failed to append topic to topic list.\n");
ret = MQTT_ERROR_SUBSCRIBE;
} else {
strcpy(&handle->topic_list[handle->topic_size], topic);
handle->topic_size += topic_size;
}
} else {
ret = MQTT_ERROR_SUBSCRIBE;
}
return ret;
}
mqtt_status_t mqtt_deinit(mqtt_handle_t *handle)
{
int rc;
if (handle->client != NULL) {
rc = mosquitto_disconnect(handle->client);
if (rc != MOSQ_ERR_SUCCESS) {
app_log("MQTT failed to disconnect: '%s', continue deinit.\n", mqtt_err2str(rc));
}
mosquitto_destroy(handle->client);
mosquitto_lib_cleanup();
if (handle->topic_list != NULL) {
free(handle->topic_list);
}
}
return MQTT_SUCCESS;
}
static void mqtt_on_connect(struct mosquitto *mosq, void *obj, int rc)
{
mqtt_handle_t *handle = (mqtt_handle_t *)obj;
size_t topic_start = 0;
char *topic;
int ret = MOSQ_ERR_SUCCESS;
app_log("MQTT connect status '%s'\n", mosquitto_connack_string(rc));
if (rc == 0) {
if (handle->on_connect != NULL) {
handle->on_connect(handle);
}
while (topic_start < handle->topic_size) {
topic = &handle->topic_list[topic_start];
ret = mosquitto_subscribe(mosq, NULL, topic, QOS);
topic_start += strlen(topic) + 1;
if (ret != MOSQ_ERR_SUCCESS) {
app_log("MQTT subscribe attempt failed to topic '%s': '%s'\n", topic, mqtt_err2str(ret));
}
}
}
}
static void mqtt_on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
int ret;
app_log("MQTT disconnected with reason '%d'\n", rc);
if (rc != 0) {
ret = mosquitto_reconnect(mosq);
app_log("MQTT reconnection attempt with status '%s'\n", mqtt_err2str(ret));
}
}
static void mqtt_on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
mqtt_handle_t *handle = (mqtt_handle_t *)obj;
char *payload;
if (handle->on_message != NULL) {
payload = malloc(message->payloadlen + 1);
if (NULL == payload) {
app_log("MQTT failed to allocate payload buffer.\n");
} else {
memcpy(payload, message->payload, message->payloadlen);
// Make sure that payload is NULL terminated.
payload[message->payloadlen] = 0;
handle->on_message(handle, message->topic, payload);
free(payload);
}
}
}
static void mqtt_on_log(struct mosquitto *mosq, void *obj, int level, const char *str)
{
if (level & LOG_MASK) {
app_log("MQTT log (%d): %s\n", level, str);
}
}
#if defined(_WIN32)
static const char * mqtt_err2str(int rc)
{
char *ret = NULL;
static char err_str[256];
if (MOSQ_ERR_ERRNO == rc) {
// Make sure to have a default output if FormatMessage fails
// or if error code is not available in errno.
strncpy(err_str, "Unknown system error", sizeof(err_str));
if (errno != 0) {
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // dwFlags
NULL, // lpSource
errno, // dwMessageId
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
err_str, // lpBuffer
sizeof(err_str), // nSize
NULL); // Arguments
}
// Make sure that err_str is NULL terminated.
err_str[sizeof(err_str) - 1] = 0;
ret = err_str;
} else {
ret = (char *)mosquitto_strerror(rc);
}
return ret;
}
#else
static const char * mqtt_err2str(int rc)
{
return (MOSQ_ERR_ERRNO == rc) ? strerror(errno) : mosquitto_strerror(rc);
}
#endif // _WIN32
I am trying to use MQTT library to connect to Amazon IOT Service
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(aws_mqtt, LOG_LEVEL_DBG);
#include <zephyr.h>
#include <net/socket.h>
#include <net/mqtt.h>
#include <net/net_config.h>
#include <net/net_event.h>
#include <net/sntp.h>
#include <sys/printk.h>
#include <string.h>
#include <errno.h>
#include "dhcp.h"
#include <time.h>
#include <inttypes.h>
#include "globalsign.inc"
/* The mqtt client struct */
static struct mqtt_client client_ctx;
s64_t time_base;
/* MQTT Broker details. */
static struct sockaddr_storage broker;
#if defined(CONFIG_SOCKS)
static struct sockaddr socks5_proxy;
#endif
static struct pollfd fds[1];
static int nfds;
#define APP_MQTT_BUFFER_SIZE 128
static sec_tag_t m_sec_tags[] = {
#if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(CONFIG_NET_SOCKETS_OFFLOAD)
APP_CA_CERT_TAG,
#endif
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
APP_PSK_TAG,
#endif
};
#define APP_CA_CERT_TAG 1
#define APP_PSK_TAG 2
/* Buffers for MQTT client. */
static u8_t rx_buffer[APP_MQTT_BUFFER_SIZE];
static u8_t tx_buffer[APP_MQTT_BUFFER_SIZE];
static bool connected;
#define MQTT_CLIENTID "zephyr_publisher"
struct zsock_addrinfo *haddr;
time_t my_k_time(time_t *ptr)
{
s64_t stamp;
time_t now;
stamp = k_uptime_get();
now = (time_t)((stamp + time_base) / 1000);
if (ptr) {
*ptr = now;
}
return now;
}
static void broker_init(void)
{
struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker;
broker4->sin_family = AF_INET;
broker4->sin_port = htons(8883);
net_ipaddr_copy(&broker4->sin_addr,
&net_sin(haddr->ai_addr)->sin_addr);
#if defined(CONFIG_SOCKS)
struct sockaddr_in *proxy4 = (struct sockaddr_in *)&socks5_proxy;
proxy4->sin_family = AF_INET;
proxy4->sin_port = htons(1081);
inet_pton(AF_INET, "agwgaprlb6xdl-ats.iot.us-west-2.amazonaws.com", &proxy4->sin_addr);
#endif
}
void mqtt_evt_handler(struct mqtt_client *const client,
const struct mqtt_evt *evt)
{
int err;
switch (evt->type) {
case MQTT_EVT_CONNACK:
if (evt->result != 0) {
LOG_ERR("MQTT connect failed %d", evt->result);
break;
}
connected = true;
LOG_INF("MQTT client connected!");
break;
case MQTT_EVT_DISCONNECT:
LOG_INF("MQTT client disconnected %d", evt->result);
connected = false;
//clear_fds();
break;
case MQTT_EVT_PUBACK:
if (evt->result != 0) {
LOG_ERR("MQTT PUBACK error %d", evt->result);
break;
}
LOG_INF("PUBACK packet id: %u", evt->param.puback.message_id);
break;
case MQTT_EVT_PUBREC:
if (evt->result != 0) {
LOG_ERR("MQTT PUBREC error %d", evt->result);
break;
}
LOG_INF("PUBREC packet id: %u", evt->param.pubrec.message_id);
const struct mqtt_pubrel_param rel_param = {
.message_id = evt->param.pubrec.message_id
};
err = mqtt_publish_qos2_release(client, &rel_param);
if (err != 0) {
LOG_ERR("Failed to send MQTT PUBREL: %d", err);
}
break;
case MQTT_EVT_PUBCOMP:
if (evt->result != 0) {
LOG_ERR("MQTT PUBCOMP error %d", evt->result);
break;
}
LOG_INF("PUBCOMP packet id: %u",
evt->param.pubcomp.message_id);
break;
default:
break;
}
}
static void client_init(struct mqtt_client *client)
{
static struct mqtt_utf8 password;
static struct mqtt_utf8 username;
mqtt_client_init(client);
broker_init();
password.utf8 = (u8_t *)CONFIG_SAMPLE_CLOUD_AWS_PASSWORD;
password.size = strlen(CONFIG_SAMPLE_CLOUD_AWS_PASSWORD);
client->password = &password;
username.utf8 = (u8_t *)CONFIG_SAMPLE_CLOUD_AWS_USERNAME;
username.size = strlen(CONFIG_SAMPLE_CLOUD_AWS_USERNAME);
client->user_name = &username;
/* MQTT client configuration */
client->broker = &broker;
client->evt_cb = mqtt_evt_handler;
client->client_id.utf8 = (u8_t *)MQTT_CLIENTID;
client->client_id.size = strlen(MQTT_CLIENTID);
client->password = NULL;
client->user_name = NULL;
client->protocol_version = MQTT_VERSION_3_1_1;
/* MQTT buffers configuration */
client->rx_buf = rx_buffer;
client->rx_buf_size = sizeof(rx_buffer);
client->tx_buf = tx_buffer;
client->tx_buf_size = sizeof(tx_buffer);
client->transport.type = MQTT_TRANSPORT_SECURE;
struct mqtt_sec_config *tls_config = &client->transport.tls.config;
tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED;
tls_config->cipher_list = NULL;
tls_config->sec_tag_list = m_sec_tags;
tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
tls_config->hostname = NULL;
client->transport.type = MQTT_TRANSPORT_NON_SECURE;
#if defined(CONFIG_SOCKS)
mqtt_client_set_proxy(client, &socks5_proxy,
socks5_proxy.sa_family == AF_INET ?
sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6));
#endif
}
#define RC_STR(rc) ((rc) == 0 ? "OK" : "ERROR")
#define PRINT_RESULT(func, rc) \
LOG_INF("%s: %d <%s>", (func), rc, RC_STR(rc))
static void prepare_fds(struct mqtt_client *client)
{
if (client->transport.type == MQTT_TRANSPORT_NON_SECURE) {
fds[0].fd = client->transport.tcp.sock;
}
#if defined(CONFIG_MQTT_LIB_TLS)
else if (client->transport.type == MQTT_TRANSPORT_SECURE) {
fds[0].fd = client->transport.tls.sock;
}
#endif
fds[0].events = ZSOCK_POLLIN;
nfds = 1;
}
static void clear_fds(void)
{
nfds = 0;
}
static void wait(int timeout)
{
if (nfds > 0) {
if (poll(fds, nfds, timeout) < 0) {
LOG_ERR("poll error: %d", errno);
}
}
}
static int try_to_connect(struct mqtt_client *client)
{
u8_t retries = 3U;
int rc;
LOG_DBG("attempting to connect...");
client_init(client);
rc = mqtt_connect(client);
if (rc != 0) {
PRINT_RESULT("mqtt_connect", rc);
k_sleep(500);
} else {
prepare_fds(client);
wait(500);
mqtt_input(client);
if (!connected) {
LOG_INF("Aborting connection\n");
mqtt_abort(client);
}
}
if (connected) {
return 0;
}
return -EINVAL;
}
void mqtt_startup(char *hostname, int port)
{
struct mqtt_client *client = &client_ctx;
int retries = 5;
int err, cnt;
static struct zsock_addrinfo hints;
int res = 0;
int rc;
mbedtls_platform_set_time(my_k_time);
err = tls_credential_add(1, TLS_CREDENTIAL_CA_CERTIFICATE,
globalsign_certificate,
sizeof(globalsign_certificate));
if (err < 0) {
LOG_ERR("Failed to register public certificate: %d", err);
}
LOG_DBG("tls credential added\n");
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
cnt = 0;
while ((err = getaddrinfo("agwgaprlb6xdl-ats.iot.us-west-2.amazonaws.com", "8883", &hints,
&haddr)) && cnt < 3) {
LOG_ERR("Unable to get address for broker, retrying");
cnt++;
}
if (err != 0) {
LOG_ERR("Unable to get address for broker, error %d",
res);
return;
}
LOG_INF("DNS resolved for agwgaprlb6xdl-ats.iot.us-west-2.amazonaws.com:8833");
try_to_connect(client);
PRINT_RESULT("try_to_connect", rc);
}
static void show_addrinfo(struct addrinfo *addr)
{
char hr_addr[NET_IPV6_ADDR_LEN];
void *a;
top:
LOG_DBG(" flags : %d", addr->ai_flags);
LOG_DBG(" family : %d", addr->ai_family);
LOG_DBG(" socktype: %d", addr->ai_socktype);
LOG_DBG(" protocol: %d", addr->ai_protocol);
LOG_DBG(" addrlen : %d", (int)addr->ai_addrlen);
/* Assume two words. */
LOG_DBG(" addr[0]: 0x%lx", ((uint32_t *)addr->ai_addr)[0]);
LOG_DBG(" addr[1]: 0x%lx", ((uint32_t *)addr->ai_addr)[1]);
if (addr->ai_next != 0) {
addr = addr->ai_next;
goto top;
}
a = &net_sin(addr->ai_addr)->sin_addr;
LOG_INF(" Got %s",
log_strdup(net_addr_ntop(addr->ai_family, a,
hr_addr, sizeof(hr_addr))));
}
void do_sntp(struct addrinfo *addr)
{
struct sntp_ctx ctx;
int rc;
s64_t stamp;
struct sntp_time sntp_time;
char time_str[sizeof("1970-01-01T00:00:00")];
LOG_INF("Sending NTP request for current time:");
/* Initialize sntp */
rc = sntp_init(&ctx, addr->ai_addr, sizeof(struct sockaddr_in));
if (rc < 0) {
LOG_ERR("Unable to init sntp context: %d", rc);
return;
}
rc = sntp_query(&ctx, K_FOREVER, &sntp_time);
if (rc == 0) {
stamp = k_uptime_get();
time_base = sntp_time.seconds * MSEC_PER_SEC - stamp;
/* Convert time to make sure. */
time_t now = sntp_time.seconds;
struct tm now_tm;
gmtime_r(&now, &now_tm);
strftime(time_str, sizeof(time_str), "%FT%T", &now_tm);
LOG_INF(" Acquired time: %s", log_strdup(time_str));
} else {
LOG_ERR(" Failed to acquire SNTP, code %d\n", rc);
}
sntp_close(&ctx);
}
void main(void)
{
static struct addrinfo hints;
struct addrinfo *haddr;
int res;
int cnt = 0;
app_dhcpv4_startup();
LOG_INF("Should have DHCPv4 lease at this point.");
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
//while ((res = getaddrinfo("console.aws.amazon.com", "80", &hints,
while ((res = getaddrinfo("time.google.com", "123", &hints,
&haddr)) && cnt < 3) {
LOG_ERR("Unable to get address for NTP server, retrying");
cnt++;
}
if (res != 0) {
LOG_ERR("Unable to get address of NTP server, exiting %d", res);
return;
}
LOG_INF("DNS resolved for console.aws.amazon.com:80");
show_addrinfo(haddr);
do_sntp(haddr);
mqtt_startup("agwgaprlb6xdl-ats.iot.us-west-2.amazonaws.com", 8883);
}
Following are the logs:
[00:00:07.193,000] <dbg> net_mqtt_enc.pack_uint8: (0x20401bac): >> val:10 cur:0x20401d64, end:0x20401de1
[00:00:07.205,000] <dbg> net_mqtt_enc.packet_length_encode: (0x20401bac): >> length:0x0000001c cur:0x20401d65, end:0x20401de1
[00:00:07.219,000] <dbg> net_mqtt.client_connect: (0x20401bac): Connect completed
[00:00:07.684,000] <dbg> net_mqtt.mqtt_input: (0x20401bac): state:0x00000002
[00:00:07.693,000] <dbg> net_mqtt_rx.mqtt_read_message_chunk: (0x20401bac): [CID 0x20400254]: Connection closed.
[00:00:07.706,000] <dbg> net_mqtt_sock_tcp.mqtt_client_tcp_disconnect: (0x20401bac): Closing socket 0
[00:00:07.718,000] <err> aws_mqtt: MQTT connect failed -111
[00:00:07.726,000] <inf> aws_mqtt: Aborting connection
[00:00:07.734,000] <inf> aws_mqtt: try_to_connect: 0 <OK>
Below is my code for connecting and sending data from device to cloud using Eclypse Paho MQTT Library. I am able to connect with IOT Hub as rc results 0 in my case but It doesn't send message to my IOT Hub device. Can anyone please guide me where I have made mistake or what I am doing wrong ?
I am using Visual studio 2015 with .Net framework 4.0 and eclipse-paho-mqtt-c-windows-1.0.3 libraries
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTAsync.h"
#if !defined(WIN32)
#include <unistd.h>
#else
#include <windows.h>
#endif
#if defined(_WRS_KERNEL)
#include <OsWrapper.h>
#endif
#define ADDRESS "ssl://xxxxx.azure-devices.net:8883" //tcp://localhost:1883"
#define CLIENTID "EnergyMeter" //"ExampleClientPub"
#define TOPIC "devices/EnergyMeter/messages/events/" //"MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
volatile MQTTAsync_token deliveredtoken;
int finished = 0;
void connlost(void *context, char *cause)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc;
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
printf("Reconnecting\n");
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
finished = 1;
}
}
void onDisconnect(void* context, MQTTAsync_successData* response)
{
printf("Successful disconnection\n");
finished = 1;
}
void onSend(void* context, MQTTAsync_successData* response)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
int rc;
printf("Message with token value %d delivery confirmed\n", response->token);
opts.onSuccess = onDisconnect;
opts.context = client;
if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
printf("Connect failed, rc %d\n", response ? response->code : 0);
finished = 1;
}
void onConnect(void* context, MQTTAsync_successData* response)
{
printf("hello");
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;
printf("Successful connection\n");
opts.onSuccess = onSend;
opts.context = client;
pubmsg.payload = PAYLOAD;
pubmsg.payloadlen = strlen(PAYLOAD);
pubmsg.qos = QOS;
pubmsg.retained = 0;
deliveredtoken = 0;
if ((rc = MQTTAsync_sendMessage(client, TOPIC, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
int main(int argc, char* argv[])
{
MQTTAsync client;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc = 5;
int a;
a = MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
printf("a is %d", a);
printf("Hey");
MQTTAsync_setCallbacks(client, NULL, connlost, NULL, NULL);
printf("check1\n");
conn_opts.keepAliveInterval = 5;
//conn_opts.username = "ssl://Ironman.azure-devices.net/stark";
//conn_opts.password = "SharedAccessSignature sr=Ironman.azure-devices.net%2Fdevices%2Fstark&sig=eoAum3Hl2gWWiFVJT%2FhmUMwYH4NFAT%2B5fG8tRTm%2BbaA%3D&se=1558677763";
conn_opts.cleansession = 1;
printf("check2\n");
conn_opts.onSuccess = onConnect;
conn_opts.username = "CCMSIoTHub.azure-devices.net/EnergyMeter/api-version=2016-11-14";
conn_opts.password = "SharedAccessSignature sr=xxxxxxx.azure-devices.net%2Fdevices%2FEnergyMeter&sig=undNm%xxxxxxxxz87I%3D&se=xxxxxxxxx";
printf("check3\n");
conn_opts.onFailure = onConnectFailure;
conn_opts.context = client;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
else
{
printf("rc is %d ", rc);
}
printf("Waiting for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
PAYLOAD, TOPIC, CLIENTID);
while (!finished)
#if defined(WIN32) || defined(WIN64)
Sleep(100);
#else
usleep(10000L);
#endif
MQTTAsync_destroy(&client);
return rc;
}
Below Code works fine In my case
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#define ADDRESS "ssl://xxxxxxxxxx.azure-devices.net:8883" //tcp://localhost:1883"
#define CLIENTID "xxxxxxxxxx" //"ExampleClientPub"
#define TOPIC "devices/xxxxxxxxxx/messages/events/" //"MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
volatile MQTTClient_deliveryToken deliveredtoken;
void delivered(void *context, MQTTClient_deliveryToken dt)
{
printf("Message with token value %d delivery confirmed\n", dt);
deliveredtoken = dt;
}
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
int i;
char* payloadptr;
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: ");
payloadptr = (char *)message->payload;
for (i = 0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
putchar('\n');
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
void connlost(void *context, char *cause)
{
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
#define TEST_SSL
int main(int argc, char* argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int rc;
rc = MQTTClient_create(&client, ADDRESS, CLIENTID,
1, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = "xxxxxxxxxx.azure-devices.net/xxxxxxxxxx/api-version=2016-11-14";
conn_opts.password = "SharedAccessSignature sr=xxxxxxxxxx.azure-devices.net%2Fdevices%2Fxxxxxxxxxx&sig=undNm%2Fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=15xxxxxx";
#ifdef TEST_SSL
MQTTClient_SSLOptions sslOptions = MQTTClient_SSLOptions_initializer;
sslOptions.enableServerCertAuth = 1;
sslOptions.trustStore = "D:/Parth/Projects/MQTT/MQTT Sample D2C Azure IOT Hub Tested Program/rootCA.crt";
conn_opts.ssl = &sslOptions;
#endif
//conn_opts.ssl->trustStore = "D:\Parth\Projects\MQTT\paho.mqtt.c-master\test\ssl\test - alt - ca.crt";
rc = MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
pubmsg.payload = PAYLOAD;
pubmsg.payloadlen = strlen(PAYLOAD);
pubmsg.qos = QOS;
pubmsg.retained = 0;
deliveredtoken = 0;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
printf("Waiting for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
PAYLOAD, TOPIC, CLIENTID);
while (deliveredtoken != token);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
I need to write an application in C for asynchronous sending and reading messages on the dbus message queue. I've read that for doing that I should use the DBusWatch and DBusTimeout objects that the connection provides, but I cannot find an example of how to use these anywhere...
For the moment i use dbus_connection_read_write_dispatch in order to do that, but I've read that it is not recommended for asynchronous operations, so I'll have to switch to creating my own main loop and using it...
The closest answer to my question was this one:
http://lists.freedesktop.org/archives/dbus/2007-September/008555.html ,
suggesting to look through the dbus-gmain.c file, which I did, but all I found there was a call of the dbus_connection_set_watch_functions and dbus_connection_set_timeout_functions, with other functions as parameters - should I overwrite those functions? Should I use them as they are?
I simply cannot figure out how to use these in order to read and write something to the dbus message queue...
Any idea would be more than welcome...
Here's something I wrote some time ago. I removed application specific code, you should just add your snippets where you handle DBus messages meant for your application and that should be it.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dbus/dbus.h>
struct dbus_ctx {
DBusConnection *conn;
struct event_base *evbase;
struct event dispatch_ev;
void *extra;
};
static void dispatch(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusConnection *c = ctx->conn;
logger(LOG_DEBUG "dispatching\n");
while (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS)
dbus_connection_dispatch(c);
}
static void handle_dispatch_status(DBusConnection *c,
DBusDispatchStatus status, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "new dbus dispatch status: %d\n", status);
if (status == DBUS_DISPATCH_DATA_REMAINS) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 0,
};
event_add(&ctx->dispatch_ev, &tv);
}
}
static void handle_watch(int fd, short events, void *x)
{
struct dbus_ctx *ctx = x;
struct DBusWatch *watch = ctx->extra;
unsigned int flags = 0;
if (events & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (events & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
/*if (events & HUP)
flags |= DBUS_WATCH_HANGUP;
if (events & ERR)
flags |= DBUS_WATCH_ERROR;*/
logger(LOG_DEBUG "got dbus watch event fd=%d watch=%p ev=%d\n",
fd, watch, events);
if (dbus_watch_handle(watch, flags) == FALSE)
logger(LOG_ERROR "dbus_watch_handle() failed\n");
handle_dispatch_status(ctx->conn, DBUS_DISPATCH_DATA_REMAINS, ctx);
}
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
struct dbus_ctx *ctx = data;
ctx->extra = w;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
short cond = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
cond |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
cond |= EV_WRITE;
struct event *event = event_new(ctx->evbase, fd, cond, handle_watch, ctx);
if (!event)
return FALSE;
event_add(event, NULL);
dbus_watch_set_data(w, event, NULL);
logger(LOG_DEBUG "added dbus watch fd=%d watch=%p cond=%d\n", fd, w, cond);
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
struct event *event = dbus_watch_get_data(w);
if (event)
event_free(event);
dbus_watch_set_data(w, NULL, NULL);
logger(LOG_DEBUG "removed dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
logger(LOG_DEBUG "toggling dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
static void handle_timeout(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusTimeout *t = ctx->extra;
logger(LOG_DEBUG "got dbus handle timeout event %p\n", t);
dbus_timeout_handle(t);
}
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
struct dbus_ctx *ctx = data;
if (!dbus_timeout_get_enabled(t))
return TRUE;
logger(LOG_DEBUG "adding timeout %p\n", t);
struct event *event = event_new(ctx->evbase, -1, EV_TIMEOUT|EV_PERSIST,
handle_timeout, t);
if (!event) {
logger(LOG_ERROR "failed to allocate new event for timeout\n");
return FALSE;
}
int ms = dbus_timeout_get_interval(t);
struct timeval tv = {
.tv_sec = ms / 1000,
.tv_usec = (ms % 1000) * 1000,
};
event_add(event, &tv);
dbus_timeout_set_data(t, event, NULL);
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
struct event *event = dbus_timeout_get_data(t);
logger(LOG_DEBUG "removing timeout %p\n", t);
event_free(event);
dbus_timeout_set_data(t, NULL, NULL);
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
logger(LOG_DEBUG "toggling timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
static DBusHandlerResult handle_nameownerchanged(DBusMessage *message,
void *data)
{
struct dbus_ctx *ctx = data;
char *name, *old, *new;
if (dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID) == FALSE) {
logger(LOG_ERROR "spurious NameOwnerChanged signal\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
logger(LOG_DEBUG "dbus NameOwnerChanged %s -> %s\n", old, new);
if (new[0] != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
/* XXX handle disconnecting clients */
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult msg_filter(DBusConnection *connection,
DBusMessage *message, void *data)
{
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
return handle_nameownerchanged(message, data);
logger(LOG_DEBUG "got dbus message %d %s -> %s %s/%s/%s %s\n",
dbus_message_get_type(message),
dbus_message_get_sender(message),
dbus_message_get_destination(message),
dbus_message_get_path(message),
dbus_message_get_interface(message),
dbus_message_get_member(message),
dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR ?
dbus_message_get_error_name(message) : "");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void unregister_func(DBusConnection *connection, void *data)
{
}
static DBusHandlerResult message_func(DBusConnection *connection,
DBusMessage *message, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "got dbus message sent to %s %s %s\n",
dbus_message_get_destination(message),
dbus_message_get_interface(message),
dbus_message_get_path(message));
/* XXX handle DBus message */
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusObjectPathVTable dbus_vtable = {
.unregister_function = unregister_func,
.message_function = message_func,
};
struct dbus_ctx *dbus_init(struct event_base *eb)
{
DBusConnection *conn = NULL;
struct dbus_ctx *ctx = calloc(1, sizeof(struct dbus_ctx));
if (!ctx) {
logger_perror("can't allocate dbus_ctx\n");
goto out;
}
conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
if (conn == NULL) {
logger(LOG_ERROR "failed to get bus\n");
goto out;
}
dbus_connection_set_exit_on_disconnect(conn, FALSE);
ctx->conn = conn;
ctx->evbase = eb;
event_assign(&ctx->dispatch_ev, eb, -1, EV_TIMEOUT, dispatch, ctx);
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_watch_functions() failed\n");
goto out;
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_timeout_functions() failed\n");
goto out;
}
if (dbus_connection_add_filter(conn, msg_filter, ctx, NULL) == FALSE) {
logger(LOG_ERROR "dbus_connection_add_filter() failed\n");
goto out;
}
dbus_connection_set_dispatch_status_function(conn, handle_dispatch_status,
ctx, NULL);
char match[256];
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='NameOwnerChanged'",
DBUS_INTERFACE_DBUS);
DBusError error;
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
"NameOwnerChanged", error.message);
dbus_error_free(&error);
goto out;
}
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='%s'",
GNP_IPC_INTERFACE, GNP_IPC_SIGNAL_DELIVER_SA);
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
GNP_IPC_SIGNAL_DELIVER_SA, error.message);
dbus_error_free(&error);
goto out;
}
if (dbus_connection_register_object_path(conn, GNP_IPC_PATH, &dbus_vtable,
ctx) != TRUE) {
logger(LOG_ERROR "failed to register object path\n");
goto out;
}
return ctx;
out:
if (conn) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
}
if (ctx)
free(ctx);
return NULL;
}
void dbus_close(struct dbus_ctx *ctx)
{
if (ctx && ctx->conn) {
dbus_connection_flush(ctx->conn);
dbus_connection_close(ctx->conn);
dbus_connection_unref(ctx->conn);
event_del(&ctx->dispatch_ev);
}
if (ctx)
free(ctx);
}
Based on Idx's code and examples from other sources (mainly example by Matthew Johnson and Will Ware), here is a synchronous event handling sample with a mainloop on select(). Just run in two terminals to see how events are passing around.
#define _GNU_SOURCE /* for pipe2 in unistd.h */
#include <dbus/dbus.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* for pipe2 */
#include <errno.h>
#include <fcntl.h> /* for O_NONBLOCK */
#include <sys/time.h> /* for gettimeofday */
#include <limits.h> /* for INT_MAX */
/* ------------------------------------------------------------ */
/* chgevt:
* when watch/timeout changes, pass a chgevt via a pipe to
* the selector loop so the loop will return from select() and
* react to the dbus change immediately. only need this when a new
* watch/timeout is added or enabled. when a watch/timeout is removed
* or disabled, immediate response is not needed.
*
* when running in single thread because those changes happen only
* in stage 2 of the selector loop, this chgevt path is not necessary.
* if running in multiple threads, e.g. calling dbus sending from
* another thread, then the path would be essential.
*/
/* events */
#define CHGEVT_ADD_WATCH (1)
#define CHGEVT_ADD_TIMEOUT (2)
static int watched_chgevt_fds[2] = {0,0}; /* [0] read, [1] write */
static void watched_chgevt_setup() {
int rc = pipe2(watched_chgevt_fds, O_NONBLOCK);
if ( rc != 0 ) watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
static void watched_chgevt_send(int evt) {
if ( watched_chgevt_fds[1] ) write(watched_chgevt_fds[1], &evt, 1);
}
static int watched_chgevt_get() {
int rc = 0;
if ( watched_chgevt_fds[0] ) {
if ( (rc = read(watched_chgevt_fds[0], &rc, 1)) < 0 ) {
if ( errno != EAGAIN ) {
perror("watched_chgevt_fds pipe failed");
watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
rc = 0;
}
}
return rc;
}
/* watch */
static DBusWatch * watched_watch = NULL;
static int watched_rd_fd = 0;
static int watched_wr_fd = 0;
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
int old_rd_fd = watched_rd_fd;
int old_wr_fd = watched_wr_fd;
if (flags & DBUS_WATCH_READABLE)
watched_rd_fd = fd;
if (flags & DBUS_WATCH_WRITABLE)
watched_wr_fd = fd;
watched_watch = w;
printf(" WATCH: add dbus watch fd=%d watch=%p rd_fd=%d/%d wr_fd=%d/%d\n",
fd, w, watched_rd_fd, old_rd_fd, watched_wr_fd, old_wr_fd);
watched_chgevt_send( CHGEVT_ADD_WATCH );
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
watched_watch = NULL;
watched_rd_fd = 0;
watched_wr_fd = 0;
printf(" WATCH: remove dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
printf(" WATCH: toggle dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
/* timeout */
static DBusTimeout * watched_timeout = NULL;
static struct timeval watched_timeout_start_tv = { 0, 0 };
/* at which timeout is enabled */
static unsigned int watched_timeout_setv = 0; /* set value */
static unsigned int watched_timeout_lastv = 0; /* last trigger */
#define TIMEOUT_MAX_MS ( 1000 * 1000 ) /* 1000 sec */
#define TIMEOUT_MOD_MS ( 8 * TIMEOUT_MAX_MS ) /* 8000 sec */
/* note: last_trigger is 0 to 7999 sec.
* next_timeout is 0 to 8999 sec.
*/
#define TIME_TV_TO_MS(x) /* convert a timeval to 0-to-7999 ms */ \
( (x.tv_sec%(TIMEOUT_MOD_MS/1000))*1000 + \
x.tv_usec/1000 )
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
if (!dbus_timeout_get_enabled(t))
return TRUE;
int ms = dbus_timeout_get_interval(t);
if ( ms < 0 || ms > TIMEOUT_MAX_MS ) {
ms = TIMEOUT_MAX_MS;
if ( ms < 0 || ms > INT_MAX/2-1 ) {
ms = INT_MAX/2-1;
}
}
if ( ms < 1 ) {
ms = 1;
}
struct timeval tnow = {0,0};
gettimeofday(&tnow, NULL);
unsigned int tnowms = TIME_TV_TO_MS(tnow);
printf(" TIMEOUT: add dbus timeout %p value %u ms\n", t, ms);
watched_timeout_start_tv = tnow;
watched_timeout_setv = ms;
watched_timeout_lastv = tnowms;
watched_timeout = t;
watched_chgevt_send( CHGEVT_ADD_TIMEOUT );
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: remove timeout %p\n", t);
watched_timeout = NULL;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0, };
watched_timeout_start_tv = tv;
watched_timeout_setv = 0;
watched_timeout_lastv = 0;
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: toggle timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
/* the selector function */
/* receive */
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr);
/* send rpc request */
static int dbus_selector_process_post_send(DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr);
/* receive rpc reply, called by process_recv() */
static int dbus_selector_process_post_reply(DBusConnection* conn,
DBusPendingCall** pendingargptr );
/* selector */
#include <sys/select.h>
#include <time.h>
static unsigned int lastregtime = 0;
int dbus_selector(char *param, int altsel )
{
DBusConnection* conn;
DBusError err;
int ret = 1; /* default fail */
watched_chgevt_setup();
char * destarray[4] = { "test.selector.server", "test.selector.client",
"test.unknown.user1", "test.unknown.user2" };
char * deststr = destarray[0];
if ( altsel != 0 ) {
deststr = destarray[1];
lastregtime = time(NULL);
}
printf("Accepting method calls and signals\n");
// initialise the error
dbus_error_init(&err);
// connect to the bus and check for errors
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
fprintf(stderr, "Connection Null\n");
return ret; /* ret=1 fail */
}
// request our name on the bus and check for errors
ret = dbus_bus_request_name(conn, deststr /* "test.selector.server" */,
DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Name Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
fprintf(stderr, "Not Primary Owner (%d)\n", ret);
return ret; /* ret=1 fail */
}
// add a rule for which messages we want to see
dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err);
// see signals from the given interface
dbus_connection_flush(conn); /* Note: this would block */
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Match Error (%s)\n", err.message);
return ret; /* ret=1 fail */
}
printf("Match signal rule sent\n");
/* setup watch and timeout */
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, NULL, NULL)) {
printf(" ERROR dbus_connection_set_watch_functions() failed\n");
return ret; /* ret=1 fail */
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
NULL, NULL)) {
printf(" ERROR dbus_connection_set_timeout_functions() failed\n");
return ret; /* ret=1 fail */
}
/* the selector loop */
ret = 0; /* default success */
struct timeval local_to_startv = {0,0}; /* timeout saved locally */
DBusPendingCall* pending = NULL; /* keep track of the outstanding rpc call */
while(ret == 0) {
/* the selector loop stage 1, setup for select() call.
* in this stage no dbus watch/timeout change should happen
*/
#define DEFAULT_SELECT_LOOP_MS (5500)
int modified_timeout = 0; /* yes or no */
fd_set rfds, wfds, efds;
struct timeval timeoutval = {
DEFAULT_SELECT_LOOP_MS/1000,
(DEFAULT_SELECT_LOOP_MS%1000)*1000 };
int nfds = 1;
int rc = 0;
printf("\n");
FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
FD_SET(watched_rd_fd, &rfds);
FD_SET(watched_rd_fd, &efds);
if ( nfds <= watched_rd_fd ) { nfds = watched_rd_fd + 1; }
printf(" SELECT nfds %d rdfd %d\n", nfds, watched_rd_fd);
}
if ( watched_wr_fd ) {
FD_SET(watched_wr_fd, &wfds);
FD_SET(watched_wr_fd, &efds);
if ( nfds <= watched_wr_fd ) { nfds = watched_wr_fd + 1; }
printf(" SELECT nfds %d wrfd %d\n", nfds, watched_wr_fd);
}
}
if ( watched_chgevt_fds[0] != 0 ) {
FD_SET(watched_chgevt_fds[0], &rfds);
FD_SET(watched_chgevt_fds[0], &efds);
}
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0};
unsigned int tnowms = 0;
unsigned int toms = 0;
unsigned int tdiff = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec != local_to_startv.tv_sec ||
startv.tv_usec != local_to_startv.tv_sec )
{ /* new timeout */
local_to_startv = startv;
}
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms > tnowms ) {
tdiff = toms - tnowms; /* ms till timeout */
}
if ( tdiff < DEFAULT_SELECT_LOOP_MS ) {
/* revise timeout value */
timeoutval.tv_sec = tdiff/1000;
timeoutval.tv_usec = (tdiff%1000)*1000;
modified_timeout = 1; /* yes */
}
}
if ( modified_timeout ) {
printf(" SELECT with nfds %d ... modified tiemout %lu.%03lu\n",
nfds, timeoutval.tv_sec, timeoutval.tv_usec/1000);
} else {
printf(" SELECT with nfds %d...\n", nfds);
}
rc = select(nfds, &rfds, &wfds, &efds, &timeoutval);
if ( rc < 0 ) {
printf(" SELECT returned error %d\n", rc);
break;
}
/* the selector loop stage 2, dbus operation.
* in this stage dbus watch/timeout could change.
*/
/* check timeout */
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0}; unsigned int tnowms = 0, toms = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec == local_to_startv.tv_sec &&
startv.tv_usec == local_to_startv.tv_sec )
{ /* same timeout */
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms >= tnowms ) {
watched_timeout_lastv = tnowms%TIMEOUT_MOD_MS;
printf(" HANDLING dbus handle timeout %p\n",
watched_timeout);
dbus_timeout_handle(watched_timeout);
printf(" HANDLING dbus handle timeout %p done\n",
watched_timeout);
}
} /* else if not the same timeout as before select() skip for now */
}
/* self initiated rpc call */
if ( altsel ) {
unsigned int tmnow = time(NULL);
unsigned int tmdiff = tmnow - lastregtime;
if ( tmdiff > 10 ) { /* send a rpc evey 10 seconds */
dbus_selector_process_post_send(conn, param, &pending);
lastregtime = tmnow;
}
}
/* select() returned no event */
if ( rc == 0 ) {
printf(" SELECT returned rc 0 \n");
continue;
}
/* some event happened according to select() */
printf(" SELECT returned rc %d \n", rc);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
if ( FD_ISSET(watched_rd_fd, &rfds) ) {
printf(" HANDLING calls watch_handle\n");
dbus_watch_handle(watched_watch, DBUS_WATCH_READABLE);
printf(" HANDLING calls process_recv\n");
dbus_selector_process_recv(conn, pending==NULL?0:1,
&pending);
printf(" HANDLING done process_recv\n");
}
if ( FD_ISSET(watched_rd_fd, &efds) ) {
printf(" HANDLING EXCEPTION with rd fd %d \n",
watched_rd_fd);
}
}
if ( watched_wr_fd ) {
if ( FD_ISSET(watched_wr_fd, &wfds) ) {
dbus_watch_handle(watched_watch, DBUS_WATCH_WRITABLE);
}
if ( FD_ISSET(watched_wr_fd, &efds) ) {
printf(" HANDLING EXCEPTION with wr fd %d \n",
watched_wr_fd);
}
}
}
/* chgevt pipe */
if ( watched_chgevt_fds[0] != 0 && FD_ISSET(watched_chgevt_fds[0], &rfds) ) {
int chgevt = watched_chgevt_get();
switch (chgevt) {
case CHGEVT_ADD_WATCH:
printf(" HANDLING chgevt 1 consumed \n"); break;
case CHGEVT_ADD_TIMEOUT:
printf(" HANDLING chgevt 2 consumed \n"); break;
default:
printf(" HANDLING chgevt n=%d consumed \n", chgevt); break;
}
}
}
return ret;
}
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr)
{
int ret = 1; /* default fail */
/* remove this call that consumes .1ms because dbus is already read
* by dbus_watch_handle():
* dbus_connection_read_write(conn, 0);
*
* according to dbus_connection_dispatch(): The incoming data buffer
* is filled when the connection reads from its underlying transport
* (such as a socket). Reading usually happens in dbus_watch_handle()
* or dbus_connection_read_write().
*/
DBusDispatchStatus dispatch_rc = dbus_connection_get_dispatch_status(conn);
if ( DBUS_DISPATCH_DATA_REMAINS != dispatch_rc ) {
printf(" ERROR recv no message in queue \n");
}
while( DBUS_DISPATCH_DATA_REMAINS == dispatch_rc ) {
DBusMessage* msg = dbus_connection_borrow_message(conn);
if ( msg == NULL ) {
printf(" ERROR recv pending check FAILED: remains but "
"no message borrowed. \n");
break;
}
int mtype = dbus_message_get_type(msg);
if ( iswaiting_rpcreply &&
( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
mtype == DBUS_MESSAGE_TYPE_ERROR ) ) {
printf(" RPC REPLY pending check SUCCESS: received rpc reply \n");
dbus_connection_return_message(conn, msg);
dbus_connection_dispatch(conn);
/* dispatch so the received message at the
* head of queue is passed to the pendingcall
*/
dbus_selector_process_post_reply( conn, pendingargptr );
printf(" RPC REPLY pending check SUCCESS: processed rpc reply \n");
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
printf(" RECV pending check FAILED: received rpc reply \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
printf(" RECV pending check FAILED: received ERROR \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_SIGNAL ) {
printf(" SIGNAL pending check SUCCESS: received and drop \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_CALL ) {
printf(" RPC RECV check SUCCESS: received rpc call. \n");
dbus_connection_steal_borrowed_message(conn, msg);
DBusMessage* reply = NULL;
do {
/* craft a reply message */
DBusMessageIter args;
dbus_uint32_t serial = 111;
dbus_bool_t stat = TRUE;
dbus_uint32_t retval1 = 555;
const char *strval = "good";
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &args);
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_BOOLEAN, &stat) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_UINT32, &retval1) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_STRING, &strval) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_connection_send(conn, reply, &serial)) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
dbus_connection_flush(conn);
} while(0);
if ( reply != NULL ) { dbus_message_unref(reply); }
if ( msg != NULL ) { /* msg not consumed */
//dbus_connection_return_message(conn, msg);
dbus_message_unref(msg);
}
ret = 0; /* success */
} else {
printf(" error unknown msg type %d \n", mtype);
}
dispatch_rc = dbus_connection_get_dispatch_status(conn);
}
return ret;
}
static int dbus_selector_process_post_send( DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr)
{ /* mostly a copy of query() */
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
DBusError err = {0};
DBusPendingCall* pending = NULL;
int ret = 0;
* pendingargptr = NULL;
printf("Calling remote method with %s\n", param);
// initialiset the errors
dbus_error_init(&err);
msg = dbus_message_new_method_call(
"test.selector.server", // target for the method call
"/test/method/Object", // object to call on
"test.method.Type", // interface to call on
"Method"); // method name
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
exit(1);
}
// append arguments
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, ¶m)) {
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (conn, msg, &pending, 300)) {
// -1 is default timeout
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
if (NULL == pending) {
fprintf(stderr, "Pending Call Null\n");
exit(1);
}
printf("Request Sent\n");
dbus_connection_flush(conn); /* Note: block until write finishes */
printf("Request flushed\n");
// free message
dbus_message_unref(msg);
* pendingargptr = pending;
return ret;
}
static int dbus_selector_process_post_reply( DBusConnection* conn,
DBusPendingCall** pendingargptr )
{
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
dbus_bool_t stat = FALSE;
dbus_uint32_t level = 0;
DBusPendingCall* pending = *pendingargptr;
if ( ! dbus_pending_call_get_completed(pending) ) {
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
fprintf(stderr, " error Reply incomplete\n");
exit(1);
}
// get the reply message
msg = dbus_pending_call_steal_reply(pending);
if (NULL == msg) {
fprintf(stderr, "Reply Null\n");
exit(1);
}
// free the pending message handle
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
/* */
int validerror = 0;
{ int mtype = dbus_message_get_type(msg);
if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
fprintf(stderr, " error Reply with a valid error detected!\n");
validerror = 1;
} else if ( mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
fprintf(stderr, " error Reply not a valid return type!"
" received message type %d\n", mtype);
}
}
// read the parameters
if (!dbus_message_iter_init(msg, &args))
fprintf(stderr, "Message has no arguments!\n");
else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
{
fprintf(stderr, "Argument is not boolean!\n");
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is string!\n");
if ( validerror ) {
char * strval = (char*)"<init-unknown>";
dbus_message_iter_get_basic(&args, &strval);
if ( strval != NULL && strnlen(strval, 160) < 160 ) {
printf("RPC reply arg 0 is c%u %s\n", 160, strval);
} else {
printf("RPC reply arg 0 error \n");
}
}
} else if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is uint32!\n");
} else {
fprintf(stderr, "Argument 1 is not recognized!\n");
}
}
else
dbus_message_iter_get_basic(&args, &stat);
if (!dbus_message_iter_next(&args))
fprintf(stderr, "Message has too few arguments!\n");
else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
fprintf(stderr, "Argument is not int!\n");
else
dbus_message_iter_get_basic(&args, &level);
printf("Got Reply: %d, %d\n", stat, level);
// free reply
dbus_message_unref(msg);
return 0;
}
/* ------------------------------------------------------------ */
int main(int argc, char** argv)
{
if (2 > argc) {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
char* param = "no cmdline param";
if (3 <= argc && NULL != argv[2]) param = argv[2];
if (0 == strncmp(argv[1], "selector", 20))
dbus_selector(param, 0);
else if (0 == strncmp(argv[1], "selpost", 20))
dbus_selector(param, 1);
else {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
return 0;
}
I have written an example for implementing main loop for dbus. I have tested it with bluez DBUS API and it works without any problem.
I have removed the bluetooth part of my application. I have used libevent to implement event loop.
Note: It is in C++. You can easily convert it to C programming language.
#include "dbus-ble/libevent.h"
#include <stdlib.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/util.h>
#include <dbus/dbus.h>
struct watch_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusWatch *watch;
};
struct timeout_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusTimeout *timeout;
};
static struct event_base *ev_base = nullptr;
static void timeout_handler_free(void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
if (to_handler == nullptr)
return;
if (to_handler->ev != nullptr) {
event_del(to_handler->ev);
event_free(to_handler->ev);
}
if (to_handler->dbus_cnx != nullptr)
dbus_connection_unref(to_handler->dbus_cnx);
free(to_handler);
}
static void libevent_dispatch_dbus(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
DBusConnection *dbus_cnx = to_handler->dbus_cnx;
dbus_connection_ref(dbus_cnx);
while (dbus_connection_dispatch(dbus_cnx) == DBUS_DISPATCH_DATA_REMAINS);
dbus_connection_unref(dbus_cnx);
timeout_handler_free(to_handler);
}
static inline void throw_libevent_dispatch_dbus(DBusConnection *dbus_cnx)
{
const struct timeval timeout = {0,0};
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return;
to_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
to_handler->ev = evtimer_new(ev_base, libevent_dispatch_dbus, to_handler);
evtimer_add(to_handler->ev, &timeout);
}
static void watch_handler_dispatch(int fd, short event, void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
DBusDispatchStatus status;
unsigned int flags = 0;
dbus_connection_ref(io_handler->dbus_cnx);
if (evutil_socket_geterror(fd) != 0)
flags |= DBUS_WATCH_ERROR;
if (event & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (event & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
dbus_watch_handle(io_handler->watch, flags);
status = dbus_connection_get_dispatch_status(io_handler->dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(io_handler->dbus_cnx);
dbus_connection_unref(io_handler->dbus_cnx);
}
static void watch_handler_free(void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
if (io_handler == nullptr)
return;
if (io_handler->ev != nullptr) {
event_del(io_handler->ev);
event_free(io_handler->ev);
}
dbus_connection_unref(io_handler->dbus_cnx);
free(io_handler);
}
static dbus_bool_t libevent_dbus_watch_add(DBusWatch *watch, void *data)
{
DBusConnection *dbus_cnx = reinterpret_cast<DBusConnection *>(data);
struct watch_handler *io_handler;
unsigned int flags;
short io_condition;
int io_fd;
if (dbus_watch_get_enabled(watch) == FALSE)
return TRUE;
io_handler = reinterpret_cast<struct watch_handler *>(calloc(1, sizeof(struct watch_handler)));
if (io_handler == nullptr)
return FALSE;
io_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
io_handler->watch = watch;
dbus_watch_set_data(watch, io_handler, watch_handler_free);
flags = dbus_watch_get_flags(watch);
io_condition = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
io_condition |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
io_condition |= EV_WRITE;
io_fd = dbus_watch_get_unix_fd(watch);
io_handler->ev = event_new(ev_base, io_fd, io_condition,
watch_handler_dispatch, io_handler);
event_add(io_handler->ev, nullptr);
return TRUE;
}
static void libevent_dbus_watch_remove(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
return;
dbus_watch_set_data(watch, nullptr, nullptr);
}
static void libevent_dbus_watch_toggled(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
libevent_dbus_watch_add(watch, data);
else
libevent_dbus_watch_remove(watch, data);
}
static void timeout_handler_dispatch(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
dbus_timeout_handle(to_handler->timeout);
}
static inline void _set_timer(struct timeval *timer, long int milliseconds)
{
timer->tv_sec = milliseconds / 1000;
timer->tv_usec = (milliseconds % 1000) * 1000;
}
static dbus_bool_t libevent_dbus_timeout_add(DBusTimeout *timeout, void *data)
{
struct timeout_handler *to_handler;
struct timeval timer;
if (dbus_timeout_get_enabled(timeout) == FALSE)
return TRUE;
to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return FALSE;
dbus_timeout_set_data(timeout, to_handler, timeout_handler_free);
_set_timer(&timer, dbus_timeout_get_interval(timeout));
to_handler->ev = evtimer_new(ev_base, timeout_handler_dispatch, to_handler);
evtimer_add(to_handler->ev, (const struct timeval *) &timer);
return TRUE;
}
static void libevent_dbus_timeout_remove(DBusTimeout *timeout, void *data)
{
dbus_timeout_set_data(timeout, nullptr, nullptr);
}
static void libevent_dbus_timeout_toggled(DBusTimeout *timeout, void *data)
{
if (dbus_timeout_get_enabled(timeout) == TRUE)
libevent_dbus_timeout_add(timeout, data);
else
libevent_dbus_timeout_remove(timeout, data);
}
static void libevent_dbus_dispatch_status(DBusConnection *dbus_cnx,
DBusDispatchStatus new_status, void *data)
{
DBusDispatchStatus status;
if (dbus_connection_get_is_connected(dbus_cnx) == FALSE)
return;
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
}
static dbus_bool_t setup_dbus_in_libevent_mainloop(DBusConnection *dbus_cnx)
{
DBusDispatchStatus status;
if (dbus_connection_set_watch_functions(dbus_cnx,
libevent_dbus_watch_add, libevent_dbus_watch_remove,
libevent_dbus_watch_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
if (dbus_connection_set_timeout_functions(dbus_cnx,
libevent_dbus_timeout_add, libevent_dbus_timeout_remove,
libevent_dbus_timeout_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
dbus_connection_set_dispatch_status_function(dbus_cnx,
libevent_dbus_dispatch_status, dbus_cnx, nullptr);
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
return TRUE;
}
int setup_event_loop_for_dbus(DBusConnection *dbus_cnx)
{
if (ev_base == nullptr)
ev_base = event_base_new();
if (ev_base == nullptr)
return -1;
if (setup_dbus_in_libevent_mainloop(dbus_cnx) == FALSE) {
dbus_connection_unref(dbus_cnx);
event_base_free(ev_base);
return -1;
}
return 0;
}
int libevent_run_loop_dbus(void)
{
return event_base_loop(ev_base, 0);
}
void dbus_cleanup_event_loop(DBusConnection *dbus_cnx)
{
if (dbus_cnx == nullptr)
return;
dbus_connection_set_watch_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_timeout_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_dispatch_status_function(dbus_cnx,
nullptr, nullptr, nullptr);
}