Merge pull request #12163 from JimMoen/EMQX-11525-gw-jt808-cannot-list-client

fix(gw_jt808): cannot list client
This commit is contained in:
JimMoen 2023-12-15 14:57:18 +08:00 committed by GitHub
commit bce35b2dd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 47 deletions

View File

@ -416,7 +416,7 @@ handle_info({sock_closed, Reason}, Channel = #channel{conn_state = disconnected}
log(error, #{msg => "unexpected_sock_closed", reason => Reason}, Channel), log(error, #{msg => "unexpected_sock_closed", reason => Reason}, Channel),
{ok, Channel}; {ok, Channel};
handle_info(Info, Channel) -> handle_info(Info, Channel) ->
log(error, #{msg => "unexpected_info}", info => Info}, Channel), log(error, #{msg => "unexpected_info", info => Info}, Channel),
{ok, Channel}. {ok, Channel}.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@ -48,7 +48,7 @@
%% AuthCode %% AuthCode
authcode :: undefined | anonymous | binary(), authcode :: undefined | anonymous | binary(),
%% Keepalive %% Keepalive
keepalive, keepalive :: maybe(emqx_keepalive:keepalive()),
%% Msg SN %% Msg SN
msg_sn, msg_sn,
%% Down Topic %% Down Topic
@ -85,6 +85,8 @@
-define(INFO_KEYS, [ctx, conninfo, zone, clientid, clientinfo, session, conn_state, authcode]). -define(INFO_KEYS, [ctx, conninfo, zone, clientid, clientinfo, session, conn_state, authcode]).
-define(DN_TOPIC_SUBOPTS, #{rap => 0, nl => 0, qos => 0, rh => 0}).
-define(RETX_INTERVAL, 8000). -define(RETX_INTERVAL, 8000).
-define(RETX_MAX_TIME, 5). -define(RETX_MAX_TIME, 5).
@ -115,15 +117,28 @@ info(clientid, #channel{clientinfo = #{clientid := ClientId}}) ->
ClientId; ClientId;
info(clientinfo, #channel{clientinfo = ClientInfo}) -> info(clientinfo, #channel{clientinfo = ClientInfo}) ->
ClientInfo; ClientInfo;
info(session, _) -> info(session, #channel{session = Session}) ->
#{}; Session;
info(conn_state, #channel{conn_state = ConnState}) -> info(conn_state, #channel{conn_state = ConnState}) ->
ConnState; ConnState;
info(authcode, #channel{authcode = AuthCode}) -> info(authcode, #channel{authcode = AuthCode}) ->
AuthCode. AuthCode.
stats(_Channel) -> -spec stats(channel()) -> emqx_types:stats().
[]. stats(#channel{inflight = Inflight, mqueue = Queue}) ->
%% XXX: A fake stats for managed by emqx_management
[
{subscriptions_cnt, 1},
{subscriptions_max, 1},
{inflight_cnt, emqx_inflight:size(Inflight)},
{inflight_max, emqx_inflight:max_size(Inflight)},
{mqueue_len, queue:len(Queue)},
{mqueue_max, 0},
{mqueue_dropped, 0},
{next_pkt_id, 0},
{awaiting_rel_cnt, 0},
{awaiting_rel_max, 0}
].
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Init the Channel %% Init the Channel
@ -173,7 +188,7 @@ init(
conn_state = idle, conn_state = idle,
timers = #{}, timers = #{},
authcode = undefined, authcode = undefined,
keepalive = maps:get(keepalive, Options, ?DEFAULT_KEEPALIVE), keepalive = undefined,
msg_sn = 0, msg_sn = 0,
% TODO: init rsa_key from user input % TODO: init rsa_key from user input
dn_topic = maps:get(dn_topic, ProtoConf, ?DEFAULT_DN_TOPIC), dn_topic = maps:get(dn_topic, ProtoConf, ?DEFAULT_DN_TOPIC),
@ -228,9 +243,8 @@ do_handle_in(Frame = ?MSG(?MC_REGISTER), Channel0) ->
#{<<"header">> := #{<<"msg_sn">> := MsgSn}} = Frame, #{<<"header">> := #{<<"msg_sn">> := MsgSn}} = Frame,
case emqx_jt808_auth:register(Frame, Channel0#channel.auth) of case emqx_jt808_auth:register(Frame, Channel0#channel.auth) of
{ok, Authcode} -> {ok, Authcode} ->
Channel = enrich_clientinfo( {ok, Conninfo} = enrich_conninfo(Frame, Channel0#channel{authcode = Authcode}),
Frame, enrich_conninfo(Frame, Channel0#channel{authcode = Authcode}) {ok, Channel} = enrich_clientinfo(Frame, Conninfo),
),
handle_out({?MS_REGISTER_ACK, 0}, MsgSn, Channel); handle_out({?MS_REGISTER_ACK, 0}, MsgSn, Channel);
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{msg => "register_failed", reason => Reason}), ?SLOG(error, #{msg => "register_failed", reason => Reason}),
@ -243,25 +257,26 @@ do_handle_in(Frame = ?MSG(?MC_REGISTER), Channel0) ->
end; end;
do_handle_in(Frame = ?MSG(?MC_AUTH), Channel0) -> do_handle_in(Frame = ?MSG(?MC_AUTH), Channel0) ->
#{<<"header">> := #{<<"msg_sn">> := MsgSn}} = Frame, #{<<"header">> := #{<<"msg_sn">> := MsgSn}} = Frame,
Channel = case
#channel{clientinfo = #{clientid := ClientId}} = emqx_utils:pipeline(
enrich_clientinfo(Frame, enrich_conninfo(Frame, Channel0)), [
authack( fun enrich_clientinfo/2,
case authenticate(Frame, Channel0) of fun enrich_conninfo/2,
true -> fun set_log_meta/2
NChannel = prepare_adapter_topic(ensure_connected(Channel)), ],
emqx_logger:set_metadata_clientid(ClientId), Frame,
%% Auto subscribe downlink topics Channel0
autosubcribe(NChannel), )
_ = start_keepalive(?DEFAULT_KEEPALIVE, NChannel), of
%% 0: Successful {ok, _NFrame, Channel} ->
{0, MsgSn, NChannel}; case authenticate(Frame, Channel) of
false -> true ->
?SLOG(error, #{msg => "authenticated_failed"}), NChannel = process_connect(Frame, ensure_connected(Channel)),
%% 1: Failure authack({0, MsgSn, NChannel});
{1, MsgSn, Channel} false ->
end authack({1, MsgSn, Channel})
); end
end;
do_handle_in(Frame = ?MSG(?MC_HEARTBEAT), Channel) -> do_handle_in(Frame = ?MSG(?MC_HEARTBEAT), Channel) ->
handle_out({?MS_GENERAL_RESPONSE, 0, ?MC_HEARTBEAT}, msgsn(Frame), Channel); handle_out({?MS_GENERAL_RESPONSE, 0, ?MC_HEARTBEAT}, msgsn(Frame), Channel);
do_handle_in(?MSG(?MC_RSA_KEY), Channel = #channel{rsa_key = [E, N]}) -> do_handle_in(?MSG(?MC_RSA_KEY), Channel = #channel{rsa_key = [E, N]}) ->
@ -428,6 +443,8 @@ handle_call(kick, _From, Channel) ->
disconnect_and_shutdown(kicked, ok, Channel1); disconnect_and_shutdown(kicked, ok, Channel1);
handle_call(discard, _From, Channel) -> handle_call(discard, _From, Channel) ->
disconnect_and_shutdown(discarded, ok, Channel); disconnect_and_shutdown(discarded, ok, Channel);
handle_call(subscriptions, _From, Channel = #channel{dn_topic = DnTopic}) ->
reply({ok, [{DnTopic, ?DN_TOPIC_SUBOPTS}]}, Channel);
handle_call(Req, _From, Channel) -> handle_call(Req, _From, Channel) ->
log(error, #{msg => "unexpected_call", call => Req}, Channel), log(error, #{msg => "unexpected_call", call => Req}, Channel),
reply(ignored, Channel). reply(ignored, Channel).
@ -464,6 +481,9 @@ handle_info(
handle_info({sock_closed, Reason}, Channel = #channel{conn_state = disconnected}) -> handle_info({sock_closed, Reason}, Channel = #channel{conn_state = disconnected}) ->
log(error, #{msg => "unexpected_sock_closed", reason => Reason}, Channel), log(error, #{msg => "unexpected_sock_closed", reason => Reason}, Channel),
{ok, Channel}; {ok, Channel};
handle_info({keepalive, start, Interval}, Channel) ->
NChannel = Channel#channel{keepalive = emqx_keepalive:init(Interval)},
{ok, ensure_timer(alive_timer, NChannel)};
handle_info(Info, Channel) -> handle_info(Info, Channel) ->
log(error, #{msg => "unexpected_info", info => Info}, Channel), log(error, #{msg => "unexpected_info", info => Info}, Channel),
{ok, Channel}. {ok, Channel}.
@ -615,6 +635,46 @@ maybe_fix_mountpoint(ClientInfo = #{mountpoint := Mountpoint}) ->
Mountpoint1 = emqx_mountpoint:replvar(Mountpoint, ClientInfo), Mountpoint1 = emqx_mountpoint:replvar(Mountpoint, ClientInfo),
ClientInfo#{mountpoint := Mountpoint1}. ClientInfo#{mountpoint := Mountpoint1}.
process_connect(
_Frame,
Channel = #channel{
ctx = Ctx,
conninfo = ConnInfo,
clientinfo = ClientInfo = #{clientid := ClientId}
}
) ->
SessFun = fun(_, _) -> #{} end,
case
emqx_gateway_ctx:open_session(
Ctx,
true,
ClientInfo,
ConnInfo,
SessFun
)
of
{ok, #{session := Session}} ->
NChannel = Channel#channel{session = Session},
%% Auto subscribe downlink topics
ok = autosubcribe(NChannel),
_ = start_keepalive(?DEFAULT_KEEPALIVE, NChannel),
_ = run_hooks(Ctx, 'client.connack', [ConnInfo, connection_accepted, #{}]),
_ = emqx_gateway_ctx:insert_channel_info(
Ctx, ClientId, info(NChannel), stats(NChannel)
),
NChannel;
{error, Reason} ->
log(
error,
#{
msg => "failed_to_open_session",
reason => Reason
},
Channel
),
shutdown(Reason, Channel)
end.
ensure_connected( ensure_connected(
Channel = #channel{ Channel = #channel{
ctx = Ctx, ctx = Ctx,
@ -624,10 +684,7 @@ ensure_connected(
) -> ) ->
NConnInfo = ConnInfo#{connected_at => erlang:system_time(millisecond)}, NConnInfo = ConnInfo#{connected_at => erlang:system_time(millisecond)},
ok = run_hooks(Ctx, 'client.connected', [ClientInfo, NConnInfo]), ok = run_hooks(Ctx, 'client.connected', [ClientInfo, NConnInfo]),
Channel#channel{ prepare_adapter_topic(Channel#channel{conninfo = NConnInfo, conn_state = connected}).
conninfo = NConnInfo,
conn_state = connected
}.
%% Ensure disconnected %% Ensure disconnected
ensure_disconnected( ensure_disconnected(
@ -836,7 +893,7 @@ enrich_conninfo(
receive_maximum => 0, receive_maximum => 0,
expiry_interval => 0 expiry_interval => 0
}, },
Channel#channel{conninfo = NConnInfo}. {ok, Channel#channel{conninfo = NConnInfo}}.
%% Register %% Register
enrich_clientinfo( enrich_clientinfo(
@ -855,7 +912,7 @@ enrich_clientinfo(
manufacturer => Manu, manufacturer => Manu,
terminal_id => DevId terminal_id => DevId
}), }),
Channel#channel{clientinfo = NClientInfo}; {ok, Channel#channel{clientinfo = NClientInfo}};
%% Auth %% Auth
enrich_clientinfo( enrich_clientinfo(
#{<<"header">> := #{<<"phone">> := Phone}}, #{<<"header">> := #{<<"phone">> := Phone}},
@ -865,7 +922,11 @@ enrich_clientinfo(
phone => Phone, phone => Phone,
clientid => Phone clientid => Phone
}, },
Channel#channel{clientinfo = NClientInfo}. {ok, Channel#channel{clientinfo = NClientInfo}}.
set_log_meta(_Packet, #channel{clientinfo = #{clientid := ClientId}}) ->
emqx_logger:set_metadata_clientid(ClientId),
ok.
prepare_adapter_topic(Channel = #channel{up_topic = UpTopic, dn_topic = DnTopic}) -> prepare_adapter_topic(Channel = #channel{up_topic = UpTopic, dn_topic = DnTopic}) ->
Channel#channel{ Channel#channel{
@ -905,9 +966,10 @@ autosubcribe(#channel{
#{clientid := ClientId}, #{clientid := ClientId},
dn_topic = Topic dn_topic = Topic
}) -> }) ->
SubOpts = #{rap => 0, nl => 0, qos => 0, rh => 0}, _ = emqx_broker:subscribe(Topic, ClientId, ?DN_TOPIC_SUBOPTS),
emqx:subscribe(Topic, ClientId, SubOpts), ok = emqx_hooks:run('session.subscribed', [
ok = emqx_hooks:run('session.subscribed', [ClientInfo, Topic, SubOpts#{is_new => true}]). ClientInfo, Topic, ?DN_TOPIC_SUBOPTS#{is_new => true}
]).
start_keepalive(Secs, _Channel) when Secs > 0 -> start_keepalive(Secs, _Channel) when Secs > 0 ->
self() ! {keepalive, start, round(Secs) * 1000}. self() ! {keepalive, start, round(Secs) * 1000}.

View File

@ -324,6 +324,14 @@ location_report_28bytes() ->
binary_to_hex_string(Data) -> binary_to_hex_string(Data) ->
lists:flatten([io_lib:format("~2.16.0B ", [X]) || <<X:8>> <= Data]). lists:flatten([io_lib:format("~2.16.0B ", [X]) || <<X:8>> <= Data]).
receive_msg() ->
receive
{deliver, Topic, #message{payload = Payload}} ->
{Topic, Payload}
after 100 ->
{error, timeout}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% test cases %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%% test cases %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
t_case00_register(_) -> t_case00_register(_) ->
@ -2677,11 +2685,3 @@ t_case34_dl_0x8805_single_mm_data_ctrl(_Config) ->
{error, timeout} = gen_tcp:recv(Socket, 0, 500), {error, timeout} = gen_tcp:recv(Socket, 0, 500),
ok = gen_tcp:close(Socket). ok = gen_tcp:close(Socket).
receive_msg() ->
receive
{deliver, Topic, #message{payload = Payload}} ->
{Topic, Payload}
after 100 ->
{error, timeout}
end.