/* Copyright (c) 2009-2020 Roger Light Copyright (c) 2013-2019 V.Krishn 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. V Krishn - implement dirpub. */ #include "config.h" #include #include #include #include #include #include #ifndef WIN32 #include #include #else #include #include #define snprintf sprintf_s #endif #include #include #include "client_shared.h" struct mosq_config cfg; bool process_messages = true; int msg_count = 0; struct mosquitto *mosq = NULL; int last_mid = 0; #ifndef WIN32 void my_signal_handler(int signum) { if(signum == SIGALRM || signum == SIGTERM || signum == SIGINT){ process_messages = false; mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); } } #endif void print_message(struct mosq_config *cfg, const struct mosquitto_message *message); void print_message_file(struct mosq_config *cfg, const struct mosquitto_message *message); void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { UNUSED(obj); UNUSED(reason_code); UNUSED(properties); if(process_messages == false && (mid == last_mid || last_mid == 0)){ mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } } void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) { int i; bool res; UNUSED(obj); UNUSED(properties); if(process_messages == false) return; if(cfg.remove_retained && message->retain){ mosquitto_publish(mosq, &last_mid, message->topic, 0, NULL, 1, true); } if(cfg.retained_only && !message->retain && process_messages){ process_messages = false; if(last_mid == 0){ mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } return; } if(message->retain && cfg.no_retain) return; if(cfg.filter_outs){ for(i=0; itopic, &res); if(res) return; } } if(cfg.remove_retained && message->retain){ mosquitto_publish(mosq, &last_mid, message->topic, 0, NULL, 1, true); } if(cfg.fmask){ print_message_file(&cfg, message); }else{ print_message(&cfg, message); } if(cfg.msg_count>0){ msg_count++; if(cfg.msg_count == msg_count){ process_messages = false; if(last_mid == 0){ mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } } } } void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) { int i; UNUSED(obj); UNUSED(flags); UNUSED(properties); if(!result){ mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.sub_opts, cfg.subscribe_props); for(i=0; i with empty --fmask "" \n"); printf(" --nodesuffix : suffix for leaf/text node, when --fmask is provided\n"); printf(" --overwrite : overwrite the existing output file, can be used with --fmask only.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); printf(" --will-qos : QoS level for the client Will.\n"); printf(" --will-retain : if given, make the client Will retained.\n"); printf(" --will-topic : the topic on which to publish the client Will.\n"); #ifdef WITH_TLS printf(" --cafile : path to a file containing trusted CA certificates to enable encrypted\n"); printf(" certificate based communication.\n"); printf(" --capath : path to a directory containing trusted CA certificates to enable encrypted\n"); printf(" communication.\n"); printf(" --cert : client certificate for authentication, if required by server.\n"); printf(" --key : client private key for authentication, if required by server.\n"); printf(" --keyform : keyfile type, can be either \"pem\" or \"engine\".\n"); printf(" --ciphers : openssl compatible list of TLS ciphers to support.\n"); printf(" --tls-version : TLS protocol version, can be one of tlsv1.3 tlsv1.2 or tlsv1.1.\n"); printf(" Defaults to tlsv1.2 if available.\n"); printf(" --insecure : do not check that the server certificate hostname matches the remote\n"); printf(" hostname. Using this option means that you cannot be sure that the\n"); printf(" remote host is the server you wish to connect to and so is insecure.\n"); printf(" Do not use this option in a production environment.\n"); printf(" --tls-engine : If set, enables the use of a SSL engine device.\n"); printf(" --tls-engine-kpass-sha1 : SHA1 of the key password to be used with the selected SSL engine.\n"); #ifdef FINAL_WITH_TLS_PSK printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n"); printf(" --psk-identity : client identity string for TLS-PSK mode.\n"); #endif #endif #ifdef WITH_SOCKS printf(" --proxy : SOCKS5 proxy URL of the form:\n"); printf(" socks5h://[username[:password]@]hostname[:port]\n"); printf(" Only \"none\" and \"username\" authentication is supported.\n"); #endif printf("\nSee https://mosquitto.org/ for more information.\n\n"); } int main(int argc, char *argv[]) { int rc; #ifndef WIN32 struct sigaction sigact; #endif mosquitto_lib_init(); rc = client_config_load(&cfg, CLIENT_SUB, argc, argv); if(rc){ if(rc == 2){ /* --help */ print_usage(); }else{ fprintf(stderr, "\nUse 'mosquitto_sub --help' to see usage.\n"); } goto cleanup; } if(cfg.no_retain && cfg.retained_only){ fprintf(stderr, "\nError: Combining '-R' and '--retained-only' makes no sense.\n"); goto cleanup; } if(client_id_generate(&cfg)){ goto cleanup; } mosq = mosquitto_new(cfg.id, cfg.clean_session, &cfg); cfg.idtext = cfg.id; if(!mosq){ switch(errno){ case ENOMEM: err_printf(&cfg, "Error: Out of memory.\n"); break; case EINVAL: err_printf(&cfg, "Error: Invalid id and/or clean_session.\n"); break; } goto cleanup; } if(client_opts_set(mosq, &cfg)){ goto cleanup; } if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); } mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); mosquitto_connect_v5_callback_set(mosq, my_connect_callback); mosquitto_message_v5_callback_set(mosq, my_message_callback); rc = client_connect(mosq, &cfg); if(rc){ goto cleanup; } #ifndef WIN32 sigact.sa_handler = my_signal_handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; if(sigaction(SIGALRM, &sigact, NULL) == -1){ perror("sigaction"); goto cleanup; } if(sigaction(SIGTERM, &sigact, NULL) == -1){ perror("sigaction"); goto cleanup; } if(sigaction(SIGINT, &sigact, NULL) == -1){ perror("sigaction"); goto cleanup; } if(cfg.timeout){ alarm(cfg.timeout); } #endif rc = mosquitto_loop_forever(mosq, -1, 1); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); if(cfg.msg_count>0 && rc == MOSQ_ERR_NO_CONN){ rc = 0; } client_config_cleanup(&cfg); if(rc){ err_printf(&cfg, "Error: %s\n", mosquitto_strerror(rc)); } return rc; cleanup: mosquitto_destroy(mosq); mosquitto_lib_cleanup(); client_config_cleanup(&cfg); return 1; }