Fix issue#1293 - the retained flags should be propagated for bridge.
This commit is contained in:
parent
2611f660de
commit
26fb809dbe
|
@ -174,7 +174,8 @@
|
||||||
will_topic = undefined :: undefined | binary(),
|
will_topic = undefined :: undefined | binary(),
|
||||||
will_msg = undefined :: undefined | binary(),
|
will_msg = undefined :: undefined | binary(),
|
||||||
username = undefined :: undefined | binary(),
|
username = undefined :: undefined | binary(),
|
||||||
password = undefined :: undefined | binary()
|
password = undefined :: undefined | binary(),
|
||||||
|
is_bridge = false :: boolean()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_connack,
|
-record(mqtt_packet_connack,
|
||||||
|
|
|
@ -79,7 +79,7 @@ parse_frame(Bin, #mqtt_packet_header{type = Type, qos = Qos} = Header, Length)
|
||||||
{?CONNECT, <<FrameBin:Length/binary, Rest/binary>>} ->
|
{?CONNECT, <<FrameBin:Length/binary, Rest/binary>>} ->
|
||||||
{ProtoName, Rest1} = parse_utf(FrameBin),
|
{ProtoName, Rest1} = parse_utf(FrameBin),
|
||||||
%% Fix mosquitto bridge: 0x83, 0x84
|
%% Fix mosquitto bridge: 0x83, 0x84
|
||||||
<<_Bridge:4, ProtoVersion:4, Rest2/binary>> = Rest1,
|
<<BridgeTag:4, ProtoVersion:4, Rest2/binary>> = Rest1,
|
||||||
<<UsernameFlag : 1,
|
<<UsernameFlag : 1,
|
||||||
PasswordFlag : 1,
|
PasswordFlag : 1,
|
||||||
WillRetain : 1,
|
WillRetain : 1,
|
||||||
|
@ -109,7 +109,8 @@ parse_frame(Bin, #mqtt_packet_header{type = Type, qos = Qos} = Header, Length)
|
||||||
will_topic = WillTopic,
|
will_topic = WillTopic,
|
||||||
will_msg = WillMsg,
|
will_msg = WillMsg,
|
||||||
username = UserName,
|
username = UserName,
|
||||||
password = PasssWord}, Rest);
|
password = PasssWord,
|
||||||
|
is_bridge = (BridgeTag =:= 8)}, Rest);
|
||||||
false ->
|
false ->
|
||||||
{error, protocol_header_corrupt}
|
{error, protocol_header_corrupt}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
clean_sess, proto_ver, proto_name, username, is_superuser,
|
clean_sess, proto_ver, proto_name, username, is_superuser,
|
||||||
will_msg, keepalive, keepalive_backoff, max_clientid_len,
|
will_msg, keepalive, keepalive_backoff, max_clientid_len,
|
||||||
session, stats_data, mountpoint, ws_initial_headers,
|
session, stats_data, mountpoint, ws_initial_headers,
|
||||||
connected_at}).
|
is_bridge, connected_at}).
|
||||||
|
|
||||||
-type(proto_state() :: #proto_state{}).
|
-type(proto_state() :: #proto_state{}).
|
||||||
|
|
||||||
|
@ -180,7 +180,8 @@ process(?CONNECT_PACKET(Var), State0) ->
|
||||||
password = Password,
|
password = Password,
|
||||||
clean_sess = CleanSess,
|
clean_sess = CleanSess,
|
||||||
keep_alive = KeepAlive,
|
keep_alive = KeepAlive,
|
||||||
client_id = ClientId} = Var,
|
client_id = ClientId,
|
||||||
|
is_bridge = IsBridge} = Var,
|
||||||
|
|
||||||
State1 = State0#proto_state{proto_ver = ProtoVer,
|
State1 = State0#proto_state{proto_ver = ProtoVer,
|
||||||
proto_name = ProtoName,
|
proto_name = ProtoName,
|
||||||
|
@ -189,6 +190,7 @@ process(?CONNECT_PACKET(Var), State0) ->
|
||||||
clean_sess = CleanSess,
|
clean_sess = CleanSess,
|
||||||
keepalive = KeepAlive,
|
keepalive = KeepAlive,
|
||||||
will_msg = willmsg(Var, State0),
|
will_msg = willmsg(Var, State0),
|
||||||
|
is_bridge = IsBridge,
|
||||||
connected_at = os:timestamp()},
|
connected_at = os:timestamp()},
|
||||||
|
|
||||||
{ReturnCode1, SessPresent, State3} =
|
{ReturnCode1, SessPresent, State3} =
|
||||||
|
@ -333,10 +335,11 @@ with_puback(Type, Packet = ?PUBLISH_PACKET(_Qos, PacketId),
|
||||||
-spec(send(mqtt_message() | mqtt_packet(), proto_state()) -> {ok, proto_state()}).
|
-spec(send(mqtt_message() | mqtt_packet(), proto_state()) -> {ok, proto_state()}).
|
||||||
send(Msg, State = #proto_state{client_id = ClientId,
|
send(Msg, State = #proto_state{client_id = ClientId,
|
||||||
username = Username,
|
username = Username,
|
||||||
mountpoint = MountPoint})
|
mountpoint = MountPoint,
|
||||||
|
is_bridge = IsBridge})
|
||||||
when is_record(Msg, mqtt_message) ->
|
when is_record(Msg, mqtt_message) ->
|
||||||
emqttd_hooks:run('message.delivered', [ClientId, Username], Msg),
|
emqttd_hooks:run('message.delivered', [ClientId, Username], Msg),
|
||||||
send(emqttd_message:to_packet(unmount(MountPoint, Msg)), State);
|
send(emqttd_message:to_packet(unmount(MountPoint, clean_retain(IsBridge, Msg))), State);
|
||||||
|
|
||||||
send(Packet = ?PACKET(Type),
|
send(Packet = ?PACKET(Type),
|
||||||
State = #proto_state{sendfun = SendFun, stats_data = Stats}) ->
|
State = #proto_state{sendfun = SendFun, stats_data = Stats}) ->
|
||||||
|
@ -543,6 +546,15 @@ check_acl(subscribe, Topic, Client) ->
|
||||||
sp(true) -> 1;
|
sp(true) -> 1;
|
||||||
sp(false) -> 0.
|
sp(false) -> 0.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% The retained flag should be propagated for bridge.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
clean_retain(false, Msg = #mqtt_message{retain = true}) ->
|
||||||
|
Msg#mqtt_message{retain = false};
|
||||||
|
clean_retain(true, Msg) ->
|
||||||
|
Msg.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Mount Point
|
%% Mount Point
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -152,9 +152,10 @@
|
||||||
%% Force GC Count
|
%% Force GC Count
|
||||||
force_gc_count :: undefined | integer(),
|
force_gc_count :: undefined | integer(),
|
||||||
|
|
||||||
created_at :: erlang:timestamp(),
|
%% Ignore loop deliver?
|
||||||
|
ignore_loop_deliver = false :: boolean(),
|
||||||
|
|
||||||
ignore_loop_deliver = false :: boolean()
|
created_at :: erlang:timestamp()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(TIMEOUT, 60000).
|
-define(TIMEOUT, 60000).
|
||||||
|
@ -529,17 +530,14 @@ handle_cast({destroy, ClientId},
|
||||||
handle_cast(Msg, State) ->
|
handle_cast(Msg, State) ->
|
||||||
?UNEXPECTED_MSG(Msg, State).
|
?UNEXPECTED_MSG(Msg, State).
|
||||||
|
|
||||||
%% Dispatch message from self publish
|
%% Ignore Messages delivered by self
|
||||||
handle_info({dispatch, Topic, Msg = #mqtt_message{from = {ClientId, _}}},
|
handle_info({dispatch, _Topic, #mqtt_message{from = {ClientId, _}}},
|
||||||
State = #state{client_id = ClientId,
|
State = #state{client_id = ClientId, ignore_loop_deliver = true}) ->
|
||||||
ignore_loop_deliver = IgnoreLoopDeliver}) when is_record(Msg, mqtt_message) ->
|
hibernate(State);
|
||||||
case IgnoreLoopDeliver of
|
|
||||||
true -> {noreply, State, hibernate};
|
|
||||||
false -> {noreply, handle_dispatch(Topic, Msg, State), hibernate}
|
|
||||||
end;
|
|
||||||
%% Dispatch Message
|
%% Dispatch Message
|
||||||
handle_info({dispatch, Topic, Msg}, State) when is_record(Msg, mqtt_message) ->
|
handle_info({dispatch, Topic, Msg}, State) when is_record(Msg, mqtt_message) ->
|
||||||
{noreply, handle_dispatch(Topic, Msg, State), hibernate};
|
hibernate(gc(dispatch(tune_qos(Topic, reset_dup(Msg), State), State)));
|
||||||
|
|
||||||
%% Do nothing if the client has been disconnected.
|
%% Do nothing if the client has been disconnected.
|
||||||
handle_info({timeout, _Timer, retry_delivery}, State = #state{client_pid = undefined}) ->
|
handle_info({timeout, _Timer, retry_delivery}, State = #state{client_pid = undefined}) ->
|
||||||
|
@ -552,7 +550,7 @@ handle_info({timeout, _Timer, check_awaiting_rel}, State) ->
|
||||||
hibernate(expire_awaiting_rel(emit_stats(State#state{await_rel_timer = undefined})));
|
hibernate(expire_awaiting_rel(emit_stats(State#state{await_rel_timer = undefined})));
|
||||||
|
|
||||||
handle_info({timeout, _Timer, expired}, State) ->
|
handle_info({timeout, _Timer, expired}, State) ->
|
||||||
?LOG(debug, "Expired, shutdown now.", [], State),
|
?LOG(info, "Expired, shutdown now.", [], State),
|
||||||
shutdown(expired, State);
|
shutdown(expired, State);
|
||||||
|
|
||||||
handle_info({'EXIT', ClientPid, _Reason},
|
handle_info({'EXIT', ClientPid, _Reason},
|
||||||
|
@ -563,7 +561,7 @@ handle_info({'EXIT', ClientPid, Reason},
|
||||||
State = #state{clean_sess = false,
|
State = #state{clean_sess = false,
|
||||||
client_pid = ClientPid,
|
client_pid = ClientPid,
|
||||||
expiry_interval = Interval}) ->
|
expiry_interval = Interval}) ->
|
||||||
?LOG(debug, "Client ~p EXIT for ~p", [ClientPid, Reason], State),
|
?LOG(info, "Client ~p EXIT for ~p", [ClientPid, Reason], State),
|
||||||
ExpireTimer = start_timer(Interval, expired),
|
ExpireTimer = start_timer(Interval, expired),
|
||||||
State1 = State#state{client_pid = undefined, expiry_timer = ExpireTimer},
|
State1 = State#state{client_pid = undefined, expiry_timer = ExpireTimer},
|
||||||
hibernate(emit_stats(State1));
|
hibernate(emit_stats(State1));
|
||||||
|
@ -687,9 +685,6 @@ is_awaiting_full(#state{awaiting_rel = AwaitingRel, max_awaiting_rel = MaxLen})
|
||||||
%% Dispatch Messages
|
%% Dispatch Messages
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
handle_dispatch(Topic, Msg, State) ->
|
|
||||||
gc(dispatch(tune_qos(Topic, reset_dup(Msg), State), State)).
|
|
||||||
|
|
||||||
%% Enqueue message if the client has been disconnected
|
%% Enqueue message if the client has been disconnected
|
||||||
dispatch(Msg, State = #state{client_pid = undefined}) ->
|
dispatch(Msg, State = #state{client_pid = undefined}) ->
|
||||||
enqueue_msg(Msg, State);
|
enqueue_msg(Msg, State);
|
||||||
|
|
Loading…
Reference in New Issue