mirror of
https://github.com/eclipse/mosquitto.git
synced 2025-05-08 16:52:13 +08:00
Merge branch 'fixes'
This commit is contained in:
commit
80f567975c
@ -11,7 +11,7 @@ project(mosquitto)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
# Only for version 3 and up. cmake_policy(SET CMP0042 NEW)
|
||||
|
||||
set (VERSION 1.4.14)
|
||||
set (VERSION 1.4.15)
|
||||
|
||||
if (WIN32)
|
||||
execute_process(COMMAND cmd /c echo %DATE% %TIME% OUTPUT_VARIABLE TIMESTAMP
|
||||
|
@ -1,9 +1,46 @@
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2014-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2014-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -34,6 +34,7 @@ Contributors:
|
||||
#define STATUS_CONNECTING 0
|
||||
#define STATUS_CONNACK_RECVD 1
|
||||
#define STATUS_WAITING 2
|
||||
#define STATUS_DISCONNECTING 3
|
||||
|
||||
/* Global variables for use in callbacks. See sub_client.c for an example of
|
||||
* using a struct to hold variables for use in callbacks. */
|
||||
@ -410,8 +411,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
if(feof(stdin)){
|
||||
last_mid = mid_sent;
|
||||
status = STATUS_WAITING;
|
||||
if(last_mid == -1){
|
||||
/* Empty file */
|
||||
mosquitto_disconnect(mosq);
|
||||
disconnect_sent = true;
|
||||
status = STATUS_DISCONNECTING;
|
||||
}else{
|
||||
last_mid = mid_sent;
|
||||
status = STATUS_WAITING;
|
||||
}
|
||||
}
|
||||
}else if(status == STATUS_WAITING){
|
||||
if(last_mid_sent == last_mid && disconnect_sent == false){
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -86,7 +86,7 @@ WITH_SOCKS:=yes
|
||||
|
||||
# Also bump lib/mosquitto.h, CMakeLists.txt,
|
||||
# installer/mosquitto.nsi, installer/mosquitto-cygwin.nsi
|
||||
VERSION=1.4.14
|
||||
VERSION=1.4.15
|
||||
TIMESTAMP:=$(shell date "+%F %T%z")
|
||||
|
||||
# Client library SO version. Bump if incompatible API/ABI changes are made.
|
||||
|
@ -43,8 +43,13 @@ void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_
|
||||
|
||||
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);
|
||||
|
@ -7,7 +7,7 @@
|
||||
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
|
||||
Name "mosquitto"
|
||||
!define VERSION 1.4.14
|
||||
!define VERSION 1.4.15
|
||||
OutFile "mosquitto-${VERSION}-install-cygwin.exe"
|
||||
|
||||
InstallDir "$PROGRAMFILES\mosquitto"
|
||||
|
@ -9,7 +9,7 @@
|
||||
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
|
||||
Name "mosquitto"
|
||||
!define VERSION 1.4.14
|
||||
!define VERSION 1.4.15
|
||||
OutFile "mosquitto-${VERSION}-install-win32.exe"
|
||||
|
||||
InstallDir "$PROGRAMFILES\mosquitto"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2013 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -37,8 +37,32 @@ 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)
|
||||
{
|
||||
#ifdef LINUX
|
||||
struct rlimit r;
|
||||
|
||||
r.rlim_cur = lim;
|
||||
r.rlim_max = lim;
|
||||
|
||||
setrlimit(RLIMIT_CPU, &r);
|
||||
|
||||
mem_limit = 0;
|
||||
#else
|
||||
mem_limit = lim;
|
||||
#endif
|
||||
}
|
||||
#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
|
||||
@ -64,6 +88,11 @@ void _mosquitto_free(void *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
|
||||
@ -90,6 +119,11 @@ unsigned long _mosquitto_max_memory_used(void)
|
||||
|
||||
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){
|
||||
@ -110,6 +144,11 @@ void *_mosquitto_realloc(void *ptr, size_t size)
|
||||
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
@ -34,4 +34,8 @@ unsigned long _mosquitto_max_memory_used(void);
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
@ -1202,15 +1202,20 @@ int mosquitto_loop_write(struct mosquitto *mosq, int max_packets)
|
||||
|
||||
bool mosquitto_want_write(struct mosquitto *mosq)
|
||||
{
|
||||
bool result = false;
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
return true;
|
||||
#ifdef WITH_TLS
|
||||
}else if(mosq->ssl && mosq->want_write){
|
||||
return true;
|
||||
#endif
|
||||
}else{
|
||||
return false;
|
||||
result = true;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
if (mosq->want_write) {
|
||||
result = true;
|
||||
}else if(mosq->want_connect){
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
@ -45,7 +45,7 @@ extern "C" {
|
||||
|
||||
#define LIBMOSQUITTO_MAJOR 1
|
||||
#define LIBMOSQUITTO_MINOR 4
|
||||
#define LIBMOSQUITTO_REVISION 14
|
||||
#define LIBMOSQUITTO_REVISION 15
|
||||
/* 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -214,33 +214,39 @@ int _mosquitto_socket_close(struct mosquitto *mosq)
|
||||
|
||||
assert(mosq);
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
SSL_shutdown(mosq->ssl);
|
||||
SSL_free(mosq->ssl);
|
||||
mosq->ssl = NULL;
|
||||
}
|
||||
if(mosq->ssl_ctx){
|
||||
SSL_CTX_free(mosq->ssl_ctx);
|
||||
mosq->ssl_ctx = NULL;
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(!mosq->wsi)
|
||||
#endif
|
||||
{
|
||||
if(mosq->ssl){
|
||||
SSL_shutdown(mosq->ssl);
|
||||
SSL_free(mosq->ssl);
|
||||
mosq->ssl = NULL;
|
||||
}
|
||||
if(mosq->ssl_ctx){
|
||||
SSL_CTX_free(mosq->ssl_ctx);
|
||||
mosq->ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if((int)mosq->sock >= 0){
|
||||
#ifdef WITH_BROKER
|
||||
HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
|
||||
#endif
|
||||
rc = COMPAT_CLOSE(mosq->sock);
|
||||
mosq->sock = INVALID_SOCKET;
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
}else if(mosq->sock == WEBSOCKET_CLIENT){
|
||||
if(mosq->wsi)
|
||||
{
|
||||
if(mosq->state != mosq_cs_disconnecting){
|
||||
mosq->state = mosq_cs_disconnect_ws;
|
||||
}
|
||||
if(mosq->wsi){
|
||||
libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
|
||||
}
|
||||
mosq->sock = INVALID_SOCKET;
|
||||
libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
if((int)mosq->sock >= 0){
|
||||
#ifdef WITH_BROKER
|
||||
HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
|
||||
#endif
|
||||
rc = COMPAT_CLOSE(mosq->sock);
|
||||
mosq->sock = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
@ -323,7 +329,6 @@ int _mosquitto_try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_soc
|
||||
|
||||
/* Set non-blocking */
|
||||
if(_mosquitto_socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -338,7 +343,6 @@ int _mosquitto_try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_soc
|
||||
|
||||
/* Set non-blocking */
|
||||
if(_mosquitto_socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -423,7 +427,6 @@ int _mosquitto_try_connect(struct mosquitto *mosq, const char *host, uint16_t po
|
||||
if(!blocking){
|
||||
/* Set non-blocking */
|
||||
if(_mosquitto_socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -440,7 +443,6 @@ int _mosquitto_try_connect(struct mosquitto *mosq, const char *host, uint16_t po
|
||||
if(blocking){
|
||||
/* Set non-blocking */
|
||||
if(_mosquitto_socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -869,7 +871,11 @@ int _mosquitto_packet_write(struct mosquitto *mosq)
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->out_packet_mutex);
|
||||
|
||||
#if defined(WITH_TLS) && !defined(WITH_BROKER)
|
||||
if((mosq->state == mosq_cs_connect_pending)||mosq->want_connect){
|
||||
#else
|
||||
if(mosq->state == mosq_cs_connect_pending){
|
||||
#endif
|
||||
pthread_mutex_unlock(&mosq->current_out_packet_mutex);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
@ -1084,6 +1090,36 @@ int _mosquitto_packet_read(struct mosquitto *mosq)
|
||||
* positive. */
|
||||
mosq->in_packet.remaining_count *= -1;
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
/* Check packet sizes before allocating memory.
|
||||
* Will need modifying for MQTT v5. */
|
||||
switch(mosq->in_packet.command & 0xF0){
|
||||
case CONNECT:
|
||||
if(mosq->in_packet.remaining_length > 327699){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
case UNSUBACK:
|
||||
if(mosq->in_packet.remaining_length != 2){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
if(mosq->in_packet.remaining_length != 0){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(mosq->in_packet.remaining_length > 0){
|
||||
mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
|
||||
if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM;
|
||||
@ -1244,7 +1280,6 @@ int _mosquitto_socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
continue;
|
||||
}
|
||||
if(_mosquitto_socket_nonblock(spR)){
|
||||
COMPAT_CLOSE(spR);
|
||||
COMPAT_CLOSE(listensock);
|
||||
continue;
|
||||
}
|
||||
@ -1272,7 +1307,6 @@ int _mosquitto_socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
|
||||
if(_mosquitto_socket_nonblock(spW)){
|
||||
COMPAT_CLOSE(spR);
|
||||
COMPAT_CLOSE(spW);
|
||||
COMPAT_CLOSE(listensock);
|
||||
continue;
|
||||
}
|
||||
@ -1290,13 +1324,11 @@ int _mosquitto_socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
if(_mosquitto_socket_nonblock(sv[0])){
|
||||
COMPAT_CLOSE(sv[0]);
|
||||
COMPAT_CLOSE(sv[1]);
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
if(_mosquitto_socket_nonblock(sv[1])){
|
||||
COMPAT_CLOSE(sv[0]);
|
||||
COMPAT_CLOSE(sv[1]);
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
*pairR = sv[0];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2014-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2014-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013,2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2013-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2011-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013,2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2013-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013,2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2013-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013,2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2013-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013,2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2013-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -228,13 +228,17 @@ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result
|
||||
int spos, tpos;
|
||||
bool multilevel_wildcard = false;
|
||||
|
||||
if(!sub || !topic || !result) return MOSQ_ERR_INVAL;
|
||||
if(!result) return MOSQ_ERR_INVAL;
|
||||
*result = false;
|
||||
|
||||
if(!sub || !topic){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
slen = strlen(sub);
|
||||
tlen = strlen(topic);
|
||||
|
||||
if(!slen || !tlen){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
@ -242,7 +246,6 @@ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result
|
||||
if((sub[0] == '$' && topic[0] != '$')
|
||||
|| (topic[0] == '$' && sub[0] != '$')){
|
||||
|
||||
*result = false;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -269,7 +272,6 @@ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(tpos == tlen && spos == slen-1 && sub[spos] == '+'){
|
||||
if(spos > 0 && sub[spos-1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
spos++;
|
||||
@ -280,12 +282,10 @@ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result
|
||||
if(sub[spos] == '+'){
|
||||
/* Check for bad "+foo" or "a/+foo" subscription */
|
||||
if(spos > 0 && sub[spos-1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
/* Check for bad "foo+" or "foo+/a" subscription */
|
||||
if(spos < slen-1 && sub[spos+1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
spos++;
|
||||
@ -298,19 +298,28 @@ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result
|
||||
}
|
||||
}else if(sub[spos] == '#'){
|
||||
if(spos > 0 && sub[spos-1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
multilevel_wildcard = true;
|
||||
if(spos+1 != slen){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else{
|
||||
*result = false;
|
||||
/* Check for e.g. foo/bar matching foo/+/# */
|
||||
if(spos > 0
|
||||
&& spos+2 == slen
|
||||
&& tpos == tlen
|
||||
&& sub[spos-1] == '+'
|
||||
&& sub[spos] == '/'
|
||||
&& sub[spos+1] == '#')
|
||||
{
|
||||
*result = true;
|
||||
multilevel_wildcard = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -50,6 +50,7 @@
|
||||
<itemizedlist mark="circle">
|
||||
<listitem><para>openssl req -out server.csr -key server.key -new</para></listitem>
|
||||
</itemizedlist>
|
||||
<note><para>When prompted for the CN (Common Name), please enter either your server (or broker) hostname or domain name.</para></note>
|
||||
|
||||
<para>Send the CSR to the CA, or sign it with your CA key:</para>
|
||||
<itemizedlist mark="circle">
|
||||
|
@ -116,7 +116,7 @@
|
||||
<para><code>user <username></code></para>
|
||||
|
||||
<para>The username referred to here is the same as in
|
||||
<option>password_fil</option>e. It is not the
|
||||
<option>password_file</option>. It is not the
|
||||
clientid.</para>
|
||||
|
||||
<para>It is also possible to define ACLs based on pattern
|
||||
@ -1031,9 +1031,9 @@
|
||||
<listitem>
|
||||
<para>Set the clientid to use on the local broker. If not
|
||||
defined, this defaults to
|
||||
<option>local.<clientid></option>. If you are
|
||||
<option>local.<remote_clientid></option>. If you are
|
||||
bridging a broker to itself, it is important that
|
||||
local_clientid and clientid do not match.</para>
|
||||
local_clientid and remote_clientid do not match.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -1059,7 +1059,7 @@
|
||||
notification messages to the local and remote brokers
|
||||
giving information about the state of the bridge
|
||||
connection. Retained messages are published to the
|
||||
topic $SYS/broker/connection/<clientid>/state
|
||||
topic $SYS/broker/connection/<remote_clientid>/state
|
||||
unless otherwise set with
|
||||
<option>notification_topic</option>s. If the message
|
||||
is 1 then the connection is active, or 0 if the
|
||||
@ -1073,7 +1073,7 @@
|
||||
<para>Choose the topic on which notifications will be
|
||||
published for this bridge. If not set the messages will
|
||||
be sent on the topic
|
||||
$SYS/broker/connection/<clientid>/state.</para>
|
||||
$SYS/broker/connection/<remote_clientid>/state.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -1295,21 +1295,6 @@ topic clients/total in 0 test/mosquitto/org $SYS/broker/
|
||||
<para>The following options are available for all bridges to
|
||||
configure SSL/TLS support.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>bridge_attempt_unsubscribe</option> [ true | false ]</term>
|
||||
<listitem>
|
||||
<para>If a bridge has topics that have "out" direction,
|
||||
the default behaviour is to send an unsubscribe
|
||||
request to the remote broker on that topic. This
|
||||
means that changing a topic direction from "in" to
|
||||
"out" will not keep receiving incoming messages.
|
||||
Sending these unsubscribe requests is not always
|
||||
desirable, setting
|
||||
<option>bridge_attempt_unsubscribe</option> to
|
||||
<replaceable>false</replaceable> will disable
|
||||
sending the unsubscribe request.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>bridge_cafile</option> <replaceable>file path</replaceable></term>
|
||||
<listitem>
|
||||
|
@ -41,7 +41,7 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para><command>mosquitto_passwd</command> is a tool for managing
|
||||
password files the mosquitto MQTT broker.</para>
|
||||
password files for the mosquitto MQTT broker.</para>
|
||||
<para>Usernames must not contain ":". Passwords are stored in a similar
|
||||
format to
|
||||
<citerefentry><refentrytitle>crypt</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
|
||||
|
@ -220,7 +220,7 @@
|
||||
#crlfile
|
||||
|
||||
# If you wish to control which encryption ciphers are used, use the ciphers
|
||||
# option. The list of available ciphers can be optained using the "openssl
|
||||
# option. The list of available ciphers can be obtained using the "openssl
|
||||
# ciphers" command and should be provided in the same format as the output of
|
||||
# that command.
|
||||
# If unset defaults to DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH
|
||||
@ -253,7 +253,7 @@
|
||||
|
||||
# When using PSK, the encryption ciphers used will be chosen from the list of
|
||||
# available PSK ciphers. If you want to control which ciphers are available,
|
||||
# use the "ciphers" option. The list of available ciphers can be optained
|
||||
# use the "ciphers" option. The list of available ciphers can be obtained
|
||||
# using the "openssl ciphers" command and should be provided in the same format
|
||||
# as the output of that command.
|
||||
#ciphers
|
||||
|
@ -69,6 +69,7 @@ already be built. Use `make binary` to skip building the man pages, or install
|
||||
* libuuid (uuid-dev) - disable with `make WITH_UUID=no`
|
||||
* libwebsockets (libwebsockets-dev) - enable with `make WITH_WEBSOCKETS=yes`
|
||||
* openssl (libssl-dev on Debian based systems) - disable with `make WITH_TLS=no`
|
||||
* xsltproc (xsltproc and docbook-xsl on Debian based systems) - only needed when building from git sources - disable with `make WITH_DOCS=no`
|
||||
|
||||
## Credits
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
MAJOR=1
|
||||
MINOR=4
|
||||
REVISION=14
|
||||
REVISION=15
|
||||
|
||||
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
181
src/conf.c
181
src/conf.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -64,6 +64,35 @@ static int _conf_parse_int(char **token, const char *name, int *value, char *sav
|
||||
static int _conf_parse_string(char **token, const char *name, char **value, char *saveptr);
|
||||
static int _config_read_file(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *config_tmp, int level, int *lineno);
|
||||
|
||||
static char *fgets_extending(char **buf, int *buflen, FILE *stream)
|
||||
{
|
||||
char *rc;
|
||||
char endchar;
|
||||
int offset = 0;
|
||||
char *newbuf;
|
||||
|
||||
do{
|
||||
rc = fgets(&((*buf)[offset]), *buflen-offset, stream);
|
||||
if(feof(stream)){
|
||||
return rc;
|
||||
}
|
||||
|
||||
endchar = (*buf)[strlen(*buf)-1];
|
||||
if(endchar == '\n'){
|
||||
return rc;
|
||||
}
|
||||
/* No EOL char found, so extend buffer */
|
||||
offset = *buflen-1;
|
||||
*buflen += 1000;
|
||||
newbuf = realloc(*buf, *buflen);
|
||||
if(!newbuf){
|
||||
return NULL;
|
||||
}
|
||||
*buf = newbuf;
|
||||
}while(1);
|
||||
}
|
||||
|
||||
|
||||
static int _conf_attempt_resolve(const char *host, const char *text, int log, const char *msg)
|
||||
{
|
||||
struct addrinfo gai_hints;
|
||||
@ -100,7 +129,7 @@ static int _conf_attempt_resolve(const char *host, const char *text, int log, co
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void _config_init_reload(struct mqtt3_config *config)
|
||||
static void _config_init_reload(struct mosquitto_db *db, struct mqtt3_config *config)
|
||||
{
|
||||
int i;
|
||||
/* Set defaults */
|
||||
@ -136,7 +165,7 @@ static void _config_init_reload(struct mqtt3_config *config)
|
||||
#else
|
||||
config->log_facility = LOG_DAEMON;
|
||||
config->log_dest = MQTT3_LOG_STDERR;
|
||||
if(config->verbose){
|
||||
if(db->verbose){
|
||||
config->log_type = INT_MAX;
|
||||
}else{
|
||||
config->log_type = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO;
|
||||
@ -168,11 +197,10 @@ static void _config_init_reload(struct mqtt3_config *config)
|
||||
}
|
||||
}
|
||||
|
||||
void mqtt3_config_init(struct mqtt3_config *config)
|
||||
void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config)
|
||||
{
|
||||
memset(config, 0, sizeof(struct mqtt3_config));
|
||||
_config_init_reload(config);
|
||||
config->config_file = NULL;
|
||||
_config_init_reload(db, config);
|
||||
config->daemon = false;
|
||||
config->default_listener.host = NULL;
|
||||
config->default_listener.port = 0;
|
||||
@ -205,7 +233,6 @@ void mqtt3_config_init(struct mqtt3_config *config)
|
||||
#endif
|
||||
config->auth_plugin = NULL;
|
||||
config->auth_plugin_deny_special_chars = true;
|
||||
config->verbose = false;
|
||||
config->message_size_limit = 0;
|
||||
}
|
||||
|
||||
@ -219,7 +246,6 @@ void mqtt3_config_cleanup(struct mqtt3_config *config)
|
||||
if(config->acl_file) _mosquitto_free(config->acl_file);
|
||||
if(config->auto_id_prefix) _mosquitto_free(config->auto_id_prefix);
|
||||
if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes);
|
||||
if(config->config_file) _mosquitto_free(config->config_file);
|
||||
if(config->password_file) _mosquitto_free(config->password_file);
|
||||
if(config->persistence_location) _mosquitto_free(config->persistence_location);
|
||||
if(config->persistence_file) _mosquitto_free(config->persistence_file);
|
||||
@ -240,10 +266,13 @@ void mqtt3_config_cleanup(struct mqtt3_config *config)
|
||||
if(config->listeners[i].psk_hint) _mosquitto_free(config->listeners[i].psk_hint);
|
||||
if(config->listeners[i].crlfile) _mosquitto_free(config->listeners[i].crlfile);
|
||||
if(config->listeners[i].tls_version) _mosquitto_free(config->listeners[i].tls_version);
|
||||
if(config->listeners[i].ssl_ctx) SSL_CTX_free(config->listeners[i].ssl_ctx);
|
||||
#endif
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(config->listeners[i].http_dir) _mosquitto_free(config->listeners[i].http_dir);
|
||||
if(!config->listeners[i].ws_context) /* libwebsockets frees its own SSL_CTX */
|
||||
#endif
|
||||
{
|
||||
SSL_CTX_free(config->listeners[i].ssl_ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
_mosquitto_free(config->listeners);
|
||||
@ -322,7 +351,7 @@ static void print_usage(void)
|
||||
printf("\nSee http://mosquitto.org/ for more information.\n\n");
|
||||
}
|
||||
|
||||
int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[])
|
||||
int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int port_tmp;
|
||||
@ -330,13 +359,9 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[])
|
||||
for(i=1; i<argc; i++){
|
||||
if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config-file")){
|
||||
if(i<argc-1){
|
||||
config->config_file = _mosquitto_strdup(argv[i+1]);
|
||||
if(!config->config_file){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
db->config_file = argv[i+1];
|
||||
|
||||
if(mqtt3_config_read(config, false)){
|
||||
if(mqtt3_config_read(db, config, false)){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open configuration file.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
@ -368,7 +393,7 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[])
|
||||
}
|
||||
i++;
|
||||
}else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){
|
||||
config->verbose = true;
|
||||
db->verbose = true;
|
||||
}else{
|
||||
fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]);
|
||||
print_usage();
|
||||
@ -443,22 +468,87 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[])
|
||||
if(!config->user){
|
||||
config->user = "mosquitto";
|
||||
}
|
||||
if(config->verbose){
|
||||
if(db->verbose){
|
||||
config->log_type = INT_MAX;
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mqtt3_config_read(struct mqtt3_config *config, bool reload)
|
||||
/* Copy reloaded config into existing config struct */
|
||||
void config__copy(struct mqtt3_config *src, struct mqtt3_config *dest)
|
||||
{
|
||||
_mosquitto_free(dest->acl_file);
|
||||
dest->acl_file = src->acl_file;
|
||||
|
||||
dest->allow_anonymous = src->allow_anonymous;
|
||||
dest->allow_duplicate_messages = src->allow_duplicate_messages;
|
||||
dest->allow_zero_length_clientid = src->allow_zero_length_clientid;
|
||||
|
||||
_mosquitto_free(dest->auto_id_prefix);
|
||||
dest->auto_id_prefix = src->auto_id_prefix;
|
||||
dest->auto_id_prefix_len = src->auto_id_prefix_len;
|
||||
|
||||
dest->autosave_interval = src->autosave_interval;
|
||||
dest->autosave_on_changes = src->autosave_on_changes;
|
||||
|
||||
_mosquitto_free(dest->clientid_prefixes);
|
||||
dest->clientid_prefixes = src->clientid_prefixes;
|
||||
|
||||
dest->connection_messages = src->connection_messages;
|
||||
dest->log_dest = src->log_dest;
|
||||
dest->log_facility = src->log_facility;
|
||||
dest->log_type = src->log_type;
|
||||
dest->log_timestamp = src->log_timestamp;
|
||||
|
||||
_mosquitto_free(dest->log_file);
|
||||
dest->log_file = src->log_file;
|
||||
|
||||
dest->message_size_limit = src->message_size_limit;
|
||||
|
||||
_mosquitto_free(dest->password_file);
|
||||
dest->password_file = src->password_file;
|
||||
|
||||
dest->persistence = src->persistence;
|
||||
|
||||
_mosquitto_free(dest->persistence_location);
|
||||
dest->persistence_location = src->persistence_location;
|
||||
|
||||
_mosquitto_free(dest->persistence_file);
|
||||
dest->persistence_file = src->persistence_file;
|
||||
|
||||
_mosquitto_free(dest->persistence_filepath);
|
||||
dest->persistence_filepath = src->persistence_filepath;
|
||||
|
||||
dest->persistent_client_expiration = src->persistent_client_expiration;
|
||||
|
||||
_mosquitto_free(dest->psk_file);
|
||||
dest->psk_file = src->psk_file;
|
||||
|
||||
dest->queue_qos0_messages = src->queue_qos0_messages;
|
||||
dest->retry_interval = src->retry_interval;
|
||||
dest->sys_interval = src->sys_interval;
|
||||
dest->upgrade_outgoing_qos = src->upgrade_outgoing_qos;
|
||||
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
dest->websockets_log_level = src->websockets_log_level;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload)
|
||||
{
|
||||
int rc = MOSQ_ERR_SUCCESS;
|
||||
struct config_recurse cr;
|
||||
int lineno;
|
||||
int len;
|
||||
struct mqtt3_config config_reload;
|
||||
#ifdef WITH_BRIDGE
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if(reload){
|
||||
memset(&config_reload, 0, sizeof(struct mqtt3_config));
|
||||
}
|
||||
|
||||
cr.log_dest = MQTT3_LOG_NONE;
|
||||
cr.log_dest_set = 0;
|
||||
cr.log_type = MOSQ_LOG_NONE;
|
||||
@ -466,18 +556,24 @@ int mqtt3_config_read(struct mqtt3_config *config, bool reload)
|
||||
cr.max_inflight_messages = 20;
|
||||
cr.max_queued_messages = 100;
|
||||
|
||||
if(!config->config_file) return 0;
|
||||
if(!db->config_file) return 0;
|
||||
|
||||
if(reload){
|
||||
/* Re-initialise appropriate config vars to default for reload. */
|
||||
_config_init_reload(config);
|
||||
_config_init_reload(db, &config_reload);
|
||||
rc = _config_read_file(&config_reload, reload, db->config_file, &cr, 0, &lineno);
|
||||
}else{
|
||||
rc = _config_read_file(config, reload, db->config_file, &cr, 0, &lineno);
|
||||
}
|
||||
rc = _config_read_file(config, reload, config->config_file, &cr, 0, &lineno);
|
||||
if(rc){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", config->config_file, lineno);
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", db->config_file, lineno);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if(reload){
|
||||
config__copy(&config_reload, config);
|
||||
}
|
||||
|
||||
#ifdef WITH_PERSISTENCE
|
||||
if(config->persistence){
|
||||
if(!config->persistence_file){
|
||||
@ -529,7 +625,7 @@ int mqtt3_config_read(struct mqtt3_config *config, bool reload)
|
||||
if(cr.log_dest_set){
|
||||
config->log_dest = cr.log_dest;
|
||||
}
|
||||
if(config->verbose){
|
||||
if(db->verbose){
|
||||
config->log_type = INT_MAX;
|
||||
}else if(cr.log_type_set){
|
||||
config->log_type = cr.log_type;
|
||||
@ -537,10 +633,9 @@ int mqtt3_config_read(struct mqtt3_config *config, bool reload)
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int _config_read_file_core(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno, FILE *fptr)
|
||||
int _config_read_file_core(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno, FILE *fptr, char **buf, int *buflen)
|
||||
{
|
||||
int rc;
|
||||
char buf[1024];
|
||||
char *token;
|
||||
int tmp_int;
|
||||
char *saveptr = NULL;
|
||||
@ -569,13 +664,13 @@ int _config_read_file_core(struct mqtt3_config *config, bool reload, const char
|
||||
|
||||
*lineno = 0;
|
||||
|
||||
while(fgets(buf, 1024, fptr)){
|
||||
while(fgets_extending(buf, buflen, fptr)){
|
||||
(*lineno)++;
|
||||
if(buf[0] != '#' && buf[0] != 10 && buf[0] != 13){
|
||||
while(buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13){
|
||||
buf[strlen(buf)-1] = 0;
|
||||
if((*buf)[0] != '#' && (*buf)[0] != 10 && (*buf)[0] != 13){
|
||||
while((*buf)[strlen((*buf))-1] == 10 || (*buf)[strlen((*buf))-1] == 13){
|
||||
(*buf)[strlen((*buf))-1] = 0;
|
||||
}
|
||||
token = strtok_r(buf, " ", &saveptr);
|
||||
token = strtok_r((*buf), " ", &saveptr);
|
||||
if(token){
|
||||
if(!strcmp(token, "acl_file")){
|
||||
if(reload){
|
||||
@ -1013,7 +1108,7 @@ int _config_read_file_core(struct mqtt3_config *config, bool reload, const char
|
||||
snprintf(conf_file, len, "%s\\%s", token, find_data.cFileName);
|
||||
conf_file[len] = '\0';
|
||||
|
||||
rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext);
|
||||
rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext, buf, buflen);
|
||||
if(rc){
|
||||
FindClose(fh);
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
|
||||
@ -1286,6 +1381,14 @@ int _config_read_file_core(struct mqtt3_config *config, bool reload, const char
|
||||
}else{
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_queued_messages value in configuration.");
|
||||
}
|
||||
}else if(!strcmp(token, "memory_limit")){
|
||||
size_t lim;
|
||||
if(_conf_parse_int(&token, "memory_limit", (int *)&lim, saveptr)) return MOSQ_ERR_INVAL;
|
||||
if(lim < 0){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid memory_limit value (%lu).", lim);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
memory__set_limit(lim);
|
||||
}else if(!strcmp(token, "message_size_limit")){
|
||||
if(_conf_parse_int(&token, "message_size_limit", (int *)&config->message_size_limit, saveptr)) return MOSQ_ERR_INVAL;
|
||||
if(config->message_size_limit > MQTT_MAX_PAYLOAD){
|
||||
@ -1765,6 +1868,8 @@ int _config_read_file(struct mqtt3_config *config, bool reload, const char *file
|
||||
{
|
||||
int rc;
|
||||
FILE *fptr = NULL;
|
||||
char *buf;
|
||||
int buflen;
|
||||
|
||||
fptr = _mosquitto_fopen(file, "rt", false);
|
||||
if(!fptr){
|
||||
@ -1772,7 +1877,15 @@ int _config_read_file(struct mqtt3_config *config, bool reload, const char *file
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = _config_read_file_core(config, reload, file, cr, level, lineno, fptr);
|
||||
buflen = 1000;
|
||||
buf = _mosquitto_malloc(buflen);
|
||||
if(!buf){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
rc = _config_read_file_core(config, reload, file, cr, level, lineno, fptr, &buf, &buflen);
|
||||
_mosquitto_free(buf);
|
||||
fclose(fptr);
|
||||
|
||||
return rc;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2012-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -390,7 +390,7 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
|
||||
#endif
|
||||
if(flag_reload){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Reloading config.");
|
||||
mqtt3_config_read(db->config, true);
|
||||
mqtt3_config_read(db, db->config, true);
|
||||
mosquitto_security_cleanup(db, true);
|
||||
mosquitto_security_init(db, true);
|
||||
mosquitto_security_apply(db);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -259,8 +259,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
_mosquitto_net_init();
|
||||
|
||||
mqtt3_config_init(&config);
|
||||
rc = mqtt3_config_parse_args(&config, argc, argv);
|
||||
mqtt3_config_init(&int_db, &config);
|
||||
rc = mqtt3_config_parse_args(&int_db, &config, argc, argv);
|
||||
if(rc != MOSQ_ERR_SUCCESS) return rc;
|
||||
int_db.config = &config;
|
||||
|
||||
@ -292,8 +292,8 @@ int main(int argc, char *argv[])
|
||||
return rc;
|
||||
}
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s (build date %s) starting", VERSION, TIMESTAMP);
|
||||
if(config.config_file){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", config.config_file);
|
||||
if(int_db.config_file){
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", int_db.config_file);
|
||||
}else{
|
||||
_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Using default config.");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -101,7 +101,6 @@ struct _mqtt3_listener {
|
||||
};
|
||||
|
||||
struct mqtt3_config {
|
||||
char *config_file;
|
||||
char *acl_file;
|
||||
bool allow_anonymous;
|
||||
bool allow_duplicate_messages;
|
||||
@ -137,7 +136,6 @@ struct mqtt3_config {
|
||||
int sys_interval;
|
||||
bool upgrade_outgoing_qos;
|
||||
char *user;
|
||||
bool verbose;
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
int websockets_log_level;
|
||||
bool have_websockets_listener;
|
||||
@ -260,9 +258,11 @@ struct mosquitto_db{
|
||||
int bridge_count;
|
||||
#endif
|
||||
int msg_store_count;
|
||||
char *config_file;
|
||||
struct mqtt3_config *config;
|
||||
int persistence_changes;
|
||||
struct _mosquitto_auth_plugin auth_plugin;
|
||||
bool verbose;
|
||||
#ifdef WITH_SYS_TREE
|
||||
int subscription_count;
|
||||
int retained_count;
|
||||
@ -365,14 +365,14 @@ struct mosquitto_db *_mosquitto_get_db(void);
|
||||
* Config functions
|
||||
* ============================================================ */
|
||||
/* Initialise config struct to default values. */
|
||||
void mqtt3_config_init(struct mqtt3_config *config);
|
||||
void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config);
|
||||
/* Parse command line options into config. */
|
||||
int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]);
|
||||
int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[]);
|
||||
/* Read configuration data from config->config_file into config.
|
||||
* If reload is true, don't process config options that shouldn't be reloaded (listeners etc)
|
||||
* Returns 0 on success, 1 if there is a configuration error or if a file cannot be opened.
|
||||
*/
|
||||
int mqtt3_config_read(struct mqtt3_config *config, bool reload);
|
||||
int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload);
|
||||
/* Free all config data. */
|
||||
void mqtt3_config_cleanup(struct mqtt3_config *config);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2012-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2012-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
@ -336,6 +336,12 @@ int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context)
|
||||
|
||||
#ifdef WITH_TLS
|
||||
if(context->listener && context->listener->ssl_ctx && context->listener->use_identity_as_username){
|
||||
/* Don't need the username or password if provided */
|
||||
_mosquitto_free(username);
|
||||
username = NULL;
|
||||
_mosquitto_free(password);
|
||||
password = NULL;
|
||||
|
||||
if(!context->ssl){
|
||||
_mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD);
|
||||
rc = 1;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2011-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2011-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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2011-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
|
||||
|
11
src/subs.c
11
src/subs.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2010-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
|
||||
@ -681,9 +681,12 @@ static int _retain_process(struct mosquitto_db *db, struct mosquitto_msg_store *
|
||||
return rc;
|
||||
}
|
||||
|
||||
qos = retained->qos;
|
||||
|
||||
if(qos > sub_qos) qos = sub_qos;
|
||||
if (db->config->upgrade_outgoing_qos){
|
||||
qos = sub_qos;
|
||||
} else {
|
||||
qos = retained->qos;
|
||||
if(qos > sub_qos) qos = sub_qos;
|
||||
}
|
||||
if(qos > 0){
|
||||
mid = _mosquitto_mid_generate(context);
|
||||
}else{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009-2014 Roger Light <roger@atchoo.org>
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2014 Roger Light <roger@atchoo.org>
|
||||
Copyright (c) 2014-2018 Roger Light <roger@atchoo.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -201,6 +201,12 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
mosq->ws_context = context;
|
||||
#endif
|
||||
mosq->wsi = wsi;
|
||||
if(in){
|
||||
mosq->ssl = (SSL *)in;
|
||||
if(!mosq->listener->ssl_ctx){
|
||||
mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl);
|
||||
}
|
||||
}
|
||||
u->mosq = mosq;
|
||||
}else{
|
||||
return -1;
|
||||
@ -234,6 +240,7 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
mosq->pollfd_index = -1;
|
||||
}
|
||||
mosq->wsi = NULL;
|
||||
mosq->ssl = NULL;
|
||||
do_disconnect(db, mosq);
|
||||
}
|
||||
break;
|
||||
@ -243,7 +250,7 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
return -1;
|
||||
}
|
||||
mosq = u->mosq;
|
||||
if(!mosq || mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
|
||||
if(!mosq){
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -276,14 +283,30 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
count = packet->to_process;
|
||||
#endif
|
||||
if(count < 0){
|
||||
if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef WITH_SYS_TREE
|
||||
g_bytes_sent += count;
|
||||
#endif
|
||||
packet->to_process -= count;
|
||||
packet->pos += count;
|
||||
if(packet->to_process > 0){
|
||||
if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WITH_SYS_TREE
|
||||
g_msgs_sent++;
|
||||
if(((packet->command)&0xF6) == PUBLISH){
|
||||
g_pub_msgs_sent++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Free data and reset values */
|
||||
mosq->current_out_packet = mosq->out_packet;
|
||||
if(mosq->out_packet){
|
||||
@ -298,6 +321,9 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
|
||||
mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
|
||||
}
|
||||
if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
|
||||
return -1;
|
||||
}
|
||||
if(mosq->current_out_packet){
|
||||
libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
|
||||
}
|
||||
@ -379,7 +405,12 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
|
||||
mosq->last_msg_in = mosquitto_time();
|
||||
|
||||
if(rc){
|
||||
if(rc && (mosq->out_packet || mosq->current_out_packet)) {
|
||||
if(mosq->state != mosq_cs_disconnecting){
|
||||
mosq->state = mosq_cs_disconnect_ws;
|
||||
}
|
||||
libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
|
||||
} else if (rc) {
|
||||
do_disconnect(db, mosq);
|
||||
return -1;
|
||||
}
|
||||
|
2
test/broker/04-retain-upgrade-outgoing-qos.conf
Normal file
2
test/broker/04-retain-upgrade-outgoing-qos.conf
Normal file
@ -0,0 +1,2 @@
|
||||
port 1888
|
||||
upgrade_outgoing_qos true
|
48
test/broker/04-retain-upgrade-outgoing-qos.py
Executable file
48
test/broker/04-retain-upgrade-outgoing-qos.py
Executable file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test whether a retained PUBLISH to a topic with QoS 0 is sent with subscriber QoS
|
||||
# when upgrade_outgoing_qos is true
|
||||
|
||||
import inspect, os, sys
|
||||
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
|
||||
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
|
||||
if cmd_subfolder not in sys.path:
|
||||
sys.path.insert(0, cmd_subfolder)
|
||||
|
||||
import mosq_test
|
||||
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
mid = 16
|
||||
connect_packet = mosq_test.gen_connect("retain-qos0-test", keepalive=keepalive)
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
publish_packet = mosq_test.gen_publish("retain/qos0/test", qos=0, payload="retained message", retain=True)
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "retain/qos0/test", 1)
|
||||
suback_packet = mosq_test.gen_suback(mid, 1)
|
||||
|
||||
publish_packet2 = mosq_test.gen_publish("retain/qos0/test", mid=1, qos=1, payload="retained message", retain=True)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__))
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet)
|
||||
sock.send(publish_packet)
|
||||
|
||||
#sock.close()
|
||||
#sock = mosq_test.do_client_connect(connect_packet, connack_packet)
|
||||
sock.send(subscribe_packet)
|
||||
|
||||
if mosq_test.expect_packet(sock, "suback", suback_packet):
|
||||
if mosq_test.expect_packet(sock, "publish", publish_packet2):
|
||||
rc = 0
|
||||
sock.close()
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
if rc:
|
||||
(stdo, stde) = broker.communicate()
|
||||
print(stde)
|
||||
|
||||
exit(rc)
|
||||
|
14
test/broker/06-bridge-b2br-remapping.conf
Normal file
14
test/broker/06-bridge-b2br-remapping.conf
Normal file
@ -0,0 +1,14 @@
|
||||
port 1889
|
||||
|
||||
retry_interval 10
|
||||
|
||||
connection bridge_sample
|
||||
address 127.0.0.1:1888
|
||||
bridge_attempt_unsubscribe false
|
||||
topic # in 0 local/topic/ remote/topic/
|
||||
topic prefix/# in 0 local2/topic/ remote2/topic/
|
||||
topic +/value in 0 local3/topic/ remote3/topic/
|
||||
topic ic/+ in 0 local4/top remote4/tip
|
||||
topic clients/total in 0 test/mosquitto/org $SYS/broker/
|
||||
notifications false
|
||||
restart_timeout 5
|
117
test/broker/06-bridge-b2br-remapping.py
Executable file
117
test/broker/06-bridge-b2br-remapping.py
Executable file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test remapping of topic name for incoming message
|
||||
|
||||
import socket
|
||||
|
||||
import inspect, os, sys
|
||||
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
|
||||
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
|
||||
if cmd_subfolder not in sys.path:
|
||||
sys.path.insert(0, cmd_subfolder)
|
||||
|
||||
import mosq_test
|
||||
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
client_id = socket.gethostname()+".bridge_sample"
|
||||
connect_packet = mosq_test.gen_connect(client_id, keepalive=keepalive, clean_session=False, proto_ver=128+3)
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
client_connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive)
|
||||
client_connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
ssock.settimeout(4)
|
||||
ssock.bind(('', 1888))
|
||||
ssock.listen(5)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=1889)
|
||||
|
||||
|
||||
def test(bridge, sock):
|
||||
if not mosq_test.expect_packet(bridge, "connect", connect_packet):
|
||||
return 1
|
||||
bridge.send(connack_packet)
|
||||
|
||||
mid = 0
|
||||
patterns = [
|
||||
"remote/topic/#",
|
||||
"remote2/topic/prefix/#",
|
||||
"remote3/topic/+/value",
|
||||
"remote4/tipic/+",
|
||||
"$SYS/broker/clients/total",
|
||||
]
|
||||
for pattern in ("remote/topic/#", "remote2/topic/prefix/#", "remote3/topic/+/value"):
|
||||
mid += 1
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, pattern, 0)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0)
|
||||
if not mosq_test.expect_packet(bridge, "subscribe", subscribe_packet):
|
||||
return 1
|
||||
bridge.send(suback_packet)
|
||||
|
||||
mid += 1
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "#", 0)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0)
|
||||
sock.send(subscribe_packet)
|
||||
if not mosq_test.expect_packet(sock, "suback", suback_packet):
|
||||
return 1
|
||||
|
||||
cases = [
|
||||
('local/topic/something', 'remote/topic/something'),
|
||||
('local/topic/some/t/h/i/n/g', 'remote/topic/some/t/h/i/n/g'),
|
||||
('local/topic/value', 'remote/topic/value'),
|
||||
# Don't work, #40 must be fixed before
|
||||
# ('local/topic', 'remote/topic'),
|
||||
('local2/topic/prefix/something', 'remote2/topic/prefix/something'),
|
||||
('local3/topic/something/value', 'remote3/topic/something/value'),
|
||||
('local4/topic/something', 'remote4/tipic/something'),
|
||||
('test/mosquitto/orgclients/total', '$SYS/broker/clients/total'),
|
||||
]
|
||||
|
||||
for (local_topic, remote_topic) in cases:
|
||||
mid += 1
|
||||
remote_publish_packet = mosq_test.gen_publish(
|
||||
remote_topic, qos=0, mid=mid, payload=''
|
||||
)
|
||||
local_publish_packet = mosq_test.gen_publish(
|
||||
local_topic, qos=0, mid=mid, payload=''
|
||||
)
|
||||
|
||||
bridge.send(remote_publish_packet)
|
||||
match = mosq_test.expect_packet(sock, "publish", local_publish_packet)
|
||||
if not match:
|
||||
print("Fail on cases local_topic=%r, remote_topic=%r" % (
|
||||
local_topic, remote_topic,
|
||||
))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
try:
|
||||
(bridge, address) = ssock.accept()
|
||||
bridge.settimeout(2)
|
||||
|
||||
sock = mosq_test.do_client_connect(
|
||||
client_connect_packet, client_connack_packet,
|
||||
port=1889,
|
||||
)
|
||||
|
||||
rc = test(bridge, sock)
|
||||
|
||||
sock.close()
|
||||
bridge.close()
|
||||
finally:
|
||||
try:
|
||||
bridge.close()
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
if rc:
|
||||
(stdo, stde) = broker.communicate()
|
||||
print(stde)
|
||||
ssock.close()
|
||||
|
||||
exit(rc)
|
15
test/broker/06-bridge-br2b-remapping.conf
Normal file
15
test/broker/06-bridge-br2b-remapping.conf
Normal file
@ -0,0 +1,15 @@
|
||||
port 1889
|
||||
|
||||
retry_interval 10
|
||||
|
||||
connection bridge_sample
|
||||
address 127.0.0.1:1888
|
||||
bridge_attempt_unsubscribe false
|
||||
topic # out 0 local/topic/ remote/topic/
|
||||
topic prefix/# out 0 local2/topic/ remote2/topic/
|
||||
topic +/value out 0 local3/topic/ remote3/topic/
|
||||
topic ic/+ out 0 local4/top remote4/tip
|
||||
# this one is invalid
|
||||
topic +/value out 0 local5/top remote5/tip
|
||||
notifications false
|
||||
restart_timeout 5
|
109
test/broker/06-bridge-br2b-remapping.py
Executable file
109
test/broker/06-bridge-br2b-remapping.py
Executable file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test remapping of topic name for outgoing message
|
||||
|
||||
import socket
|
||||
|
||||
import inspect, os, sys
|
||||
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
|
||||
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
|
||||
if cmd_subfolder not in sys.path:
|
||||
sys.path.insert(0, cmd_subfolder)
|
||||
|
||||
import mosq_test
|
||||
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
client_id = socket.gethostname()+".bridge_sample"
|
||||
connect_packet = mosq_test.gen_connect(client_id, keepalive=keepalive, clean_session=False, proto_ver=128+3)
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
client_connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive)
|
||||
client_connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
ssock.settimeout(4)
|
||||
ssock.bind(('', 1888))
|
||||
ssock.listen(5)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=1889)
|
||||
|
||||
|
||||
def test(bridge, sock):
|
||||
if not mosq_test.expect_packet(bridge, "connect", connect_packet):
|
||||
return 1
|
||||
|
||||
bridge.send(connack_packet)
|
||||
|
||||
cases = [
|
||||
('local/topic/something', 'remote/topic/something'),
|
||||
('local/topic/some/t/h/i/n/g', 'remote/topic/some/t/h/i/n/g'),
|
||||
('local/topic/value', 'remote/topic/value'),
|
||||
# Don't work, #40 must be fixed before
|
||||
# ('local/topic', 'remote/topic'),
|
||||
('local2/topic/something', None), # don't match topic pattern
|
||||
('local2/topic/prefix/something', 'remote2/topic/prefix/something'),
|
||||
('local3/topic/something/value', 'remote3/topic/something/value'),
|
||||
('local4/topic/something', 'remote4/tipic/something'),
|
||||
('local5/topic/something', None),
|
||||
]
|
||||
|
||||
mid = 3
|
||||
for (local_topic, remote_topic) in cases:
|
||||
mid += 1
|
||||
local_publish_packet = mosq_test.gen_publish(
|
||||
local_topic, qos=0, mid=mid, payload=''
|
||||
)
|
||||
sock.send(local_publish_packet)
|
||||
if remote_topic:
|
||||
remote_publish_packet = mosq_test.gen_publish(
|
||||
remote_topic, qos=0, mid=mid, payload=''
|
||||
)
|
||||
match = mosq_test.expect_packet(bridge, "publish", remote_publish_packet)
|
||||
if not match:
|
||||
print("Fail on cases local_topic=%r, remote_topic=%r" % (
|
||||
local_topic, remote_topic,
|
||||
))
|
||||
return 1
|
||||
else:
|
||||
bridge.settimeout(3)
|
||||
try:
|
||||
bridge.recv(1)
|
||||
print("FAIL: Received data when nothing is expected")
|
||||
print("Fail on cases local_topic=%r, remote_topic=%r" % (
|
||||
local_topic, remote_topic,
|
||||
))
|
||||
return 1
|
||||
except socket.timeout:
|
||||
pass
|
||||
bridge.settimeout(20)
|
||||
return 0
|
||||
|
||||
try:
|
||||
(bridge, address) = ssock.accept()
|
||||
bridge.settimeout(2)
|
||||
|
||||
sock = mosq_test.do_client_connect(
|
||||
client_connect_packet, client_connack_packet,
|
||||
port=1889,
|
||||
)
|
||||
|
||||
rc = test(bridge, sock)
|
||||
|
||||
sock.close()
|
||||
bridge.close()
|
||||
finally:
|
||||
try:
|
||||
bridge.close()
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
if rc:
|
||||
(stdo, stde) = broker.communicate()
|
||||
print(stde)
|
||||
ssock.close()
|
||||
|
||||
exit(rc)
|
@ -1,9 +1,10 @@
|
||||
port 1889
|
||||
|
||||
connection bridge_test
|
||||
address localhost:1888
|
||||
address 127.0.0.1:1888
|
||||
topic bridge/# both 0
|
||||
notifications false
|
||||
restart_timeout 2
|
||||
|
||||
#bridge_cafile ../ssl/test-root-ca.crt
|
||||
bridge_cafile ../ssl/all-ca.crt
|
||||
|
@ -59,6 +59,7 @@ endif
|
||||
./04-retain-qos0-repeated.py
|
||||
./04-retain-qos1-qos0.py
|
||||
./04-retain-qos0-clear.py
|
||||
./04-retain-upgrade-outgoing-qos.py
|
||||
|
||||
05 :
|
||||
./05-clean-session-qos1.py
|
||||
@ -71,6 +72,8 @@ endif
|
||||
./06-bridge-b2br-disconnect-qos2.py
|
||||
./06-bridge-fail-persist-resend-qos1.py
|
||||
./06-bridge-fail-persist-resend-qos2.py
|
||||
./06-bridge-b2br-remapping.py
|
||||
./06-bridge-br2b-remapping.py
|
||||
|
||||
07 :
|
||||
./07-will-qos0.py
|
||||
@ -89,9 +92,11 @@ ifeq ($(WITH_TLS),yes)
|
||||
./08-ssl-connect-identity.py
|
||||
./08-ssl-connect-no-identity.py
|
||||
./08-ssl-bridge.py
|
||||
ifeq ($(WITH_TLS_PSK),yes)
|
||||
./08-tls-psk-pub.py
|
||||
./08-tls-psk-bridge.py
|
||||
endif
|
||||
endif
|
||||
|
||||
09 :
|
||||
./09-plugin-auth-unpwd-success.py
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <mosquitto.h>
|
||||
|
||||
#define EXPECT_MATCH(A, B) do_check((A), (B), false)
|
||||
#define EXPECT_NOMATCH(A, B) do_check((A), (B), true)
|
||||
|
||||
void do_check(const char *sub, const char *topic, bool bad_res)
|
||||
{
|
||||
bool match;
|
||||
@ -16,42 +19,44 @@ void do_check(const char *sub, const char *topic, bool bad_res)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
do_check("foo/#", "foo/", false);
|
||||
do_check("foo#", "foo", true);
|
||||
do_check("fo#o/", "foo", true);
|
||||
do_check("foo#", "fooa", true);
|
||||
do_check("foo+", "foo", true);
|
||||
do_check("foo+", "fooa", true);
|
||||
EXPECT_MATCH("foo/#", "foo/");
|
||||
EXPECT_NOMATCH("foo#", "foo");
|
||||
EXPECT_NOMATCH("fo#o/", "foo");
|
||||
EXPECT_NOMATCH("foo#", "fooa");
|
||||
EXPECT_NOMATCH("foo+", "foo");
|
||||
EXPECT_NOMATCH("foo+", "fooa");
|
||||
|
||||
do_check("test/6/#", "test/3", true);
|
||||
do_check("foo/bar", "foo/bar", false);
|
||||
do_check("foo/+", "foo/bar", false);
|
||||
do_check("foo/+/baz", "foo/bar/baz", false);
|
||||
EXPECT_NOMATCH("test/6/#", "test/3");
|
||||
EXPECT_MATCH("foo/bar", "foo/bar");
|
||||
EXPECT_MATCH("foo/+", "foo/bar");
|
||||
EXPECT_MATCH("foo/+/baz", "foo/bar/baz");
|
||||
|
||||
do_check("A/B/+/#", "A/B/B/C", false);
|
||||
EXPECT_MATCH("A/B/+/#", "A/B/B/C");
|
||||
|
||||
do_check("foo/+/#", "foo/bar/baz", false);
|
||||
do_check("#", "foo/bar/baz", false);
|
||||
EXPECT_MATCH("foo/+/#", "foo/bar/baz");
|
||||
EXPECT_MATCH("foo/+/#", "foo/bar");
|
||||
EXPECT_MATCH("#", "foo/bar/baz");
|
||||
EXPECT_MATCH("#", "foo/bar/baz");
|
||||
|
||||
do_check("foo/bar", "foo", true);
|
||||
do_check("foo/+", "foo/bar/baz", true);
|
||||
do_check("foo/+/baz", "foo/bar/bar", true);
|
||||
EXPECT_NOMATCH("foo/bar", "foo");
|
||||
EXPECT_NOMATCH("foo/+", "foo/bar/baz");
|
||||
EXPECT_NOMATCH("foo/+/baz", "foo/bar/bar");
|
||||
|
||||
do_check("foo/+/#", "fo2/bar/baz", true);
|
||||
EXPECT_NOMATCH("foo/+/#", "fo2/bar/baz");
|
||||
|
||||
do_check("#", "/foo/bar", false);
|
||||
do_check("/#", "/foo/bar", false);
|
||||
do_check("/#", "foo/bar", true);
|
||||
EXPECT_MATCH("#", "/foo/bar");
|
||||
EXPECT_MATCH("/#", "/foo/bar");
|
||||
EXPECT_NOMATCH("/#", "foo/bar");
|
||||
|
||||
|
||||
do_check("foo//bar", "foo//bar", false);
|
||||
do_check("foo//+", "foo//bar", false);
|
||||
do_check("foo/+/+/baz", "foo///baz", false);
|
||||
do_check("foo/bar/+", "foo/bar/", false);
|
||||
EXPECT_MATCH("foo//bar", "foo//bar");
|
||||
EXPECT_MATCH("foo//+", "foo//bar");
|
||||
EXPECT_MATCH("foo/+/+/baz", "foo///baz");
|
||||
EXPECT_MATCH("foo/bar/+", "foo/bar/");
|
||||
|
||||
do_check("$SYS/bar", "$SYS/bar", false);
|
||||
do_check("#", "$SYS/bar", true);
|
||||
do_check("$BOB/bar", "$SYS/bar", true);
|
||||
EXPECT_MATCH("$SYS/bar", "$SYS/bar");
|
||||
EXPECT_NOMATCH("#", "$SYS/bar");
|
||||
EXPECT_NOMATCH("$BOB/bar", "$SYS/bar");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user