Merge pull request #10871 from HJianBo/fix-coap-bugs
fix(coap): to better handle coap requests in connection mode
This commit is contained in:
commit
8ce0132569
|
@ -1,7 +1,7 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{application, emqx_gateway, [
|
{application, emqx_gateway, [
|
||||||
{description, "The Gateway management application"},
|
{description, "The Gateway management application"},
|
||||||
{vsn, "0.1.18"},
|
{vsn, "0.1.19"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{mod, {emqx_gateway_app, []}},
|
{mod, {emqx_gateway_app, []}},
|
||||||
{applications, [kernel, stdlib, emqx, emqx_authn, emqx_ctl]},
|
{applications, [kernel, stdlib, emqx, emqx_authn, emqx_ctl]},
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
-export([
|
-export([
|
||||||
open_session/5,
|
open_session/5,
|
||||||
open_session/6,
|
open_session/6,
|
||||||
|
discard_session/2,
|
||||||
kick_session/2,
|
kick_session/2,
|
||||||
kick_session/3,
|
kick_session/3,
|
||||||
takeover_session/2,
|
takeover_session/2,
|
||||||
|
|
|
@ -304,6 +304,8 @@ handle_call(
|
||||||
handle_call(subscriptions, _From, Channel = #channel{session = Session}) ->
|
handle_call(subscriptions, _From, Channel = #channel{session = Session}) ->
|
||||||
Subs = emqx_coap_session:info(subscriptions, Session),
|
Subs = emqx_coap_session:info(subscriptions, Session),
|
||||||
{reply, {ok, maps:to_list(Subs)}, Channel};
|
{reply, {ok, maps:to_list(Subs)}, Channel};
|
||||||
|
handle_call({check_token, ReqToken}, _From, Channel = #channel{token = Token}) ->
|
||||||
|
{reply, ReqToken == Token, Channel};
|
||||||
handle_call(kick, _From, Channel) ->
|
handle_call(kick, _From, Channel) ->
|
||||||
NChannel = ensure_disconnected(kicked, Channel),
|
NChannel = ensure_disconnected(kicked, Channel),
|
||||||
shutdown_and_reply(kicked, ok, NChannel);
|
shutdown_and_reply(kicked, ok, NChannel);
|
||||||
|
@ -319,6 +321,9 @@ handle_call(Req, _From, Channel) ->
|
||||||
|
|
||||||
-spec handle_cast(Req :: term(), channel()) ->
|
-spec handle_cast(Req :: term(), channel()) ->
|
||||||
ok | {ok, channel()} | {shutdown, Reason :: term(), channel()}.
|
ok | {ok, channel()} | {shutdown, Reason :: term(), channel()}.
|
||||||
|
handle_cast(close, Channel) ->
|
||||||
|
?SLOG(info, #{msg => "close_connection"}),
|
||||||
|
shutdown(normal, Channel);
|
||||||
handle_cast(Req, Channel) ->
|
handle_cast(Req, Channel) ->
|
||||||
?SLOG(error, #{msg => "unexpected_cast", cast => Req}),
|
?SLOG(error, #{msg => "unexpected_cast", cast => Req}),
|
||||||
{ok, Channel}.
|
{ok, Channel}.
|
||||||
|
@ -376,18 +381,54 @@ ensure_keepalive_timer(Fun, #channel{keepalive = KeepAlive} = Channel) ->
|
||||||
Heartbeat = emqx_keepalive:info(interval, KeepAlive),
|
Heartbeat = emqx_keepalive:info(interval, KeepAlive),
|
||||||
Fun(keepalive, Heartbeat, keepalive, Channel).
|
Fun(keepalive, Heartbeat, keepalive, Channel).
|
||||||
|
|
||||||
check_auth_state(Msg, #channel{connection_required = Required} = Channel) ->
|
check_auth_state(Msg, #channel{connection_required = true} = Channel) ->
|
||||||
check_token(Required, Msg, Channel).
|
case is_create_connection_request(Msg) of
|
||||||
|
true ->
|
||||||
|
call_session(handle_request, Msg, Channel);
|
||||||
|
false ->
|
||||||
|
URIQuery = emqx_coap_message:get_option(uri_query, Msg, #{}),
|
||||||
|
case maps:get(<<"token">>, URIQuery, undefined) of
|
||||||
|
undefined ->
|
||||||
|
?SLOG(debug, #{msg => "token_required_in_conn_mode", message => Msg});
|
||||||
|
_ ->
|
||||||
|
check_token(Msg, Channel)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
is_create_connection_request(Msg = #coap_message{method = Method}) when
|
||||||
|
is_atom(Method) andalso Method =/= undefined
|
||||||
|
->
|
||||||
|
URIPath = emqx_coap_message:get_option(uri_path, Msg, []),
|
||||||
|
case URIPath of
|
||||||
|
[<<"mqtt">>, <<"connection">>] when Method == post ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
is_create_connection_request(_Msg) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
is_delete_connection_request(Msg = #coap_message{method = Method}) when
|
||||||
|
is_atom(Method) andalso Method =/= undefined
|
||||||
|
->
|
||||||
|
URIPath = emqx_coap_message:get_option(uri_path, Msg, []),
|
||||||
|
case URIPath of
|
||||||
|
[<<"mqtt">>, <<"connection">>] when Method == delete ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
is_delete_connection_request(_Msg) ->
|
||||||
|
false.
|
||||||
|
|
||||||
check_token(
|
check_token(
|
||||||
true,
|
|
||||||
Msg,
|
Msg,
|
||||||
#channel{
|
#channel{
|
||||||
token = Token,
|
token = Token,
|
||||||
clientinfo = ClientInfo,
|
clientinfo = ClientInfo
|
||||||
conn_state = CState
|
|
||||||
} = Channel
|
} = Channel
|
||||||
) ->
|
) ->
|
||||||
|
IsDeleteConn = is_delete_connection_request(Msg),
|
||||||
#{clientid := ClientId} = ClientInfo,
|
#{clientid := ClientId} = ClientInfo,
|
||||||
case emqx_coap_message:get_option(uri_query, Msg) of
|
case emqx_coap_message:get_option(uri_query, Msg) of
|
||||||
#{
|
#{
|
||||||
|
@ -395,37 +436,33 @@ check_token(
|
||||||
<<"token">> := Token
|
<<"token">> := Token
|
||||||
} ->
|
} ->
|
||||||
call_session(handle_request, Msg, Channel);
|
call_session(handle_request, Msg, Channel);
|
||||||
#{<<"clientid">> := DesireId} ->
|
#{<<"clientid">> := ReqClientId, <<"token">> := ReqToken} ->
|
||||||
try_takeover(CState, DesireId, Msg, Channel);
|
case emqx_gateway_cm:call(coap, ReqClientId, {check_token, ReqToken}) of
|
||||||
_ ->
|
undefined when IsDeleteConn ->
|
||||||
Reply = emqx_coap_message:piggyback({error, unauthorized}, Msg),
|
Reply = emqx_coap_message:piggyback({ok, deleted}, Msg),
|
||||||
{ok, {outgoing, Reply}, Channel}
|
{shutdown, normal, Reply, Channel};
|
||||||
end;
|
|
||||||
check_token(false, Msg, Channel) ->
|
|
||||||
call_session(handle_request, Msg, Channel).
|
|
||||||
|
|
||||||
try_takeover(idle, DesireId, Msg, Channel) ->
|
|
||||||
case emqx_coap_message:get_option(uri_path, Msg, []) of
|
|
||||||
[<<"mqtt">>, <<"connection">> | _] ->
|
|
||||||
%% may be is a connect request
|
|
||||||
%% TODO need check repeat connect, unless we implement the
|
|
||||||
%% udp connection baseon the clientid
|
|
||||||
call_session(handle_request, Msg, Channel);
|
|
||||||
_ ->
|
|
||||||
case emqx_conf:get([gateway, coap, ?AUTHN], undefined) of
|
|
||||||
undefined ->
|
undefined ->
|
||||||
call_session(handle_request, Msg, Channel);
|
?SLOG(info, #{
|
||||||
_ ->
|
msg => "remote_connection_not_found",
|
||||||
do_takeover(DesireId, Msg, Channel)
|
clientid => ReqClientId,
|
||||||
end
|
token => ReqToken
|
||||||
end;
|
}),
|
||||||
try_takeover(_, DesireId, Msg, Channel) ->
|
Reply = emqx_coap_message:reset(Msg),
|
||||||
do_takeover(DesireId, Msg, Channel).
|
{shutdown, normal, Reply, Channel};
|
||||||
|
false ->
|
||||||
do_takeover(_DesireId, Msg, Channel) ->
|
?SLOG(info, #{
|
||||||
%% TODO completed the takeover, now only reset the message
|
msg => "request_token_invalid", clientid => ReqClientId, token => ReqToken
|
||||||
Reset = emqx_coap_message:reset(Msg),
|
}),
|
||||||
{ok, {outgoing, Reset}, Channel}.
|
Reply = emqx_coap_message:piggyback({error, unauthorized}, Msg),
|
||||||
|
{shutdown, normal, Reply, Channel};
|
||||||
|
true ->
|
||||||
|
call_session(handle_request, Msg, Channel)
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ErrMsg = <<"Missing token or clientid in connection mode">>,
|
||||||
|
Reply = emqx_coap_message:piggyback({error, bad_request}, ErrMsg, Msg),
|
||||||
|
{shutdown, normal, Reply, Channel}
|
||||||
|
end.
|
||||||
|
|
||||||
run_conn_hooks(
|
run_conn_hooks(
|
||||||
Input,
|
Input,
|
||||||
|
@ -612,6 +649,9 @@ ensure_disconnected(
|
||||||
end,
|
end,
|
||||||
Channel#channel{conninfo = NConnInfo, conn_state = disconnected}.
|
Channel#channel{conninfo = NConnInfo, conn_state = disconnected}.
|
||||||
|
|
||||||
|
shutdown(Reason, Channel) ->
|
||||||
|
{shutdown, Reason, Channel}.
|
||||||
|
|
||||||
shutdown_and_reply(Reason, Reply, Channel) ->
|
shutdown_and_reply(Reason, Reply, Channel) ->
|
||||||
{shutdown, Reason, Reply, Channel}.
|
{shutdown, Reason, Reply, Channel}.
|
||||||
|
|
||||||
|
@ -759,6 +799,17 @@ process_connection(
|
||||||
Channel
|
Channel
|
||||||
);
|
);
|
||||||
process_connection({close, Msg}, _, Channel, _) ->
|
process_connection({close, Msg}, _, Channel, _) ->
|
||||||
|
Queries = emqx_coap_message:get_option(uri_query, Msg),
|
||||||
|
case maps:get(<<"clientid">>, Queries, undefined) of
|
||||||
|
undefined ->
|
||||||
|
ok;
|
||||||
|
ClientId ->
|
||||||
|
%% XXX: A cluster-level connection shutdown needs to be performed here.
|
||||||
|
%%
|
||||||
|
%% due to the possibility that the current close request may be
|
||||||
|
%% from a CoAP client from another IP + Port tuple
|
||||||
|
emqx_gateway_cm:cast(coap, ClientId, close)
|
||||||
|
end,
|
||||||
Reply = emqx_coap_message:piggyback({ok, deleted}, Msg),
|
Reply = emqx_coap_message:piggyback({ok, deleted}, Msg),
|
||||||
NChannel = ensure_disconnected(normal, Channel),
|
NChannel = ensure_disconnected(normal, Channel),
|
||||||
{shutdown, normal, Reply, NChannel}.
|
{shutdown, normal, Reply, NChannel}.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_gateway_coap, [
|
{application, emqx_gateway_coap, [
|
||||||
{description, "CoAP Gateway"},
|
{description, "CoAP Gateway"},
|
||||||
{vsn, "0.1.0"},
|
{vsn, "0.1.1"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [kernel, stdlib, emqx, emqx_gateway]},
|
{applications, [kernel, stdlib, emqx, emqx_gateway]},
|
||||||
{env, []},
|
{env, []},
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixes for connection deletion and message publishing requests not taking effect
|
||||||
|
issues once the connection has been created in a different UDP port first.
|
Loading…
Reference in New Issue