rewrite all modules
This commit is contained in:
parent
0dbb739416
commit
23163edab7
|
@ -31,7 +31,9 @@
|
||||||
|
|
||||||
-define(ERTS_MINIMUM, "6.0").
|
-define(ERTS_MINIMUM, "6.0").
|
||||||
|
|
||||||
%% qos levels
|
%%------------------------------------------------------------------------------
|
||||||
|
%% MQTT Qos
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
-define(QOS_0, 0).
|
-define(QOS_0, 0).
|
||||||
-define(QOS_1, 1).
|
-define(QOS_1, 1).
|
||||||
|
@ -39,6 +41,9 @@
|
||||||
|
|
||||||
-type qos() :: ?QOS_2 | ?QOS_1 | ?QOS_0.
|
-type qos() :: ?QOS_2 | ?QOS_1 | ?QOS_0.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% MQTT Message
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
-record(mqtt_msg, {
|
-record(mqtt_msg, {
|
||||||
retain,
|
retain,
|
||||||
qos,
|
qos,
|
||||||
|
@ -51,4 +56,13 @@
|
||||||
|
|
||||||
-type mqtt_msg() :: #mqtt_msg{}.
|
-type mqtt_msg() :: #mqtt_msg{}.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% MQTT User Management
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
-record(emqtt_user, {
|
||||||
|
username :: binary(),
|
||||||
|
passwdhash :: binary()
|
||||||
|
}).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
% NOTICE: copy from rabbitmq mqtt-adaper
|
% NOTICE: copy from rabbitmq mqtt-adaper
|
||||||
%
|
%
|
||||||
|
|
||||||
|
|
||||||
%% The contents of this file are subject to the Mozilla Public License
|
%% The contents of this file are subject to the Mozilla Public License
|
||||||
%% Version 1.1 (the "License"); you may not use this file except in
|
%% Version 1.1 (the "License"); you may not use this file except in
|
||||||
%% compliance with the License. You may obtain a copy of the License
|
%% compliance with the License. You may obtain a copy of the License
|
||||||
|
@ -19,6 +18,8 @@
|
||||||
%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
|
%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
-define(PROTOCOL_NAMES, [{3, "MQIsdp"}, {4, "MQTT"}]).
|
||||||
|
|
||||||
-define(MQTT_PROTO_MAJOR, 3).
|
-define(MQTT_PROTO_MAJOR, 3).
|
||||||
-define(MQTT_PROTO_MINOR, 1).
|
-define(MQTT_PROTO_MINOR, 1).
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,8 @@
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% pubsub topic
|
%% Core PubSub Topic
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%name: <<"a/b/c">>
|
|
||||||
%node: node()
|
|
||||||
%words: [<<"a">>, <<"b">>, <<"c">>]
|
|
||||||
-record(topic, {
|
-record(topic, {
|
||||||
name :: binary(),
|
name :: binary(),
|
||||||
node :: node()
|
node :: node()
|
||||||
|
@ -55,12 +52,3 @@
|
||||||
node_id :: binary()
|
node_id :: binary()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
%% internal user
|
|
||||||
%%------------------------------------------------------------------------------
|
|
||||||
-record(internal_user, {
|
|
||||||
username :: binary(),
|
|
||||||
passwdhash :: binary()
|
|
||||||
}).
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{description, "Erlang MQTT Broker"},
|
{description, "Erlang MQTT Broker"},
|
||||||
{vsn, git},
|
{vsn, git},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [ ]},
|
{registered, []},
|
||||||
{applications, [kernel,
|
{applications, [kernel,
|
||||||
stdlib]},
|
stdlib]},
|
||||||
{mod, {emqtt_app, []}},
|
{mod, {emqtt_app, []}},
|
||||||
|
|
|
@ -40,7 +40,6 @@ listen({mqtt, Port, Options}) ->
|
||||||
esockd:listen(mqtt, Port, Options ++ ?MQTT_SOCKOPTS, MFArgs);
|
esockd:listen(mqtt, Port, Options ++ ?MQTT_SOCKOPTS, MFArgs);
|
||||||
|
|
||||||
listen({http, Port, Options}) ->
|
listen({http, Port, Options}) ->
|
||||||
Auth = proplists:get_value(auth, Options),
|
MFArgs = {emqtt_http, handle, []},
|
||||||
MFArgs = {emqtt_http, handle, [Auth]},
|
mochiweb:start_http(Port, Options, MFArgs).
|
||||||
mochiweb:start_http(Port, proplists:delete(auth, Options), MFArgs).
|
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,13 @@
|
||||||
%%
|
%%
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
print_banner(),
|
print_banner(),
|
||||||
{ok, SupPid} = emqtt_sup:start_link(),
|
{ok, Sup} = emqtt_sup:start_link(),
|
||||||
|
start_servers(Sup),
|
||||||
{ok, Listeners} = application:get_env(listen),
|
{ok, Listeners} = application:get_env(listen),
|
||||||
emqtt:listen(Listeners),
|
emqtt:listen(Listeners),
|
||||||
register(emqtt, self()),
|
register(emqtt, self()),
|
||||||
print_vsn(),
|
print_vsn(),
|
||||||
{ok, SupPid}.
|
{ok, Sup}.
|
||||||
|
|
||||||
print_banner() ->
|
print_banner() ->
|
||||||
?PRINT("starting emqtt on node '~s'~n", [node()]).
|
?PRINT("starting emqtt on node '~s'~n", [node()]).
|
||||||
|
@ -55,6 +56,40 @@ print_vsn() ->
|
||||||
{ok, Desc} = application:get_key(description),
|
{ok, Desc} = application:get_key(description),
|
||||||
?PRINT("~s ~s is running now~n", [Desc, Vsn]).
|
?PRINT("~s ~s is running now~n", [Desc, Vsn]).
|
||||||
|
|
||||||
|
start_servers(Sup) ->
|
||||||
|
lists:foreach(
|
||||||
|
fun({Name, F}) when is_function(F) ->
|
||||||
|
?PRINT("~s is starting...", [Name]),
|
||||||
|
F(),
|
||||||
|
?PRINT_MSG("[done]~n");
|
||||||
|
({Name, Server}) when is_atom(Server) ->
|
||||||
|
?PRINT("~s is starting...", [Name]),
|
||||||
|
start_child(Sup, Server),
|
||||||
|
?PRINT_MSG("[done]~n");
|
||||||
|
({Name, Server, Opts}) when is_atom(Server) ->
|
||||||
|
?PRINT("~s is starting...", [ Name]),
|
||||||
|
start_child(Sup, Server, Opts),
|
||||||
|
?PRINT_MSG("[done]~n")
|
||||||
|
end,
|
||||||
|
[{"emqtt cm", emqtt_cm},
|
||||||
|
{"emqtt auth", emqtt_auth},
|
||||||
|
{"emqtt retained", emqtt_retained},
|
||||||
|
{"emqtt pubsub", emqtt_pubsub},
|
||||||
|
{"emqtt monitor", emqtt_monitor}
|
||||||
|
]).
|
||||||
|
|
||||||
|
start_child(Sup, Name) ->
|
||||||
|
{ok, _ChiId} = supervisor:start_child(Sup, worker_spec(Name)).
|
||||||
|
start_child(Sup, Name, Opts) ->
|
||||||
|
{ok, _ChiId} = supervisor:start_child(Sup, worker_spec(Name, Opts)).
|
||||||
|
|
||||||
|
worker_spec(Name) ->
|
||||||
|
{Name, {Name, start_link, []},
|
||||||
|
permanent, 5000, worker, [Name]}.
|
||||||
|
worker_spec(Name, Opts) ->
|
||||||
|
{Name, {Name, start_link, [Opts]},
|
||||||
|
permanent, 5000, worker, [Name]}.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
%% @spec stop(atom) -> 'ok'
|
%% @spec stop(atom) -> 'ok'
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -22,13 +22,12 @@
|
||||||
|
|
||||||
-module(emqtt_auth).
|
-module(emqtt_auth).
|
||||||
|
|
||||||
-author('ery.lee@gmail.com').
|
-author('feng.lee@slimchat.io').
|
||||||
|
|
||||||
-include("emqtt.hrl").
|
-include("emqtt.hrl").
|
||||||
|
|
||||||
-include("emqtt_log.hrl").
|
-include("emqtt_log.hrl").
|
||||||
|
|
||||||
|
|
||||||
-export([start_link/0,
|
-export([start_link/0,
|
||||||
add/2,
|
add/2,
|
||||||
check/2,
|
check/2,
|
||||||
|
@ -43,44 +42,40 @@
|
||||||
terminate/2,
|
terminate/2,
|
||||||
code_change/3]).
|
code_change/3]).
|
||||||
|
|
||||||
-record(state, {authmod, authopts}).
|
|
||||||
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
-spec check(Usename :: binary(), Password :: binary()) -> true | false.
|
||||||
check(Username, Password) ->
|
check(Username, Password) ->
|
||||||
gen_server:call(?MODULE, {check, Username, Password}).
|
execute(check, [Username, Password]).
|
||||||
|
|
||||||
add(Username, Password) when is_binary(Username) ->
|
-spec add(Usename :: binary(), Password :: binary()) -> ok.
|
||||||
gen_server:call(?MODULE, {add, Username, Password}).
|
add(Username, Password) ->
|
||||||
|
execute(add, [Username, Password]).
|
||||||
|
|
||||||
delete(Username) when is_binary(Username) ->
|
-spec delete(Username :: binary()) -> ok.
|
||||||
gen_server:cast(?MODULE, {delete, Username}).
|
delete(Username) ->
|
||||||
|
execute(delete, [Username]).
|
||||||
|
|
||||||
|
execute(F, Args) ->
|
||||||
|
[{_, M}] = ets:lookup(emqtt_auth, mod),
|
||||||
|
apply(M, F, Args).
|
||||||
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
{ok, {Name, Opts}} = application:get_env(auth),
|
{ok, {Name, Opts}} = application:get_env(auth),
|
||||||
AuthMod = authmod(Name),
|
AuthMod = authmod(Name),
|
||||||
ok = AuthMod:init(Opts),
|
ok = AuthMod:init(Opts),
|
||||||
?INFO("authmod is ~p", [AuthMod]),
|
ets:new(emqtt_auth, [named_table, protected]),
|
||||||
?INFO("~p is started", [?MODULE]),
|
ets:insert(emqtt_quth, {mod, AuthMod}),
|
||||||
{ok, #state{authmod=AuthMod, authopts=Opts}}.
|
?PRINT("emqtt authmod is ~p", [AuthMod]),
|
||||||
|
{ok, undefined}.
|
||||||
|
|
||||||
authmod(Name) when is_atom(Name) ->
|
authmod(Name) when is_atom(Name) ->
|
||||||
list_to_atom(lists:concat(["emqtt_auth_", Name])).
|
list_to_atom(lists:concat(["emqtt_auth_", Name])).
|
||||||
|
|
||||||
handle_call({check, Username, Password}, _From, #state{authmod=AuthMod} = State) ->
|
|
||||||
{reply, AuthMod:check(Username, Password), State};
|
|
||||||
|
|
||||||
handle_call({add, Username, Password}, _From, #state{authmod=AuthMod} = State) ->
|
|
||||||
{reply, AuthMod:add(Username, Password), State};
|
|
||||||
|
|
||||||
handle_call(Req, _From, State) ->
|
handle_call(Req, _From, State) ->
|
||||||
{stop, {badreq, Req}, State}.
|
{stop, {badreq, Req}, State}.
|
||||||
|
|
||||||
handle_cast({delete, Username}, #state{authmod=AuthMod} = State) ->
|
|
||||||
AuthMod:delete(Username),
|
|
||||||
{noreply, State};
|
|
||||||
|
|
||||||
handle_cast(Msg, State) ->
|
handle_cast(Msg, State) ->
|
||||||
{stop, {badmsg, Msg}, State}.
|
{stop, {badmsg, Msg}, State}.
|
||||||
|
|
||||||
|
@ -92,3 +87,4 @@ terminate(_Reason, _State) ->
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
-module(emqtt_auth_anonymous).
|
-module(emqtt_auth_anonymous).
|
||||||
|
|
||||||
-author('ery.lee@gmail.com').
|
-author('feng.lee@slimchat.io').
|
||||||
|
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
add/2,
|
add/2,
|
||||||
|
@ -36,3 +36,4 @@ check(_, _) -> true.
|
||||||
add(_, _) -> ok.
|
add(_, _) -> ok.
|
||||||
|
|
||||||
delete(_Username) -> ok.
|
delete(_Username) -> ok.
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
-module(emqtt_auth_internal).
|
-module(emqtt_auth_internal).
|
||||||
|
|
||||||
-include("emqtt_internal.hrl").
|
-include("emqtt.hrl").
|
||||||
|
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
add/2,
|
add/2,
|
||||||
|
@ -30,10 +30,10 @@
|
||||||
delete/1]).
|
delete/1]).
|
||||||
|
|
||||||
init(_Opts) ->
|
init(_Opts) ->
|
||||||
mnesia:create_table(internal_user, [
|
mnesia:create_table(emqtt_user, [
|
||||||
{ram_copies, [node()]},
|
{ram_copies, [node()]},
|
||||||
{attributes, record_info(fields, internal_user)}]),
|
{attributes, record_info(fields, emqtt_user)}]),
|
||||||
mnesia:add_table_copy(internal_user, node(), ram_copies),
|
mnesia:add_table_copy(emqtt_user, node(), ram_copies),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
check(undefined, _) -> false;
|
check(undefined, _) -> false;
|
||||||
|
@ -42,14 +42,14 @@ check(_, undefined) -> false;
|
||||||
|
|
||||||
check(Username, Password) when is_binary(Username) ->
|
check(Username, Password) when is_binary(Username) ->
|
||||||
PasswdHash = crypto:hash(md5, Password),
|
PasswdHash = crypto:hash(md5, Password),
|
||||||
case mnesia:dirty_read(internal_user, Username) of
|
case mnesia:dirty_read(emqtt_user, Username) of
|
||||||
[#internal_user{passwdhash=PasswdHash}] -> true;
|
[#emqtt_user{passwdhash=PasswdHash}] -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add(Username, Password) when is_binary(Username) and is_binary(Password) ->
|
add(Username, Password) when is_binary(Username) and is_binary(Password) ->
|
||||||
mnesia:dirty_write(#internal_user{username=Username, passwdhash=crypto:hash(md5, Password)}).
|
mnesia:dirty_write(#emqtt_user{username=Username, passwdhash=crypto:hash(md5, Password)}).
|
||||||
|
|
||||||
delete(Username) when is_binary(Username) ->
|
delete(Username) when is_binary(Username) ->
|
||||||
mnesia:dirty_delete(internal_user, Username).
|
mnesia:dirty_delete(emqtt_user, Username).
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
-export([start_link/1, info/1, go/2]).
|
-export([start_link/1, info/1, go/2, stop/2]).
|
||||||
|
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
handle_call/3,
|
handle_call/3,
|
||||||
|
@ -39,8 +39,6 @@
|
||||||
|
|
||||||
-include("emqtt_frame.hrl").
|
-include("emqtt_frame.hrl").
|
||||||
|
|
||||||
-include("emqtt_internal.hrl").
|
|
||||||
|
|
||||||
-define(CLIENT_ID_MAXLEN, 23).
|
-define(CLIENT_ID_MAXLEN, 23).
|
||||||
|
|
||||||
-record(state, {socket,
|
-record(state, {socket,
|
||||||
|
@ -71,6 +69,9 @@ info(Pid) ->
|
||||||
go(Pid, Sock) ->
|
go(Pid, Sock) ->
|
||||||
gen_server:call(Pid, {go, Sock}).
|
gen_server:call(Pid, {go, Sock}).
|
||||||
|
|
||||||
|
stop(Pid, Error) ->
|
||||||
|
gen_server:cast(Pid, {stop, Error}).
|
||||||
|
|
||||||
init([Sock]) ->
|
init([Sock]) ->
|
||||||
{ok, #state{socket = Sock}}.
|
{ok, #state{socket = Sock}}.
|
||||||
|
|
||||||
|
@ -89,9 +90,6 @@ handle_call({go, Sock}, _From, State=#state{socket = Sock}) ->
|
||||||
awaiting_ack = gb_trees:empty(),
|
awaiting_ack = gb_trees:empty(),
|
||||||
awaiting_rel = gb_trees:empty()})};
|
awaiting_rel = gb_trees:empty()})};
|
||||||
|
|
||||||
handle_call(duplicate_id, _From, State=#state{conn_name=ConnName, client_id=ClientId}) ->
|
|
||||||
?ERROR("Shutdown for duplicate clientid:~s, conn:~s", [ClientId, ConnName]),
|
|
||||||
stop({shutdown, duplicate_id}, State);
|
|
||||||
|
|
||||||
handle_call(info, _From, #state{conn_name=ConnName,
|
handle_call(info, _From, #state{conn_name=ConnName,
|
||||||
message_id=MsgId, client_id=ClientId} = State) ->
|
message_id=MsgId, client_id=ClientId} = State) ->
|
||||||
|
@ -103,6 +101,10 @@ handle_call(info, _From, #state{conn_name=ConnName,
|
||||||
handle_call(_Req, _From, State) ->
|
handle_call(_Req, _From, State) ->
|
||||||
{reply, ok, State}.
|
{reply, ok, State}.
|
||||||
|
|
||||||
|
handle_cast({stop, duplicate_id}, State=#state{conn_name=ConnName, client_id=ClientId}) ->
|
||||||
|
?ERROR("Shutdown for duplicate clientid:~s, conn:~s", [ClientId, ConnName]),
|
||||||
|
stop({shutdown, duplicate_id}, State);
|
||||||
|
|
||||||
handle_cast(Msg, State) ->
|
handle_cast(Msg, State) ->
|
||||||
{stop, {badmsg, Msg}, State}.
|
{stop, {badmsg, Msg}, State}.
|
||||||
|
|
||||||
|
|
|
@ -56,15 +56,25 @@
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
-spec lookup(ClientId :: binary()) -> pid() | undefined.
|
||||||
lookup(ClientId) ->
|
lookup(ClientId) ->
|
||||||
case ets:lookup(emqtt_client, ClientId) of
|
case ets:lookup(emqtt_client, ClientId) of
|
||||||
[{_, Pid}] -> Pid;
|
[{_, Pid}] -> Pid;
|
||||||
[] -> undefined
|
[] -> undefined
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec create(ClientId :: binary(), Pid :: pid()) -> ok.
|
||||||
create(ClientId, Pid) ->
|
create(ClientId, Pid) ->
|
||||||
|
case lookup(ClientId) of
|
||||||
|
OldPid when is_pid(OldPid) ->
|
||||||
|
%%TODO: FIX STOP...
|
||||||
|
emqtt_client:stop(OldPid, duplicate_id);
|
||||||
|
undefined ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
ets:insert(emqtt_client, {ClientId, Pid}).
|
ets:insert(emqtt_client, {ClientId, Pid}).
|
||||||
|
|
||||||
|
-spec destroy(binary() | pid()) -> ok.
|
||||||
destroy(ClientId) when is_binary(ClientId) ->
|
destroy(ClientId) when is_binary(ClientId) ->
|
||||||
ets:delete(emqtt_client, ClientId);
|
ets:delete(emqtt_client, ClientId);
|
||||||
|
|
||||||
|
@ -95,3 +105,4 @@ terminate(_Reason, _State) ->
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,10 @@
|
||||||
|
|
||||||
-include("emqtt_frame.hrl").
|
-include("emqtt_frame.hrl").
|
||||||
|
|
||||||
-include("emqtt_internal.hrl").
|
|
||||||
|
|
||||||
-export([parse/2, initial_state/0]).
|
-export([parse/2, initial_state/0]).
|
||||||
-export([serialise/1]).
|
-export([serialise/1]).
|
||||||
|
|
||||||
-define(RESERVED, 0).
|
-define(RESERVED, 0).
|
||||||
-define(PROTOCOL_MAGIC, "MQIsdp").
|
|
||||||
-define(MAX_LEN, 16#fffffff).
|
-define(MAX_LEN, 16#fffffff).
|
||||||
-define(HIGHBIT, 2#10000000).
|
-define(HIGHBIT, 2#10000000).
|
||||||
-define(LOWBITS, 2#01111111).
|
-define(LOWBITS, 2#01111111).
|
||||||
|
@ -68,7 +65,7 @@ parse_frame(Bin, #mqtt_frame_fixed{ type = Type,
|
||||||
qos = Qos } = Fixed, Length) ->
|
qos = Qos } = Fixed, Length) ->
|
||||||
case {Type, Bin} of
|
case {Type, Bin} of
|
||||||
{?CONNECT, <<FrameBin:Length/binary, Rest/binary>>} ->
|
{?CONNECT, <<FrameBin:Length/binary, Rest/binary>>} ->
|
||||||
{ProtocolMagic, Rest1} = parse_utf(FrameBin),
|
{ProtoName, Rest1} = parse_utf(FrameBin),
|
||||||
<<ProtoVersion : 8, Rest2/binary>> = Rest1,
|
<<ProtoVersion : 8, Rest2/binary>> = Rest1,
|
||||||
<<UsernameFlag : 1,
|
<<UsernameFlag : 1,
|
||||||
PasswordFlag : 1,
|
PasswordFlag : 1,
|
||||||
|
@ -84,7 +81,7 @@ parse_frame(Bin, #mqtt_frame_fixed{ type = Type,
|
||||||
{WillMsg, Rest6} = parse_msg(Rest5, WillFlag),
|
{WillMsg, Rest6} = parse_msg(Rest5, WillFlag),
|
||||||
{UserName, Rest7} = parse_utf(Rest6, UsernameFlag),
|
{UserName, Rest7} = parse_utf(Rest6, UsernameFlag),
|
||||||
{PasssWord, <<>>} = parse_utf(Rest7, PasswordFlag),
|
{PasssWord, <<>>} = parse_utf(Rest7, PasswordFlag),
|
||||||
case ProtocolMagic == ?PROTOCOL_MAGIC of
|
case protocol_name_approved(ProtoVersion, ProtoName) of
|
||||||
true ->
|
true ->
|
||||||
wrap(Fixed,
|
wrap(Fixed,
|
||||||
#mqtt_frame_connect{
|
#mqtt_frame_connect{
|
||||||
|
@ -265,4 +262,5 @@ opt(false) -> 0;
|
||||||
opt(true) -> 1;
|
opt(true) -> 1;
|
||||||
opt(X) when is_integer(X) -> X.
|
opt(X) when is_integer(X) -> X.
|
||||||
|
|
||||||
|
protocol_name_approved(Ver, Name) ->
|
||||||
|
lists:member({Ver, Name}, ?PROTOCOL_NAMES).
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
|
|
||||||
-import(proplists, [get_value/2, get_value/3]).
|
-import(proplists, [get_value/2, get_value/3]).
|
||||||
|
|
||||||
-export([handle/2]).
|
-export([handle/1]).
|
||||||
|
|
||||||
handle(Req, Auth) ->
|
handle(Req) ->
|
||||||
case authorized(Req, Auth) of
|
case authorized(Req) of
|
||||||
true ->
|
true ->
|
||||||
Path = Req:get(path),
|
Path = Req:get(path),
|
||||||
Method = Req:get(method),
|
Method = Req:get(method),
|
||||||
|
@ -44,11 +44,9 @@ handle('POST', "/mqtt/publish", Req) ->
|
||||||
error_logger:info_msg("~p~n", [Params]),
|
error_logger:info_msg("~p~n", [Params]),
|
||||||
Topic = get_value("topic", Params),
|
Topic = get_value("topic", Params),
|
||||||
Message = list_to_binary(get_value("message", Params)),
|
Message = list_to_binary(get_value("message", Params)),
|
||||||
Qos = list_to_integer(get_value("qos", Params, "0")),
|
|
||||||
%TODO: DUP, RETAIN...
|
|
||||||
emqtt_pubsub:publish(#mqtt_msg {
|
emqtt_pubsub:publish(#mqtt_msg {
|
||||||
retain = 0,
|
retain = 0,
|
||||||
qos = Qos,
|
qos = ?QOS_0,
|
||||||
topic = Topic,
|
topic = Topic,
|
||||||
dup = 0,
|
dup = 0,
|
||||||
payload = Message
|
payload = Message
|
||||||
|
@ -61,14 +59,13 @@ handle(_Method, _Path, Req) ->
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% basic authorization
|
%% basic authorization
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
authorized(Req, {Username, Password}) ->
|
authorized(Req) ->
|
||||||
case mochiweb_request:get_header_value("Authorization", Req) of
|
case mochiweb_request:get_header_value("Authorization", Req) of
|
||||||
undefined -> false;
|
undefined ->
|
||||||
|
false;
|
||||||
"Basic " ++ BasicAuth ->
|
"Basic " ++ BasicAuth ->
|
||||||
case user_passwd(BasicAuth) of
|
{Username, Password} = user_passwd(BasicAuth),
|
||||||
{Username, Password} -> true;
|
emqtt_auth:check(Username, Password)
|
||||||
_ -> false
|
|
||||||
end
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
user_passwd(BasicAuth) ->
|
user_passwd(BasicAuth) ->
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
-include("emqtt_log.hrl").
|
-include("emqtt_log.hrl").
|
||||||
|
|
||||||
-include("emqtt_internal.hrl").
|
-include("emqtt_topic.hrl").
|
||||||
|
|
||||||
-include_lib("stdlib/include/qlc.hrl").
|
-include_lib("stdlib/include/qlc.hrl").
|
||||||
|
|
||||||
|
@ -174,7 +174,6 @@ handle_info({'DOWN', Mon, _Type, _Object, _Info}, State) ->
|
||||||
undefined ->
|
undefined ->
|
||||||
?ERROR("unexpected 'DOWN': ~p", [Mon]);
|
?ERROR("unexpected 'DOWN': ~p", [Mon]);
|
||||||
SubPid ->
|
SubPid ->
|
||||||
%?INFO("subscriber DOWN: ~p", [SubPid]),
|
|
||||||
erase({submon, Mon}),
|
erase({submon, Mon}),
|
||||||
erase({subscriber, SubPid}),
|
erase({subscriber, SubPid}),
|
||||||
Subs = ets:match_object(topic_subscriber, #topic_subscriber{subpid=SubPid, _='_'}),
|
Subs = ets:match_object(topic_subscriber, #topic_subscriber{subpid=SubPid, _='_'}),
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
|
|
||||||
%%TODO: SHOULD BE REPLACED BY emqtt_cm.erl......
|
|
||||||
|
|
||||||
-module(emqtt_registry).
|
|
||||||
|
|
||||||
-include("emqtt.hrl").
|
|
||||||
|
|
||||||
-include("emqtt_log.hrl").
|
|
||||||
|
|
||||||
-export([start_link/0,
|
|
||||||
size/0,
|
|
||||||
register/2,
|
|
||||||
unregister/1]).
|
|
||||||
|
|
||||||
-behaviour(gen_server).
|
|
||||||
|
|
||||||
-export([init/1,
|
|
||||||
handle_call/3,
|
|
||||||
handle_cast/2,
|
|
||||||
handle_info/2,
|
|
||||||
terminate/2,
|
|
||||||
code_change/3]).
|
|
||||||
|
|
||||||
-record(state, {}).
|
|
||||||
|
|
||||||
-define(SERVER, ?MODULE).
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
start_link() ->
|
|
||||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
|
||||||
|
|
||||||
size() ->
|
|
||||||
ets:info(client, size).
|
|
||||||
|
|
||||||
register(ClientId, Pid) ->
|
|
||||||
gen_server:cast(?SERVER, {register, ClientId, Pid}).
|
|
||||||
|
|
||||||
unregister(ClientId) ->
|
|
||||||
gen_server:cast(?SERVER, {unregister, ClientId}).
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
init([]) ->
|
|
||||||
ets:new(client, [set, protected, named_table]),
|
|
||||||
?INFO("~p is started.", [?MODULE]),
|
|
||||||
{ok, #state{}}. % clientid -> {pid, monitor}
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------------
|
|
||||||
handle_call(Req, _From, State) ->
|
|
||||||
{stop, {badreq, Req}, State}.
|
|
||||||
|
|
||||||
handle_cast({register, ClientId, Pid}, State) ->
|
|
||||||
case ets:lookup(client, ClientId) of
|
|
||||||
[{_, {OldPid, MRef}}] ->
|
|
||||||
catch gen_server:call(OldPid, duplicate_id),
|
|
||||||
erlang:demonitor(MRef);
|
|
||||||
[] ->
|
|
||||||
ignore
|
|
||||||
end,
|
|
||||||
ets:insert(client, {ClientId, {Pid, erlang:monitor(process, Pid)}}),
|
|
||||||
{noreply, State};
|
|
||||||
|
|
||||||
handle_cast({unregister, ClientId}, State) ->
|
|
||||||
case ets:lookup(client, ClientId) of
|
|
||||||
[{_, {_Pid, MRef}}] ->
|
|
||||||
erlang:demonitor(MRef),
|
|
||||||
ets:delete(client, ClientId);
|
|
||||||
[] ->
|
|
||||||
ignore
|
|
||||||
end,
|
|
||||||
{noreply, State};
|
|
||||||
|
|
||||||
handle_cast(Msg, State) ->
|
|
||||||
{stop, {badmsg, Msg}, State}.
|
|
||||||
|
|
||||||
handle_info({'DOWN', MRef, process, DownPid, _Reason}, State) ->
|
|
||||||
ets:match_delete(client, {'_', {DownPid, MRef}}),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
terminate(_Reason, _State) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
|
||||||
{ok, State}.
|
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
%% There can be any number of root nodes; that is, there can be any number of topic trees.
|
%% There can be any number of root nodes; that is, there can be any number of topic trees.
|
||||||
%% ------------------------------------------------------------------------
|
%% ------------------------------------------------------------------------
|
||||||
|
|
||||||
-include("emqtt_internal.hrl").
|
-include("emqtt_topic.hrl").
|
||||||
|
|
||||||
-export([new/1,
|
-export([new/1,
|
||||||
type/1,
|
type/1,
|
||||||
|
|
|
@ -36,12 +36,11 @@
|
||||||
{listen, [
|
{listen, [
|
||||||
{mqtt, 1883, [
|
{mqtt, 1883, [
|
||||||
{max_conns, 1024},
|
{max_conns, 1024},
|
||||||
{acceptor_pool, 2}
|
{acceptor_pool, 4}
|
||||||
]},
|
]},
|
||||||
{http, 8883, [
|
{http, 8883, [
|
||||||
{max_conns, 512},
|
{max_conns, 512},
|
||||||
{acceptor_pool, 1},
|
{acceptor_pool, 1}
|
||||||
{auth, {"user", "passwd"}}
|
|
||||||
]}
|
]}
|
||||||
]}
|
]}
|
||||||
]}
|
]}
|
||||||
|
|
Loading…
Reference in New Issue