Will delay tests and implementation.
parent
b0c60fb6e1
commit
c506c8335b
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (c) 2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <utlist.h>
|
||||
|
||||
#include "mosquitto_broker_internal.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "time_mosq.h"
|
||||
|
||||
struct will_delay_list {
|
||||
struct mosquitto *context;
|
||||
struct will_delay_list *prev;
|
||||
struct will_delay_list *next;
|
||||
};
|
||||
|
||||
static struct will_delay_list *delay_list = NULL;
|
||||
static time_t last_check = 0;
|
||||
|
||||
|
||||
static int will_delay__cmp(struct will_delay_list *i1, struct will_delay_list *i2)
|
||||
{
|
||||
return i1->context->will_delay_interval - i2->context->will_delay_interval;
|
||||
}
|
||||
|
||||
|
||||
int will_delay__add(struct mosquitto *context)
|
||||
{
|
||||
struct will_delay_list *item;
|
||||
|
||||
item = mosquitto__calloc(1, sizeof(struct will_delay_list));
|
||||
if(!item) return MOSQ_ERR_NOMEM;
|
||||
|
||||
item->context = context;
|
||||
item->context->will_delay_time = time(NULL) + item->context->will_delay_interval;
|
||||
|
||||
DL_INSERT_INORDER(delay_list, item, will_delay__cmp);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Call on broker shutdown only */
|
||||
void will_delay__send_all(struct mosquitto_db *db)
|
||||
{
|
||||
struct will_delay_list *item, *tmp;
|
||||
|
||||
DL_FOREACH_SAFE(delay_list, item, tmp){
|
||||
DL_DELETE(delay_list, item);
|
||||
item->context->will_delay_interval = 0;
|
||||
context__send_will(db, item->context);
|
||||
mosquitto__free(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void will_delay__check(struct mosquitto_db *db, time_t now)
|
||||
{
|
||||
struct will_delay_list *item, *tmp;
|
||||
|
||||
if(now <= last_check) return;
|
||||
|
||||
last_check = now;
|
||||
|
||||
DL_FOREACH_SAFE(delay_list, item, tmp){
|
||||
if(item->context->will_delay_time < now){
|
||||
DL_DELETE(delay_list, item);
|
||||
item->context->will_delay_interval = 0;
|
||||
context__send_will(db, item->context);
|
||||
context__add_to_disused(db, item->context);
|
||||
mosquitto__free(item);
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test whether a client with a will delay handles correctly on the client reconnecting
|
||||
# First connection is durable, second is clean session, and without a will, so the will should not be received.
|
||||
# MQTT 5
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
|
||||
def do_test():
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
|
||||
mid = 1
|
||||
connect1_packet = mosq_test.gen_connect("will-qos0-test", keepalive=keepalive, proto_ver=5)
|
||||
connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_WILL_DELAY_INTERVAL, 3)
|
||||
connect2a_packet = mosq_test.gen_connect("will-helper", keepalive=keepalive, proto_ver=5, will_topic="will/test", will_payload="will delay", will_properties=props, clean_session=False)
|
||||
connack2a_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
connect2b_packet = mosq_test.gen_connect("will-helper", keepalive=keepalive, proto_ver=5, clean_session=True)
|
||||
connack2b_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "will/test", 0, proto_ver=5)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5)
|
||||
|
||||
pingreq_packet = mosq_test.gen_pingreq()
|
||||
pingresp_packet = mosq_test.gen_pingresp()
|
||||
|
||||
port = mosq_test.get_port()
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
sock1 = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=30, port=port)
|
||||
mosq_test.do_send_receive(sock1, subscribe_packet, suback_packet, "suback")
|
||||
|
||||
sock2 = mosq_test.do_client_connect(connect2a_packet, connack2a_packet, timeout=30, port=port)
|
||||
sock2.close()
|
||||
|
||||
time.sleep(1)
|
||||
sock2 = mosq_test.do_client_connect(connect2b_packet, connack2b_packet, timeout=30, port=port)
|
||||
time.sleep(3)
|
||||
|
||||
# The client2 has reconnected within the original will delay interval, which has now
|
||||
# passed, but it should have been deleted anyway. Disconnect and see
|
||||
# whether we get the old will. We should not.
|
||||
sock2.close()
|
||||
|
||||
mosq_test.do_send_receive(sock1, pingreq_packet, pingresp_packet, "pingresp")
|
||||
rc = 0
|
||||
|
||||
sock1.close()
|
||||
sock2.close()
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde)
|
||||
exit(rc)
|
||||
|
||||
|
||||
do_test()
|
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test whether a client with a will delay recovers on the client reconnecting
|
||||
# MQTT 5
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
|
||||
def do_test(clean_session):
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
|
||||
mid = 1
|
||||
connect1_packet = mosq_test.gen_connect("will-qos0-test", keepalive=keepalive, proto_ver=5)
|
||||
connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_WILL_DELAY_INTERVAL, 3)
|
||||
connect2_packet = mosq_test.gen_connect("will-helper", keepalive=keepalive, proto_ver=5, will_topic="will/test", will_payload="will delay", will_properties=props, clean_session=clean_session)
|
||||
connack2a_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
if clean_session == True:
|
||||
connack2b_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
else:
|
||||
connack2b_packet = mosq_test.gen_connack(rc=0, proto_ver=5, flags=1)
|
||||
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "will/test", 0, proto_ver=5)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5)
|
||||
|
||||
pingreq_packet = mosq_test.gen_pingreq()
|
||||
pingresp_packet = mosq_test.gen_pingresp()
|
||||
|
||||
port = mosq_test.get_port()
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
sock1 = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=30, port=port)
|
||||
mosq_test.do_send_receive(sock1, subscribe_packet, suback_packet, "suback")
|
||||
|
||||
sock2 = mosq_test.do_client_connect(connect2_packet, connack2a_packet, timeout=30, port=port)
|
||||
sock2.close()
|
||||
|
||||
time.sleep(1)
|
||||
sock2 = mosq_test.do_client_connect(connect2_packet, connack2b_packet, timeout=30, port=port)
|
||||
time.sleep(3)
|
||||
|
||||
# The client2 has reconnected within the will delay interval, which has now
|
||||
# passed. We should not have received the will at this point.
|
||||
mosq_test.do_send_receive(sock1, pingreq_packet, pingresp_packet, "pingresp")
|
||||
rc = 0
|
||||
|
||||
sock1.close()
|
||||
sock2.close()
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde)
|
||||
exit(rc)
|
||||
|
||||
|
||||
do_test(clean_session=True)
|
||||
do_test(clean_session=False)
|
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Test whether a client will is transmitted with a delay correctly.
|
||||
# MQTT 5
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def do_test(clean_session):
|
||||
rc = 1
|
||||
keepalive = 60
|
||||
|
||||
mid = 1
|
||||
connect1_packet = mosq_test.gen_connect("will-qos0-test", keepalive=keepalive, proto_ver=5)
|
||||
connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_WILL_DELAY_INTERVAL, 3)
|
||||
connect2_packet = mosq_test.gen_connect("will-helper", keepalive=keepalive, proto_ver=5, will_topic="will/test", will_payload="will delay", will_qos=2, will_properties=props, clean_session=clean_session)
|
||||
connack2_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
|
||||
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "will/test", 0, proto_ver=5)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5)
|
||||
|
||||
publish_packet = mosq_test.gen_publish("will/test", qos=0, payload="will delay", proto_ver=5)
|
||||
|
||||
port = mosq_test.get_port()
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
sock1 = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=30, port=port)
|
||||
mosq_test.do_send_receive(sock1, subscribe_packet, suback_packet, "suback")
|
||||
|
||||
sock2 = mosq_test.do_client_connect(connect2_packet, connack2_packet, timeout=30, port=port)
|
||||
sock2.close()
|
||||
|
||||
t_start = time.time()
|
||||
if mosq_test.expect_packet(sock1, "publish", publish_packet):
|
||||
t_finish = time.time()
|
||||
if t_finish - t_start > 2 and t_finish - t_start < 5:
|
||||
rc = 0
|
||||
|
||||
sock1.close()
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde)
|
||||
exit(rc)
|
||||
|
||||
do_test(clean_session=True)
|
||||
do_test(clean_session=False)
|
Loading…
Reference in New Issue