You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
7.1 KiB
C
280 lines
7.1 KiB
C
/*
|
|
Copyright (c) 2021 Roger Light <roger@atchoo.org>
|
|
|
|
All rights reserved. This program and the accompanying materials
|
|
are made available under the terms of the Eclipse Public License 2.0
|
|
and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
|
|
The Eclipse Public License is available at
|
|
https://www.eclipse.org/legal/epl-2.0/
|
|
and the Eclipse Distribution License is available at
|
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
|
|
|
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
|
|
|
Contributors:
|
|
Roger Light - initial implementation and documentation.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <cjson/cJSON.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "mosquitto_ctrl.h"
|
|
#include "mosquitto.h"
|
|
|
|
void broker__print_usage(void)
|
|
{
|
|
printf("\nBroker Control module\n");
|
|
printf("=======================\n");
|
|
|
|
printf("List plugins : listPlugins\n");
|
|
printf("List listeners : listListeners\n");
|
|
}
|
|
|
|
/* ################################################################
|
|
* #
|
|
* # Payload callback
|
|
* #
|
|
* ################################################################ */
|
|
|
|
static void print_listeners(cJSON *j_response)
|
|
{
|
|
cJSON *j_data, *j_listeners, *j_listener, *jtmp;
|
|
int i=1;
|
|
|
|
j_data = cJSON_GetObjectItem(j_response, "data");
|
|
if(j_data == NULL || !cJSON_IsObject(j_data)){
|
|
fprintf(stderr, "Error: Invalid response from server.\n");
|
|
return;
|
|
}
|
|
|
|
j_listeners = cJSON_GetObjectItem(j_data, "listeners");
|
|
if(j_listeners == NULL || !cJSON_IsArray(j_listeners)){
|
|
fprintf(stderr, "Error: Invalid response from server.\n");
|
|
return;
|
|
}
|
|
|
|
cJSON_ArrayForEach(j_listener, j_listeners){
|
|
printf("Listener %d:\n", i);
|
|
|
|
jtmp = cJSON_GetObjectItem(j_listener, "port");
|
|
if(jtmp && cJSON_IsNumber(jtmp)){
|
|
printf(" Port: %d\n", jtmp->valueint);
|
|
}
|
|
|
|
jtmp = cJSON_GetObjectItem(j_listener, "protocol");
|
|
if(jtmp && cJSON_IsString(jtmp)){
|
|
printf(" Protocol: %s\n", jtmp->valuestring);
|
|
}
|
|
|
|
jtmp = cJSON_GetObjectItem(j_listener, "socket-path");
|
|
if(jtmp && cJSON_IsString(jtmp)){
|
|
printf(" Socket path: %s\n", jtmp->valuestring);
|
|
}
|
|
|
|
jtmp = cJSON_GetObjectItem(j_listener, "bind-address");
|
|
if(jtmp && cJSON_IsString(jtmp)){
|
|
printf(" Bind address: %s\n", jtmp->valuestring);
|
|
}
|
|
|
|
jtmp = cJSON_GetObjectItem(j_listener, "tls");
|
|
printf(" TLS: %s\n", jtmp && cJSON_IsBool(jtmp) && cJSON_IsTrue(jtmp)?"true":"false");
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
static void print_plugin_info(cJSON *j_response)
|
|
{
|
|
cJSON *j_data, *j_plugins, *j_plugin, *jtmp, *j_eps;
|
|
bool first;
|
|
|
|
j_data = cJSON_GetObjectItem(j_response, "data");
|
|
if(j_data == NULL || !cJSON_IsObject(j_data)){
|
|
fprintf(stderr, "Error: Invalid response from server.\n");
|
|
return;
|
|
}
|
|
|
|
j_plugins = cJSON_GetObjectItem(j_data, "plugins");
|
|
if(j_plugins == NULL || !cJSON_IsArray(j_plugins)){
|
|
fprintf(stderr, "Error: Invalid response from server.\n");
|
|
return;
|
|
}
|
|
|
|
cJSON_ArrayForEach(j_plugin, j_plugins){
|
|
jtmp = cJSON_GetObjectItem(j_plugin, "name");
|
|
if(jtmp == NULL || !cJSON_IsString(jtmp)){
|
|
fprintf(stderr, "Error: Invalid response from server.\n");
|
|
return;
|
|
}
|
|
printf("Plugin: %s\n", jtmp->valuestring);
|
|
|
|
jtmp = cJSON_GetObjectItem(j_plugin, "version");
|
|
if(jtmp && cJSON_IsString(jtmp)){
|
|
printf("Version: %s\n", jtmp->valuestring);
|
|
}
|
|
|
|
j_eps = cJSON_GetObjectItem(j_plugin, "control-endpoints");
|
|
if(j_eps && cJSON_IsArray(j_eps)){
|
|
first = true;
|
|
cJSON_ArrayForEach(jtmp, j_eps){
|
|
if(jtmp && cJSON_IsString(jtmp)){
|
|
if(first){
|
|
first = false;
|
|
printf("Control endpoints: %s\n", jtmp->valuestring);
|
|
}else{
|
|
printf(" %s\n", jtmp->valuestring);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void broker__payload_callback(struct mosq_ctrl *ctrl, long payloadlen, const void *payload)
|
|
{
|
|
cJSON *tree, *j_responses, *j_response, *j_command, *j_error;
|
|
|
|
UNUSED(ctrl);
|
|
|
|
#if CJSON_VERSION_FULL < 1007013
|
|
UNUSED(payloadlen);
|
|
tree = cJSON_Parse(payload);
|
|
#else
|
|
tree = cJSON_ParseWithLength(payload, (size_t)payloadlen);
|
|
#endif
|
|
if(tree == NULL){
|
|
fprintf(stderr, "Error: Payload not JSON.\n");
|
|
return;
|
|
}
|
|
|
|
j_responses = cJSON_GetObjectItem(tree, "responses");
|
|
if(j_responses == NULL || !cJSON_IsArray(j_responses)){
|
|
fprintf(stderr, "Error: Payload missing data.\n");
|
|
cJSON_Delete(tree);
|
|
return;
|
|
}
|
|
|
|
j_response = cJSON_GetArrayItem(j_responses, 0);
|
|
if(j_response == NULL){
|
|
fprintf(stderr, "Error: Payload missing data.\n");
|
|
cJSON_Delete(tree);
|
|
return;
|
|
}
|
|
|
|
j_command = cJSON_GetObjectItem(j_response, "command");
|
|
if(j_command == NULL){
|
|
fprintf(stderr, "Error: Payload missing data.\n");
|
|
cJSON_Delete(tree);
|
|
return;
|
|
}
|
|
|
|
j_error = cJSON_GetObjectItem(j_response, "error");
|
|
if(j_error){
|
|
fprintf(stderr, "%s: Error: %s\n", j_command->valuestring, j_error->valuestring);
|
|
}else{
|
|
if(!strcasecmp(j_command->valuestring, "listPlugins")){
|
|
print_plugin_info(j_response);
|
|
}else if(!strcasecmp(j_command->valuestring, "listListeners")){
|
|
print_listeners(j_response);
|
|
}else{
|
|
/* fprintf(stderr, "%s: Success\n", j_command->valuestring); */
|
|
}
|
|
}
|
|
cJSON_Delete(tree);
|
|
}
|
|
|
|
static int broker__list_plugins(int argc, char *argv[], cJSON *j_command)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
|
|
if(cJSON_AddStringToObject(j_command, "command", "listPlugins") == NULL
|
|
){
|
|
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
}
|
|
|
|
static int broker__list_listeners(int argc, char *argv[], cJSON *j_command)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
|
|
if(cJSON_AddStringToObject(j_command, "command", "listListeners") == NULL
|
|
){
|
|
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
}
|
|
|
|
/* ################################################################
|
|
* #
|
|
* # Main
|
|
* #
|
|
* ################################################################ */
|
|
|
|
int broker__main(int argc, char *argv[], struct mosq_ctrl *ctrl)
|
|
{
|
|
int rc = -1;
|
|
cJSON *j_tree;
|
|
cJSON *j_commands, *j_command;
|
|
|
|
if(!strcasecmp(argv[0], "help")){
|
|
broker__print_usage();
|
|
return -1;
|
|
}
|
|
|
|
/* The remaining commands need a network connection and JSON command. */
|
|
|
|
ctrl->payload_callback = broker__payload_callback;
|
|
ctrl->request_topic = strdup("$CONTROL/broker/v1");
|
|
ctrl->response_topic = strdup("$CONTROL/broker/v1/response");
|
|
if(ctrl->request_topic == NULL || ctrl->response_topic == NULL){
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
j_tree = cJSON_CreateObject();
|
|
if(j_tree == NULL) return MOSQ_ERR_NOMEM;
|
|
j_commands = cJSON_AddArrayToObject(j_tree, "commands");
|
|
if(j_commands == NULL){
|
|
cJSON_Delete(j_tree);
|
|
j_tree = NULL;
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
j_command = cJSON_CreateObject();
|
|
if(j_command == NULL){
|
|
cJSON_Delete(j_tree);
|
|
j_tree = NULL;
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
cJSON_AddItemToArray(j_commands, j_command);
|
|
|
|
if(!strcasecmp(argv[0], "listPlugins")){
|
|
rc = broker__list_plugins(argc-1, &argv[1], j_command);
|
|
}else if(!strcasecmp(argv[0], "listListeners")){
|
|
rc = broker__list_listeners(argc-1, &argv[1], j_command);
|
|
|
|
}else{
|
|
fprintf(stderr, "Command '%s' not recognised.\n", argv[0]);
|
|
return MOSQ_ERR_UNKNOWN;
|
|
}
|
|
|
|
if(rc == MOSQ_ERR_SUCCESS){
|
|
ctrl->payload = cJSON_PrintUnformatted(j_tree);
|
|
cJSON_Delete(j_tree);
|
|
if(ctrl->payload == NULL){
|
|
fprintf(stderr, "Error: Out of memory.\n");
|
|
return MOSQ_ERR_NOMEM;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|