mirror of
https://github.com/eclipse/mosquitto.git
synced 2025-05-09 01:01:11 +08:00
Retain-as-published support.
This commit is contained in:
parent
4933f889ff
commit
db7901884f
@ -700,6 +700,11 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c
|
||||
}else{
|
||||
cfg->pub_mode = MSGMODE_NULL;
|
||||
}
|
||||
}else if(!strcmp(argv[i], "--retain-as-published")){
|
||||
if(pub_or_sub == CLIENT_PUB){
|
||||
goto unknown_option;
|
||||
}
|
||||
cfg->sub_opts |= MQTT_SUB_OPT_RETAIN_AS_PUBLISHED;
|
||||
}else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--protocol-version")){
|
||||
if(i==argc-1){
|
||||
fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n");
|
||||
|
@ -86,6 +86,7 @@ struct mosq_config {
|
||||
int msg_count; /* sub */
|
||||
char *format; /* sub */
|
||||
int timeout; /* sub */
|
||||
int sub_opts; /* sub */
|
||||
#ifdef WITH_SOCKS
|
||||
char *socks5_host;
|
||||
int socks5_port;
|
||||
|
@ -90,7 +90,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag
|
||||
int i;
|
||||
|
||||
if(!result){
|
||||
mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.subscribe_props);
|
||||
mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.sub_opts, cfg.subscribe_props);
|
||||
|
||||
for(i=0; i<cfg.unsub_topic_count; i++){
|
||||
mosquitto_unsubscribe_v5(mosq, NULL, cfg.unsub_topics[i], cfg.unsubscribe_props);
|
||||
|
@ -145,10 +145,10 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in
|
||||
|
||||
int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
|
||||
{
|
||||
return mosquitto_subscribe_v5(mosq, mid, sub, qos, NULL);
|
||||
return mosquitto_subscribe_v5(mosq, mid, sub, qos, 0, NULL);
|
||||
}
|
||||
|
||||
int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties)
|
||||
int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
@ -156,6 +156,8 @@ int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, in
|
||||
int rc;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL;
|
||||
if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
|
||||
|
||||
@ -175,11 +177,11 @@ int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, in
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, outgoing_properties);
|
||||
return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos|options, outgoing_properties);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties)
|
||||
int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
@ -189,6 +191,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count
|
||||
if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL;
|
||||
if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL;
|
||||
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
|
||||
|
||||
if(properties){
|
||||
@ -209,7 +212,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count
|
||||
if(mosquitto_validate_utf8(sub[i], strlen(sub[i]))) return MOSQ_ERR_MALFORMED_UTF8;
|
||||
}
|
||||
|
||||
return send__subscribe(mosq, mid, sub_count, sub, qos, properties);
|
||||
return send__subscribe(mosq, mid, sub_count, sub, qos|options, properties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -840,6 +840,30 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c
|
||||
* sent.
|
||||
* sub - the subscription pattern.
|
||||
* qos - the requested Quality of Service for this subscription.
|
||||
* options - options to apply to this subscription, OR'd together. Set to 0 to
|
||||
* use the default options, otherwise choose from the list:
|
||||
* MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client
|
||||
* publishes to a topic to which it is subscribed, the
|
||||
* broker will not publish the message back to the
|
||||
* client.
|
||||
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
|
||||
* published for this subscription will keep the
|
||||
* retain flag as was set by the publishing client.
|
||||
* The default behaviour without this option set has
|
||||
* the retain flag indicating whether a message is
|
||||
* fresh/stale.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
|
||||
* pre-existing retained messages are sent as soon as
|
||||
* the subscription is made, even if the subscription
|
||||
* already exists. This is the default behaviour, so
|
||||
* it is not necessary to set this option.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
|
||||
* retained messages for this subscription will be
|
||||
* sent when the subscription is made, but only if the
|
||||
* subscription does not already exist.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
|
||||
* pre-existing retained messages will never be sent
|
||||
* for this subscription.
|
||||
* properties - a valid mosquitto_property list, or NULL.
|
||||
*
|
||||
* Returns:
|
||||
@ -851,7 +875,7 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c
|
||||
* MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden.
|
||||
* MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE.
|
||||
*/
|
||||
libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties);
|
||||
libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties);
|
||||
|
||||
/*
|
||||
* Function: mosquitto_subscribe_multiple
|
||||
@ -871,6 +895,30 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons
|
||||
* familiar with this, just think of it as a safer "char **",
|
||||
* equivalent to "const char *" for a simple string pointer.
|
||||
* qos - the requested Quality of Service for each subscription.
|
||||
* options - options to apply to this subscription, OR'd together. Set to 0 to
|
||||
* use the default options, otherwise choose from the list:
|
||||
* MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client
|
||||
* publishes to a topic to which it is subscribed, the
|
||||
* broker will not publish the message back to the
|
||||
* client.
|
||||
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
|
||||
* published for this subscription will keep the
|
||||
* retain flag as was set by the publishing client.
|
||||
* The default behaviour without this option set has
|
||||
* the retain flag indicating whether a message is
|
||||
* fresh/stale.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
|
||||
* pre-existing retained messages are sent as soon as
|
||||
* the subscription is made, even if the subscription
|
||||
* already exists. This is the default behaviour, so
|
||||
* it is not necessary to set this option.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
|
||||
* retained messages for this subscription will be
|
||||
* sent when the subscription is made, but only if the
|
||||
* subscription does not already exist.
|
||||
* MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
|
||||
* pre-existing retained messages will never be sent
|
||||
* for this subscription.
|
||||
* properties - a valid mosquitto_property list, or NULL. Only used with MQTT
|
||||
* v5 clients.
|
||||
*
|
||||
@ -881,7 +929,7 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons
|
||||
* MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
|
||||
* MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8
|
||||
*/
|
||||
int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties);
|
||||
int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties);
|
||||
|
||||
/*
|
||||
* Function: mosquitto_unsubscribe
|
||||
|
@ -145,6 +145,14 @@ enum mqtt5_property_type {
|
||||
MQTT_PROP_TYPE_STRING_PAIR = 7
|
||||
};
|
||||
|
||||
enum mqtt5_sub_options {
|
||||
MQTT_SUB_OPT_NO_LOCAL = 0x04,
|
||||
MQTT_SUB_OPT_RETAIN_AS_PUBLISHED = 0x08,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_ALWAYS = 0x00,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_NEW = 0x10,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_NEVER = 0x20,
|
||||
};
|
||||
|
||||
#define MQTT_MAX_PAYLOAD 268435455
|
||||
|
||||
#endif
|
||||
|
@ -83,11 +83,11 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# ifdef WITH_BRIDGE
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic[0], topic_qos);
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[0], topic_qos&0x03, topic_qos&0xFC);
|
||||
# endif
|
||||
#else
|
||||
for(i=0; i<topic_count; i++){
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic[i], topic_qos);
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[i], topic_qos&0x03, topic_qos&0xFC);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
<arg choice='plain'><option>-R</option></arg>
|
||||
<arg choice='plain'><option>--retained-only</option></arg>
|
||||
</group>
|
||||
<arg><option>--retain-as-published</option></arg>
|
||||
<arg><option>-S</option></arg>
|
||||
<arg choice='opt' rep='repeat'><option>-T</option> <replaceable>filter-out</replaceable></arg>
|
||||
<arg choice='opt' rep='repeat'><option>-U</option> <replaceable>unsub-topic</replaceable></arg>
|
||||
@ -459,7 +460,20 @@
|
||||
Messages with retain set are "stale", in that it is not
|
||||
known when they were originally published. With this
|
||||
argument in use, the receipt of the first non-stale
|
||||
message will cause the client to exit.</para>
|
||||
message will cause the client to exit. See also the
|
||||
<option>--retain-as-published</option> option.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--retain-as-published</option></term>
|
||||
<listitem>
|
||||
<para>If this argument is given, the subscriptions will
|
||||
have the "retain as published" option set. This means
|
||||
that the retain flag on an incoming message will be
|
||||
exactly as set by the publishing client, rather than
|
||||
indicating whether the message is fresh/stale.</para>
|
||||
<para>This option is not valid for MQTT v3.1/v3.1.1
|
||||
clients.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -312,7 +312,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context)
|
||||
for(i=0; i<context->bridge->topic_count; i++){
|
||||
if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic);
|
||||
if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs) > 0){
|
||||
if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, true, &db->subs) > 0){
|
||||
return 1;
|
||||
}
|
||||
sub__retain_queue(db, context,
|
||||
|
@ -94,10 +94,13 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context)
|
||||
}
|
||||
if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt311){
|
||||
qos = subscription_options;
|
||||
if(context->is_bridge){
|
||||
retain_as_published = 1;
|
||||
}
|
||||
}else{
|
||||
qos = subscription_options & 0x03;
|
||||
|
||||
retain_as_published = subscription_options & 0x04;
|
||||
retain_as_published = subscription_options & 0x08;
|
||||
|
||||
retain_handling = (subscription_options & 0x30) >> 4;
|
||||
if(retain_handling == 3){
|
||||
@ -148,7 +151,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context)
|
||||
}
|
||||
|
||||
if(qos != 0x80){
|
||||
rc2 = sub__add(db, context, sub, qos, &db->subs);
|
||||
rc2 = sub__add(db, context, sub, qos, retain_as_published, &db->subs);
|
||||
if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){
|
||||
if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){
|
||||
if(sub__retain_queue(db, context, sub, qos)) rc = 1;
|
||||
|
@ -290,6 +290,7 @@ struct mosquitto__subleaf {
|
||||
struct mosquitto__subleaf *next;
|
||||
struct mosquitto *context;
|
||||
int qos;
|
||||
bool retain_as_published;
|
||||
};
|
||||
|
||||
struct mosquitto__subhier {
|
||||
@ -572,7 +573,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time);
|
||||
/* ============================================================
|
||||
* Subscription functions
|
||||
* ============================================================ */
|
||||
int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct mosquitto__subhier **root);
|
||||
int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root);
|
||||
struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len);
|
||||
int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root);
|
||||
void sub__tree_print(struct mosquitto__subhier *root, int level);
|
||||
|
@ -935,7 +935,8 @@ static int persist__restore_sub(struct mosquitto_db *db, const char *client_id,
|
||||
|
||||
context = persist__find_or_add_context(db, client_id, 0);
|
||||
if(!context) return 1;
|
||||
return sub__add(db, context, sub, qos, &db->subs);
|
||||
/* FIXME - retain_as_published needs saving */
|
||||
return sub__add(db, context, sub, qos, false, &db->subs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
20
src/subs.c
20
src/subs.c
@ -123,14 +123,9 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie
|
||||
}else{
|
||||
mid = 0;
|
||||
}
|
||||
if(leaf->context->is_bridge){
|
||||
/* If we know the client is a bridge then we should set retain
|
||||
* even if the message is fresh. If we don't do this, retained
|
||||
* messages won't be propagated. */
|
||||
if(leaf->retain_as_published){
|
||||
client_retain = retain;
|
||||
}else{
|
||||
/* Client is not a bridge and this isn't a stale message so
|
||||
* retain should be false. */
|
||||
client_retain = false;
|
||||
}
|
||||
if(db__message_insert(db, leaf->context, mid, mosq_md_out, msg_qos, client_retain, stored) == 1) rc = 1;
|
||||
@ -245,7 +240,7 @@ static void sub__topic_tokens_free(struct sub__token *tokens)
|
||||
}
|
||||
}
|
||||
|
||||
static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, struct mosquitto__subhier *subhier, struct sub__token *tokens)
|
||||
static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, bool retain_as_published, struct mosquitto__subhier *subhier, struct sub__token *tokens)
|
||||
/* FIXME - this function has the potential to leak subhier, audit calling functions. */
|
||||
{
|
||||
struct mosquitto__subhier *branch;
|
||||
@ -279,6 +274,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context,
|
||||
leaf->next = NULL;
|
||||
leaf->context = context;
|
||||
leaf->qos = qos;
|
||||
leaf->retain_as_published = retain_as_published;
|
||||
for(i=0; i<context->sub_count; i++){
|
||||
if(!context->subs[i]){
|
||||
context->subs[i] = subhier;
|
||||
@ -311,13 +307,13 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context,
|
||||
|
||||
HASH_FIND(hh, subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, branch);
|
||||
if(branch){
|
||||
return sub__add_recurse(db, context, qos, branch, tokens->next);
|
||||
return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next);
|
||||
}else{
|
||||
/* Not found */
|
||||
branch = sub__add_hier_entry(subhier, &subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len);
|
||||
if(!branch) return MOSQ_ERR_NOMEM;
|
||||
|
||||
return sub__add_recurse(db, context, qos, branch, tokens->next);
|
||||
return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next);
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,7 +442,7 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent
|
||||
}
|
||||
|
||||
|
||||
int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct mosquitto__subhier **root)
|
||||
int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root)
|
||||
{
|
||||
int rc = 0;
|
||||
struct mosquitto__subhier *subhier;
|
||||
@ -468,7 +464,7 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub
|
||||
}
|
||||
|
||||
}
|
||||
rc = sub__add_recurse(db, context, qos, subhier, tokens);
|
||||
rc = sub__add_recurse(db, context, qos, retain_as_published, subhier, tokens);
|
||||
|
||||
sub__topic_tokens_free(tokens);
|
||||
|
||||
@ -519,7 +515,7 @@ int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const ch
|
||||
/* We have a message that needs to be retained, so ensure that the subscription
|
||||
* tree for its topic exists.
|
||||
*/
|
||||
sub__add_recurse(db, NULL, 0, subhier, tokens);
|
||||
sub__add_recurse(db, NULL, 0, false, subhier, tokens);
|
||||
}
|
||||
sub__search(db, subhier, tokens, source_id, topic, qos, retain, *stored, true);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user