Merge branch 'fixes' into develop
This commit is contained in:
commit
81cb7ab547
@ -1,4 +1,4 @@
|
||||
1.5 - 2017xxxx
|
||||
1.5 - 2018xxxx
|
||||
==============
|
||||
|
||||
Broker:
|
||||
@ -45,6 +45,21 @@ Broker:
|
||||
- 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.
|
||||
|
||||
Client library:
|
||||
- Outgoing messages with QoS>1 are no longer retried after a timeout period.
|
||||
@ -66,8 +81,14 @@ Client library:
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
Client:
|
||||
Clients:
|
||||
- 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.
|
||||
@ -75,12 +96,14 @@ Client:
|
||||
messages.
|
||||
- Connections now default to using MQTT v3.1.1.
|
||||
- Default to using port 8883 when using TLS.
|
||||
- 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.
|
||||
|
||||
|
||||
1.4.14 - 20170710
|
||||
|
@ -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. */
|
||||
@ -414,9 +415,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
if(feof(stdin)){
|
||||
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){
|
||||
mosquitto_disconnect(mosq);
|
||||
|
@ -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);
|
||||
|
@ -1177,15 +1177,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)
|
||||
|
@ -143,6 +143,10 @@ int net__socket_close(struct mosquitto *mosq)
|
||||
|
||||
assert(mosq);
|
||||
#ifdef WITH_TLS
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(!mosq->wsi)
|
||||
#endif
|
||||
{
|
||||
if(mosq->ssl){
|
||||
SSL_shutdown(mosq->ssl);
|
||||
SSL_free(mosq->ssl);
|
||||
@ -152,24 +156,26 @@ int net__socket_close(struct mosquitto *mosq)
|
||||
SSL_CTX_free(mosq->ssl_ctx);
|
||||
mosq->ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(mosq->wsi)
|
||||
{
|
||||
if(mosq->state != mosq_cs_disconnecting){
|
||||
mosq->state = mosq_cs_disconnect_ws;
|
||||
}
|
||||
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_WEBSOCKETS
|
||||
}else if(mosq->sock == WEBSOCKET_CLIENT){
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
@ -253,7 +259,6 @@ int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *s
|
||||
|
||||
/* Set non-blocking */
|
||||
if(net__socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -268,7 +273,6 @@ int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *s
|
||||
|
||||
/* Set non-blocking */
|
||||
if(net__socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -353,7 +357,6 @@ int net__try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mo
|
||||
if(!blocking){
|
||||
/* Set non-blocking */
|
||||
if(net__socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -370,7 +373,6 @@ int net__try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mo
|
||||
if(blocking){
|
||||
/* Set non-blocking */
|
||||
if(net__socket_nonblock(*sock)){
|
||||
COMPAT_CLOSE(*sock);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -801,7 +803,6 @@ int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
continue;
|
||||
}
|
||||
if(net__socket_nonblock(spR)){
|
||||
COMPAT_CLOSE(spR);
|
||||
COMPAT_CLOSE(listensock);
|
||||
continue;
|
||||
}
|
||||
@ -829,7 +830,6 @@ int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
|
||||
if(net__socket_nonblock(spW)){
|
||||
COMPAT_CLOSE(spR);
|
||||
COMPAT_CLOSE(spW);
|
||||
COMPAT_CLOSE(listensock);
|
||||
continue;
|
||||
}
|
||||
@ -847,13 +847,11 @@ int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
if(net__socket_nonblock(sv[0])){
|
||||
COMPAT_CLOSE(sv[0]);
|
||||
COMPAT_CLOSE(sv[1]);
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
if(net__socket_nonblock(sv[1])){
|
||||
COMPAT_CLOSE(sv[0]);
|
||||
COMPAT_CLOSE(sv[1]);
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
*pairR = sv[0];
|
||||
|
@ -269,7 +269,11 @@ int 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;
|
||||
}
|
||||
@ -533,4 +537,3 @@ int packet__read(struct mosquitto *mosq)
|
||||
pthread_mutex_unlock(&mosq->msgtime_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,13 @@ int mosquitto_sub_topic_check2(const char *str, size_t len)
|
||||
int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
|
||||
{
|
||||
int slen, tlen;
|
||||
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);
|
||||
@ -237,7 +243,12 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top
|
||||
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;
|
||||
}
|
||||
|
||||
if(!sublen || !topiclen){
|
||||
*result = false;
|
||||
@ -248,7 +259,6 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top
|
||||
if((sub[0] == '$' && topic[0] != '$')
|
||||
|| (topic[0] == '$' && sub[0] != '$')){
|
||||
|
||||
*result = false;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -275,7 +285,6 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(tpos == topiclen && spos == sublen-1 && sub[spos] == '+'){
|
||||
if(spos > 0 && sub[spos-1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
spos++;
|
||||
@ -286,12 +295,10 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top
|
||||
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 < sublen-1 && sub[spos+1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
spos++;
|
||||
@ -304,19 +311,28 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top
|
||||
}
|
||||
}else if(sub[spos] == '#'){
|
||||
if(spos > 0 && sub[spos-1] != '/'){
|
||||
*result = false;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
multilevel_wildcard = true;
|
||||
if(spos+1 != sublen){
|
||||
*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 == sublen
|
||||
&& tpos == topiclen
|
||||
&& sub[spos-1] == '+'
|
||||
&& sub[spos] == '/'
|
||||
&& sub[spos+1] == '#')
|
||||
{
|
||||
*result = true;
|
||||
multilevel_wildcard = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -437,4 +453,3 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -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">
|
||||
|
@ -119,7 +119,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
|
||||
@ -1078,9 +1078,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>
|
||||
@ -1106,7 +1106,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
|
||||
@ -1129,7 +1129,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>
|
||||
@ -1351,21 +1351,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>
|
||||
|
@ -237,7 +237,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
|
||||
@ -270,7 +270,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
|
||||
|
||||
|
61
src/conf.c
61
src/conf.c
@ -67,6 +67,35 @@ static int conf__parse_string(char **token, const char *name, char **value, char
|
||||
static int config__read_file(struct mosquitto__config *config, bool reload, const char *file, struct config_recurse *config_tmp, int level, int *lineno);
|
||||
static int config__check(struct mosquitto__config *config);
|
||||
|
||||
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;
|
||||
@ -253,7 +282,12 @@ void config__cleanup(struct mosquitto__config *config)
|
||||
mosquitto__free(config->listeners[i].psk_hint);
|
||||
mosquitto__free(config->listeners[i].crlfile);
|
||||
mosquitto__free(config->listeners[i].tls_version);
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(!config->listeners[i].ws_context) /* libwebsockets frees its own SSL_CTX */
|
||||
#endif
|
||||
{
|
||||
SSL_CTX_free(config->listeners[i].ssl_ctx);
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
mosquitto__free(config->listeners[i].http_dir);
|
||||
@ -561,10 +595,9 @@ int config__read(struct mosquitto__config *config, bool reload)
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int config__read_file_core(struct mosquitto__config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno, FILE *fptr)
|
||||
int config__read_file_core(struct mosquitto__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;
|
||||
@ -595,13 +628,13 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, const
|
||||
|
||||
*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){
|
||||
@ -1056,7 +1089,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, const
|
||||
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);
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
|
||||
@ -1832,6 +1865,8 @@ int config__read_file(struct mosquitto__config *config, bool reload, const char
|
||||
{
|
||||
int rc;
|
||||
FILE *fptr = NULL;
|
||||
char *buf;
|
||||
int buflen;
|
||||
|
||||
fptr = mosquitto__fopen(file, "rt", false);
|
||||
if(!fptr){
|
||||
@ -1839,7 +1874,15 @@ int config__read_file(struct mosquitto__config *config, bool reload, const char
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = config__read_file_core(config, reload, file, cr, level, lineno, fptr);
|
||||
buflen = 1000;
|
||||
buf = mosquitto__malloc(buflen);
|
||||
if(!buf){
|
||||
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;
|
||||
|
@ -371,6 +371,12 @@ int 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 || context->listener->use_subject_as_username)){
|
||||
/* Don't need the username or password if provided */
|
||||
mosquitto__free(username);
|
||||
username = NULL;
|
||||
mosquitto__free(password);
|
||||
password = NULL;
|
||||
|
||||
if(!context->ssl){
|
||||
send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD);
|
||||
rc = 1;
|
||||
@ -645,5 +651,3 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context)
|
||||
do_disconnect(db, context);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -658,9 +658,12 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store *
|
||||
return rc;
|
||||
}
|
||||
|
||||
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{
|
||||
|
@ -183,6 +183,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;
|
||||
@ -216,6 +222,7 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
mosq->pollfd_index = -1;
|
||||
}
|
||||
mosq->wsi = NULL;
|
||||
mosq->ssl = NULL;
|
||||
do_disconnect(db, mosq);
|
||||
}
|
||||
break;
|
||||
@ -225,7 +232,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;
|
||||
}
|
||||
|
||||
@ -254,14 +261,30 @@ static int callback_mqtt(struct libwebsocket_context *context,
|
||||
}
|
||||
count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY);
|
||||
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){
|
||||
@ -276,6 +299,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);
|
||||
}
|
||||
@ -356,7 +382,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+4)
|
||||
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+4)
|
||||
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
|
||||
|
@ -58,6 +58,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
|
||||
@ -70,6 +71,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
|
||||
@ -88,9 +91,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…
Reference in New Issue
Block a user