PageRenderTime 460ms CodeModel.GetById 130ms app.highlight 188ms RepoModel.GetById 134ms app.codeStats 1ms

/client/pub_client.c

https://bitbucket.org/klkucan/mosqnet
C | 696 lines | 633 code | 33 blank | 30 comment | 174 complexity | dc541952a440e9667e705a48f1de850a MD5 | raw file
  1/*
  2Copyright (c) 2009-2012 Roger Light <roger@atchoo.org>
  3All rights reserved.
  4
  5Redistribution and use in source and binary forms, with or without
  6modification, are permitted provided that the following conditions are met:
  7
  81. Redistributions of source code must retain the above copyright notice,
  9   this list of conditions and the following disclaimer.
 102. Redistributions in binary form must reproduce the above copyright
 11   notice, this list of conditions and the following disclaimer in the
 12   documentation and/or other materials provided with the distribution.
 133. Neither the name of mosquitto nor the names of its
 14   contributors may be used to endorse or promote products derived from
 15   this software without specific prior written permission.
 16
 17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 27POSSIBILITY OF SUCH DAMAGE.
 28*/
 29
 30
 31#include <errno.h>
 32#include <fcntl.h>
 33#include <stdio.h>
 34#include <stdlib.h>
 35#include <string.h>
 36#ifndef WIN32
 37#include <unistd.h>
 38#else
 39#include <process.h>
 40#include <winsock2.h>
 41#define snprintf sprintf_s
 42#endif
 43
 44#include <mosquitto.h>
 45
 46#define MSGMODE_NONE 0
 47#define MSGMODE_CMD 1
 48#define MSGMODE_STDIN_LINE 2
 49#define MSGMODE_STDIN_FILE 3
 50#define MSGMODE_FILE 4
 51#define MSGMODE_NULL 5
 52
 53#define STATUS_CONNECTING 0
 54#define STATUS_CONNACK_RECVD 1
 55
 56/* Global variables for use in callbacks. See sub_client.c for an example of
 57 * using a struct to hold variables for use in callbacks. */
 58static char *topic = NULL;
 59static char *message = NULL;
 60static long msglen = 0;
 61static int qos = 0;
 62static int retain = 0;
 63static int mode = MSGMODE_NONE;
 64static int status = STATUS_CONNECTING;
 65static int mid_sent = 0;
 66static bool connected = true;
 67static char *username = NULL;
 68static char *password = NULL;
 69static bool disconnect_sent = false;
 70static bool quiet = false;
 71
 72void my_connect_callback(struct mosquitto *mosq, void *obj, int result)
 73{
 74	int rc = MOSQ_ERR_SUCCESS;
 75
 76	if(!result){
 77		switch(mode){
 78			case MSGMODE_CMD:
 79			case MSGMODE_FILE:
 80			case MSGMODE_STDIN_FILE:
 81				rc = mosquitto_publish(mosq, &mid_sent, topic, msglen, message, qos, retain);
 82				break;
 83			case MSGMODE_NULL:
 84				rc = mosquitto_publish(mosq, &mid_sent, topic, 0, NULL, qos, retain);
 85				break;
 86			case MSGMODE_STDIN_LINE:
 87				status = STATUS_CONNACK_RECVD;
 88				break;
 89		}
 90		if(rc){
 91			if(!quiet){
 92				switch(rc){
 93					case MOSQ_ERR_INVAL:
 94						fprintf(stderr, "Error: Invalid input. Does your topic contain '+' or '#'?\n");
 95						break;
 96					case MOSQ_ERR_NOMEM:
 97						fprintf(stderr, "Error: Out of memory when trying to publish message.\n");
 98						break;
 99					case MOSQ_ERR_NO_CONN:
100						fprintf(stderr, "Error: Client not connected when trying to publish.\n");
101						break;
102					case MOSQ_ERR_PROTOCOL:
103						fprintf(stderr, "Error: Protocol error when communicating with broker.\n");
104						break;
105					case MOSQ_ERR_PAYLOAD_SIZE:
106						fprintf(stderr, "Error: Message payload is too large.\n");
107						break;
108				}
109			}
110			mosquitto_disconnect(mosq);
111		}
112	}else{
113		if(result && !quiet){
114			fprintf(stderr, "%s\n", mosquitto_connack_string(result));
115		}
116	}
117}
118
119void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
120{
121	connected = false;
122}
123
124void my_publish_callback(struct mosquitto *mosq, void *obj, int mid)
125{
126	if(mode != MSGMODE_STDIN_LINE && disconnect_sent == false){
127		mosquitto_disconnect(mosq);
128		disconnect_sent = true;
129	}
130}
131
132void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
133{
134	printf("%s\n", str);
135}
136
137int load_stdin(void)
138{
139	long pos = 0, rlen;
140	char buf[1024];
141
142	mode = MSGMODE_STDIN_FILE;
143
144	while(!feof(stdin)){
145		rlen = fread(buf, 1, 1024, stdin);
146		message = realloc(message, pos+rlen);
147		if(!message){
148			if(!quiet) fprintf(stderr, "Error: Out of memory.\n");
149			return 1;
150		}
151		memcpy(&(message[pos]), buf, rlen);
152		pos += rlen;
153	}
154	msglen = pos;
155
156	if(!msglen){
157		if(!quiet) fprintf(stderr, "Error: Zero length input.\n");
158		return 1;
159	}
160
161	return 0;
162}
163
164int load_file(const char *filename)
165{
166	long pos, rlen;
167	FILE *fptr = NULL;
168
169	fptr = fopen(filename, "rb");
170	if(!fptr){
171		if(!quiet) fprintf(stderr, "Error: Unable to open file \"%s\".\n", filename);
172		return 1;
173	}
174	mode = MSGMODE_FILE;
175	fseek(fptr, 0, SEEK_END);
176	msglen = ftell(fptr);
177	if(msglen > 268435455){
178		fclose(fptr);
179		if(!quiet) fprintf(stderr, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename);
180		return 1;
181	}
182	if(msglen == 0){
183		fclose(fptr);
184		if(!quiet) fprintf(stderr, "Error: File \"%s\" is empty.\n", filename);
185		return 1;
186	}
187	fseek(fptr, 0, SEEK_SET);
188	message = malloc(msglen);
189	if(!message){
190		fclose(fptr);
191		if(!quiet) fprintf(stderr, "Error: Out of memory.\n");
192		return 1;
193	}
194	pos = 0;
195	while(pos < msglen){
196		rlen = fread(&(message[pos]), sizeof(char), msglen-pos, fptr);
197		pos += rlen;
198	}
199	fclose(fptr);
200	return 0;
201}
202
203void print_usage(void)
204{
205	printf("mosquitto_pub is a simple mqtt client that will publish a message on a single topic and exit.\n\n");
206	printf("Usage: mosquitto_pub [-h host] [-p port] [-q qos] [-r] {-f file | -l | -n | -m message} -t topic\n");
207	printf("                     [-i id] [-I id_prefix]\n");
208	printf("                     [-d] [--quiet]\n");
209	printf("                     [-u username [-P password]]\n");
210	printf("                     [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n");
211#ifdef WITH_TLS
212	printf("                     [{--cafile file | --capath dir} [--cert file] [--key file]]\n");
213#ifdef WITH_TLS_PSK
214	printf("                     [--psk hex-key --psk-identity identity]\n");
215#endif
216#endif
217	printf("       mosquitto_pub --help\n\n");
218	printf(" -d : enable debug messages.\n");
219	printf(" -f : send the contents of a file as the message.\n");
220	printf(" -h : mqtt host to connect to. Defaults to localhost.\n");
221	printf(" -i : id to use for this client. Defaults to mosquitto_pub_ appended with the process id.\n");
222	printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n");
223	printf("      broker is using the clientid_prefixes option.\n");
224	printf(" -l : read messages from stdin, sending a separate message for each line.\n");
225	printf(" -m : message payload to send.\n");
226	printf(" -n : send a null (zero length) message.\n");
227	printf(" -p : network port to connect to. Defaults to 1883.\n");
228	printf(" -q : quality of service level to use for all messages. Defaults to 0.\n");
229	printf(" -r : message should be retained.\n");
230	printf(" -s : read message from stdin, sending the entire input as a message.\n");
231	printf(" -t : mqtt topic to publish to.\n");
232	printf(" -u : provide a username (requires MQTT 3.1 broker)\n");
233	printf(" -P : provide a password (requires MQTT 3.1 broker)\n");
234	printf(" --help : display this message.\n");
235	printf(" --quiet : don't print error messages.\n");
236	printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n");
237	printf("                  unexpected disconnection. If not given and will-topic is set, a zero\n");
238	printf("                  length message will be sent.\n");
239	printf(" --will-qos : QoS level for the client Will.\n");
240	printf(" --will-retain : if given, make the client Will retained.\n");
241	printf(" --will-topic : the topic on which to publish the client Will.\n");
242#ifdef WITH_TLS
243	printf(" --cafile : path to a file containing trusted CA certificates to enable encrypted\n");
244	printf("            communication.\n");
245	printf(" --capath : path to a directory containing trusted CA certificates to enable encrypted\n");
246	printf("            communication.\n");
247	printf(" --cert : client certificate for authentication, if required by server.\n");
248	printf(" --key : client private key for authentication, if required by server.\n");
249#ifdef WITH_TLS_PSK
250	printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n");
251	printf(" --psk-identity : client identity string for TLS-PSK mode.\n");
252#endif
253#endif
254	printf("\nSee http://mosquitto.org/ for more information.\n\n");
255}
256
257int main(int argc, char *argv[])
258{
259	char *id = NULL;
260	char *id_prefix = NULL;
261	int i;
262	char *host = "localhost";
263	int port = 1883;
264	int keepalive = 60;
265#ifndef WIN32
266	int opt;
267#endif
268	char buf[1024];
269	bool debug = false;
270	struct mosquitto *mosq = NULL;
271	int rc;
272	int rc2;
273	char hostname[256];
274	char err[1024];
275	int len;
276
277	char *will_payload = NULL;
278	long will_payloadlen = 0;
279	int will_qos = 0;
280	bool will_retain = false;
281	char *will_topic = NULL;
282
283	char *cafile = NULL;
284	char *capath = NULL;
285	char *certfile = NULL;
286	char *keyfile = NULL;
287
288	char *psk = NULL;
289	char *psk_identity = NULL;
290
291	for(i=1; i<argc; i++){
292		if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){
293			if(i==argc-1){
294				fprintf(stderr, "Error: -p argument given but no port specified.\n\n");
295				print_usage();
296				return 1;
297			}else{
298				port = atoi(argv[i+1]);
299				if(port<1 || port>65535){
300					fprintf(stderr, "Error: Invalid port given: %d\n", port);
301					print_usage();
302					return 1;
303				}
304			}
305			i++;
306		}else if(!strcmp(argv[i], "--cafile")){
307			if(i==argc-1){
308				fprintf(stderr, "Error: --cafile argument given but no file specified.\n\n");
309				print_usage();
310				return 1;
311			}else{
312				cafile = argv[i+1];
313			}
314			i++;
315		}else if(!strcmp(argv[i], "--capath")){
316			if(i==argc-1){
317				fprintf(stderr, "Error: --capath argument given but no directory specified.\n\n");
318				print_usage();
319				return 1;
320			}else{
321				capath = argv[i+1];
322			}
323			i++;
324		}else if(!strcmp(argv[i], "--cert")){
325			if(i==argc-1){
326				fprintf(stderr, "Error: --cert argument given but no file specified.\n\n");
327				print_usage();
328				return 1;
329			}else{
330				certfile = argv[i+1];
331			}
332			i++;
333		}else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){
334			debug = true;
335		}else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){
336			if(mode != MSGMODE_NONE){
337				fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");
338				print_usage();
339				return 1;
340			}else if(i==argc-1){
341				fprintf(stderr, "Error: -f argument given but no file specified.\n\n");
342				print_usage();
343				return 1;
344			}else{
345				if(load_file(argv[i+1])) return 1;
346			}
347			i++;
348		}else if(!strcmp(argv[i], "--help")){
349			print_usage();
350			return 0;
351		}else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){
352			if(i==argc-1){
353				fprintf(stderr, "Error: -h argument given but no host specified.\n\n");
354				print_usage();
355				return 1;
356			}else{
357				host = argv[i+1];
358			}
359			i++;
360		}else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){
361			if(id_prefix){
362				fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n");
363				print_usage();
364				return 1;
365			}
366			if(i==argc-1){
367				fprintf(stderr, "Error: -i argument given but no id specified.\n\n");
368				print_usage();
369				return 1;
370			}else{
371				id = argv[i+1];
372			}
373			i++;
374		}else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){
375			if(id){
376				fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n");
377				print_usage();
378				return 1;
379			}
380			if(i==argc-1){
381				fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n");
382				print_usage();
383				return 1;
384			}else{
385				id_prefix = argv[i+1];
386			}
387			i++;
388		}else if(!strcmp(argv[i], "--key")){
389			if(i==argc-1){
390				fprintf(stderr, "Error: --key argument given but no file specified.\n\n");
391				print_usage();
392				return 1;
393			}else{
394				keyfile = argv[i+1];
395			}
396			i++;
397		}else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){
398			if(mode != MSGMODE_NONE){
399				fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");
400				print_usage();
401				return 1;
402			}else{
403				mode = MSGMODE_STDIN_LINE;
404#ifndef WIN32
405				opt = fcntl(fileno(stdin), F_GETFL, 0);
406				if(opt == -1 || fcntl(fileno(stdin), F_SETFL, opt | O_NONBLOCK) == -1){
407					fprintf(stderr, "Error: Unable to set stdin to non-blocking.\n");
408					return 1;
409				}
410#endif
411			}
412		}else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--message")){
413			if(mode != MSGMODE_NONE){
414				fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");
415				print_usage();
416				return 1;
417			}else if(i==argc-1){
418				fprintf(stderr, "Error: -m argument given but no message specified.\n\n");
419				print_usage();
420				return 1;
421			}else{
422				message = argv[i+1];
423				msglen = strlen(message);
424				mode = MSGMODE_CMD;
425			}
426			i++;
427		}else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--null-message")){
428			if(mode != MSGMODE_NONE){
429				fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");
430				print_usage();
431				return 1;
432			}else{
433				mode = MSGMODE_NULL;
434			}
435		}else if(!strcmp(argv[i], "--psk")){
436			if(i==argc-1){
437				fprintf(stderr, "Error: --psk argument given but no key specified.\n\n");
438				print_usage();
439				return 1;
440			}else{
441				psk = argv[i+1];
442			}
443			i++;
444		}else if(!strcmp(argv[i], "--psk-identity")){
445			if(i==argc-1){
446				fprintf(stderr, "Error: --psk-identity argument given but no identity specified.\n\n");
447				print_usage();
448				return 1;
449			}else{
450				psk_identity = argv[i+1];
451			}
452			i++;
453		}else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){
454			if(i==argc-1){
455				fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n");
456				print_usage();
457				return 1;
458			}else{
459				qos = atoi(argv[i+1]);
460				if(qos<0 || qos>2){
461					fprintf(stderr, "Error: Invalid QoS given: %d\n", qos);
462					print_usage();
463					return 1;
464				}
465			}
466			i++;
467		}else if(!strcmp(argv[i], "--quiet")){
468			quiet = true;
469		}else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--retain")){
470			retain = 1;
471		}else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){
472			if(mode != MSGMODE_NONE){
473				fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");
474				print_usage();
475				return 1;
476			}else{
477				if(load_stdin()) return 1;
478			}
479		}else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){
480			if(i==argc-1){
481				fprintf(stderr, "Error: -t argument given but no topic specified.\n\n");
482				print_usage();
483				return 1;
484			}else{
485				topic = argv[i+1];
486			}
487			i++;
488		}else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){
489			if(i==argc-1){
490				fprintf(stderr, "Error: -u argument given but no username specified.\n\n");
491				print_usage();
492				return 1;
493			}else{
494				username = argv[i+1];
495			}
496			i++;
497		}else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){
498			if(i==argc-1){
499				fprintf(stderr, "Error: -P argument given but no password specified.\n\n");
500				print_usage();
501				return 1;
502			}else{
503				password = argv[i+1];
504			}
505			i++;
506		}else if(!strcmp(argv[i], "--will-payload")){
507			if(i==argc-1){
508				fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n");
509				print_usage();
510				return 1;
511			}else{
512				will_payload = argv[i+1];
513				will_payloadlen = strlen(will_payload);
514			}
515			i++;
516		}else if(!strcmp(argv[i], "--will-qos")){
517			if(i==argc-1){
518				fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n");
519				print_usage();
520				return 1;
521			}else{
522				will_qos = atoi(argv[i+1]);
523				if(will_qos < 0 || will_qos > 2){
524					fprintf(stderr, "Error: Invalid will QoS %d.\n\n", will_qos);
525					return 1;
526				}
527			}
528			i++;
529		}else if(!strcmp(argv[i], "--will-retain")){
530			will_retain = true;
531		}else if(!strcmp(argv[i], "--will-topic")){
532			if(i==argc-1){
533				fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n");
534				print_usage();
535				return 1;
536			}else{
537				will_topic = argv[i+1];
538			}
539			i++;
540		}else{
541			fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]);
542			print_usage();
543			return 1;
544		}
545	}
546
547	if(!topic || mode == MSGMODE_NONE){
548		fprintf(stderr, "Error: Both topic and message must be supplied.\n");
549		print_usage();
550		return 1;
551	}
552
553	if(will_payload && !will_topic){
554		fprintf(stderr, "Error: Will payload given, but no will topic given.\n");
555		print_usage();
556		return 1;
557	}
558	if(will_retain && !will_topic){
559		fprintf(stderr, "Error: Will retain given, but no will topic given.\n");
560		print_usage();
561		return 1;
562	}
563	if(password && !username){
564		if(!quiet) fprintf(stderr, "Warning: Not using password since username not set.\n");
565	}
566	if((certfile && !keyfile) || (keyfile && !certfile)){
567		fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is.\n");
568		print_usage();
569		return 1;
570	}
571	if((cafile || capath) && psk){
572		if(!quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n");
573		return 1;
574	}
575	if(psk && !psk_identity){
576		if(!quiet) fprintf(stderr, "Error: --psk-identity required if --psk used.\n");
577		return 1;
578	}
579
580	mosquitto_lib_init();
581
582	if(id_prefix){
583		id = malloc(strlen(id_prefix)+10);
584		if(!id){
585			if(!quiet) fprintf(stderr, "Error: Out of memory.\n");
586			mosquitto_lib_cleanup();
587			return 1;
588		}
589		snprintf(id, strlen(id_prefix)+10, "%s%d", id_prefix, getpid());
590	}else if(!id){
591		hostname[0] = '\0';
592		gethostname(hostname, 256);
593		hostname[255] = '\0';
594		len = strlen("mosqpub/-") + 6 + strlen(hostname);
595		id = malloc(len);
596		if(!id){
597			if(!quiet) fprintf(stderr, "Error: Out of memory.\n");
598			mosquitto_lib_cleanup();
599			return 1;
600		}
601		snprintf(id, len, "mosqpub/%d-%s", getpid(), hostname);
602		id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0';
603		snprintf(id, MOSQ_MQTT_ID_MAX_LENGTH, "mosqpub/%d-%s", getpid(), hostname);
604		id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0';
605	}
606
607	mosq = mosquitto_new(id, true, NULL);
608	if(!mosq){
609		switch(errno){
610			case ENOMEM:
611				if(!quiet) fprintf(stderr, "Error: Out of memory.\n");
612				break;
613			case EINVAL:
614				if(!quiet) fprintf(stderr, "Error: Invalid id.\n");
615				break;
616		}
617		mosquitto_lib_cleanup();
618		return 1;
619	}
620	if(debug){
621		mosquitto_log_callback_set(mosq, my_log_callback);
622	}
623	if(will_topic && mosquitto_will_set(mosq, will_topic, will_payloadlen, will_payload, will_qos, will_retain)){
624		if(!quiet) fprintf(stderr, "Error: Problem setting will.\n");
625		mosquitto_lib_cleanup();
626		return 1;
627	}
628	if(username && mosquitto_username_pw_set(mosq, username, password)){
629		if(!quiet) fprintf(stderr, "Error: Problem setting username and password.\n");
630		mosquitto_lib_cleanup();
631		return 1;
632	}
633	if((cafile || capath) && mosquitto_tls_set(mosq, cafile, capath, certfile, keyfile, NULL)){
634		if(!quiet) fprintf(stderr, "Error: Problem setting TLS options.\n");
635		mosquitto_lib_cleanup();
636		return 1;
637	}
638	if(psk && mosquitto_tls_psk_set(mosq, psk, psk_identity, NULL)){
639		if(!quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n");
640		mosquitto_lib_cleanup();
641		return 1;
642	}
643	mosquitto_connect_callback_set(mosq, my_connect_callback);
644	mosquitto_disconnect_callback_set(mosq, my_disconnect_callback);
645	mosquitto_publish_callback_set(mosq, my_publish_callback);
646
647	rc = mosquitto_connect(mosq, host, port, keepalive);
648	if(rc){
649		if(!quiet){
650			if(rc == MOSQ_ERR_ERRNO){
651#ifndef WIN32
652				strerror_r(errno, err, 1024);
653#else
654				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL);
655#endif
656				fprintf(stderr, "Error: %s\n", err);
657			}else{
658				fprintf(stderr, "Unable to connect (%d).\n", rc);
659			}
660		}
661		mosquitto_lib_cleanup();
662		return rc;
663	}
664
665	do{
666		if(mode == MSGMODE_STDIN_LINE && status == STATUS_CONNACK_RECVD){
667			if(fgets(buf, 1024, stdin)){
668				buf[strlen(buf)-1] = '\0';
669				rc2 = mosquitto_publish(mosq, &mid_sent, topic, strlen(buf), buf, qos, retain);
670				if(rc2){
671					if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2);
672					mosquitto_disconnect(mosq);
673				}
674			}else if(feof(stdin) && disconnect_sent == false){
675				mosquitto_disconnect(mosq);
676				disconnect_sent = true;
677			}
678		}
679		rc = mosquitto_loop(mosq, -1, 1);
680	}while(rc == MOSQ_ERR_SUCCESS && connected);
681
682	if(message && mode == MSGMODE_FILE){
683		free(message);
684	}
685	mosquitto_destroy(mosq);
686	mosquitto_lib_cleanup();
687
688	if(rc){
689		if(rc == MOSQ_ERR_ERRNO){
690			fprintf(stderr, "Error: %s\n", strerror(errno));
691		}else{
692			fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc));
693		}
694	}
695	return rc;
696}