New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: conf.c |
| | | * Description: This file is mqttd configure file parser function |
| | | * |
| | | * Version: 1.0.0(2019年06月25日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年06月25日 22时23分55秒" |
| | | * |
| | | ********************************************************************************/ |
| | | #include "conf.h" |
| | | #include "lylib/logger.h" |
| | | #include "lylib/iniparser.h" |
| | | |
| | | |
| | | int mqttd_parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug) |
| | | { |
| | | dictionary *ini; |
| | | char *str; |
| | | int val; |
| | | |
| | | memset(ctx, 0, sizeof(*ctx)); |
| | | |
| | | if( !conf_file ) |
| | | { |
| | | |
| | | /* logger settings */ |
| | | strncpy(ctx->logfile, DBG_LOG_FILE, sizeof(ctx->logfile)); |
| | | ctx->loglevel = LOG_LEVEL_DEBUG; |
| | | ctx->logsize = 1024; |
| | | |
| | | if( logger_init(ctx->logfile, ctx->loglevel, ctx->logsize) < 0 ) |
| | | { |
| | | fprintf(stderr, "Logger system initialise failure\n"); |
| | | return -2; |
| | | } |
| | | log_nrml("Logger system initialise ok\n"); |
| | | log_warn("WARNNING: Use default MQTT configure\n"); |
| | | |
| | | /* Broker settings */ |
| | | strncpy(ctx->host, DEF_BORKER_HOSTNAME, sizeof(ctx->host)); |
| | | ctx->port = DEF_BROKER_PORT; |
| | | log_nrml("Use default broker server [%s:%d]\n", ctx->host, ctx->port); |
| | | |
| | | strncpy(ctx->uid, DEF_BROKER_USERNAME, sizeof(ctx->uid)); |
| | | strncpy(ctx->pwd, DEF_BROKER_PASSWD, sizeof(ctx->pwd)); |
| | | log_nrml("Use default broker author by [%s:%s]\n", ctx->uid, ctx->pwd); |
| | | |
| | | ctx->keepalive = DEF_BROKER_KEEPALIVE; |
| | | log_nrml("Use default broker keepalive timeout [%d] seconds\n", ctx->keepalive); |
| | | |
| | | /* Subscriber settings */ |
| | | strncpy(ctx->subTopic, DEF_SUBTOPIC, sizeof(ctx->subTopic)); |
| | | ctx->subQos = DEF_SUBQOS; |
| | | log_nrml("Use default subscriber topic \"%s\" with Qos[%d]\n", ctx->subTopic, ctx->subQos); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | ini = iniparser_load(conf_file); |
| | | if( !ini ) |
| | | { |
| | | fprintf(stderr, "ERROR: cannot parse file: '%s'\n", conf_file); |
| | | return -1; |
| | | } |
| | | |
| | | /*+------------------------------------------------------+ |
| | | *| parser logger settings and start logger system | |
| | | *+------------------------------------------------------+*/ |
| | | if( !debug ) |
| | | { |
| | | str = iniparser_getstring(ini, "logger:file", "/tmp/mqttd.log"); |
| | | strncpy(ctx->logfile, str, sizeof(ctx->logfile)); |
| | | ctx->logsize = iniparser_getint(ini, "logger:size", 1024); |
| | | ctx->loglevel = iniparser_getint(ini, "logger:level", LOG_LEVEL_DEBUG); |
| | | } |
| | | else |
| | | { |
| | | strncpy(ctx->logfile, DBG_LOG_FILE, sizeof(ctx->logfile)); |
| | | ctx->loglevel = LOG_LEVEL_DEBUG; |
| | | ctx->logsize = 1024; |
| | | } |
| | | |
| | | if( logger_init(ctx->logfile, ctx->loglevel, ctx->logsize) < 0 ) |
| | | { |
| | | fprintf(stderr, "Logger system initialise failure\n"); |
| | | return -2; |
| | | } |
| | | |
| | | log_nrml("Logger system initialise ok\n"); |
| | | |
| | | |
| | | |
| | | /*+------------------------------------------------------+ |
| | | *| parser broker settings | |
| | | *+------------------------------------------------------+*/ |
| | | |
| | | if( !(str=iniparser_getstring(ini, "broker:hostname", NULL)) ) |
| | | { |
| | | log_err("ERROR: Parser broker server hostname failure\n"); |
| | | return -2; |
| | | } |
| | | strncpy(ctx->host, str, sizeof(ctx->host) ); |
| | | |
| | | if( (val=iniparser_getint(ini, "broker:port", -1)) < 0 ) |
| | | { |
| | | log_err("ERROR: Parser broker server port failure\n"); |
| | | return -2; |
| | | } |
| | | ctx->port = val; |
| | | log_nrml("Parser broker server [%s:%d]\n", ctx->host, ctx->port); |
| | | |
| | | str=iniparser_getstring(ini, "broker:username", DEF_BROKER_USERNAME); |
| | | strncpy(ctx->uid, str, sizeof(ctx->uid) ); |
| | | |
| | | str=iniparser_getstring(ini, "broker:password", DEF_BROKER_PASSWD); |
| | | strncpy(ctx->pwd, str, sizeof(ctx->pwd) ); |
| | | |
| | | log_nrml("Parser broker author by [%s:%s]\n", ctx->uid, ctx->pwd); |
| | | |
| | | ctx->keepalive = iniparser_getint(ini, "broker:keepalive", DEF_BROKER_KEEPALIVE); |
| | | log_nrml("Parser broker keepalive timeout [%d] seconds\n", ctx->keepalive); |
| | | |
| | | /*+------------------------------------------------------+ |
| | | *| parser subscriber settings | |
| | | *+------------------------------------------------------+*/ |
| | | |
| | | str=iniparser_getstring(ini, "subsciber:subTopic", DEF_SUBTOPIC); |
| | | strncpy(ctx->subTopic, str, sizeof(ctx->subTopic) ); |
| | | |
| | | ctx->subQos = iniparser_getint(ini, "subsciber:subQos", DEF_SUBQOS); |
| | | log_nrml("Parser subscriber topic \"%s\" with Qos[%d]\n", ctx->subTopic, ctx->subQos); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: conf.h |
| | | * Description: This file is mqttd configure file parser function |
| | | * |
| | | * Version: 1.0.0(2019年06月25日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年06月25日 22时23分55秒" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CONF_H_ |
| | | #define __CONF_H_ |
| | | |
| | | #define DEF_BORKER_HOSTNAME "master.iot-yun.com" |
| | | #define DEF_BROKER_PORT 10883 |
| | | #define DEF_BROKER_KEEPALIVE 30 |
| | | #define DEF_BROKER_USERNAME "lingyun" |
| | | #define DEF_BROKER_PASSWD "lingyun-emb" |
| | | |
| | | |
| | | #define MQTT_SYS_TOPIC "$Sys/Studio/" |
| | | #define DEF_SUBTOPIC MQTT_SYS_TOPIC"Downlink" |
| | | |
| | | #define DEF_SUBQOS 0 |
| | | |
| | | enum |
| | | { |
| | | Qos0, /* 发送者只发送一次消息,不进行重试,Broker不会返回确认消息。在Qos0情况下,Broker可能没有接受到消息 */ |
| | | Qos1, /* 发送者最少发送一次消息,确保消息到达Broker,Broker需要返回确认消息PUBACK。在Qos1情况下,Broker可能接受到重复消息 */ |
| | | Qos2, /* Qos2使用两阶段确认来保证消息的不丢失和不重复。在Qos2情况下,Broker肯定会收到消息,且只收到一次 */ |
| | | }; |
| | | |
| | | typedef struct mqtt_ctx_s |
| | | { |
| | | /* logger settings */ |
| | | char logfile[128]; /* logger record file */ |
| | | int loglevel; /* logger level */ |
| | | int logsize; /* logger file maxsize, oversize will rollback */ |
| | | |
| | | /* Broker settings */ |
| | | char host[128]; /* MQTT broker server name */ |
| | | int port; /* MQTT broker listen port */ |
| | | char uid[64]; /* username */ |
| | | char pwd[64]; /* password */ |
| | | int keepalive; /* MQTT broker send PING message to subsciber/publisher keepalive timeout<seconds> */ |
| | | |
| | | /* Subscriber settings */ |
| | | char subTopic[256]; /* Subscriber topic */ |
| | | int subQos; /* Subscriber Qos */ |
| | | } mqtt_ctx_t; |
| | | |
| | | |
| | | extern int mqttd_parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug); |
| | | |
| | | #endif /* ----- #ifndef _CONF_H_ ----- */ |
| | | |
New file |
| | |
| | | |
| | | PWD=$(shell pwd ) |
| | | |
| | | LIBNAME=$(shell basename ${PWD} ) |
| | | PROJPATH=$(shell dirname ${PWD} ) |
| | | |
| | | CFLAGS+=-I${PROJPATH} |
| | | |
| | | all: clean |
| | | @rm -f *.o |
| | | @${CROSS_COMPILE}gcc ${CFLAGS} -c *.c |
| | | ${CROSS_COMPILE}ar -rcs lib${LIBNAME}.a *.o |
| | | |
| | | clean: |
| | | @rm -f *.o |
| | | @rm -f *.a |
| | | |
New file |
| | |
| | | |
| | | [logger] |
| | | |
| | | # 日志记录文件 |
| | | file=/tmp/mqttd.log |
| | | |
| | | # 日志级别: 0:Disable 1:Fatal 2:ERROR 3:warnning 4:Normal 5:Debug 6:Infor 7:Trace |
| | | level=4 |
| | | |
| | | # 日志回滚大小 |
| | | size=1024 |
| | | |
| | | |
| | | |
| | | [broker] |
| | | |
| | | # broker 服务器地址和端口号 |
| | | hostname="master.iot-yun.com" |
| | | port=10883 |
| | | |
| | | # broker 认证连接的用户名和密码 |
| | | username="lingyun" |
| | | password="lingyun-emb" |
| | | |
| | | # broker给subsciber和publisher发送PING报文保持 keepalive 的时间周期,单位是秒 |
| | | keepalive=30 |
| | | |
| | | |
| | | # Qos0: 发送者只发送一次消息,不进行重试,Broker不会返回确认消息。在Qos0情况下,Broker可能没有接受到消息 |
| | | # Qos1: 发送者最少发送一次消息,确保消息到达Broker,Broker需要返回确认消息PUBACK。在Qos1情况下,Broker可能接受到重复消息 |
| | | # Qos2: Qos2使用两阶段确认来保证消息的不丢失和不重复。在Qos2情况下,Broker肯定会收到消息,且只收到一次 |
| | | |
| | | [subsciber] |
| | | |
| | | subTopic="$Sys/Studio/Downlink" |
| | | subQos=0 |
| | | |
| | | |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009 Dave Gamble |
| | | |
| | | Permission is hereby granted, free of charge, to any person obtaining a copy |
| | | of this software and associated documentation files (the "Software"), to deal |
| | | in the Software without restriction, including without limitation the rights |
| | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| | | copies of the Software, and to permit persons to whom the Software is |
| | | furnished to do so, subject to the following conditions: |
| | | |
| | | The above copyright notice and this permission notice shall be included in |
| | | all copies or substantial portions of the Software. |
| | | |
| | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| | | THE SOFTWARE. |
| | | */ |
| | | |
| | | /* cJSON */ |
| | | /* JSON parser in C. */ |
| | | |
| | | #include <string.h> |
| | | #include <stdio.h> |
| | | #include <math.h> |
| | | #include <stdlib.h> |
| | | #include <float.h> |
| | | #include <limits.h> |
| | | #include <ctype.h> |
| | | #include "cJSON.h" |
| | | |
| | | static const char *ep; |
| | | |
| | | const char *cJSON_GetErrorPtr(void) {return ep;} |
| | | |
| | | static int cJSON_strcasecmp(const char *s1,const char *s2) |
| | | { |
| | | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; |
| | | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; |
| | | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); |
| | | } |
| | | |
| | | static void *(*cJSON_malloc)(size_t sz) = malloc; |
| | | static void (*cJSON_free)(void *ptr) = free; |
| | | |
| | | static char* cJSON_strdup(const char* str) |
| | | { |
| | | size_t len; |
| | | char* copy; |
| | | |
| | | len = strlen(str) + 1; |
| | | if (!(copy = (char*)cJSON_malloc(len))) return 0; |
| | | memcpy(copy,str,len); |
| | | return copy; |
| | | } |
| | | |
| | | void cJSON_InitHooks(cJSON_Hooks* hooks) |
| | | { |
| | | if (!hooks) { /* Reset hooks */ |
| | | cJSON_malloc = malloc; |
| | | cJSON_free = free; |
| | | return; |
| | | } |
| | | |
| | | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; |
| | | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; |
| | | } |
| | | |
| | | /* Internal constructor. */ |
| | | static cJSON *cJSON_New_Item(void) |
| | | { |
| | | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); |
| | | if (node) memset(node,0,sizeof(cJSON)); |
| | | return node; |
| | | } |
| | | |
| | | /* Delete a cJSON structure. */ |
| | | void cJSON_Delete(cJSON *c) |
| | | { |
| | | cJSON *next; |
| | | while (c) |
| | | { |
| | | next=c->next; |
| | | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); |
| | | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); |
| | | if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); |
| | | cJSON_free(c); |
| | | c=next; |
| | | } |
| | | } |
| | | |
| | | /* Parse the input text to generate a number, and populate the result into item. */ |
| | | static const char *parse_number(cJSON *item,const char *num) |
| | | { |
| | | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; |
| | | |
| | | if (*num=='-') sign=-1,num++; /* Has sign? */ |
| | | if (*num=='0') num++; /* is zero */ |
| | | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ |
| | | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ |
| | | if (*num=='e' || *num=='E') /* Exponent? */ |
| | | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ |
| | | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ |
| | | } |
| | | |
| | | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ |
| | | |
| | | item->valuedouble=n; |
| | | item->valueint=(int)n; |
| | | item->type=cJSON_Number; |
| | | return num; |
| | | } |
| | | |
| | | static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } |
| | | |
| | | typedef struct {char *buffer; int length; int offset; } printbuffer; |
| | | |
| | | static char* ensure(printbuffer *p,int needed) |
| | | { |
| | | char *newbuffer;int newsize; |
| | | if (!p || !p->buffer) return 0; |
| | | needed+=p->offset; |
| | | if (needed<=p->length) return p->buffer+p->offset; |
| | | |
| | | newsize=pow2gt(needed); |
| | | newbuffer=(char*)cJSON_malloc(newsize); |
| | | if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} |
| | | if (newbuffer) memcpy(newbuffer,p->buffer,p->length); |
| | | cJSON_free(p->buffer); |
| | | p->length=newsize; |
| | | p->buffer=newbuffer; |
| | | return newbuffer+p->offset; |
| | | } |
| | | |
| | | static int update(printbuffer *p) |
| | | { |
| | | char *str; |
| | | if (!p || !p->buffer) return 0; |
| | | str=p->buffer+p->offset; |
| | | return p->offset+strlen(str); |
| | | } |
| | | |
| | | /* Render the number nicely from the given item into a string. */ |
| | | static char *print_number(cJSON *item,printbuffer *p) |
| | | { |
| | | char *str=0; |
| | | double d=item->valuedouble; |
| | | if (d==0) |
| | | { |
| | | if (p) str=ensure(p,2); |
| | | else str=(char*)cJSON_malloc(2); /* special case for 0. */ |
| | | if (str) strcpy(str,"0"); |
| | | } |
| | | else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) |
| | | { |
| | | if (p) str=ensure(p,21); |
| | | else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ |
| | | if (str) sprintf(str,"%d",item->valueint); |
| | | } |
| | | else |
| | | { |
| | | if (p) str=ensure(p,64); |
| | | else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ |
| | | if (str) |
| | | { |
| | | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); |
| | | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); |
| | | else sprintf(str,"%f",d); |
| | | } |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | static unsigned parse_hex4(const char *str) |
| | | { |
| | | unsigned h=0; |
| | | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; |
| | | h=h<<4;str++; |
| | | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; |
| | | h=h<<4;str++; |
| | | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; |
| | | h=h<<4;str++; |
| | | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; |
| | | return h; |
| | | } |
| | | |
| | | /* Parse the input text into an unescaped cstring, and populate item. */ |
| | | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; |
| | | static const char *parse_string(cJSON *item,const char *str) |
| | | { |
| | | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; |
| | | if (*str!='\"') {ep=str;return 0;} /* not a string! */ |
| | | |
| | | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ |
| | | |
| | | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ |
| | | if (!out) return 0; |
| | | |
| | | ptr=str+1;ptr2=out; |
| | | while (*ptr!='\"' && *ptr) |
| | | { |
| | | if (*ptr!='\\') *ptr2++=*ptr++; |
| | | else |
| | | { |
| | | ptr++; |
| | | switch (*ptr) |
| | | { |
| | | case 'b': *ptr2++='\b'; break; |
| | | case 'f': *ptr2++='\f'; break; |
| | | case 'n': *ptr2++='\n'; break; |
| | | case 'r': *ptr2++='\r'; break; |
| | | case 't': *ptr2++='\t'; break; |
| | | case 'u': /* transcode utf16 to utf8. */ |
| | | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ |
| | | |
| | | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ |
| | | |
| | | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ |
| | | { |
| | | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ |
| | | uc2=parse_hex4(ptr+3);ptr+=6; |
| | | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ |
| | | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); |
| | | } |
| | | |
| | | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; |
| | | |
| | | switch (len) { |
| | | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; |
| | | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; |
| | | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; |
| | | case 1: *--ptr2 =(uc | firstByteMark[len]); |
| | | } |
| | | ptr2+=len; |
| | | break; |
| | | default: *ptr2++=*ptr; break; |
| | | } |
| | | ptr++; |
| | | } |
| | | } |
| | | *ptr2=0; |
| | | if (*ptr=='\"') ptr++; |
| | | item->valuestring=out; |
| | | item->type=cJSON_String; |
| | | return ptr; |
| | | } |
| | | |
| | | /* Render the cstring provided to an escaped version that can be printed. */ |
| | | static char *print_string_ptr(const char *str,printbuffer *p) |
| | | { |
| | | const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; |
| | | |
| | | for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; |
| | | if (!flag) |
| | | { |
| | | len=ptr-str; |
| | | if (p) out=ensure(p,len+3); |
| | | else out=(char*)cJSON_malloc(len+3); |
| | | if (!out) return 0; |
| | | ptr2=out;*ptr2++='\"'; |
| | | strcpy(ptr2,str); |
| | | ptr2[len]='\"'; |
| | | ptr2[len+1]=0; |
| | | return out; |
| | | } |
| | | |
| | | if (!str) |
| | | { |
| | | if (p) out=ensure(p,3); |
| | | else out=(char*)cJSON_malloc(3); |
| | | if (!out) return 0; |
| | | strcpy(out,"\"\""); |
| | | return out; |
| | | } |
| | | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} |
| | | |
| | | if (p) out=ensure(p,len+3); |
| | | else out=(char*)cJSON_malloc(len+3); |
| | | if (!out) return 0; |
| | | |
| | | ptr2=out;ptr=str; |
| | | *ptr2++='\"'; |
| | | while (*ptr) |
| | | { |
| | | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; |
| | | else |
| | | { |
| | | *ptr2++='\\'; |
| | | switch (token=*ptr++) |
| | | { |
| | | case '\\': *ptr2++='\\'; break; |
| | | case '\"': *ptr2++='\"'; break; |
| | | case '\b': *ptr2++='b'; break; |
| | | case '\f': *ptr2++='f'; break; |
| | | case '\n': *ptr2++='n'; break; |
| | | case '\r': *ptr2++='r'; break; |
| | | case '\t': *ptr2++='t'; break; |
| | | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ |
| | | } |
| | | } |
| | | } |
| | | *ptr2++='\"';*ptr2++=0; |
| | | return out; |
| | | } |
| | | /* Invote print_string_ptr (which is useful) on an item. */ |
| | | static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} |
| | | |
| | | /* Predeclare these prototypes. */ |
| | | static const char *parse_value(cJSON *item,const char *value); |
| | | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); |
| | | static const char *parse_array(cJSON *item,const char *value); |
| | | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); |
| | | static const char *parse_object(cJSON *item,const char *value); |
| | | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); |
| | | |
| | | /* Utility to jump whitespace and cr/lf */ |
| | | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} |
| | | |
| | | /* Parse an object - create a new root, and populate. */ |
| | | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) |
| | | { |
| | | const char *end=0; |
| | | cJSON *c=cJSON_New_Item(); |
| | | ep=0; |
| | | if (!c) return 0; /* memory fail */ |
| | | |
| | | end=parse_value(c,skip(value)); |
| | | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ |
| | | |
| | | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ |
| | | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} |
| | | if (return_parse_end) *return_parse_end=end; |
| | | return c; |
| | | } |
| | | /* Default options for cJSON_Parse */ |
| | | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} |
| | | |
| | | /* Render a cJSON item/entity/structure to text. */ |
| | | char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} |
| | | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} |
| | | |
| | | char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) |
| | | { |
| | | printbuffer p; |
| | | p.buffer=(char*)cJSON_malloc(prebuffer); |
| | | p.length=prebuffer; |
| | | p.offset=0; |
| | | return print_value(item,0,fmt,&p); |
| | | return p.buffer; |
| | | } |
| | | |
| | | |
| | | /* Parser core - when encountering text, process appropriately. */ |
| | | static const char *parse_value(cJSON *item,const char *value) |
| | | { |
| | | if (!value) return 0; /* Fail on null. */ |
| | | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } |
| | | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } |
| | | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } |
| | | if (*value=='\"') { return parse_string(item,value); } |
| | | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } |
| | | if (*value=='[') { return parse_array(item,value); } |
| | | if (*value=='{') { return parse_object(item,value); } |
| | | |
| | | ep=value;return 0; /* failure. */ |
| | | } |
| | | |
| | | /* Render a value to text. */ |
| | | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) |
| | | { |
| | | char *out=0; |
| | | if (!item) return 0; |
| | | if (p) |
| | | { |
| | | switch ((item->type)&255) |
| | | { |
| | | case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} |
| | | case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} |
| | | case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} |
| | | case cJSON_Number: out=print_number(item,p);break; |
| | | case cJSON_String: out=print_string(item,p);break; |
| | | case cJSON_Array: out=print_array(item,depth,fmt,p);break; |
| | | case cJSON_Object: out=print_object(item,depth,fmt,p);break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | switch ((item->type)&255) |
| | | { |
| | | case cJSON_NULL: out=cJSON_strdup("null"); break; |
| | | case cJSON_False: out=cJSON_strdup("false");break; |
| | | case cJSON_True: out=cJSON_strdup("true"); break; |
| | | case cJSON_Number: out=print_number(item,0);break; |
| | | case cJSON_String: out=print_string(item,0);break; |
| | | case cJSON_Array: out=print_array(item,depth,fmt,0);break; |
| | | case cJSON_Object: out=print_object(item,depth,fmt,0);break; |
| | | } |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | /* Build an array from input text. */ |
| | | static const char *parse_array(cJSON *item,const char *value) |
| | | { |
| | | cJSON *child; |
| | | if (*value!='[') {ep=value;return 0;} /* not an array! */ |
| | | |
| | | item->type=cJSON_Array; |
| | | value=skip(value+1); |
| | | if (*value==']') return value+1; /* empty array. */ |
| | | |
| | | item->child=child=cJSON_New_Item(); |
| | | if (!item->child) return 0; /* memory fail */ |
| | | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ |
| | | if (!value) return 0; |
| | | |
| | | while (*value==',') |
| | | { |
| | | cJSON *new_item; |
| | | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ |
| | | child->next=new_item;new_item->prev=child;child=new_item; |
| | | value=skip(parse_value(child,skip(value+1))); |
| | | if (!value) return 0; /* memory fail */ |
| | | } |
| | | |
| | | if (*value==']') return value+1; /* end of array */ |
| | | ep=value;return 0; /* malformed. */ |
| | | } |
| | | |
| | | /* Render an array to text */ |
| | | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) |
| | | { |
| | | char **entries; |
| | | char *out=0,*ptr,*ret;int len=5; |
| | | cJSON *child=item->child; |
| | | int numentries=0,i=0,fail=0; |
| | | size_t tmplen=0; |
| | | |
| | | /* How many entries in the array? */ |
| | | while (child) numentries++,child=child->next; |
| | | /* Explicitly handle numentries==0 */ |
| | | if (!numentries) |
| | | { |
| | | if (p) out=ensure(p,3); |
| | | else out=(char*)cJSON_malloc(3); |
| | | if (out) strcpy(out,"[]"); |
| | | return out; |
| | | } |
| | | |
| | | if (p) |
| | | { |
| | | /* Compose the output array. */ |
| | | i=p->offset; |
| | | ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; |
| | | child=item->child; |
| | | while (child && !fail) |
| | | { |
| | | print_value(child,depth+1,fmt,p); |
| | | p->offset=update(p); |
| | | if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} |
| | | child=child->next; |
| | | } |
| | | ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; |
| | | out=(p->buffer)+i; |
| | | } |
| | | else |
| | | { |
| | | /* Allocate an array to hold the values for each */ |
| | | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); |
| | | if (!entries) return 0; |
| | | memset(entries,0,numentries*sizeof(char*)); |
| | | /* Retrieve all the results: */ |
| | | child=item->child; |
| | | while (child && !fail) |
| | | { |
| | | ret=print_value(child,depth+1,fmt,0); |
| | | entries[i++]=ret; |
| | | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; |
| | | child=child->next; |
| | | } |
| | | |
| | | /* If we didn't fail, try to malloc the output string */ |
| | | if (!fail) out=(char*)cJSON_malloc(len); |
| | | /* If that fails, we fail. */ |
| | | if (!out) fail=1; |
| | | |
| | | /* Handle failure. */ |
| | | if (fail) |
| | | { |
| | | for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); |
| | | cJSON_free(entries); |
| | | return 0; |
| | | } |
| | | |
| | | /* Compose the output array. */ |
| | | *out='['; |
| | | ptr=out+1;*ptr=0; |
| | | for (i=0;i<numentries;i++) |
| | | { |
| | | tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen; |
| | | if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} |
| | | cJSON_free(entries[i]); |
| | | } |
| | | cJSON_free(entries); |
| | | *ptr++=']';*ptr++=0; |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | /* Build an object from the text. */ |
| | | static const char *parse_object(cJSON *item,const char *value) |
| | | { |
| | | cJSON *child; |
| | | if (*value!='{') {ep=value;return 0;} /* not an object! */ |
| | | |
| | | item->type=cJSON_Object; |
| | | value=skip(value+1); |
| | | if (*value=='}') return value+1; /* empty array. */ |
| | | |
| | | item->child=child=cJSON_New_Item(); |
| | | if (!item->child) return 0; |
| | | value=skip(parse_string(child,skip(value))); |
| | | if (!value) return 0; |
| | | child->string=child->valuestring;child->valuestring=0; |
| | | if (*value!=':') {ep=value;return 0;} /* fail! */ |
| | | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ |
| | | if (!value) return 0; |
| | | |
| | | while (*value==',') |
| | | { |
| | | cJSON *new_item; |
| | | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ |
| | | child->next=new_item;new_item->prev=child;child=new_item; |
| | | value=skip(parse_string(child,skip(value+1))); |
| | | if (!value) return 0; |
| | | child->string=child->valuestring;child->valuestring=0; |
| | | if (*value!=':') {ep=value;return 0;} /* fail! */ |
| | | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ |
| | | if (!value) return 0; |
| | | } |
| | | |
| | | if (*value=='}') return value+1; /* end of array */ |
| | | ep=value;return 0; /* malformed. */ |
| | | } |
| | | |
| | | /* Render an object to text. */ |
| | | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) |
| | | { |
| | | char **entries=0,**names=0; |
| | | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; |
| | | cJSON *child=item->child; |
| | | int numentries=0,fail=0; |
| | | size_t tmplen=0; |
| | | /* Count the number of entries. */ |
| | | while (child) numentries++,child=child->next; |
| | | /* Explicitly handle empty object case */ |
| | | if (!numentries) |
| | | { |
| | | if (p) out=ensure(p,fmt?depth+4:3); |
| | | else out=(char*)cJSON_malloc(fmt?depth+4:3); |
| | | if (!out) return 0; |
| | | ptr=out;*ptr++='{'; |
| | | if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} |
| | | *ptr++='}';*ptr++=0; |
| | | return out; |
| | | } |
| | | if (p) |
| | | { |
| | | /* Compose the output: */ |
| | | i=p->offset; |
| | | len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; |
| | | *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; |
| | | child=item->child;depth++; |
| | | while (child) |
| | | { |
| | | if (fmt) |
| | | { |
| | | ptr=ensure(p,depth); if (!ptr) return 0; |
| | | for (j=0;j<depth;j++) *ptr++='\t'; |
| | | p->offset+=depth; |
| | | } |
| | | print_string_ptr(child->string,p); |
| | | p->offset=update(p); |
| | | |
| | | len=fmt?2:1; |
| | | ptr=ensure(p,len); if (!ptr) return 0; |
| | | *ptr++=':';if (fmt) *ptr++='\t'; |
| | | p->offset+=len; |
| | | |
| | | print_value(child,depth,fmt,p); |
| | | p->offset=update(p); |
| | | |
| | | len=(fmt?1:0)+(child->next?1:0); |
| | | ptr=ensure(p,len+1); if (!ptr) return 0; |
| | | if (child->next) *ptr++=','; |
| | | if (fmt) *ptr++='\n';*ptr=0; |
| | | p->offset+=len; |
| | | child=child->next; |
| | | } |
| | | ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; |
| | | if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; |
| | | *ptr++='}';*ptr=0; |
| | | out=(p->buffer)+i; |
| | | } |
| | | else |
| | | { |
| | | /* Allocate space for the names and the objects */ |
| | | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); |
| | | if (!entries) return 0; |
| | | names=(char**)cJSON_malloc(numentries*sizeof(char*)); |
| | | if (!names) {cJSON_free(entries);return 0;} |
| | | memset(entries,0,sizeof(char*)*numentries); |
| | | memset(names,0,sizeof(char*)*numentries); |
| | | |
| | | /* Collect all the results into our arrays: */ |
| | | child=item->child;depth++;if (fmt) len+=depth; |
| | | while (child) |
| | | { |
| | | names[i]=str=print_string_ptr(child->string,0); |
| | | entries[i++]=ret=print_value(child,depth,fmt,0); |
| | | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; |
| | | child=child->next; |
| | | } |
| | | |
| | | /* Try to allocate the output string */ |
| | | if (!fail) out=(char*)cJSON_malloc(len); |
| | | if (!out) fail=1; |
| | | |
| | | /* Handle failure */ |
| | | if (fail) |
| | | { |
| | | for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} |
| | | cJSON_free(names);cJSON_free(entries); |
| | | return 0; |
| | | } |
| | | |
| | | /* Compose the output: */ |
| | | *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; |
| | | for (i=0;i<numentries;i++) |
| | | { |
| | | if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; |
| | | tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen; |
| | | *ptr++=':';if (fmt) *ptr++='\t'; |
| | | strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); |
| | | if (i!=numentries-1) *ptr++=','; |
| | | if (fmt) *ptr++='\n';*ptr=0; |
| | | cJSON_free(names[i]);cJSON_free(entries[i]); |
| | | } |
| | | |
| | | cJSON_free(names);cJSON_free(entries); |
| | | if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; |
| | | *ptr++='}';*ptr++=0; |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | /* Get Array size/item / object item. */ |
| | | int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} |
| | | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} |
| | | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} |
| | | |
| | | /* Utility for array list handling. */ |
| | | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} |
| | | /* Utility for handling references. */ |
| | | static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} |
| | | |
| | | /* Add item to array/object. */ |
| | | void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} |
| | | void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} |
| | | void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} |
| | | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} |
| | | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} |
| | | |
| | | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; |
| | | if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} |
| | | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} |
| | | cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} |
| | | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} |
| | | |
| | | /* Replace array/object items with new ones. */ |
| | | void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} |
| | | newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} |
| | | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; |
| | | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; |
| | | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} |
| | | void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} |
| | | |
| | | /* Create basic types: */ |
| | | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} |
| | | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} |
| | | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} |
| | | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} |
| | | cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} |
| | | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} |
| | | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} |
| | | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} |
| | | |
| | | /* Create Arrays: */ |
| | | cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} |
| | | cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} |
| | | cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} |
| | | cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} |
| | | |
| | | /* Duplication */ |
| | | cJSON *cJSON_Duplicate(cJSON *item,int recurse) |
| | | { |
| | | cJSON *newitem,*cptr,*nptr=0,*newchild; |
| | | /* Bail on bad ptr */ |
| | | if (!item) return 0; |
| | | /* Create new item */ |
| | | newitem=cJSON_New_Item(); |
| | | if (!newitem) return 0; |
| | | /* Copy over all vars */ |
| | | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; |
| | | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} |
| | | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} |
| | | /* If non-recursive, then we're done! */ |
| | | if (!recurse) return newitem; |
| | | /* Walk the ->next chain for the child. */ |
| | | cptr=item->child; |
| | | while (cptr) |
| | | { |
| | | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ |
| | | if (!newchild) {cJSON_Delete(newitem);return 0;} |
| | | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ |
| | | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ |
| | | cptr=cptr->next; |
| | | } |
| | | return newitem; |
| | | } |
| | | |
| | | void cJSON_Minify(char *json) |
| | | { |
| | | char *into=json; |
| | | while (*json) |
| | | { |
| | | if (*json==' ') json++; |
| | | else if (*json=='\t') json++; /* Whitespace characters. */ |
| | | else if (*json=='\r') json++; |
| | | else if (*json=='\n') json++; |
| | | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ |
| | | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ |
| | | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ |
| | | else *into++=*json++; /* All other characters. */ |
| | | } |
| | | *into=0; /* and null-terminate. */ |
| | | } |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009 Dave Gamble |
| | | |
| | | Permission is hereby granted, free of charge, to any person obtaining a copy |
| | | of this software and associated documentation files (the "Software"), to deal |
| | | in the Software without restriction, including without limitation the rights |
| | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| | | copies of the Software, and to permit persons to whom the Software is |
| | | furnished to do so, subject to the following conditions: |
| | | |
| | | The above copyright notice and this permission notice shall be included in |
| | | all copies or substantial portions of the Software. |
| | | |
| | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| | | THE SOFTWARE. |
| | | */ |
| | | |
| | | #ifndef cJSON__h |
| | | #define cJSON__h |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" |
| | | { |
| | | #endif |
| | | |
| | | /* cJSON Types: */ |
| | | #define cJSON_False 0 |
| | | #define cJSON_True 1 |
| | | #define cJSON_NULL 2 |
| | | #define cJSON_Number 3 |
| | | #define cJSON_String 4 |
| | | #define cJSON_Array 5 |
| | | #define cJSON_Object 6 |
| | | |
| | | #define cJSON_IsReference 256 |
| | | #define cJSON_StringIsConst 512 |
| | | |
| | | /* The cJSON structure: */ |
| | | typedef struct cJSON { |
| | | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ |
| | | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ |
| | | |
| | | int type; /* The type of the item, as above. */ |
| | | |
| | | char *valuestring; /* The item's string, if type==cJSON_String */ |
| | | int valueint; /* The item's number, if type==cJSON_Number */ |
| | | double valuedouble; /* The item's number, if type==cJSON_Number */ |
| | | |
| | | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ |
| | | } cJSON; |
| | | |
| | | typedef struct cJSON_Hooks { |
| | | void *(*malloc_fn)(size_t sz); |
| | | void (*free_fn)(void *ptr); |
| | | } cJSON_Hooks; |
| | | |
| | | /* Supply malloc, realloc and free functions to cJSON */ |
| | | extern void cJSON_InitHooks(cJSON_Hooks* hooks); |
| | | |
| | | |
| | | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ |
| | | extern cJSON *cJSON_Parse(const char *value); |
| | | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ |
| | | extern char *cJSON_Print(cJSON *item); |
| | | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ |
| | | extern char *cJSON_PrintUnformatted(cJSON *item); |
| | | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ |
| | | extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); |
| | | /* Delete a cJSON entity and all subentities. */ |
| | | extern void cJSON_Delete(cJSON *c); |
| | | |
| | | /* Returns the number of items in an array (or object). */ |
| | | extern int cJSON_GetArraySize(cJSON *array); |
| | | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ |
| | | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); |
| | | /* Get item "string" from object. Case insensitive. */ |
| | | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); |
| | | |
| | | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ |
| | | extern const char *cJSON_GetErrorPtr(void); |
| | | |
| | | /* These calls create a cJSON item of the appropriate type. */ |
| | | extern cJSON *cJSON_CreateNull(void); |
| | | extern cJSON *cJSON_CreateTrue(void); |
| | | extern cJSON *cJSON_CreateFalse(void); |
| | | extern cJSON *cJSON_CreateBool(int b); |
| | | extern cJSON *cJSON_CreateNumber(double num); |
| | | extern cJSON *cJSON_CreateString(const char *string); |
| | | extern cJSON *cJSON_CreateArray(void); |
| | | extern cJSON *cJSON_CreateObject(void); |
| | | |
| | | /* These utilities create an Array of count items. */ |
| | | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); |
| | | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); |
| | | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); |
| | | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); |
| | | |
| | | /* Append item to the specified array/object. */ |
| | | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); |
| | | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); |
| | | extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ |
| | | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ |
| | | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); |
| | | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); |
| | | |
| | | /* Remove/Detatch items from Arrays/Objects. */ |
| | | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); |
| | | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); |
| | | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); |
| | | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); |
| | | |
| | | /* Update array items. */ |
| | | extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ |
| | | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); |
| | | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); |
| | | |
| | | /* Duplicate a cJSON item */ |
| | | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); |
| | | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will |
| | | need to be released. With recurse!=0, it will duplicate any children connected to the item. |
| | | The item->next and ->prev pointers are always zero on return from Duplicate. */ |
| | | |
| | | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ |
| | | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); |
| | | |
| | | extern void cJSON_Minify(char *json); |
| | | |
| | | /* Macros for creating things quickly. */ |
| | | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) |
| | | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) |
| | | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) |
| | | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) |
| | | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) |
| | | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) |
| | | |
| | | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ |
| | | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) |
| | | #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif |
New file |
| | |
| | | /* ******************************************************************************** |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_comport.c |
| | | * Description: It's the comport operate library. |
| | | * |
| | | * Version: 2.0.0(10/17/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "comport.h" |
| | | |
| | | void set_settings(st_comport * comport, const char *settings); |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport structure |
| | | * Input Args: dev_name: The comport device name path, such as '/dev/ttyS3' |
| | | * baudrate: The baudrate, such as 115200 |
| | | * settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' |
| | | * Output Args: NONE |
| | | * Return Value: The st_comport structure pointer. |
| | | *************************************************************************************/ |
| | | st_comport *comport_init(const char *dev_name, int baudrate, const char *settings) |
| | | { |
| | | st_comport *comport = NULL; |
| | | if (NULL == (comport = (st_comport *) malloc(sizeof(st_comport)))) |
| | | { |
| | | return NULL; |
| | | } |
| | | memset(comport, 0, sizeof(st_comport)); |
| | | comport->frag_size = 128; |
| | | |
| | | strncpy(comport->dev_name, dev_name, DEVNAME_LEN); |
| | | comport->baudrate = baudrate; |
| | | |
| | | set_settings(comport, settings); |
| | | #ifdef COM_DEBUG |
| | | disp_settings(comport); |
| | | #endif |
| | | |
| | | return comport; |
| | | } |
| | | |
| | | #ifdef COM_DEBUG |
| | | void disp_settings(st_comport *comport) |
| | | { |
| | | COM_PRINT("Device:\t\t\t\"%s\"\n", comport->dev_name); |
| | | COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate); |
| | | COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit); |
| | | |
| | | switch (comport->parity) |
| | | { |
| | | case 0: |
| | | COM_PRINT("Parity:\t\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | COM_PRINT("Parity:\t\t\t\'O\'\n"); |
| | | break; |
| | | case 2: |
| | | COM_PRINT("Parity:\t\t\t\'E\'\n"); |
| | | break; |
| | | case 3: |
| | | COM_PRINT("Parity:\t\t\t\'S\'\n"); |
| | | break; |
| | | } |
| | | COM_PRINT("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit); |
| | | switch (comport->flowctrl) |
| | | { |
| | | case 0: |
| | | COM_PRINT("FlowCtrl:\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | COM_PRINT("FlowCtrl:\t\t\'S\'\n"); |
| | | break; |
| | | case 2: |
| | | COM_PRINT("FlowCtrl:\t\t\'H\'\n"); |
| | | break; |
| | | case 3: |
| | | COM_PRINT("FlowCtrl:\t\t\'B\'\n"); |
| | | break; |
| | | } |
| | | COM_PRINT("\n"); |
| | | return; |
| | | } |
| | | #endif |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport databit,parity,stopbit,flowctrl into the comport structure |
| | | * Input Args: comport: the st_comport pointer |
| | | * settings: The databit/parity/stopbit/flowctrl settings as like "8N1N" |
| | | * Output Args: NONE |
| | | * Return Value: NONE |
| | | *************************************************************************************/ |
| | | void set_settings(st_comport * comport, const char *settings) |
| | | { |
| | | if(NULL==settings || NULL==comport) |
| | | return ; |
| | | |
| | | switch (settings[0]) /* data bit */ |
| | | { |
| | | case '7': |
| | | comport->databit = 7; |
| | | break; |
| | | case '8': |
| | | default: |
| | | comport->databit = 8; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[1]) /* parity */ |
| | | { |
| | | case 'O': |
| | | case 'o': |
| | | comport->parity = 1; |
| | | break; |
| | | case 'E': |
| | | case 'e': |
| | | comport->parity = 2; |
| | | break; |
| | | case 'S': |
| | | case 's': |
| | | comport->parity = 3; |
| | | break; |
| | | case 'N': |
| | | case 'n': |
| | | default: |
| | | comport->parity = 0; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[2]) /* stop bit */ |
| | | { |
| | | case '0': |
| | | comport->stopbit = 0; |
| | | break; |
| | | case '1': |
| | | default: |
| | | comport->stopbit = 1; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[3]) /* flow control */ |
| | | { |
| | | case 'S': |
| | | case 's': |
| | | comport->flowctrl = 1; |
| | | break; |
| | | case 'H': |
| | | case 'h': |
| | | comport->flowctrl = 2; |
| | | break; |
| | | case 'B': |
| | | case 'b': |
| | | comport->flowctrl = 3; |
| | | break; |
| | | case 'N': |
| | | case 'n': |
| | | default: |
| | | comport->flowctrl = 0; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | void comport_close(st_comport * comport) |
| | | { |
| | | if (0 != comport->fd) |
| | | { |
| | | COM_PRINT("Close device \"%s\"\n", comport->dev_name); |
| | | close(comport->fd); |
| | | } |
| | | |
| | | comport->fd = -1; |
| | | } |
| | | |
| | | void comport_term(st_comport * comport) |
| | | { |
| | | if(NULL == comport) |
| | | return; |
| | | |
| | | if ( comport->fd > 0 ) |
| | | { |
| | | comport_close(comport); |
| | | } |
| | | |
| | | memset(comport, 0x00, sizeof(st_comport)); |
| | | free(comport); |
| | | |
| | | return; |
| | | } |
| | | |
| | | int comport_open(st_comport * comport) |
| | | { |
| | | int retval = -1; |
| | | struct termios old_cfg, new_cfg; |
| | | int old_flags; |
| | | long tmp; |
| | | |
| | | if(NULL==comport) |
| | | return -1; |
| | | |
| | | comport_close(comport); |
| | | |
| | | /* Not a TTY device */ |
| | | if( !strstr(comport->dev_name, "tty")) |
| | | { |
| | | COM_PRINT("Open Not tty device \"%s\"\n", comport->dev_name); |
| | | comport->fd = open(comport->dev_name, O_RDWR); |
| | | retval = comport->fd<0 ? -2 : comport->fd; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | comport->fd = open(comport->dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK); |
| | | if (comport->fd < 0) |
| | | { |
| | | retval = -3; |
| | | goto CleanUp; |
| | | } |
| | | COM_PRINT("Open device \"%s\"\n", comport->dev_name); |
| | | |
| | | if ((-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) |
| | | && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK))) |
| | | { |
| | | // Flush input and output |
| | | if (-1 == tcflush(comport->fd, TCIOFLUSH)) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else // Failure |
| | | { |
| | | retval = -5; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 != tcgetattr(comport->fd, &old_cfg)) |
| | | { |
| | | retval = -6; // Failed to get Com settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | | memset(&new_cfg, 0, sizeof(new_cfg)); |
| | | |
| | | /*=====================================*/ |
| | | /* Configure comport */ |
| | | /*=====================================*/ |
| | | |
| | | new_cfg.c_cflag &= ~CSIZE; |
| | | new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); |
| | | new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); |
| | | new_cfg.c_oflag &= ~(OPOST); |
| | | |
| | | /* Set the data bit */ |
| | | switch (comport->databit) |
| | | { |
| | | case 0x07: |
| | | new_cfg.c_cflag |= CS7; |
| | | break; |
| | | case 0x06: |
| | | new_cfg.c_cflag |= CS6; |
| | | break; |
| | | case 0x05: |
| | | new_cfg.c_cflag |= CS5; |
| | | break; |
| | | default: |
| | | new_cfg.c_cflag |= CS8; |
| | | break; |
| | | } |
| | | |
| | | /* Set the parity */ |
| | | switch (comport->parity) |
| | | { |
| | | case 0x01: // Odd |
| | | new_cfg.c_cflag |= (PARENB | PARODD); |
| | | new_cfg.c_cflag |= (INPCK | ISTRIP); |
| | | break; |
| | | case 0x02: // Even |
| | | new_cfg.c_cflag |= PARENB; |
| | | new_cfg.c_cflag &= ~PARODD;; |
| | | new_cfg.c_cflag |= (INPCK | ISTRIP); |
| | | break; |
| | | case 0x03: |
| | | new_cfg.c_cflag &= ~PARENB; |
| | | new_cfg.c_cflag &= ~CSTOPB; |
| | | break; |
| | | default: |
| | | new_cfg.c_cflag &= ~PARENB; |
| | | } |
| | | |
| | | /* Set Stop bit */ |
| | | if (0x01 != comport->stopbit) |
| | | { |
| | | new_cfg.c_cflag |= CSTOPB; |
| | | } |
| | | else |
| | | { |
| | | new_cfg.c_cflag &= ~CSTOPB; |
| | | } |
| | | |
| | | /* Set flow control */ |
| | | switch (comport->flowctrl) |
| | | { |
| | | case 1: // Software control |
| | | case 3: |
| | | new_cfg.c_cflag &= ~(CRTSCTS); |
| | | new_cfg.c_iflag |= (IXON | IXOFF); |
| | | break; |
| | | case 2: // Hardware control |
| | | new_cfg.c_cflag |= CRTSCTS; // Also called CRTSCTS |
| | | new_cfg.c_iflag &= ~(IXON | IXOFF); |
| | | break; |
| | | default: // NONE |
| | | new_cfg.c_cflag &= ~(CRTSCTS); |
| | | new_cfg.c_iflag &= ~(IXON | IXOFF); |
| | | break; |
| | | } |
| | | |
| | | /* Set baudrate */ |
| | | switch (comport->baudrate) |
| | | { |
| | | case 115200: |
| | | tmp = B115200; |
| | | break; |
| | | case 57600: |
| | | tmp = B57600; |
| | | break; |
| | | case 38400: |
| | | tmp = B38400; |
| | | break; |
| | | case 19200: |
| | | tmp = B19200; |
| | | break; |
| | | case 9600: |
| | | tmp = B9600; |
| | | break; |
| | | case 4800: |
| | | tmp = B4800; |
| | | break; |
| | | case 2400: |
| | | tmp = B2400; |
| | | break; |
| | | case 1800: |
| | | tmp = B1800; |
| | | break; |
| | | case 1200: |
| | | tmp = B1200; |
| | | break; |
| | | case 600: |
| | | tmp = B600; |
| | | break; |
| | | case 300: |
| | | tmp = B300; |
| | | break; |
| | | case 200: |
| | | tmp = B200; |
| | | break; |
| | | case 150: |
| | | tmp = B150; |
| | | break; |
| | | case 134: |
| | | tmp = B134; |
| | | break; |
| | | case 110: |
| | | tmp = B110; |
| | | break; |
| | | case 75: |
| | | tmp = B75; |
| | | break; |
| | | case 50: |
| | | tmp = B50; |
| | | break; |
| | | default: |
| | | tmp = B115200; |
| | | } |
| | | cfsetispeed(&new_cfg, tmp); |
| | | cfsetispeed(&new_cfg, tmp); |
| | | |
| | | /* Set the Com port timeout settings */ |
| | | new_cfg.c_cc[VMIN] = 0; |
| | | new_cfg.c_cc[VTIME] = 0; |
| | | |
| | | tcflush(comport->fd, TCIFLUSH); |
| | | if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg)) |
| | | { |
| | | retval = -7; // Failed to set device com port settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | | COM_PRINT("Connected device \"%s\".\n", comport->dev_name); |
| | | |
| | | retval = comport->fd; |
| | | |
| | | CleanUp: |
| | | COM_PRINT("Open device \"%s\" %s.\n", comport->dev_name, retval>0 ? "successfully" : "failure"); |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | int comport_recv(st_comport * comport, char *buf, int buf_size, unsigned long timeout) |
| | | { |
| | | int retval = 0; // Function return value |
| | | int iRet; |
| | | fd_set stReadFds, stExcpFds; |
| | | struct timeval stTime; |
| | | |
| | | if (NULL == buf || 0 >= buf_size) |
| | | { |
| | | COM_PRINT("%s() usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if ( comport->fd < 0 ) |
| | | { |
| | | COM_PRINT("%s() comport not connected.\n", __FUNCTION__); |
| | | retval = -2; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | //printf("bufsize=%d timeout=%lu\n", buf_size, timeout); |
| | | |
| | | FD_ZERO(&stReadFds); |
| | | FD_ZERO(&stExcpFds); |
| | | FD_SET(comport->fd, &stReadFds); |
| | | FD_SET(comport->fd, &stExcpFds); |
| | | |
| | | if (0xFFFFFFFF != timeout) |
| | | { |
| | | stTime.tv_sec = (time_t) (timeout / 1000); |
| | | stTime.tv_usec = (long)(1000 * (timeout % 1000)); |
| | | |
| | | iRet = select(comport->fd + 1, &stReadFds, 0, &stExcpFds, &stTime); |
| | | if (0 == iRet) |
| | | { |
| | | retval = 0; // No data in Com port buffer |
| | | goto CleanUp; |
| | | } |
| | | else if (0 < iRet) |
| | | { |
| | | if (0 != FD_ISSET(comport->fd, &stExcpFds)) |
| | | { |
| | | retval = -6; // Error during checking recv status |
| | | COM_PRINT("Error checking recv status.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 == FD_ISSET(comport->fd, &stReadFds)) |
| | | { |
| | | retval = 0; // No incoming data |
| | | COM_PRINT("No incoming data.\n"); |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (EINTR == errno) |
| | | { |
| | | COM_PRINT("catch interrupt signal.\n"); |
| | | retval = 0; // Interrupted signal catched |
| | | } |
| | | else |
| | | { |
| | | COM_PRINT("Check recv status failure.\n"); |
| | | retval = -7; // Error during checking recv status |
| | | } |
| | | |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | usleep(10000); /* sleep for 10ms for data incoming */ |
| | | |
| | | // Get data from Com port |
| | | iRet = read(comport->fd, buf, buf_size); |
| | | if (0 > iRet) |
| | | { |
| | | if (EINTR == errno) |
| | | retval = 0; // Interrupted signal catched |
| | | else |
| | | retval = -3; // Failed to read Com port |
| | | |
| | | goto CleanUp; |
| | | } |
| | | |
| | | #if 0 |
| | | { |
| | | int i=0; |
| | | printf("Receive %d bytes data: \n", iRet); |
| | | for(i=0; i<iRet; i++) |
| | | { |
| | | printf("0x%02x ", buf[i]); |
| | | } |
| | | printf("\n"); |
| | | } |
| | | #endif |
| | | |
| | | retval = iRet; |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | |
| | | } |
| | | |
| | | int comport_send(st_comport * comport, char *buf, int send_bytes) |
| | | { |
| | | char *ptr, *end; |
| | | int retval = 0; |
| | | int send = 0; |
| | | |
| | | if (NULL == buf || 0 >= send_bytes) |
| | | { |
| | | COM_PRINT("%s() Usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if ( comport->fd < 0 ) // Comport not opened ? |
| | | { |
| | | retval = -3; |
| | | COM_PRINT("Serail not connected.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | //printf("Send %s with %d bytes.\n", buf, send_bytes); |
| | | |
| | | // Large data, then slice them and send |
| | | if (comport->frag_size < send_bytes) |
| | | { |
| | | ptr = buf; |
| | | end = buf + send_bytes; |
| | | |
| | | do |
| | | { |
| | | // Large than frag_size |
| | | if (comport->frag_size < (end - ptr)) |
| | | { |
| | | send = write(comport->fd, ptr, comport->frag_size); |
| | | if (0 >= send || comport->frag_size != send) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | ptr += comport->frag_size; |
| | | } |
| | | else // Less than frag_size, maybe last fragmention. |
| | | { |
| | | send = write(comport->fd, ptr, (end - ptr)); |
| | | if (0 >= send || (end - ptr) != send) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | ptr += (end - ptr); |
| | | } |
| | | } |
| | | while (ptr < end); |
| | | } |
| | | else // The send data is not large than a fragmention. |
| | | { |
| | | send = write(comport->fd, buf, send_bytes); |
| | | if (0 >= send || send_bytes != send) |
| | | { |
| | | retval = -5; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | } |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: comport.h |
| | | * Description: This head file is for the common TTY/Serial port operator library |
| | | * |
| | | * Version: 1.0.0(10/17/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/17/2018 03:33:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __COMPORT_H_ |
| | | #define __COMPORT_H_ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <getopt.h> |
| | | #include <fcntl.h> |
| | | #include <errno.h> |
| | | #include <termios.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/wait.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/select.h> |
| | | |
| | | #define BUF_64 64 |
| | | |
| | | #ifndef DEVNAME_LEN |
| | | #define DEVNAME_LEN 64 |
| | | #endif |
| | | |
| | | //#define COM_DEBUG |
| | | #ifdef COM_DEBUG |
| | | #define COM_PRINT(format,args...) printf(format, ##args) |
| | | #else |
| | | #define COM_PRINT(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | //#define msleep(m) {struct timespec cSleep; cSleep.tv_sec = 0; cSleep.tv_nsec = m * 1000; nanosleep(&cSleep, 0);} |
| | | |
| | | typedef struct _st_comport |
| | | { |
| | | char dev_name[DEVNAME_LEN]; |
| | | unsigned char databit, parity, stopbit, flowctrl; |
| | | long baudrate; |
| | | |
| | | int fd; |
| | | int frag_size; |
| | | } st_comport; |
| | | |
| | | /* |
| | | * description: initialise the comport structure |
| | | * |
| | | * input args: $dev_name: The comport device name path, such as '/dev/ttyS3' |
| | | * $baudrate: The baudrate, such as 115200 |
| | | * $settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' |
| | | * |
| | | * return value: The st_comport structure pointer, NULL means failure. |
| | | */ |
| | | |
| | | st_comport *comport_init(const char *dev_name, int baudrate, const char *settings); |
| | | |
| | | |
| | | /* |
| | | * description: Open the comport specified by $comport |
| | | * input args: $comport: corresponding comport point |
| | | * return value: The comport opened file description, <0 means failure |
| | | */ |
| | | extern int comport_open(st_comport * comport); |
| | | |
| | | /* |
| | | * description: read data from $comport in $timeout <ms> to $buf no more than $buf_size bytes |
| | | * return value: the actual read data bytes, <0: read failure |
| | | */ |
| | | extern int comport_recv(st_comport * comport, char *buf, int buf_size, unsigned long timeout); |
| | | |
| | | /* |
| | | * description: write $send_bytes bytes data from $buf to $comport |
| | | * return value: 0: write ok <0: write failure |
| | | */ |
| | | extern int comport_send(st_comport * comport, char *buf, int send_bytes); |
| | | |
| | | /* |
| | | * description: display current comport settings such as databit,parity,stopbit,flowctrl |
| | | * input args: $comport: corresponding comport point |
| | | */ |
| | | //extern void disp_settings(st_comport * comport); |
| | | |
| | | /* |
| | | * description: close comport |
| | | * input args: $comport: corresponding comport point |
| | | */ |
| | | extern void comport_close(st_comport * comport); |
| | | |
| | | |
| | | /* |
| | | * description: terminat comport, close and free it |
| | | * input args: $comport: corresponding comport point |
| | | */ |
| | | extern void comport_term(st_comport * comport); |
| | | |
| | | #endif |
New file |
| | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file ini_dictionary.c |
| | | @author N. Devillard |
| | | @brief Implements a dictionary for string variables. |
| | | |
| | | This module implements a simple dictionary object, i.e. a list |
| | | of string/string associations. This object is useful to store e.g. |
| | | informations retrieved from a configuration file (ini files). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | #include "ini_dictionary.h" |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | |
| | | /** Maximum value size for integers and doubles. */ |
| | | #define MAXVALSZ 1024 |
| | | |
| | | /** Minimal allocated number of entries in a dictionary */ |
| | | #define DICTMINSZ 128 |
| | | |
| | | /** Invalid key token */ |
| | | #define DICT_INVALID_KEY ((char*)-1) |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Private functions |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | /* Doubles the allocated size associated to a pointer */ |
| | | /* 'size' is the current allocated size. */ |
| | | static void * mem_double(void * ptr, int size) |
| | | { |
| | | void * newptr ; |
| | | |
| | | newptr = calloc(2*size, 1); |
| | | if (newptr==NULL) { |
| | | return NULL ; |
| | | } |
| | | memcpy(newptr, ptr, size); |
| | | free(ptr); |
| | | return newptr ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Duplicate a string |
| | | @param s String to duplicate |
| | | @return Pointer to a newly allocated string, to be freed with free() |
| | | |
| | | This is a replacement for strdup(). This implementation is provided |
| | | for systems that do not have it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * xstrdup(const char * s) |
| | | { |
| | | char * t ; |
| | | if (!s) |
| | | return NULL ; |
| | | t = (char*)malloc(strlen(s)+1) ; |
| | | if (t) { |
| | | strcpy(t,s); |
| | | } |
| | | return t ; |
| | | } |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Function codes |
| | | ---------------------------------------------------------------------------*/ |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Compute the hash key for a string. |
| | | @param key Character string to use for key. |
| | | @return 1 unsigned int on at least 32 bits. |
| | | |
| | | This hash function has been taken from an Article in Dr Dobbs Journal. |
| | | This is normally a collision-free function, distributing keys evenly. |
| | | The key is stored anyway in the struct so that collision can be avoided |
| | | by comparing the key itself in last resort. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | unsigned dictionary_hash(const char * key) |
| | | { |
| | | int len ; |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | len = strlen(key); |
| | | for (hash=0, i=0 ; i<len ; i++) { |
| | | hash += (unsigned)key[i] ; |
| | | hash += (hash<<10); |
| | | hash ^= (hash>>6) ; |
| | | } |
| | | hash += (hash <<3); |
| | | hash ^= (hash >>11); |
| | | hash += (hash <<15); |
| | | return hash ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Create a new dictionary object. |
| | | @param size Optional initial size of the dictionary. |
| | | @return 1 newly allocated dictionary objet. |
| | | |
| | | This function allocates a new dictionary object of given size and returns |
| | | it. If you do not know in advance (roughly) the number of entries in the |
| | | dictionary, give size=0. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * dictionary_new(int size) |
| | | { |
| | | dictionary * d ; |
| | | |
| | | /* If no size was specified, allocate space for DICTMINSZ */ |
| | | if (size<DICTMINSZ) size=DICTMINSZ ; |
| | | |
| | | if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { |
| | | return NULL; |
| | | } |
| | | d->size = size ; |
| | | d->val = (char **)calloc(size, sizeof(char*)); |
| | | d->key = (char **)calloc(size, sizeof(char*)); |
| | | d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); |
| | | return d ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a dictionary object |
| | | @param d dictionary object to deallocate. |
| | | @return void |
| | | |
| | | Deallocate a dictionary object and all memory associated to it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_del(dictionary * d) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL) return ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]!=NULL) |
| | | free(d->key[i]); |
| | | if (d->val[i]!=NULL) |
| | | free(d->val[i]); |
| | | } |
| | | free(d->val); |
| | | free(d->key); |
| | | free(d->hash); |
| | | free(d); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get a value from a dictionary. |
| | | @param d dictionary object to search. |
| | | @param key Key to look for in the dictionary. |
| | | @param def Default value to return if key not found. |
| | | @return 1 pointer to internally allocated character string. |
| | | |
| | | This function locates a key in a dictionary and returns a pointer to its |
| | | value, or the passed 'def' pointer if no such key can be found in |
| | | dictionary. The returned character pointer points to data internal to the |
| | | dictionary object, you should not try to free it or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * dictionary_get(dictionary * d, const char * key, char * def) |
| | | { |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | hash = dictionary_hash(key); |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | /* Compare hash */ |
| | | if (hash==d->hash[i]) { |
| | | /* Compare string, to avoid hash collisions */ |
| | | if (!strcmp(key, d->key[i])) { |
| | | return d->val[i] ; |
| | | } |
| | | } |
| | | } |
| | | return def ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set a value in a dictionary. |
| | | @param d dictionary object to modify. |
| | | @param key Key to modify or add. |
| | | @param val Value to add. |
| | | @return int 0 if Ok, anything else otherwise |
| | | |
| | | If the given key is found in the dictionary, the associated value is |
| | | replaced by the provided one. If the key cannot be found in the |
| | | dictionary, it is added to it. |
| | | |
| | | It is Ok to provide a NULL value for val, but NULL values for the dictionary |
| | | or the key are considered as errors: the function will return immediately |
| | | in such a case. |
| | | |
| | | Notice that if you dictionary_set a variable to NULL, a call to |
| | | dictionary_get will return a NULL value: the variable will be found, and |
| | | its value (NULL) is returned. In other words, setting the variable |
| | | content to NULL is equivalent to deleting the variable from the |
| | | dictionary. It is not possible (in this implementation) to have a key in |
| | | the dictionary without value. |
| | | |
| | | This function returns non-zero in case of failure. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int dictionary_set(dictionary * d, const char * key, const char * val) |
| | | { |
| | | int i ; |
| | | unsigned hash ; |
| | | |
| | | if (d==NULL || key==NULL) return -1 ; |
| | | |
| | | /* Compute hash for this key */ |
| | | hash = dictionary_hash(key) ; |
| | | /* Find if value is already in dictionary */ |
| | | if (d->n>0) { |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (hash==d->hash[i]) { /* Same hash value */ |
| | | if (!strcmp(key, d->key[i])) { /* Same key */ |
| | | /* Found a value: modify and return */ |
| | | if (d->val[i]!=NULL) |
| | | free(d->val[i]); |
| | | d->val[i] = val ? xstrdup(val) : NULL ; |
| | | /* Value has been modified: return */ |
| | | return 0 ; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | /* Add a new value */ |
| | | /* See if dictionary needs to grow */ |
| | | if (d->n==d->size) { |
| | | |
| | | /* Reached maximum size: reallocate dictionary */ |
| | | d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; |
| | | d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; |
| | | d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; |
| | | if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { |
| | | /* Cannot grow dictionary */ |
| | | return -1 ; |
| | | } |
| | | /* Double size */ |
| | | d->size *= 2 ; |
| | | } |
| | | |
| | | /* Insert key in the first empty slot. Start at d->n and wrap at |
| | | d->size. Because d->n < d->size this will necessarily |
| | | terminate. */ |
| | | for (i=d->n ; d->key[i] ; ) { |
| | | if(++i == d->size) i = 0; |
| | | } |
| | | /* Copy key */ |
| | | d->key[i] = xstrdup(key); |
| | | d->val[i] = val ? xstrdup(val) : NULL ; |
| | | d->hash[i] = hash; |
| | | d->n ++ ; |
| | | return 0 ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a key in a dictionary |
| | | @param d dictionary object to modify. |
| | | @param key Key to remove. |
| | | @return void |
| | | |
| | | This function deletes a key in a dictionary. Nothing is done if the |
| | | key cannot be found. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_unset(dictionary * d, const char * key) |
| | | { |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | if (key == NULL) { |
| | | return; |
| | | } |
| | | |
| | | hash = dictionary_hash(key); |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | /* Compare hash */ |
| | | if (hash==d->hash[i]) { |
| | | /* Compare string, to avoid hash collisions */ |
| | | if (!strcmp(key, d->key[i])) { |
| | | /* Found key */ |
| | | break ; |
| | | } |
| | | } |
| | | } |
| | | if (i>=d->size) |
| | | /* Key not found */ |
| | | return ; |
| | | |
| | | free(d->key[i]); |
| | | d->key[i] = NULL ; |
| | | if (d->val[i]!=NULL) { |
| | | free(d->val[i]); |
| | | d->val[i] = NULL ; |
| | | } |
| | | d->hash[i] = 0 ; |
| | | d->n -- ; |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer. |
| | | @return void |
| | | |
| | | Dumps a dictionary onto an opened file pointer. Key pairs are printed out |
| | | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as |
| | | output file pointers. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_dump(dictionary * d, FILE * out) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL || out==NULL) return ; |
| | | if (d->n<1) { |
| | | fprintf(out, "empty dictionary\n"); |
| | | return ; |
| | | } |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]) { |
| | | fprintf(out, "%20s\t[%s]\n", |
| | | d->key[i], |
| | | d->val[i] ? d->val[i] : "UNDEF"); |
| | | } |
| | | } |
| | | return ; |
| | | } |
| | | |
| | | |
| | | /* Test code */ |
| | | #ifdef TESTDIC |
| | | #define NVALS 20000 |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | dictionary * d ; |
| | | char * val ; |
| | | int i ; |
| | | char cval[90] ; |
| | | |
| | | /* Allocate dictionary */ |
| | | printf("allocating...\n"); |
| | | d = dictionary_new(0); |
| | | |
| | | /* Set values in dictionary */ |
| | | printf("setting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | dictionary_set(d, cval, "salut"); |
| | | } |
| | | printf("getting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | val = dictionary_get(d, cval, DICT_INVALID_KEY); |
| | | if (val==DICT_INVALID_KEY) { |
| | | printf("cannot get value for key [%s]\n", cval); |
| | | } |
| | | } |
| | | printf("unsetting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | dictionary_unset(d, cval); |
| | | } |
| | | if (d->n != 0) { |
| | | printf("error deleting values\n"); |
| | | } |
| | | printf("deallocating...\n"); |
| | | dictionary_del(d); |
| | | return 0 ; |
| | | } |
| | | #endif |
| | | /* vim: set ts=4 et sw=4 tw=75 */ |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file ini_dictionary.h |
| | | @author N. Devillard |
| | | @brief Implements a dictionary for string variables. |
| | | |
| | | This module implements a simple dictionary object, i.e. a list |
| | | of string/string associations. This object is useful to store e.g. |
| | | informations retrieved from a configuration file (ini files). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | #ifndef _INI_DICTIONARY_H_ |
| | | #define _INI_DICTIONARY_H_ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | New types |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dictionary object |
| | | |
| | | This object contains a list of string/string associations. Each |
| | | association is identified by a unique string key. Looking up values |
| | | in the dictionary is speeded up by the use of a (hopefully collision-free) |
| | | hash function. |
| | | */ |
| | | /*-------------------------------------------------------------------------*/ |
| | | typedef struct _dictionary_ { |
| | | int n ; /** Number of entries in dictionary */ |
| | | int size ; /** Storage size */ |
| | | char ** val ; /** List of string values */ |
| | | char ** key ; /** List of string keys */ |
| | | unsigned * hash ; /** List of hash values for keys */ |
| | | } dictionary ; |
| | | |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Function prototypes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Compute the hash key for a string. |
| | | @param key Character string to use for key. |
| | | @return 1 unsigned int on at least 32 bits. |
| | | |
| | | This hash function has been taken from an Article in Dr Dobbs Journal. |
| | | This is normally a collision-free function, distributing keys evenly. |
| | | The key is stored anyway in the struct so that collision can be avoided |
| | | by comparing the key itself in last resort. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | unsigned dictionary_hash(const char * key); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Create a new dictionary object. |
| | | @param size Optional initial size of the dictionary. |
| | | @return 1 newly allocated dictionary objet. |
| | | |
| | | This function allocates a new dictionary object of given size and returns |
| | | it. If you do not know in advance (roughly) the number of entries in the |
| | | dictionary, give size=0. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * dictionary_new(int size); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a dictionary object |
| | | @param d dictionary object to deallocate. |
| | | @return void |
| | | |
| | | Deallocate a dictionary object and all memory associated to it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_del(dictionary * vd); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get a value from a dictionary. |
| | | @param d dictionary object to search. |
| | | @param key Key to look for in the dictionary. |
| | | @param def Default value to return if key not found. |
| | | @return 1 pointer to internally allocated character string. |
| | | |
| | | This function locates a key in a dictionary and returns a pointer to its |
| | | value, or the passed 'def' pointer if no such key can be found in |
| | | dictionary. The returned character pointer points to data internal to the |
| | | dictionary object, you should not try to free it or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * dictionary_get(dictionary * d, const char * key, char * def); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set a value in a dictionary. |
| | | @param d dictionary object to modify. |
| | | @param key Key to modify or add. |
| | | @param val Value to add. |
| | | @return int 0 if Ok, anything else otherwise |
| | | |
| | | If the given key is found in the dictionary, the associated value is |
| | | replaced by the provided one. If the key cannot be found in the |
| | | dictionary, it is added to it. |
| | | |
| | | It is Ok to provide a NULL value for val, but NULL values for the dictionary |
| | | or the key are considered as errors: the function will return immediately |
| | | in such a case. |
| | | |
| | | Notice that if you dictionary_set a variable to NULL, a call to |
| | | dictionary_get will return a NULL value: the variable will be found, and |
| | | its value (NULL) is returned. In other words, setting the variable |
| | | content to NULL is equivalent to deleting the variable from the |
| | | dictionary. It is not possible (in this implementation) to have a key in |
| | | the dictionary without value. |
| | | |
| | | This function returns non-zero in case of failure. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int dictionary_set(dictionary * vd, const char * key, const char * val); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a key in a dictionary |
| | | @param d dictionary object to modify. |
| | | @param key Key to remove. |
| | | @return void |
| | | |
| | | This function deletes a key in a dictionary. Nothing is done if the |
| | | key cannot be found. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_unset(dictionary * d, const char * key); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer. |
| | | @return void |
| | | |
| | | Dumps a dictionary onto an opened file pointer. Key pairs are printed out |
| | | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as |
| | | output file pointers. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_dump(dictionary * d, FILE * out); |
| | | |
| | | #endif |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file iniparser.c |
| | | @author N. Devillard |
| | | @brief Parser for ini files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | /*---------------------------- Includes ------------------------------------*/ |
| | | #include <ctype.h> |
| | | #include "iniparser.h" |
| | | |
| | | /*---------------------------- Defines -------------------------------------*/ |
| | | #define ASCIILINESZ (1024) |
| | | #define INI_INVALID_KEY ((char*)-1) |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Private to this module |
| | | ---------------------------------------------------------------------------*/ |
| | | /** |
| | | * This enum stores the status for each parsed line (internal use only). |
| | | */ |
| | | typedef enum _line_status_ { |
| | | LINE_UNPROCESSED, |
| | | LINE_ERROR, |
| | | LINE_EMPTY, |
| | | LINE_COMMENT, |
| | | LINE_SECTION, |
| | | LINE_VALUE |
| | | } line_status ; |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Convert a string to lowercase. |
| | | @param s String to convert. |
| | | @return ptr to statically allocated string. |
| | | |
| | | This function returns a pointer to a statically allocated string |
| | | containing a lowercased version of the input string. Do not free |
| | | or modify the returned string! Since the returned string is statically |
| | | allocated, it will be modified at each function call (not re-entrant). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * strlwc(const char * s) |
| | | { |
| | | static char l[ASCIILINESZ+1]; |
| | | int i ; |
| | | |
| | | if (s==NULL) return NULL ; |
| | | memset(l, 0, ASCIILINESZ+1); |
| | | i=0 ; |
| | | while (s[i] && i<ASCIILINESZ) { |
| | | l[i] = (char)tolower((int)s[i]); |
| | | i++ ; |
| | | } |
| | | l[ASCIILINESZ]=(char)0; |
| | | return l ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Remove blanks at the beginning and the end of a string. |
| | | @param s String to parse. |
| | | @return ptr to statically allocated string. |
| | | |
| | | This function returns a pointer to a statically allocated string, |
| | | which is identical to the input string, except that all blank |
| | | characters at the end and the beg. of the string have been removed. |
| | | Do not free or modify the returned string! Since the returned string |
| | | is statically allocated, it will be modified at each function call |
| | | (not re-entrant). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * strstrip(const char * s) |
| | | { |
| | | static char l[ASCIILINESZ+1]; |
| | | char * last ; |
| | | |
| | | if (s==NULL) return NULL ; |
| | | |
| | | while (isspace((int)*s) && *s) s++; |
| | | memset(l, 0, ASCIILINESZ+1); |
| | | strcpy(l, s); |
| | | last = l + strlen(l); |
| | | while (last > l) { |
| | | if (!isspace((int)*(last-1))) |
| | | break ; |
| | | last -- ; |
| | | } |
| | | *last = (char)0; |
| | | return (char*)l ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get number of sections in a dictionary |
| | | @param d Dictionary to examine |
| | | @return int Number of sections found in dictionary |
| | | |
| | | This function returns the number of sections found in a dictionary. |
| | | The test to recognize sections is done on the string stored in the |
| | | dictionary: a section name is given as "section" whereas a key is |
| | | stored as "section:key", thus the test looks for entries that do not |
| | | contain a colon. |
| | | |
| | | This clearly fails in the case a section name contains a colon, but |
| | | this should simply be avoided. |
| | | |
| | | This function returns -1 in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getnsec(dictionary * d) |
| | | { |
| | | int i ; |
| | | int nsec ; |
| | | |
| | | if (d==NULL) return -1 ; |
| | | nsec=0 ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (strchr(d->key[i], ':')==NULL) { |
| | | nsec ++ ; |
| | | } |
| | | } |
| | | return nsec ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get name for section n in a dictionary. |
| | | @param d Dictionary to examine |
| | | @param n Section number (from 0 to nsec-1). |
| | | @return Pointer to char string |
| | | |
| | | This function locates the n-th section in a dictionary and returns |
| | | its name as a pointer to a string statically allocated inside the |
| | | dictionary. Do not free or modify the returned string! |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getsecname(dictionary * d, int n) |
| | | { |
| | | int i ; |
| | | int foundsec ; |
| | | |
| | | if (d==NULL || n<0) return NULL ; |
| | | foundsec=0 ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (strchr(d->key[i], ':')==NULL) { |
| | | foundsec++ ; |
| | | if (foundsec>n) |
| | | break ; |
| | | } |
| | | } |
| | | if (foundsec<=n) { |
| | | return NULL ; |
| | | } |
| | | return d->key[i] ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump. |
| | | @param f Opened file pointer to dump to. |
| | | @return void |
| | | |
| | | This function prints out the contents of a dictionary, one element by |
| | | line, onto the provided file pointer. It is OK to specify @c stderr |
| | | or @c stdout as output files. This function is meant for debugging |
| | | purposes mostly. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump(dictionary * d, FILE * f) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (d->val[i]!=NULL) { |
| | | fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); |
| | | } else { |
| | | fprintf(f, "[%s]=UNDEF\n", d->key[i]); |
| | | } |
| | | } |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given dictionary into a loadable ini file. |
| | | It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump_ini(dictionary * d, FILE * f) |
| | | { |
| | | int i ; |
| | | int nsec ; |
| | | char * secname ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | |
| | | nsec = iniparser_getnsec(d); |
| | | if (nsec<1) { |
| | | /* No section in file: dump all keys as they are */ |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | fprintf(f, "%s = %s\n", d->key[i], d->val[i]); |
| | | } |
| | | return ; |
| | | } |
| | | for (i=0 ; i<nsec ; i++) { |
| | | secname = iniparser_getsecname(d, i) ; |
| | | iniparser_dumpsection_ini(d, secname, f) ; |
| | | } |
| | | fprintf(f, "\n"); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary section to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param s Section name of dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given section of a given dictionary into a loadable ini |
| | | file. It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f) |
| | | { |
| | | int j ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int seclen ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | if (! iniparser_find_entry(d, s)) return ; |
| | | |
| | | seclen = (int)strlen(s); |
| | | fprintf(f, "\n[%s]\n", s); |
| | | sprintf(keym, "%s:", s); |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) { |
| | | fprintf(f, |
| | | "%-30s = %s\n", |
| | | d->key[j]+seclen+1, |
| | | d->val[j] ? d->val[j] : ""); |
| | | } |
| | | } |
| | | fprintf(f, "\n"); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return Number of keys in section |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getsecnkeys(dictionary * d, char * s) |
| | | { |
| | | int seclen, nkeys ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int j ; |
| | | |
| | | nkeys = 0; |
| | | |
| | | if (d==NULL) return nkeys; |
| | | if (! iniparser_find_entry(d, s)) return nkeys; |
| | | |
| | | seclen = (int)strlen(s); |
| | | sprintf(keym, "%s:", s); |
| | | |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) |
| | | nkeys++; |
| | | } |
| | | |
| | | return nkeys; |
| | | |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return pointer to statically allocated character strings |
| | | |
| | | This function queries a dictionary and finds all keys in a given section. |
| | | Each pointer in the returned char pointer-to-pointer is pointing to |
| | | a string allocated in the dictionary; do not free or modify them. |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char ** iniparser_getseckeys(dictionary * d, char * s) |
| | | { |
| | | |
| | | char **keys; |
| | | |
| | | int i, j ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int seclen, nkeys ; |
| | | |
| | | keys = NULL; |
| | | |
| | | if (d==NULL) return keys; |
| | | if (! iniparser_find_entry(d, s)) return keys; |
| | | |
| | | nkeys = iniparser_getsecnkeys(d, s); |
| | | |
| | | keys = (char**) malloc(nkeys*sizeof(char*)); |
| | | |
| | | seclen = (int)strlen(s); |
| | | sprintf(keym, "%s:", s); |
| | | |
| | | i = 0; |
| | | |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) { |
| | | keys[i] = d->key[j]; |
| | | i++; |
| | | } |
| | | } |
| | | |
| | | return keys; |
| | | |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param def Default value to return if key not found. |
| | | @return pointer to statically allocated character string |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the pointer passed as 'def' is returned. |
| | | The returned char pointer is pointing to a string allocated in |
| | | the dictionary, do not free or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getstring(dictionary * d, const char * key, char * def) |
| | | { |
| | | char * lc_key ; |
| | | char * sval ; |
| | | |
| | | if (d==NULL || key==NULL) |
| | | return def ; |
| | | |
| | | lc_key = strlwc(key); |
| | | sval = dictionary_get(d, lc_key, def); |
| | | return sval ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to an int |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | Supported values for integers include the usual C notation |
| | | so decimal, octal (starting with 0) and hexadecimal (starting with 0x) |
| | | are supported. Examples: |
| | | |
| | | "42" -> 42 |
| | | "042" -> 34 (octal -> decimal) |
| | | "0x42" -> 66 (hexa -> decimal) |
| | | |
| | | Warning: the conversion may overflow in various ways. Conversion is |
| | | totally outsourced to strtol(), see the associated man page for overflow |
| | | handling. |
| | | |
| | | Credits: Thanks to A. Becker for suggesting strtol() |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getint(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return (int)strtol(str, NULL, 0); |
| | | } |
| | | |
| | | int iniparser_getlong(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return strtol(str, NULL, 0); |
| | | } |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a double |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return double |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | double iniparser_getdouble(dictionary * d, const char * key, double notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return atof(str); |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a boolean |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | A true boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'y' |
| | | - A string starting with 'Y' |
| | | - A string starting with 't' |
| | | - A string starting with 'T' |
| | | - A string starting with '1' |
| | | |
| | | A false boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'n' |
| | | - A string starting with 'N' |
| | | - A string starting with 'f' |
| | | - A string starting with 'F' |
| | | - A string starting with '0' |
| | | |
| | | The notfound value returned if no boolean is identified, does not |
| | | necessarily have to be 0 or 1. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getboolean(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * c ; |
| | | int ret ; |
| | | |
| | | c = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (c==INI_INVALID_KEY) return notfound ; |
| | | if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { |
| | | ret = 1 ; |
| | | } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { |
| | | ret = 0 ; |
| | | } else { |
| | | ret = notfound ; |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Finds out if a given entry exists in a dictionary |
| | | @param ini Dictionary to search |
| | | @param entry Name of the entry to look for |
| | | @return integer 1 if entry exists, 0 otherwise |
| | | |
| | | Finds out if a given entry exists in the dictionary. Since sections |
| | | are stored as keys with NULL associated values, this is the only way |
| | | of querying for the presence of sections in a dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_find_entry( |
| | | dictionary * ini, |
| | | const char * entry |
| | | ) |
| | | { |
| | | int found=0 ; |
| | | if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { |
| | | found = 1 ; |
| | | } |
| | | return found ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set an entry in a dictionary. |
| | | @param ini Dictionary to modify. |
| | | @param entry Entry to modify (entry name) |
| | | @param val New value to associate to the entry. |
| | | @return int 0 if Ok, -1 otherwise. |
| | | |
| | | If the given entry can be found in the dictionary, it is modified to |
| | | contain the provided value. If it cannot be found, -1 is returned. |
| | | It is Ok to set val to NULL. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_set(dictionary * ini, const char * entry, const char * val) |
| | | { |
| | | return dictionary_set(ini, strlwc(entry), val) ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete an entry in a dictionary |
| | | @param ini Dictionary to modify |
| | | @param entry Entry to delete (entry name) |
| | | @return void |
| | | |
| | | If the given entry can be found, it is deleted from the dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_unset(dictionary * ini, const char * entry) |
| | | { |
| | | dictionary_unset(ini, strlwc(entry)); |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Load a single line from an INI file |
| | | @param input_line Input line, may be concatenated multi-line input |
| | | @param section Output space to store section |
| | | @param key Output space to store key |
| | | @param value Output space to store value |
| | | @return line_status value |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static line_status iniparser_line( |
| | | char * input_line, |
| | | char * section, |
| | | char * key, |
| | | char * value) |
| | | { |
| | | line_status sta ; |
| | | char line[ASCIILINESZ+1]; |
| | | static char left_line[ASCIILINESZ+1]; |
| | | int len, offset ; |
| | | |
| | | strcpy(line, strstrip(input_line)); |
| | | len = (int)strlen(line); |
| | | |
| | | sta = LINE_UNPROCESSED ; |
| | | if (len<1) { |
| | | /* Empty line */ |
| | | sta = LINE_EMPTY ; |
| | | memset(input_line, 0, len); |
| | | } else if (line[0]=='#' || line[0]==';') { |
| | | /* Comment line */ |
| | | sta = LINE_COMMENT ; |
| | | memset(input_line, 0, len); |
| | | } else if (line[0]=='[') { |
| | | /* Section name */ |
| | | sscanf(line, "[%[^]]", section); |
| | | strcpy(section, strstrip(section)); |
| | | strcpy(section, strlwc(section)); |
| | | |
| | | /* Left configure will go to next time to parser */ |
| | | offset = strlen(section) + 2; |
| | | strcpy( left_line, strstrip(&(line[offset])) ); |
| | | strcpy( left_line, strstrip(left_line)); |
| | | |
| | | if( strlen(left_line) > 0) |
| | | { |
| | | strcpy(input_line, left_line); |
| | | strcat(input_line, "\n"); |
| | | } |
| | | else |
| | | { |
| | | memset(input_line, 0, len); |
| | | } |
| | | sta = LINE_SECTION ; |
| | | } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 |
| | | || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 |
| | | || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { |
| | | char *ptr = NULL; |
| | | |
| | | /* Usual key=value, with or without comments */ |
| | | strcpy(key, strstrip(key)); |
| | | strcpy(key, strlwc(key)); |
| | | strcpy(value, strstrip(value)); |
| | | /* |
| | | * sscanf cannot handle '' or "" as empty values |
| | | * this is done here |
| | | */ |
| | | if (!strncmp(value, "\"\"", 2) || (!strncmp(value, "''", 2)) ) { |
| | | value[0]=0 ; |
| | | } |
| | | |
| | | ptr = strchr(line, '='); |
| | | if('\''==*(ptr+1) || '\"'==*(ptr+1)) |
| | | { |
| | | offset = strlen(key)+strlen(value) + 1 + 2; /* Skip $key='$val' */ |
| | | } |
| | | else |
| | | { |
| | | offset = strlen(key)+strlen(value) + 1; /* Skip $key=$val */ |
| | | } |
| | | strcpy( left_line, strstrip(&(line[offset])) ); |
| | | |
| | | if( strlen(left_line) > 0) |
| | | { |
| | | strcpy(input_line, left_line); |
| | | strcat(input_line, "\n"); |
| | | } |
| | | else |
| | | { |
| | | memset(input_line, 0, len); |
| | | } |
| | | sta = LINE_VALUE ; |
| | | } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 |
| | | || sscanf(line, "%[^=] %[=]", key, value) == 2) { |
| | | /* |
| | | * Special cases: |
| | | * key= |
| | | * key=; |
| | | * key=# |
| | | */ |
| | | strcpy(key, strstrip(key)); |
| | | strcpy(key, strlwc(key)); |
| | | value[0]=0 ; |
| | | sta = LINE_VALUE ; |
| | | } else { |
| | | /* Generate syntax error */ |
| | | sta = LINE_ERROR ; |
| | | memset(input_line, 0, len); |
| | | } |
| | | return sta ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Parse an ini file and return an allocated dictionary object |
| | | @param ininame Name of the ini file to read. |
| | | @return Pointer to newly allocated dictionary |
| | | |
| | | This is the parser for ini files. This function is called, providing |
| | | the name of the file to be read. It returns a dictionary object that |
| | | should not be accessed directly, but through accessor functions |
| | | instead. |
| | | |
| | | The returned dictionary must be freed using iniparser_freedict(). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * iniparser_load(const char * ininame) |
| | | { |
| | | FILE * in ; |
| | | |
| | | char line [ASCIILINESZ+1] ; |
| | | char section [ASCIILINESZ+1] ; |
| | | char key [ASCIILINESZ+1] ; |
| | | char tmp [ASCIILINESZ+1] ; |
| | | char val [ASCIILINESZ+1] ; |
| | | |
| | | int last=0 ; |
| | | int len ; |
| | | int lineno=0 ; |
| | | int errs=0; |
| | | |
| | | dictionary * dict ; |
| | | |
| | | if ((in=fopen(ininame, "r"))==NULL) { |
| | | fprintf(stderr, "iniparser: cannot open %s\n", ininame); |
| | | return NULL ; |
| | | } |
| | | |
| | | dict = dictionary_new(0) ; |
| | | if (!dict) { |
| | | fclose(in); |
| | | return NULL ; |
| | | } |
| | | |
| | | memset(line, 0, ASCIILINESZ); |
| | | memset(section, 0, ASCIILINESZ); |
| | | memset(key, 0, ASCIILINESZ); |
| | | memset(val, 0, ASCIILINESZ); |
| | | last=0 ; |
| | | |
| | | while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { |
| | | lineno++ ; |
| | | CONTINUE_PARSER: |
| | | len = (int)strlen(line)-1; |
| | | if (len==0) |
| | | continue; |
| | | /* Safety check against buffer overflows */ |
| | | if (line[len]!='\n') { |
| | | fprintf(stderr, |
| | | "iniparser: input line too long in %s (%d)\n", |
| | | ininame, |
| | | lineno); |
| | | dictionary_del(dict); |
| | | fclose(in); |
| | | return NULL ; |
| | | } |
| | | /* Get rid of \n and spaces at end of line */ |
| | | while ((len>=0) && |
| | | ((line[len]=='\n') || (isspace(line[len])))) { |
| | | line[len]=0 ; |
| | | len-- ; |
| | | } |
| | | /* Detect multi-line */ |
| | | if (line[len]=='\\') { |
| | | /* Multi-line value */ |
| | | last=len ; |
| | | continue ; |
| | | } else { |
| | | last=0 ; |
| | | } |
| | | |
| | | switch ( iniparser_line(line, section, key, val) ) { |
| | | case LINE_EMPTY: |
| | | case LINE_COMMENT: |
| | | break ; |
| | | |
| | | case LINE_SECTION: |
| | | errs = dictionary_set(dict, section, NULL); |
| | | break ; |
| | | |
| | | case LINE_VALUE: |
| | | sprintf(tmp, "%s:%s", section, key); |
| | | errs = dictionary_set(dict, tmp, val) ; |
| | | break ; |
| | | |
| | | case LINE_ERROR: |
| | | fprintf(stderr, "iniparser: syntax error in %s (%d):\n", |
| | | ininame, |
| | | lineno); |
| | | fprintf(stderr, "-> %s\n", line); |
| | | errs++ ; |
| | | break; |
| | | |
| | | default: |
| | | break ; |
| | | } |
| | | |
| | | if( strlen(line) > 0) |
| | | { |
| | | goto CONTINUE_PARSER; |
| | | } |
| | | |
| | | memset(line, 0, ASCIILINESZ); |
| | | last=0; |
| | | if (errs<0) { |
| | | fprintf(stderr, "iniparser: memory allocation failure\n"); |
| | | break ; |
| | | } |
| | | } |
| | | if (errs) { |
| | | dictionary_del(dict); |
| | | dict = NULL ; |
| | | } |
| | | fclose(in); |
| | | return dict ; |
| | | } |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Free all memory associated to an ini dictionary |
| | | @param d Dictionary to free |
| | | @return void |
| | | |
| | | Free all memory associated to an ini dictionary. |
| | | It is mandatory to call this function before the dictionary object |
| | | gets out of the current context. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_freedict(dictionary * d) |
| | | { |
| | | dictionary_del(d); |
| | | } |
| | | |
| | | /* vim: set ts=4 et sw=4 tw=75 */ |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file cp_iniparser.h |
| | | @author N. Devillard |
| | | @brief Parser for ini files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | #ifndef _INIPARSER_H_ |
| | | #define _INIPARSER_H_ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | /* |
| | | * The following #include is necessary on many Unixes but not Linux. |
| | | * It is not needed for Windows platforms. |
| | | * Uncomment it if needed. |
| | | */ |
| | | /* #include <unistd.h> */ |
| | | |
| | | #include "ini_dictionary.h" |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get number of sections in a dictionary |
| | | @param d Dictionary to examine |
| | | @return int Number of sections found in dictionary |
| | | |
| | | This function returns the number of sections found in a dictionary. |
| | | The test to recognize sections is done on the string stored in the |
| | | dictionary: a section name is given as "section" whereas a key is |
| | | stored as "section:key", thus the test looks for entries that do not |
| | | contain a colon. |
| | | |
| | | This clearly fails in the case a section name contains a colon, but |
| | | this should simply be avoided. |
| | | |
| | | This function returns -1 in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | int iniparser_getnsec(dictionary * d); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get name for section n in a dictionary. |
| | | @param d Dictionary to examine |
| | | @param n Section number (from 0 to nsec-1). |
| | | @return Pointer to char string |
| | | |
| | | This function locates the n-th section in a dictionary and returns |
| | | its name as a pointer to a string statically allocated inside the |
| | | dictionary. Do not free or modify the returned string! |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | char * iniparser_getsecname(dictionary * d, int n); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given dictionary into a loadable ini file. |
| | | It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | void iniparser_dump_ini(dictionary * d, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary section to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param s Section name of dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given section of a given dictionary into a loadable ini |
| | | file. It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump. |
| | | @param f Opened file pointer to dump to. |
| | | @return void |
| | | |
| | | This function prints out the contents of a dictionary, one element by |
| | | line, onto the provided file pointer. It is OK to specify @c stderr |
| | | or @c stdout as output files. This function is meant for debugging |
| | | purposes mostly. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump(dictionary * d, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return Number of keys in section |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getsecnkeys(dictionary * d, char * s); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return pointer to statically allocated character strings |
| | | |
| | | This function queries a dictionary and finds all keys in a given section. |
| | | Each pointer in the returned char pointer-to-pointer is pointing to |
| | | a string allocated in the dictionary; do not free or modify them. |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char ** iniparser_getseckeys(dictionary * d, char * s); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param def Default value to return if key not found. |
| | | @return pointer to statically allocated character string |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the pointer passed as 'def' is returned. |
| | | The returned char pointer is pointing to a string allocated in |
| | | the dictionary, do not free or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getstring(dictionary * d, const char * key, char * def); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to an int |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | Supported values for integers include the usual C notation |
| | | so decimal, octal (starting with 0) and hexadecimal (starting with 0x) |
| | | are supported. Examples: |
| | | |
| | | - "42" -> 42 |
| | | - "042" -> 34 (octal -> decimal) |
| | | - "0x42" -> 66 (hexa -> decimal) |
| | | |
| | | Warning: the conversion may overflow in various ways. Conversion is |
| | | totally outsourced to strtol(), see the associated man page for overflow |
| | | handling. |
| | | |
| | | Credits: Thanks to A. Becker for suggesting strtol() |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getint(dictionary * d, const char * key, int notfound); |
| | | int iniparser_getlong(dictionary * d, const char * key, int notfound); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a double |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return double |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | double iniparser_getdouble(dictionary * d, const char * key, double notfound); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a boolean |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | A true boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'y' |
| | | - A string starting with 'Y' |
| | | - A string starting with 't' |
| | | - A string starting with 'T' |
| | | - A string starting with '1' |
| | | |
| | | A false boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'n' |
| | | - A string starting with 'N' |
| | | - A string starting with 'f' |
| | | - A string starting with 'F' |
| | | - A string starting with '0' |
| | | |
| | | The notfound value returned if no boolean is identified, does not |
| | | necessarily have to be 0 or 1. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getboolean(dictionary * d, const char * key, int notfound); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set an entry in a dictionary. |
| | | @param ini Dictionary to modify. |
| | | @param entry Entry to modify (entry name) |
| | | @param val New value to associate to the entry. |
| | | @return int 0 if Ok, -1 otherwise. |
| | | |
| | | If the given entry can be found in the dictionary, it is modified to |
| | | contain the provided value. If it cannot be found, -1 is returned. |
| | | It is Ok to set val to NULL. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_set(dictionary * ini, const char * entry, const char * val); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete an entry in a dictionary |
| | | @param ini Dictionary to modify |
| | | @param entry Entry to delete (entry name) |
| | | @return void |
| | | |
| | | If the given entry can be found, it is deleted from the dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_unset(dictionary * ini, const char * entry); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Finds out if a given entry exists in a dictionary |
| | | @param ini Dictionary to search |
| | | @param entry Name of the entry to look for |
| | | @return integer 1 if entry exists, 0 otherwise |
| | | |
| | | Finds out if a given entry exists in the dictionary. Since sections |
| | | are stored as keys with NULL associated values, this is the only way |
| | | of querying for the presence of sections in a dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_find_entry(dictionary * ini, const char * entry) ; |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Parse an ini file and return an allocated dictionary object |
| | | @param ininame Name of the ini file to read. |
| | | @return Pointer to newly allocated dictionary |
| | | |
| | | This is the parser for ini files. This function is called, providing |
| | | the name of the file to be read. It returns a dictionary object that |
| | | should not be accessed directly, but through accessor functions |
| | | instead. |
| | | |
| | | The returned dictionary must be freed using iniparser_freedict(). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * iniparser_load(const char * ininame); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Free all memory associated to an ini dictionary |
| | | @param d Dictionary to free |
| | | @return void |
| | | |
| | | Free all memory associated to an ini dictionary. |
| | | It is mandatory to call this function before the dictionary object |
| | | gets out of the current context. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_freedict(dictionary * d); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_list.h |
| | | * Description: This file is copied from Linux kernel, which provide link list API. |
| | | * |
| | | * Version: 1.0.0(08/09/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/09/2012 02:24:34 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef _LINUX_LIST_H |
| | | #define _LINUX_LIST_H |
| | | |
| | | #include <linux/stddef.h> |
| | | |
| | | |
| | | /** |
| | | * container_of - cast a member of a structure out to the containing structure |
| | | * @ptr: the pointer to the member. |
| | | * @type: the type of the container struct this is embedded in. |
| | | * @member: the name of the member within the struct. |
| | | * |
| | | */ |
| | | #undef offsetof |
| | | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| | | #define container_of(ptr, type, member) ({ \ |
| | | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ |
| | | (type *)( (char *)__mptr - offsetof(type,member) );}) |
| | | |
| | | |
| | | /* |
| | | * Architectures might want to move the poison pointer offset |
| | | * into some well-recognized area such as 0xdead000000000000, |
| | | * that is also not mappable by user-space exploits: |
| | | */ |
| | | #ifdef CONFIG_ILLEGAL_POINTER_VALUE |
| | | # define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL) |
| | | #else |
| | | # define POISON_POINTER_DELTA 0 |
| | | #endif |
| | | |
| | | /* |
| | | * These are non-NULL pointers that will result in page faults |
| | | * under normal circumstances, used to verify that nobody uses |
| | | * non-initialized list entries. |
| | | */ |
| | | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) |
| | | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) |
| | | |
| | | #ifndef ARCH_HAS_PREFETCH |
| | | #define ARCH_HAS_PREFETCH |
| | | static inline void prefetch(const void *x) {;} |
| | | #endif |
| | | |
| | | /* |
| | | * Simple doubly linked list implementation. |
| | | * |
| | | * Some of the internal functions ("__xxx") are useful when |
| | | * manipulating whole lists rather than single entries, as |
| | | * sometimes we already know the next/prev entries and we can |
| | | * generate better code by using them directly rather than |
| | | * using the generic single-entry routines. |
| | | */ |
| | | |
| | | struct list_head { |
| | | struct list_head *next, *prev; |
| | | }; |
| | | |
| | | #define LIST_HEAD_INIT(name) { &(name), &(name) } |
| | | |
| | | #define LIST_HEAD(name) \ |
| | | struct list_head name = LIST_HEAD_INIT(name) |
| | | |
| | | static inline void INIT_LIST_HEAD(struct list_head *list) |
| | | { |
| | | list->next = list; |
| | | list->prev = list; |
| | | } |
| | | |
| | | /* |
| | | * Insert a new entry between two known consecutive entries. |
| | | * |
| | | * This is only for internal list manipulation where we know |
| | | * the prev/next entries already! |
| | | */ |
| | | static inline void __list_add(struct list_head *new, |
| | | struct list_head *prev, |
| | | struct list_head *next) |
| | | { |
| | | next->prev = new; |
| | | new->next = next; |
| | | new->prev = prev; |
| | | prev->next = new; |
| | | } |
| | | |
| | | /** |
| | | * list_add - add a new entry |
| | | * @new: new entry to be added |
| | | * @head: list head to add it after |
| | | * |
| | | * Insert a new entry after the specified head. |
| | | * This is good for implementing stacks. |
| | | */ |
| | | static inline void list_add(struct list_head *new, struct list_head *head) |
| | | { |
| | | __list_add(new, head, head->next); |
| | | } |
| | | |
| | | /** |
| | | * list_add_tail - add a new entry |
| | | * @new: new entry to be added |
| | | * @head: list head to add it before |
| | | * |
| | | * Insert a new entry before the specified head. |
| | | * This is useful for implementing queues. |
| | | */ |
| | | static inline void list_add_tail(struct list_head *new, struct list_head *head) |
| | | { |
| | | __list_add(new, head->prev, head); |
| | | } |
| | | |
| | | /* |
| | | * Delete a list entry by making the prev/next entries |
| | | * point to each other. |
| | | * |
| | | * This is only for internal list manipulation where we know |
| | | * the prev/next entries already! |
| | | */ |
| | | static inline void __list_del(struct list_head *prev, struct list_head *next) |
| | | { |
| | | next->prev = prev; |
| | | prev->next = next; |
| | | } |
| | | |
| | | /** |
| | | * list_del - deletes entry from list. |
| | | * @entry: the element to delete from the list. |
| | | * Note: list_empty() on entry does not return true after this, the entry is |
| | | * in an undefined state. |
| | | */ |
| | | static inline void list_del(struct list_head *entry) |
| | | { |
| | | __list_del(entry->prev, entry->next); |
| | | entry->next = LIST_POISON1; |
| | | entry->prev = LIST_POISON2; |
| | | } |
| | | |
| | | /** |
| | | * list_replace - replace old entry by new one |
| | | * @old : the element to be replaced |
| | | * @new : the new element to insert |
| | | * |
| | | * If @old was empty, it will be overwritten. |
| | | */ |
| | | static inline void list_replace(struct list_head *old, |
| | | struct list_head *new) |
| | | { |
| | | new->next = old->next; |
| | | new->next->prev = new; |
| | | new->prev = old->prev; |
| | | new->prev->next = new; |
| | | } |
| | | |
| | | static inline void list_replace_init(struct list_head *old, |
| | | struct list_head *new) |
| | | { |
| | | list_replace(old, new); |
| | | INIT_LIST_HEAD(old); |
| | | } |
| | | |
| | | /** |
| | | * list_del_init - deletes entry from list and reinitialize it. |
| | | * @entry: the element to delete from the list. |
| | | */ |
| | | static inline void list_del_init(struct list_head *entry) |
| | | { |
| | | __list_del(entry->prev, entry->next); |
| | | INIT_LIST_HEAD(entry); |
| | | } |
| | | |
| | | /** |
| | | * list_move - delete from one list and add as another's head |
| | | * @list: the entry to move |
| | | * @head: the head that will precede our entry |
| | | */ |
| | | static inline void list_move(struct list_head *list, struct list_head *head) |
| | | { |
| | | __list_del(list->prev, list->next); |
| | | list_add(list, head); |
| | | } |
| | | |
| | | /** |
| | | * list_move_tail - delete from one list and add as another's tail |
| | | * @list: the entry to move |
| | | * @head: the head that will follow our entry |
| | | */ |
| | | static inline void list_move_tail(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | __list_del(list->prev, list->next); |
| | | list_add_tail(list, head); |
| | | } |
| | | |
| | | /** |
| | | * list_is_last - tests whether @list is the last entry in list @head |
| | | * @list: the entry to test |
| | | * @head: the head of the list |
| | | */ |
| | | static inline int list_is_last(const struct list_head *list, |
| | | const struct list_head *head) |
| | | { |
| | | return list->next == head; |
| | | } |
| | | |
| | | /** |
| | | * list_empty - tests whether a list is empty |
| | | * @head: the list to test. |
| | | */ |
| | | static inline int list_empty(const struct list_head *head) |
| | | { |
| | | return head->next == head; |
| | | } |
| | | |
| | | /** |
| | | * list_empty_careful - tests whether a list is empty and not being modified |
| | | * @head: the list to test |
| | | * |
| | | * Description: |
| | | * tests whether a list is empty _and_ checks that no other CPU might be |
| | | * in the process of modifying either member (next or prev) |
| | | * |
| | | * NOTE: using list_empty_careful() without synchronization |
| | | * can only be safe if the only activity that can happen |
| | | * to the list entry is list_del_init(). Eg. it cannot be used |
| | | * if another CPU could re-list_add() it. |
| | | */ |
| | | static inline int list_empty_careful(const struct list_head *head) |
| | | { |
| | | struct list_head *next = head->next; |
| | | return (next == head) && (next == head->prev); |
| | | } |
| | | |
| | | /** |
| | | * list_is_singular - tests whether a list has just one entry. |
| | | * @head: the list to test. |
| | | */ |
| | | static inline int list_is_singular(const struct list_head *head) |
| | | { |
| | | return !list_empty(head) && (head->next == head->prev); |
| | | } |
| | | |
| | | static inline void __list_cut_position(struct list_head *list, |
| | | struct list_head *head, struct list_head *entry) |
| | | { |
| | | struct list_head *new_first = entry->next; |
| | | list->next = head->next; |
| | | list->next->prev = list; |
| | | list->prev = entry; |
| | | entry->next = list; |
| | | head->next = new_first; |
| | | new_first->prev = head; |
| | | } |
| | | |
| | | /** |
| | | * list_cut_position - cut a list into two |
| | | * @list: a new list to add all removed entries |
| | | * @head: a list with entries |
| | | * @entry: an entry within head, could be the head itself |
| | | * and if so we won't cut the list |
| | | * |
| | | * This helper moves the initial part of @head, up to and |
| | | * including @entry, from @head to @list. You should |
| | | * pass on @entry an element you know is on @head. @list |
| | | * should be an empty list or a list you do not care about |
| | | * losing its data. |
| | | * |
| | | */ |
| | | static inline void list_cut_position(struct list_head *list, |
| | | struct list_head *head, struct list_head *entry) |
| | | { |
| | | if (list_empty(head)) |
| | | return; |
| | | if (list_is_singular(head) && |
| | | (head->next != entry && head != entry)) |
| | | return; |
| | | if (entry == head) |
| | | INIT_LIST_HEAD(list); |
| | | else |
| | | __list_cut_position(list, head, entry); |
| | | } |
| | | |
| | | static inline void __list_splice(const struct list_head *list, |
| | | struct list_head *prev, |
| | | struct list_head *next) |
| | | { |
| | | struct list_head *first = list->next; |
| | | struct list_head *last = list->prev; |
| | | |
| | | first->prev = prev; |
| | | prev->next = first; |
| | | |
| | | last->next = next; |
| | | next->prev = last; |
| | | } |
| | | |
| | | /** |
| | | * list_splice - join two lists, this is designed for stacks |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | */ |
| | | static inline void list_splice(const struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) |
| | | __list_splice(list, head, head->next); |
| | | } |
| | | |
| | | /** |
| | | * list_splice_tail - join two lists, each list being a queue |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | */ |
| | | static inline void list_splice_tail(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) |
| | | __list_splice(list, head->prev, head); |
| | | } |
| | | |
| | | /** |
| | | * list_splice_init - join two lists and reinitialise the emptied list. |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | * |
| | | * The list at @list is reinitialised |
| | | */ |
| | | static inline void list_splice_init(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) { |
| | | __list_splice(list, head, head->next); |
| | | INIT_LIST_HEAD(list); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * list_splice_tail_init - join two lists and reinitialise the emptied list |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | * |
| | | * Each of the lists is a queue. |
| | | * The list at @list is reinitialised |
| | | */ |
| | | static inline void list_splice_tail_init(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) { |
| | | __list_splice(list, head->prev, head); |
| | | INIT_LIST_HEAD(list); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * list_entry - get the struct for this entry |
| | | * @ptr: the &struct list_head pointer. |
| | | * @type: the type of the struct this is embedded in. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_entry(ptr, type, member) \ |
| | | container_of(ptr, type, member) |
| | | |
| | | /** |
| | | * list_first_entry - get the first element from a list |
| | | * @ptr: the list head to take the element from. |
| | | * @type: the type of the struct this is embedded in. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Note, that list is expected to be not empty. |
| | | */ |
| | | #define list_first_entry(ptr, type, member) \ |
| | | list_entry((ptr)->next, type, member) |
| | | |
| | | /** |
| | | * list_for_each - iterate over a list |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each(pos, head) \ |
| | | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * __list_for_each - iterate over a list |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * |
| | | * This variant differs from list_for_each() in that it's the |
| | | * simplest possible list iteration code, no prefetching is done. |
| | | * Use this for code that knows the list to be very short (empty |
| | | * or 1 entry) most of the time. |
| | | */ |
| | | #define __list_for_each(pos, head) \ |
| | | for (pos = (head)->next; pos != (head); pos = pos->next) |
| | | |
| | | /** |
| | | * list_for_each_prev - iterate over a list backwards |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_prev(pos, head) \ |
| | | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ |
| | | pos = pos->prev) |
| | | |
| | | /** |
| | | * list_for_each_safe - iterate over a list safe against removal of list entry |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @n: another &struct list_head to use as temporary storage |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_safe(pos, n, head) \ |
| | | for (pos = (head)->next, n = pos->next; pos != (head); \ |
| | | pos = n, n = pos->next) |
| | | |
| | | /** |
| | | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @n: another &struct list_head to use as temporary storage |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_prev_safe(pos, n, head) \ |
| | | for (pos = (head)->prev, n = pos->prev; \ |
| | | prefetch(pos->prev), pos != (head); \ |
| | | pos = n, n = pos->prev) |
| | | |
| | | /** |
| | | * list_for_each_entry - iterate over list of given type |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry(pos, head, member) \ |
| | | for (pos = list_entry((head)->next, typeof(*pos), member); \ |
| | | prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_reverse - iterate backwards over list of given type. |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry_reverse(pos, head, member) \ |
| | | for (pos = list_entry((head)->prev, typeof(*pos), member); \ |
| | | prefetch(pos->member.prev), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.prev, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() |
| | | * @pos: the type * to use as a start point |
| | | * @head: the head of the list |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). |
| | | */ |
| | | #define list_prepare_entry(pos, head, member) \ |
| | | ((pos) ? : list_entry(head, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_continue - continue iteration over list of given type |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Continue to iterate over list of given type, continuing after |
| | | * the current position. |
| | | */ |
| | | #define list_for_each_entry_continue(pos, head, member) \ |
| | | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_continue_reverse - iterate backwards from the given point |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Start to iterate over list of given type backwards, continuing after |
| | | * the current position. |
| | | */ |
| | | #define list_for_each_entry_continue_reverse(pos, head, member) \ |
| | | for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ |
| | | prefetch(pos->member.prev), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.prev, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_from - iterate over list of given type from the current point |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type, continuing from current position. |
| | | */ |
| | | #define list_for_each_entry_from(pos, head, member) \ |
| | | for (; prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry_safe(pos, n, head, member) \ |
| | | for (pos = list_entry((head)->next, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_continue |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type, continuing after current point, |
| | | * safe against removal of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_continue(pos, n, head, member) \ |
| | | for (pos = list_entry(pos->member.next, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_from |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type from current point, safe against |
| | | * removal of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_from(pos, n, head, member) \ |
| | | for (n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_reverse |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate backwards over list of given type, safe against removal |
| | | * of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ |
| | | for (pos = list_entry((head)->prev, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.prev, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.prev, typeof(*n), member)) |
| | | |
| | | /* |
| | | * Double linked lists with a single pointer list head. |
| | | * Mostly useful for hash tables where the two pointer list head is |
| | | * too wasteful. |
| | | * You lose the ability to access the tail in O(1). |
| | | */ |
| | | |
| | | struct hlist_head { |
| | | struct hlist_node *first; |
| | | }; |
| | | |
| | | struct hlist_node { |
| | | struct hlist_node *next, **pprev; |
| | | }; |
| | | |
| | | #define HLIST_HEAD_INIT { .first = NULL } |
| | | #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } |
| | | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) |
| | | static inline void INIT_HLIST_NODE(struct hlist_node *h) |
| | | { |
| | | h->next = NULL; |
| | | h->pprev = NULL; |
| | | } |
| | | |
| | | static inline int hlist_unhashed(const struct hlist_node *h) |
| | | { |
| | | return !h->pprev; |
| | | } |
| | | |
| | | static inline int hlist_empty(const struct hlist_head *h) |
| | | { |
| | | return !h->first; |
| | | } |
| | | |
| | | static inline void __hlist_del(struct hlist_node *n) |
| | | { |
| | | struct hlist_node *next = n->next; |
| | | struct hlist_node **pprev = n->pprev; |
| | | *pprev = next; |
| | | if (next) |
| | | next->pprev = pprev; |
| | | } |
| | | |
| | | static inline void hlist_del(struct hlist_node *n) |
| | | { |
| | | __hlist_del(n); |
| | | n->next = LIST_POISON1; |
| | | n->pprev = LIST_POISON2; |
| | | } |
| | | |
| | | static inline void hlist_del_init(struct hlist_node *n) |
| | | { |
| | | if (!hlist_unhashed(n)) { |
| | | __hlist_del(n); |
| | | INIT_HLIST_NODE(n); |
| | | } |
| | | } |
| | | |
| | | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) |
| | | { |
| | | struct hlist_node *first = h->first; |
| | | n->next = first; |
| | | if (first) |
| | | first->pprev = &n->next; |
| | | h->first = n; |
| | | n->pprev = &h->first; |
| | | } |
| | | |
| | | /* next must be != NULL */ |
| | | static inline void hlist_add_before(struct hlist_node *n, |
| | | struct hlist_node *next) |
| | | { |
| | | n->pprev = next->pprev; |
| | | n->next = next; |
| | | next->pprev = &n->next; |
| | | *(n->pprev) = n; |
| | | } |
| | | |
| | | static inline void hlist_add_after(struct hlist_node *n, |
| | | struct hlist_node *next) |
| | | { |
| | | next->next = n->next; |
| | | n->next = next; |
| | | next->pprev = &n->next; |
| | | |
| | | if(next->next) |
| | | next->next->pprev = &next->next; |
| | | } |
| | | |
| | | #define hlist_entry(ptr, type, member) container_of(ptr,type,member) |
| | | |
| | | #define hlist_for_each(pos, head) \ |
| | | for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ |
| | | pos = pos->next) |
| | | |
| | | #define hlist_for_each_safe(pos, n, head) \ |
| | | for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ |
| | | pos = n) |
| | | |
| | | /** |
| | | * hlist_for_each_entry - iterate over list of given type |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry(tpos, pos, head, member) \ |
| | | for (pos = (head)->first; \ |
| | | pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_continue - iterate over a hlist continuing after current point |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_continue(tpos, pos, member) \ |
| | | for (pos = (pos)->next; \ |
| | | pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_from - iterate over a hlist continuing from current point |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_from(tpos, pos, member) \ |
| | | for (; pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @n: another &struct hlist_node to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ |
| | | for (pos = (head)->first; \ |
| | | pos && ({ n = pos->next; 1; }) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = n) |
| | | |
| | | |
| | | #endif |
| | | |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: logger.c |
| | | * Description: This file is the linux infrastructural logger system library, which |
| | | * is not thread safe. |
| | | * |
| | | * Version: 1.0.0(08/08/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/08/2018 04:24:01 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "logger.h" |
| | | |
| | | #define PRECISE_TIME_FACTOR 1000 |
| | | |
| | | static unsigned long log_rollback_size = LOG_ROLLBACK_NONE; |
| | | |
| | | static st_logger _g_logger; |
| | | static st_logger *g_logger = &_g_logger; |
| | | |
| | | char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" }; |
| | | |
| | | static char *log_time_format = "%Y-%m-%d %H:%M:%S"; |
| | | |
| | | static void logger_default_signal_handler(int sig) |
| | | { |
| | | if (sig == SIGHUP) |
| | | { |
| | | signal(SIGHUP, logger_default_signal_handler); |
| | | log_fatal("SIGHUP received - reopenning log file [%s]", g_logger->file); |
| | | logger_reopen(); |
| | | } |
| | | } |
| | | |
| | | static void logger_banner(char *prefix) |
| | | { |
| | | fprintf(g_logger->fp, "%s log \"%s\" on level [%s] size [%lu], log system version %s\n", |
| | | prefix, g_logger->file, log_str[g_logger->level], log_rollback_size / 1024, LOG_VERSION_STR); |
| | | #if 0 |
| | | #ifdef LOG_FILE_LINE |
| | | fprintf(g_logger->fp, " [Date] [Time] [Level] [PID/TID] [File/Line] [Content]\n"); |
| | | #else |
| | | fprintf(g_logger->fp, " [Date] [Time] [Level] [PID/TID] [Content]\n"); |
| | | #endif |
| | | #endif |
| | | fprintf(g_logger->fp, "-----------------------------------------------------------------------------\n"); |
| | | } |
| | | |
| | | static void check_and_rollback(void) |
| | | { |
| | | if (log_rollback_size != LOG_ROLLBACK_NONE) |
| | | { |
| | | long _curOffset = ftell(g_logger->fp); |
| | | |
| | | if ((_curOffset != -1) && (_curOffset >= log_rollback_size)) |
| | | { |
| | | char cmd[512]; |
| | | |
| | | snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", g_logger->file, g_logger->file); |
| | | system(cmd); |
| | | |
| | | if (-1 == fseek(g_logger->fp, 0L, SEEK_SET)) |
| | | fprintf(g_logger->fp, "log rollback fseek failed \n"); |
| | | |
| | | rewind(g_logger->fp); |
| | | |
| | | truncate(g_logger->file, 0); |
| | | logger_banner("Already rollback"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | int logger_init(char *filename, int level, int log_size) |
| | | { |
| | | struct sigaction act; |
| | | |
| | | if( !filename || strlen(filename)<=0 ) |
| | | { |
| | | fprintf(stderr, "%s() invalid input arguments\n", __FUNCTION__); |
| | | return -1; |
| | | } |
| | | |
| | | memset(g_logger, 0, sizeof(st_logger)); |
| | | |
| | | strncpy(g_logger->file, filename, FILENAME_LEN); |
| | | g_logger->level = level; |
| | | g_logger->size = log_size; |
| | | |
| | | log_rollback_size = g_logger->size <= 0 ? LOG_ROLLBACK_NONE : g_logger->size*1024; /* Unit KiB */ |
| | | |
| | | |
| | | /* logger to console, just need point to standard error */ |
| | | if (!strcmp(g_logger->file, DBG_LOG_FILE)) |
| | | { |
| | | g_logger->fp = stderr; |
| | | log_rollback_size = LOG_ROLLBACK_NONE; |
| | | g_logger->flag |= LOGGER_CONSOLE; |
| | | goto OUT; |
| | | } |
| | | |
| | | g_logger->fp = fopen(g_logger->file, "a+"); |
| | | if ( !g_logger->fp ) |
| | | { |
| | | fprintf(stderr, "Open log file \"%s\" failure\n", g_logger->file); |
| | | return -2; |
| | | } |
| | | |
| | | OUT: |
| | | act.sa_handler = logger_default_signal_handler; |
| | | sigemptyset(&act.sa_mask); |
| | | act.sa_flags = 0; |
| | | sigaction(SIGHUP, &act, NULL); |
| | | |
| | | logger_banner("\nInitialize"); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void logger_raw(const char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if ( !g_logger->fp ) |
| | | return; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | va_start(argp, fmt); |
| | | vfprintf(g_logger->fp, fmt, argp); |
| | | va_end(argp); |
| | | } |
| | | |
| | | |
| | | void logger_term(void) |
| | | { |
| | | if ( !g_logger->fp ) |
| | | return; |
| | | |
| | | logger_banner("\nTerminate"); |
| | | logger_raw("\n\n"); |
| | | |
| | | fflush(g_logger->fp); |
| | | |
| | | fclose(g_logger->fp); |
| | | g_logger->fp = NULL; |
| | | |
| | | memset(g_logger, 0, sizeof(*g_logger)); |
| | | |
| | | return ; |
| | | } |
| | | |
| | | |
| | | int logger_reopen(void) |
| | | { |
| | | int rc = 0; |
| | | |
| | | if (g_logger->flag & LOGGER_CONSOLE ) |
| | | { |
| | | fflush(g_logger->fp); |
| | | g_logger->fp = stderr; |
| | | return 0; |
| | | } |
| | | |
| | | if( g_logger->fp ) |
| | | { |
| | | logger_banner("\nClose"); |
| | | fflush(g_logger->fp); |
| | | |
| | | g_logger->fp = fopen(g_logger->file, "a+"); |
| | | |
| | | if ( !g_logger->fp ) |
| | | rc = -2; |
| | | } |
| | | else |
| | | { |
| | | rc = -3; |
| | | } |
| | | |
| | | if (!rc) |
| | | { |
| | | logger_banner("\nReopen"); |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | static void logger_printout(char *level, char *fmt, va_list argp) |
| | | { |
| | | char buf[MAX_LOG_MESSAGE_LEN]; |
| | | struct tm *local; |
| | | struct timeval now; |
| | | char timestr[256]; |
| | | |
| | | pthread_t tid; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | #ifdef MULTHREADS |
| | | tid = pthread_self(); |
| | | #else |
| | | tid = getpid(); |
| | | #endif |
| | | |
| | | gettimeofday(&now, NULL); |
| | | local = localtime(&now.tv_sec); |
| | | |
| | | strftime(timestr, 256, log_time_format, local); |
| | | vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s.%03ld [%s] [%06lu]: %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, buf); |
| | | #endif |
| | | |
| | | if (g_logger->fp) |
| | | fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, |
| | | level, tid, buf); |
| | | |
| | | if (g_logger->fp) |
| | | fflush(g_logger->fp); |
| | | } |
| | | |
| | | static void logger_printout_line(char *level, char *fmt, char *file, int line, va_list argp) |
| | | { |
| | | char buf[MAX_LOG_MESSAGE_LEN]; |
| | | struct tm *local; |
| | | struct timeval now; |
| | | char timestr[256]; |
| | | |
| | | pthread_t tid; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | #ifdef MULTHREADS |
| | | tid = pthread_self(); |
| | | #else |
| | | tid = getpid(); |
| | | #endif |
| | | |
| | | gettimeofday(&now, NULL); |
| | | local = localtime(&now.tv_sec); |
| | | |
| | | strftime(timestr, 256, log_time_format, local); |
| | | vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); |
| | | #endif |
| | | |
| | | if (g_logger->fp) |
| | | fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); |
| | | |
| | | if (g_logger->fp) |
| | | fflush(g_logger->fp); |
| | | } |
| | | |
| | | void logger_comm(int level, char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if ( level > g_logger->level ) |
| | | return; |
| | | |
| | | va_start(argp, fmt); |
| | | logger_printout(log_str[level], fmt, argp); |
| | | va_end(argp); |
| | | } |
| | | |
| | | void logger_line(int level, char *file, int line, char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if ( level > g_logger->level ) |
| | | return; |
| | | |
| | | va_start(argp, fmt); |
| | | logger_printout_line(log_str[level], fmt, file, line, argp); |
| | | |
| | | va_end(argp); |
| | | } |
| | | |
| | | #define LINELEN 81 |
| | | #define CHARS_PER_LINE 16 |
| | | static char *print_char = |
| | | " " |
| | | " " |
| | | " !\"#$%&'()*+,-./" |
| | | "0123456789:;<=>?" |
| | | "@ABCDEFGHIJKLMNO" |
| | | "PQRSTUVWXYZ[\\]^_" |
| | | "`abcdefghijklmno" |
| | | "pqrstuvwxyz{|}~ " |
| | | " " |
| | | " " |
| | | " ???????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????"; |
| | | |
| | | void logger_dump(int level, char *buf, int len) |
| | | { |
| | | int rc; |
| | | int idx; |
| | | char prn[LINELEN]; |
| | | char lit[CHARS_PER_LINE + 2]; |
| | | char hc[4]; |
| | | short line_done = 1; |
| | | |
| | | if ( level > g_logger->level ) |
| | | return; |
| | | |
| | | rc = len; |
| | | idx = 0; |
| | | lit[CHARS_PER_LINE] = '\0'; |
| | | |
| | | while (rc > 0) |
| | | { |
| | | if (line_done) |
| | | snprintf(prn, LINELEN, "%08X: ", idx); |
| | | |
| | | do |
| | | { |
| | | unsigned char c = buf[idx]; |
| | | snprintf(hc, 4, "%02X ", c); |
| | | strncat(prn, hc, LINELEN); |
| | | |
| | | lit[idx % CHARS_PER_LINE] = print_char[c]; |
| | | } |
| | | while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); |
| | | |
| | | line_done = (idx % CHARS_PER_LINE) == 0; |
| | | if (line_done) |
| | | { |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s %s\n", prn, lit); |
| | | #endif |
| | | if (g_logger->fp) |
| | | fprintf(g_logger->fp, "%s %s\n", prn, lit); |
| | | } |
| | | } |
| | | |
| | | if (!line_done) |
| | | { |
| | | int ldx = idx % CHARS_PER_LINE; |
| | | lit[ldx++] = print_char[(int)buf[idx]]; |
| | | lit[ldx] = '\0'; |
| | | |
| | | while ((++idx % CHARS_PER_LINE) != 0) |
| | | strncat(prn, " ", LINELEN); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s %s\n", prn, lit); |
| | | #endif |
| | | if (g_logger->fp) |
| | | fprintf(g_logger->fp, "%s %s\n", prn, lit); |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: logger.h |
| | | * Description: This file is the linux infrastructural logger system library |
| | | * |
| | | * Version: 1.0.0(08/08/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/08/2018 05:16:56 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __LOGGER_H_ |
| | | #define __LOGGER_H_ |
| | | |
| | | #include <stdarg.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | |
| | | #include <pthread.h> |
| | | #include <sys/types.h> |
| | | #include <sys/time.h> |
| | | |
| | | #define LOG_VERSION_STR "2.0.0" |
| | | |
| | | #ifndef FILENAME_LEN |
| | | #define FILENAME_LEN 64 |
| | | #endif |
| | | |
| | | #define DEFAULT_LOGFILE "logger.log" |
| | | #define DBG_LOG_FILE "console" /* Debug mode log file is console */ |
| | | |
| | | #define LOG_ROLLBACK_SIZE 512 /* Default rollback log size */ |
| | | #define LOG_ROLLBACK_NONE 0 /* Set rollback size to 0 will not rollback */ |
| | | |
| | | #define MAX_LOG_MESSAGE_LEN 0x1000 |
| | | |
| | | //#define DUMPLICATE_OUTPUT /* Log to file and printf on console */ |
| | | #define LOG_FILE_LINE /* Log the file and line */ |
| | | |
| | | enum |
| | | { |
| | | LOG_LEVEL_DISB = 0, /* Disable "Debug" */ |
| | | LOG_LEVEL_FATAL, /* Debug Level "Fatal" */ |
| | | LOG_LEVEL_ERROR, /* Debug Level "ERROR" */ |
| | | LOG_LEVEL_WARN, /* Debug Level "warnning" */ |
| | | LOG_LEVEL_NRML, /* Debug Level "Normal" */ |
| | | LOG_LEVEL_DEBUG, /* Debug Level "Debug" */ |
| | | LOG_LEVEL_INFO, /* Debug Level "Information" */ |
| | | LOG_LEVEL_TRACE, /* Debug Level "Trace" */ |
| | | LOG_LEVEL_MAX, |
| | | }; |
| | | |
| | | #define LOGGER_CONSOLE 1<<1 |
| | | #define LOGGER_FILE 0<<1 |
| | | |
| | | #define LOGGER_LEVEL_OPT 1<<2 /* The log level is sepcified by the command option */ |
| | | typedef struct _st_logger |
| | | { |
| | | unsigned char flag; /* This logger pointer is malloc() or passed by argument */ |
| | | char file[FILENAME_LEN]; |
| | | int level; |
| | | int size; |
| | | |
| | | FILE *fp; |
| | | } st_logger; |
| | | |
| | | |
| | | extern int logger_init(char *filename, int level, int log_size); |
| | | extern int logger_reopen(void); |
| | | |
| | | extern void logger_term(void); |
| | | |
| | | extern void logger_comm(int level, char *fmt, ...); |
| | | extern void logger_line(int level, char *file, int line, char *fmt, ...); |
| | | |
| | | extern void logger_dump(int level, char *buf, int len); |
| | | |
| | | #ifdef LOG_FILE_LINE |
| | | #define log_trace(fmt, ...) logger_line(LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_info(fmt, ...) logger_line(LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_dbg(fmt, ...) logger_line(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_nrml(fmt, ...) logger_line(LOG_LEVEL_NRML, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_warn(fmt, ...) logger_line(LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_err(fmt, ...) logger_line(LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_fatal(fmt, ...) logger_line(LOG_LEVEL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #else |
| | | #define log_trace(fmt, ...) logger_comm(LOG_LEVEL_TRACE, fmt, ##__VA_ARGS__) |
| | | #define log_info(fmt, ...) logger_comm(tLOG_LEVEL_INFO, fmt, ##__VA_ARGS__) |
| | | #define log_dbg(fmt, ...) logger_comm(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__) |
| | | #define log_nrml(fmt, ...) logger_comm(LOG_LEVEL_NRML, fmt, ##__VA_ARGS__) |
| | | #define log_warn(fmt, ...) logger_comm(LOG_LEVEL_WARN, fmt, ##__VA_ARGS__) |
| | | #define log_err(fmt, ...) logger_comm(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__) |
| | | #define log_fatal(fmt, ...) logger_comm(LOG_LEVEL_FATAL, fmt, ##__VA_ARGS__) |
| | | #endif |
| | | |
| | | |
| | | #endif /* __LOGGER_H_ */ |
New file |
| | |
| | | |
| | | PWD=$(shell pwd ) |
| | | |
| | | LIBNAME=$(shell basename ${PWD} ) |
| | | PROJPATH=$(shell dirname ${PWD} ) |
| | | |
| | | CFLAGS+=-I${PROJPATH} |
| | | |
| | | all: clean |
| | | @rm -f *.o |
| | | @${CROSS_COMPILE}gcc ${CFLAGS} -c *.c |
| | | ${CROSS_COMPILE}ar -rcs lib${LIBNAME}.a *.o |
| | | |
| | | clean: |
| | | @rm -f *.o |
| | | @rm -f *.a |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_proc.c |
| | | * Description: This file is the process API |
| | | * |
| | | * Version: 1.0.0(11/06/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/06/2018 09:19:02 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <libgen.h> |
| | | #include <fcntl.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | |
| | | #include "proc.h" |
| | | #include "logger.h" |
| | | |
| | | st_sigproc g_signal={0}; |
| | | |
| | | void proc_sighandler(int sig) |
| | | { |
| | | switch(sig) |
| | | { |
| | | case SIGINT: |
| | | log_warn("SIGINT - stopping\n"); |
| | | g_signal.stop = 1; |
| | | break; |
| | | |
| | | case SIGTERM: |
| | | //log_warn("SIGTERM - stopping\n"); |
| | | g_signal.stop = 1; |
| | | break; |
| | | #if 0 |
| | | case SIGSEGV: |
| | | log_err("SIGSEGV - stopping\n"); |
| | | if(g_signal.stop) |
| | | exit(0); |
| | | |
| | | g_signal.stop = 1; |
| | | break; |
| | | #endif |
| | | |
| | | case SIGPIPE: |
| | | log_warn("SIGPIPE - warnning\n"); |
| | | g_signal.stop = 1; |
| | | break; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | void install_proc_signal(void) |
| | | { |
| | | struct sigaction sigact, sigign; |
| | | |
| | | log_nrml("Install default signal handler.\n"); |
| | | |
| | | /* Initialize the catch signal structure. */ |
| | | sigemptyset(&sigact.sa_mask); |
| | | sigact.sa_flags = 0; |
| | | sigact.sa_handler = proc_sighandler; |
| | | |
| | | /* Setup the ignore signal. */ |
| | | sigemptyset(&sigign.sa_mask); |
| | | sigign.sa_flags = 0; |
| | | sigign.sa_handler = SIG_IGN; |
| | | |
| | | sigaction(SIGTERM, &sigact, 0); /* catch terminate signal "kill" command */ |
| | | sigaction(SIGINT, &sigact, 0); /* catch interrupt signal CTRL+C */ |
| | | //sigaction(SIGSEGV, &sigact, 0); /* catch segmentation faults */ |
| | | sigaction(SIGPIPE, &sigact, 0); /* catch broken pipe */ |
| | | #if 0 |
| | | sigaction(SIGCHLD, &sigact, 0); /* catch child process return */ |
| | | sigaction(SIGUSR2, &sigact, 0); /* catch USER signal */ |
| | | #endif |
| | | } |
| | | |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: daemonize |
| | | * Description : Set the programe runs as daemon in background |
| | | * Inputs : nodir: DON'T change the work directory to / : 1:NoChange 0:Change |
| | | * noclose: close the opened file descrtipion or not 1:Noclose 0:Close |
| | | * Output : NONE |
| | | * Return : NONE |
| | | * *****************************************************************************/ |
| | | void daemonize(int nochdir, int noclose) |
| | | { |
| | | int retval, fd; |
| | | int i; |
| | | |
| | | /* already a daemon */ |
| | | if (1 == getppid()) |
| | | return; |
| | | |
| | | /* fork error */ |
| | | retval = fork(); |
| | | if (retval < 0) exit(1); |
| | | |
| | | /* parent process exit */ |
| | | if (retval > 0) |
| | | exit(0); |
| | | |
| | | /* obtain a new process session group */ |
| | | setsid(); |
| | | |
| | | if (!noclose) |
| | | { |
| | | /* close all descriptors */ |
| | | for (i = getdtablesize(); i >= 0; --i) |
| | | { |
| | | //if (i != g_logPtr->fd) |
| | | close(i); |
| | | } |
| | | |
| | | /* Redirect Standard input [0] to /dev/null */ |
| | | fd = open("/dev/null", O_RDWR); |
| | | |
| | | /* Redirect Standard output [1] to /dev/null */ |
| | | dup(fd); |
| | | |
| | | /* Redirect Standard error [2] to /dev/null */ |
| | | dup(fd); |
| | | } |
| | | |
| | | umask(0); |
| | | |
| | | if (!nochdir) |
| | | chdir("/"); |
| | | |
| | | return; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: record_daemon_pid |
| | | * Description : Record the running daemon program PID to the file "pid_file" |
| | | * Inputs : pid_file:The record PID file path |
| | | * Output : NONE |
| | | * Return : 0: Record successfully Else: Failure |
| | | * *****************************************************************************/ |
| | | int record_daemon_pid(const char *pid_file) |
| | | { |
| | | struct stat fStatBuf; |
| | | int fd = -1; |
| | | int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU; |
| | | char ipc_dir[64] = { 0 }; |
| | | |
| | | strncpy(ipc_dir, pid_file, 64); |
| | | |
| | | /* dirname() will modify ipc_dir and save the result */ |
| | | dirname(ipc_dir); |
| | | |
| | | /* If folder pid_file PATH doesnot exist, then we will create it" */ |
| | | if (stat(ipc_dir, &fStatBuf) < 0) |
| | | { |
| | | if (mkdir(ipc_dir, mode) < 0) |
| | | { |
| | | log_fatal("cannot create %s: %s\n", ipc_dir, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | (void)chmod(ipc_dir, mode); |
| | | } |
| | | |
| | | /* Create the process running PID file */ |
| | | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; |
| | | if ((fd = open(pid_file, O_RDWR | O_CREAT | O_TRUNC, mode)) >= 0) |
| | | { |
| | | char pid[PID_ASCII_SIZE]; |
| | | snprintf(pid, sizeof(pid), "%u\n", (unsigned)getpid()); |
| | | write(fd, pid, strlen(pid)); |
| | | close(fd); |
| | | |
| | | log_dbg("Record PID<%u> to file %s.\n", getpid(), pid_file); |
| | | } |
| | | else |
| | | { |
| | | log_fatal("cannot create %s: %s\n", pid_file, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: get_daemon_pid |
| | | * Description : Get the daemon process PID from the PID record file "pid_file" |
| | | * Inputs : pid_file: the PID record file |
| | | * Output : NONE |
| | | * Return : pid_t: The daemon process PID number |
| | | * *****************************************************************************/ |
| | | pid_t get_daemon_pid(const char *pid_file) |
| | | { |
| | | FILE *f; |
| | | pid_t pid; |
| | | |
| | | if ((f = fopen(pid_file, "rb")) != NULL) |
| | | { |
| | | char pid_ascii[PID_ASCII_SIZE]; |
| | | (void)fgets(pid_ascii, PID_ASCII_SIZE, f); |
| | | (void)fclose(f); |
| | | pid = atoi(pid_ascii); |
| | | } |
| | | else |
| | | { |
| | | log_fatal("Can't open PID record file %s: %s\n", pid_file, strerror(errno)); |
| | | return -1; |
| | | } |
| | | return pid; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: check_daemon_running |
| | | * Description : Check the daemon program already running or not |
| | | * Inputs : pid_file: The record running daemon program PID |
| | | * Output : NONE |
| | | * Return : 1: The daemon program alread running 0: Not running |
| | | * *****************************************************************************/ |
| | | int check_daemon_running(const char *pid_file) |
| | | { |
| | | int retVal = -1; |
| | | struct stat fStatBuf; |
| | | |
| | | retVal = stat(pid_file, &fStatBuf); |
| | | if (0 == retVal) |
| | | { |
| | | pid_t pid = -1; |
| | | printf("PID record file \"%s\" exist.\n", pid_file); |
| | | |
| | | pid = get_daemon_pid(pid_file); |
| | | if (pid > 0) /* Process pid exist */ |
| | | { |
| | | if ((retVal = kill(pid, 0)) == 0) |
| | | { |
| | | printf("Program with PID[%d] seems running.\n", pid); |
| | | return 1; |
| | | } |
| | | else /* Send signal to the old process get no reply. */ |
| | | { |
| | | printf("Program with PID[%d] seems exit.\n", pid); |
| | | remove(pid_file); |
| | | return 0; |
| | | } |
| | | } |
| | | else if (0 == pid) |
| | | { |
| | | printf("Can not read program PID form record file.\n"); |
| | | remove(pid_file); |
| | | return 0; |
| | | } |
| | | else /* Read pid from file "pid_file" failure */ |
| | | { |
| | | printf("Read record file \"%s\" failure, maybe program still running.\n", pid_file); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: set_daemon_running |
| | | * Description : Set the programe running as daemon if it's not running and record |
| | | * its PID to the pid_file. |
| | | * Inputs : pid_file: The record running daemon program PID |
| | | * Output : NONE |
| | | * Return : 0: Successfully. 1: Failure |
| | | * *****************************************************************************/ |
| | | int set_daemon_running(const char *pid_file) |
| | | { |
| | | daemonize(0, 1); |
| | | log_nrml("Program running as daemon [PID:%d].\n", getpid()); |
| | | |
| | | if (record_daemon_pid(pid_file) < 0) |
| | | { |
| | | log_fatal("Record PID to file \"%s\" failure.\n", pid_file); |
| | | return -2; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int thread_start(pthread_t * thread_id, thread_function* thread_workbody, void *thread_arg) |
| | | { |
| | | int retval = 0; |
| | | |
| | | pthread_attr_t thread_attr; |
| | | |
| | | /* Initialize the thread attribute */ |
| | | retval = pthread_attr_init(&thread_attr); |
| | | if(retval) |
| | | return -1; |
| | | |
| | | /* Set the stack size of the thread */ |
| | | retval = pthread_attr_setstacksize(&thread_attr, 120 * 1024); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | /* Set thread to detached state:Don`t need pthread_join */ |
| | | retval = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | /* Create the thread */ |
| | | retval = pthread_create(thread_id, &thread_attr, thread_workbody, thread_arg); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | CleanUp: |
| | | /* Destroy the attributes of thread */ |
| | | pthread_attr_destroy(&thread_attr); |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | void exec_system_cmd(const char *format, ...) |
| | | { |
| | | char cmd[256]; |
| | | va_list args; |
| | | int done; |
| | | |
| | | memset(cmd, 0, sizeof(cmd)); |
| | | |
| | | va_start(args, format); |
| | | done = vsnprintf(cmd, sizeof(cmd), format, args); |
| | | va_end(args); |
| | | |
| | | system(cmd); |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: proc.h |
| | | * Description: This head file is for Linux process API |
| | | * |
| | | * Version: 1.0.0(11/06/2018~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/06/2018 09:21:33 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_PROC_H |
| | | #define __CP_PROC_H |
| | | |
| | | #include <signal.h> |
| | | |
| | | #define PID_ASCII_SIZE 11 |
| | | |
| | | typedef struct _st_sigproc |
| | | { |
| | | int signal; |
| | | unsigned stop; /* 0: Not term 1: Stop */ |
| | | } st_sigproc; |
| | | |
| | | |
| | | /* global variable for process or thread to exit */ |
| | | extern st_sigproc g_signal; |
| | | |
| | | /* install signal handler */ |
| | | extern void install_proc_signal(void); |
| | | |
| | | /* record process PID into $pid_file for check_daemon_running() to check program running or not */ |
| | | extern int record_daemon_pid(const char *pid_file); |
| | | |
| | | /* check program already running or not |
| | | * 1: The daemon program alread running 0: Not running |
| | | */ |
| | | extern int check_daemon_running(const char *pid_file); |
| | | |
| | | /* set program running as daemon */ |
| | | extern int set_daemon_running(const char *pid_file); |
| | | |
| | | /* create a system command and excute it */ |
| | | extern void exec_system_cmd(const char *format, ...); |
| | | |
| | | /* create and start a thread to excute function pointed by $thread_workbody */ |
| | | typedef void *(thread_function) (void *thread_arg); |
| | | extern int thread_start(pthread_t * thread_id, thread_function * thread_workbody, void *thread_arg); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: main.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(29/01/19) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "29/01/19 15:34:41" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <stdio.h> |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | #include <getopt.h> |
| | | #include <libgen.h> |
| | | #include <string.h> |
| | | |
| | | #include <mosquitto.h> |
| | | |
| | | #include "logger.h" |
| | | #include "cJSON.h" |
| | | #include "proc.h" |
| | | |
| | | #include "conf.h" |
| | | |
| | | #define PROG_VERSION "v1.0.0" |
| | | #define DAEMON_PIDFILE "/tmp/.mqtt.pid" |
| | | |
| | | int check_set_program_running(int daemon); |
| | | void *mqtt_sub_worker(void *args); |
| | | |
| | | static void program_usage(char *progname) |
| | | { |
| | | |
| | | printf("Usage: %s [OPTION]...\n", progname); |
| | | printf(" %s is LingYun studio MQTT daemon program running on RaspberryPi\n", progname); |
| | | |
| | | printf("\nMandatory arguments to long options are mandatory for short options too:\n"); |
| | | printf(" -d[debug ] Running in debug mode\n"); |
| | | printf(" -c[conf ] Specify configure file\n"); |
| | | printf(" -h[help ] Display this help information\n"); |
| | | printf(" -v[version ] Display the program version\n"); |
| | | |
| | | printf("\n%s version %s\n", progname, PROG_VERSION); |
| | | return; |
| | | } |
| | | |
| | | |
| | | int main (int argc, char **argv) |
| | | { |
| | | float temp; |
| | | float rh; |
| | | int daemon = 1; |
| | | pthread_t tid; |
| | | mqtt_ctx_t ctx; |
| | | char *conf_file=NULL; |
| | | int debug = 0; |
| | | int opt; |
| | | char *progname=NULL; |
| | | |
| | | struct option long_options[] = { |
| | | {"conf", required_argument, NULL, 'c'}, |
| | | {"debug", no_argument, NULL, 'd'}, |
| | | {"version", no_argument, NULL, 'v'}, |
| | | {"help", no_argument, NULL, 'h'}, |
| | | {NULL, 0, NULL, 0} |
| | | }; |
| | | |
| | | progname = (char *)basename(argv[0]); |
| | | |
| | | /* Parser the command line parameters */ |
| | | while ((opt = getopt_long(argc, argv, "c:dvh", long_options, NULL)) != -1) |
| | | { |
| | | switch (opt) |
| | | { |
| | | case 'c': /* Set configure file */ |
| | | conf_file = optarg; |
| | | break; |
| | | |
| | | case 'd': /* Set debug running */ |
| | | daemon = 0; |
| | | debug = 1; |
| | | break; |
| | | |
| | | case 'v': /* Get software version */ |
| | | printf("%s version %s\n", progname, PROG_VERSION); |
| | | return 0; |
| | | |
| | | case 'h': /* Get help information */ |
| | | program_usage(progname); |
| | | return 0; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | if( !conf_file ) |
| | | debug = 1; |
| | | |
| | | if( mqttd_parser_conf(conf_file, &ctx, debug)<0 ) |
| | | { |
| | | fprintf(stderr, "Parser mqtted configure file failure\n"); |
| | | return -2; |
| | | } |
| | | |
| | | install_proc_signal(); |
| | | |
| | | if( check_set_program_running(daemon) < 0 ) |
| | | goto OUT; |
| | | |
| | | if( !debug ) |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | if( thread_start(&tid, mqtt_sub_worker, &ctx ) < 0 ) |
| | | { |
| | | log_fatal("Start MQTT subsciber worker thread failure\n"); |
| | | goto OUT; |
| | | } |
| | | log_nrml("Start MQTT subsciber worker thread ok\n"); |
| | | |
| | | while( ! g_signal.stop ) |
| | | { |
| | | sleep(1); |
| | | //log_nrml("Main control thread continue running\n"); |
| | | } |
| | | |
| | | |
| | | OUT: |
| | | mosquitto_lib_cleanup(); |
| | | logger_term(); |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
| | | |
| | | int check_set_program_running(int daemon) |
| | | { |
| | | if( check_daemon_running(DAEMON_PIDFILE) ) |
| | | { |
| | | log_err("Program already running, process exit now"); |
| | | return -1; |
| | | } |
| | | |
| | | if( daemon ) |
| | | { |
| | | if( set_daemon_running(DAEMON_PIDFILE) < 0 ) |
| | | { |
| | | log_err("set program running as daemon failure\n"); |
| | | return -2; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if( record_daemon_pid(DAEMON_PIDFILE) < 0 ) |
| | | { |
| | | log_err("record program running PID failure\n"); |
| | | return -3; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | void sub_connect_callback(struct mosquitto *mosq, void *userdata, int result) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata; |
| | | |
| | | if( result ) |
| | | { |
| | | log_err("Subscriber connect to broker server failed, rv=%d\n", result); |
| | | return ; |
| | | } |
| | | |
| | | log_nrml("Subscriber connect to broker server[%s:%d] successfully\n", ctx->host, ctx->port); |
| | | mosquitto_subscribe(mosq, NULL, ctx->subTopic, ctx->subQos); |
| | | } |
| | | |
| | | void sub_disconnect_callback(struct mosquitto *mosq, void *userdata, int result) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata; |
| | | |
| | | log_warn("Subscriber disconnect to broker server[%s:%d], reason=%d\n", ctx->host, ctx->port, result); |
| | | } |
| | | |
| | | |
| | | void proc_json_items(cJSON *root) |
| | | { |
| | | int i; |
| | | char *value; |
| | | cJSON *item; |
| | | cJSON *array; |
| | | |
| | | if( !root ) |
| | | { |
| | | log_err("Invalid input arguments $root\n"); |
| | | return ; |
| | | } |
| | | |
| | | for( i=0; i<cJSON_GetArraySize(root); i++ ) |
| | | { |
| | | item = cJSON_GetArrayItem(root, i); |
| | | if( !item ) |
| | | break; |
| | | |
| | | /* if item is cJSON_Object, then recursive call proc_json */ |
| | | if( cJSON_Object == item->type ) |
| | | { |
| | | proc_json_items(item); |
| | | } |
| | | else if( cJSON_Array == item->type ) |
| | | { |
| | | /* Logic C920 camera control */ |
| | | if( !strcasecmp(item->string, "camera") ) |
| | | { |
| | | array = cJSON_GetArrayItem(item, 0); |
| | | if( NULL != array ) |
| | | { |
| | | cJSON *led_item; |
| | | |
| | | if( NULL != (led_item=cJSON_GetObjectItem(array , "C920")) ) |
| | | { |
| | | log_nrml("turn Logic C920 camera '%s'\n", led_item->valuestring); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | void sub_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) |
| | | { |
| | | cJSON *root = NULL; |
| | | char *out; |
| | | |
| | | |
| | | if ( !message->payloadlen ) |
| | | { |
| | | log_err("%s (null)\n", message->topic); |
| | | return ; |
| | | } |
| | | |
| | | log_nrml("Subscriber receive message: '%s'\n", message->payload); |
| | | |
| | | root = cJSON_Parse(message->payload); |
| | | if( !root ) |
| | | { |
| | | log_err("cJSON_Parse parser failure: %s\n", cJSON_GetErrorPtr()); |
| | | return ; |
| | | } |
| | | |
| | | proc_json_items(root); |
| | | |
| | | cJSON_Delete(root); /* must delete it, or it will result memory leak */ |
| | | return ; |
| | | } |
| | | |
| | | |
| | | void *mqtt_sub_worker(void *args) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)args; |
| | | struct mosquitto *mosq; |
| | | bool session = true; |
| | | |
| | | mosq = mosquitto_new(NULL, session, ctx); |
| | | if( !mosq ) |
| | | { |
| | | log_err("mosquitto_new failure\n"); |
| | | return NULL; |
| | | } |
| | | |
| | | /* set connnect to broker username and password */ |
| | | if( strlen(ctx->uid)> 0 && strlen(ctx->pwd)> 0 ) |
| | | mosquitto_username_pw_set(mosq, ctx->uid, ctx->pwd); |
| | | |
| | | /* set callback functions */ |
| | | mosquitto_connect_callback_set(mosq, sub_connect_callback); |
| | | mosquitto_disconnect_callback_set(mosq, sub_disconnect_callback); |
| | | mosquitto_message_callback_set(mosq, sub_message_callback); |
| | | |
| | | while( !g_signal.stop ) |
| | | { |
| | | /* connect to MQTT broker */ |
| | | if( mosquitto_connect(mosq, ctx->host, ctx->port, ctx->keepalive) ) |
| | | { |
| | | log_err("Subscriber connect to broker[%s:%d] failure: %s\n", ctx->host, ctx->port, strerror(errno)); |
| | | sleep(1); |
| | | continue; |
| | | } |
| | | |
| | | /* -1: use default timeout 1000ms 1: unused */ |
| | | mosquitto_loop_forever(mosq, -1, 1); |
| | | } |
| | | |
| | | mosquitto_destroy(mosq); |
| | | return NULL; |
| | | } |
| | | |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292> |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This Makefile used to compile all the C source code file in current |
| | | # folder to one excutable binary files. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "11/11/2011 01:29:33 PM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | IMAGE_NAME=mqttd |
| | | |
| | | PWD=$(shell pwd) |
| | | INSTPATH=/usr/bin |
| | | |
| | | CFLAGS+=-I${PWD} |
| | | #CFLAGS+=-Wall -Werror |
| | | |
| | | MQTT_LIBPATH=mosquitto |
| | | |
| | | LDFLAGS+=-lwiringPi |
| | | LDFLAGS+=-lpthread |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | CFLAGS+=-Ietc -Ilylib |
| | | LDFLAGS+=-Letc -letc -Llylib -llylib |
| | | |
| | | LDFLAGS+=-lmosquitto -lpthread -lm |
| | | |
| | | SRCFILES = $(wildcard *.c) |
| | | |
| | | all: entry modules binary |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile \"${BINARIES}\" for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | modules: |
| | | make -C lylib |
| | | make -C etc |
| | | cd ${MQTT_LIBPATH} && bash build.sh |
| | | |
| | | binary: ${SRCFILES} |
| | | $(CC) $(CFLAGS) -o ${IMAGE_NAME} $^ ${LDFLAGS} |
| | | @echo " Compile over" |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @cp $(IMAGE_NAME) ${INSTPATH} |
| | | |
| | | clean: |
| | | @make clean -C etc |
| | | @make clean -C lylib |
| | | @rm -f version.h |
| | | @rm -f *.o $(IMAGE_NAME) |
| | | @rm -rf *.gdb *.a *.so *.elf* |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
| | | |
New file |
| | |
| | | #!/bin/bash |
| | | |
| | | MQTT_LIB=mosquitto-1.6.3 |
| | | |
| | | LIBPATH=/usr/local/lib/libmosquitto.so |
| | | |
| | | if [ -f ${LIBPATH} ] ; then |
| | | echo "${MQTT_LIB} already installed" |
| | | exit 0; |
| | | fi |
| | | |
| | | |
| | | if [ ! -d $MQTT_LIB ] ; then |
| | | if [ ! -f ${MQTT_LIB}.tar.gz ] ; then |
| | | wget https://mosquitto.org/files/source/${MQTT_LIB}.tar.gz |
| | | fi |
| | | |
| | | if [ ! -f ${MQTT_LIB}.tar.gz ] ; then |
| | | echo "## ERROR: MQTT Library ${MQTT_LIB}.tar.gz not exist or download failure!" |
| | | exit 1; |
| | | fi |
| | | |
| | | tar -xzf ${MQTT_LIB}.tar.gz |
| | | fi |
| | | |
| | | if [ ! -d $MQTT_LIB ] ; then |
| | | echo "## ERROR: MQTT Library ${MQTT_LIB} not exist or decompress failure!" |
| | | exit 2; |
| | | fi |
| | | |
| | | cd $MQTT_LIB |
| | | |
| | | make install |
| | | if [ $? != 0 ] ; then |
| | | echo "ERROR: MQTT Library ${MQTT_LIB} failure!" |
| | | exit 3; |
| | | fi |
New file |
| | |
| | | # This is a cmake script. Process it with the CMake gui or command line utility |
| | | # to produce makefiles / Visual Studio project files on Mac OS X and Windows. |
| | | # |
| | | # To configure the build options either use the CMake gui, or run the command |
| | | # line utility including the "-i" option. |
| | | |
| | | set(CMAKE_LEGACY_CYGWIN_WIN32 0) |
| | | |
| | | project(mosquitto) |
| | | |
| | | cmake_minimum_required(VERSION 2.8) |
| | | # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) |
| | | |
| | | set (VERSION 1.6.3) |
| | | |
| | | add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") |
| | | |
| | | if (WIN32) |
| | | add_definitions("-D_CRT_SECURE_NO_WARNINGS") |
| | | add_definitions("-D_CRT_NONSTDC_NO_DEPRECATE") |
| | | endif (WIN32) |
| | | |
| | | include(GNUInstallDirs) |
| | | |
| | | option(WITH_TLS |
| | | "Include SSL/TLS support?" ON) |
| | | option(WITH_TLS_PSK |
| | | "Include TLS-PSK support (requires WITH_TLS)?" ON) |
| | | option(WITH_EC |
| | | "Include Elliptic Curve support (requires WITH_TLS)?" ON) |
| | | if (WITH_TLS) |
| | | find_package(OpenSSL REQUIRED) |
| | | add_definitions("-DWITH_TLS") |
| | | |
| | | if (WITH_TLS_PSK) |
| | | add_definitions("-DWITH_TLS_PSK") |
| | | endif (WITH_TLS_PSK) |
| | | |
| | | if (WITH_EC) |
| | | add_definitions("-DWITH_EC") |
| | | endif (WITH_EC) |
| | | else (WITH_TLS) |
| | | set (OPENSSL_INCLUDE_DIR "") |
| | | endif (WITH_TLS) |
| | | |
| | | option(WITH_SOCKS "Include SOCKS5 support?" ON) |
| | | if (WITH_SOCKS) |
| | | add_definitions("-DWITH_SOCKS") |
| | | endif (WITH_SOCKS) |
| | | |
| | | option(WITH_SRV "Include SRV lookup support?" OFF) |
| | | |
| | | option(WITH_THREADING "Include client library threading support?" ON) |
| | | if (WITH_THREADING) |
| | | add_definitions("-DWITH_THREADING") |
| | | if (WIN32) |
| | | if (CMAKE_CL_64) |
| | | set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x64\\pthreadVC2.lib) |
| | | else (CMAKE_CL_64) |
| | | set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x86\\pthreadVC2.lib) |
| | | endif (CMAKE_CL_64) |
| | | set (PTHREAD_INCLUDE_DIR C:\\pthreads\\Pre-built.2\\include) |
| | | else (WIN32) |
| | | find_library(LIBPTHREAD pthread) |
| | | if (LIBPTHREAD) |
| | | set (PTHREAD_LIBRARIES pthread) |
| | | else (LIBPTHREAD) |
| | | set (PTHREAD_LIBRARIES "") |
| | | endif() |
| | | set (PTHREAD_INCLUDE_DIR "") |
| | | endif (WIN32) |
| | | else (WITH_THREADING) |
| | | set (PTHREAD_LIBRARIES "") |
| | | set (PTHREAD_INCLUDE_DIR "") |
| | | endif (WITH_THREADING) |
| | | |
| | | option(DOCUMENTATION "Build documentation?" ON) |
| | | |
| | | option(WITH_DLT "Include DLT support?" OFF) |
| | | message(STATUS "WITH_DLT = ${WITH_DLT}") |
| | | if (WITH_DLT) |
| | | #find_package(DLT REQUIRED) |
| | | find_package(PkgConfig) |
| | | pkg_check_modules(DLT "automotive-dlt >= 2.11") |
| | | add_definitions("-DWITH_DLT") |
| | | endif (WITH_DLT) |
| | | |
| | | # ======================================== |
| | | # Include projects |
| | | # ======================================== |
| | | |
| | | add_subdirectory(lib) |
| | | add_subdirectory(client) |
| | | add_subdirectory(src) |
| | | if (DOCUMENTATION) |
| | | add_subdirectory(man) |
| | | endif (DOCUMENTATION) |
| | | |
| | | # ======================================== |
| | | # Install config file |
| | | # ======================================== |
| | | |
| | | install(FILES mosquitto.conf aclfile.example pskfile.example pwfile.example DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/mosquitto") |
| | | |
| | | |
| | | # ======================================== |
| | | # Install pkg-config files |
| | | # ======================================== |
| | | |
| | | configure_file(libmosquitto.pc.in libmosquitto.pc @ONLY) |
| | | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquitto.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pkgconfig") |
| | | configure_file(libmosquittopp.pc.in libmosquittopp.pc @ONLY) |
| | | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquittopp.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pkgconfig") |
| | | |
| | | # ======================================== |
| | | # Testing |
| | | # ======================================== |
| | | enable_testing() |
New file |
| | |
| | | Contributing to Mosquitto |
| | | ========================= |
| | | |
| | | Thank you for your interest in this project. |
| | | |
| | | Project description: |
| | | -------------------- |
| | | |
| | | The Mosquitto project has been created to provide a light weight, open-source |
| | | implementation, of an MQTT broker to allow new, existing, and emerging |
| | | applications for Machine-to-Machine (M2M) and Internet of Things (IoT). |
| | | |
| | | - <https://mosquitto.org/> |
| | | - <https://projects.eclipse.org/projects/technology.mosquitto> |
| | | |
| | | |
| | | Source |
| | | ------ |
| | | |
| | | The Mosquitto code is stored in a git repository. |
| | | |
| | | - https://github.com/eclipse/mosquitto |
| | | |
| | | You can contribute bugfixes and new features by sending pull requests through GitHub. |
| | | |
| | | |
| | | ## Legal |
| | | |
| | | In order for your contribution to be accepted, it must comply with the Eclipse |
| | | Foundation IP policy. |
| | | |
| | | Please read the [Eclipse Foundation policy on accepting contributions via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git). |
| | | |
| | | 1. Sign the [Eclipse ECA](http://www.eclipse.org/legal/ECA.php) |
| | | 1. Register for an Eclipse Foundation User ID. You can register [here](https://accounts.eclipse.org/user/register). |
| | | 2. Log into the [Accounts Portal](https://accounts.eclipse.org/), and click on the '[Eclipse Contributor Agreement](https://accounts.eclipse.org/user/eca)' link. |
| | | 2. Go to your [account settings](https://accounts.eclipse.org/user/edit) and add your GitHub username to your account. |
| | | 3. Make sure that you _sign-off_ your Git commits in the following format: |
| | | ``` Signed-off-by: John Smith <johnsmith@nowhere.com> ``` This is usually at the bottom of the commit message. You can automate this by adding the '-s' flag when you make the commits. e.g. ```git commit -s -m "Adding a cool feature"``` |
| | | 4. Ensure that the email address that you make your commits with is the same one you used to sign up to the Eclipse Foundation website with. |
| | | |
| | | ## Contributing a change |
| | | |
| | | 1. [Fork the repository on GitHub](https://github.com/eclipse/mosquitto/fork) |
| | | 2. Clone the forked repository onto your computer: ``` git clone |
| | | https://github.com/<your username>/mosquitto.git ``` |
| | | 3. If you are adding a new feature, then create a new branch from the latest |
| | | ```develop``` branch with ```git checkout -b YOUR_BRANCH_NAME |
| | | origin/develop``` |
| | | 4. If you are fixing a bug, then create a new branch from the latest |
| | | ```fixes``` branch with ```git checkout -b YOUR_BRANCH_NAME origin/fixes``` |
| | | 5. Make your changes |
| | | 6. Ensure that all new and existing tests pass. |
| | | 7. Commit the changes into the branch: ``` git commit -s ``` Make sure that |
| | | your commit message is meaningful and describes your changes correctly. |
| | | 8. If you have a lot of commits for the change, squash them into a single / few |
| | | commits. |
| | | 9. Push the changes in your branch to your forked repository. |
| | | 10. Finally, go to |
| | | [https://github.com/eclipse/mosquitto](https://github.com/eclipse/mosquitto) |
| | | and create a pull request from your "YOUR_BRANCH_NAME" branch to the |
| | | ```develop``` or ```fixes``` branch as appropriate to request review and |
| | | merge of the commits in your pushed branch. |
| | | |
| | | |
| | | What happens next depends on the content of the patch. If it is 100% authored |
| | | by the contributor and is less than 1000 lines (and meets the needs of the |
| | | project), then it can be pulled into the main repository. If not, more steps |
| | | are required. These are detailed in the |
| | | [legal process poster](http://www.eclipse.org/legal/EclipseLegalProcessPoster.pdf). |
| | | |
| | | |
| | | |
| | | Contact: |
| | | -------- |
| | | |
| | | Contact the project developers via the project's development |
| | | [mailing list](https://dev.eclipse.org/mailman/listinfo/mosquitto-dev). |
| | | |
| | | Search for bugs: |
| | | ---------------- |
| | | |
| | | This project uses [Github](https://github.com/eclipse/mosquitto/issues) |
| | | to track ongoing development and issues. |
| | | |
| | | Create a new bug: |
| | | ----------------- |
| | | |
| | | Be sure to search for existing bugs before you create another one. Remember |
| | | that contributions are always welcome! |
| | | |
| | | - [Create new Mosquitto bug](https://github.com/eclipse/mosquitto/issues) |
New file |
| | |
| | | 1.6.3 - 20190618 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix detection of incoming v3.1/v3.1.1 bridges. Closes #1263. |
| | | - Fix default max_topic_alias listener config not being copied to the in-use |
| | | listener when compiled without TLS support. |
| | | - Fix random number generation if compiling using `WITH_TLS=no` and on Linux |
| | | with glibc >= 2.25. Without this fix, no random numbers would be generated |
| | | for e.g. on broker client id generation, and so clients connecting expecting |
| | | this feature would be unable to connect. |
| | | - Fix compilation problem related to `getrandom()` on non-glibc systems. |
| | | - Fix Will message for a persistent client incorrectly being sent when the |
| | | client reconnects after a clean disconnect. Closes #1273. |
| | | - Fix Will message for a persistent client not being sent on disconnect. |
| | | Closes #1273. |
| | | - Improve documentation around the upgrading of persistence files. Closes |
| | | #1276. |
| | | - Add 'extern "C"' on mosquitto_broker.h and mosquitto_plugin.h for C++ plugin |
| | | writing. Closes #1290. |
| | | - Fix persistent Websockets clients not receiving messages after they |
| | | reconnect, having sent DISCONNECT on a previous session. Closes #1227. |
| | | - Disable TLS renegotiation. Client initiated renegotiation is considered to |
| | | be a potential attack vector against servers. Closes #1257. |
| | | - Fix incorrect shared subscription topic '$shared'. |
| | | - Fix zero length client ids being rejected for MQTT v5 clients with clean |
| | | start set to true. |
| | | - Fix MQTT v5 overlapping subscription behaviour. Clients now receive message |
| | | from all matching subscriptions rather than the first one encountered, which |
| | | ensures the maximum QoS requirement is met. |
| | | - Fix incoming/outgoing quota problems for QoS>0. |
| | | - Remove obsolete `store_clean_interval` from documentation. |
| | | - Fix v4 authentication plugin never calling psk_key_get. |
| | | |
| | | Client library: |
| | | - Fix typo causing build error on Windows when building without TLS support. |
| | | Closes #1264. |
| | | |
| | | Clients: |
| | | - Fix -L url parsing when `/topic` part is missing. |
| | | - Stop some error messages being printed even when `--quiet` was used. |
| | | Closes #1284. |
| | | - Fix mosquitto_pub exiting with error code 0 when an error occurred. |
| | | Closes #1285. |
| | | - Fix mosquitto_pub not using the `-c` option. Closes #1273. |
| | | - Fix MQTT v5 clients not being able to specify a password without a username. |
| | | Closes #1274. |
| | | - Fix `mosquitto_pub -l` not handling network failures. Closes #1152. |
| | | - Fix `mosquitto_pub -l` not handling zero length input. Closes #1302. |
| | | - Fix double free on exit in mosquitto_pub. Closes #1280. |
| | | |
| | | Documentation: |
| | | - Remove references to Python binding and C++ wrapper in libmosquitto man |
| | | page. Closes #1266. |
| | | |
| | | Build: |
| | | - CLIENT_LDFLAGS now uses LDFLAGS. Closes #1294. |
| | | |
| | | |
| | | 1.6.2 - 20190430 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix memory access after free, leading to possible crash, when v5 client with |
| | | Will message disconnects, where the Will message has as its first property |
| | | one of `content-type`, `correlation-data`, `payload-format-indicator`, or |
| | | `response-topic`. Closes #1244. |
| | | - Fix build for WITH_TLS=no. Closes #1250. |
| | | - Fix Will message not allowing user-property properties. |
| | | - Fix broker originated messages (e.g. $SYS/broker/version) not being |
| | | published when `check_retain_source` set to true. Closes #1245. |
| | | - Fix $SYS/broker/version being incorrectly expired after 60 seconds. |
| | | Closes #1245. |
| | | |
| | | Library: |
| | | - Fix crash after client has been unable to connect to a broker. This occurs |
| | | when the client is exiting and is part of the final library cleanup routine. |
| | | Closes #1246. |
| | | |
| | | Clients: |
| | | - Fix -L url parsing. Closes #1248. |
| | | |
| | | |
| | | 1.6.1 - 20190426 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Document `memory_limit` option. |
| | | |
| | | Clients: |
| | | - Fix compilation on non glibc systems due to missing sys/time.h header. |
| | | |
| | | Build: |
| | | - Add `make check` target and document testing procedure. Closes #1230. |
| | | - Document bundled dependencies and how to disable. Closes #1231. |
| | | - Split CFLAGS and CPPFLAGS, and LDFLAGS and LDADD/LIBADD. |
| | | - test/unit now respects CPPFLAGS and LDFLAGS. Closes #1232. |
| | | - Don't call ldconfig in CMake scripts. Closes #1048. |
| | | - Use CMAKE_INSTALL_* variables when installing in CMake. Closes #1049. |
| | | |
| | | |
| | | 1.6 - 20190417 |
| | | ============== |
| | | |
| | | Broker features: |
| | | - Add support for MQTT v5 |
| | | - Add support for OCSP stapling. |
| | | - Add support for ALPN on bridge TLS connections. Closes #924. |
| | | - Add support for Automotive DLT logging. |
| | | - Add TLS Engine support. |
| | | - Persistence file read/write performance improvements. |
| | | - General performance improvements. |
| | | - Add max_keepalive option, to allow a maximum keepalive value to be set for |
| | | MQTT v5 clients only. |
| | | - Add `bind_interface` option which allows a listener to be bound to a |
| | | specific network interface, in a similar fashion to the `bind_address` option. |
| | | Linux only. |
| | | - Add improved bridge restart interval based on Decorrelated Jitter. |
| | | - Add `dhparamfile` option, to allow DH parameters to be loaded for Ephemeral |
| | | DH support |
| | | - Disallow writing to $ topics where appropriate. |
| | | - Fix mosquitto_passwd crashing on corrupt password file. Closes #1207. |
| | | - Add explicit support for TLS v1.3. |
| | | - Drop support for TLS v1.0. |
| | | - Improved general support for broker generated client ids. Removed libuuid |
| | | dependency. |
| | | - auto_id_prefix now defaults to 'auto-'. |
| | | - QoS 1 and 2 flow control improvements. |
| | | |
| | | Client library features: |
| | | - Add support for MQTT v5 |
| | | - Add mosquitto_subscribe_multiple() for sending subscriptions to multiple |
| | | topics in one command. |
| | | - Add TLS Engine support. |
| | | - Add explicit support for TLS v1.3. |
| | | - Drop support for TLS v1.0. |
| | | - QoS 1 and 2 flow control improvements. |
| | | |
| | | Client features: |
| | | - Add support for MQTT v5 |
| | | - Add mosquitto_rr client, which can be used for "request-response" messaging, |
| | | by sending a request message and awaiting a response. |
| | | - Add TLS Engine support. |
| | | - Add support for ALPN on TLS connections. Closes #924. |
| | | - Add -D option for all clients to specify MQTT v5 properties. |
| | | - Add -E to mosquitto_sub, which causes it to exit immediately after having |
| | | its subscriptions acknowledged. Use with -c to create a durable client |
| | | session without requiring a message to be received. |
| | | - Add --remove-retained to mosquitto_sub, which can be used to clear retained |
| | | messages on a broker. |
| | | - Add --repeat and --repeat-delay to mosquitto_pub, which can be used to |
| | | repeat single message publishes at a regular interval. |
| | | - -V now accepts `5, `311`, `31`, as well as `mqttv5` etc. |
| | | - Add explicit support for TLS v1.3. |
| | | - Drop support for TLS v1.0. |
| | | |
| | | Broker fixes: |
| | | - Improve error reporting when creating listeners. |
| | | - Fix build on SmartOS due to missing IPV6_V6ONLY. Closes #1212. |
| | | |
| | | Client library fixes |
| | | - Add missing `mosquitto_userdata()` function. |
| | | |
| | | Client fixes: |
| | | - mosquitto_pub wouldn't always publish all messages when using `-l` and |
| | | QoS>0. This has been fixed. |
| | | - mosquitto_sub was incorrectly encoding special characters when using %j |
| | | output format. Closes #1220. |
| | | |
| | | |
| | | 1.5.8 - 20190228 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix clients being disconnected when ACLs are in use. This only affects the |
| | | case where a client connects using a username, and the anonymous ACL list is |
| | | defined but specific user ACLs are not defined. Closes #1162. |
| | | - Make error messages for missing config file clearer. |
| | | - Fix some Coverity Scan reported errors that could occur when the broker was |
| | | already failing to start. |
| | | - Fix broken mosquitto_passwd on FreeBSD. Closes #1032. |
| | | - Fix delayed bridge local subscriptions causing missing messages. |
| | | Closes #1174. |
| | | |
| | | Library: |
| | | - Use higher resolution timer for random initialisation of client id |
| | | generation. Closes #1177. |
| | | - Fix some Coverity Scan reported errors that could occur when the library was |
| | | already quitting. |
| | | |
| | | |
| | | 1.5.7 - 20190213 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix build failure when using WITH_ADNS=yes |
| | | - Ensure that an error occurs if `per_listener_settings true` is given after |
| | | other security options. Closes #1149. |
| | | - Fix include_dir not sorting config files before loading. This was partially |
| | | fixed in 1.5 previously. |
| | | - Improve documentation around the `include_dir` option. Closes #1154. |
| | | - Fix case where old unreferenced msg_store messages were being saved to the |
| | | persistence file, bloating its size unnecessarily. Closes #389. |
| | | |
| | | Library: |
| | | - Fix `mosquitto_topic_matches_sub()` not returning MOSQ_ERR_INVAL for |
| | | invalid subscriptions like `topic/#abc`. This only affects the return value, |
| | | not the match/no match result, which was already correct. |
| | | |
| | | Build: |
| | | - Don't require C99 compiler. |
| | | - Add rewritten build test script and remove some build warnings. |
| | | |
| | | |
| | | 1.5.6 - 20190206 |
| | | ================ |
| | | |
| | | Security: |
| | | - CVE-2018-12551: If Mosquitto is configured to use a password file for |
| | | authentication, any malformed data in the password file will be treated as |
| | | valid. This typically means that the malformed data becomes a username and no |
| | | password. If this occurs, clients can circumvent authentication and get access |
| | | to the broker by using the malformed username. In particular, a blank line |
| | | will be treated as a valid empty username. Other security measures are |
| | | unaffected. Users who have only used the mosquitto_passwd utility to create |
| | | and modify their password files are unaffected by this vulnerability. |
| | | Affects version 1.0 to 1.5.5 inclusive. |
| | | - CVE-2018-12550: If an ACL file is empty, or has only blank lines or |
| | | comments, then mosquitto treats the ACL file as not being defined, which |
| | | means that no topic access is denied. Although denying access to all topics |
| | | is not a useful configuration, this behaviour is unexpected and could lead |
| | | to access being incorrectly granted in some circumstances. This is now |
| | | fixed. Affects versions 1.0 to 1.5.5 inclusive. |
| | | - CVE-2018-12546. If a client publishes a retained message to a topic that |
| | | they have access to, and then their access to that topic is revoked, the |
| | | retained message will still be delivered to future subscribers. This |
| | | behaviour may be undesirable in some applications, so a configuration option |
| | | `check_retain_source` has been introduced to enforce checking of the |
| | | retained message source on publish. |
| | | |
| | | Broker: |
| | | - Fixed comment handling for config options that have optional arguments. |
| | | - Improved documentation around bridge topic remapping. |
| | | - Handle mismatched handshakes (e.g. QoS1 PUBLISH with QoS2 reply) properly. |
| | | - Fix spaces not being allowed in the bridge remote_username option. Closes |
| | | #1131. |
| | | - Allow broker to always restart on Windows when using `log_dest file`. Closes |
| | | #1080. |
| | | - Fix Will not being sent for Websockets clients. Closes #1143. |
| | | - Windows: Fix possible crash when client disconnects. Closes #1137. |
| | | - Fixed durable clients being unable to receive messages when offline, when |
| | | per_listener_settings was set to true. Closes #1081. |
| | | - Add log message for the case where a client is disconnected for sending a |
| | | topic with invalid UTF-8. Closes #1144. |
| | | |
| | | Library: |
| | | - Fix TLS connections not working over SOCKS. |
| | | - Don't clear SSL context when TLS connection is closed, meaning if a user |
| | | provided an external SSL_CTX they have less chance of leaking references. |
| | | |
| | | Build: |
| | | - Fix comparison of boolean values in CMake build. Closes #1101. |
| | | - Fix compilation when openssl deprecated APIs are not available. |
| | | Closes #1094. |
| | | - Man pages can now be built on any system. Closes #1139. |
| | | |
| | | |
| | | 1.5.5 - 20181211 |
| | | ================ |
| | | |
| | | Security: |
| | | - If `per_listener_settings` is set to true, then the `acl_file` setting was |
| | | ignored for the "default listener" only. This has been fixed. This does not |
| | | affect any listeners defined with the `listener` option. Closes #1073. |
| | | This is now tracked as CVE-2018-20145. |
| | | |
| | | Broker: |
| | | - Add `socket_domain` option to allow listeners to disable IPv6 support. |
| | | This is required to work around a problem in libwebsockets that means |
| | | sockets only listen on IPv6 by default if IPv6 support is compiled in. |
| | | Closes #1004. |
| | | - When using ADNS, don't ask for all network protocols when connecting, |
| | | because this can lead to confusing "Protocol not supported" errors if the |
| | | network is down. Closes #1062. |
| | | - Fix outgoing retained messages not being sent by bridges on initial |
| | | connection. Closes #1040. |
| | | - Don't reload auth_opt_ options on reload, to match the behaviour of the |
| | | other plugin options. Closes #1068. |
| | | - Print message on error when installing/uninstalling as a Windows service. |
| | | - All non-error connect/disconnect messages are controlled by the |
| | | `connection_messages` option. Closes #772. Closes #613. Closes #537. |
| | | |
| | | Library: |
| | | - Fix reconnect delay backoff behaviour. Closes #1027. |
| | | - Don't call on_disconnect() twice if keepalive tests fail. Closes #1067. |
| | | |
| | | Client: |
| | | - Always print leading zeros in mosquitto_sub when output format is hex. |
| | | Closes #1066. |
| | | |
| | | Build: |
| | | - Fix building where TLS-PSK is not available. Closes #68. |
| | | |
| | | |
| | | 1.5.4 - 20181108 |
| | | ================ |
| | | |
| | | Security: |
| | | - When using a TLS enabled websockets listener with "require_certificate" |
| | | enabled, the mosquitto broker does not correctly verify client certificates. |
| | | This is now fixed. All other security measures operate as expected, and in |
| | | particular non-websockets listeners are not affected by this. Closes #996. |
| | | |
| | | Broker: |
| | | - Process all pending messages even when a client has disconnected. This means |
| | | a client that send a PUBLISH then DISCONNECT quickly, then disconnects will |
| | | have its DISCONNECT message processed properly and so no Will will be sent. |
| | | Closes #7. |
| | | - $SYS/broker/clients/disconnected should never be negative. Closes #287. |
| | | - Give better error message if a client sends a password without a username. |
| | | Closes #1015. |
| | | - Fix bridge not honoring restart_timeout. Closes #1019. |
| | | - Don't disconnect a client if an auth plugin denies access to SUBSCRIBE. |
| | | Closes #1016. |
| | | |
| | | Library: |
| | | - Fix memory leak that occurred if mosquitto_reconnect() was used when TLS |
| | | errors were present. Closes #592. |
| | | - Fix TLS connections when using an external event loop with |
| | | mosquitto_loop_read() and mosquitto_write(). Closes #990. |
| | | |
| | | Build: |
| | | - Fix clients not being compiled with threading support when using CMake. |
| | | Closes #983. |
| | | - Header fixes for FreeBSD. Closes #977. |
| | | - Use _GNU_SOURCE to fix build errors in websockets and getaddrinfo usage. |
| | | Closes #862 and #933. |
| | | - Fix builds on QNX 7.0.0. Closes #1018. |
| | | |
| | | |
| | | 1.5.3 - 20180925 |
| | | ================ |
| | | |
| | | Security: |
| | | - Fix CVE-2018-12543. If a message is sent to Mosquitto with a topic that |
| | | begins with $, but is not $SYS, then an assert that should be unreachable is |
| | | triggered and Mosquitto will exit. |
| | | |
| | | Broker: |
| | | - Elevate log level to warning for situation when socket limit is hit. |
| | | - Remove requirement to use `user root` in snap package config files. |
| | | - Fix retained messages not sent by bridges on outgoing topics at the first |
| | | connection. Closes #701. |
| | | - Documentation fixes. Closes #520, #600. |
| | | - Fix duplicate clients being added to by_id hash before the old client was |
| | | removed. Closes #645. |
| | | - Fix Windows version not starting if include_dir did not contain any files. |
| | | Closes #566. |
| | | - When an authentication plugin denied access to a SUBSCRIBE, the client would |
| | | be disconnected incorrectly. This has been fixed. Closes #1016. |
| | | |
| | | Build: |
| | | - Various fixes to ease building. |
| | | |
| | | |
| | | 1.5.2 - 20180919 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix build when using WITH_ADNS=yes. |
| | | - Fix incorrect call to setsockopt() for TCP_NODELAY. Closes #941. |
| | | - Fix excessive CPU usage when the number of sockets exceeds the system limit. |
| | | Closes #948. |
| | | - Fix for bridge connections when using WITH_ADNS=yes. |
| | | - Fix round_robin false behaviour. Closes #481. |
| | | - Fix segfault on HUP when bridges and security options are configured. |
| | | Closes #965. |
| | | |
| | | Library: |
| | | - Fix situation where username and password is used with SOCKS5 proxy. Closes |
| | | #927. |
| | | - Fix SOCKS5 behaviour when passing IP addresses. Closes #927. |
| | | |
| | | Build: |
| | | - Make it easier to build without bundled uthash.h using "WITH_BUNDLED_DEPS=no". |
| | | - Fix build with OPENSSL_NO_ENGINE. Closes #932. |
| | | |
| | | |
| | | 1.5.1 - 20180816 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix plugin cleanup function not being called on exit of the broker. |
| | | Closes #900. |
| | | - Print more OpenSSL errors when loading certificates/keys fail. |
| | | - Use AF_UNSPEC etc. instead of PF_UNSPEC to comply with POSIX. Closes #863. |
| | | - Remove use of AI_ADDRCONFIG, which means the broker can be used on systems |
| | | where only the loopback interface is defined. Closes #869, Closes #901. |
| | | - Fix IPv6 addresses not being able to be used as bridge addresses. |
| | | Closes #886. |
| | | - All clients now time out if they exceed their keepalive*1.5, rather than |
| | | just reach it. This was inconsistent in two places. |
| | | - Fix segfault on startup if bridge CA certificates could not be read. |
| | | Closes #851. |
| | | - Fix problem opening listeners on Pi caused by unsigned char being default. |
| | | Found via #849. |
| | | - ACL patterns that do not contain either %c or %u now produce a warning in |
| | | the log. Closes #209. |
| | | - Fix bridge publishing failing when per_listener_settings was true. Closes |
| | | #860. |
| | | - Fix `use_identity_as_username true` not working. Closes #833. |
| | | - Fix UNSUBACK messages not being logged. Closes #903. |
| | | - Fix possible endian issue when reading the `memory_limit` option. |
| | | - Fix building for libwebsockets < 1.6. |
| | | - Fix accessor functions for username and client id when used in plugin auth |
| | | check. |
| | | |
| | | Library: |
| | | - Fix some places where return codes were incorrect, including to the |
| | | on_disconnect() callback. This has resulted in two new error codes, |
| | | MOSQ_ERR_KEEPALIVE and MOSQ_ERR_LOOKUP. |
| | | - Fix connection problems when mosquitto_loop_start() was called before |
| | | mosquitto_connect_async(). Closes #848. |
| | | |
| | | Clients: |
| | | - When compiled using WITH_TLS=no, the default port was incorrectly being set |
| | | to -1. This has been fixed. |
| | | - Fix compiling on Mac OS X <10.12. Closes #813 and #240. |
| | | |
| | | Build: |
| | | - Fixes for building on NetBSD. Closes #258. |
| | | - Fixes for building on FreeBSD. |
| | | - Add support for compiling with static libwebsockets library. |
| | | |
| | | |
| | | 1.5 - 20180502 |
| | | ============== |
| | | |
| | | Security: |
| | | - Fix memory leak that could be caused by a malicious CONNECT packet. This |
| | | does not yet have a CVE assigned. Closes #533493 (on Eclipse bugtracker) |
| | | |
| | | Broker features: |
| | | - Add per_listener_settings to allow authentication and access control to be |
| | | per listener. |
| | | - Add limited support for reloading listener settings. This allows settings |
| | | for an already defined listener to be reloaded, but port numbers must not be |
| | | changed. |
| | | - Add ability to deny access to SUBSCRIBE messages as well as the current |
| | | read/write accesses. Currently for auth plugins only. |
| | | - Reduce calls to malloc through the use of UHPA. |
| | | - Outgoing messages with QoS>1 are no longer retried after a timeout period. |
| | | Messages will be retried when a client reconnects. This change in behaviour |
| | | can be justified by considering when the timeout may have occurred. |
| | | * If a connection is unreliable and has dropped, but without one end |
| | | noticing, the messages will be retried on reconnection. Sending |
| | | additional PUBLISH or PUBREL would not have changed anything. |
| | | * If a client is overloaded/unable to respond/has a slow connection then |
| | | sending additional PUBLISH or PUBREL would not help the client catch |
| | | up. Once the backlog has cleared the client will respond. If it is not |
| | | able to catch up, sending additional duplicates would not help either. |
| | | - Add use_subject_as_username option for certificate based client |
| | | authentication to use the entire certificate subject as a username, rather |
| | | than just the CN. Closes #469467. |
| | | - Change sys tree printing output. This format shouldn't be relied upon and |
| | | may change at any time. Closes #470246. |
| | | - Minimum supported libwebsockets version is now 1.3. |
| | | - Add systemd startup notification and services. Closes #471053. |
| | | - Reduce unnecessary malloc and memcpy when receiving a message and storing |
| | | it. Closes #470258. |
| | | - Support for Windows XP has been dropped. |
| | | - Bridge connections now default to using MQTT v3.1.1. |
| | | - mosquitto_db_dump tool can now output some stats on clients. |
| | | - Perform utf-8 validation on incoming will, subscription and unsubscription |
| | | topics. |
| | | - new $SYS/broker/store/messages/count (deprecates $SYS/broker/messages/stored) |
| | | - new $SYS/broker/store/messages/bytes |
| | | - max_queued_bytes feature to limit queues by real size rather than |
| | | than just message count. Closes Eclipse #452919 or Github #100 |
| | | - Add support for bridges to be configured to only send notifications to the |
| | | local broker. |
| | | - Add set_tcp_nodelay option to allow Nagle's algorithm to be disabled on |
| | | client sockets. Closes #433. |
| | | - The behaviour of allow_anonymous has changed. In the old behaviour, the |
| | | default if not set was to allow anonymous access. The new behaviour is to |
| | | default is to allow anonymous access unless another security option is set. |
| | | For example, if password_file is set and allow_anonymous is not set, then |
| | | anonymous access will be denied. It is still possible to allow anonymous |
| | | access by setting it explicitly. |
| | | |
| | | Broker fixes: |
| | | - Fix UNSUBSCRIBE with no topic is accepted on MQTT 3.1.1. Closes #665. |
| | | - Produce an error if two bridges share the same local_clientid. |
| | | - Miscellaneous fixes on Windows. |
| | | - queue_qos0_messages was not observing max_queued_** limits |
| | | - When using the include_dir configuration option sort the files |
| | | alphabetically before loading them. Closes #17. |
| | | - IPv6 is no longer disabled for websockets listeners. |
| | | - Remove all build timestamp information including $SYS/broker/timestamp. |
| | | Close #651. |
| | | - Correctly handle incoming strings that contain a NULL byte. Closes #693. |
| | | - Use constant time memcmp for password comparisons. |
| | | - Fix incorrect PSK key being used if it had leading zeroes. |
| | | - Fix memory leak if a client provided a username/password for a listener with |
| | | use_identity_as_username configured. |
| | | - Fix use_identity_as_username not working on websockets clients. |
| | | - Don't crash if an auth plugin returns MOSQ_ERR_AUTH for a username check on |
| | | a websockets client. Closes #490. |
| | | - Fix 08-ssl-bridge.py test when using async dns lookups. Closes #507. |
| | | - Lines in the config file are no longer limited to 1024 characters long. |
| | | Closes #652. |
| | | - Fix $SYS counters of messages and bytes sent when message is sent over |
| | | a Websockets. Closes #250. |
| | | - Fix upgrade_outgoing_qos for retained message. Closes #534. |
| | | - Fix CONNACK message not being sent for unauthorised connect on websockets. |
| | | Closes #8. |
| | | - Maximum connections on Windows increased to 2048. |
| | | - When a client with an in-use client-id connects, if the old client has a |
| | | will, send the will message. Closes #26. |
| | | - Fix parsing of configuration options that end with a space. Closes #804. |
| | | |
| | | Client library features: |
| | | - Outgoing messages with QoS>1 are no longer retried after a timeout period. |
| | | Messages will be retried when a client reconnects. |
| | | - DNS-SRV support is now disabled by default. |
| | | - Add mosquitto_subscribe_simple() This is a helper function to make |
| | | retrieving messages from a broker very straightforward. Examples of its use |
| | | are in examples/subscribe_simple. |
| | | - Add mosquitto_subscribe_callback() This is a helper function to make |
| | | processing messages from a broker very straightforward. An example of its use |
| | | is in examples/subscribe_simple. |
| | | - Connections now default to using MQTT v3.1.1. |
| | | - Add mosquitto_validate_utf8() to check whether a string is valid UTF-8 |
| | | according to the UTF-8 spec and to the additional restrictions imposed by |
| | | the MQTT spec. |
| | | - Topic inputs are checked for UTF-8 validity. |
| | | - Add mosquitto_userdata function to allow retrieving the client userdata |
| | | member variable. Closes #111. |
| | | - Add mosquitto_pub_topic_check2(), mosquitto_sub_topic_check2(), and |
| | | mosquitto_topic_matches_sub2() which are identical to the similarly named |
| | | functions but also take length arguments. |
| | | - Add mosquitto_connect_with_flags_callback_set(), which allows a second |
| | | connect callback to be used which also exposes the connect flags parameter. |
| | | Closes #738 and #128. |
| | | - Add MOSQ_OPT_SSL_CTX option to allow a user specified SSL_CTX to be used |
| | | instead of the one generated by libmosquitto. This allows greater control |
| | | over what options can be set. Closes #715. |
| | | - Add MOSQ_OPT_SSL_CTX_WITH_DEFAULTS to work with MOSQ_OPT_SSL_CTX and have |
| | | the default libmosquitto SSL_CTX configuration applied to the user provided |
| | | SSL_CTX. Closes #567. |
| | | |
| | | Client library fixes: |
| | | - Fix incorrect PSK key being used if it had leading zeroes. |
| | | - Initialise "result" variable as soon as possible in |
| | | mosquitto_topic_matches_sub. Closes #654. |
| | | - No need to close socket again if setting non-blocking failed. Closes #649. |
| | | - Fix mosquitto_topic_matches_sub() not correctly matching foo/bar against |
| | | foo/+/#. Closes #670. |
| | | - SNI host support added. |
| | | |
| | | Client features: |
| | | - Add -F to mosquitto_sub to allow the user to choose the output format. |
| | | - Add -U to mosquitto_sub for unsubscribing from topics. |
| | | - Add -c (clean session) to mosquitto_pub. |
| | | - Add --retained-only to mosquitto_sub to exit after receiving all retained |
| | | messages. |
| | | - Add -W to allow mosquitto_sub to stop processing incoming messages after a |
| | | timeout. |
| | | - Connections now default to using MQTT v3.1.1. |
| | | - Default to using port 8883 when using TLS. |
| | | - mosquitto_sub doesn't continue to keep connecting if CONNACK tells it the |
| | | connection was refused. |
| | | |
| | | Client fixes: |
| | | - Correctly handle empty files with "mosquitto_pub -l". Closes #676. |
| | | |
| | | Build: |
| | | - Add WITH_STRIP option (defaulting to "no") that when set to "yes" will strip |
| | | executables and shared libraries when installing. |
| | | - Add WITH_STATIC_LIBRARIES (defaulting to "no") that when set to "yes" will |
| | | build and install static versions of the client libraries. |
| | | - Don't run TLS-PSK tests if TLS-PSK disabled at compile time. Closes #636. |
| | | - Support for openssl versions 1.0.0 and 1.0.1 has been removed as these are |
| | | no longer supported by openssl. |
| | | |
| | | Documentation: |
| | | - Replace mentions of deprecated 'c_rehash' with 'openssl rehash'. |
| | | |
| | | 1.4.15 - 20180228 |
| | | ================= |
| | | |
| | | Security: |
| | | - Fix CVE-2017-7652. If a SIGHUP is sent to the broker when there are no more |
| | | file descriptors, then opening the configuration file will fail and security |
| | | settings will be set back to their default values. |
| | | - Fix CVE-2017-7651. Unauthenticated clients can cause excessive memory use by |
| | | setting "remaining length" to be a large value. This is now mitigated by |
| | | limiting the size of remaining length to valid values. A "memory_limit" |
| | | configuration option has also been added to allow the overall memory used by |
| | | the broker to be limited. |
| | | |
| | | Broker: |
| | | - Use constant time memcmp for password comparisons. |
| | | - Fix incorrect PSK key being used if it had leading zeroes. |
| | | - Fix memory leak if a client provided a username/password for a listener with |
| | | use_identity_as_username configured. |
| | | - Fix use_identity_as_username not working on websockets clients. |
| | | - Don't crash if an auth plugin returns MOSQ_ERR_AUTH for a username check on |
| | | a websockets client. Closes #490. |
| | | - Fix 08-ssl-bridge.py test when using async dns lookups. Closes #507. |
| | | - Lines in the config file are no longer limited to 1024 characters long. |
| | | Closes #652. |
| | | - Fix $SYS counters of messages and bytes sent when message is sent over |
| | | a Websockets. Closes #250. |
| | | - Fix upgrade_outgoing_qos for retained message. Closes #534. |
| | | - Fix CONNACK message not being sent for unauthorised connect on websockets. |
| | | Closes #8. |
| | | |
| | | Client library: |
| | | - Fix incorrect PSK key being used if it had leading zeroes. |
| | | - Initialise "result" variable as soon as possible in |
| | | mosquitto_topic_matches_sub. Closes #654. |
| | | - No need to close socket again if setting non-blocking failed. Closes #649. |
| | | - Fix mosquitto_topic_matches_sub() not correctly matching foo/bar against |
| | | foo/+/#. Closes #670. |
| | | |
| | | Clients: |
| | | - Correctly handle empty files with "mosquitto_pub -l". Closes #676. |
| | | |
| | | Build: |
| | | - Don't run TLS-PSK tests if TLS-PSK disabled at compile time. Closes #636. |
| | | |
| | | |
| | | 1.4.14 - 20170710 |
| | | ================= |
| | | |
| | | Broker: |
| | | - Fix regression from 1.4.13 where persistence data was not being saved. |
| | | |
| | | |
| | | 1.4.13 - 20170627 |
| | | ================= |
| | | |
| | | Security: |
| | | - Fix CVE-2017-9868. The persistence file was readable by all local users, |
| | | potentially allowing sensitive information to be leaked. |
| | | This can also be fixed administratively, by restricting access to the |
| | | directory in which the persistence file is stored. |
| | | |
| | | Broker: |
| | | - Fix for poor websockets performance. |
| | | - Fix lazy bridges not timing out for idle_timeout. Closes #417. |
| | | - Fix problems with large retained messages over websockets. Closes #427. |
| | | - Set persistence file to only be readable by owner, except on Windows. Closes |
| | | #468. |
| | | - Fix CONNECT check for reserved=0, as per MQTT v3.1.1 check MQTT-3.1.2-3. |
| | | - When the broker stop, wills for any connected clients are now "sent". Closes |
| | | #477. |
| | | - Auth plugins can be configured to disable the check for +# in |
| | | usernames/client ids with the auth_plugin_deny_special_chars option. |
| | | Partially closes #462. |
| | | - Restrictions for CVE-2017-7650 have been relaxed - '/' is allowed in |
| | | usernames/client ids. Remainder of fix for #462. |
| | | |
| | | Clients: |
| | | - Don't use / in auto-generated client ids. |
| | | |
| | | |
| | | 1.4.12 - 20170528 |
| | | ================= |
| | | |
| | | Security: |
| | | - Fix CVE-2017-7650, which allows clients with username or client id set to |
| | | '#' or '+' to bypass pattern based ACLs or third party plugins. The fix |
| | | denies message sending or receiving of messages for clients with a '#' or |
| | | '+' in their username or client id and if the message is subject to a |
| | | pattern ACL check or plugin check. |
| | | Patches for other versions are available at |
| | | https://mosquitto.org/files/cve/2017-7650/ |
| | | |
| | | Broker: |
| | | - Fix mosquitto.db from becoming corrupted due to client messages being |
| | | persisted with no stored message. Closes #424. |
| | | - Fix bridge not restarting properly. Closes #428. |
| | | - Fix unitialized memory in gets_quiet on Windows. Closes #426. |
| | | - Fix building with WITH_ADNS=no for systems that don't use glibc. Closes |
| | | #415. |
| | | - Fixes to readme.md. |
| | | - Fix deprecation warning for OpenSSL 1.1. PR #416. |
| | | - Don't segfault on duplicate bridge names. Closes #446. |
| | | - Fix CVE-2017-7650. |
| | | |
| | | |
| | | 1.4.11 - 20170220 |
| | | ================= |
| | | |
| | | Broker: |
| | | - Fix crash when "lazy" type bridge attempts to reconnect. Closes #259. |
| | | - maximum_connections now applies to websockets listeners. Closes #271. |
| | | - Allow bridges to use TLS with IPv6. |
| | | - Don't error on zero length persistence files. Closes #316. |
| | | - For http only websockets clients, close files served over http in all cases |
| | | when the client disconnects. Closes #354. |
| | | - Fix error message when websockets http_dir directory does not exist. |
| | | - Improve password utility error message. Closes #379. |
| | | |
| | | Clients: |
| | | - Use of --ciphers no longer requires you to also pass --tls-version. |
| | | Closes #380. |
| | | |
| | | Client library: |
| | | - Clients can now use TLS with IPv6. |
| | | - Fix potential socket leakage when reconnecting. Closes #304. |
| | | - Fix potential negative timeout being passed to pselect. Closes #329. |
| | | |
| | | |
| | | 1.4.10 - 20160816 |
| | | ================= |
| | | |
| | | Broker: |
| | | - Fix TLS operation with websockets listeners and libwebsockts 2.x. Closes |
| | | #186. |
| | | - Don't disconnect client on HUP before reading the pending data. Closes #7. |
| | | - Fix some $SYS messages being incorrectly persisted. Closes #191. |
| | | - Support OpenSSL 1.1.0. |
| | | - Call fsync after persisting data to ensure it is correctly written. Closes |
| | | #189. |
| | | - Fix persistence saving of subscription QoS on big-endian machines. |
| | | - Fix will retained flag handling on Windows. Closes #222. |
| | | - Broker now displays an error if it is unable to open the log file. Closes |
| | | #234. |
| | | |
| | | Client library: |
| | | - Support OpenSSL 1.1.0. |
| | | - Fixed the C++ library not allowing SOCKS support to be used. Closes #198. |
| | | - Fix memory leak when verifying a server certificate with a subjectAltName |
| | | section. Closes #237. |
| | | |
| | | Build: |
| | | - Don't attempt to install docs when WITH_DOCS=no. Closes #184. |
| | | |
| | | |
| | | 1.4.9 - 20160603 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Ensure websockets clients that previously connected with clean session set |
| | | to false have their queued messages delivered immediately on reconnecting. |
| | | Closes #476314. |
| | | - Reconnecting client with clean session set to false doesn't start with mid=1 |
| | | again. |
| | | - Will topic isn't truncated by one byte when using a mount_point any more. |
| | | - Network errors are printed correctly on Windows. |
| | | - Fix incorrect $SYS heap memory reporting when using ACLs. |
| | | - Bridge config parameters couldn't contain a space, this has been fixed. |
| | | Closes #150. |
| | | - Fix saving of persistence messages that start with a '/'. Closes #151. |
| | | - Fix reconnecting for bridges that use TLS on Windows. Closes #154. |
| | | - Broker and bridges can now cope with unknown incoming PUBACK, PUBREC, |
| | | PUBREL, PUBCOMP without disconnecting. Closes #57. |
| | | - Fix websockets listeners not being able to bind to an IP address. Closes |
| | | #170. |
| | | - mosquitto_passwd utility now correctly deals with unknown command line |
| | | arguments in all cases. Closes #169. |
| | | - Fix publishing of $SYS/broker/clients/maximum |
| | | - Fix order of #includes in lib/send_mosq.c to ensure struct mosquitto doesn't |
| | | differ between source files when websockets is being used. Closes #180. |
| | | - Fix possible rare crash when writing out persistence file and a client has |
| | | incomplete messages inflight that it has been denied the right to publish. |
| | | |
| | | Client library: |
| | | - Fix the case where a message received just before the keepalive timer |
| | | expired would cause the client to miss the keepalive timer. |
| | | - Return value of pthread_create is now checked. |
| | | - _mosquitto_destroy should not cancel threads that weren't created by |
| | | libmosquitto. Closes #166. |
| | | - Clients can now cope with unknown incoming PUBACK, PUBREC, PUBREL, PUBCOMP |
| | | without disconnecting. Closes #57. |
| | | - Fix mosquitto_topic_matches_sub() reporting matches on some invalid |
| | | subscriptions. |
| | | |
| | | Clients: |
| | | - Handle some unchecked malloc() calls. Closes #1. |
| | | |
| | | Build: |
| | | - Fix string quoting in CMakeLists.txt. Closes #4. |
| | | - Fix building on Visual Studio 2015. Closes #136. |
| | | |
| | | |
| | | 1.4.8 - 20160214 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Wills published by clients connected to a listener with mount_point defined |
| | | now correctly obey the mount point. This was a potential security risk |
| | | because it allowed clients to publish messages outside of their restricted |
| | | mount point. This is only affects brokers where the mount_point option is in |
| | | use. Closes #487178. |
| | | - Fix detection of broken connections on Windows. Closes #485143. |
| | | - Close stdin etc. when daemonised. Closes #485589. |
| | | - Fix incorrect detection of FreeBSD and OpenBSD. Closes #485131. |
| | | |
| | | Client library: |
| | | - mosq->want_write should be cleared immediately before a call to SSL_write, |
| | | to allow clients using mosquitto_want_write() to get accurate results. |
| | | |
| | | |
| | | 1.4.7 - 20151221 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix support for libwebsockets 1.22. |
| | | |
| | | |
| | | 1.4.6 - 20151220 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Add support for libwebsockets 1.6. |
| | | |
| | | Client library: |
| | | - Fix _mosquitto_socketpair() on Windows, reducing the chance of delays when |
| | | publishing. Closes #483979. |
| | | |
| | | Clients: |
| | | - Fix "mosquitto_pub -l" stripping the final character on a line. Closes |
| | | #483981. |
| | | |
| | | |
| | | 1.4.5 - 20151108 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix possible memory leak if bridge using SSL attempts to connect to a |
| | | host that is not up. |
| | | - Free unused topic tree elements (fix in 1.4.3 was incomplete). Closes |
| | | #468987. |
| | | |
| | | Clients: |
| | | - "mosquitto_pub -l" now no longer limited to 1024 byte lines. Closes #478917. |
| | | |
| | | |
| | | 1.4.4 - 20150916 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Don't leak sockets when outgoing bridge with multiple addresses cannot |
| | | connect. Closes #477571. |
| | | - Fix cross compiling of websockets. Closes #475807. |
| | | - Fix memory free related crashes on openwrt. Closes #475707. |
| | | - Fix excessive calls to message retry check. |
| | | |
| | | |
| | | 1.4.3 - 20150818 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix incorrect bridge notification on initial connection. Closes #467096. |
| | | - Build fixes for OpenBSD. |
| | | - Fix incorrect behaviour for autosave_interval, most noticable for |
| | | autosave_interval=1. Closes #465438. |
| | | - Fix handling of outgoing QoS>0 messages for bridges that could not be sent |
| | | because the bridge connection was down. |
| | | - Free unused topic tree elements. Closes #468987. |
| | | - Fix some potential memory leaks. Closes #470253. |
| | | - Fix potential crash on libwebsockets error. |
| | | |
| | | Client library: |
| | | - Add missing error strings to mosquitto_strerror. |
| | | - Handle fragmented TLS packets without a delay. Closes #470660. |
| | | - Fix incorrect loop timeout being chosen when using threaded interface and |
| | | keepalive = 0. Closes #471334. |
| | | - Increment inflight messages count correctly. Closes #474935. |
| | | |
| | | Clients: |
| | | - Report error string on connection failure rather than error code. |
| | | |
| | | |
| | | 1.4.2 - 20150507 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix bridge prefixes only working for the first outgoing message. Closes |
| | | #464437. |
| | | - Fix incorrect bridge connection notifications on local broker. |
| | | - Fix persistent db writing on Windows. Closes #464779. |
| | | - ACLs are now checked before sending a will message. |
| | | - Fix possible crash when using bridges on Windows. Closes #465384. |
| | | - Fix parsing of auth_opt_ arguments with extra spaces/tabs. |
| | | - Broker will return CONNACK rc=5 when a username/password is not authorised. |
| | | This was being incorrectly set as rc=4. |
| | | - Fix handling of payload lengths>4096 with websockets. |
| | | |
| | | Client library: |
| | | - Inflight message count wasn't being decreased for outgoing messages using |
| | | QoS 2, meaning that only up to 20 QoS 2 messages could be sent. This has |
| | | been fixed. Closes #464436. |
| | | - Fix CMake dependencies for C++ wrapper building. Closes #463884. |
| | | - Fix possibility of select() being called with a socket that is >FD_SETSIZE. |
| | | This is a fix for #464632 that will be followed up by removing the select() |
| | | call in a future version. |
| | | - Fix calls to mosquitto_connect*_async() not completing. |
| | | |
| | | |
| | | 1.4.1 - 20150403 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix possible crash under heavy network load. Closes #463241. |
| | | - Fix possible crash when using pattern ACLs. |
| | | - Fix problems parsing config strings with multiple leading spaces. Closes |
| | | #462154. |
| | | - Websockets clients are now periodically disconnected if they have not |
| | | maintained their keepalive timer. Closes #461619. |
| | | - Fix possible minor memory leak on acl parsing. |
| | | |
| | | Client library: |
| | | - Inflight limits should only apply to outgoing messages. Closes #461620. |
| | | - Fix reconnect bug on Windows. Closes #463000. |
| | | - Return -1 on error from mosquitto_socket(). Closes #461705. |
| | | - Fix crash on multiple calls to mosquitto_lib_init/mosquitto_lib_cleanup. |
| | | Closes #462780. |
| | | - Allow longer paths on Windows. Closes #462781. |
| | | - Make _mosquitto_mid_generate() thread safe. Closes #463479. |
| | | |
| | | |
| | | 1.4 - 20150218 |
| | | ============== |
| | | |
| | | Important changes: |
| | | - Websockets support in the broker. |
| | | - Bridge behaviour on the local broker has changed due to the introduction of |
| | | the local_* options. This may affect you if you are using authentication |
| | | and/or ACLs with bridges. |
| | | - The default TLS behaviour has changed to accept all of TLS v1.2, v1.1 and |
| | | v1.0, rather than only only one version of the protocol. It is still |
| | | possible to restrict a listener to a single version of TLS. |
| | | - The Python client has been removed now that the Eclipse Paho Python client |
| | | has had a release. |
| | | - When a durable client reconnects, its queued messages are now checked |
| | | against ACLs in case of a change in username/ACL state since it last |
| | | connected. |
| | | - New use_username_as_clientid option on the broker, for preventing hijacking |
| | | of a client id. |
| | | - The client library and clients now have experimental SOCKS5 support. |
| | | - Wildcard TLS certificates are now supported for bridges and clients. |
| | | - The clients have support for config files with default options. |
| | | - Client and client libraries have support for MQTT v3.1.1. |
| | | - Bridge support for MQTT v3.1.1. |
| | | |
| | | |
| | | Broker: |
| | | - Websockets support in the broker. |
| | | - Add local_clientid, local_username, local_password for bridge connections to |
| | | authenticate to the local broker. |
| | | - Default TLS mode now accepts TLS v1.2, v1.1 and v1.0. |
| | | - Support for ECDHE-ECDSA family ciphers. |
| | | - Fix bug #1324411, which could have had unexpected consequences for delayed |
| | | messages in rare circumstances. |
| | | - Add support for "session present" in CONNACK messages for MQTT v3.1.1. |
| | | - Remove strict protocol #ifdefs. |
| | | - Change $SYS/broker/clients/active -> $SYS/broker/clients/connected |
| | | - Change $SYS/broker/clients/inactive -> $SYS/broker/clients/disconnected |
| | | - When a durable client reconnects, its queued messages are now checked |
| | | against ACLs in case of a change in username/ACL state since it last |
| | | connected. |
| | | - libuuid is used to generate client ids, where it is available, when an MQTT |
| | | v3.1.1 client connects with a zero length client id. |
| | | - Anonymous clients are no longer accidently disconnected from the broker |
| | | after a SIGHUP. |
| | | - mosquitto_passwd now supports -b (batch mode) to allow the password to be |
| | | provided at the command line. |
| | | - Removed $SYS/broker/changeset. This was intended for use with debugging, but |
| | | in practice is of no use. |
| | | - Add support for use_username_as_clientid which can be used with |
| | | authentication to restrict ownership of client ids and hence prevent one |
| | | client disconnecting another by using the same client id. |
| | | - When "require_certificate" was false, the broker was incorrectly asking for |
| | | a certificate (but not checking it). This caused problems with some clients |
| | | and has been fixed so the broker no longer asks. |
| | | - When using syslog logging on non-Windows OSs, it is now possible to specify |
| | | the logging facility to one of local0-7 instead of the default "daemon". |
| | | - The bridge_attempt_unsubscribe option has been added, to allow the sending |
| | | of UNSUBSCRIBE requests to be disabled for topics with "out" direction. |
| | | Closes bug #456899. |
| | | - Wildcard TLS certificates are now supported for bridges. |
| | | - Support for "hour" client expiration lengths for the |
| | | persistent_client_expiration option. Closes bug #425835. |
| | | - Bridge support for MQTT v3.1.1. |
| | | - Root privileges are now dropped after starting listeners and loading |
| | | certificates/private keys, to allow private keys to have their permissions |
| | | restricted to the root user only. Closes bug #452914. |
| | | - Usernames and topics given in ACL files can now include a space. Closes bug |
| | | #431780. |
| | | - Fix hang if pattern acl contains a %u but an anonymous client connect. |
| | | Closes bug #455402. |
| | | - Fix man page installation with cmake. Closes bug #458843. |
| | | - When using "log_dest file" the output file is now flushed periodically. |
| | | |
| | | Clients: |
| | | - Both clients can now load default configuration options from a file. |
| | | - Add -C option to mosquitto_sub to allow the client to quit after receiving a |
| | | certain count of messages. Closes bug #453850. |
| | | - Add --proxy SOCKS5 support for both clients. |
| | | - Pub client supports setting its keepalive. Closes bug #454852. |
| | | - Add support for config files with default options. |
| | | - Add support for MQTT v3.1.1. |
| | | |
| | | Client library: |
| | | - Add experimental SOCKS5 support. |
| | | - mosquitto_loop_forever now quits after a fatal error, rather than blindly |
| | | retrying. |
| | | - SRV support is now not compiled in by default. |
| | | - Wildcard TLS certificates are now supported. |
| | | - mosquittopp now has a virtual destructor. Closes bug #452915. |
| | | - Add support for MQTT v3.1.1. |
| | | - Don't quit mosquitto_loop_forever() if broker not available on first |
| | | connect. Closes bug #453293, but requires more work. |
| | | |
| | | |
| | | 1.3.5 - 20141008 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix possible memory leak when using a topic that has a leading slash. Fixes |
| | | bug #1360985. |
| | | - Fix saving persistent database on Windows. |
| | | - Temporarily disable ACL checks on subscriptions when using MQTT v3.1.1. This |
| | | is due to the complexity of checking wildcard ACLs against wildcard |
| | | subscriptions. This does not have a negative impact on security because |
| | | checks are still made before a message is sent to a client. |
| | | Fixes bug #1374291. |
| | | - When using -v and the broker receives a SIGHUP, verbose logging was being |
| | | disabled. This has been fixed. |
| | | |
| | | Client library: |
| | | - Fix mutex being incorrectly passed by value. Fixes bug #1373785. |
| | | |
| | | 1.3.4 - 20140806 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Don't ask client for certificate when require_certificate is false. |
| | | - Backout incomplete functionality that was incorrectly included in 1.3.2. |
| | | |
| | | 1.3.3 - 20140801 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix incorrect handling of anonymous bridges on the local broker. |
| | | |
| | | 1.3.2 - 20140713 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Don't allow access to clients when authenticating if a security plugin |
| | | returns an application error. Fixes bug #1340782. |
| | | - Ensure that bridges verify certificates by default when using TLS. |
| | | - Fix possible crash when using pattern ACLs that do not include a %u and |
| | | clients that connect without a username. |
| | | - Fix subscriptions being deleted when clients subscribed to a topic beginning |
| | | with a $ but that is not $SYS. |
| | | - When a durable client reconnects, its queued messages are now checked |
| | | against ACLs in case of a change in username/ACL state since it last |
| | | connected. |
| | | - Fix bug #1324411, which could have had unexpected consequences for delayed |
| | | messages in rare circumstances. |
| | | - Anonymous clients are no longer accidently disconnected from the broker |
| | | after a SIGHUP. |
| | | |
| | | Client library: |
| | | - Fix topic matching edge case. |
| | | - Fix callback deadlocks after calling mosquitto_disconnect(), when using the |
| | | threaded interfaces. Closes bug #1313725. |
| | | - Fix SRV support when building with CMake. |
| | | - Remove strict protocol #ifdefs. |
| | | |
| | | General: |
| | | - Use $(STRIP) for stripping binaries when installing, to allow easier cross |
| | | compilation. |
| | | |
| | | 1.3.1 - 20140324 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Prevent possible crash on client reconnect. Closes bug #1294108. |
| | | - Don't accept zero length unsubscription strings (MQTT v3.1.1 fix) |
| | | - Don't accept QoS 3 (MQTT v3.1.1 fix) |
| | | - Don't disconnect clients immediately on HUP to give chance for all data to |
| | | be read. |
| | | - Reject invalid un/subscriptions e.g. foo/+bar #/bar. |
| | | - Take more care not to disconnect clients that are sending large messages. |
| | | |
| | | Client library: |
| | | - Fix socketpair code on the Mac. |
| | | - Fix compilation for WITH_THREADING=no. |
| | | - Break out of select() when calling mosquitto_loop_stop(). |
| | | - Reject invalid un/subscriptions e.g. foo/+bar #/bar. |
| | | - Add mosquitto_threaded_set(). |
| | | |
| | | Clients: |
| | | - Fix keepalive value on mosquitto_pub. |
| | | - Fix possibility of mosquitto_pub not exiting after sending messages when |
| | | using -l. |
| | | |
| | | 1.3 - 20140316 |
| | | ============== |
| | | |
| | | Broker: |
| | | - The broker no longer ignores the auth_plugin_init() return value. |
| | | - Accept SSLv2/SSLv3 HELLOs when using TLSv1, whilst keeping SSLv2 and SSLv3 |
| | | disabled. This increases client compatibility without sacrificing security. |
| | | - The $SYS tree can now be disabled at runtime as well as at compile time. |
| | | - When remapping bridged topics, only check for matches when the message |
| | | direction is correct. This allows two identical topics to be remapped |
| | | differently for both in and out. |
| | | - Change "$SYS/broker/heap/current size" to "$SYS/broker/heap/current" for |
| | | easier parsing. |
| | | - Change "$SYS/broker/heap/maximum size" to "$SYS/broker/heap/maximum" for |
| | | easier parsing. |
| | | - Topics are no longer normalised from e.g a///topic to a/topic. This matches |
| | | the behaviour as clarified by the Oasis MQTT spec. This will lead to |
| | | unexpected behaviour if you were using topics of this form. |
| | | - Log when outgoing messages for a client begin to drop off the end of the |
| | | queue. |
| | | - Bridge clients are recognised as bridges even after reloading from |
| | | persistence. |
| | | - Basic support for MQTT v3.1.1. This does not include being able to bridge to |
| | | an MQTT v3.1.1 broker. |
| | | - Username is displayed in log if present when a client connects. |
| | | - Support for 0 length client ids (v3.1.1 only) that result in automatically |
| | | generated client ids on the broker (see option allow_zero_length_clientid). |
| | | - Ability to set the prefix of automatically generated client ids (see option |
| | | auto_id_prefix). |
| | | - Add support for TLS session resumption. |
| | | - When using TLS, the server now chooses the cipher to use when negotiating |
| | | with the client. |
| | | - Weak TLS ciphers are now disabled by default. |
| | | |
| | | Client library: |
| | | - Fix support for Python 2.6, 3.0, 3.1. |
| | | - Add support for un/subscribing to multiple topics at once in un/subscribe(). |
| | | - Clients now close their socket after sending DISCONNECT. |
| | | - Python client now contains its version number. |
| | | - C library mosquitto_want_write() now supports TLS clients. |
| | | - Fix possible memory leak in C/C++ library when communicating with |
| | | a broker that doesn't follow the spec. |
| | | - Return strerror() through mosquitto_strerror() to make error printing |
| | | easier. |
| | | - Topics are no longer normalised from e.g a///topic to a/topic. This matches |
| | | the behaviour as clarified by the Oasis MQTT spec. This will lead to |
| | | unexpected behaviour if you were using topics of this form. |
| | | - Add support for SRV lookups. |
| | | - Break out of select() on publish(), subscribe() etc. when using the threaded |
| | | interface. Fixes bug #1270062. |
| | | - Handle incoming and outgoing messages separately. Fixes bug #1263172. |
| | | - Don't terminate threads on mosquitto_destroy() when a client is not using |
| | | the threaded interface but does use their own thread. Fixes bug #1291473. |
| | | |
| | | Clients: |
| | | - Add --ciphers to allow specifying which TLS ciphers to support. |
| | | - Add support for SRV lookups. |
| | | - Add -N to sub client to suppress printing of EOL after the payload. |
| | | - Add -T to sub client to suppress printing of a topic hierarchy. |
| | | |
| | | 1.2.3 - 20131202 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Don't always attempt to call read() for SSL clients, irrespective of whether |
| | | they were ready to read or not. Reduces syscalls significantly. |
| | | - Possible memory leak fixes. |
| | | - Further fix for bug #1226040: multiple retained messages being delivered for |
| | | subscriptions ending in #. |
| | | - Fix bridge reconnections when using multiple bridge addresses. |
| | | |
| | | Client library: |
| | | - Fix possible memory leak in C/C++ library when communicating with |
| | | a broker that doesn't follow the spec. |
| | | - Block in Python loop_stop() until all messages are sent, as the |
| | | documentation states should happen. |
| | | - Fix for asynchronous connections on Windows. Closes bug #1249202. |
| | | - Module version is now available in mosquitto.py. |
| | | |
| | | Clients: |
| | | - mosquitto_sub now uses fwrite() instead of printf() to output messages, so |
| | | messages with NULL characters aren't truncated. |
| | | |
| | | 1.2.2 - 20131021 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix compliance with max_inflight_messages when a non-clean session client |
| | | reconnects. Closes one of the issues on bug #1237389. |
| | | |
| | | Client library: |
| | | - Fix incorrect inflight message accounting, which caused messages to go |
| | | unsent. Partial fix for bug #1237351. |
| | | - Fix potential memory corruption when sending QoS>0 messages at a high rate |
| | | using the threaded interface. Further fix for #1237351. |
| | | - Fix incorrect delay scaling when exponential_backoff=true in |
| | | mosquitto_reconnect_delay_set(). |
| | | - Some pep8 fixes for Python. |
| | | |
| | | 1.2.1 - 20130918 |
| | | ================ |
| | | |
| | | Broker: |
| | | - The broker no longer ignores the auth_plugin_init() return value. Closes |
| | | bug #1215084. |
| | | - Use RTLD_GLOBAL when opening authentication plugins on posix systems. Fixes |
| | | resolving of symbols in libraries used by authentication plugins. |
| | | - Add/fix some config documentation. |
| | | - Fix ACLs for topics with $SYS. |
| | | - Clients loaded from the persistence file on startup were not being added to |
| | | the client hash, causing subtle problems when the client reconnected, |
| | | including ACLs failing. This has been fixed. |
| | | - Add note to mosquitto-tls man page stating that certificates need to be |
| | | unique. Closes bug #1221285. |
| | | - Fix incorrect retained message delivery when using wildcard subs in some |
| | | circumstances. Fixes bug #1226040. |
| | | |
| | | Client library: |
| | | - Fix support for Python 2.6, 3.0, 3.1. |
| | | - Fix TLS subjectAltName verification and segfaults. |
| | | - Handle EAGAIN in Python on Windows. Closes bug #1220004. |
| | | - Fix compilation when using WITH_TLS=no. |
| | | - Don't fail reconnecting in Python when broker is temporarily unavailable. |
| | | |
| | | 1.2 - 20130708 |
| | | ============== |
| | | |
| | | Broker: |
| | | - Replace O(n) username lookup on CONNECT with a roughly O(1) hashtable version. |
| | | - It is now possible to disable $SYS at compile time. |
| | | - Add dropped publish messages to load tree in $SYS. Closes bug #1183318. |
| | | - Add support for logging SUBSCRIBE/UNSUBSCRIBE events. |
| | | - Add "log_dest file" logging support. |
| | | - Auth plugin ACL check function now passes the client id as well as username |
| | | and password. |
| | | - The queue_qos0_messages option wasn't working correctly, this has now been |
| | | fixed. Closes bug #1125200. |
| | | - Don't drop all messages for disconnected durable clients when |
| | | max_queued_messages=0. |
| | | - Add support for "log_type all". |
| | | - Add support for "-v" option on the command line to provide the equivalent of |
| | | "log_type all" without needing a config file. |
| | | - Add the "upgrade_outgoing_qos" option, a non-standard feature. |
| | | - Persistence data is now written to a temporary file which is atomically |
| | | renamed on completion, so a crash during writing will not produce a corrupt |
| | | file. |
| | | - mosquitto.conf is now installed as mosquitto.conf.example |
| | | - Configuration file errors are now reported with filename and line number. |
| | | - The broker now uses a monotonic clock if available, to avoid changes in time |
| | | causing client disconnections or message retries. |
| | | - Clean session and keepalive status are now display the log when a client |
| | | connects. |
| | | - Add support for TLSv1.2 and TLSv1.1. |
| | | - Clients that connect with zero length will topics are now rejected. |
| | | - Add the ability to set a maximum allowed PUBLISH payload size. |
| | | - Fix an ACL with topic "#" incorrectly granting access to $SYS. |
| | | - Fix retained messages incorrectly being set on wildcard topics, leading to |
| | | duplicate retained messages being sent on subscription. Closes bug #1116233. |
| | | - Don't discard listener values when no "port" option given. Closes bug |
| | | #1131406. |
| | | - Client password check was always failing when security was being reapplied |
| | | after a config reload. This meant that all clients were being disconnected. |
| | | This has been fixed. |
| | | - Fix build when WITH_TLS=no. Closes bug #1174971. |
| | | - Fix single outgoing packets not being sent in a timely fashion if they were |
| | | not sent in one call to write(). Closes bug #1176796. |
| | | - Fix remapping of messages for clients connected to a listener with |
| | | mount_point set. Closes bug #1180765. |
| | | - Fix duplicate retained messages being sent for some wildcard patterns. |
| | | - If a client connects with a will topic to which they do not have write |
| | | access, they are now disconnected with CONNACK "not authorised". |
| | | - Fix retained messages on topic foo being incorrectly delivered to |
| | | subscriptions of /# |
| | | - Fix handling of SSL errors on SSL_accept(). |
| | | - Fix handling of QoS 2 messages on client reconnect. |
| | | - Drop privileges now sets supplementary groups correctly. |
| | | - Fix load reporting interval (is now 60s). |
| | | - Be strict with malformed PUBLISH packets - clients are now disconnected |
| | | rather than the packet discarded. This goes inline with future OASIS spec |
| | | changes and makes other changes more straightforward. |
| | | - Process incoming messages denied by ACL properly so that clients don't keep |
| | | resending them. |
| | | |
| | | - Add support for round_robin bridge option. |
| | | - Add bridge support for verifying remote server certificate subject against |
| | | the remote hostname. |
| | | - Fix problem with out of order calls to free() when restarting a lazy bridge. |
| | | - The broker now attempts to resolve bind_address and bridge addresses |
| | | immediately when parsing the config file in order to detect invalid hosts. |
| | | - Bridges now set their notification state before attempting to connect, so if |
| | | they fail to connect the state can still be seen. |
| | | - Fix bridge notification payload length - no need to send a null byte. |
| | | |
| | | - mosquitto_passwd utility now reports errors more clearly. |
| | | - Fix "mosquitto_passwd -U". |
| | | |
| | | Client library: |
| | | - Add support for TLSv1.2 and TLSv1.1, except for on the Python module. |
| | | - Add support for verifying remote server certificate subject against the |
| | | remote hostname. |
| | | - Add mosquitto_reconnect_async() support and make asynchronous connections |
| | | truely asynchronous rather than simply deferred. DNS lookups are still |
| | | blocking, so asynchronous connections require an IP address instead of |
| | | hostname. |
| | | - Allow control of reconnection timeouts in mosquitto_loop_forever() and after |
| | | mosquitto_loop_start() by using mosquitto_reconnect_delay_set(). |
| | | - Fix building on Android NDK. |
| | | - Re-raise unhandled errors in Python so as not to provide confusing error |
| | | messages later on. |
| | | - Python module supports IPv6 connections. |
| | | - mosquitto_sub_topic_tokenise() was behaving incorrectly if the last topic |
| | | hierarchy had only a single character. This has been fixed. Closes bug |
| | | #1163348. |
| | | - Fix possible crash after disconnects when using the threaded interface with |
| | | TLS. |
| | | - Allow build/install without Python. Closes bug #1174972. |
| | | - Add support for binding connection to a local interface. |
| | | - Implement maximum inflight messages handling. |
| | | - Fix Python client not handling will_payload==None. |
| | | - Fix potential memory leak when setting username/password. |
| | | - Fix handling of QoS 2 messages on reconnect. |
| | | - Improve handling of mosquitto_disconnect() with threaded mode. |
| | | |
| | | |
| | | Clients: |
| | | - Add support for TLSv1.2 and TLSv1.1. |
| | | - Sub client can now suppress printing of messages with the retain bit set. |
| | | - Add support for binding connection to a local interface. |
| | | - Implement maximum inflight messages handling for the pub client. |
| | | |
| | | 1.1.3 - 20130211 |
| | | ================ |
| | | |
| | | Broker: |
| | | - mosquitto_passwd utility now uses tmpfile() to generate its temporary data |
| | | storage file. It also creates a backup file that can be used to recover data |
| | | if an errors occur. |
| | | |
| | | Other: |
| | | - Build script fixes to help packaging on Debian. |
| | | |
| | | 1.1.2 - 20130130 |
| | | ================ |
| | | |
| | | Client library: |
| | | - Fix tls_cert_reqs not being set to SSL_VERIFY_PEER by default. This meant |
| | | that clients were not verifying the server certificate when connecting over |
| | | TLS. This affects the C, C++ and Python libraries. |
| | | |
| | | 1.1.1 - 20130116 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix crash on reload if using acl patterns. |
| | | |
| | | Client library: |
| | | - Fix static C++ functions not being exported on Windows. Fixes bug #1098256. |
| | | |
| | | 1.1 - 20121219 |
| | | ============== |
| | | |
| | | Broker: |
| | | - Add $SYS/broker/messages/dropped |
| | | - Add $SYS/broker/clients/expired |
| | | - Replace $SYS/broker/+/per second/+ with moving average versions published at |
| | | $SYS/broker/load/# |
| | | - Add $SYS/broker/load/sockets/+ and $SYS/broker/load/connections/+ |
| | | - Documentation on password file format has been fixed. |
| | | - Disable SSL compression. This reduces memory usage significantly and removes |
| | | the possibility of CRIME type attacks. |
| | | - Enable SSL_MODE_RELEASE_BUFFERS mode to reduce SSL memory usage further. |
| | | - Add allow_duplicate_messages option. |
| | | - ACL files can now have comment lines with # as the first character. |
| | | - Display message on startup about which config is being loaded. |
| | | - Fix max_inflight_messages and max_queued_messages not being applied. |
| | | - Fix documentation error in mosquitto.conf. |
| | | - Ensure that QoS 2 queued messages are sent out in a timely manner. |
| | | - Local bridges now act on clean_session correctly. |
| | | - Local bridges with clean_session==false now remove unused subscriptions on |
| | | broker restart. |
| | | - The $SYS/broker/heap/# messages now no longer include "bytes" as part of the |
| | | string for ease of use. |
| | | |
| | | Client library: |
| | | - Free memory used by OpenSSL in mosquitto_lib_cleanup() where possible. |
| | | - Change WebSocket subprotocol name to mqttv3.1 to make future changes easier |
| | | and for compatibility with other implementations. |
| | | - mosquitto_loop_read() and mosquitto_loop_write() now handle errors |
| | | themselves rather than having mosquitto_loop() handle their errors. This |
| | | makes using them in a separate event loop more straightforward. |
| | | - Add mosquitto_loop_forever() / loop_forever() function call to make simple |
| | | clients easier. |
| | | - Disable SSL compression. This reduces memory usage significantly and removes |
| | | the possibility of CRIME type attacks. |
| | | - Enable SSL_MODE_RELEASE_BUFFERS mode to reduce SSL memory usage further. |
| | | - mosquitto_tls_set() will now return an error or raise an exception |
| | | immediately if the CA certificate or client certificate/key cannot be |
| | | accessed. |
| | | - Fix potential memory leaks on connection failures. |
| | | - Don't produce return error from mosquitto_loop() if a system call is |
| | | interrupted. This prevents disconnects/reconnects in threaded mode and |
| | | simplifies non-threaded client handling. |
| | | - Ignore SIGPIPE to prevent unnecessary client quits in threaded mode. |
| | | - Fix document error for mosquitto_message_retry_set(). |
| | | - Fix mosquitto_topic_matches_sub() for subscriptions with + as the final |
| | | character. Fixes bug #1085797. |
| | | - Rename all "obj" parameters to "userdata" for consistency with other |
| | | libraries. |
| | | - Reset errno before network read/write to ensure EAGAIN isn't mistakenly |
| | | returned. |
| | | - The message queue length is now tracked and used to determine the maximum |
| | | number of packets to process at once. This removes the need for the |
| | | max_packets parameter which is now unused. |
| | | - Fix incorrect error value in Python error_string() function. Fixes bug |
| | | #1086777. |
| | | - Reset last message in/out timer in Python module when we send a PINGREQ. |
| | | Fixes too-early disconnects. |
| | | |
| | | Clients: |
| | | - Clients now display their own version number and library version number in |
| | | their help messages. |
| | | - Fix "mosquitto_pub -l -q 2" disconnecting before all messages were |
| | | transmitted. |
| | | - Fix potential out-of-bounds array access with client ids. Fixes bug |
| | | #1083182. |
| | | |
| | | Other: |
| | | - mosquitto_passwd can now convert password files with plain text files to |
| | | hashed versions. |
| | | |
| | | 1.0.5 - 20121103 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix crash when the broker has use_identity_as_username set to true but a |
| | | client connects without a certificate. |
| | | - mosquitto_passwd should only be installed if WITH_TLS=yes. |
| | | |
| | | Library: |
| | | - Use symbolic errno values rather than numbers in Python module to avoid |
| | | cross platform issues (incorrect errno on Mac OS). |
| | | |
| | | Other: |
| | | - Build script fixes for FreeBSD. |
| | | |
| | | 1.0.4 - 20121017 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Deal with poll() POLLIN/POLLOUT before POLL[RD]HUP to correctly handle the |
| | | case where a client sends data and immediately closes its socket. |
| | | |
| | | Library: |
| | | - Fix memory leak with messages of QoS=2. Fixes bug #1064981. |
| | | - Fix potential thread synchronisation problem with outgoing packets in the |
| | | Python module. Fixes bug #1064977. |
| | | |
| | | Clients: |
| | | - Fix "mosquitto_sub -l" incorrectly only sending one message per second. |
| | | |
| | | 1.0.3 - 20120927 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix loading of psk files. |
| | | - Don't return an error when reloading config if an ACL file isn't defined. |
| | | This was preventing psk files being reloaded. |
| | | - Clarify meaning of $SYS/broker/clients/total in mosquitto(8) man page. |
| | | - Clarify meaning of $SYS/broker/messages/stored in mosquitto(8) man page. |
| | | - Fix non-retained message delivery when subscribing to #. |
| | | - Fix retained message delivery for subs to foo/# with retained messages at |
| | | foo. |
| | | - Include the filename in password/acl file loading errors. |
| | | |
| | | Library: |
| | | - Fix possible AttributeError when self._sock == None in Python module. |
| | | - Fix reconnecting after a timeout in Python module. |
| | | - Fix reconnecting when there were outgoing packets in the queue in the Python |
| | | module. |
| | | - Fix problem with mutex initialisation causing crashes on some Windows |
| | | installations. |
| | | |
| | | 1.0.2 - 20120919 |
| | | ================ |
| | | |
| | | Broker: |
| | | - If the broker was configured for persistence, a durable client had a |
| | | subscription to topics in $SYS/# and had messages in its queue when the |
| | | broker restarted, then the persistent database would have messages missing |
| | | and so the broker would not restart properly. This has been fixed. |
| | | |
| | | Library: |
| | | - Fix threading problem on some systems. |
| | | |
| | | Tests: |
| | | - Close socket after 08-ssl-connect-no-auth-wrong-ca.py test to prevent |
| | | subsequent tests having problems. |
| | | |
| | | Build scripts: |
| | | - Install pskfile.example in CMake. Fixes bug #1037504. |
| | | |
| | | Other: |
| | | - Fix db_dump parameter printing message store and sub chunks. |
| | | |
| | | 1.0.1 - 20120815 |
| | | ================ |
| | | |
| | | Broker: |
| | | - Fix default log_dest when running as a Windows service. |
| | | |
| | | Client library: |
| | | - Fix incorrect parameters in Python on_log() callback call. Fixes bug |
| | | #1036818. |
| | | |
| | | Clients: |
| | | - Clients now don't display TLS/TLS-PSK usage help if they don't support it. |
| | | |
| | | Build scripts: |
| | | - Fix TLS-PSK support in the CMake build files. |
| | | - Fix man page installation in the CMake build files. |
| | | - Fix SYSCONFDIR in cmake on *nix when installing to /usr. Fixes bug #1036908. |
| | | |
| | | Documentation: |
| | | - Fix mqtt/MQTT capitalisation in man pages. |
| | | - Update compiling.txt. |
| | | - Fix incorrect callback docs in mosquitto.py. Fixes bug #1036607. |
| | | - Fix various doc typos and remove obsolete script. Fixes bug #1037088. |
| | | |
| | | 1.0 - 20120814 |
| | | ============== |
| | | |
| | | Broker: |
| | | |
| | | - Add SSL/TLS support. |
| | | - Add TLS-PSK support, providing a simpler encryption method for constrained |
| | | devices. |
| | | - Passwords are now salted+hashed if compiled with WITH_TLS (recommended). |
| | | - Add mosquitto_passwd for handling password files. |
| | | - Add $SYS/broker/publish/messages/{sent|received} to show the number of |
| | | PUBLISH messages sent/received. |
| | | - Add $SYS/broker/publish/bytes/{sent|received} to show the number of |
| | | PUBLISH bytes sent/received. |
| | | - Add reload parameter for security init/cleanup functions. |
| | | - Add option for expiring disconnected persistent clients. |
| | | - Add option for queueing of QoS 0 messages when persistent clients are |
| | | disconnected. |
| | | - Enforce client id limits in the broker (only when WITH_STRICT_PROTOCOL is |
| | | defined). |
| | | - Fix reloading of log configuration. |
| | | - Add support for try_private config option for bridge connections. |
| | | - Add support for autosave_on_changes config option. |
| | | - Add support for include_dir config option. |
| | | - Add support for topic remapping. |
| | | - Usernames were being lost when a non clean-session client reconnected, |
| | | potentially causing problems with ACLs. This has been fixed. |
| | | - Significant improvement to memory handling on Windows. |
| | | - Bridges with outgoing topics will now set the retain flag correctly so that |
| | | messages will be retained on the remote broker. |
| | | - Incoming bridge connections are now detected by checking if bit 8 of the |
| | | protocol version number is set. This requires support from the remote broker. |
| | | - Add support for notification_topic option. |
| | | - Add $SYS/broker/subscriptions/count and $SYS/broker/retained messages/count. |
| | | - Add restart_timeout to control the amount of time an automatic bridge will |
| | | wait before reconnecting. |
| | | - Overlapping subscriptions are now handled properly. Fixes bug #928538. |
| | | - Fix reloading of persistence_file and persistence_location. |
| | | - Fix broker crash on incorrect protocol number. |
| | | - Fix missing COMPAT_ECONNRESET define on Windows. |
| | | - Clients that had disconnected were not always being detected immediately on |
| | | Linux. This has been fixed. |
| | | - Don't save $SYS messages to the on-disk persistent db. All $SYS messages |
| | | should be reconstructed on a restart. This means bridge connection |
| | | notifications will now be correct on a restart. |
| | | - Fix reloading of bridge clients from the persistent db. This means that |
| | | outgoing bridged topics should always work. |
| | | - Local bridges are now no longer restricted by local ACLs. |
| | | - Discard publish messages with zero length topics. |
| | | - Drop to "mosquitto" user even if no config file specified. |
| | | - Don't incorrectly allow topic access if ACL patterns but no normal ACL rules |
| | | are defined. |
| | | |
| | | Client library: |
| | | |
| | | - Add SSL/TLS support. |
| | | - Add TLS-PSK support, providing a simpler encryption method for constrained |
| | | devices. |
| | | - Add javascript/websockets client library. |
| | | - Add "struct mosquitto *mosq" parameter for all callbacks in the client |
| | | library. This is a binary incompatible change so the soversion of the |
| | | libraries has been incremented. The new parameter should make it easier to |
| | | use callbacks in practice. |
| | | - Add mosquitto_want_write() for use when using own select() loop with |
| | | mosquitto_socket(). |
| | | - Add mosquitto_connect_async() to provide a non-blocking connect client call. |
| | | - Add mosquitto_user_data_set() to allow user data pointer to be updated. |
| | | - Add "int rc" parameter to disconnect callback to indicate whether disconnect |
| | | was unexpected or the result of calling mosquitto_disconnect(). |
| | | - Add mosquitto_strerror() for obtaining a string description of error numbers. |
| | | - Add mosquitto_connack_string() for obtaining a string description of MQTT |
| | | connection results. |
| | | - Add mosquitto_will_clear() and change mosquitto_will_set() to only set the |
| | | will. |
| | | - Add mosquitto_sub_topic_tokenise() and mosquitto_sub_topic_tokens_free() |
| | | utility functions to tokenise a subscription/topic string into a string |
| | | array. |
| | | - Add mosquitto_topic_matches_sub() to check whether a topic matches a |
| | | subscription. |
| | | - Replaced mosquitto_log_init() with mosquitto_log_callback_set() to allow |
| | | clients to decide what to do with log messages. |
| | | - Client will now disconnect itself from the broker if it doesn't receive a |
| | | PINGRESP in the keepalive period after sending a PINGREQ. |
| | | - Client will now send a PINGREQ if it has not received a message from the |
| | | broker in keepalive seconds. |
| | | - mosquitto_new() will now generate a random client id if the id parameter is |
| | | NULL. |
| | | - Added max_packets to mosquitto_loop(), mosquitto_loop_read() and |
| | | mosquitto_loop_write() to control the maximum number of packets that are |
| | | handled per call. |
| | | - Payload parameters are now void * instead of uint8_t *. |
| | | - The clean_session parameter has been moved from mosquitto_connect() to |
| | | mosquitto_new() because it is a client parameter rather than a connection |
| | | parameter. |
| | | - Functions now use int instead of uint*_t where possible. |
| | | - mosquitto_new() now sets errno to indicate failure type. |
| | | - Return MOSQ_ERR_INVAL on zero length topic. |
| | | - Fix automatic client id generation on Windows. |
| | | - mosquitto_loop_misq() can now return MOSQ_ERR_NO_CONN. |
| | | - Compile static library as well as dynamic library with default makefiles. |
| | | - Rename C++ namespace from mosquittopp to mosqpp to remove ambiguity. |
| | | - C++ lib_init(), lib_version() and lib_cleanup() are now in the mosqpp |
| | | namespace directly, not mosquittopp class members. |
| | | - The Python library is now written in pure Python and so no longer depends on |
| | | libmosquitto. |
| | | - The Python library includes SSL/TLS support. |
| | | - The Python library should now be compatible with Python 3. |
| | | |
| | | Other: |
| | | |
| | | - Fix db_dump reading of retained messages. |
| | | - Add example of logging all messages to mysql. |
| | | - Add C++ client example. |
| | | - Fix potential buffer overflow in pub/sub clients. |
| | | - Add "make binary" target that doesn't make documents. |
| | | - Add "--help" arguments to pub/sub clients. |
| | | - Fix building on Solaris. |
| | | |
| | | 0.15 - 20120205 |
| | | =============== |
| | | |
| | | - Add support for $SYS/broker/clients/maximum and $SYS/broker/clients/active |
| | | topics. |
| | | - Add support for $SYS messages/byte per second received/sent topics. |
| | | - Updated mosquitto man page - $SYS hierarchy and signal support were out of |
| | | date. |
| | | - Auto generated pub/sub client ids now include the hostname. |
| | | - Tool for dumping persistent DB contents is available in src/db_dump. It isn't |
| | | installed by default. |
| | | - Enforce topic length checks in client library. |
| | | - Implement "once" and "lazy" bridge start types. |
| | | - Add new return type MOSQ_ERR_ERRNO to indicate that the errno variable should |
| | | be checked for the real error code. |
| | | - Add support for connection_messages config option. |
| | | - mosquitto_sub will now refuse to run if the -c option (disable clean session) |
| | | is given and no client id is provided. |
| | | - mosquitto_pub now gives more useful error messages on invalid input or other |
| | | error conditions. |
| | | - Fix Python will_set() true/True typo. |
| | | - Fix messages to topic "a/b" incorrectly matching on a subscription "a" if |
| | | another subscription "a/#" exists. |
| | | |
| | | 0.14.4 - 20120106 |
| | | ================= |
| | | |
| | | - Fix local bridge notification messages. |
| | | - Fix return values for more internal library calls. |
| | | - Fix incorrect out of memory checks in library and broker. |
| | | - Never time out local bridge connections. |
| | | |
| | | 0.14.3 - 20111210 |
| | | ================= |
| | | |
| | | - Fix potential crash when client connects with an invalid CONNECT packet. |
| | | - Fix incorrect invalid socket comparison on Windows. |
| | | - Server shouldn't crash when a message is published to foo/ when a |
| | | subscription to foo/# exists (bug #901697). |
| | | - SO_REUSEADDR doesn't work the same on Windows, so don't use it. |
| | | - Cygwin builds now support Windows service features. |
| | | - Fix $SYS/broker/bytes/sent reporting. |
| | | |
| | | 0.14.2 - 20111123 |
| | | ================= |
| | | |
| | | - Add uninstall target for libs. |
| | | - Don't try to write packet whilst in a callback. |
| | | |
| | | 0.14.1 - 20111117 |
| | | ================= |
| | | |
| | | - Fix Python sytax errors (bug #891673). |
| | | |
| | | 0.14 - 20111116 |
| | | =============== |
| | | |
| | | - Add support for matching ACLs based on client id and username. |
| | | - Add a Windows installer file (NSIS based). |
| | | - Add native support for running the broker as a Windows service. This is the |
| | | default when installed using the new installer. |
| | | - Fix client count for listeners. When clients disconnect, decrement the |
| | | count. Allow max_connections to work again. |
| | | - Attempt to send all packets immediately upon being queued. This will result |
| | | in more immediate network communication in many cases. |
| | | - Log IP address when reporting CONNACK packets if the client id isn't yet |
| | | known. |
| | | - Fix payload length calculation in python will_set function. |
| | | - Fix Python publish and will_set functions for payload=None. |
| | | - Fix keepalive value being lost when reconnecting a client (bug #880863). |
| | | - Persistence file writing now uses portable file functions, so the Cygwin |
| | | broker build should no longer be necessary. |
| | | - Duplicate code between the client and broker side has been reduced. |
| | | - Queued messages for clients reconnecting with clean_session=false set were |
| | | not being sent until the next message for that client was received. This has |
| | | been fixed (bug #890724). |
| | | - Fix subscriptions to # incorrectly matching against topics beginning with / |
| | | |
| | | 0.13 - 20110920 |
| | | =============== |
| | | |
| | | - Implement bridge state notification messages. |
| | | - Save client last used mid in persistent database (DB version number bumped). |
| | | - Expose message id in Python MosquittoMessage. |
| | | - It is now possible to set the topic QoS level for bridges. |
| | | - Python MosquittoMessage payload parameter is now a Python string, not a |
| | | ctypes object which makes it much easier to use. |
| | | - Fix queueing of messages for disconnected clients. The max_queued_messages |
| | | option is now obeyed. |
| | | - C++ library is now in its own namespace, mosquittopp. |
| | | - Add support for adding log message timestamps in the broker. |
| | | - Fix missing mosquitto_username_pw_set() python binding. |
| | | - Fix keepalive timeout for reconnecting non clean-session clients. Prevents |
| | | immediate disconnection on reconnection. |
| | | - Fix subscription wildcard matching - a subscription of +/+ will now match |
| | | against /foo |
| | | - Fix subscription wildcard matching - a subscription of foo/# will now match |
| | | against foo |
| | | - When restoring persistent database, clients should be set to non |
| | | clean-session or their subscriptions will be immediately removed. |
| | | - Fix SUBACK payload for multiple topic subscriptions. |
| | | - Don't send retained messages when a client subscribes to a topic it is |
| | | already subscribed to. |
| | | |
| | | 0.12 - 20110725 |
| | | =============== |
| | | |
| | | - Reload (most) configuration on SIGHUP. |
| | | - Memory tracking is no longer compiled in the client library. |
| | | - Add --help option to mosquitto to display usage. |
| | | - Add --id-prefix option to clients to allow easier use with brokers that are |
| | | using the clientid_prefix option. |
| | | - Fix compilation on QNX. |
| | | - Add -P as a synonym argument for --pw in the clients. |
| | | - Fix python MosquittoMessage payload parameter. This is now returned as a |
| | | pointer to an array of c_uint8 values so binary data is handled correctly. |
| | | If a string is needed, use msg.payload_str |
| | | - Fix memory leaks on client authentication. |
| | | - If password_file is not defined then clients can now connect even if they |
| | | use a username/password. |
| | | - Add mosquitto_reconnect() to the client library. |
| | | - Add option for compiling with liberal protocol compliance support (enabled |
| | | by default). |
| | | - Fix problems with clients reconnecting and old messages remaining in the |
| | | message store. |
| | | - Display both ip and client id in the log message when a client connects. |
| | | Change the socket connection message to make it more obvious that it is just |
| | | a socket connection being made (bug #801135). |
| | | - Fix retained message delivery where a subscription contains a +. |
| | | - Be more lenient when reloading persistent database to reduce errors with |
| | | empty retained messages. |
| | | |
| | | 0.11.3 - 20110707 |
| | | ================= |
| | | |
| | | - Don't complain and quit if persistence_file option is given (bug #802423). |
| | | - Initialise listeners correctly when clients with duplicate client ids |
| | | connect. Bug #801678. |
| | | - Memory tracking is now disabled for Symbian builds due to lack of malloc.h. |
| | | - Fix memory tracking compilation for kFreeBSD. |
| | | - Python callbacks can now be used with class member functions. |
| | | - Fix persistent database writing of client message chunks which caused |
| | | errors when restoring (bug #798164). |
| | | |
| | | 0.11.2 - 20110626 |
| | | ================= |
| | | |
| | | - Don't free contexts in mqtt3_context_disconnect() (bug #799688 / #801678). |
| | | - Only free will if present when freeing a client context. |
| | | |
| | | 0.11.1 - 20110620 |
| | | ================= |
| | | |
| | | - Fix buffer overrun when checking for + and # in topics (bug #799688). |
| | | - Pub client now quits if publish fails. |
| | | |
| | | 0.11 - 20110619 |
| | | =============== |
| | | |
| | | - Removed all old sqlite code. |
| | | - Remove client id limit in clients. |
| | | - Implemented $SYS/broker/heap/maximum size |
| | | - Implemented $SYS/broker/clients/inactive to show the number of disconnected |
| | | non-clean session clients. |
| | | - $SYS/broker/heap/current size and maximum size messages now include "bytes" |
| | | to match rsmb message format. |
| | | - Implemented the retained_persistence config file option - a synonym of the |
| | | "persistence" option. |
| | | - Added security_external.c to broker source to make it easier for third |
| | | parties to add support for their existing username/password and ACL database |
| | | for security checks. See external_security_checks.txt. |
| | | - $SYS messages are now only republished when their value changes. |
| | | - Windows native broker now responds to command line arguments. |
| | | - Simplify client disconnecting so wills gets sent in all cases (bug #792468). |
| | | - Clients now have a --quiet option. |
| | | - The on_disconnect() callback will always be called now, even if the client |
| | | has disconnected unexpectedly. |
| | | - Always close persistent DB file after restoring. |
| | | - Return error code when exiting the clients. |
| | | - mosquitto_publish() now returns MOSQ_ERR_INVAL if the topic contains + or # |
| | | - mosquitto now silently rejects published messages with + or # in the topic. |
| | | - max_connections is now a per-listener setting instead of global. |
| | | - Connection count is now reduced when clients disconnect (bug #797983). |
| | | |
| | | 0.10.2 - 20110106 |
| | | ================= |
| | | |
| | | - Don't abort when connecting if the first connection fails. This is important |
| | | on e.g. Windows 7, where IPV6 is offered as the first choice but may not be |
| | | available. |
| | | - Deal with long logging messages properly (bug #785882). |
| | | - Fix library compilation on Symbian - no pselect() available. |
| | | - Don't stop processing subscriptions on received messages after a |
| | | subscription with # matches. (bug #791206). |
| | | |
| | | 0.10.1 - 20110512 |
| | | ================= |
| | | |
| | | - Fix Windows compilation. |
| | | - Fix mosquitto.py on Windows - call lib init/cleanup. |
| | | - Don't abort when connecting if given an unknown address type (assuming an |
| | | IPv4 or IPv6 address is given). |
| | | |
| | | 0.10 - 20110429 |
| | | =============== |
| | | |
| | | - Implement support for the password_file option and accompanying |
| | | authentication requirements in the broker. |
| | | - Implement topic Access Control Lists. |
| | | - mosquitto_will_set() and mosquitto_publish() now return |
| | | MOSQ_ERR_PAYLOAD_SIZE if the payload is too large (>268,435,455 bytes). |
| | | - Bridge support can now be disabled at compile time. |
| | | - Group together network writes for outgoing packets - don't send single byte |
| | | writes! |
| | | - Add support for clientid_prefixes variable. |
| | | - Add support for the clientid config variable for controlling bridge client |
| | | ids. |
| | | - Remove 32-bit database ID support because htobe64() no longer used. |
| | | - Multiple client subscriptions to the same topic result in only a single |
| | | subscription. Bug #744077. |
| | | |
| | | 0.9.3 - 20110310 |
| | | ================ |
| | | |
| | | - Set retained message status for QoS 2 messages (bug #726535). |
| | | - Only abort with an error when opening listening sockets if no address family |
| | | is available, rather than aborting when any address family is not available. |
| | | - Don't clean queued messages when a non clean session client reconnects. |
| | | - Make mosquitto.py compatible with Python <2.6. |
| | | - Fix mosquitto.h header includes for Windows. |
| | | |
| | | 0.9.2 - 20110208 |
| | | ================ |
| | | |
| | | - Only send a single DISCONNECT command when using -l in the pub client. |
| | | - Set QoS=1 on PUBREL commands to meet protocol spec. |
| | | - Don't leak sockets on connection failure in the library. |
| | | - Install man pages when building under cmake. |
| | | - Fix crash bug on malformed CONNECT message. |
| | | - Clients are now rejected if their socket peer name cannot be obtained on |
| | | connection. |
| | | - Fix a number of potential problems caused when a client with a duplicate id |
| | | connects. |
| | | - Install mosquitto.conf under cmake. |
| | | |
| | | 0.9.1 - 20101203 |
| | | ================ |
| | | |
| | | - Add missing code for parsing the "bind_address" configuration option. |
| | | - Fix missing include when compiling with tcp-wrappers support. |
| | | - Add linker version script for C library to control exported functions. |
| | | |
| | | 0.9 - 20101114 |
| | | ============== |
| | | |
| | | - Client and message data is now stored in memory with custom routines rather |
| | | than a sqlite database. This removes the dependencies on sqlite, pcre and |
| | | sqlite3-pcre. It also means that the persistent database format has had to |
| | | be reimplemented in a custom format. Optional support for importing old |
| | | sqlite databases is provided. |
| | | - Added IPv6 support for mosquitto and the clients. |
| | | - Provide username and password support for the clients and client libraries. |
| | | This is part of the new MQTT v3.1 spec. |
| | | - The broker supports the username and password connection flags, but will not |
| | | do anything with the username and password. |
| | | - Python callback functions now optionally take an extra argument which will |
| | | return the user object passed to the Mosquitto() constructor, or the calling |
| | | python object itself if nothing was given to Mosquitto(). |
| | | - Remove the mosquitto command line option "-i interface". |
| | | - Remove the mosquitto.conf "interface" variable. |
| | | - Add support for the listener config variable (replaces the interface |
| | | variable) |
| | | - Add support for the bind_address config variable. |
| | | - Change the port config variable behaviour to match that of rsmb (applies to |
| | | the default listener only, can be given just once). |
| | | - Fix QoS 2 protocol compliance - stop sending duplicate messages and handle |
| | | timeouts correctly. Fixes bug #598290. |
| | | - Set retain flag correctly for outgoing messages. It should only be set for |
| | | messages sent in response to a subscribe command (ie. stale data). |
| | | - Fix bug in returning correct CONNACK result to on_connect client callback. |
| | | - Don't send client will if it is disconnected for exceeding its keepalive |
| | | timer. |
| | | - Fix client library unsubscribe function incorrectly sending a SUBSCRIBE |
| | | command when it should be UNSUBSCRIBE. |
| | | - Fix max_inflight_messages and max_queued_messages operation. These |
| | | parameters now apply only to QoS 1 and 2 messages and are used regardless of |
| | | the client connection state. |
| | | - mosquitto.conf now installed to /etc/mosquitto/mosquitto.conf instead of |
| | | /etc/mosquitto.conf. The /etc/mosquitto/ directory will be used for password |
| | | and access control files in the future. |
| | | - Give the compile time option of using 32-bit integers for the database IDs |
| | | instead of 64-bit integers. This is useful where htobe64()/be64toh() are not |
| | | available or for embedded systems for example. |
| | | - The DUP bit is now set correctly when resending PUBREL messages. |
| | | - A port to Windows native has been partially completed. This currently drops a |
| | | number of features, including the ability to change configuration parameters |
| | | and persistent storage. |
| | | |
| | | 0.8.3 - 20101004 |
| | | ================ |
| | | |
| | | - Fix QoS 2 protocol compliance - stop sending duplicate messages and handle |
| | | timeouts correctly. Fixes bug #598290. (backported from future 0.9 code) |
| | | |
| | | 0.8.2 - 20100815 |
| | | ================ |
| | | |
| | | - Fix default loop() timeout value in mosquitto.py. Previous value was 0, |
| | | causing high cpu load. |
| | | - Fix message handling problem in client library when more than one message was |
| | | in the client queue. |
| | | - Fix the logic used to determine whether a QoS>0 message needs to be retried. |
| | | - Fix the Python sub.py example so that it quits on error. |
| | | |
| | | 0.8.1 - 20100812 |
| | | ================ |
| | | |
| | | - Improve python interface |
| | | - Fix incorrect return value from message delete function |
| | | - Use logging function to print error messages in clients. |
| | | - Fix python installation script DESTDIR. |
| | | - Fix library destination path for 64-bit machines. |
| | | |
| | | 0.8 - 20100807 |
| | | ============== |
| | | |
| | | - Topics starting with a / are treated as distinct to those not starting with |
| | | a /. For example, /topic/path is different to topic/path. This matches the |
| | | behaviour of rsmb. |
| | | - Correctly calculate the will QoS on a new client connection (bug #597451). |
| | | - Add "addresses" configuration file variable as an alias of "address", for |
| | | better rsmb compatibility. |
| | | - Bridge clean_session setting is now false, to give more sensible behaviour |
| | | and be more compatible with rsmb. |
| | | - Add cleansession variable for configuring bridges. |
| | | - Add keepalive_interval variable for bridges. |
| | | - Remove default topic subscription for mosquitto_sub because the old |
| | | behaviour was too confusing. |
| | | - Added a C client library, which the pub and sub clients now use. |
| | | - Added a C++ client library (bound to the C library). |
| | | - Added a Python client library (bound to the C library). |
| | | - Added CMake build scripts to allow the library and clients (not the broker) |
| | | to be compiled natively on Windows. |
| | | |
| | | 0.7 - 20100615 |
| | | ============== |
| | | |
| | | - mosquitto_pub can now send null (zero length) messages. |
| | | - Don't store QoS=0 messages for disconnected clients with subscriptions of |
| | | QoS>0. |
| | | - accept() all available sockets when new clients are connecting, rather than |
| | | just one. |
| | | - Add option to print debug messages in pub and sub clients. |
| | | - hg revision is now exported via $SYS/broker/changeset |
| | | - Send Will when client exceeds keepalive timer and is disconnected. |
| | | - Check to see if a client has a will before sending it. |
| | | - Correctly deal with clients connecting with the same id multiple times. |
| | | - Add compile time option to disable heap memory tracking. |
| | | - Use poll() instead of select() to allow >1024 clients. |
| | | - Implement max_connections. |
| | | - Run VACUUM on in-memory database on receiving SIGUSR2. |
| | | - Fix bridge keepalive timeouts and reconnects. |
| | | - Don't attempt to drop root privileges when running on Windows as this isn't |
| | | well supported (bug #586231). |
| | | |
| | | 0.6.1 - 20100506 |
| | | ================ |
| | | |
| | | - Fix DB auto upgrade for messages table. |
| | | |
| | | 0.6 - 20100505 |
| | | ============== |
| | | |
| | | - Basic support for connecting multiple MQTT brokers together (bridging). |
| | | - mosquitto_sub can now subscribe to multiple topics (limited to a global QoS). |
| | | - mosquitto_pub can now send a file as a message. |
| | | - mosquitto_pub can now read all of stdin and send it as a message. |
| | | - mosquitto_pub can now read stdin and send each line as a message. |
| | | - mosquitto will now correctly run VACUUM on the persistent database on exit. |
| | | - Implement a more efficient database design, so that only one copy of each |
| | | message is held in the database, rather than one per subscribed client. |
| | | - Add the store_cleanup_interval config option for dealing with the internal |
| | | message store. |
| | | - Add support for disabling "clean session" for the sub client. |
| | | - Add support for automatic upgrading of the mosquitto DB from v1 to v2. |
| | | - Add persistence_file config option to allow changing the filename of the |
| | | persistence database. This allows multiple mosquitto DBs to be stored in the |
| | | same location whilst keeping persistence_location compatible with rsmb. |
| | | - Don't store QoS=0 messages for disconnected clients. Fixes bug #572608. This |
| | | wasn't correctly fixed in version 0.5. |
| | | - Don't disconnect clients if they send a PUBLISH with zero length payload |
| | | (bug #573610). |
| | | - If a retained message is received with a zero length payload, the retained |
| | | message for that topic is deleted. |
| | | - Send through zero length messages. |
| | | - Produce a warning on unsupported rsmb options instead of quitting. |
| | | - Describe clean session flag in the mqtt man page. |
| | | - Implement the max_inflight_messages and max_queued_messages features in the |
| | | broker. |
| | | |
| | | 0.5.4 - 20100311 |
| | | ================ |
| | | |
| | | - Fix memory allocation in mqtt3_fix_sub_topic() (bug #531861). |
| | | - Remove accidental limit of 100 client connections. |
| | | - Fix mosquitto_pub handling of messages with QoS>0 (bug #537061). |
| | | |
| | | 0.5.3 - 20100303 |
| | | ================ |
| | | |
| | | - Will messages are now only sent when a client disconnects unexpectedly. |
| | | - Fix all incoming topics/subscriptions that start with a / or contain |
| | | multiple / in a row (//). |
| | | - Do actually disconnect client when it sends an empty subscription/topic string. |
| | | - Add missing $SYS/broker/clients/total to man page. |
| | | |
| | | 0.5.2 - 20100302 |
| | | ================ |
| | | |
| | | - Always update last backup time, so that the backup doesn't run every time |
| | | through the main loop once autosave_interval has been reached. |
| | | - Report $SYS/broker/uptime in the same format as rsmb. |
| | | - Make mandatory options obvious in usage output and man page of mosquitto_pub. |
| | | Fixes bug #529990. |
| | | - Treat subscriptions with a trailing slash correctly. This should fix bugs |
| | | #530369 and #530099. |
| | | |
| | | 0.5.1 - 20100227 |
| | | ================ |
| | | |
| | | - Must daemonise before pid file is written. |
| | | |
| | | 0.5 - 20100227 |
| | | ============== |
| | | |
| | | - No longer store QoS=0 messages for disconnected clients that do not have |
| | | clean start set. |
| | | - Rename msg_timeout option to retry_interval for better rsmb compatibility. |
| | | - Change persistence behaviour. The database is now stored in memory even if |
| | | persistence is enabled. It is written to disk when mosquitto exits and also at |
| | | periodic intervals as defined by the new autosave_interval option. |
| | | - The writing of the persistence database may be forced by sending mosquitto |
| | | the SIGUSR1 signal. |
| | | - Clients that do not send CONNECT as their first command are now |
| | | disconnected. |
| | | - Boolean configuration values may now be specified with true/false as well as |
| | | 1/0. |
| | | - Log message on CONNECT with invalid protocol or protocol version. |
| | | - Default sqlite3-pcre path on Linux is now /usr/lib/sqlite3/pcre.so to match |
| | | future sqlite3-pcre packages. |
| | | - Add mosquitto_sub and mosquitto_pub, simple clients for subscribe/publish. |
| | | - Add man pages for clients. |
| | | - Add general man page on mqtt. |
| | | - Root privileges are now dropped only after attempting to write a pid file |
| | | (if configured). This means that the pid file can be written to /var/run/ |
| | | directly and should fix bug #523183. |
| | | |
| | | 0.4.2 - 20100203 |
| | | ================ |
| | | |
| | | - Fix segfault on client connect with invalid protocol name/version. |
| | | |
| | | 0.4.1 - 20100112 |
| | | =============== |
| | | |
| | | - Fix regex used for finding retained messages to send on new subscription. |
| | | |
| | | 0.4 - 20100105 |
| | | ============== |
| | | |
| | | - Added support for wildcard subscriptions using + and #. |
| | | - All network operations are now non-blocking and can cope with partial |
| | | packets, meaning that networking should be a lot more reliable. |
| | | - Total messsages/bytes sent/received are now available in $SYS. |
| | | - Improved logging information - use client ip address and id instead of |
| | | socket number. |
| | | - Broker build timestamp is available in $SYS. |
| | | - Keepalive==0 is now correctly treated as "never disconnect". |
| | | - Fixed manpage installation. |
| | | - Fixed incorrect $SYS hierarchy locations in documentation and code. |
| | | - Debug type log messages are no longer sent to "topics". |
| | | - Default logging destination no longer includes "topics" to prevent possible |
| | | error logging to the db before it is initialised. |
| | | - Periodic $SYS messages can now be disabled. |
| | | - stdout and stderr are flushed when logging to them to give more timely |
| | | updates. |
| | | - dup is now set correctly when resending messages. |
| | | - Database format bumped due to topic column naming fix. |
| | | |
| | | 0.3 - 20091217 |
| | | ============== |
| | | |
| | | - The port option in the configuration file and --port command line argument |
| | | may now be given any number of times to make mosquitto listen on multiple |
| | | sockets. |
| | | - Add new config file and command line option "interface" to specify an |
| | | interface to listen on, rather than all interfaces. |
| | | - Added host access control through tcp-wrappers support. |
| | | - Set SO_REUSEADDR on the listening socket so restart is much quicker. |
| | | - Added support for tracking current heap memory usage - this is published on |
| | | the topic "$SYS/broker/heap/current size" |
| | | - Added code for logging to stderr, stdout, syslog and topics. |
| | | - Added logging to numerous places - still plenty of scope for more. |
| | | |
| | | 0.2 - 20091204 |
| | | ============== |
| | | |
| | | - Replaced the command line option --foreground with --daemon, swapping the |
| | | default behaviour. |
| | | - Added the command line option --config-file, to specify a config file to |
| | | load. If this is not given, no config file is load and the default options |
| | | are used. |
| | | - Added the command line option --port for specifying the port to listen on. |
| | | This overrides values in the config file. |
| | | - Don't use persistence by default. |
| | | - Default behaviour is now more sane when run by a normal user with no command |
| | | line options (combination of above changes). |
| | | - Added option user to config file, defaulting to a value of mosquitto. If |
| | | this value isn't blank and mosquitto is started by root, then it will drop |
| | | privileges by changing to the user and its primary group. This replaces the |
| | | current behaviour of refusing to start if run by root. |
| | | - Fix non-persistent mode, which would never work in the previous release. |
| | | - Added information on default values of msg_timeout and sys_interval to the |
| | | mosquitto.conf man page. (closes bug #492045). |
New file |
| | |
| | | This project is dual licensed under the Eclipse Public License 1.0 and the |
| | | Eclipse Distribution License 1.0 as described in the epl-v10 and edl-v10 files. |
New file |
| | |
| | | include config.mk |
| | | |
| | | DIRS=lib client src |
| | | DOCDIRS=man |
| | | DISTDIRS=man |
| | | DISTFILES= \ |
| | | client/ \ |
| | | examples/ \ |
| | | installer/ \ |
| | | lib/ \ |
| | | logo/ \ |
| | | man/ \ |
| | | misc/ \ |
| | | security/ \ |
| | | service/ \ |
| | | src/ \ |
| | | test/ \ |
| | | \ |
| | | CMakeLists.txt \ |
| | | CONTRIBUTING.md \ |
| | | ChangeLog.txt \ |
| | | LICENSE.txt \ |
| | | Makefile \ |
| | | about.html \ |
| | | aclfile.example \ |
| | | compiling.txt \ |
| | | config.h \ |
| | | config.mk \ |
| | | edl-v10 \ |
| | | epl-v10 \ |
| | | libmosquitto.pc.in \ |
| | | libmosquittopp.pc.in \ |
| | | mosquitto.conf \ |
| | | notice.html \ |
| | | pskfile.example \ |
| | | pwfile.example \ |
| | | readme-windows.txt \ |
| | | readme.md |
| | | |
| | | .PHONY : all mosquitto api docs binary check clean reallyclean test install uninstall dist sign copy localdocker |
| | | |
| | | all : $(MAKE_ALL) |
| | | |
| | | api : |
| | | mkdir -p api p |
| | | naturaldocs -o HTML api -i lib -p p |
| | | rm -rf p |
| | | |
| | | docs : |
| | | set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d}; done |
| | | |
| | | binary : mosquitto |
| | | |
| | | mosquitto : |
| | | ifeq ($(UNAME),Darwin) |
| | | $(error Please compile using CMake on Mac OS X) |
| | | endif |
| | | |
| | | set -e; for d in ${DIRS}; do $(MAKE) -C $${d}; done |
| | | |
| | | clean : |
| | | set -e; for d in ${DIRS}; do $(MAKE) -C $${d} clean; done |
| | | set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} clean; done |
| | | $(MAKE) -C test clean |
| | | |
| | | reallyclean : |
| | | set -e; for d in ${DIRS}; do $(MAKE) -C $${d} reallyclean; done |
| | | set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} reallyclean; done |
| | | $(MAKE) -C test reallyclean |
| | | -rm -f *.orig |
| | | |
| | | check : test |
| | | |
| | | test : mosquitto |
| | | $(MAKE) -C test test |
| | | |
| | | ptest : mosquitto |
| | | $(MAKE) -C test ptest |
| | | |
| | | utest : mosquitto |
| | | $(MAKE) -C test utest |
| | | |
| | | install : mosquitto |
| | | set -e; for d in ${DIRS}; do $(MAKE) -C $${d} install; done |
| | | ifeq ($(WITH_DOCS),yes) |
| | | set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} install; done |
| | | endif |
| | | $(INSTALL) -d "${DESTDIR}/etc/mosquitto" |
| | | $(INSTALL) -m 644 mosquitto.conf "${DESTDIR}/etc/mosquitto/mosquitto.conf.example" |
| | | $(INSTALL) -m 644 aclfile.example "${DESTDIR}/etc/mosquitto/aclfile.example" |
| | | $(INSTALL) -m 644 pwfile.example "${DESTDIR}/etc/mosquitto/pwfile.example" |
| | | $(INSTALL) -m 644 pskfile.example "${DESTDIR}/etc/mosquitto/pskfile.example" |
| | | |
| | | uninstall : |
| | | set -e; for d in ${DIRS}; do $(MAKE) -C $${d} uninstall; done |
| | | rm -f "${DESTDIR}/etc/mosquitto/mosquitto.conf.example" |
| | | rm -f "${DESTDIR}/etc/mosquitto/aclfile.example" |
| | | rm -f "${DESTDIR}/etc/mosquitto/pwfile.example" |
| | | rm -f "${DESTDIR}/etc/mosquitto/pskfile.example" |
| | | |
| | | dist : reallyclean |
| | | set -e; for d in ${DISTDIRS}; do $(MAKE) -C $${d} dist; done |
| | | |
| | | mkdir -p dist/mosquitto-${VERSION} |
| | | cp -r ${DISTFILES} dist/mosquitto-${VERSION}/ |
| | | cd dist; tar -zcf mosquitto-${VERSION}.tar.gz mosquitto-${VERSION}/ |
| | | |
| | | sign : dist |
| | | cd dist; gpg --detach-sign -a mosquitto-${VERSION}.tar.gz |
| | | |
| | | copy : sign |
| | | cd dist; scp mosquitto-${VERSION}.tar.gz mosquitto-${VERSION}.tar.gz.asc mosquitto:site/mosquitto.org/files/source/ |
| | | cd dist; scp *.html mosquitto:site/mosquitto.org/man/ |
| | | scp ChangeLog.txt mosquitto:site/mosquitto.org/ |
| | | |
| | | coverage : |
| | | lcov --capture --directory . --output-file coverage.info |
| | | genhtml coverage.info --output-directory out |
| | | |
| | | localdocker : reallyclean |
| | | set -e; for d in ${DISTDIRS}; do $(MAKE) -C $${d} dist; done |
| | | |
| | | rm -rf dockertmp/ |
| | | mkdir -p dockertmp/mosquitto-${VERSION} |
| | | cp -r ${DISTFILES} dockertmp/mosquitto-${VERSION}/ |
| | | cd dockertmp/; tar -zcf mosq.tar.gz mosquitto-${VERSION}/ |
| | | cp dockertmp/mosq.tar.gz docker/local |
| | | rm -rf dockertmp/ |
| | | cd docker/local && docker build . |
| | | |
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| | | <html xmlns="http://www.w3.org/1999/xhtml"><head> |
| | | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
| | | <title>About</title> |
| | | </head> |
| | | <body lang="EN-US"> |
| | | <h2>About This Content</h2> |
| | | |
| | | <p><em>May 8, 2014</em></p> |
| | | <h3>License</h3> |
| | | |
| | | <p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise |
| | | indicated below, the Content is provided to you under the terms and conditions of the |
| | | Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL"). |
| | | A copy of the EPL is available at |
| | | <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> |
| | | and a copy of the EDL is available at |
| | | <a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>. |
| | | For purposes of the EPL, "Program" will mean the Content.</p> |
| | | |
| | | <p>If you did not receive this Content directly from the Eclipse Foundation, the Content is |
| | | being redistributed by another party ("Redistributor") and different terms and conditions may |
| | | apply to your use of any object code in the Content. Check the Redistributor's license that was |
| | | provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise |
| | | indicated below, the terms and conditions of the EPL still apply to any source code in the Content |
| | | and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p> |
| | | |
| | | |
| | | <h3>Third Party Content</h3> |
| | | <p>The Content includes items that have been sourced from third parties as set out below. If you |
| | | did not receive this Content directly from the Eclipse Foundation, the following is provided |
| | | for informational purposes only, and you should look to the Redistributor's license for |
| | | terms and conditions of use.</p> |
| | | |
| | | <h4>libwebsockets 2.4.2</h4> |
| | | <p>This project makes use of the libwebsockets library.</p> |
| | | <p>The use of libwebsockets is based on the terms and conditions of the |
| | | LGPL 2.1 with some specific exceptions. |
| | | <a href="https://github.com/warmcat/libwebsockets/blob/v2.4.2/LICENSE">https://github.com/warmcat/libwebsockets/blob/v2.4.2/LICENSE</a></p> |
| | | <p>When libwebsockets is distributed with the project, it is being used |
| | | subject to the Static Linking Exception (Section 2) of the License. As |
| | | a result, the content is not subject to the LGPL 2.1.</p> |
| | | |
| | | </body></html> |
New file |
| | |
| | | # This affects access control for clients with no username. |
| | | topic read $SYS/# |
| | | |
| | | # This only affects clients with username "roger". |
| | | user roger |
| | | topic foo/bar |
| | | |
| | | # This affects all clients. |
| | | pattern write $SYS/broker/connection/%c/state |
New file |
| | |
| | | include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib |
| | | ${STDBOOL_H_PATH} ${STDINT_H_PATH} ${PTHREAD_INCLUDE_DIR} |
| | | ${OPENSSL_INCLUDE_DIR}) |
| | | link_directories(${mosquitto_BINARY_DIR}/lib) |
| | | |
| | | set(shared_src client_shared.c client_shared.h client_props.c) |
| | | |
| | | if (WITH_SRV) |
| | | add_definitions("-DWITH_SRV") |
| | | endif (WITH_SRV) |
| | | |
| | | add_executable(mosquitto_pub pub_client.c pub_shared.c ${shared_src}) |
| | | add_executable(mosquitto_sub sub_client.c sub_client_output.c ${shared_src}) |
| | | add_executable(mosquitto_rr rr_client.c pub_shared.c sub_client_output.c ${shared_src}) |
| | | |
| | | |
| | | target_link_libraries(mosquitto_pub libmosquitto) |
| | | target_link_libraries(mosquitto_sub libmosquitto) |
| | | target_link_libraries(mosquitto_rr libmosquitto) |
| | | |
| | | if (QNX) |
| | | target_link_libraries(mosquitto_pub socket) |
| | | target_link_libraries(mosquitto_sub socket) |
| | | target_link_libraries(mosquitto_rr socket) |
| | | endif() |
| | | |
| | | install(TARGETS mosquitto_pub RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") |
| | | install(TARGETS mosquitto_sub RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") |
| | | install(TARGETS mosquitto_rr RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") |
New file |
| | |
| | | include ../config.mk |
| | | |
| | | .PHONY: all install uninstall reallyclean clean static static_pub static_sub static_rr |
| | | |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | SHARED_DEP:=../lib/libmosquitto.so.${SOVERSION} |
| | | endif |
| | | |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | ALL_DEPS:= mosquitto_pub mosquitto_sub mosquitto_rr |
| | | else |
| | | ifeq ($(WITH_STATIC_LIBRARIES),yes) |
| | | ALL_DEPS:= static_pub static_sub static_rr |
| | | endif |
| | | endif |
| | | |
| | | all : ${ALL_DEPS} |
| | | |
| | | static : static_pub static_sub static_rr |
| | | # This makes mosquitto_pub/sub/rr versions that are statically linked with |
| | | # libmosquitto only. |
| | | |
| | | static_pub : pub_client.o pub_shared.o client_props.o client_shared.o ../lib/libmosquitto.a |
| | | ${CROSS_COMPILE}${CC} $^ -o mosquitto_pub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} |
| | | |
| | | static_sub : sub_client.o sub_client_output.o client_props.o client_shared.o ../lib/libmosquitto.a |
| | | ${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} |
| | | |
| | | static_rr : rr_client.o client_props.o client_shared.o pub_shared.o sub_client_output.o ../lib/libmosquitto.a |
| | | ${CROSS_COMPILE}${CC} $^ -o mosquitto_rr ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} |
| | | |
| | | mosquitto_pub : pub_client.o pub_shared.o client_shared.o client_props.o |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_LDFLAGS) $^ -o $@ $(CLIENT_LDADD) |
| | | |
| | | mosquitto_sub : sub_client.o sub_client_output.o client_shared.o client_props.o |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_LDFLAGS) $^ -o $@ $(CLIENT_LDADD) |
| | | |
| | | mosquitto_rr : rr_client.o client_shared.o client_props.o pub_shared.o sub_client_output.o |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_LDFLAGS) $^ -o $@ $(CLIENT_LDADD) |
| | | |
| | | pub_client.o : pub_client.c ${SHARED_DEP} |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | pub_shared.o : pub_shared.c ${SHARED_DEP} |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | sub_client.o : sub_client.c ${SHARED_DEP} |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | sub_client_output.o : sub_client_output.c ${SHARED_DEP} |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | rr_client.o : rr_client.c ${SHARED_DEP} |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | client_shared.o : client_shared.c client_shared.h |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | client_props.o : client_props.c client_shared.h |
| | | ${CROSS_COMPILE}${CC} $(CLIENT_CPPFLAGS) $(CLIENT_CFLAGS) -c $< -o $@ |
| | | |
| | | ../lib/libmosquitto.so.${SOVERSION} : |
| | | $(MAKE) -C ../lib |
| | | |
| | | ../lib/libmosquitto.a : |
| | | $(MAKE) -C ../lib libmosquitto.a |
| | | |
| | | install : all |
| | | $(INSTALL) -d "${DESTDIR}$(prefix)/bin" |
| | | $(INSTALL) ${STRIP_OPTS} mosquitto_pub "${DESTDIR}${prefix}/bin/mosquitto_pub" |
| | | $(INSTALL) ${STRIP_OPTS} mosquitto_sub "${DESTDIR}${prefix}/bin/mosquitto_sub" |
| | | $(INSTALL) ${STRIP_OPTS} mosquitto_rr "${DESTDIR}${prefix}/bin/mosquitto_rr" |
| | | |
| | | uninstall : |
| | | -rm -f "${DESTDIR}${prefix}/bin/mosquitto_pub" |
| | | -rm -f "${DESTDIR}${prefix}/bin/mosquitto_sub" |
| | | -rm -f "${DESTDIR}${prefix}/bin/mosquitto_rr" |
| | | |
| | | reallyclean : clean |
| | | |
| | | clean : |
| | | -rm -f *.o mosquitto_pub mosquitto_sub mosquitto_rr *.gcda *.gcno |
New file |
| | |
| | | /* |
| | | Copyright (c) 2018 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <fcntl.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #ifndef WIN32 |
| | | #include <unistd.h> |
| | | #include <strings.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #define strncasecmp _strnicmp |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "client_shared.h" |
| | | |
| | | enum prop_type |
| | | { |
| | | PROP_TYPE_BYTE, |
| | | PROP_TYPE_INT16, |
| | | PROP_TYPE_INT32, |
| | | PROP_TYPE_BINARY, |
| | | PROP_TYPE_STRING, |
| | | PROP_TYPE_STRING_PAIR |
| | | }; |
| | | |
| | | /* This parses property inputs. It should work for any command type, but is limited at the moment. |
| | | * |
| | | * Format: |
| | | * |
| | | * command property value |
| | | * command property key value |
| | | * |
| | | * Example: |
| | | * |
| | | * publish message-expiry-interval 32 |
| | | * connect user-property key value |
| | | */ |
| | | |
| | | int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx) |
| | | { |
| | | char *cmdname = NULL, *propname = NULL; |
| | | char *key = NULL, *value = NULL; |
| | | int cmd, identifier, type; |
| | | mosquitto_property **proplist; |
| | | int rc; |
| | | |
| | | /* idx now points to "command" */ |
| | | if((*idx)+2 > argc-1){ |
| | | /* Not enough args */ |
| | | fprintf(stderr, "Error: --property argument given but not enough arguments specified.\n\n"); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | cmdname = argv[*idx]; |
| | | if(mosquitto_string_to_command(cmdname, &cmd)){ |
| | | fprintf(stderr, "Error: Invalid command given in --property argument.\n\n"); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | propname = argv[(*idx)+1]; |
| | | if(mosquitto_string_to_property_info(propname, &identifier, &type)){ |
| | | fprintf(stderr, "Error: Invalid property name given in --property argument.\n\n"); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | if(mosquitto_property_check_command(cmd, identifier)){ |
| | | fprintf(stderr, "Error: %s property not allow for %s in --property argument.\n\n", propname, cmdname); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | if(identifier == MQTT_PROP_USER_PROPERTY){ |
| | | if((*idx)+3 > argc-1){ |
| | | /* Not enough args */ |
| | | fprintf(stderr, "Error: --property argument given but not enough arguments specified.\n\n"); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | key = argv[(*idx)+2]; |
| | | value = argv[(*idx)+3]; |
| | | (*idx) += 3; |
| | | }else{ |
| | | value = argv[(*idx)+2]; |
| | | (*idx) += 2; |
| | | } |
| | | |
| | | |
| | | switch(cmd){ |
| | | case CMD_CONNECT: |
| | | proplist = &cfg->connect_props; |
| | | break; |
| | | |
| | | case CMD_PUBLISH: |
| | | if(identifier == MQTT_PROP_TOPIC_ALIAS){ |
| | | cfg->have_topic_alias = true; |
| | | } |
| | | if(identifier == MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ |
| | | fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | proplist = &cfg->publish_props; |
| | | break; |
| | | |
| | | case CMD_SUBSCRIBE: |
| | | if(identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER && identifier != MQTT_PROP_USER_PROPERTY){ |
| | | fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); |
| | | return MOSQ_ERR_NOT_SUPPORTED; |
| | | } |
| | | proplist = &cfg->subscribe_props; |
| | | break; |
| | | |
| | | case CMD_UNSUBSCRIBE: |
| | | proplist = &cfg->unsubscribe_props; |
| | | break; |
| | | |
| | | case CMD_DISCONNECT: |
| | | proplist = &cfg->disconnect_props; |
| | | break; |
| | | |
| | | case CMD_AUTH: |
| | | fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); |
| | | return MOSQ_ERR_NOT_SUPPORTED; |
| | | |
| | | case CMD_WILL: |
| | | proplist = &cfg->will_props; |
| | | break; |
| | | |
| | | case CMD_PUBACK: |
| | | case CMD_PUBREC: |
| | | case CMD_PUBREL: |
| | | case CMD_PUBCOMP: |
| | | case CMD_SUBACK: |
| | | case CMD_UNSUBACK: |
| | | fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); |
| | | return MOSQ_ERR_NOT_SUPPORTED; |
| | | |
| | | default: |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | switch(type){ |
| | | case MQTT_PROP_TYPE_BYTE: |
| | | rc = mosquitto_property_add_byte(proplist, identifier, atoi(value)); |
| | | break; |
| | | case MQTT_PROP_TYPE_INT16: |
| | | rc = mosquitto_property_add_int16(proplist, identifier, atoi(value)); |
| | | break; |
| | | case MQTT_PROP_TYPE_INT32: |
| | | rc = mosquitto_property_add_int32(proplist, identifier, atoi(value)); |
| | | break; |
| | | case MQTT_PROP_TYPE_VARINT: |
| | | rc = mosquitto_property_add_varint(proplist, identifier, atoi(value)); |
| | | break; |
| | | case MQTT_PROP_TYPE_BINARY: |
| | | rc = mosquitto_property_add_binary(proplist, identifier, value, strlen(value)); |
| | | break; |
| | | case MQTT_PROP_TYPE_STRING: |
| | | rc = mosquitto_property_add_string(proplist, identifier, value); |
| | | break; |
| | | case MQTT_PROP_TYPE_STRING_PAIR: |
| | | rc = mosquitto_property_add_string_pair(proplist, identifier, key, value); |
| | | break; |
| | | default: |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | if(rc){ |
| | | fprintf(stderr, "Error adding property %s %d\n", propname, type); |
| | | return rc; |
| | | } |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2014-2019 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <fcntl.h> |
| | | #include <stdarg.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #ifndef WIN32 |
| | | #include <unistd.h> |
| | | #include <strings.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #define strncasecmp _strnicmp |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include <mqtt_protocol.h> |
| | | #include "client_shared.h" |
| | | |
| | | #ifdef WITH_SOCKS |
| | | static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url); |
| | | #endif |
| | | static int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]); |
| | | |
| | | |
| | | static int check_format(const char *str) |
| | | { |
| | | int i; |
| | | int len; |
| | | |
| | | len = strlen(str); |
| | | for(i=0; i<len; i++){ |
| | | if(str[i] == '%'){ |
| | | if(i == len-1){ |
| | | // error |
| | | fprintf(stderr, "Error: Incomplete format specifier.\n"); |
| | | return 1; |
| | | }else{ |
| | | if(str[i+1] == '%'){ |
| | | // Print %, ignore |
| | | }else if(str[i+1] == 'I'){ |
| | | // ISO 8601 date+time |
| | | }else if(str[i+1] == 'l'){ |
| | | // payload length |
| | | }else if(str[i+1] == 'm'){ |
| | | // mid |
| | | }else if(str[i+1] == 'p'){ |
| | | // payload |
| | | }else if(str[i+1] == 'q'){ |
| | | // qos |
| | | }else if(str[i+1] == 'r'){ |
| | | // retain |
| | | }else if(str[i+1] == 't'){ |
| | | // topic |
| | | }else if(str[i+1] == 'j'){ |
| | | // JSON output, escaped payload |
| | | }else if(str[i+1] == 'J'){ |
| | | // JSON output, assuming JSON payload |
| | | }else if(str[i+1] == 'U'){ |
| | | // Unix time+nanoseconds |
| | | }else if(str[i+1] == 'x' || str[i+1] == 'X'){ |
| | | // payload in hex |
| | | }else{ |
| | | fprintf(stderr, "Error: Invalid format specifier '%c'.\n", str[i+1]); |
| | | return 1; |
| | | } |
| | | i++; |
| | | } |
| | | }else if(str[i] == '@'){ |
| | | if(i == len-1){ |
| | | // error |
| | | fprintf(stderr, "Error: Incomplete format specifier.\n"); |
| | | return 1; |
| | | } |
| | | i++; |
| | | }else if(str[i] == '\\'){ |
| | | if(i == len-1){ |
| | | // error |
| | | fprintf(stderr, "Error: Incomplete escape specifier.\n"); |
| | | return 1; |
| | | }else{ |
| | | switch(str[i+1]){ |
| | | case '\\': // '\' |
| | | case '0': // 0 (NULL) |
| | | case 'a': // alert |
| | | case 'e': // escape |
| | | case 'n': // new line |
| | | case 'r': // carriage return |
| | | case 't': // horizontal tab |
| | | case 'v': // vertical tab |
| | | break; |
| | | |
| | | default: |
| | | fprintf(stderr, "Error: Invalid escape specifier '%c'.\n", str[i+1]); |
| | | return 1; |
| | | } |
| | | i++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | void init_config(struct mosq_config *cfg, int pub_or_sub) |
| | | { |
| | | memset(cfg, 0, sizeof(*cfg)); |
| | | cfg->port = -1; |
| | | cfg->max_inflight = 20; |
| | | cfg->keepalive = 60; |
| | | cfg->clean_session = true; |
| | | cfg->eol = true; |
| | | cfg->repeat_count = 1; |
| | | cfg->repeat_delay.tv_sec = 0; |
| | | cfg->repeat_delay.tv_usec = 0; |
| | | if(pub_or_sub == CLIENT_RR){ |
| | | cfg->protocol_version = MQTT_PROTOCOL_V5; |
| | | cfg->msg_count = 1; |
| | | }else{ |
| | | cfg->protocol_version = MQTT_PROTOCOL_V311; |
| | | } |
| | | } |
| | | |
| | | void client_config_cleanup(struct mosq_config *cfg) |
| | | { |
| | | int i; |
| | | free(cfg->id); |
| | | free(cfg->id_prefix); |
| | | free(cfg->host); |
| | | free(cfg->file_input); |
| | | free(cfg->message); |
| | | free(cfg->topic); |
| | | free(cfg->bind_address); |
| | | free(cfg->username); |
| | | free(cfg->password); |
| | | free(cfg->will_topic); |
| | | free(cfg->will_payload); |
| | | free(cfg->format); |
| | | free(cfg->response_topic); |
| | | #ifdef WITH_TLS |
| | | free(cfg->cafile); |
| | | free(cfg->capath); |
| | | free(cfg->certfile); |
| | | free(cfg->keyfile); |
| | | free(cfg->ciphers); |
| | | free(cfg->tls_alpn); |
| | | free(cfg->tls_version); |
| | | free(cfg->tls_engine); |
| | | free(cfg->tls_engine_kpass_sha1); |
| | | free(cfg->keyform); |
| | | # ifdef FINAL_WITH_TLS_PSK |
| | | free(cfg->psk); |
| | | free(cfg->psk_identity); |
| | | # endif |
| | | #endif |
| | | if(cfg->topics){ |
| | | for(i=0; i<cfg->topic_count; i++){ |
| | | free(cfg->topics[i]); |
| | | } |
| | | free(cfg->topics); |
| | | } |
| | | if(cfg->filter_outs){ |
| | | for(i=0; i<cfg->filter_out_count; i++){ |
| | | free(cfg->filter_outs[i]); |
| | | } |
| | | free(cfg->filter_outs); |
| | | } |
| | | if(cfg->unsub_topics){ |
| | | for(i=0; i<cfg->unsub_topic_count; i++){ |
| | | free(cfg->unsub_topics[i]); |
| | | } |
| | | free(cfg->unsub_topics); |
| | | } |
| | | #ifdef WITH_SOCKS |
| | | free(cfg->socks5_host); |
| | | free(cfg->socks5_username); |
| | | free(cfg->socks5_password); |
| | | #endif |
| | | mosquitto_property_free_all(&cfg->connect_props); |
| | | mosquitto_property_free_all(&cfg->publish_props); |
| | | mosquitto_property_free_all(&cfg->subscribe_props); |
| | | mosquitto_property_free_all(&cfg->unsubscribe_props); |
| | | mosquitto_property_free_all(&cfg->disconnect_props); |
| | | mosquitto_property_free_all(&cfg->will_props); |
| | | } |
| | | |
| | | int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) |
| | | { |
| | | int rc; |
| | | FILE *fptr; |
| | | char line[1024]; |
| | | int count; |
| | | char *loc = NULL; |
| | | int len; |
| | | char *args[3]; |
| | | |
| | | #ifndef WIN32 |
| | | char *env; |
| | | #else |
| | | char env[1024]; |
| | | #endif |
| | | args[0] = NULL; |
| | | |
| | | init_config(cfg, pub_or_sub); |
| | | |
| | | /* Default config file */ |
| | | #ifndef WIN32 |
| | | env = getenv("XDG_CONFIG_HOME"); |
| | | if(env){ |
| | | len = strlen(env) + strlen("/mosquitto_pub") + 1; |
| | | loc = malloc(len); |
| | | if(!loc){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | snprintf(loc, len, "%s/mosquitto_pub", env); |
| | | }else if(pub_or_sub == CLIENT_SUB){ |
| | | snprintf(loc, len, "%s/mosquitto_sub", env); |
| | | }else{ |
| | | snprintf(loc, len, "%s/mosquitto_rr", env); |
| | | } |
| | | loc[len-1] = '\0'; |
| | | }else{ |
| | | env = getenv("HOME"); |
| | | if(env){ |
| | | len = strlen(env) + strlen("/.config/mosquitto_pub") + 1; |
| | | loc = malloc(len); |
| | | if(!loc){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | snprintf(loc, len, "%s/.config/mosquitto_pub", env); |
| | | }else if(pub_or_sub == CLIENT_SUB){ |
| | | snprintf(loc, len, "%s/.config/mosquitto_sub", env); |
| | | }else{ |
| | | snprintf(loc, len, "%s/.config/mosquitto_rr", env); |
| | | } |
| | | loc[len-1] = '\0'; |
| | | } |
| | | } |
| | | |
| | | #else |
| | | rc = GetEnvironmentVariable("USERPROFILE", env, 1024); |
| | | if(rc > 0 && rc < 1024){ |
| | | len = strlen(env) + strlen("\\mosquitto_pub.conf") + 1; |
| | | loc = malloc(len); |
| | | if(!loc){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | snprintf(loc, len, "%s\\mosquitto_pub.conf", env); |
| | | }else if(pub_or_sub == CLIENT_SUB){ |
| | | snprintf(loc, len, "%s\\mosquitto_sub.conf", env); |
| | | }else{ |
| | | snprintf(loc, len, "%s\\mosquitto_rr.conf", env); |
| | | } |
| | | loc[len-1] = '\0'; |
| | | } |
| | | #endif |
| | | |
| | | if(loc){ |
| | | fptr = fopen(loc, "rt"); |
| | | if(fptr){ |
| | | while(fgets(line, 1024, fptr)){ |
| | | if(line[0] == '#') continue; /* Comments */ |
| | | |
| | | while(line[strlen(line)-1] == 10 || line[strlen(line)-1] == 13){ |
| | | line[strlen(line)-1] = 0; |
| | | } |
| | | /* All offset by one "args" here, because real argc/argv has |
| | | * program name as the first entry. */ |
| | | args[1] = strtok(line, " "); |
| | | if(args[1]){ |
| | | args[2] = strtok(NULL, " "); |
| | | if(args[2]){ |
| | | count = 3; |
| | | }else{ |
| | | count = 2; |
| | | } |
| | | rc = client_config_line_proc(cfg, pub_or_sub, count, args); |
| | | if(rc){ |
| | | fclose(fptr); |
| | | free(loc); |
| | | return rc; |
| | | } |
| | | } |
| | | } |
| | | fclose(fptr); |
| | | } |
| | | free(loc); |
| | | } |
| | | |
| | | /* Deal with real argc/argv */ |
| | | rc = client_config_line_proc(cfg, pub_or_sub, argc, argv); |
| | | if(rc) return rc; |
| | | |
| | | 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; |
| | | } |
| | | #ifdef WITH_TLS |
| | | if((cfg->certfile && !cfg->keyfile) || (cfg->keyfile && !cfg->certfile)){ |
| | | fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is set.\n"); |
| | | return 1; |
| | | } |
| | | if((cfg->keyform && !cfg->keyfile)){ |
| | | fprintf(stderr, "Error: If keyform is set, keyfile must be also specified.\n"); |
| | | return 1; |
| | | } |
| | | if((cfg->tls_engine_kpass_sha1 && (!cfg->keyform || !cfg->tls_engine))){ |
| | | fprintf(stderr, "Error: when using tls-engine-kpass-sha1, both tls-engine and keyform must also be provided.\n"); |
| | | return 1; |
| | | } |
| | | #endif |
| | | #ifdef FINAL_WITH_TLS_PSK |
| | | if((cfg->cafile || cfg->capath) && cfg->psk){ |
| | | fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); |
| | | return 1; |
| | | } |
| | | if(cfg->psk && !cfg->psk_identity){ |
| | | fprintf(stderr, "Error: --psk-identity required if --psk used.\n"); |
| | | return 1; |
| | | } |
| | | #endif |
| | | |
| | | if(cfg->clean_session == false && (cfg->id_prefix || !cfg->id)){ |
| | | fprintf(stderr, "Error: You must provide a client id if you are using the -c option.\n"); |
| | | return 1; |
| | | } |
| | | |
| | | if(pub_or_sub == CLIENT_SUB){ |
| | | if(cfg->topic_count == 0){ |
| | | fprintf(stderr, "Error: You must specify a topic to subscribe to.\n"); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | if(!cfg->host){ |
| | | cfg->host = strdup("localhost"); |
| | | if(!cfg->host){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | rc = mosquitto_property_check_all(CMD_CONNECT, cfg->connect_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in CONNECT properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_PUBLISH, cfg->publish_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in PUBLISH properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_SUBSCRIBE, cfg->subscribe_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in SUBSCRIBE properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, cfg->unsubscribe_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in UNSUBSCRIBE properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_DISCONNECT, cfg->disconnect_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in DISCONNECT properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_WILL, cfg->will_props); |
| | | if(rc){ |
| | | err_printf(cfg, "Error in Will properties: %s\n", mosquitto_strerror(rc)); |
| | | return 1; |
| | | } |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | int cfg_add_topic(struct mosq_config *cfg, int type, char *topic, const char *arg) |
| | | { |
| | | if(mosquitto_validate_utf8(topic, strlen(topic))){ |
| | | fprintf(stderr, "Error: Malformed UTF-8 in %s argument.\n\n", arg); |
| | | return 1; |
| | | } |
| | | if(type == CLIENT_PUB || type == CLIENT_RR){ |
| | | if(mosquitto_pub_topic_check(topic) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid publish topic '%s', does it contain '+' or '#'?\n", topic); |
| | | return 1; |
| | | } |
| | | cfg->topic = strdup(topic); |
| | | }else if(type == CLIENT_RESPONSE_TOPIC){ |
| | | if(mosquitto_pub_topic_check(topic) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid response topic '%s', does it contain '+' or '#'?\n", topic); |
| | | return 1; |
| | | } |
| | | cfg->response_topic = strdup(topic); |
| | | }else{ |
| | | if(mosquitto_sub_topic_check(topic) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid subscription topic '%s', are all '+' and '#' wildcards correct?\n", topic); |
| | | return 1; |
| | | } |
| | | cfg->topic_count++; |
| | | cfg->topics = realloc(cfg->topics, cfg->topic_count*sizeof(char *)); |
| | | if(!cfg->topics){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | cfg->topics[cfg->topic_count-1] = strdup(topic); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | /* Process a tokenised single line from a file or set of real argc/argv */ |
| | | int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) |
| | | { |
| | | int i; |
| | | float f; |
| | | |
| | | for(i=1; i<argc; i++){ |
| | | 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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #ifdef WITH_TLS |
| | | }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 = strdup(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 = strdup(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 = strdup(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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #endif |
| | | }else if(!strcmp(argv[i], "-C")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | }else{ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -C argument given but no count specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->msg_count = atoi(argv[i+1]); |
| | | if(cfg->msg_count < 1){ |
| | | fprintf(stderr, "Error: Invalid message count \"%d\".\n\n", cfg->msg_count); |
| | | return 1; |
| | | } |
| | | } |
| | | i++; |
| | | } |
| | | }else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--disable-clean-session")){ |
| | | cfg->clean_session = false; |
| | | }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ |
| | | cfg->debug = true; |
| | | }else if(!strcmp(argv[i], "-D") || !strcmp(argv[i], "--property")){ |
| | | i++; |
| | | if(cfg_parse_property(cfg, argc, argv, &i)){ |
| | | return 1; |
| | | } |
| | | cfg->protocol_version = MQTT_PROTOCOL_V5; |
| | | }else if(!strcmp(argv[i], "-e")){ |
| | | if(pub_or_sub != CLIENT_RR){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -e argument given but no response topic specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | if(cfg_add_topic(cfg, CLIENT_RESPONSE_TOPIC, argv[i+1], "-e")){ |
| | | return 1; |
| | | } |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "-E")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->exit_after_sub = true; |
| | | }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){ |
| | | if(pub_or_sub == CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | 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 = strdup(argv[i+1]); |
| | | if(!cfg->file_input){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "-F")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -F argument given but no format specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->format = strdup(argv[i+1]); |
| | | if(!cfg->format){ |
| | | fprintf(stderr, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | if(check_format(cfg->format)){ |
| | | return 1; |
| | | } |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--help")){ |
| | | return 2; |
| | | }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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #ifdef WITH_TLS |
| | | }else if(!strcmp(argv[i], "--insecure")){ |
| | | cfg->insecure = true; |
| | | #endif |
| | | }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 = strdup(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 = strdup(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++; |
| | | #ifdef WITH_TLS |
| | | }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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--keyform")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --keyform argument given but no keyform specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->keyform = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #endif |
| | | }else if(!strcmp(argv[i], "-L") || !strcmp(argv[i], "--url")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -L argument given but no URL specified.\n\n"); |
| | | return 1; |
| | | } else { |
| | | char *url = argv[i+1]; |
| | | char *topic; |
| | | char *tmp; |
| | | |
| | | if(!strncasecmp(url, "mqtt://", 7)) { |
| | | url += 7; |
| | | cfg->port = 1883; |
| | | } else if(!strncasecmp(url, "mqtts://", 8)) { |
| | | url += 8; |
| | | cfg->port = 8883; |
| | | } else { |
| | | fprintf(stderr, "Error: unsupported URL scheme.\n\n"); |
| | | return 1; |
| | | } |
| | | topic = strchr(url, '/'); |
| | | if(!topic){ |
| | | fprintf(stderr, "Error: Invalid URL for -L argument specified - topic missing.\n"); |
| | | return 1; |
| | | } |
| | | *topic++ = 0; |
| | | |
| | | if(cfg_add_topic(cfg, pub_or_sub, topic, "-L topic")) |
| | | return 1; |
| | | |
| | | tmp = strchr(url, '@'); |
| | | if(tmp) { |
| | | *tmp++ = 0; |
| | | char *colon = strchr(url, ':'); |
| | | if(colon) { |
| | | *colon = 0; |
| | | cfg->password = strdup(colon + 1); |
| | | } |
| | | cfg->username = strdup(url); |
| | | url = tmp; |
| | | } |
| | | cfg->host = url; |
| | | |
| | | tmp = strchr(url, ':'); |
| | | if(tmp) { |
| | | *tmp++ = 0; |
| | | cfg->port = atoi(tmp); |
| | | } |
| | | /* Now we've removed the port, time to get the host on the heap */ |
| | | cfg->host = strdup(cfg->host); |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){ |
| | | if(pub_or_sub != CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | 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(pub_or_sub == CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | 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 = strdup(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(pub_or_sub == CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | 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], "-N")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->eol = false; |
| | | }else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -p argument given but no port specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->port = 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], "-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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #ifdef WITH_SOCKS |
| | | }else if(!strcmp(argv[i], "--proxy")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --proxy argument given but no proxy url specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | if(mosquitto__parse_socks_url(cfg, argv[i+1])){ |
| | | return 1; |
| | | } |
| | | i++; |
| | | } |
| | | #endif |
| | | #ifdef FINAL_WITH_TLS_PSK |
| | | }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 = strdup(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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #endif |
| | | }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")){ |
| | | if(pub_or_sub != CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->retain = 1; |
| | | }else if(!strcmp(argv[i], "-R")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->no_retain = true; |
| | | cfg->sub_opts |= MQTT_SUB_OPT_SEND_RETAIN_NEVER; |
| | | }else if(!strcmp(argv[i], "--remove-retained")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->remove_retained = true; |
| | | }else if(!strcmp(argv[i], "--repeat")){ |
| | | if(pub_or_sub != CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --repeat argument given but no count specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->repeat_count = atoi(argv[i+1]); |
| | | if(cfg->repeat_count < 1){ |
| | | fprintf(stderr, "Error: --repeat argument must be >0.\n\n"); |
| | | return 1; |
| | | } |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--repeat-delay")){ |
| | | if(pub_or_sub != CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --repeat-delay argument given but no time specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | f = atof(argv[i+1]); |
| | | if(f < 0.0f){ |
| | | fprintf(stderr, "Error: --repeat-delay argument must be >=0.0.\n\n"); |
| | | return 1; |
| | | } |
| | | f *= 1.0e6; |
| | | cfg->repeat_delay.tv_sec = (int)f/1e6; |
| | | cfg->repeat_delay.tv_usec = (int)f%1000000; |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--retain-as-published")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->sub_opts |= MQTT_SUB_OPT_RETAIN_AS_PUBLISHED; |
| | | }else if(!strcmp(argv[i], "--retained-only")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->retained_only = true; |
| | | }else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){ |
| | | if(pub_or_sub == CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | 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; |
| | | } |
| | | #ifdef WITH_SRV |
| | | }else if(!strcmp(argv[i], "-S")){ |
| | | cfg->use_srv = true; |
| | | #endif |
| | | }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(cfg_add_topic(cfg, pub_or_sub, argv[i + 1], "-t")) |
| | | return 1; |
| | | i++; |
| | | } |
| | | }else if(!strcmp(argv[i], "-T") || !strcmp(argv[i], "--filter-out")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -T argument given but no topic filter specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | if(mosquitto_validate_utf8(argv[i+1], strlen(argv[i+1]))){ |
| | | fprintf(stderr, "Error: Malformed UTF-8 in -T argument.\n\n"); |
| | | return 1; |
| | | } |
| | | if(mosquitto_sub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid filter topic '%s', are all '+' and '#' wildcards correct?\n", argv[i+1]); |
| | | return 1; |
| | | } |
| | | cfg->filter_out_count++; |
| | | cfg->filter_outs = realloc(cfg->filter_outs, cfg->filter_out_count*sizeof(char *)); |
| | | if(!cfg->filter_outs){ |
| | | fprintf(stderr, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | cfg->filter_outs[cfg->filter_out_count-1] = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #ifdef WITH_TLS |
| | | }else if(!strcmp(argv[i], "--tls-alpn")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --tls-alpn argument given but no protocol specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->tls_alpn = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--tls-engine")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --tls-engine argument given but no engine_id specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->tls_engine = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "--tls-engine-kpass-sha1")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --tls-engine-kpass-sha1 argument given but no kpass sha1 specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->tls_engine_kpass_sha1 = strdup(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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | #endif |
| | | }else if(!strcmp(argv[i], "-U") || !strcmp(argv[i], "--unsubscribe")){ |
| | | if(pub_or_sub != CLIENT_SUB){ |
| | | goto unknown_option; |
| | | } |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -U argument given but no unsubscribe topic specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | if(mosquitto_validate_utf8(argv[i+1], strlen(argv[i+1]))){ |
| | | fprintf(stderr, "Error: Malformed UTF-8 in -U argument.\n\n"); |
| | | return 1; |
| | | } |
| | | if(mosquitto_sub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid unsubscribe topic '%s', are all '+' and '#' wildcards correct?\n", argv[i+1]); |
| | | return 1; |
| | | } |
| | | cfg->unsub_topic_count++; |
| | | cfg->unsub_topics = realloc(cfg->unsub_topics, cfg->unsub_topic_count*sizeof(char *)); |
| | | if(!cfg->unsub_topics){ |
| | | fprintf(stderr, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | cfg->unsub_topics[cfg->unsub_topic_count-1] = strdup(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 = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | }else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--protocol-version")){ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | if(!strcmp(argv[i+1], "mqttv31") || !strcmp(argv[i+1], "31")){ |
| | | cfg->protocol_version = MQTT_PROTOCOL_V31; |
| | | }else if(!strcmp(argv[i+1], "mqttv311") || !strcmp(argv[i+1], "311")){ |
| | | cfg->protocol_version = MQTT_PROTOCOL_V311; |
| | | }else if(!strcmp(argv[i+1], "mqttv5") || !strcmp(argv[i+1], "5")){ |
| | | cfg->protocol_version = MQTT_PROTOCOL_V5; |
| | | }else{ |
| | | fprintf(stderr, "Error: Invalid protocol version argument given.\n\n"); |
| | | return 1; |
| | | } |
| | | i++; |
| | | } |
| | | }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | } |
| | | cfg->verbose = 1; |
| | | }else if(!strcmp(argv[i], "-W")){ |
| | | if(pub_or_sub == CLIENT_PUB){ |
| | | goto unknown_option; |
| | | }else{ |
| | | if(i==argc-1){ |
| | | fprintf(stderr, "Error: -W argument given but no timeout specified.\n\n"); |
| | | return 1; |
| | | }else{ |
| | | cfg->timeout = atoi(argv[i+1]); |
| | | if(cfg->timeout < 1){ |
| | | fprintf(stderr, "Error: Invalid timeout \"%d\".\n\n", cfg->msg_count); |
| | | return 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 = strdup(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{ |
| | | if(mosquitto_validate_utf8(argv[i+1], strlen(argv[i+1]))){ |
| | | fprintf(stderr, "Error: Malformed UTF-8 in --will-topic argument.\n\n"); |
| | | return 1; |
| | | } |
| | | if(mosquitto_pub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ |
| | | fprintf(stderr, "Error: Invalid will topic '%s', does it contain '+' or '#'?\n", argv[i+1]); |
| | | return 1; |
| | | } |
| | | cfg->will_topic = strdup(argv[i+1]); |
| | | } |
| | | i++; |
| | | }else{ |
| | | goto unknown_option; |
| | | } |
| | | } |
| | | |
| | | 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 defined(WITH_TLS) || defined(WITH_SOCKS) |
| | | int rc; |
| | | #endif |
| | | |
| | | mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, cfg->protocol_version); |
| | | |
| | | if(cfg->will_topic && mosquitto_will_set_v5(mosq, cfg->will_topic, |
| | | cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, |
| | | cfg->will_retain, cfg->will_props)){ |
| | | |
| | | err_printf(cfg, "Error: Problem setting will.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | cfg->will_props = NULL; |
| | | |
| | | if((cfg->username || cfg->password) && mosquitto_username_pw_set(mosq, cfg->username, cfg->password)){ |
| | | err_printf(cfg, "Error: Problem setting username and/or password.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | #ifdef WITH_TLS |
| | | if(cfg->cafile || cfg->capath){ |
| | | rc = mosquitto_tls_set(mosq, cfg->cafile, cfg->capath, cfg->certfile, cfg->keyfile, NULL); |
| | | if(rc){ |
| | | if(rc == MOSQ_ERR_INVAL){ |
| | | err_printf(cfg, "Error: Problem setting TLS options: File not found.\n"); |
| | | }else{ |
| | | err_printf(cfg, "Error: Problem setting TLS options: %s.\n", mosquitto_strerror(rc)); |
| | | } |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | } |
| | | if(cfg->insecure && mosquitto_tls_insecure_set(mosq, true)){ |
| | | err_printf(cfg, "Error: Problem setting TLS insecure option.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | if(cfg->tls_engine && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ENGINE, cfg->tls_engine)){ |
| | | err_printf(cfg, "Error: Problem setting TLS engine, is %s a valid engine?\n", cfg->tls_engine); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | if(cfg->keyform && mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, cfg->keyform)){ |
| | | err_printf(cfg, "Error: Problem setting key form, it must be one of 'pem' or 'engine'.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | if(cfg->tls_engine_kpass_sha1 && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ENGINE_KPASS_SHA1, cfg->tls_engine_kpass_sha1)){ |
| | | err_printf(cfg, "Error: Problem setting TLS engine key pass sha, is it a 40 character hex string?\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | if(cfg->tls_alpn && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ALPN, cfg->tls_alpn)){ |
| | | err_printf(cfg, "Error: Problem setting TLS ALPN protocol.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | # ifdef FINAL_WITH_TLS_PSK |
| | | if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ |
| | | err_printf(cfg, "Error: Problem setting TLS-PSK options.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | # endif |
| | | if((cfg->tls_version || cfg->ciphers) && mosquitto_tls_opts_set(mosq, 1, cfg->tls_version, cfg->ciphers)){ |
| | | err_printf(cfg, "Error: Problem setting TLS options, check the options are valid.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | #endif |
| | | mosquitto_max_inflight_messages_set(mosq, cfg->max_inflight); |
| | | #ifdef WITH_SOCKS |
| | | if(cfg->socks5_host){ |
| | | rc = mosquitto_socks5_set(mosq, cfg->socks5_host, cfg->socks5_port, cfg->socks5_username, cfg->socks5_password); |
| | | if(rc){ |
| | | mosquitto_lib_cleanup(); |
| | | return rc; |
| | | } |
| | | } |
| | | #endif |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | int client_id_generate(struct mosq_config *cfg) |
| | | { |
| | | if(cfg->id_prefix){ |
| | | cfg->id = malloc(strlen(cfg->id_prefix)+10); |
| | | if(!cfg->id){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | mosquitto_lib_cleanup(); |
| | | return 1; |
| | | } |
| | | snprintf(cfg->id, strlen(cfg->id_prefix)+10, "%s%d", cfg->id_prefix, getpid()); |
| | | } |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) |
| | | { |
| | | #ifndef WIN32 |
| | | char *err; |
| | | #else |
| | | char err[1024]; |
| | | #endif |
| | | int rc; |
| | | int port; |
| | | |
| | | if(cfg->port < 0){ |
| | | #ifdef WITH_TLS |
| | | if(cfg->cafile || cfg->capath |
| | | # ifdef FINAL_WITH_TLS_PSK |
| | | || cfg->psk |
| | | # endif |
| | | ){ |
| | | port = 8883; |
| | | }else |
| | | #endif |
| | | { |
| | | port = 1883; |
| | | } |
| | | }else{ |
| | | port = cfg->port; |
| | | } |
| | | |
| | | #ifdef WITH_SRV |
| | | if(cfg->use_srv){ |
| | | rc = mosquitto_connect_srv(mosq, cfg->host, cfg->keepalive, cfg->bind_address); |
| | | }else{ |
| | | rc = mosquitto_connect_bind_v5(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); |
| | | } |
| | | #else |
| | | rc = mosquitto_connect_bind_v5(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); |
| | | #endif |
| | | if(rc>0){ |
| | | if(rc == MOSQ_ERR_ERRNO){ |
| | | #ifndef WIN32 |
| | | err = strerror(errno); |
| | | #else |
| | | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL); |
| | | #endif |
| | | err_printf(cfg, "Error: %s\n", err); |
| | | }else{ |
| | | err_printf(cfg, "Unable to connect (%s).\n", mosquitto_strerror(rc)); |
| | | } |
| | | mosquitto_lib_cleanup(); |
| | | return rc; |
| | | } |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | #ifdef WITH_SOCKS |
| | | /* Convert %25 -> %, %3a, %3A -> :, %40 -> @ */ |
| | | static int mosquitto__urldecode(char *str) |
| | | { |
| | | int i, j; |
| | | int len; |
| | | if(!str) return 0; |
| | | |
| | | if(!strchr(str, '%')) return 0; |
| | | |
| | | len = strlen(str); |
| | | for(i=0; i<len; i++){ |
| | | if(str[i] == '%'){ |
| | | if(i+2 >= len){ |
| | | return 1; |
| | | } |
| | | if(str[i+1] == '2' && str[i+2] == '5'){ |
| | | str[i] = '%'; |
| | | len -= 2; |
| | | for(j=i+1; j<len; j++){ |
| | | str[j] = str[j+2]; |
| | | } |
| | | str[j] = '\0'; |
| | | }else if(str[i+1] == '3' && (str[i+2] == 'A' || str[i+2] == 'a')){ |
| | | str[i] = ':'; |
| | | len -= 2; |
| | | for(j=i+1; j<len; j++){ |
| | | str[j] = str[j+2]; |
| | | } |
| | | str[j] = '\0'; |
| | | }else if(str[i+1] == '4' && str[i+2] == '0'){ |
| | | str[i] = ':'; |
| | | len -= 2; |
| | | for(j=i+1; j<len; j++){ |
| | | str[j] = str[j+2]; |
| | | } |
| | | str[j] = '\0'; |
| | | }else{ |
| | | return 1; |
| | | } |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url) |
| | | { |
| | | char *str; |
| | | size_t i; |
| | | char *username = NULL, *password = NULL, *host = NULL, *port = NULL; |
| | | char *username_or_host = NULL; |
| | | size_t start; |
| | | size_t len; |
| | | bool have_auth = false; |
| | | int port_int; |
| | | |
| | | if(!strncmp(url, "socks5h://", strlen("socks5h://"))){ |
| | | str = url + strlen("socks5h://"); |
| | | }else{ |
| | | err_printf(cfg, "Error: Unsupported proxy protocol: %s\n", url); |
| | | return 1; |
| | | } |
| | | |
| | | // socks5h://username:password@host:1883 |
| | | // socks5h://username:password@host |
| | | // socks5h://username@host:1883 |
| | | // socks5h://username@host |
| | | // socks5h://host:1883 |
| | | // socks5h://host |
| | | |
| | | start = 0; |
| | | for(i=0; i<strlen(str); i++){ |
| | | if(str[i] == ':'){ |
| | | if(i == start){ |
| | | goto cleanup; |
| | | } |
| | | if(have_auth){ |
| | | /* Have already seen a @ , so this must be of form |
| | | * socks5h://username[:password]@host:port */ |
| | | if(host){ |
| | | /* Already seen a host, must be malformed. */ |
| | | goto cleanup; |
| | | } |
| | | len = i-start; |
| | | host = malloc(len + 1); |
| | | if(!host){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(host, &(str[start]), len); |
| | | host[len] = '\0'; |
| | | start = i+1; |
| | | }else if(!username_or_host){ |
| | | /* Haven't seen a @ before, so must be of form |
| | | * socks5h://host:port or |
| | | * socks5h://username:password@host[:port] */ |
| | | len = i-start; |
| | | username_or_host = malloc(len + 1); |
| | | if(!username_or_host){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(username_or_host, &(str[start]), len); |
| | | username_or_host[len] = '\0'; |
| | | start = i+1; |
| | | } |
| | | }else if(str[i] == '@'){ |
| | | if(i == start){ |
| | | goto cleanup; |
| | | } |
| | | have_auth = true; |
| | | if(username_or_host){ |
| | | /* Must be of form socks5h://username:password@... */ |
| | | username = username_or_host; |
| | | username_or_host = NULL; |
| | | |
| | | len = i-start; |
| | | password = malloc(len + 1); |
| | | if(!password){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(password, &(str[start]), len); |
| | | password[len] = '\0'; |
| | | start = i+1; |
| | | }else{ |
| | | /* Haven't seen a : yet, so must be of form |
| | | * socks5h://username@... */ |
| | | if(username){ |
| | | /* Already got a username, must be malformed. */ |
| | | goto cleanup; |
| | | } |
| | | len = i-start; |
| | | username = malloc(len + 1); |
| | | if(!username){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(username, &(str[start]), len); |
| | | username[len] = '\0'; |
| | | start = i+1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* Deal with remainder */ |
| | | if(i > start){ |
| | | len = i-start; |
| | | if(host){ |
| | | /* Have already seen a @ , so this must be of form |
| | | * socks5h://username[:password]@host:port */ |
| | | port = malloc(len + 1); |
| | | if(!port){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(port, &(str[start]), len); |
| | | port[len] = '\0'; |
| | | }else if(username_or_host){ |
| | | /* Haven't seen a @ before, so must be of form |
| | | * socks5h://host:port */ |
| | | host = username_or_host; |
| | | username_or_host = NULL; |
| | | port = malloc(len + 1); |
| | | if(!port){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(port, &(str[start]), len); |
| | | port[len] = '\0'; |
| | | }else{ |
| | | host = malloc(len + 1); |
| | | if(!host){ |
| | | err_printf(cfg, "Error: Out of memory.\n"); |
| | | goto cleanup; |
| | | } |
| | | memcpy(host, &(str[start]), len); |
| | | host[len] = '\0'; |
| | | } |
| | | } |
| | | |
| | | if(!host){ |
| | | err_printf(cfg, "Error: Invalid proxy.\n"); |
| | | goto cleanup; |
| | | } |
| | | |
| | | if(mosquitto__urldecode(username)){ |
| | | goto cleanup; |
| | | } |
| | | if(mosquitto__urldecode(password)){ |
| | | goto cleanup; |
| | | } |
| | | if(port){ |
| | | port_int = atoi(port); |
| | | if(port_int < 1 || port_int > 65535){ |
| | | err_printf(cfg, "Error: Invalid proxy port %d\n", port_int); |
| | | goto cleanup; |
| | | } |
| | | free(port); |
| | | }else{ |
| | | port_int = 1080; |
| | | } |
| | | |
| | | cfg->socks5_username = username; |
| | | cfg->socks5_password = password; |
| | | cfg->socks5_host = host; |
| | | cfg->socks5_port = port_int; |
| | | |
| | | return 0; |
| | | cleanup: |
| | | if(username_or_host) free(username_or_host); |
| | | if(username) free(username); |
| | | if(password) free(password); |
| | | if(host) free(host); |
| | | if(port) free(port); |
| | | return 1; |
| | | } |
| | | #endif |
| | | |
| | | void err_printf(const struct mosq_config *cfg, const char *fmt, ...) |
| | | { |
| | | va_list va; |
| | | |
| | | if(cfg->quiet) return; |
| | | |
| | | va_start(va, fmt); |
| | | vfprintf(stderr, fmt, va); |
| | | va_end(va); |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2014-2019 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 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 <stdio.h> |
| | | |
| | | #ifdef WIN32 |
| | | # include <winsock2.h> |
| | | #else |
| | | # include <sys/time.h> |
| | | #endif |
| | | |
| | | /* 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 |
| | | #define CLIENT_RR 3 |
| | | #define CLIENT_RESPONSE_TOPIC 4 |
| | | |
| | | struct mosq_config { |
| | | char *id; |
| | | char *id_prefix; |
| | | int protocol_version; |
| | | int keepalive; |
| | | char *host; |
| | | int port; |
| | | int qos; |
| | | bool retain; |
| | | int pub_mode; /* pub, rr */ |
| | | char *file_input; /* pub, rr */ |
| | | char *message; /* pub, rr */ |
| | | long msglen; /* pub, rr */ |
| | | char *topic; /* pub, rr */ |
| | | char *bind_address; |
| | | int repeat_count; /* pub */ |
| | | struct timeval repeat_delay; /* pub */ |
| | | #ifdef WITH_SRV |
| | | bool use_srv; |
| | | #endif |
| | | 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_alpn; |
| | | char *tls_version; |
| | | char *tls_engine; |
| | | char *tls_engine_kpass_sha1; |
| | | char *keyform; |
| | | # ifdef FINAL_WITH_TLS_PSK |
| | | char *psk; |
| | | char *psk_identity; |
| | | # endif |
| | | #endif |
| | | bool clean_session; |
| | | char **topics; /* sub */ |
| | | int topic_count; /* sub */ |
| | | bool exit_after_sub; /* sub */ |
| | | bool no_retain; /* sub */ |
| | | bool retained_only; /* sub */ |
| | | bool remove_retained; /* sub */ |
| | | char **filter_outs; /* sub */ |
| | | int filter_out_count; /* sub */ |
| | | char **unsub_topics; /* sub */ |
| | | int unsub_topic_count; /* sub */ |
| | | bool verbose; /* sub */ |
| | | bool eol; /* sub */ |
| | | int msg_count; /* sub */ |
| | | char *format; /* sub */ |
| | | int timeout; /* sub */ |
| | | int sub_opts; /* sub */ |
| | | #ifdef WITH_SOCKS |
| | | char *socks5_host; |
| | | int socks5_port; |
| | | char *socks5_username; |
| | | char *socks5_password; |
| | | #endif |
| | | mosquitto_property *connect_props; |
| | | mosquitto_property *publish_props; |
| | | mosquitto_property *subscribe_props; |
| | | mosquitto_property *unsubscribe_props; |
| | | mosquitto_property *disconnect_props; |
| | | mosquitto_property *will_props; |
| | | bool have_topic_alias; /* pub */ |
| | | char *response_topic; /* rr */ |
| | | }; |
| | | |
| | | int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); |
| | | void client_config_cleanup(struct mosq_config *cfg); |
| | | int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg); |
| | | int client_id_generate(struct mosq_config *cfg); |
| | | int client_connect(struct mosquitto *mosq, struct mosq_config *cfg); |
| | | |
| | | int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx); |
| | | |
| | | void err_printf(const struct mosq_config *cfg, const char *fmt, ...); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <fcntl.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #ifndef WIN32 |
| | | #include <sys/time.h> |
| | | #include <time.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #include <mqtt_protocol.h> |
| | | #include <mosquitto.h> |
| | | #include "client_shared.h" |
| | | #include "pub_shared.h" |
| | | |
| | | /* Global variables for use in callbacks. See sub_client.c for an example of |
| | | * using a struct to hold variables for use in callbacks. */ |
| | | static bool first_publish = true; |
| | | static int last_mid = -1; |
| | | static int last_mid_sent = -1; |
| | | static char *line_buf = NULL; |
| | | static int line_buf_len = 1024; |
| | | static bool disconnect_sent = false; |
| | | static int publish_count = 0; |
| | | static bool ready_for_repeat = false; |
| | | |
| | | #ifdef WIN32 |
| | | static uint64_t next_publish_tv; |
| | | |
| | | static void set_repeat_time(void) |
| | | { |
| | | uint64_t ticks = GetTickCount64(); |
| | | next_publish_tv = ticks + cfg.repeat_delay.tv_sec*1000 + cfg.repeat_delay.tv_usec/1000; |
| | | } |
| | | |
| | | static int check_repeat_time(void) |
| | | { |
| | | uint64_t ticks = GetTickCount64(); |
| | | |
| | | if(ticks > next_publish_tv){ |
| | | return 1; |
| | | }else{ |
| | | return 0; |
| | | } |
| | | } |
| | | #else |
| | | |
| | | static struct timeval next_publish_tv; |
| | | |
| | | static void set_repeat_time(void) |
| | | { |
| | | gettimeofday(&next_publish_tv, NULL); |
| | | next_publish_tv.tv_sec += cfg.repeat_delay.tv_sec; |
| | | next_publish_tv.tv_usec += cfg.repeat_delay.tv_usec; |
| | | |
| | | next_publish_tv.tv_sec += next_publish_tv.tv_usec/1e6; |
| | | next_publish_tv.tv_usec = next_publish_tv.tv_usec%1000000; |
| | | } |
| | | |
| | | static int check_repeat_time(void) |
| | | { |
| | | struct timeval tv; |
| | | |
| | | gettimeofday(&tv, NULL); |
| | | |
| | | if(tv.tv_sec > next_publish_tv.tv_sec){ |
| | | return 1; |
| | | }else if(tv.tv_sec == next_publish_tv.tv_sec |
| | | && tv.tv_usec > next_publish_tv.tv_usec){ |
| | | |
| | | return 1; |
| | | } |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties) |
| | | { |
| | | UNUSED(mosq); |
| | | UNUSED(obj); |
| | | UNUSED(rc); |
| | | UNUSED(properties); |
| | | |
| | | status = STATUS_DISCONNECTED; |
| | | } |
| | | |
| | | int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) |
| | | { |
| | | ready_for_repeat = false; |
| | | if(cfg.protocol_version == MQTT_PROTOCOL_V5 && cfg.have_topic_alias && first_publish == false){ |
| | | return mosquitto_publish_v5(mosq, mid, NULL, payloadlen, payload, qos, retain, cfg.publish_props); |
| | | }else{ |
| | | first_publish = false; |
| | | return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, cfg.publish_props); |
| | | } |
| | | } |
| | | |
| | | |
| | | void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) |
| | | { |
| | | int rc = MOSQ_ERR_SUCCESS; |
| | | |
| | | UNUSED(obj); |
| | | UNUSED(flags); |
| | | UNUSED(properties); |
| | | |
| | | if(!result){ |
| | | switch(cfg.pub_mode){ |
| | | case MSGMODE_CMD: |
| | | case MSGMODE_FILE: |
| | | case MSGMODE_STDIN_FILE: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, cfg.msglen, cfg.message, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_NULL: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_STDIN_LINE: |
| | | status = STATUS_CONNACK_RECVD; |
| | | break; |
| | | } |
| | | if(rc){ |
| | | switch(rc){ |
| | | case MOSQ_ERR_INVAL: |
| | | err_printf(&cfg, "Error: Invalid input. Does your topic contain '+' or '#'?\n"); |
| | | break; |
| | | case MOSQ_ERR_NOMEM: |
| | | err_printf(&cfg, "Error: Out of memory when trying to publish message.\n"); |
| | | break; |
| | | case MOSQ_ERR_NO_CONN: |
| | | err_printf(&cfg, "Error: Client not connected when trying to publish.\n"); |
| | | break; |
| | | case MOSQ_ERR_PROTOCOL: |
| | | err_printf(&cfg, "Error: Protocol error when communicating with broker.\n"); |
| | | break; |
| | | case MOSQ_ERR_PAYLOAD_SIZE: |
| | | err_printf(&cfg, "Error: Message payload is too large.\n"); |
| | | break; |
| | | case MOSQ_ERR_QOS_NOT_SUPPORTED: |
| | | err_printf(&cfg, "Error: Message QoS not supported on broker, try a lower QoS.\n"); |
| | | break; |
| | | } |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | } |
| | | }else{ |
| | | if(result){ |
| | | if(cfg.protocol_version == MQTT_PROTOCOL_V5){ |
| | | err_printf(&cfg, "%s\n", mosquitto_reason_string(result)); |
| | | }else{ |
| | | err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) |
| | | { |
| | | UNUSED(obj); |
| | | UNUSED(properties); |
| | | |
| | | last_mid_sent = mid; |
| | | if(reason_code > 127){ |
| | | err_printf(&cfg, "Warning: Publish %d failed: %s.\n", mid, mosquitto_reason_string(reason_code)); |
| | | } |
| | | publish_count++; |
| | | |
| | | if(cfg.pub_mode == MSGMODE_STDIN_LINE){ |
| | | if(mid == last_mid){ |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | disconnect_sent = true; |
| | | } |
| | | }else if(publish_count < cfg.repeat_count){ |
| | | ready_for_repeat = true; |
| | | set_repeat_time(); |
| | | }else if(disconnect_sent == false){ |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | disconnect_sent = true; |
| | | } |
| | | } |
| | | |
| | | |
| | | int pub_shared_init(void) |
| | | { |
| | | line_buf = malloc(line_buf_len); |
| | | if(!line_buf){ |
| | | err_printf(&cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int pub_shared_loop(struct mosquitto *mosq) |
| | | { |
| | | int read_len; |
| | | int pos; |
| | | int rc, rc2; |
| | | char *buf2; |
| | | int buf_len_actual; |
| | | int mode; |
| | | int loop_delay = 1000; |
| | | bool stdin_finished = false; |
| | | |
| | | if(cfg.repeat_count > 1 && (cfg.repeat_delay.tv_sec == 0 || cfg.repeat_delay.tv_usec != 0)){ |
| | | loop_delay = cfg.repeat_delay.tv_usec / 2000; |
| | | } |
| | | |
| | | mode = cfg.pub_mode; |
| | | |
| | | if(mode == MSGMODE_STDIN_LINE){ |
| | | mosquitto_loop_start(mosq); |
| | | stdin_finished = false; |
| | | } |
| | | |
| | | do{ |
| | | if(mode == MSGMODE_STDIN_LINE){ |
| | | if(status == STATUS_CONNACK_RECVD){ |
| | | pos = 0; |
| | | read_len = line_buf_len; |
| | | while(status == STATUS_CONNACK_RECVD && fgets(&line_buf[pos], read_len, stdin)){ |
| | | buf_len_actual = strlen(line_buf); |
| | | if(line_buf[buf_len_actual-1] == '\n'){ |
| | | line_buf[buf_len_actual-1] = '\0'; |
| | | rc2 = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, line_buf, cfg.qos, cfg.retain); |
| | | if(rc2){ |
| | | err_printf(&cfg, "Error: Publish returned %d, disconnecting.\n", rc2); |
| | | mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); |
| | | } |
| | | break; |
| | | }else{ |
| | | line_buf_len += 1024; |
| | | pos += 1023; |
| | | read_len = 1024; |
| | | buf2 = realloc(line_buf, line_buf_len); |
| | | if(!buf2){ |
| | | err_printf(&cfg, "Error: Out of memory.\n"); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | line_buf = buf2; |
| | | } |
| | | } |
| | | if(feof(stdin)){ |
| | | if(mid_sent == -1){ |
| | | /* Empty file */ |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | disconnect_sent = true; |
| | | status = STATUS_DISCONNECTING; |
| | | }else{ |
| | | last_mid = mid_sent; |
| | | status = STATUS_WAITING; |
| | | } |
| | | stdin_finished = true; |
| | | }else if(status == STATUS_DISCONNECTED){ |
| | | /* Not end of stdin, so we've lost our connection and must |
| | | * reconnect */ |
| | | } |
| | | }else if(status == STATUS_WAITING){ |
| | | if(last_mid_sent == last_mid && disconnect_sent == false){ |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | disconnect_sent = true; |
| | | } |
| | | #ifdef WIN32 |
| | | Sleep(100); |
| | | #else |
| | | struct timespec ts; |
| | | ts.tv_sec = 0; |
| | | ts.tv_nsec = 100000000; |
| | | nanosleep(&ts, NULL); |
| | | #endif |
| | | } |
| | | rc = MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | rc = mosquitto_loop(mosq, loop_delay, 1); |
| | | if(ready_for_repeat && check_repeat_time()){ |
| | | rc = 0; |
| | | switch(cfg.pub_mode){ |
| | | case MSGMODE_CMD: |
| | | case MSGMODE_FILE: |
| | | case MSGMODE_STDIN_FILE: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, cfg.msglen, cfg.message, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_NULL: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_STDIN_LINE: |
| | | break; |
| | | } |
| | | if(rc){ |
| | | err_printf(&cfg, "Error sending repeat publish: %s", mosquitto_strerror(rc)); |
| | | } |
| | | } |
| | | } |
| | | }while(rc == MOSQ_ERR_SUCCESS && stdin_finished == false); |
| | | |
| | | if(mode == MSGMODE_STDIN_LINE){ |
| | | mosquitto_loop_stop(mosq, false); |
| | | } |
| | | if(status == STATUS_DISCONNECTED){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return rc; |
| | | } |
| | | } |
| | | |
| | | |
| | | void pub_shared_cleanup(void) |
| | | { |
| | | free(line_buf); |
| | | } |
| | | |
| | | |
| | | void print_usage(void) |
| | | { |
| | | int major, minor, revision; |
| | | |
| | | mosquitto_lib_version(&major, &minor, &revision); |
| | | printf("mosquitto_pub is a simple mqtt client that will publish a message on a single topic and exit.\n"); |
| | | printf("mosquitto_pub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); |
| | | printf("Usage: mosquitto_pub {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL}\n"); |
| | | printf(" {-f file | -l | -n | -m message}\n"); |
| | | printf(" [-c] [-k keepalive] [-q qos] [-r] [--repeat N] [--repeat-delay time]\n"); |
| | | #ifdef WITH_SRV |
| | | printf(" [-A bind_address] [-S]\n"); |
| | | #else |
| | | printf(" [-A bind_address]\n"); |
| | | #endif |
| | | printf(" [-i id] [-I id_prefix]\n"); |
| | | printf(" [-d] [--quiet]\n"); |
| | | printf(" [-M max_inflight]\n"); |
| | | printf(" [-u username [-P password]]\n"); |
| | | printf(" [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n"); |
| | | #ifdef WITH_TLS |
| | | printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); |
| | | printf(" [--ciphers ciphers] [--insecure]\n"); |
| | | printf(" [--tls-alpn protocol]\n"); |
| | | printf(" [--tls-engine engine] [--keyform keyform] [--tls-engine-kpass-sha1]]\n"); |
| | | #ifdef FINAL_WITH_TLS_PSK |
| | | printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); |
| | | #endif |
| | | #endif |
| | | #ifdef WITH_SOCKS |
| | | printf(" [--proxy socks-url]\n"); |
| | | #endif |
| | | printf(" [--property command identifier value]\n"); |
| | | printf(" [-D command identifier value]\n"); |
| | | printf(" mosquitto_pub --help\n\n"); |
| | | printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); |
| | | printf(" the client communicates over.\n"); |
| | | printf(" -d : enable debug messages.\n"); |
| | | printf(" -D : Define MQTT v5 properties. See the documentation for more details.\n"); |
| | | printf(" -f : send the contents of a file as the message.\n"); |
| | | printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); |
| | | printf(" -i : id to use for this client. Defaults to mosquitto_pub_ appended with the process id.\n"); |
| | | printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n"); |
| | | printf(" broker is using the clientid_prefixes option.\n"); |
| | | printf(" -k : keep alive in seconds for this client. Defaults to 60.\n"); |
| | | printf(" -L : specify user, password, hostname, port and topic as a URL in the form:\n"); |
| | | printf(" mqtt(s)://[username[:password]@]host[:port]/topic\n"); |
| | | printf(" -l : read messages from stdin, sending a separate message for each line.\n"); |
| | | printf(" -m : message payload to send.\n"); |
| | | printf(" -M : the maximum inflight messages for QoS 1/2..\n"); |
| | | printf(" -n : send a null (zero length) message.\n"); |
| | | printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); |
| | | printf(" -P : provide a password\n"); |
| | | printf(" -q : quality of service level to use for all messages. Defaults to 0.\n"); |
| | | printf(" -r : message should be retained.\n"); |
| | | printf(" -s : read message from stdin, sending the entire input as a message.\n"); |
| | | #ifdef WITH_SRV |
| | | printf(" -S : use SRV lookups to determine which host to connect to.\n"); |
| | | #endif |
| | | printf(" -t : mqtt topic to publish to.\n"); |
| | | printf(" -u : provide a username\n"); |
| | | printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); |
| | | printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); |
| | | printf(" --help : display this message.\n"); |
| | | printf(" --repeat : if publish mode is -f, -m, or -s, then repeat the publish N times.\n"); |
| | | printf(" --repeat-delay : if using --repeat, wait time seconds between publishes. Defaults to 0.\n"); |
| | | printf(" --quiet : don't print error messages.\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(" 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 TLS 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[]) |
| | | { |
| | | struct mosquitto *mosq = NULL; |
| | | int rc; |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | if(pub_shared_init()) return 1; |
| | | |
| | | memset(&cfg, 0, sizeof(struct mosq_config)); |
| | | rc = client_config_load(&cfg, CLIENT_PUB, argc, argv); |
| | | if(rc){ |
| | | if(rc == 2){ |
| | | /* --help */ |
| | | print_usage(); |
| | | }else{ |
| | | fprintf(stderr, "\nUse 'mosquitto_pub --help' to see usage.\n"); |
| | | } |
| | | goto cleanup; |
| | | } |
| | | |
| | | #ifndef WITH_THREADING |
| | | if(cfg.pub_mode == MSGMODE_STDIN_LINE){ |
| | | fprintf(stderr, "Error: '-l' mode not available, threading support has not been compiled in.\n"); |
| | | goto cleanup; |
| | | } |
| | | #endif |
| | | |
| | | if(cfg.pub_mode == MSGMODE_STDIN_FILE){ |
| | | if(load_stdin()){ |
| | | err_printf(&cfg, "Error loading input from stdin.\n"); |
| | | goto cleanup; |
| | | } |
| | | }else if(cfg.file_input){ |
| | | if(load_file(cfg.file_input)){ |
| | | err_printf(&cfg, "Error loading input file \"%s\".\n", cfg.file_input); |
| | | goto cleanup; |
| | | } |
| | | } |
| | | |
| | | if(!cfg.topic || cfg.pub_mode == MSGMODE_NONE){ |
| | | fprintf(stderr, "Error: Both topic and message must be supplied.\n"); |
| | | print_usage(); |
| | | goto cleanup; |
| | | } |
| | | |
| | | |
| | | if(client_id_generate(&cfg)){ |
| | | goto cleanup; |
| | | } |
| | | |
| | | mosq = mosquitto_new(cfg.id, cfg.clean_session, NULL); |
| | | if(!mosq){ |
| | | switch(errno){ |
| | | case ENOMEM: |
| | | err_printf(&cfg, "Error: Out of memory.\n"); |
| | | break; |
| | | case EINVAL: |
| | | err_printf(&cfg, "Error: Invalid id.\n"); |
| | | break; |
| | | } |
| | | goto cleanup; |
| | | } |
| | | if(cfg.debug){ |
| | | mosquitto_log_callback_set(mosq, my_log_callback); |
| | | } |
| | | mosquitto_connect_v5_callback_set(mosq, my_connect_callback); |
| | | mosquitto_disconnect_v5_callback_set(mosq, my_disconnect_callback); |
| | | mosquitto_publish_v5_callback_set(mosq, my_publish_callback); |
| | | |
| | | if(client_opts_set(mosq, &cfg)){ |
| | | goto cleanup; |
| | | } |
| | | |
| | | rc = client_connect(mosq, &cfg); |
| | | if(rc){ |
| | | goto cleanup; |
| | | } |
| | | |
| | | rc = pub_shared_loop(mosq); |
| | | |
| | | if(cfg.message && cfg.pub_mode == MSGMODE_FILE){ |
| | | free(cfg.message); |
| | | cfg.message = NULL; |
| | | } |
| | | mosquitto_destroy(mosq); |
| | | mosquitto_lib_cleanup(); |
| | | client_config_cleanup(&cfg); |
| | | pub_shared_cleanup(); |
| | | |
| | | if(rc){ |
| | | err_printf(&cfg, "Error: %s\n", mosquitto_strerror(rc)); |
| | | } |
| | | return rc; |
| | | |
| | | cleanup: |
| | | mosquitto_lib_cleanup(); |
| | | client_config_cleanup(&cfg); |
| | | pub_shared_cleanup(); |
| | | return 1; |
| | | } |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2018 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <fcntl.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #ifndef WIN32 |
| | | #include <time.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include <mqtt_protocol.h> |
| | | #include "client_shared.h" |
| | | #include "pub_shared.h" |
| | | |
| | | /* Global variables for use in callbacks. See sub_client.c for an example of |
| | | * using a struct to hold variables for use in callbacks. */ |
| | | int mid_sent = -1; |
| | | int status = STATUS_CONNECTING; |
| | | struct mosq_config cfg; |
| | | |
| | | void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) |
| | | { |
| | | UNUSED(mosq); |
| | | UNUSED(obj); |
| | | UNUSED(level); |
| | | |
| | | printf("%s\n", str); |
| | | } |
| | | |
| | | int load_stdin(void) |
| | | { |
| | | long pos = 0, rlen; |
| | | char buf[1024]; |
| | | char *aux_message = NULL; |
| | | |
| | | cfg.pub_mode = MSGMODE_STDIN_FILE; |
| | | |
| | | while(!feof(stdin)){ |
| | | rlen = fread(buf, 1, 1024, stdin); |
| | | aux_message = realloc(cfg.message, pos+rlen); |
| | | if(!aux_message){ |
| | | err_printf(&cfg, "Error: Out of memory.\n"); |
| | | free(cfg.message); |
| | | return 1; |
| | | } else |
| | | { |
| | | cfg.message = aux_message; |
| | | } |
| | | memcpy(&(cfg.message[pos]), buf, rlen); |
| | | pos += rlen; |
| | | } |
| | | cfg.msglen = pos; |
| | | |
| | | if(!cfg.msglen){ |
| | | err_printf(&cfg, "Error: Zero length input.\n"); |
| | | return 1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int load_file(const char *filename) |
| | | { |
| | | long pos, rlen; |
| | | FILE *fptr = NULL; |
| | | |
| | | fptr = fopen(filename, "rb"); |
| | | if(!fptr){ |
| | | err_printf(&cfg, "Error: Unable to open file \"%s\".\n", filename); |
| | | return 1; |
| | | } |
| | | cfg.pub_mode = MSGMODE_FILE; |
| | | fseek(fptr, 0, SEEK_END); |
| | | cfg.msglen = ftell(fptr); |
| | | if(cfg.msglen > 268435455){ |
| | | fclose(fptr); |
| | | err_printf(&cfg, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename); |
| | | return 1; |
| | | }else if(cfg.msglen == 0){ |
| | | fclose(fptr); |
| | | err_printf(&cfg, "Error: File \"%s\" is empty.\n", filename); |
| | | return 1; |
| | | }else if(cfg.msglen < 0){ |
| | | fclose(fptr); |
| | | err_printf(&cfg, "Error: Unable to determine size of file \"%s\".\n", filename); |
| | | return 1; |
| | | } |
| | | fseek(fptr, 0, SEEK_SET); |
| | | cfg.message = malloc(cfg.msglen); |
| | | if(!cfg.message){ |
| | | fclose(fptr); |
| | | err_printf(&cfg, "Error: Out of memory.\n"); |
| | | return 1; |
| | | } |
| | | pos = 0; |
| | | while(pos < cfg.msglen){ |
| | | rlen = fread(&(cfg.message[pos]), sizeof(char), cfg.msglen-pos, fptr); |
| | | pos += rlen; |
| | | } |
| | | fclose(fptr); |
| | | return 0; |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2018 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 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 PUB_SHARED_H |
| | | #define PUB_SHARED_H |
| | | |
| | | #define STATUS_CONNECTING 0 |
| | | #define STATUS_CONNACK_RECVD 1 |
| | | #define STATUS_WAITING 2 |
| | | #define STATUS_DISCONNECTING 3 |
| | | #define STATUS_DISCONNECTED 4 |
| | | |
| | | extern int mid_sent; |
| | | extern int status; |
| | | extern struct mosq_config cfg; |
| | | |
| | | |
| | | void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties); |
| | | void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties); |
| | | void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties); |
| | | void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str); |
| | | int load_stdin(void); |
| | | int load_file(const char *filename); |
| | | |
| | | int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain); |
| | | |
| | | int pub_shared_init(void); |
| | | int pub_shared_loop(struct mosquitto *mosq); |
| | | void pub_shared_cleanup(void); |
| | | |
| | | #endif |
New file |
| | |
| | | LD_LIBRARY_PATH=../lib ./mosquitto_pub \ |
| | | \ |
| | | -t asdf -V mqttv5 -m '{"key":"value"}' \ |
| | | \ |
| | | -D connect authentication-data password \ |
| | | -D connect authentication-method something \ |
| | | -D connect maximum-packet-size 0191 \ |
| | | -D connect receive-maximum 1000 \ |
| | | -D connect request-problem-information 1 \ |
| | | -D connect request-response-information 1 \ |
| | | -D connect session-expiry-interval 39 \ |
| | | -D connect topic-alias-maximum 123 \ |
| | | -D connect user-property connect up \ |
| | | \ |
| | | -D publish content-type application/json \ |
| | | -D publish correlation-data some-data \ |
| | | -D publish message-expiry-interval 59 \ |
| | | -D publish payload-format-indicator 1 \ |
| | | -D publish response-topic /dev/null \ |
| | | -D publish topic-alias 4 \ |
| | | -D publish user-property publish up \ |
| | | \ |
| | | -D disconnect reason-string "reason" \ |
| | | -D disconnect session-expiry-interval 40 \ |
| | | -D disconnect user-property disconnect up |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2018 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <errno.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #ifndef WIN32 |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include <mqtt_protocol.h> |
| | | #include "client_shared.h" |
| | | #include "pub_shared.h" |
| | | |
| | | enum rr__state { |
| | | rr_s_new, |
| | | rr_s_connected, |
| | | rr_s_subscribed, |
| | | rr_s_ready_to_publish, |
| | | rr_s_wait_for_response, |
| | | rr_s_disconnect |
| | | }; |
| | | |
| | | static enum rr__state client_state = rr_s_new; |
| | | |
| | | struct mosq_config cfg; |
| | | bool process_messages = true; |
| | | int msg_count = 0; |
| | | struct mosquitto *mosq = NULL; |
| | | |
| | | #ifndef WIN32 |
| | | void my_signal_handler(int signum) |
| | | { |
| | | if(signum == SIGALRM){ |
| | | 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); |
| | | |
| | | |
| | | int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) |
| | | { |
| | | return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, cfg.publish_props); |
| | | } |
| | | |
| | | |
| | | void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) |
| | | { |
| | | print_message(&cfg, message); |
| | | switch(cfg.pub_mode){ |
| | | case MSGMODE_CMD: |
| | | case MSGMODE_FILE: |
| | | case MSGMODE_STDIN_FILE: |
| | | case MSGMODE_NULL: |
| | | client_state = rr_s_disconnect; |
| | | break; |
| | | case MSGMODE_STDIN_LINE: |
| | | client_state = rr_s_ready_to_publish; |
| | | break; |
| | | } |
| | | /* FIXME - check all below |
| | | if(process_messages == false) return; |
| | | |
| | | if(cfg.retained_only && !message->retain && process_messages){ |
| | | process_messages = false; |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | return; |
| | | } |
| | | |
| | | if(message->retain && cfg.no_retain) return; |
| | | if(cfg.filter_outs){ |
| | | for(i=0; i<cfg.filter_out_count; i++){ |
| | | mosquitto_topic_matches_sub(cfg.filter_outs[i], message->topic, &res); |
| | | if(res) return; |
| | | } |
| | | } |
| | | |
| | | //print_message(&cfg, message); |
| | | |
| | | if(cfg.msg_count>0){ |
| | | msg_count++; |
| | | if(cfg.msg_count == msg_count){ |
| | | process_messages = false; |
| | | 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) |
| | | { |
| | | if(!result){ |
| | | client_state = rr_s_connected; |
| | | mosquitto_subscribe_v5(mosq, NULL, cfg.response_topic, cfg.qos, 0, cfg.subscribe_props); |
| | | }else{ |
| | | client_state = rr_s_disconnect; |
| | | if(result){ |
| | | err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); |
| | | } |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | } |
| | | } |
| | | |
| | | |
| | | void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) |
| | | { |
| | | if(granted_qos[0] < 128){ |
| | | client_state = rr_s_ready_to_publish; |
| | | }else{ |
| | | client_state = rr_s_disconnect; |
| | | err_printf(&cfg, "%s\n", mosquitto_reason_string(granted_qos[0])); |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | } |
| | | } |
| | | |
| | | |
| | | void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) |
| | | { |
| | | client_state = rr_s_wait_for_response; |
| | | } |
| | | |
| | | |
| | | void print_usage(void) |
| | | { |
| | | int major, minor, revision; |
| | | |
| | | mosquitto_lib_version(&major, &minor, &revision); |
| | | printf("mosquitto_rr is an mqtt client that can be used to publish a request message and wait for a response.\n"); |
| | | printf(" Defaults to MQTT v5, where the Request-Response feature will be used, but v3.1.1 can also be used\n"); |
| | | printf(" with v3.1.1 brokers.\n"); |
| | | printf("mosquitto_rr version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); |
| | | printf("Usage: mosquitto_rr {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL} -e response-topic\n"); |
| | | printf(" [-c] [-k keepalive] [-q qos] [-R]\n"); |
| | | printf(" [-F format]\n"); |
| | | #ifndef WIN32 |
| | | printf(" [-W timeout_secs]\n"); |
| | | #endif |
| | | #ifdef WITH_SRV |
| | | printf(" [-A bind_address] [-S]\n"); |
| | | #else |
| | | printf(" [-A bind_address]\n"); |
| | | #endif |
| | | printf(" [-i id] [-I id_prefix]\n"); |
| | | printf(" [-d] [-N] [--quiet] [-v]\n"); |
| | | printf(" [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n"); |
| | | #ifdef WITH_TLS |
| | | printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); |
| | | printf(" [--ciphers ciphers] [--insecure]\n"); |
| | | printf(" [--tls-alpn protocol]\n"); |
| | | printf(" [--tls-engine engine] [--keyform keyform] [--tls-engine-kpass-sha1]]\n"); |
| | | #ifdef FINAL_WITH_TLS_PSK |
| | | printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); |
| | | #endif |
| | | #endif |
| | | #ifdef WITH_SOCKS |
| | | printf(" [--proxy socks-url]\n"); |
| | | #endif |
| | | printf(" [-D command identifier value]\n"); |
| | | printf(" mosquitto_rr --help\n\n"); |
| | | printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); |
| | | printf(" the client communicates over.\n"); |
| | | printf(" -c : disable 'clean session' (store subscription and pending messages when client disconnects).\n"); |
| | | printf(" -d : enable debug messages.\n"); |
| | | printf(" -D : Define MQTT v5 properties. See the documentation for more details.\n"); |
| | | printf(" -F : output format.\n"); |
| | | printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); |
| | | printf(" -i : id to use for this client. Defaults to mosquitto_rr_ appended with the process id.\n"); |
| | | printf(" -k : keep alive in seconds for this client. Defaults to 60.\n"); |
| | | printf(" -L : specify user, password, hostname, port and topic as a URL in the form:\n"); |
| | | printf(" mqtt(s)://[username[:password]@]host[:port]/topic\n"); |
| | | printf(" -N : do not add an end of line character when printing the payload.\n"); |
| | | printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); |
| | | printf(" -P : provide a password\n"); |
| | | printf(" -q : quality of service level to use for communications. Defaults to 0.\n"); |
| | | printf(" -R : do not print stale messages (those with retain set).\n"); |
| | | #ifdef WITH_SRV |
| | | printf(" -S : use SRV lookups to determine which host to connect to.\n"); |
| | | #endif |
| | | printf(" -t : mqtt response topic to subscribe to. May be repeated multiple times.\n"); |
| | | printf(" -u : provide a username\n"); |
| | | printf(" -v : print received messages verbosely.\n"); |
| | | printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); |
| | | printf(" Defaults to 5.\n"); |
| | | #ifndef WIN32 |
| | | printf(" -W : Specifies a timeout in seconds how long to wait for a response.\n"); |
| | | #endif |
| | | printf(" --help : display this message.\n"); |
| | | printf(" --quiet : don't print error messages.\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(" --ciphers : openssl compatible list of TLS ciphers to support.\n"); |
| | | printf(" --tls-version : TLS protocol version, can be one of tlsv1.2 tlsv1.1 or tlsv1.\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"); |
| | | #ifdef 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 |
| | | |
| | | memset(&cfg, 0, sizeof(struct mosq_config)); |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | rc = client_config_load(&cfg, CLIENT_RR, argc, argv); |
| | | if(rc){ |
| | | if(rc == 2){ |
| | | /* --help */ |
| | | print_usage(); |
| | | }else{ |
| | | fprintf(stderr, "\nUse 'mosquitto_rr --help' to see usage.\n"); |
| | | } |
| | | goto cleanup; |
| | | } |
| | | |
| | | if(!cfg.topic || cfg.pub_mode == MSGMODE_NONE || !cfg.response_topic){ |
| | | fprintf(stderr, "Error: All of topic, message, and response topic must be supplied.\n"); |
| | | fprintf(stderr, "\nUse 'mosquitto_rr --help' to see usage.\n"); |
| | | goto cleanup; |
| | | } |
| | | rc = mosquitto_property_add_string(&cfg.publish_props, MQTT_PROP_RESPONSE_TOPIC, cfg.response_topic); |
| | | if(rc){ |
| | | fprintf(stderr, "Error adding property RESPONSE_TOPIC.\n"); |
| | | goto cleanup; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_PUBLISH, cfg.publish_props); |
| | | if(rc){ |
| | | err_printf(&cfg, "Error in PUBLISH properties: Duplicate response topic.\n"); |
| | | goto cleanup; |
| | | } |
| | | |
| | | if(client_id_generate(&cfg)){ |
| | | goto cleanup; |
| | | } |
| | | |
| | | mosq = mosquitto_new(cfg.id, cfg.clean_session, &cfg); |
| | | 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_connect_v5_callback_set(mosq, my_connect_callback); |
| | | mosquitto_subscribe_callback_set(mosq, my_subscribe_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(cfg.timeout){ |
| | | alarm(cfg.timeout); |
| | | } |
| | | #endif |
| | | |
| | | do{ |
| | | rc = mosquitto_loop(mosq, -1, 1); |
| | | if(client_state == rr_s_ready_to_publish){ |
| | | client_state = rr_s_wait_for_response; |
| | | switch(cfg.pub_mode){ |
| | | case MSGMODE_CMD: |
| | | case MSGMODE_FILE: |
| | | case MSGMODE_STDIN_FILE: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, cfg.msglen, cfg.message, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_NULL: |
| | | rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain); |
| | | break; |
| | | case MSGMODE_STDIN_LINE: |
| | | /* FIXME */ |
| | | break; |
| | | } |
| | | } |
| | | }while(rc == MOSQ_ERR_SUCCESS && client_state != rr_s_disconnect); |
| | | |
| | | mosquitto_destroy(mosq); |
| | | mosquitto_lib_cleanup(); |
| | | |
| | | if(cfg.msg_count>0 && rc == MOSQ_ERR_NO_CONN){ |
| | | rc = 0; |
| | | } |
| | | client_config_cleanup(&cfg); |
| | | if(rc){ |
| | | fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); |
| | | } |
| | | return rc; |
| | | |
| | | cleanup: |
| | | mosquitto_lib_cleanup(); |
| | | client_config_cleanup(&cfg); |
| | | return 1; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <errno.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #ifndef WIN32 |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include <mqtt_protocol.h> |
| | | #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){ |
| | | 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 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; i<cfg.filter_out_count; i++){ |
| | | mosquitto_topic_matches_sub(cfg.filter_outs[i], message->topic, &res); |
| | | if(res) return; |
| | | } |
| | | } |
| | | |
| | | 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<cfg.unsub_topic_count; i++){ |
| | | mosquitto_unsubscribe_v5(mosq, NULL, cfg.unsub_topics[i], cfg.unsubscribe_props); |
| | | } |
| | | }else{ |
| | | if(result){ |
| | | if(cfg.protocol_version == MQTT_PROTOCOL_V5){ |
| | | err_printf(&cfg, "%s\n", mosquitto_reason_string(result)); |
| | | }else{ |
| | | err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); |
| | | } |
| | | } |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | } |
| | | } |
| | | |
| | | void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) |
| | | { |
| | | int i; |
| | | |
| | | UNUSED(obj); |
| | | |
| | | if(!cfg.quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); |
| | | for(i=1; i<qos_count; i++){ |
| | | if(!cfg.quiet) printf(", %d", granted_qos[i]); |
| | | } |
| | | if(!cfg.quiet) printf("\n"); |
| | | |
| | | if(cfg.exit_after_sub){ |
| | | mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); |
| | | } |
| | | } |
| | | |
| | | void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) |
| | | { |
| | | UNUSED(mosq); |
| | | UNUSED(obj); |
| | | UNUSED(level); |
| | | |
| | | printf("%s\n", str); |
| | | } |
| | | |
| | | void print_usage(void) |
| | | { |
| | | int major, minor, revision; |
| | | |
| | | mosquitto_lib_version(&major, &minor, &revision); |
| | | printf("mosquitto_sub is a simple mqtt client that will subscribe to a set of topics and print all messages it receives.\n"); |
| | | printf("mosquitto_sub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); |
| | | printf("Usage: mosquitto_sub {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL [-t topic]}\n"); |
| | | printf(" [-c] [-k keepalive] [-q qos]\n"); |
| | | printf(" [-C msg_count] [-E] [-R] [--retained-only] [--remove-retained] [-T filter_out] [-U topic ...]\n"); |
| | | printf(" [-F format]\n"); |
| | | #ifndef WIN32 |
| | | printf(" [-W timeout_secs]\n"); |
| | | #endif |
| | | #ifdef WITH_SRV |
| | | printf(" [-A bind_address] [-S]\n"); |
| | | #else |
| | | printf(" [-A bind_address]\n"); |
| | | #endif |
| | | printf(" [-i id] [-I id_prefix]\n"); |
| | | printf(" [-d] [-N] [--quiet] [-v]\n"); |
| | | printf(" [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n"); |
| | | #ifdef WITH_TLS |
| | | printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); |
| | | printf(" [--ciphers ciphers] [--insecure]\n"); |
| | | printf(" [--tls-alpn protocol]\n"); |
| | | printf(" [--tls-engine engine] [--keyform keyform] [--tls-engine-kpass-sha1]]\n"); |
| | | #ifdef FINAL_WITH_TLS_PSK |
| | | printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); |
| | | #endif |
| | | #endif |
| | | #ifdef WITH_SOCKS |
| | | printf(" [--proxy socks-url]\n"); |
| | | #endif |
| | | printf(" [-D command identifier value]\n"); |
| | | printf(" mosquitto_sub --help\n\n"); |
| | | printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); |
| | | printf(" the client communicates over.\n"); |
| | | printf(" -c : disable 'clean session' (store subscription and pending messages when client disconnects).\n"); |
| | | printf(" -C : disconnect and exit after receiving the 'msg_count' messages.\n"); |
| | | printf(" -d : enable debug messages.\n"); |
| | | printf(" -D : Define MQTT v5 properties. See the documentation for more details.\n"); |
| | | printf(" -E : Exit once all subscriptions have been acknowledged by the broker.\n"); |
| | | printf(" -F : output format.\n"); |
| | | printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); |
| | | printf(" -i : id to use for this client. Defaults to mosquitto_sub_ appended with the process id.\n"); |
| | | printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n"); |
| | | printf(" broker is using the clientid_prefixes option.\n"); |
| | | printf(" -k : keep alive in seconds for this client. Defaults to 60.\n"); |
| | | printf(" -L : specify user, password, hostname, port and topic as a URL in the form:\n"); |
| | | printf(" mqtt(s)://[username[:password]@]host[:port]/topic\n"); |
| | | printf(" -N : do not add an end of line character when printing the payload.\n"); |
| | | printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); |
| | | printf(" -P : provide a password\n"); |
| | | printf(" -q : quality of service level to use for the subscription. Defaults to 0.\n"); |
| | | printf(" -R : do not print stale messages (those with retain set).\n"); |
| | | #ifdef WITH_SRV |
| | | printf(" -S : use SRV lookups to determine which host to connect to.\n"); |
| | | #endif |
| | | printf(" -t : mqtt topic to subscribe to. May be repeated multiple times.\n"); |
| | | printf(" -T : topic string to filter out of results. May be repeated.\n"); |
| | | printf(" -u : provide a username\n"); |
| | | printf(" -U : unsubscribe from a topic. May be repeated.\n"); |
| | | printf(" -v : print published messages verbosely.\n"); |
| | | printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); |
| | | printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); |
| | | #ifndef WIN32 |
| | | printf(" -W : Specifies a timeout in seconds how long to process incoming MQTT messages.\n"); |
| | | #endif |
| | | printf(" --help : display this message.\n"); |
| | | printf(" --quiet : don't print error messages.\n"); |
| | | printf(" --retained-only : only handle messages with the retained flag set, and exit when the\n"); |
| | | printf(" first non-retained message is received.\n"); |
| | | printf(" --remove-retained : send a message to the server to clear any received retained messages\n"); |
| | | printf(" Use -T to filter out messages you do not want to be cleared.\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 |
| | | |
| | | memset(&cfg, 0, sizeof(struct mosq_config)); |
| | | |
| | | 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); |
| | | 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(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){ |
| | | fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); |
| | | } |
| | | return rc; |
| | | |
| | | cleanup: |
| | | mosquitto_lib_cleanup(); |
| | | client_config_cleanup(&cfg); |
| | | return 1; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <errno.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #ifndef WIN32 |
| | | #include <unistd.h> |
| | | #else |
| | | #include <process.h> |
| | | #include <winsock2.h> |
| | | #define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #ifdef __APPLE__ |
| | | # include <sys/time.h> |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include "client_shared.h" |
| | | |
| | | extern struct mosq_config cfg; |
| | | |
| | | static int get_time(struct tm **ti, long *ns) |
| | | { |
| | | #ifdef WIN32 |
| | | SYSTEMTIME st; |
| | | #elif defined(__APPLE__) |
| | | struct timeval tv; |
| | | #else |
| | | struct timespec ts; |
| | | #endif |
| | | time_t s; |
| | | |
| | | #ifdef WIN32 |
| | | s = time(NULL); |
| | | |
| | | GetLocalTime(&st); |
| | | *ns = st.wMilliseconds*1000000L; |
| | | #elif defined(__APPLE__) |
| | | gettimeofday(&tv, NULL); |
| | | s = tv.tv_sec; |
| | | *ns = tv.tv_usec*1000; |
| | | #else |
| | | if(clock_gettime(CLOCK_REALTIME, &ts) != 0){ |
| | | err_printf(&cfg, "Error obtaining system time.\n"); |
| | | return 1; |
| | | } |
| | | s = ts.tv_sec; |
| | | *ns = ts.tv_nsec; |
| | | #endif |
| | | |
| | | *ti = localtime(&s); |
| | | if(!(*ti)){ |
| | | err_printf(&cfg, "Error obtaining system time.\n"); |
| | | return 1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | static void write_payload(const unsigned char *payload, int payloadlen, int hex) |
| | | { |
| | | int i; |
| | | |
| | | if(hex == 0){ |
| | | (void)fwrite(payload, 1, payloadlen, stdout); |
| | | }else if(hex == 1){ |
| | | for(i=0; i<payloadlen; i++){ |
| | | fprintf(stdout, "%02x", payload[i]); |
| | | } |
| | | }else if(hex == 2){ |
| | | for(i=0; i<payloadlen; i++){ |
| | | fprintf(stdout, "%02X", payload[i]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | static void write_json_payload(const char *payload, int payloadlen) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<payloadlen; i++){ |
| | | if(payload[i] == '"' || payload[i] == '\\' || (payload[i] >=0 && payload[i] < 32)){ |
| | | printf("\\u%04x", payload[i]); |
| | | }else{ |
| | | fputc(payload[i], stdout); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | static void json_print(const struct mosquitto_message *message, const struct tm *ti, bool escaped) |
| | | { |
| | | char buf[100]; |
| | | |
| | | strftime(buf, 100, "%s", ti); |
| | | printf("{\"tst\":%s,\"topic\":\"%s\",\"qos\":%d,\"retain\":%d,\"payloadlen\":%d,", buf, message->topic, message->qos, message->retain, message->payloadlen); |
| | | if(message->qos > 0){ |
| | | printf("\"mid\":%d,", message->mid); |
| | | } |
| | | if(escaped){ |
| | | fputs("\"payload\":\"", stdout); |
| | | write_json_payload(message->payload, message->payloadlen); |
| | | fputs("\"}", stdout); |
| | | }else{ |
| | | fputs("\"payload\":", stdout); |
| | | write_payload(message->payload, message->payloadlen, 0); |
| | | fputs("}", stdout); |
| | | } |
| | | } |
| | | |
| | | |
| | | static void formatted_print(const struct mosq_config *lcfg, const struct mosquitto_message *message) |
| | | { |
| | | int len; |
| | | int i; |
| | | struct tm *ti = NULL; |
| | | long ns; |
| | | char strf[3]; |
| | | char buf[100]; |
| | | |
| | | len = strlen(lcfg->format); |
| | | |
| | | for(i=0; i<len; i++){ |
| | | if(lcfg->format[i] == '%'){ |
| | | if(i < len-1){ |
| | | i++; |
| | | switch(lcfg->format[i]){ |
| | | case '%': |
| | | fputc('%', stdout); |
| | | break; |
| | | |
| | | case 'I': |
| | | if(!ti){ |
| | | if(get_time(&ti, &ns)){ |
| | | err_printf(lcfg, "Error obtaining system time.\n"); |
| | | return; |
| | | } |
| | | } |
| | | if(strftime(buf, 100, "%FT%T%z", ti) != 0){ |
| | | fputs(buf, stdout); |
| | | } |
| | | break; |
| | | |
| | | case 'j': |
| | | if(!ti){ |
| | | if(get_time(&ti, &ns)){ |
| | | err_printf(lcfg, "Error obtaining system time.\n"); |
| | | return; |
| | | } |
| | | } |
| | | json_print(message, ti, true); |
| | | break; |
| | | |
| | | case 'J': |
| | | if(!ti){ |
| | | if(get_time(&ti, &ns)){ |
| | | err_printf(lcfg, "Error obtaining system time.\n"); |
| | | return; |
| | | } |
| | | } |
| | | json_print(message, ti, false); |
| | | break; |
| | | |
| | | case 'l': |
| | | printf("%d", message->payloadlen); |
| | | break; |
| | | |
| | | case 'm': |
| | | printf("%d", message->mid); |
| | | break; |
| | | |
| | | case 'p': |
| | | write_payload(message->payload, message->payloadlen, 0); |
| | | break; |
| | | |
| | | case 'q': |
| | | fputc(message->qos + 48, stdout); |
| | | break; |
| | | |
| | | case 'r': |
| | | if(message->retain){ |
| | | fputc('1', stdout); |
| | | }else{ |
| | | fputc('0', stdout); |
| | | } |
| | | break; |
| | | |
| | | case 't': |
| | | fputs(message->topic, stdout); |
| | | break; |
| | | |
| | | case 'U': |
| | | if(!ti){ |
| | | if(get_time(&ti, &ns)){ |
| | | err_printf(lcfg, "Error obtaining system time.\n"); |
| | | return; |
| | | } |
| | | } |
| | | if(strftime(buf, 100, "%s", ti) != 0){ |
| | | printf("%s.%09ld", buf, ns); |
| | | } |
| | | break; |
| | | |
| | | case 'x': |
| | | write_payload(message->payload, message->payloadlen, 1); |
| | | break; |
| | | |
| | | case 'X': |
| | | write_payload(message->payload, message->payloadlen, 2); |
| | | break; |
| | | } |
| | | } |
| | | }else if(lcfg->format[i] == '@'){ |
| | | if(i < len-1){ |
| | | i++; |
| | | if(lcfg->format[i] == '@'){ |
| | | fputc('@', stdout); |
| | | }else{ |
| | | if(!ti){ |
| | | if(get_time(&ti, &ns)){ |
| | | err_printf(lcfg, "Error obtaining system time.\n"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | strf[0] = '%'; |
| | | strf[1] = lcfg->format[i]; |
| | | strf[2] = 0; |
| | | |
| | | if(lcfg->format[i] == 'N'){ |
| | | printf("%09ld", ns); |
| | | }else{ |
| | | if(strftime(buf, 100, strf, ti) != 0){ |
| | | fputs(buf, stdout); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }else if(lcfg->format[i] == '\\'){ |
| | | if(i < len-1){ |
| | | i++; |
| | | switch(lcfg->format[i]){ |
| | | case '\\': |
| | | fputc('\\', stdout); |
| | | break; |
| | | |
| | | case '0': |
| | | fputc('\0', stdout); |
| | | break; |
| | | |
| | | case 'a': |
| | | fputc('\a', stdout); |
| | | break; |
| | | |
| | | case 'e': |
| | | fputc('\033', stdout); |
| | | break; |
| | | |
| | | case 'n': |
| | | fputc('\n', stdout); |
| | | break; |
| | | |
| | | case 'r': |
| | | fputc('\r', stdout); |
| | | break; |
| | | |
| | | case 't': |
| | | fputc('\t', stdout); |
| | | break; |
| | | |
| | | case 'v': |
| | | fputc('\v', stdout); |
| | | break; |
| | | } |
| | | } |
| | | }else{ |
| | | fputc(lcfg->format[i], stdout); |
| | | } |
| | | } |
| | | if(lcfg->eol){ |
| | | fputc('\n', stdout); |
| | | } |
| | | fflush(stdout); |
| | | } |
| | | |
| | | |
| | | void print_message(struct mosq_config *cfg, const struct mosquitto_message *message) |
| | | { |
| | | if(cfg->format){ |
| | | formatted_print(cfg, message); |
| | | }else if(cfg->verbose){ |
| | | if(message->payloadlen){ |
| | | printf("%s ", message->topic); |
| | | write_payload(message->payload, message->payloadlen, false); |
| | | if(cfg->eol){ |
| | | printf("\n"); |
| | | } |
| | | }else{ |
| | | if(cfg->eol){ |
| | | printf("%s (null)\n", message->topic); |
| | | } |
| | | } |
| | | fflush(stdout); |
| | | }else{ |
| | | if(message->payloadlen){ |
| | | write_payload(message->payload, message->payloadlen, false); |
| | | if(cfg->eol){ |
| | | printf("\n"); |
| | | } |
| | | fflush(stdout); |
| | | } |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | LD_LIBRARY_PATH=../lib ./mosquitto_sub \ |
| | | \ |
| | | -V mqttv5 -C 10 -t \$SYS/# -v -U unsub --will-topic will --will-payload '{"key":"value"}' \ |
| | | \ |
| | | -D connect authentication-data password \ |
| | | -D connect authentication-method something \ |
| | | -D connect maximum-packet-size 0191 \ |
| | | -D connect receive-maximum 1000 \ |
| | | -D connect request-problem-information 1 \ |
| | | -D connect request-response-information 1 \ |
| | | -D connect session-expiry-interval 39 \ |
| | | -D connect topic-alias-maximum 123 \ |
| | | -D connect user-property connect up \ |
| | | \ |
| | | -D will content-type application/json \ |
| | | -D will correlation-data some-data \ |
| | | -D will message-expiry-interval 59 \ |
| | | -D will payload-format-indicator 1 \ |
| | | -D will response-topic /dev/null \ |
| | | -D will user-property will up \ |
| | | -D will will-delay-interval 100 \ |
| | | \ |
| | | -D subscribe subscription-identifier 1 \ |
| | | -D subscribe user-property subscribe up \ |
| | | \ |
| | | -D unsubscribe user-property unsubscribe up \ |
| | | \ |
| | | -D disconnect reason-string "reason" \ |
| | | -D disconnect session-expiry-interval 40 \ |
| | | -D disconnect user-property disconnect up |
| | | |
New file |
| | |
| | | The following packages can be used to add features to mosquitto. All of them |
| | | are optional. |
| | | |
| | | * openssl |
| | | * c-ares (for DNS-SRV support, disabled by default) |
| | | * tcp-wrappers (optional, package name libwrap0-dev) |
| | | * libwebsockets (optional, disabled by default, version 1.3 and above) |
| | | * On Windows, a pthreads library is required if threading support is to be |
| | | included. |
| | | |
| | | To compile, run "make", but also see the file config.mk for more details on the |
| | | various options that can be compiled in. |
| | | |
| | | Where possible use the Makefiles to compile. This is particularly relevant for |
| | | the client libraries as symbol information will be included. Use cmake to |
| | | compile on Windows or Mac. |
| | | |
| | | If you have any questions, problems or suggestions (particularly related to |
| | | installing on a more unusual device like a plug-computer) then please get in |
| | | touch using the details in readme.txt. |
New file |
| | |
| | | #ifndef CONFIG_H |
| | | #define CONFIG_H |
| | | /* ============================================================ |
| | | * Platform options |
| | | * ============================================================ */ |
| | | |
| | | #ifdef __APPLE__ |
| | | # define __DARWIN_C_SOURCE |
| | | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__SYMBIAN32__) || defined(__QNX__) |
| | | # define _XOPEN_SOURCE 700 |
| | | # define __BSD_VISIBLE 1 |
| | | # define HAVE_NETINET_IN_H |
| | | #else |
| | | # define _XOPEN_SOURCE 700 |
| | | # define _DEFAULT_SOURCE 1 |
| | | # define _POSIX_C_SOURCE 200809L |
| | | #endif |
| | | |
| | | #define _GNU_SOURCE |
| | | |
| | | #define OPENSSL_LOAD_CONF |
| | | |
| | | /* ============================================================ |
| | | * Compatibility defines |
| | | * ============================================================ */ |
| | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
| | | # define snprintf sprintf_s |
| | | # define EPROTO ECONNABORTED |
| | | #endif |
| | | |
| | | #ifdef WIN32 |
| | | # ifndef strcasecmp |
| | | # define strcasecmp strcmpi |
| | | # endif |
| | | # define strtok_r strtok_s |
| | | # define strerror_r(e, b, l) strerror_s(b, l, e) |
| | | #endif |
| | | |
| | | |
| | | #define uthash_malloc(sz) mosquitto__malloc(sz) |
| | | #define uthash_free(ptr,sz) mosquitto__free(ptr) |
| | | |
| | | |
| | | #ifdef WITH_TLS |
| | | # include <openssl/opensslconf.h> |
| | | # if defined(WITH_TLS_PSK) && !defined(OPENSSL_NO_PSK) |
| | | # define FINAL_WITH_TLS_PSK |
| | | # endif |
| | | #endif |
| | | |
| | | |
| | | #ifdef __COVERITY__ |
| | | # include <stdint.h> |
| | | /* These are "wrong", but we don't use them so it doesn't matter */ |
| | | # define _Float32 uint32_t |
| | | # define _Float32x uint32_t |
| | | # define _Float64 uint64_t |
| | | # define _Float64x uint64_t |
| | | # define _Float128 uint64_t |
| | | #endif |
| | | |
| | | #define UNUSED(A) (void)(A) |
| | | |
| | | /* Android Bionic libpthread implementation doesn't have pthread_cancel */ |
| | | #ifndef ANDROID |
| | | # define HAVE_PTHREAD_CANCEL |
| | | #endif |
| | | |
| | | #endif |
New file |
| | |
| | | # ============================================================================= |
| | | # User configuration section. |
| | | # |
| | | # These options control compilation on all systems apart from Windows and Mac |
| | | # OS X. Use CMake to compile on Windows and Mac. |
| | | # |
| | | # Largely, these are options that are designed to make mosquitto run more |
| | | # easily in restrictive environments by removing features. |
| | | # |
| | | # Modify the variable below to enable/disable features. |
| | | # |
| | | # Can also be overriden at the command line, e.g.: |
| | | # |
| | | # make WITH_TLS=no |
| | | # ============================================================================= |
| | | |
| | | # Uncomment to compile the broker with tcpd/libwrap support. |
| | | #WITH_WRAP:=yes |
| | | |
| | | # Comment out to disable SSL/TLS support in the broker and client. |
| | | # Disabling this will also mean that passwords must be stored in plain text. It |
| | | # is strongly recommended that you only disable WITH_TLS if you are not using |
| | | # password authentication at all. |
| | | WITH_TLS:=yes |
| | | |
| | | # Comment out to disable TLS/PSK support in the broker and client. Requires |
| | | # WITH_TLS=yes. |
| | | # This must be disabled if using openssl < 1.0. |
| | | WITH_TLS_PSK:=yes |
| | | |
| | | # Comment out to disable client threading support. |
| | | WITH_THREADING:=yes |
| | | |
| | | # Comment out to remove bridge support from the broker. This allow the broker |
| | | # to connect to other brokers and subscribe/publish to topics. You probably |
| | | # want to leave this included unless you want to save a very small amount of |
| | | # memory size and CPU time. |
| | | WITH_BRIDGE:=yes |
| | | |
| | | # Comment out to remove persistent database support from the broker. This |
| | | # allows the broker to store retained messages and durable subscriptions to a |
| | | # file periodically and on shutdown. This is usually desirable (and is |
| | | # suggested by the MQTT spec), but it can be disabled if required. |
| | | WITH_PERSISTENCE:=yes |
| | | |
| | | # Comment out to remove memory tracking support from the broker. If disabled, |
| | | # mosquitto won't track heap memory usage nor export '$SYS/broker/heap/current |
| | | # size', but will use slightly less memory and CPU time. |
| | | WITH_MEMORY_TRACKING:=yes |
| | | |
| | | # Compile with database upgrading support? If disabled, mosquitto won't |
| | | # automatically upgrade old database versions. |
| | | # Not currently supported. |
| | | #WITH_DB_UPGRADE:=yes |
| | | |
| | | # Comment out to remove publishing of the $SYS topic hierarchy containing |
| | | # information about the broker state. |
| | | WITH_SYS_TREE:=yes |
| | | |
| | | # Build with systemd support. If enabled, mosquitto will notify systemd after |
| | | # initialization. See README in service/systemd/ for more information. |
| | | WITH_SYSTEMD:=no |
| | | |
| | | # Build with SRV lookup support. |
| | | WITH_SRV:=no |
| | | |
| | | # Build with websockets support on the broker. |
| | | WITH_WEBSOCKETS:=no |
| | | |
| | | # Use elliptic keys in broker |
| | | WITH_EC:=yes |
| | | |
| | | # Build man page documentation by default. |
| | | WITH_DOCS:=yes |
| | | |
| | | # Build with client support for SOCK5 proxy. |
| | | WITH_SOCKS:=yes |
| | | |
| | | # Strip executables and shared libraries on install. |
| | | WITH_STRIP:=no |
| | | |
| | | # Build static libraries |
| | | WITH_STATIC_LIBRARIES:=no |
| | | |
| | | # Build shared libraries |
| | | WITH_SHARED_LIBRARIES:=yes |
| | | |
| | | # Build with async dns lookup support for bridges (temporary). Requires glibc. |
| | | #WITH_ADNS:=yes |
| | | |
| | | # Build with epoll support. |
| | | WITH_EPOLL:=yes |
| | | |
| | | # Build with bundled uthash.h |
| | | WITH_BUNDLED_DEPS:=yes |
| | | |
| | | # Build with coverage options |
| | | WITH_COVERAGE:=no |
| | | |
| | | # ============================================================================= |
| | | # End of user configuration |
| | | # ============================================================================= |
| | | |
| | | |
| | | # Also bump lib/mosquitto.h, CMakeLists.txt, |
| | | # installer/mosquitto.nsi, installer/mosquitto64.nsi |
| | | VERSION=1.6.3 |
| | | |
| | | # Client library SO version. Bump if incompatible API/ABI changes are made. |
| | | SOVERSION=1 |
| | | |
| | | # Man page generation requires xsltproc and docbook-xsl |
| | | XSLTPROC=xsltproc --nonet |
| | | # For html generation |
| | | DB_HTML_XSL=man/html.xsl |
| | | |
| | | #MANCOUNTRIES=en_GB |
| | | |
| | | UNAME:=$(shell uname -s) |
| | | |
| | | ifeq ($(UNAME),SunOS) |
| | | ifeq ($(CC),cc) |
| | | CFLAGS?=-O |
| | | else |
| | | CFLAGS?=-Wall -ggdb -O2 |
| | | endif |
| | | else |
| | | CFLAGS?=-Wall -ggdb -O2 |
| | | endif |
| | | |
| | | STATIC_LIB_DEPS:= |
| | | |
| | | LIB_CPPFLAGS=$(CPPFLAGS) -I. -I.. -I../lib -I../src/deps |
| | | LIB_CFLAGS:=$(CFLAGS) |
| | | LIB_CXXFLAGS:=$(CXXFLAGS) |
| | | LIB_LDFLAGS:=$(LDFLAGS) |
| | | LIB_LIBADD:=$(LIBADD) |
| | | |
| | | BROKER_CPPFLAGS:=$(LIB_CPPFLAGS) |
| | | BROKER_CFLAGS:=${CFLAGS} -DVERSION="\"${VERSION}\"" -DWITH_BROKER |
| | | BROKER_LDFLAGS:=${LDFLAGS} |
| | | BROKER_LDADD:= |
| | | |
| | | CLIENT_CPPFLAGS:=$(CPPFLAGS) -I.. -I../lib |
| | | CLIENT_CFLAGS:=${CFLAGS} -DVERSION="\"${VERSION}\"" |
| | | CLIENT_LDFLAGS:=$(LDFLAGS) -L../lib |
| | | CLIENT_LDADD:= |
| | | |
| | | PASSWD_LDADD:= |
| | | |
| | | ifneq ($(or $(findstring $(UNAME),FreeBSD), $(findstring $(UNAME),OpenBSD), $(findstring $(UNAME),NetBSD)),) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lm |
| | | else |
| | | BROKER_LDADD:=$(BROKER_LDADD) -ldl -lm |
| | | endif |
| | | |
| | | ifeq ($(UNAME),Linux) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lrt |
| | | BROKER_LDFLAGS:=$(BROKER_LDFLAGS) -Wl,--dynamic-list=linker.syms |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lrt |
| | | endif |
| | | |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | CLIENT_LDADD:=${CLIENT_LDADD} ../lib/libmosquitto.so.${SOVERSION} |
| | | endif |
| | | |
| | | ifeq ($(UNAME),SunOS) |
| | | ifeq ($(CC),cc) |
| | | LIB_CFLAGS:=$(LIB_CFLAGS) -xc99 -KPIC |
| | | else |
| | | LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC |
| | | endif |
| | | |
| | | ifeq ($(CXX),CC) |
| | | LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -KPIC |
| | | else |
| | | LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -fPIC |
| | | endif |
| | | else |
| | | LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC |
| | | LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -fPIC |
| | | endif |
| | | |
| | | ifneq ($(UNAME),SunOS) |
| | | LIB_LDFLAGS:=$(LIB_LDFLAGS) -Wl,--version-script=linker.version -Wl,-soname,libmosquitto.so.$(SOVERSION) |
| | | endif |
| | | |
| | | ifeq ($(UNAME),QNX) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lsocket |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lsocket |
| | | endif |
| | | |
| | | ifeq ($(WITH_WRAP),yes) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lwrap |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_WRAP |
| | | endif |
| | | |
| | | ifeq ($(WITH_TLS),yes) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lssl -lcrypto |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lssl -lcrypto |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_TLS |
| | | LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_TLS |
| | | PASSWD_LDADD:=$(PASSWD_LDADD) -lcrypto |
| | | CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_TLS |
| | | STATIC_LIB_DEPS:=$(STATIC_LIB_DEPS) -lssl -lcrypto |
| | | |
| | | ifeq ($(WITH_TLS_PSK),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_TLS_PSK |
| | | LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_TLS_PSK |
| | | CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_TLS_PSK |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(WITH_THREADING),yes) |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lpthread |
| | | LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_THREADING |
| | | CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_THREADING |
| | | STATIC_LIB_DEPS:=$(STATIC_LIB_DEPS) -lpthread |
| | | endif |
| | | |
| | | ifeq ($(WITH_SOCKS),yes) |
| | | LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_SOCKS |
| | | CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_SOCKS |
| | | endif |
| | | |
| | | ifeq ($(WITH_BRIDGE),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_BRIDGE |
| | | endif |
| | | |
| | | ifeq ($(WITH_PERSISTENCE),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_PERSISTENCE |
| | | endif |
| | | |
| | | ifeq ($(WITH_MEMORY_TRACKING),yes) |
| | | ifneq ($(UNAME),SunOS) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_MEMORY_TRACKING |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(WITH_SYS_TREE),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_SYS_TREE |
| | | endif |
| | | |
| | | ifeq ($(WITH_SYSTEMD),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_SYSTEMD |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lsystemd |
| | | endif |
| | | |
| | | ifeq ($(WITH_SRV),yes) |
| | | LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_SRV |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lcares |
| | | CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_SRV |
| | | STATIC_LIB_DEPS:=$(STATIC_LIB_DEPS) -lcares |
| | | endif |
| | | |
| | | ifeq ($(UNAME),SunOS) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lsocket -lnsl |
| | | LIB_LIBADD:=$(LIB_LIBADD) -lsocket -lnsl |
| | | endif |
| | | |
| | | ifeq ($(WITH_EC),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_EC |
| | | endif |
| | | |
| | | ifeq ($(WITH_ADNS),yes) |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lanl |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_ADNS |
| | | endif |
| | | |
| | | MAKE_ALL:=mosquitto |
| | | ifeq ($(WITH_DOCS),yes) |
| | | MAKE_ALL:=$(MAKE_ALL) docs |
| | | endif |
| | | |
| | | ifeq ($(WITH_WEBSOCKETS),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_WEBSOCKETS |
| | | BROKER_LDADD:=$(BROKER_LDADD) -lwebsockets |
| | | endif |
| | | |
| | | ifeq ($(WITH_WEBSOCKETS),static) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_WEBSOCKETS |
| | | BROKER_LDADD:=$(BROKER_LDADD) -static -lwebsockets |
| | | endif |
| | | |
| | | INSTALL?=install |
| | | prefix?=/usr/local |
| | | incdir?=${prefix}/include |
| | | libdir?=${prefix}/lib${LIB_SUFFIX} |
| | | localedir?=${prefix}/share/locale |
| | | mandir?=${prefix}/share/man |
| | | STRIP?=strip |
| | | |
| | | ifeq ($(WITH_STRIP),yes) |
| | | STRIP_OPTS?=-s --strip-program=${CROSS_COMPILE}${STRIP} |
| | | endif |
| | | |
| | | ifeq ($(WITH_EPOLL),yes) |
| | | ifeq ($(UNAME),Linux) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_EPOLL |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(WITH_BUNDLED_DEPS),yes) |
| | | BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -Ideps |
| | | endif |
| | | |
| | | ifeq ($(WITH_COVERAGE),yes) |
| | | BROKER_CFLAGS:=$(BROKER_CFLAGS) -coverage |
| | | BROKER_LDFLAGS:=$(BROKER_LDFLAGS) -coverage |
| | | LIB_CFLAGS:=$(LIB_CFLAGS) -coverage |
| | | LIB_LDFLAGS:=$(LIB_LDFLAGS) -coverage |
| | | CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -coverage |
| | | CLIENT_LDFLAGS:=$(CLIENT_LDFLAGS) -coverage |
| | | endif |
New file |
| | |
| | | Eclipse Distribution License - v 1.0 |
| | | |
| | | Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. |
| | | |
| | | All rights reserved. |
| | | |
| | | Redistribution and use in source and binary forms, with or without |
| | | modification, are permitted provided that the following conditions are met: |
| | | |
| | | Redistributions of source code must retain the above copyright notice, this |
| | | list of conditions and the following disclaimer. |
| | | |
| | | Redistributions in binary form must reproduce the above copyright notice, |
| | | this list of conditions and the following disclaimer in the documentation |
| | | and/or other materials provided with the distribution. |
| | | |
| | | Neither the name of the Eclipse Foundation, Inc. nor the names of its |
| | | contributors may be used to endorse or promote products derived from this |
| | | software without specific prior written permission. |
| | | |
| | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| | | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | |
New file |
| | |
| | | Eclipse Public License - v 1.0 |
| | | |
| | | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC |
| | | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM |
| | | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. |
| | | |
| | | |
| | | 1. DEFINITIONS |
| | | |
| | | "Contribution" means: |
| | | a) in the case of the initial Contributor, the initial code and |
| | | documentation distributed under this Agreement, and |
| | | |
| | | b) in the case of each subsequent Contributor: |
| | | |
| | | i) changes to the Program, and |
| | | ii) additions to the Program; |
| | | |
| | | where such changes and/or additions to the Program originate from and are |
| | | distributed by that particular Contributor. A Contribution 'originates' from a |
| | | Contributor if it was added to the Program by such Contributor itself or anyone |
| | | acting on such Contributor's behalf. Contributions do not include additions to |
| | | the Program which: (i) are separate modules of software distributed in |
| | | conjunction with the Program under their own license agreement, and (ii) are |
| | | not derivative works of the Program. |
| | | |
| | | "Contributor" means any person or entity that distributes the Program. |
| | | |
| | | "Licensed Patents " mean patent claims licensable by a Contributor which are |
| | | necessarily infringed by the use or sale of its Contribution alone or when |
| | | combined with the Program. |
| | | |
| | | "Program" means the Contributions distributed in accordance with this Agreement. |
| | | |
| | | "Recipient" means anyone who receives the Program under this Agreement, |
| | | including all Contributors. |
| | | |
| | | |
| | | 2. GRANT OF RIGHTS |
| | | |
| | | a) Subject to the terms of this Agreement, each Contributor hereby grants |
| | | Recipient a non-exclusive, worldwide, royalty-free copyright license to |
| | | reproduce, prepare derivative works of, publicly display, publicly |
| | | perform, distribute and sublicense the Contribution of such Contributor, |
| | | if any, and such derivative works, in source code and object code form. |
| | | |
| | | b) Subject to the terms of this Agreement, each Contributor hereby grants |
| | | Recipient a non-exclusive, worldwide, royalty-free patent license under |
| | | Licensed Patents to make, use, sell, offer to sell, import and otherwise |
| | | transfer the Contribution of such Contributor, if any, in source code and |
| | | object code form. This patent license shall apply to the combination of the |
| | | Contribution and the Program if, at the time the Contribution is added by the |
| | | Contributor, such addition of the Contribution causes such combination to be |
| | | covered by the Licensed Patents. The patent license shall not apply to any |
| | | other combinations which include the Contribution. No hardware per se is |
| | | licensed hereunder. |
| | | |
| | | c) Recipient understands that although each Contributor grants the licenses |
| | | to its Contributions set forth herein, no assurances are provided by any |
| | | Contributor that the Program does not infringe the patent or other |
| | | intellectual property rights of any other entity. Each Contributor disclaims |
| | | any liability to Recipient for claims brought by any other entity based on |
| | | infringement of intellectual property rights or otherwise. As a condition to |
| | | exercising the rights and licenses granted hereunder, each Recipient hereby |
| | | assumes sole responsibility to secure any other intellectual property rights |
| | | needed, if any. For example, if a third party patent license is required to |
| | | allow Recipient to distribute the Program, it is Recipient's responsibility |
| | | to acquire that license before distributing the Program. |
| | | |
| | | d) Each Contributor represents that to its knowledge it has sufficient |
| | | copyright rights in its Contribution, if any, to grant the copyright license |
| | | set forth in this Agreement. |
| | | |
| | | |
| | | 3. REQUIREMENTS |
| | | |
| | | A Contributor may choose to distribute the Program in object code form under |
| | | its own license agreement, provided that: |
| | | |
| | | a) it complies with the terms and conditions of this Agreement; and |
| | | |
| | | b) its license agreement: |
| | | |
| | | i) effectively disclaims on behalf of all Contributors all warranties and |
| | | conditions, express and implied, including warranties or conditions of |
| | | title and non-infringement, and implied warranties or conditions of |
| | | merchantability and fitness for a particular purpose; |
| | | |
| | | ii) effectively excludes on behalf of all Contributors all liability for |
| | | damages, including direct, indirect, special, incidental and consequential |
| | | damages, such as lost profits; |
| | | |
| | | iii) states that any provisions which differ from this Agreement are offered |
| | | by that Contributor alone and not by any other party; and |
| | | |
| | | iv) states that source code for the Program is available from such |
| | | Contributor, and informs licensees how to obtain it in a reasonable manner |
| | | on or through a medium customarily used for software exchange. |
| | | |
| | | When the Program is made available in source code form: |
| | | |
| | | a) it must be made available under this Agreement; and |
| | | |
| | | b) a copy of this Agreement must be included with each copy of the Program. |
| | | |
| | | Contributors may not remove or alter any copyright notices contained within |
| | | the Program. |
| | | |
| | | Each Contributor must identify itself as the originator of its Contribution, |
| | | if any, in a manner that reasonably allows subsequent Recipients to identify |
| | | the originator of the Contribution. |
| | | |
| | | |
| | | 4. COMMERCIAL DISTRIBUTION |
| | | |
| | | Commercial distributors of software may accept certain responsibilities with |
| | | respect to end users, business partners and the like. While this license is |
| | | intended to facilitate the commercial use of the Program, the Contributor who |
| | | includes the Program in a commercial product offering should do so in a |
| | | manner which does not create potential liability for other Contributors. |
| | | Therefore, if a Contributor includes the Program in a commercial product |
| | | offering, such Contributor ("Commercial Contributor") hereby agrees to defend |
| | | and indemnify every other Contributor ("Indemnified Contributor") against any |
| | | losses, damages and costs (collectively "Losses") arising from claims, |
| | | lawsuits and other legal actions brought by a third party against the |
| | | Indemnified Contributor to the extent caused by the acts or omissions of such |
| | | Commercial Contributor in connection with its distribution of the Program in |
| | | a commercial product offering. The obligations in this section do not apply |
| | | to any claims or Losses relating to any actual or alleged intellectual |
| | | property infringement. In order to qualify, an Indemnified Contributor must: |
| | | a) promptly notify the Commercial Contributor in writing of such claim, and |
| | | b) allow the Commercial Contributor to control, and cooperate with the |
| | | Commercial Contributor in, the defense and any related settlement |
| | | negotiations. The Indemnified Contributor may participate in any such claim |
| | | at its own expense. |
| | | |
| | | For example, a Contributor might include the Program in a commercial product |
| | | offering, Product X. That Contributor is then a Commercial Contributor. If |
| | | that Commercial Contributor then makes performance claims, or offers |
| | | warranties related to Product X, those performance claims and warranties are |
| | | such Commercial Contributor's responsibility alone. Under this section, the |
| | | Commercial Contributor would have to defend claims against the other |
| | | Contributors related to those performance claims and warranties, and if a |
| | | court requires any other Contributor to pay any damages as a result, the |
| | | Commercial Contributor must pay those damages. |
| | | |
| | | |
| | | 5. NO WARRANTY |
| | | |
| | | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON |
| | | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER |
| | | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR |
| | | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A |
| | | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the |
| | | appropriateness of using and distributing the Program and assumes all risks |
| | | associated with its exercise of rights under this Agreement , including but |
| | | not limited to the risks and costs of program errors, compliance with |
| | | applicable laws, damage to or loss of data, programs or equipment, and |
| | | unavailability or interruption of operations. |
| | | |
| | | |
| | | 6. DISCLAIMER OF LIABILITY |
| | | |
| | | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY |
| | | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION |
| | | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| | | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE |
| | | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY |
| | | OF SUCH DAMAGES. |
| | | |
| | | |
| | | 7. GENERAL |
| | | |
| | | If any provision of this Agreement is invalid or unenforceable under |
| | | applicable law, it shall not affect the validity or enforceability of the |
| | | remainder of the terms of this Agreement, and without further action by the |
| | | parties hereto, such provision shall be reformed to the minimum extent |
| | | necessary to make such provision valid and enforceable. |
| | | |
| | | If Recipient institutes patent litigation against any entity (including a |
| | | cross-claim or counterclaim in a lawsuit) alleging that the Program itself |
| | | (excluding combinations of the Program with other software or hardware) |
| | | infringes such Recipient's patent(s), then such Recipient's rights granted |
| | | under Section 2(b) shall terminate as of the date such litigation is filed. |
| | | |
| | | All Recipient's rights under this Agreement shall terminate if it fails to |
| | | comply with any of the material terms or conditions of this Agreement and |
| | | does not cure such failure in a reasonable period of time after becoming |
| | | aware of such noncompliance. If all Recipient's rights under this Agreement |
| | | terminate, Recipient agrees to cease use and distribution of the Program as |
| | | soon as reasonably practicable. However, Recipient's obligations under this |
| | | Agreement and any licenses granted by Recipient relating to the Program shall |
| | | continue and survive. |
| | | |
| | | Everyone is permitted to copy and distribute copies of this Agreement, but in |
| | | order to avoid inconsistency the Agreement is copyrighted and may only be |
| | | modified in the following manner. The Agreement Steward reserves the right to |
| | | publish new versions (including revisions) of this Agreement from time to |
| | | time. No one other than the Agreement Steward has the right to modify this |
| | | Agreement. The Eclipse Foundation is the initial Agreement Steward. The |
| | | Eclipse Foundation may assign the responsibility to serve as the Agreement |
| | | Steward to a suitable separate entity. Each new version of the Agreement will |
| | | be given a distinguishing version number. The Program (including |
| | | Contributions) may always be distributed subject to the version of the |
| | | Agreement under which it was received. In addition, after a new version of |
| | | the Agreement is published, Contributor may elect to distribute the Program |
| | | (including its Contributions) under the new version. Except as expressly |
| | | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or |
| | | licenses to the intellectual property of any Contributor under this |
| | | Agreement, whether expressly, by implication, estoppel or otherwise. All |
| | | rights in the Program not expressly granted under this Agreement are |
| | | reserved. |
| | | |
| | | This Agreement is governed by the laws of the State of New York and the |
| | | intellectual property laws of the United States of America. No party to this |
| | | Agreement will bring a legal action under this Agreement more than one year |
| | | after the cause of action arose. Each party waives its rights to a jury trial |
| | | in any resulting litigation. |
| | | |
New file |
| | |
| | | CFLAGS=-Wall -ggdb |
| | | LDFLAGS=../../lib/libmosquitto.so.1 -lmysqlclient |
| | | |
| | | .PHONY: all clean |
| | | |
| | | all : mosquitto_mysql_log |
| | | |
| | | mosquitto_mysql_log : mysql_log.o |
| | | ${CC} $^ -o $@ ${LDFLAGS} |
| | | |
| | | mysql_log.o : mysql_log.c |
| | | ${CC} -c $^ -o $@ ${CFLAGS} -I../../lib |
| | | |
| | | clean : |
| | | -rm -f *.o mosquitto_mysql_log |
New file |
| | |
| | | #include <signal.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifndef WIN32 |
| | | # include <unistd.h> |
| | | #else |
| | | # include <process.h> |
| | | # define snprintf sprintf_s |
| | | #endif |
| | | |
| | | #include <mosquitto.h> |
| | | #include <mysql/mysql.h> |
| | | |
| | | #define db_host "localhost" |
| | | #define db_username "mqtt_log" |
| | | #define db_password "password" |
| | | #define db_database "mqtt_log" |
| | | #define db_port 3306 |
| | | |
| | | #define db_query "INSERT INTO mqtt_log (topic, payload) VALUES (?,?)" |
| | | |
| | | #define mqtt_host "localhost" |
| | | #define mqtt_port 1883 |
| | | |
| | | static int run = 1; |
| | | static MYSQL_STMT *stmt = NULL; |
| | | |
| | | void handle_signal(int s) |
| | | { |
| | | run = 0; |
| | | } |
| | | |
| | | void connect_callback(struct mosquitto *mosq, void *obj, int result) |
| | | { |
| | | } |
| | | |
| | | void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | { |
| | | MYSQL_BIND bind[2]; |
| | | |
| | | memset(bind, 0, sizeof(bind)); |
| | | |
| | | bind[0].buffer_type = MYSQL_TYPE_STRING; |
| | | bind[0].buffer = message->topic; |
| | | bind[0].buffer_length = strlen(message->topic); |
| | | // Note: payload is normally a binary blob and could contains |
| | | // NULL byte. This sample does not handle it and assume payload is a |
| | | // string. |
| | | bind[1].buffer_type = MYSQL_TYPE_STRING; |
| | | bind[1].buffer = message->payload; |
| | | bind[1].buffer_length = message->payloadlen; |
| | | |
| | | mysql_stmt_bind_param(stmt, bind); |
| | | mysql_stmt_execute(stmt); |
| | | } |
| | | |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | MYSQL *connection; |
| | | my_bool reconnect = true; |
| | | char clientid[24]; |
| | | struct mosquitto *mosq; |
| | | int rc = 0; |
| | | |
| | | signal(SIGINT, handle_signal); |
| | | signal(SIGTERM, handle_signal); |
| | | |
| | | mysql_library_init(0, NULL, NULL); |
| | | mosquitto_lib_init(); |
| | | |
| | | connection = mysql_init(NULL); |
| | | |
| | | if(connection){ |
| | | mysql_options(connection, MYSQL_OPT_RECONNECT, &reconnect); |
| | | |
| | | connection = mysql_real_connect(connection, db_host, db_username, db_password, db_database, db_port, NULL, 0); |
| | | |
| | | if(connection){ |
| | | stmt = mysql_stmt_init(connection); |
| | | |
| | | mysql_stmt_prepare(stmt, db_query, strlen(db_query)); |
| | | |
| | | memset(clientid, 0, 24); |
| | | snprintf(clientid, 23, "mysql_log_%d", getpid()); |
| | | mosq = mosquitto_new(clientid, true, connection); |
| | | if(mosq){ |
| | | mosquitto_connect_callback_set(mosq, connect_callback); |
| | | mosquitto_message_callback_set(mosq, message_callback); |
| | | |
| | | |
| | | rc = mosquitto_connect(mosq, mqtt_host, mqtt_port, 60); |
| | | |
| | | mosquitto_subscribe(mosq, NULL, "#", 0); |
| | | |
| | | while(run){ |
| | | rc = mosquitto_loop(mosq, -1, 1); |
| | | if(run && rc){ |
| | | sleep(20); |
| | | mosquitto_reconnect(mosq); |
| | | } |
| | | } |
| | | mosquitto_destroy(mosq); |
| | | } |
| | | mysql_stmt_close(stmt); |
| | | |
| | | mysql_close(connection); |
| | | }else{ |
| | | fprintf(stderr, "Error: Unable to connect to database.\n"); |
| | | printf("%s\n", mysql_error(connection)); |
| | | rc = 1; |
| | | } |
| | | }else{ |
| | | fprintf(stderr, "Error: Unable to start mysql.\n"); |
| | | rc = 1; |
| | | } |
| | | |
| | | mysql_library_end(); |
| | | mosquitto_lib_cleanup(); |
| | | |
| | | return rc; |
| | | } |
| | | |
New file |
| | |
| | | include ../../config.mk |
| | | |
| | | .PHONY: all |
| | | |
| | | all : sub_callback sub_single sub_multiple |
| | | |
| | | sub_callback : callback.o |
| | | ${CROSS_COMPILE}${CC} $^ -o $@ ../../lib/libmosquitto.so.${SOVERSION} |
| | | |
| | | sub_single : single.o |
| | | ${CROSS_COMPILE}${CC} $^ -o $@ ../../lib/libmosquitto.so.${SOVERSION} |
| | | |
| | | sub_multiple : multiple.o |
| | | ${CROSS_COMPILE}${CC} $^ -o $@ ../../lib/libmosquitto.so.${SOVERSION} |
| | | |
| | | callback.o : callback.c ../../lib/libmosquitto.so.${SOVERSION} |
| | | ${CROSS_COMPILE}${CC} -c $< -o $@ -I../../lib ${CFLAGS} |
| | | |
| | | single.o : single.c ../../lib/libmosquitto.so.${SOVERSION} |
| | | ${CROSS_COMPILE}${CC} -c $< -o $@ -I../../lib ${CFLAGS} |
| | | |
| | | multiple.o : multiple.c ../../lib/libmosquitto.so.${SOVERSION} |
| | | ${CROSS_COMPILE}${CC} -c $< -o $@ -I../../lib ${CFLAGS} |
| | | |
| | | ../../lib/libmosquitto.so.${SOVERSION} : |
| | | $(MAKE) -C ../../lib |
| | | |
| | | clean : |
| | | -rm -f *.o sub_single sub_multiple |
New file |
| | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include "mosquitto.h" |
| | | |
| | | int on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *msg) |
| | | { |
| | | printf("%s %s (%d)\n", msg->topic, (const char *)msg->payload, msg->payloadlen); |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | int rc; |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | rc = mosquitto_subscribe_callback( |
| | | on_message, NULL, |
| | | "irc/#", 0, |
| | | "test.mosquitto.org", 1883, |
| | | NULL, 60, true, |
| | | NULL, NULL, |
| | | NULL, NULL); |
| | | |
| | | if(rc){ |
| | | printf("Error: %s\n", mosquitto_strerror(rc)); |
| | | } |
| | | |
| | | mosquitto_lib_cleanup(); |
| | | |
| | | return rc; |
| | | } |
| | | |
New file |
| | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include "mosquitto.h" |
| | | |
| | | #define COUNT 3 |
| | | |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | int rc; |
| | | int i; |
| | | struct mosquitto_message *msg; |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | rc = mosquitto_subscribe_simple( |
| | | &msg, COUNT, true, |
| | | "irc/#", 0, |
| | | "test.mosquitto.org", 1883, |
| | | NULL, 60, true, |
| | | NULL, NULL, |
| | | NULL, NULL); |
| | | |
| | | if(rc){ |
| | | printf("Error: %s\n", mosquitto_strerror(rc)); |
| | | mosquitto_lib_cleanup(); |
| | | return rc; |
| | | } |
| | | |
| | | for(i=0; i<COUNT; i++){ |
| | | printf("%s %s\n", msg[i].topic, (char *)msg[i].payload); |
| | | mosquitto_message_free_contents(&msg[i]); |
| | | } |
| | | free(msg); |
| | | |
| | | mosquitto_lib_cleanup(); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include "mosquitto.h" |
| | | |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | int rc; |
| | | struct mosquitto_message *msg; |
| | | |
| | | mosquitto_lib_init(); |
| | | |
| | | rc = mosquitto_subscribe_simple( |
| | | &msg, 1, true, |
| | | "irc/#", 0, |
| | | "test.mosquitto.org", 1883, |
| | | NULL, 60, true, |
| | | NULL, NULL, |
| | | NULL, NULL); |
| | | |
| | | if(rc){ |
| | | printf("Error: %s\n", mosquitto_strerror(rc)); |
| | | mosquitto_lib_cleanup(); |
| | | return rc; |
| | | } |
| | | |
| | | printf("%s %s\n", msg->topic, (char *)msg->payload); |
| | | mosquitto_message_free(&msg); |
| | | |
| | | mosquitto_lib_cleanup(); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | CFLAGS=-Wall -ggdb -I../../lib -I../../lib/cpp |
| | | LDFLAGS=-L../../lib ../../lib/cpp/libmosquittopp.so.1 ../../lib/libmosquitto.so.1 |
| | | |
| | | .PHONY: all clean |
| | | |
| | | all : mqtt_temperature_conversion |
| | | |
| | | mqtt_temperature_conversion : main.o temperature_conversion.o |
| | | ${CXX} $^ -o $@ ${LDFLAGS} |
| | | |
| | | main.o : main.cpp |
| | | ${CXX} -c $^ -o $@ ${CFLAGS} |
| | | |
| | | temperature_conversion.o : temperature_conversion.cpp |
| | | ${CXX} -c $^ -o $@ ${CFLAGS} |
| | | |
| | | clean : |
| | | -rm -f *.o mqtt_temperature_conversion |
New file |
| | |
| | | #include "temperature_conversion.h" |
| | | |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | class mqtt_tempconv *tempconv; |
| | | int rc; |
| | | |
| | | mosqpp::lib_init(); |
| | | |
| | | tempconv = new mqtt_tempconv("tempconv", "localhost", 1883); |
| | | tempconv->loop_forever(); |
| | | |
| | | mosqpp::lib_cleanup(); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | This is a simple example of the C++ library mosquittopp. |
| | | |
| | | It is a client that subscribes to the topic temperature/celsius which should |
| | | have temperature data in text form being published to it. It reads this data as |
| | | a Celsius temperature, converts to Farenheit and republishes on |
| | | temperature/farenheit. |
New file |
| | |
| | | #include <cstdio> |
| | | #include <cstring> |
| | | |
| | | #include "temperature_conversion.h" |
| | | #include <mosquittopp.h> |
| | | |
| | | mqtt_tempconv::mqtt_tempconv(const char *id, const char *host, int port) : mosquittopp(id) |
| | | { |
| | | int keepalive = 60; |
| | | |
| | | /* Connect immediately. This could also be done by calling |
| | | * mqtt_tempconv->connect(). */ |
| | | connect(host, port, keepalive); |
| | | }; |
| | | |
| | | mqtt_tempconv::~mqtt_tempconv() |
| | | { |
| | | } |
| | | |
| | | void mqtt_tempconv::on_connect(int rc) |
| | | { |
| | | printf("Connected with code %d.\n", rc); |
| | | if(rc == 0){ |
| | | /* Only attempt to subscribe on a successful connect. */ |
| | | subscribe(NULL, "temperature/celsius"); |
| | | } |
| | | } |
| | | |
| | | void mqtt_tempconv::on_message(const struct mosquitto_message *message) |
| | | { |
| | | double temp_celsius, temp_farenheit; |
| | | char buf[51]; |
| | | |
| | | if(!strcmp(message->topic, "temperature/celsius")){ |
| | | memset(buf, 0, 51*sizeof(char)); |
| | | /* Copy N-1 bytes to ensure always 0 terminated. */ |
| | | memcpy(buf, message->payload, 50*sizeof(char)); |
| | | temp_celsius = atof(buf); |
| | | temp_farenheit = temp_celsius*9.0/5.0 + 32.0; |
| | | snprintf(buf, 50, "%f", temp_farenheit); |
| | | publish(NULL, "temperature/farenheit", strlen(buf), buf); |
| | | } |
| | | } |
| | | |
| | | void mqtt_tempconv::on_subscribe(int mid, int qos_count, const int *granted_qos) |
| | | { |
| | | printf("Subscription succeeded.\n"); |
| | | } |
| | | |
New file |
| | |
| | | #ifndef TEMPERATURE_CONVERSION_H |
| | | #define TEMPERATURE_CONVERSION_H |
| | | |
| | | #include <mosquittopp.h> |
| | | |
| | | class mqtt_tempconv : public mosqpp::mosquittopp |
| | | { |
| | | public: |
| | | mqtt_tempconv(const char *id, const char *host, int port); |
| | | ~mqtt_tempconv(); |
| | | |
| | | void on_connect(int rc); |
| | | void on_message(const struct mosquitto_message *message); |
| | | void on_subscribe(int mid, int qos_count, const int *granted_qos); |
| | | }; |
| | | |
| | | #endif |
New file |
| | |
| | | ; NSIS installer script for mosquitto |
| | | |
| | | !include "MUI2.nsh" |
| | | !include "nsDialogs.nsh" |
| | | !include "LogicLib.nsh" |
| | | |
| | | ; For environment variable code |
| | | !include "WinMessages.nsh" |
| | | !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' |
| | | |
| | | Name "Eclipse Mosquitto" |
| | | !define VERSION 1.6.3 |
| | | OutFile "mosquitto-${VERSION}-install-windows-x86.exe" |
| | | |
| | | InstallDir "$PROGRAMFILES\mosquitto" |
| | | |
| | | ;-------------------------------- |
| | | ; Installer pages |
| | | !insertmacro MUI_PAGE_WELCOME |
| | | |
| | | !insertmacro MUI_PAGE_COMPONENTS |
| | | !insertmacro MUI_PAGE_DIRECTORY |
| | | !insertmacro MUI_PAGE_INSTFILES |
| | | !insertmacro MUI_PAGE_FINISH |
| | | |
| | | |
| | | ;-------------------------------- |
| | | ; Uninstaller pages |
| | | !insertmacro MUI_UNPAGE_WELCOME |
| | | !insertmacro MUI_UNPAGE_CONFIRM |
| | | !insertmacro MUI_UNPAGE_INSTFILES |
| | | !insertmacro MUI_UNPAGE_FINISH |
| | | |
| | | ;-------------------------------- |
| | | ; Languages |
| | | !insertmacro MUI_LANGUAGE "English" |
| | | |
| | | ;-------------------------------- |
| | | ; Installer sections |
| | | |
| | | Section "Files" SecInstall |
| | | SectionIn RO |
| | | SetOutPath "$INSTDIR" |
| | | File "..\build\src\Release\mosquitto.exe" |
| | | File "..\build\src\Release\mosquitto_passwd.exe" |
| | | File "..\build\client\Release\mosquitto_pub.exe" |
| | | File "..\build\client\Release\mosquitto_sub.exe" |
| | | File "..\build\lib\Release\mosquitto.dll" |
| | | File "..\build\lib\cpp\Release\mosquittopp.dll" |
| | | File "..\aclfile.example" |
| | | File "..\ChangeLog.txt" |
| | | File "..\mosquitto.conf" |
| | | File "..\pwfile.example" |
| | | File "..\readme.md" |
| | | File "..\readme-windows.txt" |
| | | ;File "C:\pthreads\Pre-built.2\dll\x86\pthreadVC2.dll" |
| | | File "C:\OpenSSL-Win32\bin\libssl-1_1.dll" |
| | | File "C:\OpenSSL-Win32\bin\libcrypto-1_1.dll" |
| | | File "..\edl-v10" |
| | | File "..\epl-v10" |
| | | |
| | | SetOutPath "$INSTDIR\devel" |
| | | File "..\lib\mosquitto.h" |
| | | File "..\build\lib\Release\mosquitto.lib" |
| | | File "..\lib\cpp\mosquittopp.h" |
| | | File "..\build\lib\cpp\Release\mosquittopp.lib" |
| | | File "..\src\mosquitto_plugin.h" |
| | | |
| | | WriteUninstaller "$INSTDIR\Uninstall.exe" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "DisplayName" "Eclipse Mosquitto MQTT broker" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "HelpLink" "https://mosquitto.org/" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "URLInfoAbout" "https://mosquitto.org/" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "DisplayVersion" "${VERSION}" |
| | | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "NoModify" "1" |
| | | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "NoRepair" "1" |
| | | |
| | | WriteRegExpandStr ${env_hklm} MOSQUITTO_DIR $INSTDIR |
| | | SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| | | SectionEnd |
| | | |
| | | Section "Service" SecService |
| | | ExecWait '"$INSTDIR\mosquitto.exe" install' |
| | | SectionEnd |
| | | |
| | | Section "Uninstall" |
| | | ExecWait '"$INSTDIR\mosquitto.exe" uninstall' |
| | | Delete "$INSTDIR\mosquitto.exe" |
| | | Delete "$INSTDIR\mosquitto_passwd.exe" |
| | | Delete "$INSTDIR\mosquitto_pub.exe" |
| | | Delete "$INSTDIR\mosquitto_sub.exe" |
| | | Delete "$INSTDIR\mosquitto.dll" |
| | | Delete "$INSTDIR\mosquittopp.dll" |
| | | Delete "$INSTDIR\aclfile.example" |
| | | Delete "$INSTDIR\ChangeLog.txt" |
| | | Delete "$INSTDIR\mosquitto.conf" |
| | | Delete "$INSTDIR\pwfile.example" |
| | | Delete "$INSTDIR\readme.txt" |
| | | Delete "$INSTDIR\readme-windows.txt" |
| | | ;Delete "$INSTDIR\pthreadVC2.dll" |
| | | Delete "$INSTDIR\libssl-1_1.dll" |
| | | Delete "$INSTDIR\libcrypto-1_1.dll" |
| | | Delete "$INSTDIR\edl-v10" |
| | | Delete "$INSTDIR\epl-v10" |
| | | |
| | | Delete "$INSTDIR\devel\mosquitto.h" |
| | | Delete "$INSTDIR\devel\mosquitto.lib" |
| | | Delete "$INSTDIR\devel\mosquittopp.h" |
| | | Delete "$INSTDIR\devel\mosquittopp.lib" |
| | | Delete "$INSTDIR\devel\mosquitto_plugin.h" |
| | | |
| | | Delete "$INSTDIR\Uninstall.exe" |
| | | RMDir "$INSTDIR" |
| | | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" |
| | | |
| | | DeleteRegValue ${env_hklm} MOSQUITTO_DIR |
| | | SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| | | SectionEnd |
| | | |
| | | LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." |
| | | LangString DESC_SecService ${LANG_ENGLISH} "Install mosquitto as a Windows service?" |
| | | |
| | | !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN |
| | | !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) |
| | | !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService) |
| | | !insertmacro MUI_FUNCTION_DESCRIPTION_END |
| | | |
New file |
| | |
| | | ; NSIS installer script for mosquitto |
| | | |
| | | !include "MUI2.nsh" |
| | | !include "nsDialogs.nsh" |
| | | !include "LogicLib.nsh" |
| | | |
| | | ; For environment variable code |
| | | !include "WinMessages.nsh" |
| | | !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' |
| | | |
| | | Name "Eclipse Mosquitto" |
| | | !define VERSION 1.6.3 |
| | | OutFile "mosquitto-${VERSION}-install-windows-x64.exe" |
| | | |
| | | !include "x64.nsh" |
| | | InstallDir "$PROGRAMFILES64\mosquitto" |
| | | |
| | | ;-------------------------------- |
| | | ; Installer pages |
| | | !insertmacro MUI_PAGE_WELCOME |
| | | |
| | | !insertmacro MUI_PAGE_COMPONENTS |
| | | !insertmacro MUI_PAGE_DIRECTORY |
| | | !insertmacro MUI_PAGE_INSTFILES |
| | | !insertmacro MUI_PAGE_FINISH |
| | | |
| | | |
| | | ;-------------------------------- |
| | | ; Uninstaller pages |
| | | !insertmacro MUI_UNPAGE_WELCOME |
| | | !insertmacro MUI_UNPAGE_CONFIRM |
| | | !insertmacro MUI_UNPAGE_INSTFILES |
| | | !insertmacro MUI_UNPAGE_FINISH |
| | | |
| | | ;-------------------------------- |
| | | ; Languages |
| | | !insertmacro MUI_LANGUAGE "English" |
| | | |
| | | ;-------------------------------- |
| | | ; Installer sections |
| | | |
| | | Section "Files" SecInstall |
| | | SectionIn RO |
| | | SetOutPath "$INSTDIR" |
| | | File "..\build64\src\Release\mosquitto.exe" |
| | | File "..\build64\src\Release\mosquitto_passwd.exe" |
| | | File "..\build64\client\Release\mosquitto_pub.exe" |
| | | File "..\build64\client\Release\mosquitto_sub.exe" |
| | | File "..\build64\lib\Release\mosquitto.dll" |
| | | File "..\build64\lib\cpp\Release\mosquittopp.dll" |
| | | File "..\aclfile.example" |
| | | File "..\ChangeLog.txt" |
| | | File "..\mosquitto.conf" |
| | | File "..\pwfile.example" |
| | | File "..\readme.md" |
| | | File "..\readme-windows.txt" |
| | | ;File "C:\pthreads\Pre-built.2\dll\x64\pthreadVC2.dll" |
| | | File "C:\OpenSSL-Win64\bin\libssl-1_1-x64.dll" |
| | | File "C:\OpenSSL-Win64\bin\libcrypto-1_1-x64.dll" |
| | | File "..\edl-v10" |
| | | File "..\epl-v10" |
| | | |
| | | SetOutPath "$INSTDIR\devel" |
| | | File "..\lib\mosquitto.h" |
| | | File "..\build64\lib\Release\mosquitto.lib" |
| | | File "..\lib\cpp\mosquittopp.h" |
| | | File "..\build64\lib\cpp\Release\mosquittopp.lib" |
| | | File "..\src\mosquitto_plugin.h" |
| | | |
| | | WriteUninstaller "$INSTDIR\Uninstall.exe" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "DisplayName" "Eclipse Mosquitto MQTT broker (64 bit)" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "HelpLink" "https://mosquitto.org/" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "URLInfoAbout" "https://mosquitto.org/" |
| | | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "DisplayVersion" "${VERSION}" |
| | | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "NoModify" "1" |
| | | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" "NoRepair" "1" |
| | | |
| | | WriteRegExpandStr ${env_hklm} MOSQUITTO_DIR $INSTDIR |
| | | SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| | | SectionEnd |
| | | |
| | | Section "Service" SecService |
| | | ExecWait '"$INSTDIR\mosquitto.exe" install' |
| | | SectionEnd |
| | | |
| | | Section "Uninstall" |
| | | ExecWait '"$INSTDIR\mosquitto.exe" uninstall' |
| | | Delete "$INSTDIR\mosquitto.exe" |
| | | Delete "$INSTDIR\mosquitto_passwd.exe" |
| | | Delete "$INSTDIR\mosquitto_pub.exe" |
| | | Delete "$INSTDIR\mosquitto_sub.exe" |
| | | Delete "$INSTDIR\mosquitto.dll" |
| | | Delete "$INSTDIR\mosquittopp.dll" |
| | | Delete "$INSTDIR\aclfile.example" |
| | | Delete "$INSTDIR\ChangeLog.txt" |
| | | Delete "$INSTDIR\mosquitto.conf" |
| | | Delete "$INSTDIR\pwfile.example" |
| | | Delete "$INSTDIR\readme.txt" |
| | | Delete "$INSTDIR\readme-windows.txt" |
| | | ;Delete "$INSTDIR\pthreadVC2.dll" |
| | | Delete "$INSTDIR\libssl-1_1-x64.dll" |
| | | Delete "$INSTDIR\libcrypto-1_1-x64.dll" |
| | | Delete "$INSTDIR\edl-v10" |
| | | Delete "$INSTDIR\epl-v10" |
| | | |
| | | Delete "$INSTDIR\devel\mosquitto.h" |
| | | Delete "$INSTDIR\devel\mosquitto.lib" |
| | | Delete "$INSTDIR\devel\mosquittopp.h" |
| | | Delete "$INSTDIR\devel\mosquittopp.lib" |
| | | Delete "$INSTDIR\devel\mosquitto_plugin.h" |
| | | |
| | | Delete "$INSTDIR\Uninstall.exe" |
| | | RMDir "$INSTDIR" |
| | | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto64" |
| | | |
| | | DeleteRegValue ${env_hklm} MOSQUITTO_DIR |
| | | SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| | | SectionEnd |
| | | |
| | | LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." |
| | | LangString DESC_SecService ${LANG_ENGLISH} "Install mosquitto as a Windows service?" |
| | | |
| | | !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN |
| | | !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) |
| | | !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService) |
| | | !insertmacro MUI_FUNCTION_DESCRIPTION_END |
| | | |
New file |
| | |
| | | option(WITH_STATIC_LIBRARIES "Build static versions of the libmosquitto/pp libraries?" OFF) |
| | | option(WITH_PIC "Build the static library with PIC (Position Independent Code) enabled archives?" OFF) |
| | | add_subdirectory(cpp) |
| | | |
| | | include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib |
| | | ${mosquitto_SOURCE_DIR}/src/deps |
| | | ${STDBOOL_H_PATH} ${STDINT_H_PATH} |
| | | ${OPENSSL_INCLUDE_DIR} ${PTHREAD_INCLUDE_DIR}) |
| | | link_directories(${mosquitto_SOURCE_DIR}/lib) |
| | | |
| | | set(C_SRC |
| | | actions.c |
| | | callbacks.c |
| | | connect.c |
| | | handle_auth.c |
| | | handle_connack.c |
| | | handle_disconnect.c |
| | | handle_ping.c |
| | | handle_pubackcomp.c |
| | | handle_publish.c |
| | | handle_pubrec.c |
| | | handle_pubrel.c |
| | | handle_suback.c |
| | | handle_unsuback.c |
| | | helpers.c |
| | | logging_mosq.c logging_mosq.h |
| | | loop.c |
| | | memory_mosq.c memory_mosq.h |
| | | messages_mosq.c messages_mosq.h |
| | | mosquitto.c mosquitto.h |
| | | mosquitto_internal.h |
| | | mqtt_protocol.h |
| | | net_mosq_ocsp.c net_mosq.c net_mosq.h |
| | | options.c |
| | | packet_datatypes.c |
| | | packet_mosq.c packet_mosq.h |
| | | property_mosq.c property_mosq.h |
| | | read_handle.c read_handle.h |
| | | send_connect.c |
| | | send_disconnect.c |
| | | send_mosq.c |
| | | send_publish.c |
| | | send_subscribe.c |
| | | send_unsubscribe.c |
| | | send_mosq.c send_mosq.h |
| | | socks_mosq.c |
| | | srv_mosq.c |
| | | thread_mosq.c |
| | | time_mosq.c |
| | | tls_mosq.c |
| | | utf8_mosq.c |
| | | util_mosq.c util_topic.c util_mosq.h |
| | | will_mosq.c will_mosq.h) |
| | | |
| | | set (LIBRARIES ${OPENSSL_LIBRARIES} ${PTHREAD_LIBRARIES}) |
| | | |
| | | if (UNIX AND NOT APPLE) |
| | | find_library(LIBRT rt) |
| | | if (LIBRT) |
| | | set (LIBRARIES ${LIBRARIES} rt) |
| | | endif (LIBRT) |
| | | endif (UNIX AND NOT APPLE) |
| | | |
| | | if (WIN32) |
| | | set (LIBRARIES ${LIBRARIES} ws2_32) |
| | | endif (WIN32) |
| | | |
| | | if (WITH_SRV) |
| | | # Simple detect c-ares |
| | | find_path(ARES_HEADER ares.h) |
| | | if (ARES_HEADER) |
| | | add_definitions("-DWITH_SRV") |
| | | set (LIBRARIES ${LIBRARIES} cares) |
| | | else (ARES_HEADER) |
| | | message(WARNING "c-ares library not found.") |
| | | endif (ARES_HEADER) |
| | | endif (WITH_SRV) |
| | | |
| | | add_library(libmosquitto SHARED ${C_SRC}) |
| | | set_target_properties(libmosquitto PROPERTIES |
| | | POSITION_INDEPENDENT_CODE 1 |
| | | ) |
| | | |
| | | target_link_libraries(libmosquitto ${LIBRARIES}) |
| | | |
| | | set_target_properties(libmosquitto PROPERTIES |
| | | OUTPUT_NAME mosquitto |
| | | VERSION ${VERSION} |
| | | SOVERSION 1 |
| | | ) |
| | | |
| | | install(TARGETS libmosquitto RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") |
| | | |
| | | if (WITH_STATIC_LIBRARIES) |
| | | add_library(libmosquitto_static STATIC ${C_SRC}) |
| | | if (WITH_PIC) |
| | | set_target_properties(libmosquitto_static PROPERTIES |
| | | POSITION_INDEPENDENT_CODE 1 |
| | | ) |
| | | endif (WITH_PIC) |
| | | |
| | | target_link_libraries(libmosquitto_static ${LIBRARIES}) |
| | | |
| | | set_target_properties(libmosquitto_static PROPERTIES |
| | | OUTPUT_NAME mosquitto |
| | | VERSION ${VERSION} |
| | | ) |
| | | |
| | | target_compile_definitions(libmosquitto_static PUBLIC "LIBMOSQUITTO_STATIC") |
| | | install(TARGETS libmosquitto_static ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") |
| | | endif (WITH_STATIC_LIBRARIES) |
| | | |
| | | install(FILES mosquitto.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") |
New file |
| | |
| | | include ../config.mk |
| | | |
| | | .PHONY : really clean install |
| | | |
| | | MOSQ_OBJS=mosquitto.o \ |
| | | actions.o \ |
| | | callbacks.o \ |
| | | connect.o \ |
| | | handle_auth.o \ |
| | | handle_connack.o \ |
| | | handle_disconnect.o \ |
| | | handle_ping.o \ |
| | | handle_pubackcomp.o \ |
| | | handle_publish.o \ |
| | | handle_pubrec.o \ |
| | | handle_pubrel.o \ |
| | | handle_suback.o \ |
| | | handle_unsuback.o \ |
| | | helpers.o \ |
| | | logging_mosq.o \ |
| | | loop.o \ |
| | | memory_mosq.o \ |
| | | messages_mosq.o \ |
| | | net_mosq_ocsp.o \ |
| | | net_mosq.o \ |
| | | options.o \ |
| | | packet_datatypes.o \ |
| | | packet_mosq.o \ |
| | | property_mosq.o \ |
| | | read_handle.o \ |
| | | send_connect.o \ |
| | | send_disconnect.o \ |
| | | send_mosq.o \ |
| | | send_publish.o \ |
| | | send_subscribe.o \ |
| | | send_unsubscribe.o \ |
| | | socks_mosq.o \ |
| | | srv_mosq.o \ |
| | | thread_mosq.o \ |
| | | time_mosq.o \ |
| | | tls_mosq.o \ |
| | | utf8_mosq.o \ |
| | | util_mosq.o \ |
| | | util_topic.o \ |
| | | will_mosq.o |
| | | |
| | | ALL_DEPS:= |
| | | |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | ALL_DEPS+=libmosquitto.so.${SOVERSION} |
| | | endif |
| | | |
| | | ifeq ($(WITH_STATIC_LIBRARIES),yes) |
| | | ALL_DEPS+=libmosquitto.a |
| | | endif |
| | | |
| | | all : ${ALL_DEPS} |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | $(MAKE) -C cpp |
| | | endif |
| | | |
| | | install : all |
| | | $(INSTALL) -d "${DESTDIR}${libdir}/" |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | $(INSTALL) ${STRIP_OPTS} libmosquitto.so.${SOVERSION} "${DESTDIR}${libdir}/libmosquitto.so.${SOVERSION}" |
| | | ln -sf libmosquitto.so.${SOVERSION} "${DESTDIR}${libdir}/libmosquitto.so" |
| | | endif |
| | | ifeq ($(WITH_STATIC_LIBRARIES),yes) |
| | | $(INSTALL) ${STRIP_OPTS} libmosquitto.a "${DESTDIR}${libdir}/libmosquitto.a" |
| | | endif |
| | | $(INSTALL) -d "${DESTDIR}${incdir}/" |
| | | $(INSTALL) mosquitto.h "${DESTDIR}${incdir}/mosquitto.h" |
| | | $(INSTALL) -d "${DESTDIR}${libdir}/pkgconfig" |
| | | $(INSTALL) -m644 ../libmosquitto.pc.in "${DESTDIR}${libdir}/pkgconfig/libmosquitto.pc" |
| | | sed -i -e "s#@CMAKE_INSTALL_PREFIX@#${prefix}#" -e "s#@VERSION@#${VERSION}#" "${DESTDIR}${libdir}/pkgconfig/libmosquitto.pc" |
| | | ifeq ($(WITH_SHARED_LIBRARIES),yes) |
| | | $(MAKE) -C cpp install |
| | | endif |
| | | |
| | | uninstall : |
| | | -rm -f "${DESTDIR}${libdir}/libmosquitto.so.${SOVERSION}" |
| | | -rm -f "${DESTDIR}${libdir}/libmosquitto.so" |
| | | -rm -f "${DESTDIR}${libdir}/libmosquitto.a" |
| | | -rm -f "${DESTDIR}${incdir}/mosquitto.h" |
| | | |
| | | reallyclean : clean |
| | | |
| | | clean : |
| | | -rm -f *.o libmosquitto.so.${SOVERSION} libmosquitto.so libmosquitto.a *.gcno *.gcda |
| | | $(MAKE) -C cpp clean |
| | | |
| | | libmosquitto.so.${SOVERSION} : ${MOSQ_OBJS} |
| | | ${CROSS_COMPILE}$(CC) -shared $(LIB_LDFLAGS) $^ -o $@ ${LIB_LIBADD} |
| | | |
| | | libmosquitto.a : ${MOSQ_OBJS} |
| | | ${CROSS_COMPILE}$(AR) cr $@ $^ |
| | | |
| | | mosquitto.o : mosquitto.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | actions.o : actions.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | callbacks.o : callbacks.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | connect.o : connect.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_auth.o : handle_auth.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_connack.o : handle_connack.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_disconnect.o : handle_disconnect.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_publish.o : handle_publish.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_ping.o : handle_ping.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_pubackcomp.o : handle_pubackcomp.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_pubrec.o : handle_pubrec.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_pubrel.o : handle_pubrel.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_suback.o : handle_suback.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | handle_unsuback.o : handle_unsuback.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | helpers.o : helpers.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | logging_mosq.o : logging_mosq.c logging_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | loop.o : loop.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | messages_mosq.o : messages_mosq.c messages_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | memory_mosq.o : memory_mosq.c memory_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | net_mosq_ocsp.o : net_mosq_ocsp.c net_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | net_mosq.o : net_mosq.c net_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | options.o : options.c mosquitto.h mosquitto_internal.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | packet_datatypes.o : packet_datatypes.c packet_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | packet_mosq.o : packet_mosq.c packet_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | property_mosq.o : property_mosq.c property_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | read_handle.o : read_handle.c read_handle.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_connect.o : send_connect.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_disconnect.o : send_disconnect.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_mosq.o : send_mosq.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_publish.o : send_publish.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_subscribe.o : send_subscribe.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | send_unsubscribe.o : send_unsubscribe.c send_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | socks_mosq.o : socks_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | srv_mosq.o : srv_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | thread_mosq.o : thread_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | time_mosq.o : time_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | tls_mosq.o : tls_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | utf8_mosq.o : utf8_mosq.c |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | util_mosq.o : util_mosq.c util_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | util_topic.o : util_topic.c util_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
| | | will_mosq.o : will_mosq.c will_mosq.h |
| | | ${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) -c $< -o $@ |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include <string.h> |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | |
| | | int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) |
| | | { |
| | | return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, NULL); |
| | | } |
| | | |
| | | int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain, const mosquitto_property *properties) |
| | | { |
| | | struct mosquitto_message_all *message; |
| | | uint16_t local_mid; |
| | | const mosquitto_property *p; |
| | | const mosquitto_property *outgoing_properties = NULL; |
| | | mosquitto_property local_property; |
| | | bool have_topic_alias; |
| | | int rc; |
| | | int tlen = 0; |
| | | uint32_t remaining_length; |
| | | |
| | | if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; |
| | | if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; |
| | | if(qos > mosq->maximum_qos) return MOSQ_ERR_QOS_NOT_SUPPORTED; |
| | | |
| | | if(properties){ |
| | | if(properties->client_generated){ |
| | | outgoing_properties = properties; |
| | | }else{ |
| | | memcpy(&local_property, properties, sizeof(mosquitto_property)); |
| | | local_property.client_generated = true; |
| | | local_property.next = NULL; |
| | | outgoing_properties = &local_property; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_PUBLISH, outgoing_properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | if(!topic || STREMPTY(topic)){ |
| | | if(topic) topic = NULL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | p = outgoing_properties; |
| | | have_topic_alias = false; |
| | | while(p){ |
| | | if(p->identifier == MQTT_PROP_TOPIC_ALIAS){ |
| | | have_topic_alias = true; |
| | | break; |
| | | } |
| | | p = p->next; |
| | | } |
| | | if(have_topic_alias == false){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | }else{ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | }else{ |
| | | tlen = strlen(topic); |
| | | if(mosquitto_validate_utf8(topic, tlen)) return MOSQ_ERR_MALFORMED_UTF8; |
| | | if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; |
| | | if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | } |
| | | |
| | | if(mosq->maximum_packet_size > 0){ |
| | | remaining_length = 1 + 2+tlen + payloadlen + property__get_length_all(outgoing_properties); |
| | | if(qos > 0){ |
| | | remaining_length++; |
| | | } |
| | | if(packet__check_oversize(mosq, remaining_length)){ |
| | | return MOSQ_ERR_OVERSIZE_PACKET; |
| | | } |
| | | } |
| | | |
| | | local_mid = mosquitto__mid_generate(mosq); |
| | | if(mid){ |
| | | *mid = local_mid; |
| | | } |
| | | |
| | | if(qos == 0){ |
| | | return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL, 0); |
| | | }else{ |
| | | message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); |
| | | if(!message) return MOSQ_ERR_NOMEM; |
| | | |
| | | message->next = NULL; |
| | | message->timestamp = mosquitto_time(); |
| | | message->msg.mid = local_mid; |
| | | if(topic){ |
| | | message->msg.topic = mosquitto__strdup(topic); |
| | | if(!message->msg.topic){ |
| | | message__cleanup(&message); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | } |
| | | if(payloadlen){ |
| | | message->msg.payloadlen = payloadlen; |
| | | message->msg.payload = mosquitto__malloc(payloadlen*sizeof(uint8_t)); |
| | | if(!message->msg.payload){ |
| | | message__cleanup(&message); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t)); |
| | | }else{ |
| | | message->msg.payloadlen = 0; |
| | | message->msg.payload = NULL; |
| | | } |
| | | message->msg.qos = qos; |
| | | message->msg.retain = retain; |
| | | message->dup = false; |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | message->state = mosq_ms_invalid; |
| | | message__queue(mosq, message, mosq_md_out); |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | } |
| | | |
| | | |
| | | int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos) |
| | | { |
| | | return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, 0, NULL); |
| | | } |
| | | |
| | | |
| | | int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties) |
| | | { |
| | | return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, options, properties); |
| | | } |
| | | |
| | | |
| | | int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties) |
| | | { |
| | | const mosquitto_property *outgoing_properties = NULL; |
| | | mosquitto_property local_property; |
| | | int i; |
| | | int rc; |
| | | uint32_t remaining_length = 0; |
| | | int slen; |
| | | |
| | | if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL; |
| | | if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; |
| | | if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL; |
| | | if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL; |
| | | if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; |
| | | |
| | | if(properties){ |
| | | if(properties->client_generated){ |
| | | outgoing_properties = properties; |
| | | }else{ |
| | | memcpy(&local_property, properties, sizeof(mosquitto_property)); |
| | | local_property.client_generated = true; |
| | | local_property.next = NULL; |
| | | outgoing_properties = &local_property; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | for(i=0; i<sub_count; i++){ |
| | | if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL; |
| | | slen = strlen(sub[i]); |
| | | if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8; |
| | | remaining_length += 2+slen + 1; |
| | | } |
| | | |
| | | if(mosq->maximum_packet_size > 0){ |
| | | remaining_length += 2 + property__get_length_all(outgoing_properties); |
| | | if(packet__check_oversize(mosq, remaining_length)){ |
| | | return MOSQ_ERR_OVERSIZE_PACKET; |
| | | } |
| | | } |
| | | |
| | | return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties); |
| | | } |
| | | |
| | | |
| | | int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub) |
| | | { |
| | | return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, NULL); |
| | | } |
| | | |
| | | int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties) |
| | | { |
| | | return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, properties); |
| | | } |
| | | |
| | | int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties) |
| | | { |
| | | const mosquitto_property *outgoing_properties = NULL; |
| | | mosquitto_property local_property; |
| | | int rc; |
| | | int i; |
| | | uint32_t remaining_length = 0; |
| | | int slen; |
| | | |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; |
| | | if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; |
| | | |
| | | if(properties){ |
| | | if(properties->client_generated){ |
| | | outgoing_properties = properties; |
| | | }else{ |
| | | memcpy(&local_property, properties, sizeof(mosquitto_property)); |
| | | local_property.client_generated = true; |
| | | local_property.next = NULL; |
| | | outgoing_properties = &local_property; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, outgoing_properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | for(i=0; i<sub_count; i++){ |
| | | if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL; |
| | | slen = strlen(sub[i]); |
| | | if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8; |
| | | remaining_length += 2+slen; |
| | | } |
| | | |
| | | if(mosq->maximum_packet_size > 0){ |
| | | remaining_length += 2 + property__get_length_all(outgoing_properties); |
| | | if(packet__check_oversize(mosq, remaining_length)){ |
| | | return MOSQ_ERR_OVERSIZE_PACKET; |
| | | } |
| | | } |
| | | |
| | | return send__unsubscribe(mosq, mid, sub_count, sub, outgoing_properties); |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2019 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 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 "config.h" |
| | | |
| | | #include "mosquitto.h" |
| | | #include "alias_mosq.h" |
| | | #include "memory_mosq.h" |
| | | |
| | | int alias__add(struct mosquitto *mosq, const char *topic, int alias) |
| | | { |
| | | int i; |
| | | struct mosquitto__alias *aliases; |
| | | |
| | | for(i=0; i<mosq->alias_count; i++){ |
| | | if(mosq->aliases[i].alias == alias){ |
| | | mosquitto__free(mosq->aliases[i].topic); |
| | | mosq->aliases[i].topic = mosquitto__strdup(topic); |
| | | if(mosq->aliases[i].topic){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* New alias */ |
| | | aliases = mosquitto__realloc(mosq->aliases, sizeof(struct mosquitto__alias)*(mosq->alias_count+1)); |
| | | if(!aliases) return MOSQ_ERR_NOMEM; |
| | | |
| | | mosq->aliases = aliases; |
| | | mosq->aliases[mosq->alias_count].alias = alias; |
| | | mosq->aliases[mosq->alias_count].topic = mosquitto__strdup(topic); |
| | | if(!mosq->aliases[mosq->alias_count].topic){ |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | mosq->alias_count++; |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | |
| | | int alias__find(struct mosquitto *mosq, char **topic, int alias) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<mosq->alias_count; i++){ |
| | | if(mosq->aliases[i].alias == alias){ |
| | | *topic = mosquitto__strdup(mosq->aliases[i].topic); |
| | | if(*topic){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | } |
| | | } |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | |
| | | void alias__free_all(struct mosquitto *mosq) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<mosq->alias_count; i++){ |
| | | mosquitto__free(mosq->aliases[i].topic); |
| | | } |
| | | mosquitto__free(mosq->aliases); |
| | | mosq->aliases = NULL; |
| | | mosq->alias_count = 0; |
| | | } |
New file |
| | |
| | | /* |
| | | Copyright (c) 2019 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 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 ALIAS_MOSQ_H |
| | | #define ALIAS_MOSQ_H |
| | | |
| | | #include "mosquitto_internal.h" |
| | | |
| | | int alias__add(struct mosquitto *mosq, const char *topic, int alias); |
| | | int alias__find(struct mosquitto *mosq, char **topic, int alias); |
| | | void alias__free_all(struct mosquitto *mosq); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | |
| | | |
| | | void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_connect = on_connect; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_connect_with_flags = on_connect; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_connect_v5 = on_connect; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_disconnect = on_disconnect; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_disconnect_v5 = on_disconnect; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_publish = on_publish; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *props)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_publish_v5 = on_publish; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_message = on_message; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *props)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_message_v5 = on_message; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_subscribe = on_subscribe; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *props)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_subscribe_v5 = on_subscribe; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_unsubscribe = on_unsubscribe; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *props)) |
| | | { |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | mosq->on_unsubscribe_v5 = on_unsubscribe; |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | |
| | | void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)) |
| | | { |
| | | pthread_mutex_lock(&mosq->log_callback_mutex); |
| | | mosq->on_log = on_log; |
| | | pthread_mutex_unlock(&mosq->log_callback_mutex); |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include <string.h> |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "logging_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "send_mosq.h" |
| | | #include "socks_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | static char alphanum[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; |
| | | |
| | | static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties); |
| | | static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); |
| | | |
| | | |
| | | static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) |
| | | { |
| | | int i; |
| | | int rc; |
| | | |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | if(!host || port <= 0) return MOSQ_ERR_INVAL; |
| | | |
| | | if(mosq->id == NULL && (mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311)){ |
| | | mosq->id = (char *)mosquitto__calloc(24, sizeof(char)); |
| | | if(!mosq->id){ |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | mosq->id[0] = 'm'; |
| | | mosq->id[1] = 'o'; |
| | | mosq->id[2] = 's'; |
| | | mosq->id[3] = 'q'; |
| | | mosq->id[4] = '/'; |
| | | |
| | | rc = util__random_bytes(&mosq->id[5], 18); |
| | | if(rc) return rc; |
| | | |
| | | for(i=5; i<23; i++){ |
| | | mosq->id[i] = alphanum[(mosq->id[i]&0x7F)%(sizeof(alphanum)-1)]; |
| | | } |
| | | } |
| | | |
| | | mosquitto__free(mosq->host); |
| | | mosq->host = mosquitto__strdup(host); |
| | | if(!mosq->host) return MOSQ_ERR_NOMEM; |
| | | mosq->port = port; |
| | | |
| | | mosquitto__free(mosq->bind_address); |
| | | if(bind_address){ |
| | | mosq->bind_address = mosquitto__strdup(bind_address); |
| | | if(!mosq->bind_address) return MOSQ_ERR_NOMEM; |
| | | } |
| | | |
| | | mosq->keepalive = keepalive; |
| | | mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum; |
| | | mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; |
| | | |
| | | if(mosq->sockpairR != INVALID_SOCKET){ |
| | | COMPAT_CLOSE(mosq->sockpairR); |
| | | mosq->sockpairR = INVALID_SOCKET; |
| | | } |
| | | if(mosq->sockpairW != INVALID_SOCKET){ |
| | | COMPAT_CLOSE(mosq->sockpairW); |
| | | mosq->sockpairW = INVALID_SOCKET; |
| | | } |
| | | |
| | | if(net__socketpair(&mosq->sockpairR, &mosq->sockpairW)){ |
| | | log__printf(mosq, MOSQ_LOG_WARNING, |
| | | "Warning: Unable to open socket pair, outgoing publish commands may be delayed."); |
| | | } |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | |
| | | int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive) |
| | | { |
| | | return mosquitto_connect_bind(mosq, host, port, keepalive, NULL); |
| | | } |
| | | |
| | | |
| | | int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) |
| | | { |
| | | return mosquitto_connect_bind_v5(mosq, host, port, keepalive, bind_address, NULL); |
| | | } |
| | | |
| | | int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties) |
| | | { |
| | | int rc; |
| | | |
| | | if(properties){ |
| | | rc = mosquitto_property_check_all(CMD_CONNECT, properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address); |
| | | if(rc) return rc; |
| | | |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | mosq->state = mosq_cs_new; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | return mosquitto__reconnect(mosq, true, properties); |
| | | } |
| | | |
| | | |
| | | int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive) |
| | | { |
| | | return mosquitto_connect_bind_async(mosq, host, port, keepalive, NULL); |
| | | } |
| | | |
| | | |
| | | int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) |
| | | { |
| | | int rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address); |
| | | if(rc) return rc; |
| | | |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | mosq->state = mosq_cs_connect_async; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | return mosquitto__reconnect(mosq, false, NULL); |
| | | } |
| | | |
| | | |
| | | int mosquitto_reconnect_async(struct mosquitto *mosq) |
| | | { |
| | | return mosquitto__reconnect(mosq, false, NULL); |
| | | } |
| | | |
| | | |
| | | int mosquitto_reconnect(struct mosquitto *mosq) |
| | | { |
| | | return mosquitto__reconnect(mosq, true, NULL); |
| | | } |
| | | |
| | | |
| | | static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties) |
| | | { |
| | | const mosquitto_property *outgoing_properties = NULL; |
| | | mosquitto_property local_property; |
| | | int rc; |
| | | struct mosquitto__packet *packet; |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; |
| | | if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; |
| | | |
| | | if(properties){ |
| | | if(properties->client_generated){ |
| | | outgoing_properties = properties; |
| | | }else{ |
| | | memcpy(&local_property, properties, sizeof(mosquitto_property)); |
| | | local_property.client_generated = true; |
| | | local_property.next = NULL; |
| | | outgoing_properties = &local_property; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_CONNECT, outgoing_properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | #ifdef WITH_SOCKS |
| | | if(mosq->socks5_host){ |
| | | mosq->state = mosq_cs_socks5_new; |
| | | }else |
| | | #endif |
| | | { |
| | | mosq->state = mosq_cs_new; |
| | | } |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | pthread_mutex_lock(&mosq->msgtime_mutex); |
| | | mosq->last_msg_in = mosquitto_time(); |
| | | mosq->next_msg_out = mosq->last_msg_in + mosq->keepalive; |
| | | pthread_mutex_unlock(&mosq->msgtime_mutex); |
| | | |
| | | mosq->ping_t = 0; |
| | | |
| | | packet__cleanup(&mosq->in_packet); |
| | | |
| | | pthread_mutex_lock(&mosq->current_out_packet_mutex); |
| | | pthread_mutex_lock(&mosq->out_packet_mutex); |
| | | |
| | | if(mosq->out_packet && !mosq->current_out_packet){ |
| | | mosq->current_out_packet = mosq->out_packet; |
| | | mosq->out_packet = mosq->out_packet->next; |
| | | } |
| | | |
| | | while(mosq->current_out_packet){ |
| | | packet = mosq->current_out_packet; |
| | | /* Free data and reset values */ |
| | | mosq->current_out_packet = mosq->out_packet; |
| | | if(mosq->out_packet){ |
| | | mosq->out_packet = mosq->out_packet->next; |
| | | } |
| | | |
| | | packet__cleanup(packet); |
| | | mosquitto__free(packet); |
| | | } |
| | | pthread_mutex_unlock(&mosq->out_packet_mutex); |
| | | pthread_mutex_unlock(&mosq->current_out_packet_mutex); |
| | | |
| | | message__reconnect_reset(mosq); |
| | | |
| | | if(mosq->sock != INVALID_SOCKET){ |
| | | net__socket_close(mosq); //close socket |
| | | } |
| | | |
| | | #ifdef WITH_SOCKS |
| | | if(mosq->socks5_host){ |
| | | rc = net__socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking); |
| | | }else |
| | | #endif |
| | | { |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | mosq->state = mosq_cs_connecting; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | rc = net__socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking); |
| | | } |
| | | if(rc>0){ |
| | | return rc; |
| | | } |
| | | |
| | | #ifdef WITH_SOCKS |
| | | if(mosq->socks5_host){ |
| | | return socks5__send(mosq); |
| | | }else |
| | | #endif |
| | | { |
| | | return send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties); |
| | | } |
| | | } |
| | | |
| | | |
| | | int mosquitto_disconnect(struct mosquitto *mosq) |
| | | { |
| | | return mosquitto_disconnect_v5(mosq, 0, NULL); |
| | | } |
| | | |
| | | int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties) |
| | | { |
| | | const mosquitto_property *outgoing_properties = NULL; |
| | | mosquitto_property local_property; |
| | | int rc; |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; |
| | | |
| | | if(properties){ |
| | | if(properties->client_generated){ |
| | | outgoing_properties = properties; |
| | | }else{ |
| | | memcpy(&local_property, properties, sizeof(mosquitto_property)); |
| | | local_property.client_generated = true; |
| | | local_property.next = NULL; |
| | | outgoing_properties = &local_property; |
| | | } |
| | | rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | mosq->state = mosq_cs_disconnecting; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; |
| | | return send__disconnect(mosq, reason_code, outgoing_properties); |
| | | } |
| | | |
| | | |
| | | void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties) |
| | | { |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | mosq->state = mosq_cs_disconnecting; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | net__socket_close(mosq); |
| | | |
| | | /* Free data and reset values */ |
| | | pthread_mutex_lock(&mosq->out_packet_mutex); |
| | | mosq->current_out_packet = mosq->out_packet; |
| | | if(mosq->out_packet){ |
| | | mosq->out_packet = mosq->out_packet->next; |
| | | if(!mosq->out_packet){ |
| | | mosq->out_packet_last = NULL; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mosq->out_packet_mutex); |
| | | |
| | | pthread_mutex_lock(&mosq->msgtime_mutex); |
| | | mosq->next_msg_out = mosquitto_time() + mosq->keepalive; |
| | | pthread_mutex_unlock(&mosq->msgtime_mutex); |
| | | |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_disconnect){ |
| | | mosq->in_callback = true; |
| | | mosq->on_disconnect(mosq, mosq->userdata, reason_code); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_disconnect_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | pthread_mutex_unlock(&mosq->current_out_packet_mutex); |
| | | } |
| | | |
New file |
| | |
| | | include_directories(${mosquitto_SOURCE_DIR}/lib ${mosquitto_SOURCE_DIR}/lib/cpp |
| | | ${STDBOOL_H_PATH} ${STDINT_H_PATH}) |
| | | link_directories(${mosquitto_BINARY_DIR}/lib) |
| | | |
| | | set(CPP_SRC mosquittopp.cpp mosquittopp.h) |
| | | |
| | | add_library(mosquittopp SHARED ${CPP_SRC}) |
| | | set_target_properties(mosquittopp PROPERTIES |
| | | POSITION_INDEPENDENT_CODE 1 |
| | | ) |
| | | target_link_libraries(mosquittopp libmosquitto) |
| | | set_target_properties(mosquittopp PROPERTIES |
| | | VERSION ${VERSION} |
| | | SOVERSION 1 |
| | | ) |
| | | install(TARGETS mosquittopp RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") |
| | | |
| | | if (WITH_STATIC_LIBRARIES) |
| | | add_library(mosquittopp_static STATIC |
| | | ${C_SRC} |
| | | ${CPP_SRC} |
| | | ) |
| | | if (WITH_PIC) |
| | | set_target_properties(mosquittopp_static PROPERTIES |
| | | POSITION_INDEPENDENT_CODE 1 |
| | | ) |
| | | endif (WITH_PIC) |
| | | |
| | | target_link_libraries(mosquittopp_static ${LIBRARIES}) |
| | | |
| | | set_target_properties(mosquittopp_static PROPERTIES |
| | | OUTPUT_NAME mosquittopp |
| | | VERSION ${VERSION} |
| | | ) |
| | | |
| | | target_compile_definitions(mosquittopp_static PUBLIC "LIBMOSQUITTO_STATIC") |
| | | install(TARGETS mosquittopp_static ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") |
| | | endif (WITH_STATIC_LIBRARIES) |
| | | |
| | | install(FILES mosquittopp.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") |
New file |
| | |
| | | include ../../config.mk |
| | | |
| | | ifneq ($(UNAME),SunOS) |
| | | LIB_LDFLAGS:=$(LDFLAGS) -Wl,-soname,libmosquittopp.so.${SOVERSION} |
| | | endif |
| | | |
| | | .PHONY : clean install |
| | | |
| | | ALL_DEPS=libmosquittopp.so.${SOVERSION} |
| | | |
| | | ifeq ($(WITH_STATIC_LIBRARIES),yes) |
| | | ALL_DEPS+=libmosquittopp.a |
| | | endif |
| | | |
| | | all : ${ALL_DEPS} |
| | | |
| | | install : all |
| | | $(INSTALL) -d "${DESTDIR}${libdir}/" |
| | | $(INSTALL) ${STRIP_OPTS} libmosquittopp.so.${SOVERSION} "${DESTDIR}${libdir}/libmosquittopp.so.${SOVERSION}" |
| | | ln -sf libmosquittopp.so.${SOVERSION} "${DESTDIR}${libdir}/libmosquittopp.so" |
| | | ifeq ($(WITH_STATIC_LIBRARIES),yes) |
| | | $(INSTALL) libmosquittopp.a "${DESTDIR}${libdir}/libmosquittopp.a" |
| | | ${CROSS_COMPILE}${STRIP} -g --strip-unneeded "${DESTDIR}${libdir}/libmosquittopp.a" |
| | | endif |
| | | $(INSTALL) -d "${DESTDIR}${incdir}/" |
| | | $(INSTALL) mosquittopp.h "${DESTDIR}${incdir}/mosquittopp.h" |
| | | $(INSTALL) -d "${DESTDIR}${libdir}/pkgconfig/" |
| | | $(INSTALL) -m644 ../../libmosquittopp.pc.in "${DESTDIR}${libdir}/pkgconfig/libmosquittopp.pc" |
| | | sed -i -e "s#@CMAKE_INSTALL_PREFIX@#${prefix}#" -e "s#@VERSION@#${VERSION}#" "${DESTDIR}${libdir}/pkgconfig/libmosquittopp.pc" |
| | | |
| | | uninstall : |
| | | -rm -f "${DESTDIR}${libdir}/libmosquittopp.so.${SOVERSION}" |
| | | -rm -f "${DESTDIR}${libdir}/libmosquittopp.so" |
| | | -rm -f "${DESTDIR}${libdir}/libmosquittopp.a" |
| | | -rm -f "${DESTDIR}${incdir}/mosquittopp.h" |
| | | |
| | | clean : |
| | | -rm -f *.o libmosquittopp.so.${SOVERSION} libmosquittopp.a |
| | | |
| | | libmosquittopp.so.${SOVERSION} : mosquittopp.o |
| | | ${CROSS_COMPILE}$(CXX) -shared $(LIB_LDFLAGS) $< -o $@ ../libmosquitto.so.${SOVERSION} $(LIB_LIDADD) |
| | | |
| | | libmosquittopp.a : mosquittopp.o |
| | | ${CROSS_COMPILE}$(AR) cr $@ $^ |
| | | |
| | | mosquittopp.o : mosquittopp.cpp mosquittopp.h |
| | | ${CROSS_COMPILE}$(CXX) $(LIB_CPPFLAGS) $(LIB_CXXFLAGS) -c $< -o $@ |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 <cstdlib> |
| | | #include <mosquitto.h> |
| | | #include <mosquittopp.h> |
| | | |
| | | #define UNUSED(A) (void)(A) |
| | | |
| | | namespace mosqpp { |
| | | |
| | | static void on_connect_wrapper(struct mosquitto *mosq, void *userdata, int rc) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | |
| | | UNUSED(mosq); |
| | | |
| | | m->on_connect(rc); |
| | | } |
| | | |
| | | static void on_connect_with_flags_wrapper(struct mosquitto *mosq, void *userdata, int rc, int flags) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_connect_with_flags(rc, flags); |
| | | } |
| | | |
| | | static void on_disconnect_wrapper(struct mosquitto *mosq, void *userdata, int rc) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_disconnect(rc); |
| | | } |
| | | |
| | | static void on_publish_wrapper(struct mosquitto *mosq, void *userdata, int mid) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_publish(mid); |
| | | } |
| | | |
| | | static void on_message_wrapper(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_message(message); |
| | | } |
| | | |
| | | static void on_subscribe_wrapper(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_subscribe(mid, qos_count, granted_qos); |
| | | } |
| | | |
| | | static void on_unsubscribe_wrapper(struct mosquitto *mosq, void *userdata, int mid) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_unsubscribe(mid); |
| | | } |
| | | |
| | | |
| | | static void on_log_wrapper(struct mosquitto *mosq, void *userdata, int level, const char *str) |
| | | { |
| | | class mosquittopp *m = (class mosquittopp *)userdata; |
| | | UNUSED(mosq); |
| | | m->on_log(level, str); |
| | | } |
| | | |
| | | int lib_version(int *major, int *minor, int *revision) |
| | | { |
| | | if(major) *major = LIBMOSQUITTO_MAJOR; |
| | | if(minor) *minor = LIBMOSQUITTO_MINOR; |
| | | if(revision) *revision = LIBMOSQUITTO_REVISION; |
| | | return LIBMOSQUITTO_VERSION_NUMBER; |
| | | } |
| | | |
| | | int lib_init() |
| | | { |
| | | return mosquitto_lib_init(); |
| | | } |
| | | |
| | | int lib_cleanup() |
| | | { |
| | | return mosquitto_lib_cleanup(); |
| | | } |
| | | |
| | | const char* strerror(int mosq_errno) |
| | | { |
| | | return mosquitto_strerror(mosq_errno); |
| | | } |
| | | |
| | | const char* connack_string(int connack_code) |
| | | { |
| | | return mosquitto_connack_string(connack_code); |
| | | } |
| | | |
| | | int sub_topic_tokenise(const char *subtopic, char ***topics, int *count) |
| | | { |
| | | return mosquitto_sub_topic_tokenise(subtopic, topics, count); |
| | | } |
| | | |
| | | int sub_topic_tokens_free(char ***topics, int count) |
| | | { |
| | | return mosquitto_sub_topic_tokens_free(topics, count); |
| | | } |
| | | |
| | | int topic_matches_sub(const char *sub, const char *topic, bool *result) |
| | | { |
| | | return mosquitto_topic_matches_sub(sub, topic, result); |
| | | } |
| | | |
| | | int validate_utf8(const char *str, int len) |
| | | { |
| | | return mosquitto_validate_utf8(str, len); |
| | | } |
| | | |
| | | int subscribe_simple( |
| | | struct mosquitto_message **messages, |
| | | int msg_count, |
| | | bool retained, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls) |
| | | { |
| | | return mosquitto_subscribe_simple( |
| | | messages, msg_count, retained, |
| | | topic, qos, |
| | | host, port, client_id, keepalive, clean_session, |
| | | username, password, |
| | | will, tls); |
| | | } |
| | | |
| | | mosqpp_EXPORT int subscribe_callback( |
| | | int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *), |
| | | void *userdata, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls) |
| | | { |
| | | return mosquitto_subscribe_callback( |
| | | callback, userdata, |
| | | topic, qos, |
| | | host, port, client_id, keepalive, clean_session, |
| | | username, password, |
| | | will, tls); |
| | | } |
| | | |
| | | |
| | | mosquittopp::mosquittopp(const char *id, bool clean_session) |
| | | { |
| | | m_mosq = mosquitto_new(id, clean_session, this); |
| | | mosquitto_connect_callback_set(m_mosq, on_connect_wrapper); |
| | | mosquitto_connect_with_flags_callback_set(m_mosq, on_connect_with_flags_wrapper); |
| | | mosquitto_disconnect_callback_set(m_mosq, on_disconnect_wrapper); |
| | | mosquitto_publish_callback_set(m_mosq, on_publish_wrapper); |
| | | mosquitto_message_callback_set(m_mosq, on_message_wrapper); |
| | | mosquitto_subscribe_callback_set(m_mosq, on_subscribe_wrapper); |
| | | mosquitto_unsubscribe_callback_set(m_mosq, on_unsubscribe_wrapper); |
| | | mosquitto_log_callback_set(m_mosq, on_log_wrapper); |
| | | } |
| | | |
| | | mosquittopp::~mosquittopp() |
| | | { |
| | | mosquitto_destroy(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::reinitialise(const char *id, bool clean_session) |
| | | { |
| | | int rc; |
| | | rc = mosquitto_reinitialise(m_mosq, id, clean_session, this); |
| | | if(rc == MOSQ_ERR_SUCCESS){ |
| | | mosquitto_connect_callback_set(m_mosq, on_connect_wrapper); |
| | | mosquitto_connect_with_flags_callback_set(m_mosq, on_connect_with_flags_wrapper); |
| | | mosquitto_disconnect_callback_set(m_mosq, on_disconnect_wrapper); |
| | | mosquitto_publish_callback_set(m_mosq, on_publish_wrapper); |
| | | mosquitto_message_callback_set(m_mosq, on_message_wrapper); |
| | | mosquitto_subscribe_callback_set(m_mosq, on_subscribe_wrapper); |
| | | mosquitto_unsubscribe_callback_set(m_mosq, on_unsubscribe_wrapper); |
| | | mosquitto_log_callback_set(m_mosq, on_log_wrapper); |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | int mosquittopp::connect(const char *host, int port, int keepalive) |
| | | { |
| | | return mosquitto_connect(m_mosq, host, port, keepalive); |
| | | } |
| | | |
| | | int mosquittopp::connect(const char *host, int port, int keepalive, const char *bind_address) |
| | | { |
| | | return mosquitto_connect_bind(m_mosq, host, port, keepalive, bind_address); |
| | | } |
| | | |
| | | int mosquittopp::connect_async(const char *host, int port, int keepalive) |
| | | { |
| | | return mosquitto_connect_async(m_mosq, host, port, keepalive); |
| | | } |
| | | |
| | | int mosquittopp::connect_async(const char *host, int port, int keepalive, const char *bind_address) |
| | | { |
| | | return mosquitto_connect_bind_async(m_mosq, host, port, keepalive, bind_address); |
| | | } |
| | | |
| | | int mosquittopp::reconnect() |
| | | { |
| | | return mosquitto_reconnect(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::reconnect_async() |
| | | { |
| | | return mosquitto_reconnect_async(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::disconnect() |
| | | { |
| | | return mosquitto_disconnect(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::socket() |
| | | { |
| | | return mosquitto_socket(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::will_set(const char *topic, int payloadlen, const void *payload, int qos, bool retain) |
| | | { |
| | | return mosquitto_will_set(m_mosq, topic, payloadlen, payload, qos, retain); |
| | | } |
| | | |
| | | int mosquittopp::will_clear() |
| | | { |
| | | return mosquitto_will_clear(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::username_pw_set(const char *username, const char *password) |
| | | { |
| | | return mosquitto_username_pw_set(m_mosq, username, password); |
| | | } |
| | | |
| | | int mosquittopp::publish(int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) |
| | | { |
| | | return mosquitto_publish(m_mosq, mid, topic, payloadlen, payload, qos, retain); |
| | | } |
| | | |
| | | void mosquittopp::reconnect_delay_set(unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff) |
| | | { |
| | | mosquitto_reconnect_delay_set(m_mosq, reconnect_delay, reconnect_delay_max, reconnect_exponential_backoff); |
| | | } |
| | | |
| | | int mosquittopp::max_inflight_messages_set(unsigned int max_inflight_messages) |
| | | { |
| | | return mosquitto_max_inflight_messages_set(m_mosq, max_inflight_messages); |
| | | } |
| | | |
| | | void mosquittopp::message_retry_set(unsigned int message_retry) |
| | | { |
| | | mosquitto_message_retry_set(m_mosq, message_retry); |
| | | } |
| | | |
| | | int mosquittopp::subscribe(int *mid, const char *sub, int qos) |
| | | { |
| | | return mosquitto_subscribe(m_mosq, mid, sub, qos); |
| | | } |
| | | |
| | | int mosquittopp::unsubscribe(int *mid, const char *sub) |
| | | { |
| | | return mosquitto_unsubscribe(m_mosq, mid, sub); |
| | | } |
| | | |
| | | int mosquittopp::loop(int timeout, int max_packets) |
| | | { |
| | | return mosquitto_loop(m_mosq, timeout, max_packets); |
| | | } |
| | | |
| | | int mosquittopp::loop_misc() |
| | | { |
| | | return mosquitto_loop_misc(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::loop_read(int max_packets) |
| | | { |
| | | return mosquitto_loop_read(m_mosq, max_packets); |
| | | } |
| | | |
| | | int mosquittopp::loop_write(int max_packets) |
| | | { |
| | | return mosquitto_loop_write(m_mosq, max_packets); |
| | | } |
| | | |
| | | int mosquittopp::loop_forever(int timeout, int max_packets) |
| | | { |
| | | return mosquitto_loop_forever(m_mosq, timeout, max_packets); |
| | | } |
| | | |
| | | int mosquittopp::loop_start() |
| | | { |
| | | return mosquitto_loop_start(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::loop_stop(bool force) |
| | | { |
| | | return mosquitto_loop_stop(m_mosq, force); |
| | | } |
| | | |
| | | bool mosquittopp::want_write() |
| | | { |
| | | return mosquitto_want_write(m_mosq); |
| | | } |
| | | |
| | | int mosquittopp::opts_set(enum mosq_opt_t option, void *value) |
| | | { |
| | | return mosquitto_opts_set(m_mosq, option, value); |
| | | } |
| | | |
| | | int mosquittopp::threaded_set(bool threaded) |
| | | { |
| | | return mosquitto_threaded_set(m_mosq, threaded); |
| | | } |
| | | |
| | | void mosquittopp::user_data_set(void *userdata) |
| | | { |
| | | mosquitto_user_data_set(m_mosq, userdata); |
| | | } |
| | | |
| | | int mosquittopp::socks5_set(const char *host, int port, const char *username, const char *password) |
| | | { |
| | | return mosquitto_socks5_set(m_mosq, host, port, username, password); |
| | | } |
| | | |
| | | |
| | | int mosquittopp::tls_set(const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)) |
| | | { |
| | | return mosquitto_tls_set(m_mosq, cafile, capath, certfile, keyfile, pw_callback); |
| | | } |
| | | |
| | | int mosquittopp::tls_opts_set(int cert_reqs, const char *tls_version, const char *ciphers) |
| | | { |
| | | return mosquitto_tls_opts_set(m_mosq, cert_reqs, tls_version, ciphers); |
| | | } |
| | | |
| | | int mosquittopp::tls_insecure_set(bool value) |
| | | { |
| | | return mosquitto_tls_insecure_set(m_mosq, value); |
| | | } |
| | | |
| | | int mosquittopp::tls_psk_set(const char *psk, const char *identity, const char *ciphers) |
| | | { |
| | | return mosquitto_tls_psk_set(m_mosq, psk, identity, ciphers); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 MOSQUITTOPP_H |
| | | #define MOSQUITTOPP_H |
| | | |
| | | #ifdef _WIN32 |
| | | # ifdef mosquittopp_EXPORTS |
| | | # define mosqpp_EXPORT __declspec(dllexport) |
| | | # else |
| | | # define mosqpp_EXPORT __declspec(dllimport) |
| | | # endif |
| | | #else |
| | | # define mosqpp_EXPORT |
| | | #endif |
| | | |
| | | #if defined(__GNUC__) || defined(__clang__) |
| | | # define DEPRECATED __attribute__ ((deprecated)) |
| | | #else |
| | | # define DEPRECATED |
| | | #endif |
| | | |
| | | #include <cstdlib> |
| | | #include <mosquitto.h> |
| | | #include <time.h> |
| | | |
| | | namespace mosqpp { |
| | | |
| | | |
| | | mosqpp_EXPORT const char * DEPRECATED strerror(int mosq_errno); |
| | | mosqpp_EXPORT const char * DEPRECATED connack_string(int connack_code); |
| | | mosqpp_EXPORT int DEPRECATED sub_topic_tokenise(const char *subtopic, char ***topics, int *count); |
| | | mosqpp_EXPORT int DEPRECATED sub_topic_tokens_free(char ***topics, int count); |
| | | mosqpp_EXPORT int DEPRECATED lib_version(int *major, int *minor, int *revision); |
| | | mosqpp_EXPORT int DEPRECATED lib_init(); |
| | | mosqpp_EXPORT int DEPRECATED lib_cleanup(); |
| | | mosqpp_EXPORT int DEPRECATED topic_matches_sub(const char *sub, const char *topic, bool *result); |
| | | mosqpp_EXPORT int DEPRECATED validate_utf8(const char *str, int len); |
| | | mosqpp_EXPORT int DEPRECATED subscribe_simple( |
| | | struct mosquitto_message **messages, |
| | | int msg_count, |
| | | bool retained, |
| | | const char *topic, |
| | | int qos=0, |
| | | const char *host="localhost", |
| | | int port=1883, |
| | | const char *client_id=NULL, |
| | | int keepalive=60, |
| | | bool clean_session=true, |
| | | const char *username=NULL, |
| | | const char *password=NULL, |
| | | const struct libmosquitto_will *will=NULL, |
| | | const struct libmosquitto_tls *tls=NULL); |
| | | |
| | | mosqpp_EXPORT int DEPRECATED subscribe_callback( |
| | | int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *), |
| | | void *userdata, |
| | | const char *topic, |
| | | int qos=0, |
| | | bool retained=true, |
| | | const char *host="localhost", |
| | | int port=1883, |
| | | const char *client_id=NULL, |
| | | int keepalive=60, |
| | | bool clean_session=true, |
| | | const char *username=NULL, |
| | | const char *password=NULL, |
| | | const struct libmosquitto_will *will=NULL, |
| | | const struct libmosquitto_tls *tls=NULL); |
| | | |
| | | /* |
| | | * Class: mosquittopp |
| | | * |
| | | * A mosquitto client class. This is a C++ wrapper class for the mosquitto C |
| | | * library. Please see mosquitto.h for details of the functions. |
| | | */ |
| | | class mosqpp_EXPORT DEPRECATED mosquittopp { |
| | | private: |
| | | struct mosquitto *m_mosq; |
| | | public: |
| | | DEPRECATED mosquittopp(const char *id=NULL, bool clean_session=true); |
| | | virtual ~mosquittopp(); |
| | | |
| | | int DEPRECATED reinitialise(const char *id, bool clean_session); |
| | | int DEPRECATED socket(); |
| | | int DEPRECATED will_set(const char *topic, int payloadlen=0, const void *payload=NULL, int qos=0, bool retain=false); |
| | | int DEPRECATED will_clear(); |
| | | int DEPRECATED username_pw_set(const char *username, const char *password=NULL); |
| | | int DEPRECATED connect(const char *host, int port=1883, int keepalive=60); |
| | | int DEPRECATED connect_async(const char *host, int port=1883, int keepalive=60); |
| | | int DEPRECATED connect(const char *host, int port, int keepalive, const char *bind_address); |
| | | int DEPRECATED connect_async(const char *host, int port, int keepalive, const char *bind_address); |
| | | int DEPRECATED reconnect(); |
| | | int DEPRECATED reconnect_async(); |
| | | int DEPRECATED disconnect(); |
| | | int DEPRECATED publish(int *mid, const char *topic, int payloadlen=0, const void *payload=NULL, int qos=0, bool retain=false); |
| | | int DEPRECATED subscribe(int *mid, const char *sub, int qos=0); |
| | | int DEPRECATED unsubscribe(int *mid, const char *sub); |
| | | void DEPRECATED reconnect_delay_set(unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); |
| | | int DEPRECATED max_inflight_messages_set(unsigned int max_inflight_messages); |
| | | void DEPRECATED message_retry_set(unsigned int message_retry); |
| | | void DEPRECATED user_data_set(void *userdata); |
| | | int DEPRECATED tls_set(const char *cafile, const char *capath=NULL, const char *certfile=NULL, const char *keyfile=NULL, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)=NULL); |
| | | int DEPRECATED tls_opts_set(int cert_reqs, const char *tls_version=NULL, const char *ciphers=NULL); |
| | | int DEPRECATED tls_insecure_set(bool value); |
| | | int DEPRECATED tls_psk_set(const char *psk, const char *identity, const char *ciphers=NULL); |
| | | int DEPRECATED opts_set(enum mosq_opt_t option, void *value); |
| | | |
| | | int DEPRECATED loop(int timeout=-1, int max_packets=1); |
| | | int DEPRECATED loop_misc(); |
| | | int DEPRECATED loop_read(int max_packets=1); |
| | | int DEPRECATED loop_write(int max_packets=1); |
| | | int DEPRECATED loop_forever(int timeout=-1, int max_packets=1); |
| | | int DEPRECATED loop_start(); |
| | | int DEPRECATED loop_stop(bool force=false); |
| | | bool DEPRECATED want_write(); |
| | | int DEPRECATED threaded_set(bool threaded=true); |
| | | int DEPRECATED socks5_set(const char *host, int port=1080, const char *username=NULL, const char *password=NULL); |
| | | |
| | | // names in the functions commented to prevent unused parameter warning |
| | | virtual void on_connect(int /*rc*/) {return;} |
| | | virtual void on_connect_with_flags(int /*rc*/, int /*flags*/) {return;} |
| | | virtual void on_disconnect(int /*rc*/) {return;} |
| | | virtual void on_publish(int /*mid*/) {return;} |
| | | virtual void on_message(const struct mosquitto_message * /*message*/) {return;} |
| | | virtual void on_subscribe(int /*mid*/, int /*qos_count*/, const int * /*granted_qos*/) {return;} |
| | | virtual void on_unsubscribe(int /*mid*/) {return;} |
| | | virtual void on_log(int /*level*/, const char * /*str*/) {return;} |
| | | virtual void on_error() {return;} |
| | | }; |
| | | |
| | | } |
| | | #endif |
New file |
| | |
| | | #ifndef DUMMYPTHREAD_H |
| | | #define DUMMYPTHREAD_H |
| | | |
| | | #define pthread_create(A, B, C, D) |
| | | #define pthread_join(A, B) |
| | | #define pthread_cancel(A) |
| | | |
| | | #define pthread_mutex_init(A, B) |
| | | #define pthread_mutex_destroy(A) |
| | | #define pthread_mutex_lock(A) |
| | | #define pthread_mutex_unlock(A) |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2018 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 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 "config.h" |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #include "logging_mosq.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | |
| | | |
| | | int handle__auth(struct mosquitto *mosq) |
| | | { |
| | | int rc = 0; |
| | | uint8_t reason_code; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received AUTH", mosq->id); |
| | | |
| | | if(mosq->protocol != mosq_p_mqtt5){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | if(packet__read_byte(&mosq->in_packet, &reason_code)) return 1; |
| | | |
| | | rc = property__read_all(CMD_AUTH, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | #include "read_handle.h" |
| | | |
| | | int handle__connack(struct mosquitto *mosq) |
| | | { |
| | | uint8_t connect_flags; |
| | | uint8_t reason_code; |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | char *clientid = NULL; |
| | | |
| | | assert(mosq); |
| | | rc = packet__read_byte(&mosq->in_packet, &connect_flags); |
| | | if(rc) return rc; |
| | | rc = packet__read_byte(&mosq->in_packet, &reason_code); |
| | | if(rc) return rc; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | mosquitto_property_read_string(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, &clientid, false); |
| | | if(clientid){ |
| | | if(mosq->id){ |
| | | /* We've been sent a client identifier but already have one. This |
| | | * shouldn't happen. */ |
| | | free(clientid); |
| | | mosquitto_property_free_all(&properties); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | }else{ |
| | | mosq->id = clientid; |
| | | clientid = NULL; |
| | | } |
| | | } |
| | | |
| | | mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS, &mosq->maximum_qos, false); |
| | | mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->msgs_out.inflight_maximum, false); |
| | | mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); |
| | | mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE, &mosq->maximum_packet_size, false); |
| | | |
| | | mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; |
| | | |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_connect){ |
| | | mosq->in_callback = true; |
| | | mosq->on_connect(mosq, mosq->userdata, reason_code); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_connect_with_flags){ |
| | | mosq->in_callback = true; |
| | | mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_connect_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | |
| | | switch(reason_code){ |
| | | case 0: |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | if(mosq->state != mosq_cs_disconnecting){ |
| | | mosq->state = mosq_cs_connected; |
| | | } |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | message__retry_check(mosq); |
| | | return MOSQ_ERR_SUCCESS; |
| | | case 1: |
| | | case 2: |
| | | case 3: |
| | | case 4: |
| | | case 5: |
| | | return MOSQ_ERR_CONN_REFUSED; |
| | | default: |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2018 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 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 "config.h" |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #include "logging_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "memory_mosq.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | int handle__disconnect(struct mosquitto *mosq) |
| | | { |
| | | int rc; |
| | | uint8_t reason_code; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | if(!mosq){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | if(mosq->protocol != mosq_p_mqtt5){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | rc = packet__read_byte(&mosq->in_packet, &reason_code); |
| | | if(rc) return rc; |
| | | |
| | | if(mosq->in_packet.remaining_length > 2){ |
| | | rc = property__read_all(CMD_DISCONNECT, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | mosquitto_property_free_all(&properties); |
| | | } |
| | | |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Received DISCONNECT (%d)", reason_code); |
| | | |
| | | do_client_disconnect(mosq, reason_code, properties); |
| | | |
| | | mosquitto_property_free_all(&properties); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "read_handle.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | int handle__pingreq(struct mosquitto *mosq) |
| | | { |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGREQ from %s", mosq->id); |
| | | #else |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGREQ", mosq->id); |
| | | #endif |
| | | return send__pingresp(mosq); |
| | | } |
| | | |
| | | int handle__pingresp(struct mosquitto *mosq) |
| | | { |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | mosq->ping_t = 0; /* No longer waiting for a PINGRESP. */ |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGRESP from %s", mosq->id); |
| | | #else |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGRESP", mosq->id); |
| | | #endif |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "read_handle.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | |
| | | #ifdef WITH_BROKER |
| | | int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type) |
| | | #else |
| | | int handle__pubackcomp(struct mosquitto *mosq, const char *type) |
| | | #endif |
| | | { |
| | | uint8_t reason_code = 0; |
| | | uint16_t mid; |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | int qos; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | util__increment_send_quota(mosq); |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc) return rc; |
| | | qos = type[3] == 'A'?1:2; /* pubAck or pubComp */ |
| | | if(mid == 0) return MOSQ_ERR_PROTOCOL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ |
| | | rc = packet__read_byte(&mosq->in_packet, &reason_code); |
| | | if(rc) return rc; |
| | | |
| | | if(mosq->in_packet.remaining_length > 3){ |
| | | rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d, RC:%d)", type, mosq->id, mid, reason_code); |
| | | |
| | | /* Immediately free, we don't do anything with Reason String or User Property at the moment */ |
| | | mosquitto_property_free_all(&properties); |
| | | |
| | | rc = db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubcomp, qos); |
| | | if(rc == MOSQ_ERR_NOT_FOUND){ |
| | | log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received %s from %s for an unknown packet identifier %d.", type, mosq->id, mid); |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return rc; |
| | | } |
| | | #else |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d, RC:%d)", mosq->id, type, mid, reason_code); |
| | | |
| | | rc = message__delete(mosq, mid, mosq_md_out, qos); |
| | | if(rc){ |
| | | return rc; |
| | | }else{ |
| | | /* Only inform the client the message has been sent once. */ |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_publish){ |
| | | mosq->in_callback = true; |
| | | mosq->on_publish(mosq, mosq->userdata, mid); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_publish_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | } |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | message__release_to_inflight(mosq, mosq_md_out); |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | #endif |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <string.h> |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "messages_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | #include "send_mosq.h" |
| | | #include "time_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | |
| | | int handle__publish(struct mosquitto *mosq) |
| | | { |
| | | uint8_t header; |
| | | struct mosquitto_message_all *message; |
| | | int rc = 0; |
| | | uint16_t mid; |
| | | int slen; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); |
| | | if(!message) return MOSQ_ERR_NOMEM; |
| | | |
| | | header = mosq->in_packet.command; |
| | | |
| | | message->dup = (header & 0x08)>>3; |
| | | message->msg.qos = (header & 0x06)>>1; |
| | | message->msg.retain = (header & 0x01); |
| | | |
| | | rc = packet__read_string(&mosq->in_packet, &message->msg.topic, &slen); |
| | | if(rc){ |
| | | message__cleanup(&message); |
| | | return rc; |
| | | } |
| | | if(!slen){ |
| | | message__cleanup(&message); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | if(message->msg.qos > 0){ |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | if(mosq->msgs_in.inflight_quota == 0){ |
| | | message__cleanup(&message); |
| | | /* FIXME - should send a DISCONNECT here */ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | } |
| | | |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc){ |
| | | message__cleanup(&message); |
| | | return rc; |
| | | } |
| | | if(mid == 0){ |
| | | message__cleanup(&message); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | message->msg.mid = (int)mid; |
| | | } |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | rc = property__read_all(CMD_PUBLISH, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; |
| | | if(message->msg.payloadlen){ |
| | | message->msg.payload = mosquitto__calloc(message->msg.payloadlen+1, sizeof(uint8_t)); |
| | | if(!message->msg.payload){ |
| | | message__cleanup(&message); |
| | | mosquitto_property_free_all(&properties); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | rc = packet__read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen); |
| | | if(rc){ |
| | | message__cleanup(&message); |
| | | mosquitto_property_free_all(&properties); |
| | | return rc; |
| | | } |
| | | } |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, |
| | | "Client %s received PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", |
| | | mosq->id, message->dup, message->msg.qos, message->msg.retain, |
| | | message->msg.mid, message->msg.topic, |
| | | (long)message->msg.payloadlen); |
| | | |
| | | message->timestamp = mosquitto_time(); |
| | | switch(message->msg.qos){ |
| | | case 0: |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_message){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message(mosq, mosq->userdata, &message->msg); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_message_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | message__cleanup(&message); |
| | | mosquitto_property_free_all(&properties); |
| | | return MOSQ_ERR_SUCCESS; |
| | | case 1: |
| | | util__decrement_receive_quota(mosq); |
| | | rc = send__puback(mosq, message->msg.mid, 0); |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_message){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message(mosq, mosq->userdata, &message->msg); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_message_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | message__cleanup(&message); |
| | | mosquitto_property_free_all(&properties); |
| | | return rc; |
| | | case 2: |
| | | util__decrement_receive_quota(mosq); |
| | | rc = send__pubrec(mosq, message->msg.mid, 0); |
| | | pthread_mutex_lock(&mosq->msgs_in.mutex); |
| | | message->state = mosq_ms_wait_for_pubrel; |
| | | message__queue(mosq, message, mosq_md_in); |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | return rc; |
| | | default: |
| | | message__cleanup(&message); |
| | | mosquitto_property_free_all(&properties); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "read_handle.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq) |
| | | { |
| | | uint8_t reason_code = 0; |
| | | uint16_t mid; |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc) return rc; |
| | | if(mid == 0) return MOSQ_ERR_PROTOCOL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ |
| | | rc = packet__read_byte(&mosq->in_packet, &reason_code); |
| | | if(rc) return rc; |
| | | |
| | | if(mosq->in_packet.remaining_length > 3){ |
| | | rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | /* Immediately free, we don't do anything with Reason String or User Property at the moment */ |
| | | mosquitto_property_free_all(&properties); |
| | | } |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid); |
| | | |
| | | if(reason_code < 0x80){ |
| | | rc = db__message_update_outgoing(mosq, mid, mosq_ms_wait_for_pubcomp, 2); |
| | | }else{ |
| | | return db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubrec, 2); |
| | | } |
| | | #else |
| | | UNUSED(db); |
| | | |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid); |
| | | |
| | | if(reason_code < 0x80 || mosq->protocol != mosq_p_mqtt5){ |
| | | rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp, 2); |
| | | }else{ |
| | | if(!message__delete(mosq, mid, mosq_md_out, 2)){ |
| | | /* Only inform the client the message has been sent once. */ |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_publish_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | } |
| | | util__increment_send_quota(mosq); |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | message__release_to_inflight(mosq, mosq_md_out); |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | #endif |
| | | if(rc == MOSQ_ERR_NOT_FOUND){ |
| | | log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREC from %s for an unknown packet identifier %d.", mosq->id, mid); |
| | | }else if(rc != MOSQ_ERR_SUCCESS){ |
| | | return rc; |
| | | } |
| | | rc = send__pubrel(mosq, mid); |
| | | if(rc) return rc; |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "read_handle.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | |
| | | int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) |
| | | { |
| | | uint8_t reason_code; |
| | | uint16_t mid; |
| | | #ifndef WITH_BROKER |
| | | struct mosquitto_message_all *message = NULL; |
| | | #endif |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | if(mosq->protocol != mosq_p_mqtt31){ |
| | | if((mosq->in_packet.command&0x0F) != 0x02){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | } |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc) return rc; |
| | | if(mid == 0) return MOSQ_ERR_PROTOCOL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ |
| | | rc = packet__read_byte(&mosq->in_packet, &reason_code); |
| | | if(rc) return rc; |
| | | |
| | | if(mosq->in_packet.remaining_length > 3){ |
| | | rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid); |
| | | |
| | | /* Immediately free, we don't do anything with Reason String or User Property at the moment */ |
| | | mosquitto_property_free_all(&properties); |
| | | |
| | | rc = db__message_release_incoming(db, mosq, mid); |
| | | if(rc == MOSQ_ERR_PROTOCOL){ |
| | | return rc; |
| | | }else if(rc != MOSQ_ERR_SUCCESS){ |
| | | /* Message not found. Still send a PUBCOMP anyway because this could be |
| | | * due to a repeated PUBREL after a client has reconnected. */ |
| | | } |
| | | |
| | | rc = send__pubcomp(mosq, mid); |
| | | if(rc) return rc; |
| | | #else |
| | | UNUSED(db); |
| | | |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid); |
| | | |
| | | rc = send__pubcomp(mosq, mid); |
| | | if(rc){ |
| | | message__remove(mosq, mid, mosq_md_in, &message, 2); |
| | | return rc; |
| | | } |
| | | |
| | | rc = message__remove(mosq, mid, mosq_md_in, &message, 2); |
| | | if(rc){ |
| | | return rc; |
| | | }else{ |
| | | /* Only pass the message on if we have removed it from the queue - this |
| | | * prevents multiple callbacks for the same message. */ |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_message){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message(mosq, mosq->userdata, &message->msg); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_message_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | message__cleanup(&message); |
| | | } |
| | | #endif |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | |
| | | |
| | | int handle__suback(struct mosquitto *mosq) |
| | | { |
| | | uint16_t mid; |
| | | uint8_t qos; |
| | | int *granted_qos; |
| | | int qos_count; |
| | | int i = 0; |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id); |
| | | #else |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id); |
| | | #endif |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc) return rc; |
| | | if(mid == 0) return MOSQ_ERR_PROTOCOL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | rc = property__read_all(CMD_SUBACK, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos; |
| | | granted_qos = mosquitto__malloc(qos_count*sizeof(int)); |
| | | if(!granted_qos) return MOSQ_ERR_NOMEM; |
| | | while(mosq->in_packet.pos < mosq->in_packet.remaining_length){ |
| | | rc = packet__read_byte(&mosq->in_packet, &qos); |
| | | if(rc){ |
| | | mosquitto__free(granted_qos); |
| | | return rc; |
| | | } |
| | | granted_qos[i] = (int)qos; |
| | | i++; |
| | | } |
| | | #ifdef WITH_BROKER |
| | | /* Immediately free, we don't do anything with Reason String or User Property at the moment */ |
| | | mosquitto_property_free_all(&properties); |
| | | #else |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_subscribe){ |
| | | mosq->in_callback = true; |
| | | mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_subscribe_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_subscribe_v5(mosq, mosq->userdata, mid, qos_count, granted_qos, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | #endif |
| | | mosquitto__free(granted_qos); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #ifdef WITH_BROKER |
| | | # include "mosquitto_broker_internal.h" |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "logging_mosq.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "property_mosq.h" |
| | | #include "read_handle.h" |
| | | #include "send_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | |
| | | int handle__unsuback(struct mosquitto *mosq) |
| | | { |
| | | uint16_t mid; |
| | | int rc; |
| | | mosquitto_property *properties = NULL; |
| | | |
| | | assert(mosq); |
| | | |
| | | if(mosq->state != mosq_cs_connected){ |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBACK from %s", mosq->id); |
| | | #else |
| | | log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received UNSUBACK", mosq->id); |
| | | #endif |
| | | rc = packet__read_uint16(&mosq->in_packet, &mid); |
| | | if(rc) return rc; |
| | | if(mid == 0) return MOSQ_ERR_PROTOCOL; |
| | | |
| | | if(mosq->protocol == mosq_p_mqtt5){ |
| | | rc = property__read_all(CMD_UNSUBACK, &mosq->in_packet, &properties); |
| | | if(rc) return rc; |
| | | } |
| | | |
| | | #ifdef WITH_BROKER |
| | | /* Immediately free, we don't do anything with Reason String or User Property at the moment */ |
| | | mosquitto_property_free_all(&properties); |
| | | #else |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_unsubscribe){ |
| | | mosq->in_callback = true; |
| | | mosq->on_unsubscribe(mosq, mosq->userdata, mid); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_unsubscribe_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_unsubscribe_v5(mosq, mosq->userdata, mid, properties); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | mosquitto_property_free_all(&properties); |
| | | #endif |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2016-2019 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <stdbool.h> |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | |
| | | struct userdata__callback { |
| | | const char *topic; |
| | | int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *); |
| | | void *userdata; |
| | | int qos; |
| | | int rc; |
| | | }; |
| | | |
| | | struct userdata__simple { |
| | | struct mosquitto_message *messages; |
| | | int max_msg_count; |
| | | int message_count; |
| | | bool want_retained; |
| | | }; |
| | | |
| | | |
| | | static void on_connect(struct mosquitto *mosq, void *obj, int rc) |
| | | { |
| | | struct userdata__callback *userdata = obj; |
| | | |
| | | UNUSED(rc); |
| | | |
| | | mosquitto_subscribe(mosq, NULL, userdata->topic, userdata->qos); |
| | | } |
| | | |
| | | |
| | | static void on_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | { |
| | | int rc; |
| | | struct userdata__callback *userdata = obj; |
| | | |
| | | rc = userdata->callback(mosq, userdata->userdata, message); |
| | | if(rc){ |
| | | mosquitto_disconnect(mosq); |
| | | } |
| | | } |
| | | |
| | | static int on_message_simple(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | { |
| | | struct userdata__simple *userdata = obj; |
| | | int rc; |
| | | |
| | | if(userdata->max_msg_count == 0){ |
| | | return 0; |
| | | } |
| | | |
| | | /* Don't process stale retained messages if 'want_retained' was false */ |
| | | if(!userdata->want_retained && message->retain){ |
| | | return 0; |
| | | } |
| | | |
| | | userdata->max_msg_count--; |
| | | |
| | | rc = mosquitto_message_copy(&userdata->messages[userdata->message_count], message); |
| | | if(rc){ |
| | | return rc; |
| | | } |
| | | userdata->message_count++; |
| | | if(userdata->max_msg_count == 0){ |
| | | mosquitto_disconnect(mosq); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | libmosq_EXPORT int mosquitto_subscribe_simple( |
| | | struct mosquitto_message **messages, |
| | | int msg_count, |
| | | bool want_retained, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls) |
| | | { |
| | | struct userdata__simple userdata; |
| | | int rc; |
| | | int i; |
| | | |
| | | if(!topic || msg_count < 1 || !messages){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | *messages = NULL; |
| | | |
| | | userdata.messages = calloc(sizeof(struct mosquitto_message), msg_count); |
| | | if(!userdata.messages){ |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | userdata.message_count = 0; |
| | | userdata.max_msg_count = msg_count; |
| | | userdata.want_retained = want_retained; |
| | | |
| | | rc = mosquitto_subscribe_callback( |
| | | on_message_simple, &userdata, |
| | | topic, qos, |
| | | host, port, |
| | | client_id, keepalive, clean_session, |
| | | username, password, |
| | | will, tls); |
| | | |
| | | if(!rc && userdata.max_msg_count == 0){ |
| | | *messages = userdata.messages; |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | for(i=0; i<msg_count; i++){ |
| | | mosquitto_message_free_contents(&userdata.messages[i]); |
| | | } |
| | | free(userdata.messages); |
| | | userdata.messages = NULL; |
| | | return rc; |
| | | } |
| | | } |
| | | |
| | | |
| | | libmosq_EXPORT int mosquitto_subscribe_callback( |
| | | int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *), |
| | | void *userdata, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls) |
| | | { |
| | | struct mosquitto *mosq; |
| | | struct userdata__callback cb_userdata; |
| | | int rc; |
| | | |
| | | if(!callback || !topic){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | cb_userdata.topic = topic; |
| | | cb_userdata.qos = qos; |
| | | cb_userdata.rc = 0; |
| | | cb_userdata.userdata = userdata; |
| | | cb_userdata.callback = callback; |
| | | |
| | | mosq = mosquitto_new(client_id, clean_session, &cb_userdata); |
| | | if(!mosq){ |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | |
| | | if(will){ |
| | | rc = mosquitto_will_set(mosq, will->topic, will->payloadlen, will->payload, will->qos, will->retain); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | return rc; |
| | | } |
| | | } |
| | | if(username){ |
| | | rc = mosquitto_username_pw_set(mosq, username, password); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | return rc; |
| | | } |
| | | } |
| | | if(tls){ |
| | | rc = mosquitto_tls_set(mosq, tls->cafile, tls->capath, tls->certfile, tls->keyfile, tls->pw_callback); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | return rc; |
| | | } |
| | | rc = mosquitto_tls_opts_set(mosq, tls->cert_reqs, tls->tls_version, tls->ciphers); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | return rc; |
| | | } |
| | | } |
| | | |
| | | mosquitto_connect_callback_set(mosq, on_connect); |
| | | mosquitto_message_callback_set(mosq, on_message_callback); |
| | | |
| | | rc = mosquitto_connect(mosq, host, port, keepalive); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | return rc; |
| | | } |
| | | rc = mosquitto_loop_forever(mosq, -1, 1); |
| | | mosquitto_destroy(mosq); |
| | | if(cb_userdata.rc){ |
| | | rc = cb_userdata.rc; |
| | | } |
| | | //if(!rc && cb_userdata.max_msg_count == 0){ |
| | | //return MOSQ_ERR_SUCCESS; |
| | | //}else{ |
| | | //return rc; |
| | | //} |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* Linker version script - currently used here primarily to control which |
| | | * symbols are exported. |
| | | */ |
| | | |
| | | MOSQ_1.0 { |
| | | global: |
| | | mosquitto_lib_version; |
| | | mosquitto_lib_init; |
| | | mosquitto_lib_cleanup; |
| | | mosquitto_new; |
| | | mosquitto_destroy; |
| | | mosquitto_reinitialise; |
| | | mosquitto_will_set; |
| | | mosquitto_will_clear; |
| | | mosquitto_username_pw_set; |
| | | mosquitto_connect; |
| | | mosquitto_connect_async; |
| | | mosquitto_reconnect; |
| | | mosquitto_disconnect; |
| | | mosquitto_publish; |
| | | mosquitto_subscribe; |
| | | mosquitto_unsubscribe; |
| | | mosquitto_message_copy; |
| | | mosquitto_message_free; |
| | | mosquitto_loop; |
| | | mosquitto_socket; |
| | | mosquitto_loop_start; |
| | | mosquitto_loop_stop; |
| | | mosquitto_loop_read; |
| | | mosquitto_loop_write; |
| | | mosquitto_loop_misc; |
| | | mosquitto_connect_callback_set; |
| | | mosquitto_disconnect_callback_set; |
| | | mosquitto_publish_callback_set; |
| | | mosquitto_message_callback_set; |
| | | mosquitto_subscribe_callback_set; |
| | | mosquitto_unsubscribe_callback_set; |
| | | mosquitto_log_callback_set; |
| | | mosquitto_message_retry_set; |
| | | mosquitto_want_write; |
| | | mosquitto_user_data_set; |
| | | mosquitto_strerror; |
| | | mosquitto_connack_string; |
| | | mosquitto_tls_set; |
| | | mosquitto_tls_opts_set; |
| | | mosquitto_tls_psk_set; |
| | | mosquitto_sub_topic_tokenise; |
| | | mosquitto_sub_topic_tokens_free; |
| | | mosquitto_topic_matches_sub; |
| | | local: *; |
| | | }; |
| | | |
| | | MOSQ_1.1 { |
| | | global: |
| | | mosquitto_loop_forever; |
| | | } MOSQ_1.0; |
| | | |
| | | MOSQ_1.2 { |
| | | global: |
| | | mosquitto_connect_bind; |
| | | mosquitto_connect_bind_async; |
| | | mosquitto_max_inflight_messages_set; |
| | | mosquitto_reconnect_delay_set; |
| | | mosquitto_reconnect_async; |
| | | mosquitto_tls_insecure_set; |
| | | } MOSQ_1.1; |
| | | |
| | | MOSQ_1.3 { |
| | | global: |
| | | mosquitto_connect_srv; |
| | | } MOSQ_1.2; |
| | | |
| | | MOSQ_1.4 { |
| | | global: |
| | | mosquitto_threaded_set; |
| | | mosquitto_opts_set; |
| | | mosquitto_pub_topic_check; |
| | | mosquitto_sub_topic_check; |
| | | mosquitto_socks5_set; |
| | | } MOSQ_1.3; |
| | | |
| | | MOSQ_1.5 { |
| | | global: |
| | | mosquitto_subscribe_simple; |
| | | mosquitto_subscribe_callback; |
| | | mosquitto_message_free_contents; |
| | | mosquitto_validate_utf8; |
| | | mosquitto_userdata; |
| | | mosquitto_pub_topic_check2; |
| | | mosquitto_sub_topic_check2; |
| | | mosquitto_topic_matches_sub2; |
| | | mosquitto_connect_with_flags_callback_set; |
| | | } MOSQ_1.4; |
| | | |
| | | MOSQ_1.6 { |
| | | global: |
| | | mosquitto_connect_bind_v5; |
| | | mosquitto_connect_v5_callback_set; |
| | | mosquitto_disconnect_v5; |
| | | mosquitto_disconnect_v5_callback_set; |
| | | mosquitto_int_option; |
| | | mosquitto_message_v5_callback_set; |
| | | mosquitto_property_add_binary; |
| | | mosquitto_property_add_byte; |
| | | mosquitto_property_add_int16; |
| | | mosquitto_property_add_int32; |
| | | mosquitto_property_add_string; |
| | | mosquitto_property_add_string_pair; |
| | | mosquitto_property_add_varint; |
| | | mosquitto_property_check_all; |
| | | mosquitto_property_check_command; |
| | | mosquitto_property_free_all; |
| | | mosquitto_property_read_binary; |
| | | mosquitto_property_read_byte; |
| | | mosquitto_property_read_int16; |
| | | mosquitto_property_read_int32; |
| | | mosquitto_property_read_string; |
| | | mosquitto_property_read_string_pair; |
| | | mosquitto_property_read_varint; |
| | | mosquitto_publish_v5; |
| | | mosquitto_publish_v5_callback_set; |
| | | mosquitto_reason_string; |
| | | mosquitto_string_option; |
| | | mosquitto_string_to_command; |
| | | mosquitto_string_to_property_info; |
| | | mosquitto_subscribe_multiple; |
| | | mosquitto_subscribe_v5; |
| | | mosquitto_subscribe_v5_callback_set; |
| | | mosquitto_unsubscribe_multiple; |
| | | mosquitto_unsubscribe_v5; |
| | | mosquitto_unsubscribe_v5_callback_set; |
| | | mosquitto_void_option; |
| | | mosquitto_will_set_v5; |
| | | } MOSQ_1.5; |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdarg.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | |
| | | #include "mosquitto_internal.h" |
| | | #include "mosquitto.h" |
| | | #include "memory_mosq.h" |
| | | |
| | | int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...) |
| | | { |
| | | va_list va; |
| | | char *s; |
| | | int len; |
| | | |
| | | assert(mosq); |
| | | assert(fmt); |
| | | |
| | | pthread_mutex_lock(&mosq->log_callback_mutex); |
| | | if(mosq->on_log){ |
| | | len = strlen(fmt) + 500; |
| | | s = mosquitto__malloc(len*sizeof(char)); |
| | | if(!s){ |
| | | pthread_mutex_unlock(&mosq->log_callback_mutex); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | |
| | | va_start(va, fmt); |
| | | vsnprintf(s, len, fmt, va); |
| | | va_end(va); |
| | | s[len-1] = '\0'; /* Ensure string is null terminated. */ |
| | | |
| | | mosq->on_log(mosq, mosq->userdata, priority, s); |
| | | |
| | | mosquitto__free(s); |
| | | } |
| | | pthread_mutex_unlock(&mosq->log_callback_mutex); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 LOGGING_MOSQ_H |
| | | #define LOGGING_MOSQ_H |
| | | |
| | | #include "mosquitto.h" |
| | | |
| | | int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #ifndef WIN32 |
| | | #include <sys/select.h> |
| | | #include <time.h> |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "socks_mosq.h" |
| | | #include "tls_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | #if !defined(WIN32) && !defined(__SYMBIAN32__) |
| | | #define HAVE_PSELECT |
| | | #endif |
| | | |
| | | int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) |
| | | { |
| | | #ifdef HAVE_PSELECT |
| | | struct timespec local_timeout; |
| | | #else |
| | | struct timeval local_timeout; |
| | | #endif |
| | | fd_set readfds, writefds; |
| | | int fdcount; |
| | | int rc; |
| | | char pairbuf; |
| | | int maxfd = 0; |
| | | time_t now; |
| | | |
| | | if(!mosq || max_packets < 1) return MOSQ_ERR_INVAL; |
| | | #ifndef WIN32 |
| | | if(mosq->sock >= FD_SETSIZE || mosq->sockpairR >= FD_SETSIZE){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | #endif |
| | | |
| | | FD_ZERO(&readfds); |
| | | FD_ZERO(&writefds); |
| | | if(mosq->sock != INVALID_SOCKET){ |
| | | maxfd = mosq->sock; |
| | | FD_SET(mosq->sock, &readfds); |
| | | pthread_mutex_lock(&mosq->current_out_packet_mutex); |
| | | pthread_mutex_lock(&mosq->out_packet_mutex); |
| | | if(mosq->out_packet || mosq->current_out_packet){ |
| | | FD_SET(mosq->sock, &writefds); |
| | | } |
| | | #ifdef WITH_TLS |
| | | if(mosq->ssl){ |
| | | if(mosq->want_write){ |
| | | FD_SET(mosq->sock, &writefds); |
| | | }else if(mosq->want_connect){ |
| | | /* Remove possible FD_SET from above, we don't want to check |
| | | * for writing if we are still connecting, unless want_write is |
| | | * definitely set. The presence of outgoing packets does not |
| | | * matter yet. */ |
| | | FD_CLR(mosq->sock, &writefds); |
| | | } |
| | | } |
| | | #endif |
| | | pthread_mutex_unlock(&mosq->out_packet_mutex); |
| | | pthread_mutex_unlock(&mosq->current_out_packet_mutex); |
| | | }else{ |
| | | #ifdef WITH_SRV |
| | | if(mosq->achan){ |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | if(mosq->state == mosq_cs_connect_srv){ |
| | | rc = ares_fds(mosq->achan, &readfds, &writefds); |
| | | if(rc > maxfd){ |
| | | maxfd = rc; |
| | | } |
| | | }else{ |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | return MOSQ_ERR_NO_CONN; |
| | | } |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | } |
| | | #else |
| | | return MOSQ_ERR_NO_CONN; |
| | | #endif |
| | | } |
| | | if(mosq->sockpairR != INVALID_SOCKET){ |
| | | /* sockpairR is used to break out of select() before the timeout, on a |
| | | * call to publish() etc. */ |
| | | FD_SET(mosq->sockpairR, &readfds); |
| | | if(mosq->sockpairR > maxfd){ |
| | | maxfd = mosq->sockpairR; |
| | | } |
| | | } |
| | | |
| | | if(timeout < 0){ |
| | | timeout = 1000; |
| | | } |
| | | |
| | | now = mosquitto_time(); |
| | | if(mosq->next_msg_out && now + timeout/1000 > mosq->next_msg_out){ |
| | | timeout = (mosq->next_msg_out - now)*1000; |
| | | } |
| | | |
| | | if(timeout < 0){ |
| | | /* There has been a delay somewhere which means we should have already |
| | | * sent a message. */ |
| | | timeout = 0; |
| | | } |
| | | |
| | | local_timeout.tv_sec = timeout/1000; |
| | | #ifdef HAVE_PSELECT |
| | | local_timeout.tv_nsec = (timeout-local_timeout.tv_sec*1000)*1e6; |
| | | #else |
| | | local_timeout.tv_usec = (timeout-local_timeout.tv_sec*1000)*1000; |
| | | #endif |
| | | |
| | | #ifdef HAVE_PSELECT |
| | | fdcount = pselect(maxfd+1, &readfds, &writefds, NULL, &local_timeout, NULL); |
| | | #else |
| | | fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout); |
| | | #endif |
| | | if(fdcount == -1){ |
| | | #ifdef WIN32 |
| | | errno = WSAGetLastError(); |
| | | #endif |
| | | if(errno == EINTR){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return MOSQ_ERR_ERRNO; |
| | | } |
| | | }else{ |
| | | if(mosq->sock != INVALID_SOCKET){ |
| | | if(FD_ISSET(mosq->sock, &readfds)){ |
| | | rc = mosquitto_loop_read(mosq, max_packets); |
| | | if(rc || mosq->sock == INVALID_SOCKET){ |
| | | return rc; |
| | | } |
| | | } |
| | | if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){ |
| | | #ifndef WIN32 |
| | | if(read(mosq->sockpairR, &pairbuf, 1) == 0){ |
| | | } |
| | | #else |
| | | recv(mosq->sockpairR, &pairbuf, 1, 0); |
| | | #endif |
| | | /* Fake write possible, to stimulate output write even though |
| | | * we didn't ask for it, because at that point the publish or |
| | | * other command wasn't present. */ |
| | | if(mosq->sock != INVALID_SOCKET) |
| | | FD_SET(mosq->sock, &writefds); |
| | | } |
| | | if(mosq->sock != INVALID_SOCKET && FD_ISSET(mosq->sock, &writefds)){ |
| | | #ifdef WITH_TLS |
| | | if(mosq->want_connect){ |
| | | rc = net__socket_connect_tls(mosq); |
| | | if(rc) return rc; |
| | | }else |
| | | #endif |
| | | { |
| | | rc = mosquitto_loop_write(mosq, max_packets); |
| | | if(rc || mosq->sock == INVALID_SOCKET){ |
| | | return rc; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | #ifdef WITH_SRV |
| | | if(mosq->achan){ |
| | | ares_process(mosq->achan, &readfds, &writefds); |
| | | } |
| | | #endif |
| | | } |
| | | return mosquitto_loop_misc(mosq); |
| | | } |
| | | |
| | | |
| | | int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) |
| | | { |
| | | int run = 1; |
| | | int rc; |
| | | unsigned int reconnects = 0; |
| | | unsigned long reconnect_delay; |
| | | #ifndef WIN32 |
| | | struct timespec req, rem; |
| | | #endif |
| | | |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | |
| | | if(mosq->state == mosq_cs_connect_async){ |
| | | mosquitto_reconnect(mosq); |
| | | } |
| | | |
| | | while(run){ |
| | | do{ |
| | | rc = mosquitto_loop(mosq, timeout, max_packets); |
| | | if (reconnects !=0 && rc == MOSQ_ERR_SUCCESS){ |
| | | reconnects = 0; |
| | | } |
| | | }while(run && rc == MOSQ_ERR_SUCCESS); |
| | | /* Quit after fatal errors. */ |
| | | switch(rc){ |
| | | case MOSQ_ERR_NOMEM: |
| | | case MOSQ_ERR_PROTOCOL: |
| | | case MOSQ_ERR_INVAL: |
| | | case MOSQ_ERR_NOT_FOUND: |
| | | case MOSQ_ERR_TLS: |
| | | case MOSQ_ERR_PAYLOAD_SIZE: |
| | | case MOSQ_ERR_NOT_SUPPORTED: |
| | | case MOSQ_ERR_AUTH: |
| | | case MOSQ_ERR_ACL_DENIED: |
| | | case MOSQ_ERR_UNKNOWN: |
| | | case MOSQ_ERR_EAI: |
| | | case MOSQ_ERR_PROXY: |
| | | return rc; |
| | | case MOSQ_ERR_ERRNO: |
| | | break; |
| | | } |
| | | if(errno == EPROTO){ |
| | | return rc; |
| | | } |
| | | do{ |
| | | rc = MOSQ_ERR_SUCCESS; |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | if(mosq->state == mosq_cs_disconnecting){ |
| | | run = 0; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | }else{ |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | |
| | | if(mosq->reconnect_delay_max > mosq->reconnect_delay){ |
| | | if(mosq->reconnect_exponential_backoff){ |
| | | reconnect_delay = mosq->reconnect_delay*(reconnects+1)*(reconnects+1); |
| | | }else{ |
| | | reconnect_delay = mosq->reconnect_delay*(reconnects+1); |
| | | } |
| | | }else{ |
| | | reconnect_delay = mosq->reconnect_delay; |
| | | } |
| | | |
| | | if(reconnect_delay > mosq->reconnect_delay_max){ |
| | | reconnect_delay = mosq->reconnect_delay_max; |
| | | }else{ |
| | | reconnects++; |
| | | } |
| | | |
| | | #ifdef WIN32 |
| | | Sleep(reconnect_delay*1000); |
| | | #else |
| | | req.tv_sec = reconnect_delay; |
| | | req.tv_nsec = 0; |
| | | while(nanosleep(&req, &rem) == -1 && errno == EINTR){ |
| | | req = rem; |
| | | } |
| | | #endif |
| | | |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | if(mosq->state == mosq_cs_disconnecting){ |
| | | run = 0; |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | }else{ |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | rc = mosquitto_reconnect(mosq); |
| | | } |
| | | } |
| | | }while(run && rc != MOSQ_ERR_SUCCESS); |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | |
| | | int mosquitto_loop_misc(struct mosquitto *mosq) |
| | | { |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; |
| | | |
| | | return mosquitto__check_keepalive(mosq); |
| | | } |
| | | |
| | | |
| | | static int mosquitto__loop_rc_handle(struct mosquitto *mosq, int rc) |
| | | { |
| | | if(rc){ |
| | | net__socket_close(mosq); |
| | | pthread_mutex_lock(&mosq->state_mutex); |
| | | if(mosq->state == mosq_cs_disconnecting){ |
| | | rc = MOSQ_ERR_SUCCESS; |
| | | } |
| | | pthread_mutex_unlock(&mosq->state_mutex); |
| | | pthread_mutex_lock(&mosq->callback_mutex); |
| | | if(mosq->on_disconnect){ |
| | | mosq->in_callback = true; |
| | | mosq->on_disconnect(mosq, mosq->userdata, rc); |
| | | mosq->in_callback = false; |
| | | } |
| | | if(mosq->on_disconnect_v5){ |
| | | mosq->in_callback = true; |
| | | mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL); |
| | | mosq->in_callback = false; |
| | | } |
| | | pthread_mutex_unlock(&mosq->callback_mutex); |
| | | return rc; |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | |
| | | int mosquitto_loop_read(struct mosquitto *mosq, int max_packets) |
| | | { |
| | | int rc; |
| | | int i; |
| | | if(max_packets < 1) return MOSQ_ERR_INVAL; |
| | | |
| | | #ifdef WITH_TLS |
| | | if(mosq->want_connect){ |
| | | return net__socket_connect_tls(mosq); |
| | | } |
| | | #endif |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | max_packets = mosq->msgs_out.queue_len; |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_in.mutex); |
| | | max_packets += mosq->msgs_in.queue_len; |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | |
| | | if(max_packets < 1) max_packets = 1; |
| | | /* Queue len here tells us how many messages are awaiting processing and |
| | | * have QoS > 0. We should try to deal with that many in this loop in order |
| | | * to keep up. */ |
| | | for(i=0; i<max_packets || SSL_DATA_PENDING(mosq); i++){ |
| | | #ifdef WITH_SOCKS |
| | | if(mosq->socks5_host){ |
| | | rc = socks5__read(mosq); |
| | | }else |
| | | #endif |
| | | { |
| | | rc = packet__read(mosq); |
| | | } |
| | | if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ |
| | | return mosquitto__loop_rc_handle(mosq, rc); |
| | | } |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | |
| | | int mosquitto_loop_write(struct mosquitto *mosq, int max_packets) |
| | | { |
| | | int rc; |
| | | int i; |
| | | if(max_packets < 1) return MOSQ_ERR_INVAL; |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | max_packets = mosq->msgs_out.queue_len; |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_in.mutex); |
| | | max_packets += mosq->msgs_in.queue_len; |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | |
| | | if(max_packets < 1) max_packets = 1; |
| | | /* Queue len here tells us how many messages are awaiting processing and |
| | | * have QoS > 0. We should try to deal with that many in this loop in order |
| | | * to keep up. */ |
| | | for(i=0; i<max_packets; i++){ |
| | | rc = packet__write(mosq); |
| | | if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ |
| | | return mosquitto__loop_rc_handle(mosq, rc); |
| | | } |
| | | } |
| | | return rc; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2009-2019 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 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 "config.h" |
| | | |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | #include "memory_mosq.h" |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | # if defined(__APPLE__) |
| | | # include <malloc/malloc.h> |
| | | # define malloc_usable_size malloc_size |
| | | # elif defined(__FreeBSD__) |
| | | # include <malloc_np.h> |
| | | # else |
| | | # include <malloc.h> |
| | | # endif |
| | | #endif |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | static unsigned long memcount = 0; |
| | | static unsigned long max_memcount = 0; |
| | | #endif |
| | | |
| | | #ifdef WITH_BROKER |
| | | static size_t mem_limit = 0; |
| | | void memory__set_limit(size_t lim) |
| | | { |
| | | mem_limit = lim; |
| | | } |
| | | #endif |
| | | |
| | | void *mosquitto__calloc(size_t nmemb, size_t size) |
| | | { |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem_limit && memcount + size > mem_limit){ |
| | | return NULL; |
| | | } |
| | | #endif |
| | | void *mem = calloc(nmemb, size); |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem){ |
| | | memcount += malloc_usable_size(mem); |
| | | if(memcount > max_memcount){ |
| | | max_memcount = memcount; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | return mem; |
| | | } |
| | | |
| | | void mosquitto__free(void *mem) |
| | | { |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(!mem){ |
| | | return; |
| | | } |
| | | memcount -= malloc_usable_size(mem); |
| | | #endif |
| | | free(mem); |
| | | } |
| | | |
| | | void *mosquitto__malloc(size_t size) |
| | | { |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem_limit && memcount + size > mem_limit){ |
| | | return NULL; |
| | | } |
| | | #endif |
| | | void *mem = malloc(size); |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem){ |
| | | memcount += malloc_usable_size(mem); |
| | | if(memcount > max_memcount){ |
| | | max_memcount = memcount; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | return mem; |
| | | } |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | unsigned long mosquitto__memory_used(void) |
| | | { |
| | | return memcount; |
| | | } |
| | | |
| | | unsigned long mosquitto__max_memory_used(void) |
| | | { |
| | | return max_memcount; |
| | | } |
| | | #endif |
| | | |
| | | void *mosquitto__realloc(void *ptr, size_t size) |
| | | { |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem_limit && memcount + size > mem_limit){ |
| | | return NULL; |
| | | } |
| | | #endif |
| | | void *mem; |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(ptr){ |
| | | memcount -= malloc_usable_size(ptr); |
| | | } |
| | | #endif |
| | | mem = realloc(ptr, size); |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem){ |
| | | memcount += malloc_usable_size(mem); |
| | | if(memcount > max_memcount){ |
| | | max_memcount = memcount; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | return mem; |
| | | } |
| | | |
| | | char *mosquitto__strdup(const char *s) |
| | | { |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(mem_limit && memcount + strlen(s) > mem_limit){ |
| | | return NULL; |
| | | } |
| | | #endif |
| | | char *str = strdup(s); |
| | | |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | if(str){ |
| | | memcount += malloc_usable_size(str); |
| | | if(memcount > max_memcount){ |
| | | max_memcount = memcount; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | return str; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 MEMORY_MOSQ_H |
| | | #define MEMORY_MOSQ_H |
| | | |
| | | #include <stdio.h> |
| | | #include <sys/types.h> |
| | | |
| | | #if defined(WITH_MEMORY_TRACKING) && defined(WITH_BROKER) && defined(__GLIBC__) |
| | | #define REAL_WITH_MEMORY_TRACKING |
| | | #endif |
| | | |
| | | void *mosquitto__calloc(size_t nmemb, size_t size); |
| | | void mosquitto__free(void *mem); |
| | | void *mosquitto__malloc(size_t size); |
| | | #ifdef REAL_WITH_MEMORY_TRACKING |
| | | unsigned long mosquitto__memory_used(void); |
| | | unsigned long mosquitto__max_memory_used(void); |
| | | #endif |
| | | void *mosquitto__realloc(void *ptr, size_t size); |
| | | char *mosquitto__strdup(const char *s); |
| | | |
| | | #ifdef WITH_BROKER |
| | | void memory__set_limit(size_t lim); |
| | | #endif |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include <assert.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <utlist.h> |
| | | |
| | | #include "mosquitto_internal.h" |
| | | #include "mosquitto.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "send_mosq.h" |
| | | #include "time_mosq.h" |
| | | #include "util_mosq.h" |
| | | |
| | | void message__cleanup(struct mosquitto_message_all **message) |
| | | { |
| | | struct mosquitto_message_all *msg; |
| | | |
| | | if(!message || !*message) return; |
| | | |
| | | msg = *message; |
| | | |
| | | mosquitto__free(msg->msg.topic); |
| | | mosquitto__free(msg->msg.payload); |
| | | mosquitto__free(msg); |
| | | } |
| | | |
| | | void message__cleanup_all(struct mosquitto *mosq) |
| | | { |
| | | struct mosquitto_message_all *tail, *tmp; |
| | | |
| | | assert(mosq); |
| | | |
| | | DL_FOREACH_SAFE(mosq->msgs_in.inflight, tail, tmp){ |
| | | DL_DELETE(mosq->msgs_in.inflight, tail); |
| | | message__cleanup(&tail); |
| | | } |
| | | DL_FOREACH_SAFE(mosq->msgs_out.inflight, tail, tmp){ |
| | | DL_DELETE(mosq->msgs_out.inflight, tail); |
| | | message__cleanup(&tail); |
| | | } |
| | | } |
| | | |
| | | int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src) |
| | | { |
| | | if(!dst || !src) return MOSQ_ERR_INVAL; |
| | | |
| | | dst->mid = src->mid; |
| | | dst->topic = mosquitto__strdup(src->topic); |
| | | if(!dst->topic) return MOSQ_ERR_NOMEM; |
| | | dst->qos = src->qos; |
| | | dst->retain = src->retain; |
| | | if(src->payloadlen){ |
| | | dst->payload = mosquitto__calloc(src->payloadlen+1, sizeof(uint8_t)); |
| | | if(!dst->payload){ |
| | | mosquitto__free(dst->topic); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | memcpy(dst->payload, src->payload, src->payloadlen); |
| | | dst->payloadlen = src->payloadlen; |
| | | }else{ |
| | | dst->payloadlen = 0; |
| | | dst->payload = NULL; |
| | | } |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos) |
| | | { |
| | | struct mosquitto_message_all *message; |
| | | int rc; |
| | | assert(mosq); |
| | | |
| | | rc = message__remove(mosq, mid, dir, &message, qos); |
| | | if(rc == MOSQ_ERR_SUCCESS){ |
| | | message__cleanup(&message); |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | void mosquitto_message_free(struct mosquitto_message **message) |
| | | { |
| | | struct mosquitto_message *msg; |
| | | |
| | | if(!message || !*message) return; |
| | | |
| | | msg = *message; |
| | | |
| | | mosquitto__free(msg->topic); |
| | | mosquitto__free(msg->payload); |
| | | mosquitto__free(msg); |
| | | } |
| | | |
| | | void mosquitto_message_free_contents(struct mosquitto_message *message) |
| | | { |
| | | if(!message) return; |
| | | |
| | | mosquitto__free(message->topic); |
| | | mosquitto__free(message->payload); |
| | | } |
| | | |
| | | int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir) |
| | | { |
| | | /* mosq->*_message_mutex should be locked before entering this function */ |
| | | assert(mosq); |
| | | assert(message); |
| | | assert(message->msg.qos != 0); |
| | | |
| | | if(dir == mosq_md_out){ |
| | | DL_APPEND(mosq->msgs_out.inflight, message); |
| | | mosq->msgs_out.queue_len++; |
| | | }else{ |
| | | DL_APPEND(mosq->msgs_in.inflight, message); |
| | | mosq->msgs_in.queue_len++; |
| | | } |
| | | |
| | | return message__release_to_inflight(mosq, dir); |
| | | } |
| | | |
| | | void message__reconnect_reset(struct mosquitto *mosq) |
| | | { |
| | | struct mosquitto_message_all *message, *tmp; |
| | | assert(mosq); |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_in.mutex); |
| | | mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum; |
| | | mosq->msgs_in.queue_len = 0; |
| | | DL_FOREACH_SAFE(mosq->msgs_in.inflight, message, tmp){ |
| | | mosq->msgs_in.queue_len++; |
| | | message->timestamp = 0; |
| | | if(message->msg.qos != 2){ |
| | | DL_DELETE(mosq->msgs_in.inflight, message); |
| | | message__cleanup(&message); |
| | | }else{ |
| | | /* Message state can be preserved here because it should match |
| | | * whatever the client has got. */ |
| | | util__decrement_receive_quota(mosq); |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; |
| | | mosq->msgs_out.queue_len = 0; |
| | | DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){ |
| | | mosq->msgs_out.queue_len++; |
| | | |
| | | message->timestamp = 0; |
| | | if(mosq->msgs_out.inflight_quota != 0){ |
| | | util__decrement_send_quota(mosq); |
| | | if(message->msg.qos == 1){ |
| | | message->state = mosq_ms_publish_qos1; |
| | | }else if(message->msg.qos == 2){ |
| | | if(message->state == mosq_ms_wait_for_pubrec){ |
| | | message->state = mosq_ms_publish_qos2; |
| | | }else if(message->state == mosq_ms_wait_for_pubcomp){ |
| | | message->state = mosq_ms_resend_pubrel; |
| | | } |
| | | /* Should be able to preserve state. */ |
| | | } |
| | | }else{ |
| | | message->state = mosq_ms_invalid; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | } |
| | | |
| | | |
| | | int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir) |
| | | { |
| | | /* mosq->*_message_mutex should be locked before entering this function */ |
| | | struct mosquitto_message_all *cur, *tmp; |
| | | int rc = MOSQ_ERR_SUCCESS; |
| | | |
| | | if(dir == mosq_md_out){ |
| | | DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){ |
| | | if(mosq->msgs_out.inflight_quota > 0){ |
| | | if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){ |
| | | if(cur->msg.qos == 1){ |
| | | cur->state = mosq_ms_wait_for_puback; |
| | | }else if(cur->msg.qos == 2){ |
| | | cur->state = mosq_ms_wait_for_pubrec; |
| | | } |
| | | rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL, 0); |
| | | if(rc){ |
| | | return rc; |
| | | } |
| | | util__decrement_send_quota(mosq); |
| | | } |
| | | }else{ |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return rc; |
| | | } |
| | | |
| | | |
| | | int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos) |
| | | { |
| | | struct mosquitto_message_all *cur, *tmp; |
| | | bool found = false; |
| | | assert(mosq); |
| | | assert(message); |
| | | |
| | | if(dir == mosq_md_out){ |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | |
| | | DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){ |
| | | if(found == false && cur->msg.mid == mid){ |
| | | if(cur->msg.qos != qos){ |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | DL_DELETE(mosq->msgs_out.inflight, cur); |
| | | |
| | | *message = cur; |
| | | mosq->msgs_out.queue_len--; |
| | | found = true; |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | if(found){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return MOSQ_ERR_NOT_FOUND; |
| | | } |
| | | }else{ |
| | | pthread_mutex_lock(&mosq->msgs_in.mutex); |
| | | DL_FOREACH_SAFE(mosq->msgs_in.inflight, cur, tmp){ |
| | | if(cur->msg.mid == mid){ |
| | | if(cur->msg.qos != qos){ |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | DL_DELETE(mosq->msgs_in.inflight, cur); |
| | | *message = cur; |
| | | mosq->msgs_in.queue_len--; |
| | | found = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | pthread_mutex_unlock(&mosq->msgs_in.mutex); |
| | | if(found){ |
| | | return MOSQ_ERR_SUCCESS; |
| | | }else{ |
| | | return MOSQ_ERR_NOT_FOUND; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void message__retry_check(struct mosquitto *mosq) |
| | | { |
| | | struct mosquitto_message_all *msg; |
| | | time_t now = mosquitto_time(); |
| | | assert(mosq); |
| | | |
| | | #ifdef WITH_THREADING |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | #endif |
| | | |
| | | DL_FOREACH(mosq->msgs_out.inflight, msg){ |
| | | switch(msg->state){ |
| | | case mosq_ms_publish_qos1: |
| | | case mosq_ms_publish_qos2: |
| | | msg->timestamp = now; |
| | | msg->dup = true; |
| | | send__publish(mosq, msg->msg.mid, msg->msg.topic, msg->msg.payloadlen, msg->msg.payload, msg->msg.qos, msg->msg.retain, msg->dup, NULL, NULL, 0); |
| | | break; |
| | | case mosq_ms_wait_for_pubrel: |
| | | msg->timestamp = now; |
| | | msg->dup = true; |
| | | send__pubrec(mosq, msg->msg.mid, 0); |
| | | break; |
| | | case mosq_ms_resend_pubrel: |
| | | case mosq_ms_wait_for_pubcomp: |
| | | msg->timestamp = now; |
| | | msg->dup = true; |
| | | send__pubrel(mosq, msg->msg.mid); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | #ifdef WITH_THREADING |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | #endif |
| | | } |
| | | |
| | | |
| | | void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry) |
| | | { |
| | | UNUSED(mosq); |
| | | UNUSED(message_retry); |
| | | } |
| | | |
| | | int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos) |
| | | { |
| | | struct mosquitto_message_all *message, *tmp; |
| | | assert(mosq); |
| | | |
| | | pthread_mutex_lock(&mosq->msgs_out.mutex); |
| | | DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){ |
| | | if(message->msg.mid == mid){ |
| | | if(message->msg.qos != qos){ |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_PROTOCOL; |
| | | } |
| | | message->state = state; |
| | | message->timestamp = mosquitto_time(); |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mosq->msgs_out.mutex); |
| | | return MOSQ_ERR_NOT_FOUND; |
| | | } |
| | | |
| | | int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages) |
| | | { |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | |
| | | mosq->send_maximum = max_inflight_messages; |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 MESSAGES_MOSQ_H |
| | | #define MESSAGES_MOSQ_H |
| | | |
| | | #include "mosquitto_internal.h" |
| | | #include "mosquitto.h" |
| | | |
| | | void message__cleanup_all(struct mosquitto *mosq); |
| | | void message__cleanup(struct mosquitto_message_all **message); |
| | | int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos); |
| | | int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir); |
| | | void message__reconnect_reset(struct mosquitto *mosq); |
| | | int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir); |
| | | int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos); |
| | | void message__retry_check(struct mosquitto *mosq); |
| | | int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 "config.h" |
| | | |
| | | #include <errno.h> |
| | | #include <signal.h> |
| | | #include <string.h> |
| | | #ifndef WIN32 |
| | | #include <sys/time.h> |
| | | #endif |
| | | |
| | | #include "mosquitto.h" |
| | | #include "mosquitto_internal.h" |
| | | #include "memory_mosq.h" |
| | | #include "messages_mosq.h" |
| | | #include "mqtt_protocol.h" |
| | | #include "net_mosq.h" |
| | | #include "packet_mosq.h" |
| | | #include "will_mosq.h" |
| | | |
| | | |
| | | void mosquitto__destroy(struct mosquitto *mosq); |
| | | |
| | | int mosquitto_lib_version(int *major, int *minor, int *revision) |
| | | { |
| | | if(major) *major = LIBMOSQUITTO_MAJOR; |
| | | if(minor) *minor = LIBMOSQUITTO_MINOR; |
| | | if(revision) *revision = LIBMOSQUITTO_REVISION; |
| | | return LIBMOSQUITTO_VERSION_NUMBER; |
| | | } |
| | | |
| | | int mosquitto_lib_init(void) |
| | | { |
| | | #ifdef WIN32 |
| | | srand(GetTickCount64()); |
| | | #elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK) |
| | | struct timespec tp; |
| | | |
| | | clock_gettime(CLOCK_MONOTONIC, &tp); |
| | | srand(tp.tv_nsec); |
| | | #elif defined(__APPLE__) |
| | | uint64_t ticks; |
| | | |
| | | ticks = mach_absolute_time(); |
| | | srand((unsigned int)ticks); |
| | | #else |
| | | struct timeval tv; |
| | | |
| | | gettimeofday(&tv, NULL); |
| | | srand(tv.tv_sec*1000 + tv.tv_usec/1000); |
| | | #endif |
| | | |
| | | return net__init(); |
| | | } |
| | | |
| | | int mosquitto_lib_cleanup(void) |
| | | { |
| | | net__cleanup(); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata) |
| | | { |
| | | struct mosquitto *mosq = NULL; |
| | | int rc; |
| | | |
| | | if(clean_start == false && id == NULL){ |
| | | errno = EINVAL; |
| | | return NULL; |
| | | } |
| | | |
| | | #ifndef WIN32 |
| | | signal(SIGPIPE, SIG_IGN); |
| | | #endif |
| | | |
| | | mosq = (struct mosquitto *)mosquitto__calloc(1, sizeof(struct mosquitto)); |
| | | if(mosq){ |
| | | mosq->sock = INVALID_SOCKET; |
| | | mosq->sockpairR = INVALID_SOCKET; |
| | | mosq->sockpairW = INVALID_SOCKET; |
| | | #ifdef WITH_THREADING |
| | | mosq->thread_id = pthread_self(); |
| | | #endif |
| | | rc = mosquitto_reinitialise(mosq, id, clean_start, userdata); |
| | | if(rc){ |
| | | mosquitto_destroy(mosq); |
| | | if(rc == MOSQ_ERR_INVAL){ |
| | | errno = EINVAL; |
| | | }else if(rc == MOSQ_ERR_NOMEM){ |
| | | errno = ENOMEM; |
| | | } |
| | | return NULL; |
| | | } |
| | | }else{ |
| | | errno = ENOMEM; |
| | | } |
| | | return mosq; |
| | | } |
| | | |
| | | int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_start, void *userdata) |
| | | { |
| | | if(!mosq) return MOSQ_ERR_INVAL; |
| | | |
| | | if(clean_start == false && id == NULL){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | |
| | | mosquitto__destroy(mosq); |
| | | memset(mosq, 0, sizeof(struct mosquitto)); |
| | | |
| | | if(userdata){ |
| | | mosq->userdata = userdata; |
| | | }else{ |
| | | mosq->userdata = mosq; |
| | | } |
| | | mosq->protocol = mosq_p_mqtt311; |
| | | mosq->sock = INVALID_SOCKET; |
| | | mosq->sockpairR = INVALID_SOCKET; |
| | | mosq->sockpairW = INVALID_SOCKET; |
| | | mosq->keepalive = 60; |
| | | mosq->clean_start = clean_start; |
| | | if(id){ |
| | | if(STREMPTY(id)){ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | if(mosquitto_validate_utf8(id, strlen(id))){ |
| | | return MOSQ_ERR_MALFORMED_UTF8; |
| | | } |
| | | mosq->id = mosquitto__strdup(id); |
| | | } |
| | | mosq->in_packet.payload = NULL; |
| | | packet__cleanup(&mosq->in_packet); |
| | | mosq->out_packet = NULL; |
| | | mosq->current_out_packet = NULL; |
| | | mosq->last_msg_in = mosquitto_time(); |
| | | mosq->next_msg_out = mosquitto_time() + mosq->keepalive; |
| | | mosq->ping_t = 0; |
| | | mosq->last_mid = 0; |
| | | mosq->state = mosq_cs_new; |
| | | mosq->maximum_qos = 2; |
| | | mosq->msgs_in.inflight_maximum = 20; |
| | | mosq->msgs_out.inflight_maximum = 20; |
| | | mosq->msgs_in.inflight_quota = 20; |
| | | mosq->msgs_out.inflight_quota = 20; |
| | | mosq->will = NULL; |
| | | mosq->on_connect = NULL; |
| | | mosq->on_publish = NULL; |
| | | mosq->on_message = NULL; |
| | | mosq->on_subscribe = NULL; |
| | | mosq->on_unsubscribe = NULL; |
| | | mosq->host = NULL; |
| | | mosq->port = 1883; |
| | | mosq->in_callback = false; |
| | | mosq->reconnect_delay = 1; |
| | | mosq->reconnect_delay_max = 1; |
| | | mosq->reconnect_exponential_backoff = false; |
| | | mosq->threaded = mosq_ts_none; |
| | | #ifdef WITH_TLS |
| | | mosq->ssl = NULL; |
| | | mosq->ssl_ctx = NULL; |
| | | mosq->tls_cert_reqs = SSL_VERIFY_PEER; |
| | | mosq->tls_insecure = false; |
| | | mosq->want_write = false; |
| | | mosq->tls_ocsp_required = false; |
| | | #endif |
| | | #ifdef WITH_THREADING |
| | | pthread_mutex_init(&mosq->callback_mutex, NULL); |
| | | pthread_mutex_init(&mosq->log_callback_mutex, NULL); |
| | | pthread_mutex_init(&mosq->state_mutex, NULL); |
| | | pthread_mutex_init(&mosq->out_packet_mutex, NULL); |
| | | pthread_mutex_init(&mosq->current_out_packet_mutex, NULL); |
| | | pthread_mutex_init(&mosq->msgtime_mutex, NULL); |
| | | pthread_mutex_init(&mosq->msgs_in.mutex, NULL); |
| | | pthread_mutex_init(&mosq->msgs_out.mutex, NULL); |
| | | pthread_mutex_init(&mosq->mid_mutex, NULL); |
| | | mosq->thread_id = pthread_self(); |
| | | #endif |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | |
| | | void mosquitto__destroy(struct mosquitto *mosq) |
| | | { |
| | | struct mosquitto__packet *packet; |
| | | if(!mosq) return; |
| | | |
| | | #ifdef WITH_THREADING |
| | | # ifdef HAVE_PTHREAD_CANCEL |
| | | if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){ |
| | | pthread_cancel(mosq->thread_id); |
| | | pthread_join(mosq->thread_id, NULL); |
| | | mosq->threaded = mosq_ts_none; |
| | | } |
| | | # endif |
| | | |
| | | if(mosq->id){ |
| | | /* If mosq->id is not NULL then the client has already been initialised |
| | | * and so the mutexes need destroying. If mosq->id is NULL, the mutexes |
| | | * haven't been initialised. */ |
| | | pthread_mutex_destroy(&mosq->callback_mutex); |
| | | pthread_mutex_destroy(&mosq->log_callback_mutex); |
| | | pthread_mutex_destroy(&mosq->state_mutex); |
| | | pthread_mutex_destroy(&mosq->out_packet_mutex); |
| | | pthread_mutex_destroy(&mosq->current_out_packet_mutex); |
| | | pthread_mutex_destroy(&mosq->msgtime_mutex); |
| | | pthread_mutex_destroy(&mosq->msgs_in.mutex); |
| | | pthread_mutex_destroy(&mosq->msgs_out.mutex); |
| | | pthread_mutex_destroy(&mosq->mid_mutex); |
| | | } |
| | | #endif |
| | | if(mosq->sock != INVALID_SOCKET){ |
| | | net__socket_close(mosq); |
| | | } |
| | | message__cleanup_all(mosq); |
| | | will__clear(mosq); |
| | | #ifdef WITH_TLS |
| | | if(mosq->ssl){ |
| | | SSL_free(mosq->ssl); |
| | | } |
| | | if(mosq->ssl_ctx){ |
| | | SSL_CTX_free(mosq->ssl_ctx); |
| | | } |
| | | mosquitto__free(mosq->tls_cafile); |
| | | mosquitto__free(mosq->tls_capath); |
| | | mosquitto__free(mosq->tls_certfile); |
| | | mosquitto__free(mosq->tls_keyfile); |
| | | if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL; |
| | | mosquitto__free(mosq->tls_version); |
| | | mosquitto__free(mosq->tls_ciphers); |
| | | mosquitto__free(mosq->tls_psk); |
| | | mosquitto__free(mosq->tls_psk_identity); |
| | | mosquitto__free(mosq->tls_alpn); |
| | | #endif |
| | | |
| | | mosquitto__free(mosq->address); |
| | | mosq->address = NULL; |
| | | |
| | | mosquitto__free(mosq->id); |
| | | mosq->id = NULL; |
| | | |
| | | mosquitto__free(mosq->username); |
| | | mosq->username = NULL; |
| | | |
| | | mosquitto__free(mosq->password); |
| | | mosq->password = NULL; |
| | | |
| | | mosquitto__free(mosq->host); |
| | | mosq->host = NULL; |
| | | |
| | | mosquitto__free(mosq->bind_address); |
| | | mosq->bind_address = NULL; |
| | | |
| | | /* Out packet cleanup */ |
| | | if(mosq->out_packet && !mosq->current_out_packet){ |
| | | mosq->current_out_packet = mosq->out_packet; |
| | | mosq->out_packet = mosq->out_packet->next; |
| | | } |
| | | while(mosq->current_out_packet){ |
| | | packet = mosq->current_out_packet; |
| | | /* Free data and reset values */ |
| | | mosq->current_out_packet = mosq->out_packet; |
| | | if(mosq->out_packet){ |
| | | mosq->out_packet = mosq->out_packet->next; |
| | | } |
| | | |
| | | packet__cleanup(packet); |
| | | mosquitto__free(packet); |
| | | } |
| | | |
| | | packet__cleanup(&mosq->in_packet); |
| | | if(mosq->sockpairR != INVALID_SOCKET){ |
| | | COMPAT_CLOSE(mosq->sockpairR); |
| | | mosq->sockpairR = INVALID_SOCKET; |
| | | } |
| | | if(mosq->sockpairW != INVALID_SOCKET){ |
| | | COMPAT_CLOSE(mosq->sockpairW); |
| | | mosq->sockpairW = INVALID_SOCKET; |
| | | } |
| | | } |
| | | |
| | | void mosquitto_destroy(struct mosquitto *mosq) |
| | | { |
| | | if(!mosq) return; |
| | | |
| | | mosquitto__destroy(mosq); |
| | | mosquitto__free(mosq); |
| | | } |
| | | |
| | | int mosquitto_socket(struct mosquitto *mosq) |
| | | { |
| | | if(!mosq) return INVALID_SOCKET; |
| | | return mosq->sock; |
| | | } |
| | | |
| | | |
| | | bool mosquitto_want_write(struct mosquitto *mosq) |
| | | { |
| | | bool result = false; |
| | | if(mosq->out_packet || mosq->current_out_packet){ |
| | | result = true; |
| | | } |
| | | #ifdef WITH_TLS |
| | | if(mosq->ssl){ |
| | | if (mosq->want_write) { |
| | | result = true; |
| | | }else if(mosq->want_connect){ |
| | | result = false; |
| | | } |
| | | } |
| | | #endif |
| | | return result; |
| | | } |
| | | |
| | | |
| | | const char *mosquitto_strerror(int mosq_errno) |
| | | { |
| | | switch(mosq_errno){ |
| | | case MOSQ_ERR_AUTH_CONTINUE: |
| | | return "Continue with authentication."; |
| | | case MOSQ_ERR_NO_SUBSCRIBERS: |
| | | return "No subscribers."; |
| | | case MOSQ_ERR_SUB_EXISTS: |
| | | return "Subscription already exists."; |
| | | case MOSQ_ERR_CONN_PENDING: |
| | | return "Connection pending."; |
| | | case MOSQ_ERR_SUCCESS: |
| | | return "No error."; |
| | | case MOSQ_ERR_NOMEM: |
| | | return "Out of memory."; |
| | | case MOSQ_ERR_PROTOCOL: |
| | | return "A network protocol error occurred when communicating with the broker."; |
| | | case MOSQ_ERR_INVAL: |
| | | return "Invalid function arguments provided."; |
| | | case MOSQ_ERR_NO_CONN: |
| | | return "The client is not currently connected."; |
| | | case MOSQ_ERR_CONN_REFUSED: |
| | | return "The connection was refused."; |
| | | case MOSQ_ERR_NOT_FOUND: |
| | | return "Message not found (internal error)."; |
| | | case MOSQ_ERR_CONN_LOST: |
| | | return "The connection was lost."; |
| | | case MOSQ_ERR_TLS: |
| | | return "A TLS error occurred."; |
| | | case MOSQ_ERR_PAYLOAD_SIZE: |
| | | return "Payload too large."; |
| | | case MOSQ_ERR_NOT_SUPPORTED: |
| | | return "This feature is not supported."; |
| | | case MOSQ_ERR_AUTH: |
| | | return "Authorisation failed."; |
| | | case MOSQ_ERR_ACL_DENIED: |
| | | return "Access denied by ACL."; |
| | | case MOSQ_ERR_UNKNOWN: |
| | | return "Unknown error."; |
| | | case MOSQ_ERR_ERRNO: |
| | | return strerror(errno); |
| | | case MOSQ_ERR_EAI: |
| | | return "Lookup error."; |
| | | case MOSQ_ERR_PROXY: |
| | | return "Proxy error."; |
| | | case MOSQ_ERR_MALFORMED_UTF8: |
| | | return "Malformed UTF-8"; |
| | | case MOSQ_ERR_DUPLICATE_PROPERTY: |
| | | return "Duplicate property in property list"; |
| | | case MOSQ_ERR_TLS_HANDSHAKE: |
| | | return "TLS handshake failed."; |
| | | case MOSQ_ERR_QOS_NOT_SUPPORTED: |
| | | return "Requested QoS not supported on server."; |
| | | case MOSQ_ERR_OVERSIZE_PACKET: |
| | | return "Packet larger than supported by the server."; |
| | | case MOSQ_ERR_OCSP: |
| | | return "OCSP error."; |
| | | default: |
| | | return "Unknown error."; |
| | | } |
| | | } |
| | | |
| | | const char *mosquitto_connack_string(int connack_code) |
| | | { |
| | | switch(connack_code){ |
| | | case 0: |
| | | return "Connection Accepted."; |
| | | case 1: |
| | | return "Connection Refused: unacceptable protocol version."; |
| | | case 2: |
| | | return "Connection Refused: identifier rejected."; |
| | | case 3: |
| | | return "Connection Refused: broker unavailable."; |
| | | case 4: |
| | | return "Connection Refused: bad user name or password."; |
| | | case 5: |
| | | return "Connection Refused: not authorised."; |
| | | default: |
| | | return "Connection Refused: unknown reason."; |
| | | } |
| | | } |
| | | |
| | | const char *mosquitto_reason_string(int reason_code) |
| | | { |
| | | switch(reason_code){ |
| | | case MQTT_RC_SUCCESS: |
| | | return "Success"; |
| | | case MQTT_RC_GRANTED_QOS1: |
| | | return "Granted QoS 1"; |
| | | case MQTT_RC_GRANTED_QOS2: |
| | | return "Granted QoS 2"; |
| | | case MQTT_RC_DISCONNECT_WITH_WILL_MSG: |
| | | return "Disconnect with Will Message"; |
| | | case MQTT_RC_NO_MATCHING_SUBSCRIBERS: |
| | | return "No matching subscribers"; |
| | | case MQTT_RC_NO_SUBSCRIPTION_EXISTED: |
| | | return "No subscription existed"; |
| | | case MQTT_RC_CONTINUE_AUTHENTICATION: |
| | | return "Continue authentication"; |
| | | case MQTT_RC_REAUTHENTICATE: |
| | | return "Re-authenticate"; |
| | | |
| | | case MQTT_RC_UNSPECIFIED: |
| | | return "Unspecified error"; |
| | | case MQTT_RC_MALFORMED_PACKET: |
| | | return "Malformed Packet"; |
| | | case MQTT_RC_PROTOCOL_ERROR: |
| | | return "Protocol Error"; |
| | | case MQTT_RC_IMPLEMENTATION_SPECIFIC: |
| | | return "Implementation specific error"; |
| | | case MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION: |
| | | return "Unsupported Protocol Version"; |
| | | case MQTT_RC_CLIENTID_NOT_VALID: |
| | | return "Client Identifier not valid"; |
| | | case MQTT_RC_BAD_USERNAME_OR_PASSWORD: |
| | | return "Bad User Name or Password"; |
| | | case MQTT_RC_NOT_AUTHORIZED: |
| | | return "Not authorized"; |
| | | case MQTT_RC_SERVER_UNAVAILABLE: |
| | | return "Server unavailable"; |
| | | case MQTT_RC_SERVER_BUSY: |
| | | return "Server busy"; |
| | | case MQTT_RC_BANNED: |
| | | return "Banned"; |
| | | case MQTT_RC_SERVER_SHUTTING_DOWN: |
| | | return "Server shutting down"; |
| | | case MQTT_RC_BAD_AUTHENTICATION_METHOD: |
| | | return "Bad authentication method"; |
| | | case MQTT_RC_KEEP_ALIVE_TIMEOUT: |
| | | return "Keep Alive timeout"; |
| | | case MQTT_RC_SESSION_TAKEN_OVER: |
| | | return "Session taken over"; |
| | | case MQTT_RC_TOPIC_FILTER_INVALID: |
| | | return "Topic Filter invalid"; |
| | | case MQTT_RC_TOPIC_NAME_INVALID: |
| | | return "Topic Name invalid"; |
| | | case MQTT_RC_PACKET_ID_IN_USE: |
| | | return "Packet Identifier in use"; |
| | | case MQTT_RC_PACKET_ID_NOT_FOUND: |
| | | return "Packet Identifier not found"; |
| | | case MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED: |
| | | return "Receive Maximum exceeded"; |
| | | case MQTT_RC_TOPIC_ALIAS_INVALID: |
| | | return "Topic Alias invalid"; |
| | | case MQTT_RC_PACKET_TOO_LARGE: |
| | | return "Packet too large"; |
| | | case MQTT_RC_MESSAGE_RATE_TOO_HIGH: |
| | | return "Message rate too high"; |
| | | case MQTT_RC_QUOTA_EXCEEDED: |
| | | return "Quota exceeded"; |
| | | case MQTT_RC_ADMINISTRATIVE_ACTION: |
| | | return "Administrative action"; |
| | | case MQTT_RC_PAYLOAD_FORMAT_INVALID: |
| | | return "Payload format invalid"; |
| | | case MQTT_RC_RETAIN_NOT_SUPPORTED: |
| | | return "Retain not supported"; |
| | | case MQTT_RC_QOS_NOT_SUPPORTED: |
| | | return "QoS not supported"; |
| | | case MQTT_RC_USE_ANOTHER_SERVER: |
| | | return "Use another server"; |
| | | case MQTT_RC_SERVER_MOVED: |
| | | return "Server moved"; |
| | | case MQTT_RC_SHARED_SUBS_NOT_SUPPORTED: |
| | | return "Shared Subscriptions not supported"; |
| | | case MQTT_RC_CONNECTION_RATE_EXCEEDED: |
| | | return "Connection rate exceeded"; |
| | | case MQTT_RC_MAXIMUM_CONNECT_TIME: |
| | | return "Maximum connect time"; |
| | | case MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED: |
| | | return "Subscription identifiers not supported"; |
| | | case MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED: |
| | | return "Wildcard Subscriptions not supported"; |
| | | default: |
| | | return "Unknown reason"; |
| | | } |
| | | } |
| | | |
| | | |
| | | int mosquitto_string_to_command(const char *str, int *cmd) |
| | | { |
| | | if(!strcasecmp(str, "connect")){ |
| | | *cmd = CMD_CONNECT; |
| | | }else if(!strcasecmp(str, "connack")){ |
| | | *cmd = CMD_CONNACK; |
| | | }else if(!strcasecmp(str, "publish")){ |
| | | *cmd = CMD_PUBLISH; |
| | | }else if(!strcasecmp(str, "puback")){ |
| | | *cmd = CMD_PUBACK; |
| | | }else if(!strcasecmp(str, "pubrec")){ |
| | | *cmd = CMD_PUBREC; |
| | | }else if(!strcasecmp(str, "pubrel")){ |
| | | *cmd = CMD_PUBREL; |
| | | }else if(!strcasecmp(str, "pubcomp")){ |
| | | *cmd = CMD_PUBCOMP; |
| | | }else if(!strcasecmp(str, "subscribe")){ |
| | | *cmd = CMD_SUBSCRIBE; |
| | | }else if(!strcasecmp(str, "unsubscribe")){ |
| | | *cmd = CMD_UNSUBSCRIBE; |
| | | }else if(!strcasecmp(str, "disconnect")){ |
| | | *cmd = CMD_DISCONNECT; |
| | | }else if(!strcasecmp(str, "auth")){ |
| | | *cmd = CMD_AUTH; |
| | | }else if(!strcasecmp(str, "will")){ |
| | | *cmd = CMD_WILL; |
| | | }else{ |
| | | return MOSQ_ERR_INVAL; |
| | | } |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | |
| | | int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count) |
| | | { |
| | | int len; |
| | | int hier_count = 1; |
| | | int start, stop; |
| | | int hier; |
| | | int tlen; |
| | | int i, j; |
| | | |
| | | if(!subtopic || !topics || !count) return MOSQ_ERR_INVAL; |
| | | |
| | | len = strlen(subtopic); |
| | | |
| | | for(i=0; i<len; i++){ |
| | | if(subtopic[i] == '/'){ |
| | | if(i > len-1){ |
| | | /* Separator at end of line */ |
| | | }else{ |
| | | hier_count++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | (*topics) = mosquitto__calloc(hier_count, sizeof(char *)); |
| | | if(!(*topics)) return MOSQ_ERR_NOMEM; |
| | | |
| | | start = 0; |
| | | stop = 0; |
| | | hier = 0; |
| | | |
| | | for(i=0; i<len+1; i++){ |
| | | if(subtopic[i] == '/' || subtopic[i] == '\0'){ |
| | | stop = i; |
| | | if(start != stop){ |
| | | tlen = stop-start + 1; |
| | | (*topics)[hier] = mosquitto__calloc(tlen, sizeof(char)); |
| | | if(!(*topics)[hier]){ |
| | | for(j=0; j<hier; j++){ |
| | | mosquitto__free((*topics)[j]); |
| | | } |
| | | mosquitto__free((*topics)); |
| | | return MOSQ_ERR_NOMEM; |
| | | } |
| | | for(j=start; j<stop; j++){ |
| | | (*topics)[hier][j-start] = subtopic[j]; |
| | | } |
| | | } |
| | | start = i+1; |
| | | hier++; |
| | | } |
| | | } |
| | | |
| | | *count = hier_count; |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
| | | int mosquitto_sub_topic_tokens_free(char ***topics, int count) |
| | | { |
| | | int i; |
| | | |
| | | if(!topics || !(*topics) || count<1) return MOSQ_ERR_INVAL; |
| | | |
| | | for(i=0; i<count; i++){ |
| | | mosquitto__free((*topics)[i]); |
| | | } |
| | | mosquitto__free(*topics); |
| | | |
| | | return MOSQ_ERR_SUCCESS; |
| | | } |
| | | |
New file |
| | |
| | | /* |
| | | Copyright (c) 2010-2019 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 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 MOSQUITTO_H |
| | | #define MOSQUITTO_H |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #if defined(WIN32) && !defined(WITH_BROKER) && !defined(LIBMOSQUITTO_STATIC) |
| | | # ifdef libmosquitto_EXPORTS |
| | | # define libmosq_EXPORT __declspec(dllexport) |
| | | # else |
| | | # define libmosq_EXPORT __declspec(dllimport) |
| | | # endif |
| | | #else |
| | | # define libmosq_EXPORT |
| | | #endif |
| | | |
| | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
| | | # ifndef __cplusplus |
| | | # define bool char |
| | | # define true 1 |
| | | # define false 0 |
| | | # endif |
| | | #else |
| | | # ifndef __cplusplus |
| | | # include <stdbool.h> |
| | | # endif |
| | | #endif |
| | | |
| | | #include <stddef.h> |
| | | #include <stdint.h> |
| | | |
| | | #define LIBMOSQUITTO_MAJOR 1 |
| | | #define LIBMOSQUITTO_MINOR 6 |
| | | #define LIBMOSQUITTO_REVISION 3 |
| | | /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ |
| | | #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) |
| | | |
| | | /* Log types */ |
| | | #define MOSQ_LOG_NONE 0 |
| | | #define MOSQ_LOG_INFO (1<<0) |
| | | #define MOSQ_LOG_NOTICE (1<<1) |
| | | #define MOSQ_LOG_WARNING (1<<2) |
| | | #define MOSQ_LOG_ERR (1<<3) |
| | | #define MOSQ_LOG_DEBUG (1<<4) |
| | | #define MOSQ_LOG_SUBSCRIBE (1<<5) |
| | | #define MOSQ_LOG_UNSUBSCRIBE (1<<6) |
| | | #define MOSQ_LOG_WEBSOCKETS (1<<7) |
| | | #define MOSQ_LOG_INTERNAL 0x80000000 |
| | | #define MOSQ_LOG_ALL 0x7FFFFFFF |
| | | |
| | | /* Error values */ |
| | | enum mosq_err_t { |
| | | MOSQ_ERR_AUTH_CONTINUE = -4, |
| | | MOSQ_ERR_NO_SUBSCRIBERS = -3, |
| | | MOSQ_ERR_SUB_EXISTS = -2, |
| | | MOSQ_ERR_CONN_PENDING = -1, |
| | | MOSQ_ERR_SUCCESS = 0, |
| | | MOSQ_ERR_NOMEM = 1, |
| | | MOSQ_ERR_PROTOCOL = 2, |
| | | MOSQ_ERR_INVAL = 3, |
| | | MOSQ_ERR_NO_CONN = 4, |
| | | MOSQ_ERR_CONN_REFUSED = 5, |
| | | MOSQ_ERR_NOT_FOUND = 6, |
| | | MOSQ_ERR_CONN_LOST = 7, |
| | | MOSQ_ERR_TLS = 8, |
| | | MOSQ_ERR_PAYLOAD_SIZE = 9, |
| | | MOSQ_ERR_NOT_SUPPORTED = 10, |
| | | MOSQ_ERR_AUTH = 11, |
| | | MOSQ_ERR_ACL_DENIED = 12, |
| | | MOSQ_ERR_UNKNOWN = 13, |
| | | MOSQ_ERR_ERRNO = 14, |
| | | MOSQ_ERR_EAI = 15, |
| | | MOSQ_ERR_PROXY = 16, |
| | | MOSQ_ERR_PLUGIN_DEFER = 17, |
| | | MOSQ_ERR_MALFORMED_UTF8 = 18, |
| | | MOSQ_ERR_KEEPALIVE = 19, |
| | | MOSQ_ERR_LOOKUP = 20, |
| | | MOSQ_ERR_MALFORMED_PACKET = 21, |
| | | MOSQ_ERR_DUPLICATE_PROPERTY = 22, |
| | | MOSQ_ERR_TLS_HANDSHAKE = 23, |
| | | MOSQ_ERR_QOS_NOT_SUPPORTED = 24, |
| | | MOSQ_ERR_OVERSIZE_PACKET = 25, |
| | | MOSQ_ERR_OCSP = 26, |
| | | }; |
| | | |
| | | /* Option values */ |
| | | enum mosq_opt_t { |
| | | MOSQ_OPT_PROTOCOL_VERSION = 1, |
| | | MOSQ_OPT_SSL_CTX = 2, |
| | | MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3, |
| | | MOSQ_OPT_RECEIVE_MAXIMUM = 4, |
| | | MOSQ_OPT_SEND_MAXIMUM = 5, |
| | | MOSQ_OPT_TLS_KEYFORM = 6, |
| | | MOSQ_OPT_TLS_ENGINE = 7, |
| | | MOSQ_OPT_TLS_ENGINE_KPASS_SHA1 = 8, |
| | | MOSQ_OPT_TLS_OCSP_REQUIRED = 9, |
| | | MOSQ_OPT_TLS_ALPN = 10, |
| | | }; |
| | | |
| | | |
| | | /* MQTT specification restricts client ids to a maximum of 23 characters */ |
| | | #define MOSQ_MQTT_ID_MAX_LENGTH 23 |
| | | |
| | | #define MQTT_PROTOCOL_V31 3 |
| | | #define MQTT_PROTOCOL_V311 4 |
| | | #define MQTT_PROTOCOL_V5 5 |
| | | |
| | | struct mosquitto_message{ |
| | | int mid; |
| | | char *topic; |
| | | void *payload; |
| | | int payloadlen; |
| | | int qos; |
| | | bool retain; |
| | | }; |
| | | |
| | | struct mosquitto; |
| | | typedef struct mqtt5__property mosquitto_property; |
| | | |
| | | /* |
| | | * Topic: Threads |
| | | * libmosquitto provides thread safe operation, with the exception of |
| | | * <mosquitto_lib_init> which is not thread safe. |
| | | * |
| | | * If your application uses threads you must use <mosquitto_threaded_set> to |
| | | * tell the library this is the case, otherwise it makes some optimisations |
| | | * for the single threaded case that may result in unexpected behaviour for |
| | | * the multi threaded case. |
| | | */ |
| | | /*************************************************** |
| | | * Important note |
| | | * |
| | | * The following functions that deal with network operations will return |
| | | * MOSQ_ERR_SUCCESS on success, but this does not mean that the operation has |
| | | * taken place. An attempt will be made to write the network data, but if the |
| | | * socket is not available for writing at that time then the packet will not be |
| | | * sent. To ensure the packet is sent, call mosquitto_loop() (which must also |
| | | * be called to process incoming network data). |
| | | * This is especially important when disconnecting a client that has a will. If |
| | | * the broker does not receive the DISCONNECT command, it will assume that the |
| | | * client has disconnected unexpectedly and send the will. |
| | | * |
| | | * mosquitto_connect() |
| | | * mosquitto_disconnect() |
| | | * mosquitto_subscribe() |
| | | * mosquitto_unsubscribe() |
| | | * mosquitto_publish() |
| | | ***************************************************/ |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Library version, init, and cleanup |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_lib_version |
| | | * |
| | | * Can be used to obtain version information for the mosquitto library. |
| | | * This allows the application to compare the library version against the |
| | | * version it was compiled against by using the LIBMOSQUITTO_MAJOR, |
| | | * LIBMOSQUITTO_MINOR and LIBMOSQUITTO_REVISION defines. |
| | | * |
| | | * Parameters: |
| | | * major - an integer pointer. If not NULL, the major version of the |
| | | * library will be returned in this variable. |
| | | * minor - an integer pointer. If not NULL, the minor version of the |
| | | * library will be returned in this variable. |
| | | * revision - an integer pointer. If not NULL, the revision of the library will |
| | | * be returned in this variable. |
| | | * |
| | | * Returns: |
| | | * LIBMOSQUITTO_VERSION_NUMBER, which is a unique number based on the major, |
| | | * minor and revision values. |
| | | * See Also: |
| | | * <mosquitto_lib_cleanup>, <mosquitto_lib_init> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_lib_version(int *major, int *minor, int *revision); |
| | | |
| | | /* |
| | | * Function: mosquitto_lib_init |
| | | * |
| | | * Must be called before any other mosquitto functions. |
| | | * |
| | | * This function is *not* thread safe. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - always |
| | | * |
| | | * See Also: |
| | | * <mosquitto_lib_cleanup>, <mosquitto_lib_version> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_lib_init(void); |
| | | |
| | | /* |
| | | * Function: mosquitto_lib_cleanup |
| | | * |
| | | * Call to free resources associated with the library. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - always |
| | | * |
| | | * See Also: |
| | | * <mosquitto_lib_init>, <mosquitto_lib_version> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_lib_cleanup(void); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Client creation, destruction, and reinitialisation |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_new |
| | | * |
| | | * Create a new mosquitto client instance. |
| | | * |
| | | * Parameters: |
| | | * id - String to use as the client id. If NULL, a random client id |
| | | * will be generated. If id is NULL, clean_session must be true. |
| | | * clean_session - set to true to instruct the broker to clean all messages |
| | | * and subscriptions on disconnect, false to instruct it to |
| | | * keep them. See the man page mqtt(7) for more details. |
| | | * Note that a client will never discard its own outgoing |
| | | * messages on disconnect. Calling <mosquitto_connect> or |
| | | * <mosquitto_reconnect> will cause the messages to be resent. |
| | | * Use <mosquitto_reinitialise> to reset a client to its |
| | | * original state. |
| | | * Must be set to true if the id parameter is NULL. |
| | | * obj - A user pointer that will be passed as an argument to any |
| | | * callbacks that are specified. |
| | | * |
| | | * Returns: |
| | | * Pointer to a struct mosquitto on success. |
| | | * NULL on failure. Interrogate errno to determine the cause for the failure: |
| | | * - ENOMEM on out of memory. |
| | | * - EINVAL on invalid input parameters. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_reinitialise>, <mosquitto_destroy>, <mosquitto_user_data_set> |
| | | */ |
| | | libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj); |
| | | |
| | | /* |
| | | * Function: mosquitto_destroy |
| | | * |
| | | * Use to free memory associated with a mosquitto client instance. |
| | | * |
| | | * Parameters: |
| | | * mosq - a struct mosquitto pointer to free. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_new>, <mosquitto_reinitialise> |
| | | */ |
| | | libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_reinitialise |
| | | * |
| | | * This function allows an existing mosquitto client to be reused. Call on a |
| | | * mosquitto instance to close any open network connections, free memory |
| | | * and reinitialise the client with the new parameters. The end result is the |
| | | * same as the output of <mosquitto_new>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * id - string to use as the client id. If NULL, a random client id |
| | | * will be generated. If id is NULL, clean_session must be true. |
| | | * clean_session - set to true to instruct the broker to clean all messages |
| | | * and subscriptions on disconnect, false to instruct it to |
| | | * keep them. See the man page mqtt(7) for more details. |
| | | * Must be set to true if the id parameter is NULL. |
| | | * obj - A user pointer that will be passed as an argument to any |
| | | * callbacks that are specified. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_new>, <mosquitto_destroy> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *obj); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Will |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_will_set |
| | | * |
| | | * Configure will information for a mosquitto instance. By default, clients do |
| | | * not have a will. This must be called before calling <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * topic - the topic on which to publish the will. |
| | | * payloadlen - the size of the payload (bytes). Valid values are between 0 and |
| | | * 268,435,455. |
| | | * payload - pointer to the data to send. If payloadlen > 0 this must be a |
| | | * valid memory location. |
| | | * qos - integer value 0, 1 or 2 indicating the Quality of Service to be |
| | | * used for the will. |
| | | * retain - set to true to make the will a retained message. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); |
| | | |
| | | /* |
| | | * Function: mosquitto_will_set_v5 |
| | | * |
| | | * Configure will information for a mosquitto instance, with attached |
| | | * properties. By default, clients do not have a will. This must be called |
| | | * before calling <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * topic - the topic on which to publish the will. |
| | | * payloadlen - the size of the payload (bytes). Valid values are between 0 and |
| | | * 268,435,455. |
| | | * payload - pointer to the data to send. If payloadlen > 0 this must be a |
| | | * valid memory location. |
| | | * qos - integer value 0, 1 or 2 indicating the Quality of Service to be |
| | | * used for the will. |
| | | * retain - set to true to make the will a retained message. |
| | | * properties - list of MQTT 5 properties. Can be NULL. On success only, the |
| | | * property list becomes the property of libmosquitto once this |
| | | * function is called and will be freed by the library. The |
| | | * property list must be freed by the application on error. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8. |
| | | * MOSQ_ERR_NOT_SUPPORTED - if properties is not NULL and the client is not |
| | | * using MQTT v5 |
| | | * MOSQ_ERR_PROTOCOL - if a property is invalid for use with wills. |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_will_clear |
| | | * |
| | | * Remove a previously configured will. This must be called before calling |
| | | * <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Username and password |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_username_pw_set |
| | | * |
| | | * Configure username and password for a mosquitton instance. This is only |
| | | * supported by brokers that implement the MQTT spec v3.1. By default, no |
| | | * username or password will be sent. |
| | | * If username is NULL, the password argument is ignored. |
| | | * This must be called before calling mosquitto_connect(). |
| | | * |
| | | * This is must be called before calling <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * username - the username to send as a string, or NULL to disable |
| | | * authentication. |
| | | * password - the password to send as a string. Set to NULL when username is |
| | | * valid in order to send just a username. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Connecting, reconnecting, disconnecting |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_connect |
| | | * |
| | | * Connect to an MQTT broker. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * port - the network port to connect to. Usually 1883. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect_bind>, <mosquitto_connect_async>, <mosquitto_reconnect>, <mosquitto_disconnect>, <mosquitto_tls_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_bind |
| | | * |
| | | * Connect to an MQTT broker. This extends the functionality of |
| | | * <mosquitto_connect> by adding the bind_address parameter. Use this function |
| | | * if you need to restrict network communication over a particular interface. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * port - the network port to connect to. Usually 1883. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * bind_address - the hostname or ip address of the local network interface to |
| | | * bind to. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect>, <mosquitto_connect_async>, <mosquitto_connect_bind_async> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_bind_v5 |
| | | * |
| | | * Connect to an MQTT broker. This extends the functionality of |
| | | * <mosquitto_connect> by adding the bind_address parameter. Use this function |
| | | * if you need to restrict network communication over a particular interface. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * port - the network port to connect to. Usually 1883. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * bind_address - the hostname or ip address of the local network interface to |
| | | * bind to. |
| | | * properties - the MQTT 5 properties for the connect (not for the Will). |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid for use with CONNECT. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect>, <mosquitto_connect_async>, <mosquitto_connect_bind_async> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_async |
| | | * |
| | | * Connect to an MQTT broker. This is a non-blocking call. If you use |
| | | * <mosquitto_connect_async> your client must use the threaded interface |
| | | * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use |
| | | * <mosquitto_connect> to connect the client. |
| | | * |
| | | * May be called before or after <mosquitto_loop_start>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * port - the network port to connect to. Usually 1883. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect_bind_async>, <mosquitto_connect>, <mosquitto_reconnect>, <mosquitto_disconnect>, <mosquitto_tls_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_bind_async |
| | | * |
| | | * Connect to an MQTT broker. This is a non-blocking call. If you use |
| | | * <mosquitto_connect_bind_async> your client must use the threaded interface |
| | | * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use |
| | | * <mosquitto_connect> to connect the client. |
| | | * |
| | | * This extends the functionality of <mosquitto_connect_async> by adding the |
| | | * bind_address parameter. Use this function if you need to restrict network |
| | | * communication over a particular interface. |
| | | * |
| | | * May be called before or after <mosquitto_loop_start>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * port - the network port to connect to. Usually 1883. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * bind_address - the hostname or ip address of the local network interface to |
| | | * bind to. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect_async>, <mosquitto_connect>, <mosquitto_connect_bind> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_srv |
| | | * |
| | | * Connect to an MQTT broker. This is a non-blocking call. If you use |
| | | * <mosquitto_connect_async> your client must use the threaded interface |
| | | * <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use |
| | | * <mosquitto_connect> to connect the client. |
| | | * |
| | | * This extends the functionality of <mosquitto_connect_async> by adding the |
| | | * bind_address parameter. Use this function if you need to restrict network |
| | | * communication over a particular interface. |
| | | * |
| | | * May be called before or after <mosquitto_loop_start>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the hostname or ip address of the broker to connect to. |
| | | * keepalive - the number of seconds after which the broker should send a PING |
| | | * message to the client if no other messages have been exchanged |
| | | * in that time. |
| | | * bind_address - the hostname or ip address of the local network interface to |
| | | * bind to. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect_async>, <mosquitto_connect>, <mosquitto_connect_bind> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address); |
| | | |
| | | /* |
| | | * Function: mosquitto_reconnect |
| | | * |
| | | * Reconnect to a broker. |
| | | * |
| | | * This function provides an easy way of reconnecting to a broker after a |
| | | * connection has been lost. It uses the values that were provided in the |
| | | * <mosquitto_connect> call. It must not be called before |
| | | * <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect>, <mosquitto_disconnect>, <mosquitto_reconnect_async> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_reconnect(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_reconnect_async |
| | | * |
| | | * Reconnect to a broker. Non blocking version of <mosquitto_reconnect>. |
| | | * |
| | | * This function provides an easy way of reconnecting to a broker after a |
| | | * connection has been lost. It uses the values that were provided in the |
| | | * <mosquitto_connect> or <mosquitto_connect_async> calls. It must not be |
| | | * called before <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect>, <mosquitto_disconnect> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_disconnect |
| | | * |
| | | * Disconnect from the broker. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_disconnect_v5 |
| | | * |
| | | * Disconnect from the broker, with attached MQTT properties. |
| | | * |
| | | * Use <mosquitto_property_add_*> to create a list of properties, then attach |
| | | * them to this publish. Properties need freeing with |
| | | * <mosquitto_property_free_all>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * reason_code - the disconnect reason code. |
| | | * properties - a valid mosquitto_property list, or NULL. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Publishing, subscribing, unsubscribing |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_publish |
| | | * |
| | | * Publish a message on a given topic. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - pointer to an int. If not NULL, the function will set this |
| | | * to the message id of this particular message. This can be then |
| | | * used with the publish callback to determine when the message |
| | | * has been sent. |
| | | * Note that although the MQTT protocol doesn't use message ids |
| | | * for messages with QoS=0, libmosquitto assigns them message ids |
| | | * so they can be tracked with this parameter. |
| | | * topic - null terminated string of the topic to publish to. |
| | | * payloadlen - the size of the payload (bytes). Valid values are between 0 and |
| | | * 268,435,455. |
| | | * payload - pointer to the data to send. If payloadlen > 0 this must be a |
| | | * valid memory location. |
| | | * qos - integer value 0, 1 or 2 indicating the Quality of Service to be |
| | | * used for the message. |
| | | * retain - set to true to make the message retained. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by |
| | | * the broker. |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_max_inflight_messages_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_publish_v5 |
| | | * |
| | | * Publish a message on a given topic, with attached MQTT properties. |
| | | * |
| | | * Use <mosquitto_property_add_*> to create a list of properties, then attach |
| | | * them to this publish. Properties need freeing with |
| | | * <mosquitto_property_free_all>. |
| | | * |
| | | * Requires the mosquitto instance to be connected with MQTT 5. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - pointer to an int. If not NULL, the function will set this |
| | | * to the message id of this particular message. This can be then |
| | | * used with the publish callback to determine when the message |
| | | * has been sent. |
| | | * Note that although the MQTT protocol doesn't use message ids |
| | | * for messages with QoS=0, libmosquitto assigns them message ids |
| | | * so they can be tracked with this parameter. |
| | | * topic - null terminated string of the topic to publish to. |
| | | * payloadlen - the size of the payload (bytes). Valid values are between 0 and |
| | | * 268,435,455. |
| | | * payload - pointer to the data to send. If payloadlen > 0 this must be a |
| | | * valid memory location. |
| | | * qos - integer value 0, 1 or 2 indicating the Quality of Service to be |
| | | * used for the message. |
| | | * retain - set to true to make the message retained. |
| | | * properties - a valid mosquitto_property list, or NULL. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. |
| | | * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by |
| | | * the broker. |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_publish_v5( |
| | | struct mosquitto *mosq, |
| | | int *mid, |
| | | const char *topic, |
| | | int payloadlen, |
| | | const void *payload, |
| | | int qos, |
| | | bool retain, |
| | | const mosquitto_property *properties); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe |
| | | * |
| | | * Subscribe to a topic. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the subscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub - the subscription pattern. |
| | | * qos - the requested Quality of Service for this subscription. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_v5 |
| | | * |
| | | * Subscribe to a topic, with attached MQTT properties. |
| | | * |
| | | * Use <mosquitto_property_add_*> to create a list of properties, then attach |
| | | * them to this subscribe. Properties need freeing with |
| | | * <mosquitto_property_free_all>. |
| | | * |
| | | * Requires the mosquitto instance to be connected with MQTT 5. |
| | | * |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the subscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub - the subscription pattern. |
| | | * qos - the requested Quality of Service for this subscription. |
| | | * options - options to apply to this subscription, OR'd together. Set to 0 to |
| | | * use the default options, otherwise choose from the list: |
| | | * MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client |
| | | * publishes to a topic to which it is subscribed, the |
| | | * broker will not publish the message back to the |
| | | * client. |
| | | * MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages |
| | | * published for this subscription will keep the |
| | | * retain flag as was set by the publishing client. |
| | | * The default behaviour without this option set has |
| | | * the retain flag indicating whether a message is |
| | | * fresh/stale. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set, |
| | | * pre-existing retained messages are sent as soon as |
| | | * the subscription is made, even if the subscription |
| | | * already exists. This is the default behaviour, so |
| | | * it is not necessary to set this option. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing |
| | | * retained messages for this subscription will be |
| | | * sent when the subscription is made, but only if the |
| | | * subscription does not already exist. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set, |
| | | * pre-existing retained messages will never be sent |
| | | * for this subscription. |
| | | * properties - a valid mosquitto_property list, or NULL. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_multiple |
| | | * |
| | | * Subscribe to multiple topics. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the subscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub_count - the count of subscriptions to be made |
| | | * sub - array of sub_count pointers, each pointing to a subscription string. |
| | | * The "char *const *const" datatype ensures that neither the array of |
| | | * pointers nor the strings that they point to are mutable. If you aren't |
| | | * familiar with this, just think of it as a safer "char **", |
| | | * equivalent to "const char *" for a simple string pointer. |
| | | * qos - the requested Quality of Service for each subscription. |
| | | * options - options to apply to this subscription, OR'd together. Set to 0 to |
| | | * use the default options, otherwise choose from the list: |
| | | * MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client |
| | | * publishes to a topic to which it is subscribed, the |
| | | * broker will not publish the message back to the |
| | | * client. |
| | | * MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages |
| | | * published for this subscription will keep the |
| | | * retain flag as was set by the publishing client. |
| | | * The default behaviour without this option set has |
| | | * the retain flag indicating whether a message is |
| | | * fresh/stale. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set, |
| | | * pre-existing retained messages are sent as soon as |
| | | * the subscription is made, even if the subscription |
| | | * already exists. This is the default behaviour, so |
| | | * it is not necessary to set this option. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing |
| | | * retained messages for this subscription will be |
| | | * sent when the subscription is made, but only if the |
| | | * subscription does not already exist. |
| | | * MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set, |
| | | * pre-existing retained messages will never be sent |
| | | * for this subscription. |
| | | * properties - a valid mosquitto_property list, or NULL. Only used with MQTT |
| | | * v5 clients. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_unsubscribe |
| | | * |
| | | * Unsubscribe from a topic. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the unsubscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub - the unsubscription pattern. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); |
| | | |
| | | /* |
| | | * Function: mosquitto_unsubscribe_v5 |
| | | * |
| | | * Unsubscribe from a topic, with attached MQTT properties. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the unsubscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub - the unsubscription pattern. |
| | | * properties - a valid mosquitto_property list, or NULL. Only used with MQTT |
| | | * v5 clients. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE. |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_unsubscribe_multiple |
| | | * |
| | | * Unsubscribe from multiple topics. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * mid - a pointer to an int. If not NULL, the function will set this to |
| | | * the message id of this particular message. This can be then used |
| | | * with the subscribe callback to determine when the message has been |
| | | * sent. |
| | | * sub_count - the count of unsubscriptions to be made |
| | | * sub - array of sub_count pointers, each pointing to an unsubscription string. |
| | | * The "char *const *const" datatype ensures that neither the array of |
| | | * pointers nor the strings that they point to are mutable. If you aren't |
| | | * familiar with this, just think of it as a safer "char **", |
| | | * equivalent to "const char *" for a simple string pointer. |
| | | * properties - a valid mosquitto_property list, or NULL. Only used with MQTT |
| | | * v5 clients. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 |
| | | * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than |
| | | * supported by the broker. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Struct mosquitto_message helper functions |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_message_copy |
| | | * |
| | | * Copy the contents of a mosquitto message to another message. |
| | | * Useful for preserving a message received in the on_message() callback. |
| | | * |
| | | * Parameters: |
| | | * dst - a pointer to a valid mosquitto_message struct to copy to. |
| | | * src - a pointer to a valid mosquitto_message struct to copy from. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_message_free> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src); |
| | | |
| | | /* |
| | | * Function: mosquitto_message_free |
| | | * |
| | | * Completely free a mosquitto_message struct. |
| | | * |
| | | * Parameters: |
| | | * message - pointer to a mosquitto_message pointer to free. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_message_copy>, <mosquitto_message_free_contents> |
| | | */ |
| | | libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message); |
| | | |
| | | /* |
| | | * Function: mosquitto_message_free_contents |
| | | * |
| | | * Free a mosquitto_message struct contents, leaving the struct unaffected. |
| | | * |
| | | * Parameters: |
| | | * message - pointer to a mosquitto_message struct to free its contents. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_message_copy>, <mosquitto_message_free> |
| | | */ |
| | | libmosq_EXPORT void mosquitto_message_free_contents(struct mosquitto_message *message); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Network loop (managed by libmosquitto) |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_loop |
| | | * |
| | | * The main network loop for the client. You must call this frequently in order |
| | | * to keep communications between the client and broker working. If incoming |
| | | * data is present it will then be processed. Outgoing commands, from e.g. |
| | | * <mosquitto_publish>, are normally sent immediately that their function is |
| | | * called, but this is not always possible. <mosquitto_loop> will also attempt |
| | | * to send any remaining outgoing messages, which also includes commands that |
| | | * are part of the flow for messages with QoS>0. |
| | | * |
| | | * An alternative approach is to use <mosquitto_loop_start> to run the client |
| | | * loop in its own thread. |
| | | * |
| | | * This calls select() to monitor the client network socket. If you want to |
| | | * integrate mosquitto client operation with your own select() call, use |
| | | * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> and |
| | | * <mosquitto_loop_misc>. |
| | | * |
| | | * Threads: |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * timeout - Maximum number of milliseconds to wait for network activity |
| | | * in the select() call before timing out. Set to 0 for instant |
| | | * return. Set negative to use the default of 1000ms. |
| | | * max_packets - this parameter is currently unused and should be set to 1 for |
| | | * future compatibility. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * See Also: |
| | | * <mosquitto_loop_forever>, <mosquitto_loop_start>, <mosquitto_loop_stop> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets); |
| | | |
| | | /* |
| | | * Function: mosquitto_loop_forever |
| | | * |
| | | * This function call loop() for you in an infinite blocking loop. It is useful |
| | | * for the case where you only want to run the MQTT client loop in your |
| | | * program. |
| | | * |
| | | * It handles reconnecting in case server connection is lost. If you call |
| | | * mosquitto_disconnect() in a callback it will return. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * timeout - Maximum number of milliseconds to wait for network activity |
| | | * in the select() call before timing out. Set to 0 for instant |
| | | * return. Set negative to use the default of 1000ms. |
| | | * max_packets - this parameter is currently unused and should be set to 1 for |
| | | * future compatibility. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_loop>, <mosquitto_loop_start> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets); |
| | | |
| | | /* |
| | | * Function: mosquitto_loop_start |
| | | * |
| | | * This is part of the threaded client interface. Call this once to start a new |
| | | * thread to process network traffic. This provides an alternative to |
| | | * repeatedly calling <mosquitto_loop> yourself. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_connect_async>, <mosquitto_loop>, <mosquitto_loop_forever>, <mosquitto_loop_stop> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_loop_stop |
| | | * |
| | | * This is part of the threaded client interface. Call this once to stop the |
| | | * network thread previously created with <mosquitto_loop_start>. This call |
| | | * will block until the network thread finishes. For the network thread to end, |
| | | * you must have previously called <mosquitto_disconnect> or have set the force |
| | | * parameter to true. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * force - set to true to force thread cancellation. If false, |
| | | * <mosquitto_disconnect> must have already been called. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_loop>, <mosquitto_loop_start> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Network loop (for use in other event loops) |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_loop_read |
| | | * |
| | | * Carry out network read operations. |
| | | * This should only be used if you are not using mosquitto_loop() and are |
| | | * monitoring the client network socket for activity yourself. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * max_packets - this parameter is currently unused and should be set to 1 for |
| | | * future compatibility. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_socket>, <mosquitto_loop_write>, <mosquitto_loop_misc> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_read(struct mosquitto *mosq, int max_packets); |
| | | |
| | | /* |
| | | * Function: mosquitto_loop_write |
| | | * |
| | | * Carry out network write operations. |
| | | * This should only be used if you are not using mosquitto_loop() and are |
| | | * monitoring the client network socket for activity yourself. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * max_packets - this parameter is currently unused and should be set to 1 for |
| | | * future compatibility. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. |
| | | * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the |
| | | * broker. |
| | | * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno |
| | | * contains the error code, even on Windows. |
| | | * Use strerror_r() where available or FormatMessage() on |
| | | * Windows. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_misc>, <mosquitto_want_write> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets); |
| | | |
| | | /* |
| | | * Function: mosquitto_loop_misc |
| | | * |
| | | * Carry out miscellaneous operations required as part of the network loop. |
| | | * This should only be used if you are not using mosquitto_loop() and are |
| | | * monitoring the client network socket for activity yourself. |
| | | * |
| | | * This function deals with handling PINGs and checking whether messages need |
| | | * to be retried, so should be called fairly frequently. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_loop_misc(struct mosquitto *mosq); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Network loop (helper functions) |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_socket |
| | | * |
| | | * Return the socket handle for a mosquitto instance. Useful if you want to |
| | | * include a mosquitto client in your own select() calls. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * The socket for the mosquitto client or -1 on failure. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_want_write |
| | | * |
| | | * Returns true if there is data ready to be written on the socket. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> |
| | | */ |
| | | libmosq_EXPORT bool mosquitto_want_write(struct mosquitto *mosq); |
| | | |
| | | /* |
| | | * Function: mosquitto_threaded_set |
| | | * |
| | | * Used to tell the library that your application is using threads, but not |
| | | * using <mosquitto_loop_start>. The library operates slightly differently when |
| | | * not in threaded mode in order to simplify its operation. If you are managing |
| | | * your own threads and do not use this function you will experience crashes |
| | | * due to race conditions. |
| | | * |
| | | * When using <mosquitto_loop_start>, this is set automatically. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * threaded - true if your application is using threads, false otherwise. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Client options |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_opts_set |
| | | * |
| | | * Used to set options for the client. |
| | | * |
| | | * This function is deprecated, the replacement <mosquitto_int_option> and |
| | | * <mosquitto_void_option> functions should be used instead. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * option - the option to set. |
| | | * value - the option specific value. |
| | | * |
| | | * Options: |
| | | * MOSQ_OPT_PROTOCOL_VERSION |
| | | * Value must be an int, set to either MQTT_PROTOCOL_V31 or |
| | | * MQTT_PROTOCOL_V311. Must be set before the client connects. |
| | | * Defaults to MQTT_PROTOCOL_V31. |
| | | * |
| | | * MOSQ_OPT_SSL_CTX |
| | | * Pass an openssl SSL_CTX to be used when creating TLS connections |
| | | * rather than libmosquitto creating its own. This must be called |
| | | * before connecting to have any effect. If you use this option, the |
| | | * onus is on you to ensure that you are using secure settings. |
| | | * Setting to NULL means that libmosquitto will use its own SSL_CTX |
| | | * if TLS is to be used. |
| | | * This option is only available for openssl 1.1.0 and higher. |
| | | * |
| | | * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS |
| | | * Value must be an int set to 1 or 0. If set to 1, then the user |
| | | * specified SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the |
| | | * default options applied to it. This means that you only need to |
| | | * change the values that are relevant to you. If you use this |
| | | * option then you must configure the TLS options as normal, i.e. |
| | | * you should use <mosquitto_tls_set> to configure the cafile/capath |
| | | * as a minimum. |
| | | * This option is only available for openssl 1.1.0 and higher. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); |
| | | |
| | | /* |
| | | * Function: mosquitto_int_option |
| | | * |
| | | * Used to set integer options for the client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * option - the option to set. |
| | | * value - the option specific value. |
| | | * |
| | | * Options: |
| | | * MOSQ_OPT_PROTOCOL_VERSION |
| | | * Value must be set to either MQTT_PROTOCOL_V31, |
| | | * MQTT_PROTOCOL_V311, or MQTT_PROTOCOL_V5. Must be set before the |
| | | * client connects. Defaults to MQTT_PROTOCOL_V311. |
| | | * |
| | | * MOSQ_OPT_RECEIVE_MAXIMUM |
| | | * Value can be set between 1 and 65535 inclusive, and represents |
| | | * the maximum number of incoming QoS 1 and QoS 2 messages that this |
| | | * client wants to process at once. Defaults to 20. This option is |
| | | * not valid for MQTT v3.1 or v3.1.1 clients. |
| | | * Note that if the MQTT_PROP_RECEIVE_MAXIMUM property is in the |
| | | * proplist passed to mosquitto_connect_v5(), then that property |
| | | * will override this option. Using this option is the recommended |
| | | * method however. |
| | | * |
| | | * MOSQ_OPT_SEND_MAXIMUM |
| | | * Value can be set between 1 and 65535 inclusive, and represents |
| | | * the maximum number of outgoing QoS 1 and QoS 2 messages that this |
| | | * client will attempt to have "in flight" at once. Defaults to 20. |
| | | * This option is not valid for MQTT v3.1 or v3.1.1 clients. |
| | | * Note that if the broker being connected to sends a |
| | | * MQTT_PROP_RECEIVE_MAXIMUM property that has a lower value than |
| | | * this option, then the broker provided value will be used. |
| | | * |
| | | * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS |
| | | * If value is set to a non zero value, then the user specified |
| | | * SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the default |
| | | * options applied to it. This means that you only need to change |
| | | * the values that are relevant to you. If you use this option then |
| | | * you must configure the TLS options as normal, i.e. you should |
| | | * use <mosquitto_tls_set> to configure the cafile/capath as a |
| | | * minimum. |
| | | * This option is only available for openssl 1.1.0 and higher. |
| | | * MOSQ_OPT_TLS_OCSP_REQUIRED |
| | | * Set whether OCSP checking on TLS connections is required. Set to |
| | | * 1 to enable checking, or 0 (the default) for no checking. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_void_option |
| | | * |
| | | * Used to set void* options for the client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * option - the option to set. |
| | | * value - the option specific value. |
| | | * |
| | | * Options: |
| | | * MOSQ_OPT_SSL_CTX |
| | | * Pass an openssl SSL_CTX to be used when creating TLS connections |
| | | * rather than libmosquitto creating its own. This must be called |
| | | * before connecting to have any effect. If you use this option, the |
| | | * onus is on you to ensure that you are using secure settings. |
| | | * Setting to NULL means that libmosquitto will use its own SSL_CTX |
| | | * if TLS is to be used. |
| | | * This option is only available for openssl 1.1.0 and higher. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_reconnect_delay_set |
| | | * |
| | | * Control the behaviour of the client when it has unexpectedly disconnected in |
| | | * <mosquitto_loop_forever> or after <mosquitto_loop_start>. The default |
| | | * behaviour if this function is not used is to repeatedly attempt to reconnect |
| | | * with a delay of 1 second until the connection succeeds. |
| | | * |
| | | * Use reconnect_delay parameter to change the delay between successive |
| | | * reconnection attempts. You may also enable exponential backoff of the time |
| | | * between reconnections by setting reconnect_exponential_backoff to true and |
| | | * set an upper bound on the delay with reconnect_delay_max. |
| | | * |
| | | * Example 1: |
| | | * delay=2, delay_max=10, exponential_backoff=False |
| | | * Delays would be: 2, 4, 6, 8, 10, 10, ... |
| | | * |
| | | * Example 2: |
| | | * delay=3, delay_max=30, exponential_backoff=True |
| | | * Delays would be: 3, 6, 12, 24, 30, 30, ... |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * reconnect_delay - the number of seconds to wait between |
| | | * reconnects. |
| | | * reconnect_delay_max - the maximum number of seconds to wait |
| | | * between reconnects. |
| | | * reconnect_exponential_backoff - use exponential backoff between |
| | | * reconnect attempts. Set to true to enable |
| | | * exponential backoff. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); |
| | | |
| | | /* |
| | | * Function: mosquitto_max_inflight_messages_set |
| | | * |
| | | * This function is deprected. Use the <mosquitto_int_option> function with the |
| | | * MOSQ_OPT_SEND_MAXIMUM option instead. |
| | | * |
| | | * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. |
| | | * An in flight message is part way through its delivery flow. Attempts to send |
| | | * further messages with <mosquitto_publish> will result in the messages being |
| | | * queued until the number of in flight messages reduces. |
| | | * |
| | | * A higher number here results in greater message throughput, but if set |
| | | * higher than the maximum in flight messages on the broker may lead to |
| | | * delays in the messages being acknowledged. |
| | | * |
| | | * Set to 0 for no maximum. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * max_inflight_messages - the maximum number of inflight messages. Defaults |
| | | * to 20. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages); |
| | | |
| | | /* |
| | | * Function: mosquitto_message_retry_set |
| | | * |
| | | * This function now has no effect. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry); |
| | | |
| | | /* |
| | | * Function: mosquitto_user_data_set |
| | | * |
| | | * When <mosquitto_new> is called, the pointer given as the "obj" parameter |
| | | * will be passed to the callbacks as user data. The <mosquitto_user_data_set> |
| | | * function allows this obj parameter to be updated at any time. This function |
| | | * will not modify the memory pointed to by the current user data pointer. If |
| | | * it is dynamically allocated memory you must free it yourself. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * obj - A user pointer that will be passed as an argument to any callbacks |
| | | * that are specified. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); |
| | | |
| | | /* Function: mosquitto_userdata |
| | | * |
| | | * Retrieve the "userdata" variable for a mosquitto client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * |
| | | * Returns: |
| | | * A pointer to the userdata member variable. |
| | | */ |
| | | libmosq_EXPORT void *mosquitto_userdata(struct mosquitto *mosq); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: TLS support |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_tls_set |
| | | * |
| | | * Configure the client for certificate based SSL/TLS support. Must be called |
| | | * before <mosquitto_connect>. |
| | | * |
| | | * Cannot be used in conjunction with <mosquitto_tls_psk_set>. |
| | | * |
| | | * Define the Certificate Authority certificates to be trusted (ie. the server |
| | | * certificate must be signed with one of these certificates) using cafile. |
| | | * |
| | | * If the server you are connecting to requires clients to provide a |
| | | * certificate, define certfile and keyfile with your client certificate and |
| | | * private key. If your private key is encrypted, provide a password callback |
| | | * function or you will have to enter the password at the command line. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * cafile - path to a file containing the PEM encoded trusted CA |
| | | * certificate files. Either cafile or capath must not be NULL. |
| | | * capath - path to a directory containing the PEM encoded trusted CA |
| | | * certificate files. See mosquitto.conf for more details on |
| | | * configuring this directory. Either cafile or capath must not |
| | | * be NULL. |
| | | * certfile - path to a file containing the PEM encoded certificate file |
| | | * for this client. If NULL, keyfile must also be NULL and no |
| | | * client certificate will be used. |
| | | * keyfile - path to a file containing the PEM encoded private key for |
| | | * this client. If NULL, certfile must also be NULL and no |
| | | * client certificate will be used. |
| | | * pw_callback - if keyfile is encrypted, set pw_callback to allow your client |
| | | * to pass the correct password for decryption. If set to NULL, |
| | | * the password must be entered on the command line. |
| | | * Your callback must write the password into "buf", which is |
| | | * "size" bytes long. The return value must be the length of the |
| | | * password. "userdata" will be set to the calling mosquitto |
| | | * instance. The mosquitto userdata member variable can be |
| | | * retrieved using <mosquitto_userdata>. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_tls_opts_set>, <mosquitto_tls_psk_set>, |
| | | * <mosquitto_tls_insecure_set>, <mosquitto_userdata> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_tls_set(struct mosquitto *mosq, |
| | | const char *cafile, const char *capath, |
| | | const char *certfile, const char *keyfile, |
| | | int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)); |
| | | |
| | | /* |
| | | * Function: mosquitto_tls_insecure_set |
| | | * |
| | | * Configure verification of the server hostname in the server certificate. If |
| | | * value is set to true, it is impossible to guarantee that the host you are |
| | | * connecting to is not impersonating your server. This can be useful in |
| | | * initial server testing, but makes it possible for a malicious third party to |
| | | * impersonate your server through DNS spoofing, for example. |
| | | * Do not use this function in a real system. Setting value to true makes the |
| | | * connection encryption pointless. |
| | | * Must be called before <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * value - if set to false, the default, certificate hostname checking is |
| | | * performed. If set to true, no hostname checking is performed and |
| | | * the connection is insecure. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_tls_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value); |
| | | |
| | | /* |
| | | * Function: mosquitto_tls_opts_set |
| | | * |
| | | * Set advanced SSL/TLS options. Must be called before <mosquitto_connect>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * cert_reqs - an integer defining the verification requirements the client |
| | | * will impose on the server. This can be one of: |
| | | * * SSL_VERIFY_NONE (0): the server will not be verified in any way. |
| | | * * SSL_VERIFY_PEER (1): the server certificate will be verified |
| | | * and the connection aborted if the verification fails. |
| | | * The default and recommended value is SSL_VERIFY_PEER. Using |
| | | * SSL_VERIFY_NONE provides no security. |
| | | * tls_version - the version of the SSL/TLS protocol to use as a string. If NULL, |
| | | * the default value is used. The default value and the |
| | | * available values depend on the version of openssl that the |
| | | * library was compiled against. For openssl >= 1.0.1, the |
| | | * available options are tlsv1.2, tlsv1.1 and tlsv1, with tlv1.2 |
| | | * as the default. For openssl < 1.0.1, only tlsv1 is available. |
| | | * ciphers - a string describing the ciphers available for use. See the |
| | | * "openssl ciphers" tool for more information. If NULL, the |
| | | * default ciphers will be used. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_tls_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers); |
| | | |
| | | /* |
| | | * Function: mosquitto_tls_psk_set |
| | | * |
| | | * Configure the client for pre-shared-key based TLS support. Must be called |
| | | * before <mosquitto_connect>. |
| | | * |
| | | * Cannot be used in conjunction with <mosquitto_tls_set>. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * psk - the pre-shared-key in hex format with no leading "0x". |
| | | * identity - the identity of this client. May be used as the username |
| | | * depending on the server settings. |
| | | * ciphers - a string describing the PSK ciphers available for use. See the |
| | | * "openssl ciphers" tool for more information. If NULL, the |
| | | * default ciphers will be used. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_tls_set> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers); |
| | | |
| | | |
| | | /* ====================================================================== |
| | | * |
| | | * Section: Callbacks |
| | | * |
| | | * ====================================================================== */ |
| | | /* |
| | | * Function: mosquitto_connect_callback_set |
| | | * |
| | | * Set the connect callback. This is called when the broker sends a CONNACK |
| | | * message in response to a connection. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_connect - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int rc) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * rc - the return code of the connection response, one of: |
| | | * |
| | | * * 0 - success |
| | | * * 1 - connection refused (unacceptable protocol version) |
| | | * * 2 - connection refused (identifier rejected) |
| | | * * 3 - connection refused (broker unavailable) |
| | | * * 4-255 - reserved for future use |
| | | */ |
| | | libmosq_EXPORT void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int)); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_with_flags_callback_set |
| | | * |
| | | * Set the connect callback. This is called when the broker sends a CONNACK |
| | | * message in response to a connection. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_connect - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int rc) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * rc - the return code of the connection response, one of: |
| | | * flags - the connect flags. |
| | | * |
| | | * * 0 - success |
| | | * * 1 - connection refused (unacceptable protocol version) |
| | | * * 2 - connection refused (identifier rejected) |
| | | * * 3 - connection refused (broker unavailable) |
| | | * * 4-255 - reserved for future use |
| | | */ |
| | | libmosq_EXPORT void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int)); |
| | | |
| | | /* |
| | | * Function: mosquitto_connect_v5_callback_set |
| | | * |
| | | * Set the connect callback. This is called when the broker sends a CONNACK |
| | | * message in response to a connection. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_connect - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int rc) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * rc - the return code of the connection response, one of: |
| | | * * 0 - success |
| | | * * 1 - connection refused (unacceptable protocol version) |
| | | * * 2 - connection refused (identifier rejected) |
| | | * * 3 - connection refused (broker unavailable) |
| | | * * 4-255 - reserved for future use |
| | | * flags - the connect flags. |
| | | * props - list of MQTT 5 properties, or NULL |
| | | * |
| | | */ |
| | | libmosq_EXPORT void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *props)); |
| | | |
| | | /* |
| | | * Function: mosquitto_disconnect_callback_set |
| | | * |
| | | * Set the disconnect callback. This is called when the broker has received the |
| | | * DISCONNECT command and has disconnected the client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_disconnect - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * rc - integer value indicating the reason for the disconnect. A value of 0 |
| | | * means the client has called <mosquitto_disconnect>. Any other value |
| | | * indicates that the disconnect is unexpected. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)); |
| | | |
| | | /* |
| | | * Function: mosquitto_disconnect_v5_callback_set |
| | | * |
| | | * Set the disconnect callback. This is called when the broker has received the |
| | | * DISCONNECT command and has disconnected the client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_disconnect - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * rc - integer value indicating the reason for the disconnect. A value of 0 |
| | | * means the client has called <mosquitto_disconnect>. Any other value |
| | | * indicates that the disconnect is unexpected. |
| | | * props - list of MQTT 5 properties, or NULL |
| | | */ |
| | | libmosq_EXPORT void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_publish_callback_set |
| | | * |
| | | * Set the publish callback. This is called when a message initiated with |
| | | * <mosquitto_publish> has been sent to the broker successfully. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_publish - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the sent message. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)); |
| | | |
| | | /* |
| | | * Function: mosquitto_publish_v5_callback_set |
| | | * |
| | | * Set the publish callback. This is called when a message initiated with |
| | | * <mosquitto_publish> has been sent to the broker. This callback will be |
| | | * called both if the message is sent successfully, or if the broker responded |
| | | * with an error, which will be reflected in the reason_code parameter. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_publish - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the sent message. |
| | | * reason_code - the MQTT 5 reason code |
| | | * props - list of MQTT 5 properties, or NULL |
| | | */ |
| | | libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_message_callback_set |
| | | * |
| | | * Set the message callback. This is called when a message is received from the |
| | | * broker. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_message - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * message - the message data. This variable and associated memory will be |
| | | * freed by the library after the callback completes. The client |
| | | * should make copies of any of the data it requires. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_message_copy> |
| | | */ |
| | | libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_message_v5_callback_set |
| | | * |
| | | * Set the message callback. This is called when a message is received from the |
| | | * broker. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_message - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * message - the message data. This variable and associated memory will be |
| | | * freed by the library after the callback completes. The client |
| | | * should make copies of any of the data it requires. |
| | | * props - list of MQTT 5 properties, or NULL |
| | | * |
| | | * See Also: |
| | | * <mosquitto_message_copy> |
| | | */ |
| | | libmosq_EXPORT void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_callback_set |
| | | * |
| | | * Set the subscribe callback. This is called when the broker responds to a |
| | | * subscription request. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_subscribe - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the subscribe message. |
| | | * qos_count - the number of granted subscriptions (size of granted_qos). |
| | | * granted_qos - an array of integers indicating the granted QoS for each of |
| | | * the subscriptions. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_v5_callback_set |
| | | * |
| | | * Set the subscribe callback. This is called when the broker responds to a |
| | | * subscription request. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_subscribe - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the subscribe message. |
| | | * qos_count - the number of granted subscriptions (size of granted_qos). |
| | | * granted_qos - an array of integers indicating the granted QoS for each of |
| | | * the subscriptions. |
| | | * props - list of MQTT 5 properties, or NULL |
| | | */ |
| | | libmosq_EXPORT void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_unsubscribe_callback_set |
| | | * |
| | | * Set the unsubscribe callback. This is called when the broker responds to a |
| | | * unsubscription request. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_unsubscribe - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the unsubscribe message. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)); |
| | | |
| | | /* |
| | | * Function: mosquitto_unsubscribe_v5_callback_set |
| | | * |
| | | * Set the unsubscribe callback. This is called when the broker responds to a |
| | | * unsubscription request. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * on_unsubscribe - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int mid) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * mid - the message id of the unsubscribe message. |
| | | * props - list of MQTT 5 properties, or NULL |
| | | */ |
| | | libmosq_EXPORT void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_log_callback_set |
| | | * |
| | | * Set the logging callback. This should be used if you want event logging |
| | | * information from the client library. |
| | | * |
| | | * mosq - a valid mosquitto instance. |
| | | * on_log - a callback function in the following form: |
| | | * void callback(struct mosquitto *mosq, void *obj, int level, const char *str) |
| | | * |
| | | * Callback Parameters: |
| | | * mosq - the mosquitto instance making the callback. |
| | | * obj - the user data provided in <mosquitto_new> |
| | | * level - the log message level from the values: |
| | | * MOSQ_LOG_INFO |
| | | * MOSQ_LOG_NOTICE |
| | | * MOSQ_LOG_WARNING |
| | | * MOSQ_LOG_ERR |
| | | * MOSQ_LOG_DEBUG |
| | | * str - the message string. |
| | | */ |
| | | libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)); |
| | | |
| | | /* |
| | | * Function: mosquitto_string_option |
| | | * |
| | | * Used to set const char* options for the client. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * option - the option to set. |
| | | * value - the option specific value. |
| | | * |
| | | * Options: |
| | | * MOSQ_OPT_TLS_ENGINE |
| | | * Configure the client for TLS Engine support. Pass a TLS Engine ID |
| | | * to be used when creating TLS connections. |
| | | * Must be set before <mosquitto_connect>. |
| | | * MOSQ_OPT_TLS_KEYFORM |
| | | * Configure the client to treat the keyfile differently depending |
| | | * on its type. Must be set before <mosquitto_connect>. |
| | | * Set as either "pem" or "engine", to determine from where the |
| | | * private key for a TLS connection will be obtained. Defaults to |
| | | * "pem", a normal private key file. |
| | | * MOSQ_OPT_TLS_KPASS_SHA1 |
| | | * Where the TLS Engine requires the use of a password to be |
| | | * accessed, this option allows a hex encoded SHA1 hash of the |
| | | * private key password to be passed to the engine directly. |
| | | * Must be set before <mosquitto_connect>. |
| | | * MOSQ_OPT_TLS_ALPN |
| | | * If the broker being connected to has multiple services available |
| | | * on a single TLS port, such as both MQTT and WebSockets, use this |
| | | * option to configure the ALPN option for the connection. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_reconnect_delay_set |
| | | * |
| | | * Control the behaviour of the client when it has unexpectedly disconnected in |
| | | * <mosquitto_loop_forever> or after <mosquitto_loop_start>. The default |
| | | * behaviour if this function is not used is to repeatedly attempt to reconnect |
| | | * with a delay of 1 second until the connection succeeds. |
| | | * |
| | | * Use reconnect_delay parameter to change the delay between successive |
| | | * reconnection attempts. You may also enable exponential backoff of the time |
| | | * between reconnections by setting reconnect_exponential_backoff to true and |
| | | * set an upper bound on the delay with reconnect_delay_max. |
| | | * |
| | | * Example 1: |
| | | * delay=2, delay_max=10, exponential_backoff=False |
| | | * Delays would be: 2, 4, 6, 8, 10, 10, ... |
| | | * |
| | | * Example 2: |
| | | * delay=3, delay_max=30, exponential_backoff=True |
| | | * Delays would be: 3, 6, 12, 24, 30, 30, ... |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * reconnect_delay - the number of seconds to wait between |
| | | * reconnects. |
| | | * reconnect_delay_max - the maximum number of seconds to wait |
| | | * between reconnects. |
| | | * reconnect_exponential_backoff - use exponential backoff between |
| | | * reconnect attempts. Set to true to enable |
| | | * exponential backoff. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success. |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); |
| | | |
| | | |
| | | /* ============================================================================= |
| | | * |
| | | * Section: SOCKS5 proxy functions |
| | | * |
| | | * ============================================================================= |
| | | */ |
| | | |
| | | /* |
| | | * Function: mosquitto_socks5_set |
| | | * |
| | | * Configure the client to use a SOCKS5 proxy when connecting. Must be called |
| | | * before connecting. "None" and "username/password" authentication is |
| | | * supported. |
| | | * |
| | | * Parameters: |
| | | * mosq - a valid mosquitto instance. |
| | | * host - the SOCKS5 proxy host to connect to. |
| | | * port - the SOCKS5 proxy port to use. |
| | | * username - if not NULL, use this username when authenticating with the proxy. |
| | | * password - if not NULL and username is not NULL, use this password when |
| | | * authenticating with the proxy. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password); |
| | | |
| | | |
| | | /* ============================================================================= |
| | | * |
| | | * Section: Utility functions |
| | | * |
| | | * ============================================================================= |
| | | */ |
| | | |
| | | /* |
| | | * Function: mosquitto_strerror |
| | | * |
| | | * Call to obtain a const string description of a mosquitto error number. |
| | | * |
| | | * Parameters: |
| | | * mosq_errno - a mosquitto error number. |
| | | * |
| | | * Returns: |
| | | * A constant string describing the error. |
| | | */ |
| | | libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno); |
| | | |
| | | /* |
| | | * Function: mosquitto_connack_string |
| | | * |
| | | * Call to obtain a const string description of an MQTT connection result. |
| | | * |
| | | * Parameters: |
| | | * connack_code - an MQTT connection result. |
| | | * |
| | | * Returns: |
| | | * A constant string describing the result. |
| | | */ |
| | | libmosq_EXPORT const char *mosquitto_connack_string(int connack_code); |
| | | |
| | | /* |
| | | * Function: mosquitto_reason_string |
| | | * |
| | | * Call to obtain a const string description of an MQTT reason code. |
| | | * |
| | | * Parameters: |
| | | * reason_code - an MQTT reason code. |
| | | * |
| | | * Returns: |
| | | * A constant string describing the reason. |
| | | */ |
| | | libmosq_EXPORT const char *mosquitto_reason_string(int reason_code); |
| | | |
| | | /* Function: mosquitto_string_to_command |
| | | * |
| | | * Take a string input representing an MQTT command and convert it to the |
| | | * libmosquitto integer representation. |
| | | * |
| | | * Parameters: |
| | | * str - the string to parse. |
| | | * cmd - pointer to an int, for the result. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - on an invalid input. |
| | | * |
| | | * Example: |
| | | * mosquitto_string_to_command("CONNECT", &cmd); |
| | | * // cmd == CMD_CONNECT |
| | | */ |
| | | libmosq_EXPORT int mosquitto_string_to_command(const char *str, int *cmd); |
| | | |
| | | /* |
| | | * Function: mosquitto_sub_topic_tokenise |
| | | * |
| | | * Tokenise a topic or subscription string into an array of strings |
| | | * representing the topic hierarchy. |
| | | * |
| | | * For example: |
| | | * |
| | | * subtopic: "a/deep/topic/hierarchy" |
| | | * |
| | | * Would result in: |
| | | * |
| | | * topics[0] = "a" |
| | | * topics[1] = "deep" |
| | | * topics[2] = "topic" |
| | | * topics[3] = "hierarchy" |
| | | * |
| | | * and: |
| | | * |
| | | * subtopic: "/a/deep/topic/hierarchy/" |
| | | * |
| | | * Would result in: |
| | | * |
| | | * topics[0] = NULL |
| | | * topics[1] = "a" |
| | | * topics[2] = "deep" |
| | | * topics[3] = "topic" |
| | | * topics[4] = "hierarchy" |
| | | * |
| | | * Parameters: |
| | | * subtopic - the subscription/topic to tokenise |
| | | * topics - a pointer to store the array of strings |
| | | * count - an int pointer to store the number of items in the topics array. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 |
| | | * |
| | | * Example: |
| | | * |
| | | * > char **topics; |
| | | * > int topic_count; |
| | | * > int i; |
| | | * > |
| | | * > mosquitto_sub_topic_tokenise("$SYS/broker/uptime", &topics, &topic_count); |
| | | * > |
| | | * > for(i=0; i<token_count; i++){ |
| | | * > printf("%d: %s\n", i, topics[i]); |
| | | * > } |
| | | * |
| | | * See Also: |
| | | * <mosquitto_sub_topic_tokens_free> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count); |
| | | |
| | | /* |
| | | * Function: mosquitto_sub_topic_tokens_free |
| | | * |
| | | * Free memory that was allocated in <mosquitto_sub_topic_tokenise>. |
| | | * |
| | | * Parameters: |
| | | * topics - pointer to string array. |
| | | * count - count of items in string array. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * |
| | | * See Also: |
| | | * <mosquitto_sub_topic_tokenise> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count); |
| | | |
| | | /* |
| | | * Function: mosquitto_topic_matches_sub |
| | | * Function: mosquitto_topic_matches_sub2 |
| | | * |
| | | * Check whether a topic matches a subscription. |
| | | * |
| | | * For example: |
| | | * |
| | | * foo/bar would match the subscription foo/# or +/bar |
| | | * non/matching would not match the subscription non/+/+ |
| | | * |
| | | * Parameters: |
| | | * sub - subscription string to check topic against. |
| | | * sublen - length in bytes of sub string |
| | | * topic - topic to check. |
| | | * topiclen - length in bytes of topic string |
| | | * result - bool pointer to hold result. Will be set to true if the topic |
| | | * matches the subscription. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if the input parameters were invalid. |
| | | * MOSQ_ERR_NOMEM - if an out of memory condition occurred. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result); |
| | | libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result); |
| | | |
| | | /* |
| | | * Function: mosquitto_pub_topic_check |
| | | * |
| | | * Check whether a topic to be used for publishing is valid. |
| | | * |
| | | * This searches for + or # in a topic and checks its length. |
| | | * |
| | | * This check is already carried out in <mosquitto_publish> and |
| | | * <mosquitto_will_set>, there is no need to call it directly before them. It |
| | | * may be useful if you wish to check the validity of a topic in advance of |
| | | * making a connection for example. |
| | | * |
| | | * Parameters: |
| | | * topic - the topic to check |
| | | * topiclen - length of the topic in bytes |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - for a valid topic |
| | | * MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if sub or topic is not valid UTF-8 |
| | | * |
| | | * See Also: |
| | | * <mosquitto_sub_topic_check> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic); |
| | | libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen); |
| | | |
| | | /* |
| | | * Function: mosquitto_sub_topic_check |
| | | * |
| | | * Check whether a topic to be used for subscribing is valid. |
| | | * |
| | | * This searches for + or # in a topic and checks that they aren't in invalid |
| | | * positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its |
| | | * length. |
| | | * |
| | | * This check is already carried out in <mosquitto_subscribe> and |
| | | * <mosquitto_unsubscribe>, there is no need to call it directly before them. |
| | | * It may be useful if you wish to check the validity of a topic in advance of |
| | | * making a connection for example. |
| | | * |
| | | * Parameters: |
| | | * topic - the topic to check |
| | | * topiclen - the length in bytes of the topic |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - for a valid topic |
| | | * MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an |
| | | * invalid position, or if it is too long. |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8 |
| | | * |
| | | * See Also: |
| | | * <mosquitto_sub_topic_check> |
| | | */ |
| | | libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic); |
| | | libmosq_EXPORT int mosquitto_sub_topic_check2(const char *topic, size_t topiclen); |
| | | |
| | | |
| | | struct libmosquitto_will { |
| | | char *topic; |
| | | void *payload; |
| | | int payloadlen; |
| | | int qos; |
| | | bool retain; |
| | | }; |
| | | |
| | | struct libmosquitto_auth { |
| | | char *username; |
| | | char *password; |
| | | }; |
| | | |
| | | struct libmosquitto_tls { |
| | | char *cafile; |
| | | char *capath; |
| | | char *certfile; |
| | | char *keyfile; |
| | | char *ciphers; |
| | | char *tls_version; |
| | | int (*pw_callback)(char *buf, int size, int rwflag, void *userdata); |
| | | int cert_reqs; |
| | | }; |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_simple |
| | | * |
| | | * Helper function to make subscribing to a topic and retrieving some messages |
| | | * very straightforward. |
| | | * |
| | | * This connects to a broker, subscribes to a topic, waits for msg_count |
| | | * messages to be received, then returns after disconnecting cleanly. |
| | | * |
| | | * Parameters: |
| | | * messages - pointer to a "struct mosquitto_message *". The received |
| | | * messages will be returned here. On error, this will be set to |
| | | * NULL. |
| | | * msg_count - the number of messages to retrieve. |
| | | * want_retained - if set to true, stale retained messages will be treated as |
| | | * normal messages with regards to msg_count. If set to |
| | | * false, they will be ignored. |
| | | * topic - the subscription topic to use (wildcards are allowed). |
| | | * qos - the qos to use for the subscription. |
| | | * host - the broker to connect to. |
| | | * port - the network port the broker is listening on. |
| | | * client_id - the client id to use, or NULL if a random client id should be |
| | | * generated. |
| | | * keepalive - the MQTT keepalive value. |
| | | * clean_session - the MQTT clean session flag. |
| | | * username - the username string, or NULL for no username authentication. |
| | | * password - the password string, or NULL for an empty password. |
| | | * will - a libmosquitto_will struct containing will information, or NULL for |
| | | * no will. |
| | | * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL |
| | | * for no use of TLS. |
| | | * |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * >0 - on error. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_subscribe_simple( |
| | | struct mosquitto_message **messages, |
| | | int msg_count, |
| | | bool want_retained, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_subscribe_callback |
| | | * |
| | | * Helper function to make subscribing to a topic and processing some messages |
| | | * very straightforward. |
| | | * |
| | | * This connects to a broker, subscribes to a topic, then passes received |
| | | * messages to a user provided callback. If the callback returns a 1, it then |
| | | * disconnects cleanly and returns. |
| | | * |
| | | * Parameters: |
| | | * callback - a callback function in the following form: |
| | | * int callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) |
| | | * Note that this is the same as the normal on_message callback, |
| | | * except that it returns an int. |
| | | * userdata - user provided pointer that will be passed to the callback. |
| | | * topic - the subscription topic to use (wildcards are allowed). |
| | | * qos - the qos to use for the subscription. |
| | | * host - the broker to connect to. |
| | | * port - the network port the broker is listening on. |
| | | * client_id - the client id to use, or NULL if a random client id should be |
| | | * generated. |
| | | * keepalive - the MQTT keepalive value. |
| | | * clean_session - the MQTT clean session flag. |
| | | * username - the username string, or NULL for no username authentication. |
| | | * password - the password string, or NULL for an empty password. |
| | | * will - a libmosquitto_will struct containing will information, or NULL for |
| | | * no will. |
| | | * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL |
| | | * for no use of TLS. |
| | | * |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * >0 - on error. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_subscribe_callback( |
| | | int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *), |
| | | void *userdata, |
| | | const char *topic, |
| | | int qos, |
| | | const char *host, |
| | | int port, |
| | | const char *client_id, |
| | | int keepalive, |
| | | bool clean_session, |
| | | const char *username, |
| | | const char *password, |
| | | const struct libmosquitto_will *will, |
| | | const struct libmosquitto_tls *tls); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_validate_utf8 |
| | | * |
| | | * Helper function to validate whether a UTF-8 string is valid, according to |
| | | * the UTF-8 spec and the MQTT additions. |
| | | * |
| | | * Parameters: |
| | | * str - a string to check |
| | | * len - the length of the string in bytes |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if str is NULL or len<0 or len>65536 |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if str is not valid UTF-8 |
| | | */ |
| | | libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); |
| | | |
| | | |
| | | /* ============================================================================= |
| | | * |
| | | * Section: Properties |
| | | * |
| | | * ============================================================================= |
| | | */ |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_byte |
| | | * |
| | | * Add a new byte property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - integer value for the new property |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_IDENTIFIER, 1); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_int16 |
| | | * |
| | | * Add a new int16 property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_RECEIVE_MAXIMUM) |
| | | * value - integer value for the new property |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1000); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_int32 |
| | | * |
| | | * Add a new int32 property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) |
| | | * value - integer value for the new property |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_int32(&proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 86400); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_varint |
| | | * |
| | | * Add a new varint property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_SUBSCRIPTION_IDENTIFIER) |
| | | * value - integer value for the new property |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_varint(&proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 1); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_binary |
| | | * |
| | | * Add a new binary property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to the property data |
| | | * len - length of property data in bytes |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, auth_data, auth_data_len); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_string |
| | | * |
| | | * Add a new string property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_CONTENT_TYPE) |
| | | * value - string value for the new property, must be UTF-8 and zero terminated |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, if value is NULL, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * MOSQ_ERR_MALFORMED_UTF8 - value is not valid UTF-8. |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_string(&proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_add_string_pair |
| | | * |
| | | * Add a new string pair property to a property list. |
| | | * |
| | | * If *proplist == NULL, a new list will be created, otherwise the new property |
| | | * will be appended to the list. |
| | | * |
| | | * Parameters: |
| | | * proplist - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_USER_PROPERTY) |
| | | * name - string name for the new property, must be UTF-8 and zero terminated |
| | | * value - string value for the new property, must be UTF-8 and zero terminated |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if identifier is invalid, if name or value is NULL, or if proplist is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory |
| | | * MOSQ_ERR_MALFORMED_UTF8 - if name or value are not valid UTF-8. |
| | | * |
| | | * Example: |
| | | * mosquitto_property *proplist = NULL; |
| | | * mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client", "mosquitto_pub"); |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_byte |
| | | * |
| | | * Attempt to read a byte property matching an identifier, from a property list |
| | | * or single property. This function can search for multiple entries of the |
| | | * same identifier by using the returned value and skip_first. Note however |
| | | * that it is forbidden for most properties to be duplicated. |
| | | * |
| | | * If the property is not found, *value will not be modified, so it is safe to |
| | | * pass a variable with a default value to be potentially overwritten: |
| | | * |
| | | * uint16_t keepalive = 60; // default value |
| | | * // Get value from property list, or keep default if not found. |
| | | * mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &keepalive, false); |
| | | * |
| | | * Parameters: |
| | | * proplist - mosquitto_property pointer, the list of properties or single property |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to store the value, or NULL if the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL. |
| | | * |
| | | * Example: |
| | | * // proplist is obtained from a callback |
| | | * mosquitto_property *prop; |
| | | * prop = mosquitto_property_read_byte(proplist, identifier, &value, false); |
| | | * while(prop){ |
| | | * printf("value: %s\n", value); |
| | | * prop = mosquitto_property_read_byte(prop, identifier, &value); |
| | | * } |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_byte( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | uint8_t *value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_int16 |
| | | * |
| | | * Read an int16 property value from a property. |
| | | * |
| | | * Parameters: |
| | | * property - property to read |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to store the value, or NULL if the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int16( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | uint16_t *value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_int32 |
| | | * |
| | | * Read an int32 property value from a property. |
| | | * |
| | | * Parameters: |
| | | * property - pointer to mosquitto_property pointer, the list of properties |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to store the value, or NULL if the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int32( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | uint32_t *value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_varint |
| | | * |
| | | * Read a varint property value from a property. |
| | | * |
| | | * Parameters: |
| | | * property - property to read |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to store the value, or NULL if the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_varint( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | uint32_t *value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_binary |
| | | * |
| | | * Read a binary property value from a property. |
| | | * |
| | | * On success, value must be free()'d by the application. |
| | | * |
| | | * Parameters: |
| | | * property - property to read |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to store the value, or NULL if the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_binary( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | void **value, |
| | | uint16_t *len, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_string |
| | | * |
| | | * Read a string property value from a property. |
| | | * |
| | | * On success, value must be free()'d by the application. |
| | | * |
| | | * Parameters: |
| | | * property - property to read |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * value - pointer to char*, for the property data to be stored in, or NULL if |
| | | * the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | char **value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_read_string_pair |
| | | * |
| | | * Read a string pair property value pair from a property. |
| | | * |
| | | * On success, name and value must be free()'d by the application. |
| | | * |
| | | * Parameters: |
| | | * property - property to read |
| | | * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) |
| | | * name - pointer to char* for the name property data to be stored in, or NULL |
| | | * if the name is not required. |
| | | * value - pointer to char*, for the property data to be stored in, or NULL if |
| | | * the value is not required. |
| | | * skip_first - boolean that indicates whether the first item in the list |
| | | * should be ignored or not. Should usually be set to false. |
| | | * |
| | | * Returns: |
| | | * A valid property pointer if the property is found |
| | | * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. |
| | | * |
| | | * Example: |
| | | * See <mosquitto_property_read_byte> |
| | | */ |
| | | libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string_pair( |
| | | const mosquitto_property *proplist, |
| | | int identifier, |
| | | char **name, |
| | | char **value, |
| | | bool skip_first); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_free_all |
| | | * |
| | | * Free all properties from a list of properties. Frees the list and sets *properties to NULL. |
| | | * |
| | | * Parameters: |
| | | * properties - list of properties to free |
| | | * |
| | | * Example: |
| | | * mosquitto_properties *properties = NULL; |
| | | * // Add properties |
| | | * mosquitto_property_free_all(&properties); |
| | | */ |
| | | libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_copy_all |
| | | * |
| | | * Parameters: |
| | | * dest : pointer for new property list |
| | | * src : property list |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on successful copy |
| | | * MOSQ_ERR_INVAL - if dest is NULL |
| | | * MOSQ_ERR_NOMEM - on out of memory (dest will be set to NULL) |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src); |
| | | |
| | | /* |
| | | * Function: mosquitto_property_check_command |
| | | * |
| | | * Check whether a property identifier is valid for the given command. |
| | | * |
| | | * Parameters: |
| | | * command - MQTT command (e.g. CMD_CONNECT) |
| | | * identifier - MQTT property (e.g. MQTT_PROP_USER_PROPERTY) |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - if the identifier is valid for command |
| | | * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command. |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_check_command(int command, int identifier); |
| | | |
| | | |
| | | /* |
| | | * Function: mosquitto_property_check_all |
| | | * |
| | | * Check whether a list of properties are valid for a particular command, |
| | | * whether there are duplicates, and whether the values are valid where |
| | | * possible. |
| | | * |
| | | * Note that this function is used internally in the library whenever |
| | | * properties are passed to it, so in basic use this is not needed, but should |
| | | * be helpful to check property lists *before* the point of using them. |
| | | * |
| | | * Parameters: |
| | | * command - MQTT command (e.g. CMD_CONNECT) |
| | | * properties - list of MQTT properties to check. |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - if all properties are valid |
| | | * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. |
| | | * MOSQ_ERR_PROTOCOL - if any property is invalid |
| | | */ |
| | | libmosq_EXPORT int mosquitto_property_check_all(int command, const mosquitto_property *properties); |
| | | |
| | | /* Function: mosquitto_string_to_property_info |
| | | * |
| | | * Parse a property name string and convert to a property identifier and data type. |
| | | * The property name is as defined in the MQTT specification, with - as a |
| | | * separator, for example: payload-format-indicator. |
| | | * |
| | | * Parameters: |
| | | * propname - the string to parse |
| | | * identifier - pointer to an int to receive the property identifier |
| | | * type - pointer to an int to receive the property type |
| | | * |
| | | * Returns: |
| | | * MOSQ_ERR_SUCCESS - on success |
| | | * MOSQ_ERR_INVAL - if the string does not match a property |
| | | * |
| | | * Example: |
| | | * mosquitto_string_to_property_info("response-topic", &id, &type); |
| | | * // id == MQTT_PROP_RESPONSE_TOPIC |
| | | * // type == MQTT_PROP_TYPE_STRING |
| | | */ |
| | | libmosq_EXPORT int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type); |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif |
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/mosquitto.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/mosquitto_internal.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/mqtt_protocol.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/net_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/net_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/net_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/net_mosq_ocsp.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/net_mosq_ocsp.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/options.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/options.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/packet_datatypes.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/packet_datatypes.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/packet_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/packet_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/packet_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/property_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/property_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/property_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/read_handle.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/read_handle.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/read_handle.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_connect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_connect.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_disconnect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_disconnect.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_publish.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_publish.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_subscribe.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_subscribe.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_unsubscribe.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/send_unsubscribe.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/socks_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/socks_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/socks_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/srv_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/srv_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/thread_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/thread_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/time_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/time_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/time_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/tls_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/tls_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/tls_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/utf8_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/utf8_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/util_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/util_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/util_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/util_topic.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/util_topic.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/will_mosq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/will_mosq.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/lib/will_mosq.o
proj1_mqttd/mosquitto/mosquitto-1.6.3/libmosquitto.pc.in
proj1_mqttd/mosquitto/mosquitto-1.6.3/libmosquittopp.pc.in
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/legacy/mosquitto-14x14.png
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/legacy/mosquitto-16x16.png
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/legacy/mosquitto.svg
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/mosquitto-logo-min.svg
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/mosquitto-logo-only.svg
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/mosquitto-text-below.svg
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/mosquitto-text-side.svg
proj1_mqttd/mosquitto/mosquitto-1.6.3/logo/mosquitto.ico
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/CMakeLists.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/html.xsl
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/libmosquitto.3
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/libmosquitto.3.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/libmosquitto.3.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/manpage.xsl
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto-tls.7
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto-tls.7.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto-tls.7.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.8
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.8.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.8.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.conf.5
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.conf.5.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto.conf.5.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_passwd.1
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_passwd.1.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_passwd.1.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_pub.1
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_pub.1.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_pub.1.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_rr.1
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_rr.1.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_rr.1.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_sub.1
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_sub.1.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mosquitto_sub.1.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mqtt.7
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mqtt.7.meta
proj1_mqttd/mosquitto/mosquitto-1.6.3/man/mqtt.7.xml
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/cc128_log_mysql.pl
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/cc128_parse.pl
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/cc128_read.pl
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/cc128_read.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/gnome-panel/CurrentCostMQTT.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/gnome-panel/CurrentCostMQTT.server
proj1_mqttd/mosquitto/mosquitto-1.6.3/misc/currentcost/gnome-panel/currentcost.png
proj1_mqttd/mosquitto/mosquitto-1.6.3/mosquitto.conf
proj1_mqttd/mosquitto/mosquitto-1.6.3/notice.html
proj1_mqttd/mosquitto/mosquitto-1.6.3/pskfile.example
proj1_mqttd/mosquitto/mosquitto-1.6.3/pwfile.example
proj1_mqttd/mosquitto/mosquitto-1.6.3/readme-windows.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/readme.md
proj1_mqttd/mosquitto/mosquitto-1.6.3/security/mosquitto.apparmor
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/monit/mosquitto.monit
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/svscan/run
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/systemd/README
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/systemd/mosquitto.service.notify
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/systemd/mosquitto.service.simple
proj1_mqttd/mosquitto/mosquitto-1.6.3/service/upstart/mosquitto.conf
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/CMakeLists.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/bridge.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/conf.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/conf_includedir.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/context.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/database.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/db_dump/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/db_dump/db_dump.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/deps/uthash.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/deps/utlist.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_auth.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_connack.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_connect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_disconnect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_publish.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_subscribe.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/handle_unsubscribe.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/lib_load.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/linker-macosx.syms
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/linker.syms
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/logging.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/loop.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/mosquitto.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/mosquitto_broker.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/mosquitto_broker_internal.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/mosquitto_passwd.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/mosquitto_plugin.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/net.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist_read.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist_read_v234.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist_read_v5.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist_write.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/persist_write_v5.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/plugin.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/plugin_defer.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/property_broker.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/read_handle.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/security.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/security_default.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/send_auth.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/send_connack.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/send_suback.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/send_unsuback.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/service.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/session_expiry.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/signals.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/subs.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/sys_tree.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/sys_tree.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/uhpa.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/websockets.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/src/will_delay.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/tags
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-anon-denied.pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-anon-denied.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-bad-packet.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-disconnect-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-duplicate-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-duplicate.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-id-0-311.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-id-0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-id-missing.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-id-utf8.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-protonum.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-invalid-reserved.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-success-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-invalid-utf8.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-no-flag.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-no-password-denied.pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-no-password-denied.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-denied-no-will.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-denied.pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-denied.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-success-no-tls.pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-success-no-tls.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-success.pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-password-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/01-connect-uname-pwd-no-flag.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-shared-qos0-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subhier-crash.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-retain-as-publish.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-send-retain.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-subscription-id.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-topic-alias-unknown.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-topic-alias.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-bad-pubcomp.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-bad-pubrec.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-message-expiry-retain.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-message-expiry-will.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-message-expiry.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-nolocal.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-bad-puback-1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-bad-puback-2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-bad-pubcomp.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-pubrec-error-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-pubrec-error.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-receive-maximum-1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-receive-maximum-2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-receive-maximum-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subpub-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-dollar-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-invalid-utf8.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-persistence-flipflop.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-subscribe-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-invalid-no-topic.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos2-multiple-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos2-multiple.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos2-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/02-unsubscribe-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-pattern-matching-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-pattern-matching.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-disconnect-qos1-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-disconnect-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-disconnect-qos2-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-disconnect-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-qos1-len-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-qos1-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-qos2-len-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-qos2-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-timeout-qos1-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-timeout-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-timeout-qos2-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-b2c-timeout-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-c2b-disconnect-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-c2b-qos2-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-c2b-timeout-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-dollar-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-dollar.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-invalid-utf8.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos1-no-subscribers-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos1-queued-bytes.conf
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos1-queued-bytes.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos1-retain-disabled.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/03-publish-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-check-source-persist-diff-port.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-check-source-persist.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-check-source.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-qos0-clear.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-qos0-fresh.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-qos0-repeated.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-qos1-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/04-retain-upgrade-outgoing-qos.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/05-clean-session-qos1-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/05-clean-session-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/05-session-expiry-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-b2br-disconnect-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-b2br-disconnect-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-b2br-late-connection-retain.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-b2br-late-connection.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-b2br-remapping.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-br2b-disconnect-qos1-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-br2b-disconnect-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-br2b-disconnect-qos2-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-br2b-disconnect-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-br2b-remapping.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-fail-persist-resend-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-fail-persist-resend-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-no-local.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-per-listener-settings.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-reconnect-local-out-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/06-bridge-reconnect-local-out.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-delay-reconnect.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-delay-recover.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-delay.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-disconnect-with-will.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-invalid-utf8.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-no-flag.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-null-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-null-topic.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-null.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-properties.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/07-will-reconnect-1273.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-bridge-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-bridge.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-cert-auth-crl.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-cert-auth-expired.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-cert-auth-revoked.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-cert-auth-without.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-cert-auth.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-identity.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-no-auth-wrong-ca.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-no-auth.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-ssl-connect-no-identity.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-tls-psk-bridge.psk
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-tls-psk-bridge.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-tls-psk-pub.psk
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/08-tls-psk-pub.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-acl-access-variants.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-acl-change.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-acl-empty-file.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-auth-bad-method.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-change-username.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-multistep-reauth.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-multistep.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-single.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-single2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-extended-auth-unsupported.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-acl-pub.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-acl-sub-denied.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-acl-sub.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-context-params.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-defer-unpwd-fail.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-defer-unpwd-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-msg-params.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-unpwd-fail.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-unpwd-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-v2-unpwd-fail.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-plugin-auth-v2-unpwd-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/09-pwfile-parse-invalid.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/10-listener-mount-point-helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/10-listener-mount-point.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-message-expiry.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-persistent-subscription-no-local.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-persistent-subscription-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-persistent-subscription.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-pub-props.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/11-subscription-id.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-assigned-client-identifier.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-maximum-packet-size-broker.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-maximum-packet-size-connect.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-maximum-packet-size-publish-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-maximum-packet-size-publish-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-maximum-packet-size-publish.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-response-topic-correlation-data.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-response-topic.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-server-keepalive.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-session-expiry-invalid.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-subpub-content-type.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-subpub-payload-format.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/12-prop-topic-alias-invalid.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/08-tls-psk-bridge.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/08-tls-psk-pub.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_acl.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_acl_sub_denied.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_context_params.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_extended_multiple.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_extended_single.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_extended_single2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_msg_params.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_pwd.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/auth_plugin_v2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/c/mosquitto_plugin_v2.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/mosq_test_helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/prop_subpub_helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/readme.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/broker/test.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-con-discon-success.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-keepalive-pingreq.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-no-clean-session.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-server-keepalive-pingreq.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-unpwd-set.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-will-set.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/01-will-unpwd-set.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-subscribe-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-subscribe-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-subscribe-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-unsubscribe-multiple-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-unsubscribe-v5.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/02-unsubscribe.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-b2c-qos1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-b2c-qos2-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-b2c-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos1-disconnect.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos1-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos1-receive-maximum.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos1-timeout.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-disconnect.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-len.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-maximum-qos-0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-maximum-qos-1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-pubrec-error.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-receive-maximum-1.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-receive-maximum-2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2-timeout.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-c2b-qos2.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-qos0-no-payload.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-publish-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-request-response-correlation.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/03-request-response.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/04-retain-qos0.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/08-ssl-bad-cacert.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/08-ssl-connect-cert-auth-enc.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/08-ssl-connect-cert-auth.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/08-ssl-connect-no-auth.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/08-ssl-fake-cacert.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/09-util-topic-tokenise.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/11-prop-oversize-packet.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/11-prop-send-content-type.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/11-prop-send-payload-format.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-con-discon-success.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-keepalive-pingreq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-no-clean-session.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-server-keepalive-pingreq.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-unpwd-set.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-will-set.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/01-will-unpwd-set.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-subscribe-qos0.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-subscribe-qos1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-subscribe-qos2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-unsubscribe-multiple-v5.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-unsubscribe-v5.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/02-unsubscribe.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-b2c-qos1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-b2c-qos2-len.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-b2c-qos2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos1-disconnect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos1-len.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos1-receive-maximum.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-disconnect.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-len.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-maximum-qos-0.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-maximum-qos-1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-pubrec-error.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-c2b-qos2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-qos0-no-payload.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-publish-qos0.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-request-response-1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-request-response-2.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/03-request-response-correlation-1.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/04-retain-qos0.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/08-ssl-bad-cacert.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/08-ssl-connect-cert-auth-enc.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/08-ssl-connect-cert-auth.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/08-ssl-connect-no-auth.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/08-ssl-fake-cacert.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/09-util-topic-tokenise.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/11-prop-oversize-packet.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/11-prop-send-content-type.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/11-prop-send-payload-format.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/c/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-con-discon-success.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-keepalive-pingreq.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-no-clean-session.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-unpwd-set.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-will-set.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/01-will-unpwd-set.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/02-subscribe-qos0.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/02-subscribe-qos1.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/02-subscribe-qos2.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/02-unsubscribe.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-b2c-qos1.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-b2c-qos2.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-c2b-qos1-disconnect.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-c2b-qos2-disconnect.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-c2b-qos2.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-qos0-no-payload.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/03-publish-qos0.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/04-retain-qos0.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/08-ssl-bad-cacert.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/08-ssl-connect-cert-auth.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/08-ssl-connect-no-auth.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/08-ssl-fake-cacert.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/09-util-topic-tokenise.cpp
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/cpp/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/mosq_test_helper.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/lib/test.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/mosq_test.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/mqtt5_opts.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/mqtt5_props.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/mqtt5_rc.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/old/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/old/msgsps_common.h
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/old/msgsps_pub.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/old/msgsps_sub.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ptest.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/auth_plugin.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/pwfile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/random.conf
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/random_client.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/random/test.py
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/all-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client-encrypted.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client-encrypted.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client-expired.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client-revoked.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client-revoked.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/client.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/crl.pem
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/demoCA/crlnumber
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/demoCA/index.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/demoCA/index.txt.attr
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/demoCA/serial
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/gen.sh
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/openssl.cnf
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/readme.txt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/rootCA/crlnumber
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/rootCA/index.txt.attr
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/rootCA/serial
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/server-expired.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/server.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/server.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/signingCA/crlnumber
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/signingCA/index.txt.attr
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/signingCA/serial
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-alt-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-alt-ca.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-bad-root-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-bad-root-ca.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-ca.srl
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-fake-root-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-fake-root-ca.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-root-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-root-ca.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-signing-ca.crt
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/ssl/test-signing-ca.key
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/Makefile
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/datatype_read.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/datatype_write.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/corrupt-header-long.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/corrupt-header-short.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/empty.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/unsupported-version.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-bad-chunk.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-cfg-bad-dbid.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-cfg-truncated.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-cfg.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-client-message.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-client.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-message-store.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-retain.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v3-sub.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v4-cfg.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v4-message-store.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-bad-chunk.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-cfg-truncated.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-cfg.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-client-message-props.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-client-message.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-client.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-message-store-props.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-message-store.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-retain.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_read/v5-sub.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_write/empty.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_write/v4-full.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/files/persist_write/v5-message-store-no-ref.test-db
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/persist_read_stubs.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/persist_read_test.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/persist_write_stubs.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/persist_write_test.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/property_add.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/property_read.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/property_user_read.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/property_write.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/publish_test.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/stubs.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/test.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/utf8.c
proj1_mqttd/mosquitto/mosquitto-1.6.3/test/unit/util_topic_test.c |