gen_fw

Generic firewall process for Erlang/Elixir. It's an Erlang process between client processes and server process/port and prevents receiving some unwanted Erlang messages from server process/port.

When to use gen_fw?

When writing new server process, It's better to receive all messages and handle unwanted messages in that process instead of using gen_fw. But when you are using some generic behaviour or someone else's library and you don't want your client processes send everything (even wrongly) to server process/port, gen_fw is your firned. In below example i will show you how to prevent client process call supervisor:terminate/2 successfully for your supervisor.

How to use?

To starting main process you have to give its MFA to gen_fw and gen_fw will start itself and main process in order. Note that if you want to register main process, you have to give its register name to gen_fw and gen_fw will register itself.
API functions for starting linked gen_fw process:

gen_fw:start_link({Mod, Func, Args}=_MFA, Rules).
gen_fw:start_link({local, Name}, {Mod, Func, Args}=_MFA, Rules).

API functions for starting stand-alone gen_fw process:

gen_fw:start({Mod, Func, Args}=_MFA, Rules).
gen_fw:start({local, Name}, {Mod, Func, Args}=_MFA, Rules).

Rules

-type rules() :: [] | [rule()].
-type  rule() :: {'cast', action()}
               | {'call', action()}
               | {'message', action()}
               | {'system', action()}
               | {'all', action()}.
-type   action() :: 'allow' | 'deny' | 'dynamic'.

For example:

gen_fw:start_link({gen_server, start_link, [module, [], []]}
                 ,[{cast, deny}, {message, allow}, {system, allow}, {call, dynamic}]).

means start my process using gen_server:start_link(module, [], []) and:

If function module:fw_handle_message/2 is not exported or if it did not yield allow or deny or if it crashed, gen_fw denies message silently.

Note that instead of writing:

gen_fw:start_link({gen_server, start_link, [module, [], []]}, [{cast, deny}, {message, deny}, {system, deny}, {call, allow}]).

you can just write:

gen_fw:start_link({gen_server, start_link, [module, [], []]}, [{all, deny}, {call, allow}]).

Example

I wrote a supervisor called my_sup. Let's start supervisor directly first: