From f7aa7cb48e5d8c108d07f17210e841867593361d Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Sun, 3 May 2015 10:40:43 +0800 Subject: [PATCH 1/5] emqttd graph --- doc/emqtt.png | Bin 8953 -> 0 bytes doc/emqttd.graphml | 993 +++++++++++++++++++++++++++++++++++++++++++++ doc/emqttd.png | Bin 0 -> 40662 bytes 3 files changed, 993 insertions(+) delete mode 100644 doc/emqtt.png create mode 100644 doc/emqttd.graphml create mode 100644 doc/emqttd.png diff --git a/doc/emqtt.png b/doc/emqtt.png deleted file mode 100644 index df6462e86033a8252334e946071efb14effcac64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8953 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 + + + + + + + + + + + + + + + + + + + + + + + + + emqttd broker cluster + + + + + + + + + + Folder 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + y + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + y + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + y + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + y + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + Client + + + + + + + + + + + + + + + + + Sensor + + + + + + + + + + + + + + + + + Sensor + + + + + + + + + + + + + + + + + Client + + + + + + + + + + + + + + + + + + Application Server + + + + + + + + + + + + + + + + + + Web + + + + + + + + + + + + + + + + + + Web + + + + + + + + + + + + + + + + + + iPhone + + + + + + + + + + + + + + + + + + Android + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MQTT + + + + + + + + + + + + + + + + + + + HTTP + + + + + + + + + + + + + + + + + + + MQTT + + + + + + + + + + + + + + + + + + + WebSocket + + + + + + + + + + + + + + + + + + + WebSocket + + + + + + + + + + + + + + + + + + + MQTT + + + + + + + + + + + + + + + + + + + MQTT + + + + + + + + + + + + + + + + + + + MQTT + + + + + + + + + + + + + + + + diff --git a/doc/emqttd.png b/doc/emqttd.png new file mode 100644 index 0000000000000000000000000000000000000000..6066d5d08837f676dfd62863bc050d6d684d435b GIT binary patch literal 40662 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 Date: Sun, 3 May 2015 10:58:50 +0800 Subject: [PATCH 2/5] goals --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7d3bcf55f..4a508c41a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ emqttd requires Erlang R17+ to build. emqttd is aimed to provide a solid, enterprise grade, extensible open-source MQTT broker for IoT(M2M) applications that need to support ten millions of concurrent MQTT clients. +* Easy to install +* Massively scalable +* Easy to extend +* Solid stable + ## Design ![emqttd architecture](http://emqtt.io/static/img/Architecture.png) From f6c69208a53429a954f1af7d93ea037a454978ff Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Mon, 4 May 2015 12:52:10 +0800 Subject: [PATCH 3/5] auth mysql --- plugins/emqttd_auth_mysql/.placehodler | 0 plugins/emqttd_auth_mysql/README.md | 21 ++++++++ plugins/emqttd_auth_mysql/rebar.config | 19 +++++++ .../src/emqttd_auth_mysql.app.src | 12 +++++ .../src/emqttd_auth_mysql.erl | 54 +++++++++++++++++++ .../src/emqttd_auth_mysql_app.erl | 19 +++++++ .../src/emqttd_auth_mysql_sup.erl | 27 ++++++++++ 7 files changed, 152 insertions(+) create mode 100644 plugins/emqttd_auth_mysql/.placehodler create mode 100644 plugins/emqttd_auth_mysql/README.md create mode 100644 plugins/emqttd_auth_mysql/rebar.config create mode 100644 plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.app.src create mode 100644 plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.erl create mode 100644 plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_app.erl create mode 100644 plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_sup.erl diff --git a/plugins/emqttd_auth_mysql/.placehodler b/plugins/emqttd_auth_mysql/.placehodler new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/emqttd_auth_mysql/README.md b/plugins/emqttd_auth_mysql/README.md new file mode 100644 index 000000000..d6f783945 --- /dev/null +++ b/plugins/emqttd_auth_mysql/README.md @@ -0,0 +1,21 @@ +## Overview + +Authentication with user table of MySQL database. + +## Demo User Table + +``` +CREATE TABLE `mqtt_users` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(60) DEFAULT NULL, + `password` varchar(60) DEFAULT NULL, + `salt` varchar(20) DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `mqtt_users_username` (`username`) +) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +``` + +## Plugin config + + diff --git a/plugins/emqttd_auth_mysql/rebar.config b/plugins/emqttd_auth_mysql/rebar.config new file mode 100644 index 000000000..2e9d5c953 --- /dev/null +++ b/plugins/emqttd_auth_mysql/rebar.config @@ -0,0 +1,19 @@ +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 ft=erlang et + +{require_min_otp_vsn, "R17"}. + +%% fail_on_warning, +{erl_opts, [debug_info, {parse_transform, lager_transform}]}. + +{erl_opts, [warn_export_all, + warn_unused_import, + {i, "include"}, + {src_dirs, ["src"]}]}. + +{xref_checks, [undefined_function_calls]}. + +{deps, [ + {'Emysql', "*", {git, "git://github.com/Eonblast/Emysql.git", {branch, "master"}}} +]}. + diff --git a/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.app.src b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.app.src new file mode 100644 index 000000000..9094f9e77 --- /dev/null +++ b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.app.src @@ -0,0 +1,12 @@ +{application, emqttd_auth_mysql, + [ + {description, ""}, + {vsn, "0.1"}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {emqttd_auth_mysql_app, []}}, + {env, []} + ]}. diff --git a/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.erl b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.erl new file mode 100644 index 000000000..a6d5ce5a8 --- /dev/null +++ b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql.erl @@ -0,0 +1,54 @@ +%%%----------------------------------------------------------------------------- +%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved. +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in all +%%% copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +%%% SOFTWARE. +%%%----------------------------------------------------------------------------- +%%% @doc +%%% emqttd authentication by mysql user table. +%%% +%%% @end +%%%----------------------------------------------------------------------------- +-module(emqttd_auth_mysql). + +-author("Feng Lee "). + +-include_lib("emqttd/include/emqttd.hrl"). + +-behaviour(emqttd_auth_mod). + +-export([init/1, check/3, description/0]). + +-record(state, {user_tab}). + +init(Opts) -> + UserTab = proplists:get_value(user_table, Opts, mqtt_users), + {ok, #state{user_tab = UserTab}}. + +check(#mqtt_client{username = undefined}, _Password, _State) -> + {error, "Username undefined"}; +check(_Client, undefined, _State) -> + {error, "Password undefined"}; +check(#mqtt_client{username = Username}, Password, #state{user_tab = UserTab}) -> + case emysql:select(UserTab, {{username, Username}, {password, erlang:md5(Password)}}) of + {ok, []} -> {error, "Username or Password not match"}; + {ok, _Record} -> ok + end. + +description() -> "Authentication by MySQL". + diff --git a/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_app.erl b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_app.erl new file mode 100644 index 000000000..e1f16bf98 --- /dev/null +++ b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_app.erl @@ -0,0 +1,19 @@ +-module(emqttd_auth_mysql_app). + +-behaviour(application). + +%% Application callbacks +-export([start/2, stop/1]). + +%% =================================================================== +%% Application callbacks +%% =================================================================== + +start(_StartType, _StartArgs) -> + {ok, Sup} = emqttd_auth_mysql_sup:start_link(), + emqttd_access_control:register_mod(auth, emqttd_auth_mysql, []), + {ok, Sup}. + +stop(_State) -> + emqttd_access_control:unregister_mod(auth, emqttd_auth_mysql), + ok. diff --git a/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_sup.erl b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_sup.erl new file mode 100644 index 000000000..f2fc9e0b1 --- /dev/null +++ b/plugins/emqttd_auth_mysql/src/emqttd_auth_mysql_sup.erl @@ -0,0 +1,27 @@ +-module(emqttd_auth_mysql_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +%% Helper macro for declaring children of supervisor +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). + +%% =================================================================== +%% API functions +%% =================================================================== + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% =================================================================== +%% Supervisor callbacks +%% =================================================================== + +init([]) -> + {ok, { {one_for_one, 5, 10}, []} }. + From 5e8ac6b3ea721d59dafba04b69950ca0d6cc9b89 Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Mon, 4 May 2015 21:49:58 +0800 Subject: [PATCH 4/5] conver_enabled --- rebar.config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rebar.config b/rebar.config index 57e35432f..7755b06d7 100644 --- a/rebar.config +++ b/rebar.config @@ -2,7 +2,6 @@ %% ex: ts=4 sw=4 ft=erlang et {require_min_otp_vsn, "R17"}. -{cover_enabled, true}. %% fail_on_warning, {erl_opts, [debug_info, {parse_transform, lager_transform}]}. @@ -15,7 +14,7 @@ {eunit_opts, [verbose]}. {xref_checks, [undefined_function_calls]}. -{cover_enabled, false}. +{cover_enabled, true}. {validate_app_modules, true}. From 613d38e288c0e848dc6616fc59a5a2ed69dac165 Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Mon, 4 May 2015 23:25:17 +0800 Subject: [PATCH 5/5] dialyzer --- Makefile | 15 +++++++++++++++ apps/emqttd/src/emqttd_bridge_sup.erl | 2 +- apps/emqttd/src/emqttd_event.erl | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3babaec69..a3b509386 100644 --- a/Makefile +++ b/Makefile @@ -38,3 +38,18 @@ plugins: dist: rel plugins +PLT = $(BASE_DIR)/.emqttd_dialyzer.plt +APPS = erts kernel stdlib sasl crypto ssl os_mon syntax_tools \ + public_key mnesia inets compiler + +check_plt: compile + dialyzer --check_plt --plt $(PLT) --apps $(APPS) \ + deps/*/ebin apps/*/ebin + +build_plt: compile + dialyzer --build_plt --output_plt $(PLT) --apps $(APPS) \ + deps/*/ebin apps/*/ebin + +dialyzer: compile + dialyzer -Wno_return --plt $(PLT) deps/*/ebin apps/*/ebin + diff --git a/apps/emqttd/src/emqttd_bridge_sup.erl b/apps/emqttd/src/emqttd_bridge_sup.erl index 5adda423a..93787937d 100644 --- a/apps/emqttd/src/emqttd_bridge_sup.erl +++ b/apps/emqttd/src/emqttd_bridge_sup.erl @@ -74,7 +74,7 @@ start_bridge(Node, SubTopic, Options) when is_atom(Node) and is_binary(SubTopic) -spec stop_bridge(atom(), binary()) -> {ok, pid()} | ok. stop_bridge(Node, SubTopic) -> ChildId = bridge_id(Node, SubTopic), - case supervisor:terminate_child(ChildId) of + case supervisor:terminate_child(?MODULE, ChildId) of ok -> supervisor:delete_child(?MODULE, ChildId); {error, Reason} -> diff --git a/apps/emqttd/src/emqttd_event.erl b/apps/emqttd/src/emqttd_event.erl index 4fa57ac56..3db7817aa 100644 --- a/apps/emqttd/src/emqttd_event.erl +++ b/apps/emqttd/src/emqttd_event.erl @@ -114,5 +114,5 @@ payload(connected, Params) -> iolist_to_binary(io_lib:format("from: ~s~nprotocol: ~p~nsession: ~s", [From, Proto, Sess])); payload(disconnected, Reason) -> - list_to_binary(io_lib:format(["reason: ~p", Reason])). + list_to_binary(io_lib:format("reason: ~p", [Reason])).