diff --git a/client/Makefile b/client/Makefile index 54a12f09..cfd8c76a 100644 --- a/client/Makefile +++ b/client/Makefile @@ -4,11 +4,11 @@ include ../config.mk all : mosquitto_pub mosquitto_sub -mosquitto_pub : pub_client.o ../lib/libmosquitto.so.${SOVERSION} - ${CC} $< -o $@ ${CLIENT_LDFLAGS} +mosquitto_pub : pub_client.o client_shared.o + ${CC} $^ -o $@ ${CLIENT_LDFLAGS} -mosquitto_sub : sub_client.o ../lib/libmosquitto.so.${SOVERSION} - ${CC} $< -o $@ ${CLIENT_LDFLAGS} +mosquitto_sub : sub_client.o client_shared.o + ${CC} $^ -o $@ ${CLIENT_LDFLAGS} pub_client.o : pub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CC} -c $< -o $@ ${CLIENT_CFLAGS} @@ -16,6 +16,9 @@ pub_client.o : pub_client.c ../lib/libmosquitto.so.${SOVERSION} sub_client.o : sub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CC} -c $< -o $@ ${CLIENT_CFLAGS} +client_shared.o : client_shared.c client_shared.h + ${CC} -c $< -o $@ ${CLIENT_CFLAGS} + ../lib/libmosquitto.so.${SOVERSION} : $(MAKE) -C ../lib diff --git a/client/client_shared.c b/client/client_shared.c new file mode 100644 index 00000000..10a8409b --- /dev/null +++ b/client/client_shared.c @@ -0,0 +1,503 @@ +/* +Copyright (c) 2014 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#else +#include +#include +#define snprintf sprintf_s +#endif + +#include +#include "client_shared.h" + +void init_config(struct mosq_config *cfg) +{ + memset(cfg, 0, sizeof(*cfg)); + cfg->port = 1883; + cfg->max_inflight = 20; + cfg->keepalive = 60; + cfg->clean_session = true; + cfg->eol = true; +} + +int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) +{ + int i; + + init_config(cfg); + + for(i=1; iport = atoi(argv[i+1]); + if(cfg->port<1 || cfg->port>65535){ + fprintf(stderr, "Error: Invalid port given: %d\n", cfg->port); + return 1; + } + } + i++; + }else if(!strcmp(argv[i], "-A")){ + if(i==argc-1){ + fprintf(stderr, "Error: -A argument given but no address specified.\n\n"); + return 1; + }else{ + cfg->bind_address = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--cafile")){ + if(i==argc-1){ + fprintf(stderr, "Error: --cafile argument given but no file specified.\n\n"); + return 1; + }else{ + cfg->cafile = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--capath")){ + if(i==argc-1){ + fprintf(stderr, "Error: --capath argument given but no directory specified.\n\n"); + return 1; + }else{ + cfg->capath = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--cert")){ + if(i==argc-1){ + fprintf(stderr, "Error: --cert argument given but no file specified.\n\n"); + return 1; + }else{ + cfg->certfile = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--ciphers")){ + if(i==argc-1){ + fprintf(stderr, "Error: --ciphers argument given but no ciphers specified.\n\n"); + return 1; + }else{ + cfg->ciphers = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ + cfg->debug = true; + }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){ + if(cfg->pub_mode != MSGMODE_NONE){ + fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); + return 1; + }else if(i==argc-1){ + fprintf(stderr, "Error: -f argument given but no file specified.\n\n"); + return 1; + }else{ + cfg->pub_mode = MSGMODE_FILE; + cfg->file_input = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--help")){ + return 1; + }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){ + if(i==argc-1){ + fprintf(stderr, "Error: -h argument given but no host specified.\n\n"); + return 1; + }else{ + cfg->host = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--insecure")){ + cfg->insecure = true; + }else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){ + if(cfg->id_prefix){ + fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); + return 1; + } + if(i==argc-1){ + fprintf(stderr, "Error: -i argument given but no id specified.\n\n"); + return 1; + }else{ + cfg->id = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){ + if(cfg->id){ + fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); + return 1; + } + if(i==argc-1){ + fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n"); + return 1; + }else{ + cfg->id_prefix = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-k") || !strcmp(argv[i], "--keepalive")){ + if(i==argc-1){ + fprintf(stderr, "Error: -k argument given but no keepalive specified.\n\n"); + return 1; + }else{ + cfg->keepalive = atoi(argv[i+1]); + if(cfg->keepalive>65535){ + fprintf(stderr, "Error: Invalid keepalive given: %d\n", cfg->keepalive); + return 1; + } + } + i++; + }else if(!strcmp(argv[i], "--key")){ + if(i==argc-1){ + fprintf(stderr, "Error: --key argument given but no file specified.\n\n"); + return 1; + }else{ + cfg->keyfile = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){ + if(cfg->pub_mode != MSGMODE_NONE){ + fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); + return 1; + }else{ + cfg->pub_mode = MSGMODE_STDIN_LINE; + } + }else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--message")){ + if(cfg->pub_mode != MSGMODE_NONE){ + fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); + return 1; + }else if(i==argc-1){ + fprintf(stderr, "Error: -m argument given but no message specified.\n\n"); + return 1; + }else{ + cfg->message = argv[i+1]; + cfg->msglen = strlen(cfg->message); + cfg->pub_mode = MSGMODE_CMD; + } + i++; + }else if(!strcmp(argv[i], "-M")){ + if(i==argc-1){ + fprintf(stderr, "Error: -M argument given but max_inflight not specified.\n\n"); + return 1; + }else{ + cfg->max_inflight = atoi(argv[i+1]); + } + i++; + }else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--null-message")){ + if(cfg->pub_mode != MSGMODE_NONE){ + fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); + return 1; + }else{ + cfg->pub_mode = MSGMODE_NULL; + } + }else if(!strcmp(argv[i], "--psk")){ + if(i==argc-1){ + fprintf(stderr, "Error: --psk argument given but no key specified.\n\n"); + return 1; + }else{ + cfg->psk = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--psk-identity")){ + if(i==argc-1){ + fprintf(stderr, "Error: --psk-identity argument given but no identity specified.\n\n"); + return 1; + }else{ + cfg->psk_identity = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){ + if(i==argc-1){ + fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n"); + return 1; + }else{ + cfg->qos = atoi(argv[i+1]); + if(cfg->qos<0 || cfg->qos>2){ + fprintf(stderr, "Error: Invalid QoS given: %d\n", cfg->qos); + return 1; + } + } + i++; + }else if(!strcmp(argv[i], "--quiet")){ + cfg->quiet = true; + }else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--retain")){ + cfg->retain = 1; + }else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){ + if(cfg->pub_mode != MSGMODE_NONE){ + fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); + return 1; + }else{ + cfg->pub_mode = MSGMODE_STDIN_FILE; + } + }else if(!strcmp(argv[i], "-S")){ + cfg->use_srv = true; + }else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){ + if(i==argc-1){ + fprintf(stderr, "Error: -t argument given but no topic specified.\n\n"); + return 1; + }else{ + if(pub_or_sub == CLIENT_PUB){ + cfg->topic = argv[i+1]; + }else{ + cfg->topic_count++; + cfg->topics = realloc(cfg->topics, cfg->topic_count*sizeof(char *)); + cfg->topics[cfg->topic_count-1] = argv[i+1]; + } + i++; + } + }else if(!strcmp(argv[i], "-T") || !strcmp(argv[i], "--filter-out")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + if(i==argc-1){ + fprintf(stderr, "Error: -T argument given but no topic filter specified.\n\n"); + return 1; + }else{ + cfg->filter_out_count++; + cfg->filter_outs = realloc(cfg->filter_outs, cfg->filter_out_count*sizeof(char *)); + cfg->filter_outs[cfg->filter_out_count-1] = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--tls-version")){ + if(i==argc-1){ + fprintf(stderr, "Error: --tls-version argument given but no version specified.\n\n"); + return 1; + }else{ + cfg->tls_version = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){ + if(i==argc-1){ + fprintf(stderr, "Error: -u argument given but no username specified.\n\n"); + return 1; + }else{ + cfg->username = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){ + if(i==argc-1){ + fprintf(stderr, "Error: -P argument given but no password specified.\n\n"); + return 1; + }else{ + cfg->password = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "--will-payload")){ + if(i==argc-1){ + fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n"); + return 1; + }else{ + cfg->will_payload = argv[i+1]; + cfg->will_payloadlen = strlen(cfg->will_payload); + } + i++; + }else if(!strcmp(argv[i], "--will-qos")){ + if(i==argc-1){ + fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n"); + return 1; + }else{ + cfg->will_qos = atoi(argv[i+1]); + if(cfg->will_qos < 0 || cfg->will_qos > 2){ + fprintf(stderr, "Error: Invalid will QoS %d.\n\n", cfg->will_qos); + return 1; + } + } + i++; + }else if(!strcmp(argv[i], "--will-retain")){ + cfg->will_retain = true; + }else if(!strcmp(argv[i], "--will-topic")){ + if(i==argc-1){ + fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n"); + return 1; + }else{ + cfg->will_topic = argv[i+1]; + } + i++; + }else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--disable-clean-session")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + cfg->clean_session = false; + }else if(!strcmp(argv[i], "-N")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + cfg->eol = false; + }else if(!strcmp(argv[i], "-R")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + cfg->no_retain = true; + }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + cfg->verbose = 1; + }else{ + goto unknown_option; + } + } + + if(cfg->will_payload && !cfg->will_topic){ + fprintf(stderr, "Error: Will payload given, but no will topic given.\n"); + return 1; + } + if(cfg->will_retain && !cfg->will_topic){ + fprintf(stderr, "Error: Will retain given, but no will topic given.\n"); + return 1; + } + if(cfg->password && !cfg->username){ + if(!cfg->quiet) fprintf(stderr, "Warning: Not using password since username not set.\n"); + } + if((cfg->certfile && !cfg->keyfile) || (cfg->keyfile && !cfg->certfile)){ + fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is.\n"); + return 1; + } + if((cfg->cafile || cfg->capath) && cfg->psk){ + if(!cfg->quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); + return 1; + } + if(cfg->psk && !cfg->psk_identity){ + if(!cfg->quiet) fprintf(stderr, "Error: --psk-identity required if --psk used.\n"); + return 1; + } + + if(pub_or_sub == CLIENT_SUB){ + if(cfg->clean_session == false && (cfg->id_prefix || !cfg->id)){ + if(!cfg->quiet) fprintf(stderr, "Error: You must provide a client id if you are using the -c option.\n"); + return 1; + } + if(cfg->topic_count == 0){ + if(!cfg->quiet) fprintf(stderr, "Error: You must specify a topic to subscribe to.\n"); + return 1; + } + } + + if(!cfg->host){ + cfg->host = "localhost"; + } + + return MOSQ_ERR_SUCCESS; + +unknown_option: + fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); + return 1; +} + +int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) +{ + if(cfg->will_topic && mosquitto_will_set(mosq, cfg->will_topic, + cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, + cfg->will_retain)){ + + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting will.\n"); + mosquitto_lib_cleanup(); + return 1; + } + if(cfg->username && mosquitto_username_pw_set(mosq, cfg->username, cfg->password)){ + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting username and password.\n"); + mosquitto_lib_cleanup(); + return 1; + } + if((cfg->cafile || cfg->capath) + && mosquitto_tls_set(mosq, cfg->cafile, cfg->capath, cfg->certfile, cfg->keyfile, NULL)){ + + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); + mosquitto_lib_cleanup(); + return 1; + } + if(cfg->insecure && mosquitto_tls_insecure_set(mosq, true)){ + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS insecure option.\n"); + mosquitto_lib_cleanup(); + return 1; + } + if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); + mosquitto_lib_cleanup(); + return 1; + } + if(cfg->tls_version && mosquitto_tls_opts_set(mosq, 1, cfg->tls_version, cfg->ciphers)){ + if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); + mosquitto_lib_cleanup(); + return 1; + } + mosquitto_max_inflight_messages_set(mosq, cfg->max_inflight); + return MOSQ_ERR_SUCCESS; +} + +int client_id_generate(struct mosq_config *cfg, const char *id_base) +{ + int len; + char hostname[256]; + + if(cfg->id_prefix){ + cfg->id = malloc(strlen(cfg->id_prefix)+10); + if(!cfg->id){ + if(!cfg->quiet) fprintf(stderr, "Error: Out of memory.\n"); + mosquitto_lib_cleanup(); + return 1; + } + snprintf(cfg->id, strlen(cfg->id_prefix)+10, "%s%d", cfg->id_prefix, getpid()); + }else if(!cfg->id){ + hostname[0] = '\0'; + gethostname(hostname, 256); + hostname[255] = '\0'; + len = strlen(id_base) + strlen("/-") + 6 + strlen(hostname); + cfg->id = malloc(len); + if(!cfg->id){ + if(!cfg->quiet) fprintf(stderr, "Error: Out of memory.\n"); + mosquitto_lib_cleanup(); + return 1; + } + snprintf(cfg->id, len, "%s/%d-%s", id_base, getpid(), hostname); + if(strlen(cfg->id) > MOSQ_MQTT_ID_MAX_LENGTH){ + /* Enforce maximum client id length of 23 characters */ + cfg->id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; + } + } + return MOSQ_ERR_SUCCESS; +} + +int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) +{ + char err[1024]; + int rc; + + if(cfg->use_srv){ + rc = mosquitto_connect_srv(mosq, cfg->host, cfg->keepalive, cfg->bind_address); + }else{ + rc = mosquitto_connect_bind(mosq, cfg->host, cfg->port, cfg->keepalive, cfg->bind_address); + } + if(rc){ + if(!cfg->quiet){ + if(rc == MOSQ_ERR_ERRNO){ +#ifndef WIN32 + strerror_r(errno, err, 1024); +#else + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL); +#endif + fprintf(stderr, "Error: %s\n", err); + }else{ + fprintf(stderr, "Unable to connect (%d).\n", rc); + } + } + mosquitto_lib_cleanup(); + return rc; + } + return MOSQ_ERR_SUCCESS; +} diff --git a/client/client_shared.h b/client/client_shared.h new file mode 100644 index 00000000..5d2b6fed --- /dev/null +++ b/client/client_shared.h @@ -0,0 +1,87 @@ +/* +Copyright (c) 2014 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#ifndef _CLIENT_CONFIG_H +#define _CLIENT_CONFIG_H + +#include + +/* pub_client.c modes */ +#define MSGMODE_NONE 0 +#define MSGMODE_CMD 1 +#define MSGMODE_STDIN_LINE 2 +#define MSGMODE_STDIN_FILE 3 +#define MSGMODE_FILE 4 +#define MSGMODE_NULL 5 + +#define CLIENT_PUB 1 +#define CLIENT_SUB 2 + +struct mosq_config { + char *id; + char *id_prefix; + int keepalive; + char *host; + int port; + int qos; + bool retain; + int pub_mode; /* pub */ + char *file_input; /* pub */ + char *message; /* pub */ + long msglen; /* pub */ + char *topic; /* pub */ + char *bind_address; + bool use_srv; + bool debug; + bool quiet; + unsigned int max_inflight; + char *username; + char *password; + char *will_topic; + char *will_payload; + long will_payloadlen; + int will_qos; + bool will_retain; +#ifdef WITH_TLS + char *cafile; + char *capath; + char *certfile; + char *keyfile; + char *ciphers; + bool insecure; + char *tls_version; +# ifdef WITH_TLS_PSK + char *psk; + char *psk_identity; +# endif + bool clean_session; /* sub */ + char **topics; /* sub */ + int topic_count; /* sub */ + int topic_qos; /* sub */ + bool no_retain; /* sub */ + char **filter_outs; /* sub */ + int filter_out_count; /* sub */ + bool verbose; /* sub */ + bool eol; /* sub */ +#endif +}; + +int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); +int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg); +int client_id_generate(struct mosq_config *cfg, const char *id_base); +int client_connect(struct mosquitto *mosq, struct mosq_config *cfg); + +#endif diff --git a/client/pub_client.c b/client/pub_client.c index d08dcb69..3a0c8972 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -29,13 +29,7 @@ Contributors: #endif #include - -#define MSGMODE_NONE 0 -#define MSGMODE_CMD 1 -#define MSGMODE_STDIN_LINE 2 -#define MSGMODE_STDIN_FILE 3 -#define MSGMODE_FILE 4 -#define MSGMODE_NULL 5 +#include "client_shared.h" #define STATUS_CONNECTING 0 #define STATUS_CONNACK_RECVD 1 @@ -273,328 +267,36 @@ void print_usage(void) int main(int argc, char *argv[]) { - char *id = NULL; - char *id_prefix = NULL; - int i; - char *host = "localhost"; - int port = 1883; - char *bind_address = NULL; - int keepalive = 60; + struct mosq_config cfg; char buf[1024]; bool debug = false; struct mosquitto *mosq = NULL; int rc; int rc2; - char hostname[256]; - char err[1024]; - int len; - unsigned int max_inflight = 20; - char *will_payload = NULL; - long will_payloadlen = 0; - int will_qos = 0; - bool will_retain = false; - char *will_topic = NULL; + if(client_config_load(&cfg, CLIENT_PUB, argc, argv)){ + print_usage(); + return 1; + } - bool insecure = false; - char *cafile = NULL; - char *capath = NULL; - char *certfile = NULL; - char *keyfile = NULL; - char *tls_version = NULL; + topic = cfg.topic; + message = cfg.message; + msglen = cfg.msglen; + qos = cfg.qos; + retain = cfg.retain; + mode = cfg.pub_mode; + username = cfg.username; + password = cfg.password; + quiet = cfg.quiet; - char *psk = NULL; - char *psk_identity = NULL; - - char *ciphers = NULL; - - bool use_srv = false; - - for(i=1; i65535){ - fprintf(stderr, "Error: Invalid port given: %d\n", port); - print_usage(); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "-A")){ - if(i==argc-1){ - fprintf(stderr, "Error: -A argument given but no address specified.\n\n"); - print_usage(); - return 1; - }else{ - bind_address = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--cafile")){ - if(i==argc-1){ - fprintf(stderr, "Error: --cafile argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - cafile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--capath")){ - if(i==argc-1){ - fprintf(stderr, "Error: --capath argument given but no directory specified.\n\n"); - print_usage(); - return 1; - }else{ - capath = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--cert")){ - if(i==argc-1){ - fprintf(stderr, "Error: --cert argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - certfile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--ciphers")){ - if(i==argc-1){ - fprintf(stderr, "Error: --ciphers argument given but no ciphers specified.\n\n"); - print_usage(); - return 1; - }else{ - ciphers = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ - debug = true; - }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){ - if(mode != MSGMODE_NONE){ - fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); - print_usage(); - return 1; - }else if(i==argc-1){ - fprintf(stderr, "Error: -f argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - if(load_file(argv[i+1])) return 1; - } - i++; - }else if(!strcmp(argv[i], "--help")){ - print_usage(); - return 0; - }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){ - if(i==argc-1){ - fprintf(stderr, "Error: -h argument given but no host specified.\n\n"); - print_usage(); - return 1; - }else{ - host = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--insecure")){ - insecure = true; - }else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){ - if(id_prefix){ - fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); - print_usage(); - return 1; - } - if(i==argc-1){ - fprintf(stderr, "Error: -i argument given but no id specified.\n\n"); - print_usage(); - return 1; - }else{ - id = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){ - if(id){ - fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); - print_usage(); - return 1; - } - if(i==argc-1){ - fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n"); - print_usage(); - return 1; - }else{ - id_prefix = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--key")){ - if(i==argc-1){ - fprintf(stderr, "Error: --key argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - keyfile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){ - if(mode != MSGMODE_NONE){ - fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); - print_usage(); - return 1; - }else{ - mode = MSGMODE_STDIN_LINE; - } - }else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--message")){ - if(mode != MSGMODE_NONE){ - fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); - print_usage(); - return 1; - }else if(i==argc-1){ - fprintf(stderr, "Error: -m argument given but no message specified.\n\n"); - print_usage(); - return 1; - }else{ - message = argv[i+1]; - msglen = strlen(message); - mode = MSGMODE_CMD; - } - i++; - }else if(!strcmp(argv[i], "-M")){ - if(i==argc-1){ - fprintf(stderr, "Error: -M argument given but max_inflight not specified.\n\n"); - print_usage(); - return 1; - }else{ - max_inflight = atoi(argv[i+1]); - } - i++; - }else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--null-message")){ - if(mode != MSGMODE_NONE){ - fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); - print_usage(); - return 1; - }else{ - mode = MSGMODE_NULL; - } - }else if(!strcmp(argv[i], "--psk")){ - if(i==argc-1){ - fprintf(stderr, "Error: --psk argument given but no key specified.\n\n"); - print_usage(); - return 1; - }else{ - psk = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--psk-identity")){ - if(i==argc-1){ - fprintf(stderr, "Error: --psk-identity argument given but no identity specified.\n\n"); - print_usage(); - return 1; - }else{ - psk_identity = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){ - if(i==argc-1){ - fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n"); - print_usage(); - return 1; - }else{ - qos = atoi(argv[i+1]); - if(qos<0 || qos>2){ - fprintf(stderr, "Error: Invalid QoS given: %d\n", qos); - print_usage(); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "--quiet")){ - quiet = true; - }else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--retain")){ - retain = 1; - }else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){ - if(mode != MSGMODE_NONE){ - fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); - print_usage(); - return 1; - }else{ - if(load_stdin()) return 1; - } - }else if(!strcmp(argv[i], "-S")){ - use_srv = true; - }else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){ - if(i==argc-1){ - fprintf(stderr, "Error: -t argument given but no topic specified.\n\n"); - print_usage(); - return 1; - }else{ - topic = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--tls-version")){ - if(i==argc-1){ - fprintf(stderr, "Error: --tls-version argument given but no version specified.\n\n"); - print_usage(); - return 1; - }else{ - tls_version = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){ - if(i==argc-1){ - fprintf(stderr, "Error: -u argument given but no username specified.\n\n"); - print_usage(); - return 1; - }else{ - username = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){ - if(i==argc-1){ - fprintf(stderr, "Error: -P argument given but no password specified.\n\n"); - print_usage(); - return 1; - }else{ - password = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--will-payload")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n"); - print_usage(); - return 1; - }else{ - will_payload = argv[i+1]; - will_payloadlen = strlen(will_payload); - } - i++; - }else if(!strcmp(argv[i], "--will-qos")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n"); - print_usage(); - return 1; - }else{ - will_qos = atoi(argv[i+1]); - if(will_qos < 0 || will_qos > 2){ - fprintf(stderr, "Error: Invalid will QoS %d.\n\n", will_qos); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "--will-retain")){ - will_retain = true; - }else if(!strcmp(argv[i], "--will-topic")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n"); - print_usage(); - return 1; - }else{ - will_topic = argv[i+1]; - } - i++; - }else{ - fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); - print_usage(); + if(cfg.pub_mode == MSGMODE_STDIN_FILE){ + if(load_stdin()){ + fprintf(stderr, "Error loading input from stdin.\n"); + return 1; + } + }else if(cfg.file_input){ + if(load_file(cfg.file_input)){ + fprintf(stderr, "Error loading input file \"%s\".\n", cfg.file_input); return 1; } } @@ -605,62 +307,14 @@ int main(int argc, char *argv[]) return 1; } - if(will_payload && !will_topic){ - fprintf(stderr, "Error: Will payload given, but no will topic given.\n"); - print_usage(); - return 1; - } - if(will_retain && !will_topic){ - fprintf(stderr, "Error: Will retain given, but no will topic given.\n"); - print_usage(); - return 1; - } - if(password && !username){ - if(!quiet) fprintf(stderr, "Warning: Not using password since username not set.\n"); - } - if((certfile && !keyfile) || (keyfile && !certfile)){ - fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is.\n"); - print_usage(); - return 1; - } - if((cafile || capath) && psk){ - if(!quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); - return 1; - } - if(psk && !psk_identity){ - if(!quiet) fprintf(stderr, "Error: --psk-identity required if --psk used.\n"); - return 1; - } mosquitto_lib_init(); - if(id_prefix){ - id = malloc(strlen(id_prefix)+10); - if(!id){ - if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); - mosquitto_lib_cleanup(); - return 1; - } - snprintf(id, strlen(id_prefix)+10, "%s%d", id_prefix, getpid()); - }else if(!id){ - hostname[0] = '\0'; - gethostname(hostname, 256); - hostname[255] = '\0'; - len = strlen("mosqpub/-") + 6 + strlen(hostname); - id = malloc(len); - if(!id){ - if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); - mosquitto_lib_cleanup(); - return 1; - } - snprintf(id, len, "mosqpub/%d-%s", getpid(), hostname); - if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH){ - /* Enforce maximum client id length of 23 characters */ - id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; - } + if(client_id_generate(&cfg, "mosqpub")){ + return 1; } - mosq = mosquitto_new(id, true, NULL); + mosq = mosquitto_new(cfg.id, true, NULL); if(!mosq){ switch(errno){ case ENOMEM: @@ -676,62 +330,15 @@ int main(int argc, char *argv[]) if(debug){ mosquitto_log_callback_set(mosq, my_log_callback); } - if(will_topic && mosquitto_will_set(mosq, will_topic, will_payloadlen, will_payload, will_qos, will_retain)){ - if(!quiet) fprintf(stderr, "Error: Problem setting will.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(username && mosquitto_username_pw_set(mosq, username, password)){ - if(!quiet) fprintf(stderr, "Error: Problem setting username and password.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if((cafile || capath) && mosquitto_tls_set(mosq, cafile, capath, certfile, keyfile, NULL)){ - if(!quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(insecure && mosquitto_tls_insecure_set(mosq, true)){ - if(!quiet) fprintf(stderr, "Error: Problem setting TLS insecure option.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(psk && mosquitto_tls_psk_set(mosq, psk, psk_identity, NULL)){ - if(!quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(tls_version && mosquitto_tls_opts_set(mosq, 1, tls_version, ciphers)){ - if(!quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); - mosquitto_lib_cleanup(); - return 1; - } - mosquitto_max_inflight_messages_set(mosq, max_inflight); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); mosquitto_publish_callback_set(mosq, my_publish_callback); - if(use_srv){ - rc = mosquitto_connect_srv(mosq, host, keepalive, bind_address); - }else{ - rc = mosquitto_connect_bind(mosq, host, port, keepalive, bind_address); - } - if(rc){ - if(!quiet){ - if(rc == MOSQ_ERR_ERRNO){ -#ifndef WIN32 - strerror_r(errno, err, 1024); -#else - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL); -#endif - fprintf(stderr, "Error: %s\n", err); - }else{ - fprintf(stderr, "Unable to connect (%d).\n", rc); - } - } - mosquitto_lib_cleanup(); - return rc; + if(client_opts_set(mosq, &cfg)){ + return 1; } + rc = client_connect(mosq, &cfg); + if(rc) return rc; if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_start(mosq); diff --git a/client/sub_client.c b/client/sub_client.c index 4dd31d8b..afdfe43b 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -28,50 +28,34 @@ Contributors: #endif #include - -/* This struct is used to pass data to callbacks. - * An instance "ud" is created in main() and populated, then passed to - * mosquitto_new(). */ -struct userdata { - char **topics; - int topic_count; - int topic_qos; - char **filter_outs; - int filter_out_count; - char *username; - char *password; - int verbose; - bool quiet; - bool no_retain; - bool eol; -}; +#include "client_shared.h" void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) { - struct userdata *ud; + struct mosq_config *cfg; int i; bool res; assert(obj); - ud = (struct userdata *)obj; + cfg = (struct mosq_config *)obj; - if(message->retain && ud->no_retain) return; - if(ud->filter_outs){ - for(i=0; ifilter_out_count; i++){ - mosquitto_topic_matches_sub(ud->filter_outs[i], message->topic, &res); + if(message->retain && cfg->no_retain) return; + if(cfg->filter_outs){ + for(i=0; ifilter_out_count; i++){ + mosquitto_topic_matches_sub(cfg->filter_outs[i], message->topic, &res); if(res) return; } } - if(ud->verbose){ + if(cfg->verbose){ if(message->payloadlen){ printf("%s ", message->topic); fwrite(message->payload, 1, message->payloadlen, stdout); - if(ud->eol){ + if(cfg->eol){ printf("\n"); } }else{ - if(ud->eol){ + if(cfg->eol){ printf("%s (null)\n", message->topic); } } @@ -79,7 +63,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit }else{ if(message->payloadlen){ fwrite(message->payload, 1, message->payloadlen, stdout); - if(ud->eol){ + if(cfg->eol){ printf("\n"); } fflush(stdout); @@ -90,17 +74,17 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { int i; - struct userdata *ud; + struct mosq_config *cfg; assert(obj); - ud = (struct userdata *)obj; + cfg = (struct mosq_config *)obj; if(!result){ - for(i=0; itopic_count; i++){ - mosquitto_subscribe(mosq, NULL, ud->topics[i], ud->topic_qos); + for(i=0; itopic_count; i++){ + mosquitto_subscribe(mosq, NULL, cfg->topics[i], cfg->topic_qos); } }else{ - if(result && !ud->quiet){ + if(result && !cfg->quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } } @@ -109,16 +93,16 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { int i; - struct userdata *ud; + struct mosq_config *cfg; assert(obj); - ud = (struct userdata *)obj; + cfg = (struct mosq_config *)obj; - if(!ud->quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + if(!cfg->quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; iquiet) printf(", %d", granted_qos[i]); + if(!cfg->quiet) printf(", %d", granted_qos[i]); } - if(!ud->quiet) printf("\n"); + if(!cfg->quiet) printf("\n"); } void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) @@ -198,444 +182,47 @@ void print_usage(void) int main(int argc, char *argv[]) { - char *id = NULL; - char *id_prefix = NULL; - int i; - char *host = "localhost"; - int port = 1883; - char *bind_address = NULL; - int keepalive = 60; - bool clean_session = true; - bool debug = false; + struct mosq_config cfg; struct mosquitto *mosq = NULL; int rc; - char hostname[256]; - char err[1024]; - struct userdata ud; - int len; - char *will_payload = NULL; - long will_payloadlen = 0; - int will_qos = 0; - bool will_retain = false; - char *will_topic = NULL; - - bool insecure = false; - char *cafile = NULL; - char *capath = NULL; - char *certfile = NULL; - char *keyfile = NULL; - char *tls_version = NULL; - - char *psk = NULL; - char *psk_identity = NULL; - - char *ciphers = NULL; - - bool use_srv = false; - - memset(&ud, 0, sizeof(struct userdata)); - ud.eol = true; - - for(i=1; i65535){ - fprintf(stderr, "Error: Invalid port given: %d\n", port); - print_usage(); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "-A")){ - if(i==argc-1){ - fprintf(stderr, "Error: -A argument given but no address specified.\n\n"); - print_usage(); - return 1; - }else{ - bind_address = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--disable-clean-session")){ - clean_session = false; - }else if(!strcmp(argv[i], "--cafile")){ - if(i==argc-1){ - fprintf(stderr, "Error: --cafile argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - cafile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--capath")){ - if(i==argc-1){ - fprintf(stderr, "Error: --capath argument given but no directory specified.\n\n"); - print_usage(); - return 1; - }else{ - capath = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--cert")){ - if(i==argc-1){ - fprintf(stderr, "Error: --cert argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - certfile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--ciphers")){ - if(i==argc-1){ - fprintf(stderr, "Error: --ciphers argument given but no ciphers specified.\n\n"); - print_usage(); - return 1; - }else{ - ciphers = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ - debug = true; - }else if(!strcmp(argv[i], "--help")){ - print_usage(); - return 0; - }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){ - if(i==argc-1){ - fprintf(stderr, "Error: -h argument given but no host specified.\n\n"); - print_usage(); - return 1; - }else{ - host = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--insecure")){ - insecure = true; - }else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){ - if(id_prefix){ - fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); - print_usage(); - return 1; - } - if(i==argc-1){ - fprintf(stderr, "Error: -i argument given but no id specified.\n\n"); - print_usage(); - return 1; - }else{ - id = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){ - if(id){ - fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); - print_usage(); - return 1; - } - if(i==argc-1){ - fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n"); - print_usage(); - return 1; - }else{ - id_prefix = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-k") || !strcmp(argv[i], "--keepalive")){ - if(i==argc-1){ - fprintf(stderr, "Error: -k argument given but no keepalive specified.\n\n"); - print_usage(); - return 1; - }else{ - keepalive = atoi(argv[i+1]); - if(keepalive>65535){ - fprintf(stderr, "Error: Invalid keepalive given: %d\n", keepalive); - print_usage(); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "--key")){ - if(i==argc-1){ - fprintf(stderr, "Error: --key argument given but no file specified.\n\n"); - print_usage(); - return 1; - }else{ - keyfile = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-N")){ - ud.eol = false; - }else if(!strcmp(argv[i], "--psk")){ - if(i==argc-1){ - fprintf(stderr, "Error: --psk argument given but no key specified.\n\n"); - print_usage(); - return 1; - }else{ - psk = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--psk-identity")){ - if(i==argc-1){ - fprintf(stderr, "Error: --psk-identity argument given but no identity specified.\n\n"); - print_usage(); - return 1; - }else{ - psk_identity = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){ - if(i==argc-1){ - fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n"); - print_usage(); - return 1; - }else{ - ud.topic_qos = atoi(argv[i+1]); - if(ud.topic_qos<0 || ud.topic_qos>2){ - fprintf(stderr, "Error: Invalid QoS given: %d\n", ud.topic_qos); - print_usage(); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "--quiet")){ - ud.quiet = true; - }else if(!strcmp(argv[i], "-R")){ - ud.no_retain = true; - }else if(!strcmp(argv[i], "-S")){ - use_srv = true; - }else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){ - if(i==argc-1){ - fprintf(stderr, "Error: -t argument given but no topic specified.\n\n"); - print_usage(); - return 1; - }else{ - ud.topic_count++; - ud.topics = realloc(ud.topics, ud.topic_count*sizeof(char *)); - ud.topics[ud.topic_count-1] = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-T") || !strcmp(argv[i], "--filter-out")){ - if(i==argc-1){ - fprintf(stderr, "Error: -T argument given but no topic filter specified.\n\n"); - print_usage(); - return 1; - }else{ - ud.filter_out_count++; - ud.filter_outs = realloc(ud.filter_outs, ud.filter_out_count*sizeof(char *)); - ud.filter_outs[ud.filter_out_count-1] = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--tls-version")){ - if(i==argc-1){ - fprintf(stderr, "Error: --tls-version argument given but no version specified.\n\n"); - print_usage(); - return 1; - }else{ - tls_version = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){ - if(i==argc-1){ - fprintf(stderr, "Error: -u argument given but no username specified.\n\n"); - print_usage(); - return 1; - }else{ - ud.username = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ - ud.verbose = 1; - }else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){ - if(i==argc-1){ - fprintf(stderr, "Error: -P argument given but no password specified.\n\n"); - print_usage(); - return 1; - }else{ - ud.password = argv[i+1]; - } - i++; - }else if(!strcmp(argv[i], "--will-payload")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n"); - print_usage(); - return 1; - }else{ - will_payload = argv[i+1]; - will_payloadlen = strlen(will_payload); - } - i++; - }else if(!strcmp(argv[i], "--will-qos")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n"); - print_usage(); - return 1; - }else{ - will_qos = atoi(argv[i+1]); - if(will_qos < 0 || will_qos > 2){ - fprintf(stderr, "Error: Invalid will QoS %d.\n\n", will_qos); - return 1; - } - } - i++; - }else if(!strcmp(argv[i], "--will-retain")){ - will_retain = true; - }else if(!strcmp(argv[i], "--will-topic")){ - if(i==argc-1){ - fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n"); - print_usage(); - return 1; - }else{ - will_topic = argv[i+1]; - } - i++; - }else{ - fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); - print_usage(); - return 1; - } - } - - if(clean_session == false && (id_prefix || !id)){ - if(!ud.quiet) fprintf(stderr, "Error: You must provide a client id if you are using the -c option.\n"); - return 1; - } - - if(ud.topic_count == 0){ - fprintf(stderr, "Error: You must specify a topic to subscribe to.\n"); + if(client_config_load(&cfg, CLIENT_SUB, argc, argv)){ print_usage(); return 1; } - if(will_payload && !will_topic){ - fprintf(stderr, "Error: Will payload given, but no will topic given.\n"); - print_usage(); - return 1; - } - if(will_retain && !will_topic){ - fprintf(stderr, "Error: Will retain given, but no will topic given.\n"); - print_usage(); - return 1; - } - if(ud.password && !ud.username){ - if(!ud.quiet) fprintf(stderr, "Warning: Not using password since username not set.\n"); - } - if((certfile && !keyfile) || (keyfile && !certfile)){ - fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is.\n"); - print_usage(); - return 1; - } - if((cafile || capath) && psk){ - if(!ud.quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); - return 1; - } - if(psk && !psk_identity){ - if(!ud.quiet) fprintf(stderr, "Error: --psk-identity required if --psk used.\n"); - return 1; - } mosquitto_lib_init(); - if(id_prefix){ - id = malloc(strlen(id_prefix)+10); - if(!id){ - if(!ud.quiet) fprintf(stderr, "Error: Out of memory.\n"); - mosquitto_lib_cleanup(); - return 1; - } - snprintf(id, strlen(id_prefix)+10, "%s%d", id_prefix, getpid()); - }else if(!id){ - hostname[0] = '\0'; - gethostname(hostname, 256); - hostname[255] = '\0'; - len = strlen("mosqsub/-") + 6 + strlen(hostname); - id = malloc(len); - if(!id){ - if(!ud.quiet) fprintf(stderr, "Error: Out of memory.\n"); - mosquitto_lib_cleanup(); - return 1; - } - snprintf(id, len, "mosqsub/%d-%s", getpid(), hostname); - if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH){ - /* Enforce maximum client id length of 23 characters */ - id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; - } + if(client_id_generate(&cfg, "mosqsub")){ + return 1; } - mosq = mosquitto_new(id, clean_session, &ud); + mosq = mosquitto_new(cfg.id, cfg.clean_session, &cfg); if(!mosq){ switch(errno){ case ENOMEM: - if(!ud.quiet) fprintf(stderr, "Error: Out of memory.\n"); + if(!cfg.quiet) fprintf(stderr, "Error: Out of memory.\n"); break; case EINVAL: - if(!ud.quiet) fprintf(stderr, "Error: Invalid id and/or clean_session.\n"); + if(!cfg.quiet) fprintf(stderr, "Error: Invalid id and/or clean_session.\n"); break; } mosquitto_lib_cleanup(); return 1; } - if(debug){ + if(client_opts_set(mosq, &cfg)){ + return 1; + } + if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); - } - if(will_topic && mosquitto_will_set(mosq, will_topic, will_payloadlen, will_payload, will_qos, will_retain)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting will.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(ud.username && mosquitto_username_pw_set(mosq, ud.username, ud.password)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting username and password.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if((cafile || capath) && mosquitto_tls_set(mosq, cafile, capath, certfile, keyfile, NULL)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(insecure && mosquitto_tls_insecure_set(mosq, true)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting TLS insecure option.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(psk && mosquitto_tls_psk_set(mosq, psk, psk_identity, NULL)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); - mosquitto_lib_cleanup(); - return 1; - } - if(tls_version && mosquitto_tls_opts_set(mosq, 1, tls_version, ciphers)){ - if(!ud.quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); - mosquitto_lib_cleanup(); - return 1; + mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); } mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); - if(debug){ - mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); - } - if(use_srv){ - rc = mosquitto_connect_srv(mosq, host, keepalive, bind_address); - }else{ - rc = mosquitto_connect_bind(mosq, host, port, keepalive, bind_address); - } - if(rc){ - if(!ud.quiet){ - if(rc == MOSQ_ERR_ERRNO){ -#ifndef WIN32 - strerror_r(errno, err, 1024); -#else - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL); -#endif - fprintf(stderr, "Error: %s\n", err); - }else{ - fprintf(stderr, "Unable to connect (%d).\n", rc); - } - } - mosquitto_lib_cleanup(); - return rc; - } + rc = client_connect(mosq, &cfg); + if(rc) return rc; + rc = mosquitto_loop_forever(mosq, -1, 1);