Current section
Files
Jump to
Current section
Files
src/sockerl.erl
%%% ------------------------------------------------------------------------------------------------
%%% Sockerl is available for use under the following license, commonly known as the 3-clause (or
%%% "modified") BSD license:
%%%
%%% Copyright (c) 2017-2018, Pouriya Jahanbakhsh
%%% (pouriya.jahanbakhsh@gmail.com)
%%% All rights reserved.
%%%
%%% Redistribution and use in source and binary forms, with or without modification, are permitted
%%% provided that the following conditions are met:
%%%
%%% 1. Redistributions of source code must retain the above copyright notice, this list of
%%% conditions and the following disclaimer.
%%%
%%% 2. Redistributions in binary form must reproduce the above copyright notice, this list of
%%% conditions and the following disclaimer in the documentation and/or other materials provided
%%% with the distribution.
%%%
%%% 3. Neither the name of the copyright holder nor the names of its contributors may be used to
%%% endorse or promote products derived from this software without specific prior written
%%% permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
%%% IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
%%% FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
%%% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
%%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
%%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
%%% THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
%%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE.
%%% ------------------------------------------------------------------------------------------------
%% @author Pouriya Jahanbakhsh <pouriya.jahanbakhsh@gmail.com>
%% @version 17.9.2
%% -------------------------------------------------------------------------------------------------
-module(sockerl).
-author("pouriya.jahanbakhsh@gmail.com").
%% -------------------------------------------------------------------------------------------------
%% Exports:
%% API:
-export([start_link_server/3
,start_link_server/4
,start_link_server/5
,stop_server/1
,stop_server/2
,get_acceptors/1
,sleep_acceptors/1
,wakeup_acceptors/1
,get_acceptor_modes/1
,change_acceptor_modes/1
,get_server_connections/1
,start_link_connector_pool/3
,start_link_connector_pool/4
,start_link_connector_pool/5
,stop_pool/1
,stop_pool/2
,get_pool_connections/1
,add_connector/3
,start_link_connector/4
,start_link_connector/5
,start_link_connector/6
,send_sync/2
,send_sync/3
,send_async/2
,stop_connector/1
,stop_connector/2]).
%% -------------------------------------------------------------------------------------------------
%% Behaviour info:
%% Mandatory for server implementation.
%%-callback
%%listen_init(InitArg, ListenSock) ->
%% 'ok' |
%% {'ok', InitArg2} |
%% {'stop', Reason} |
%% 'ignore'
%%when
%% InitArg :: any(),
%% ListenSock :: sockerl_types:socket(),
%% InitArg2 :: any(),
%% Reason :: any().
-callback
connector_init(InitArg, ConnectionSock) ->
'ok' | %% your State will be atom 'undefined'
{'ok', Opts} |
'close' |
{'close', Opts} |
{'stop', Reason} |
{'stop', Reason, Opts} |
'ignore'
when
InitArg :: any(),
ConnectionSock :: sockerl_types:socket(),
Opts :: [] | [Opt],
Opt :: {'state', any()}
| {'timeout', timeout()}
| {'srtimeout', timeout()}
| {'length', sockerl_types:length()}
| {'packet', sockerl_types:packet()}
| {'transporter', module()}
| {'socket', sockerl_types:socket()}
| {'setopts', list()},
Reason :: any().
-callback
handle_packet(Packet, State, Metadata) ->
'ok' |
{'ok', Opts} |
'close' |
{'close', Opts} |
{'stop', Reason} |
{'stop', Reason, Opts}
when
Packet :: sockerl_types:packet(),
State :: any(),
Metadata :: sockerl_types:metadata(),
Opts :: [] | [Opt],
Opt :: {'state', any()}
| {'timeout', timeout()}
| {'srtimeout', timeout()}
| {'length', sockerl_types:length()}
| {'packet', sockerl_types:packet()}
| {'transporter', module()}
| {'socket', sockerl_types:socket()}
| {'setopts', list()},
Reason :: any().
%% Mandatory when you want to send call to connections ('$gen_call')
%%-callback
%%handle_call(Request, From, State, Metadata) ->
%% 'ok' |
%% {'ok', Opts} |
%% 'close' |
%% {'close', Opts} |
%% {'stop', Reason} |
%% {'stop', Reason, Opts}
%%when
%% Request :: any(),
%% From :: {pid(), ref()},
%% State :: any(),
%% Metadata :: sockerl_types:metadata(),
%% Opts :: [] | [Opt],
%% Opt :: {'state', any()}
%% | {'reply', From, Response} % Just use in handle_call/4
%% | {'timeout', timeout()}
%% | {'srtimeout', timeout()}
%% | {'length', sockerl_types:length()}
%% | {'packet', sockerl_types:packet()}
%% | {'transporter', module()}
%% | {'socket', sockerl_types:socket()}
%% | {'setopts', list()},
%% Response :: any(),
%% Reason :: any().
%% Mandatory when you want to send cast to connections ('$gen_cast')
%%-callback
%%handle_cast(Cast, State, Metadata) ->
%% 'ok' |
%% {'ok', Opts} |
%% 'close' |
%% {'close', Opts} |
%% {'stop', Reason} |
%% {'stop', Reason, Opts}
%%when
%% State :: any(),
%% Metadata :: sockerl_types:metadata(),
%% Opts :: [] | [Opt],
%% Opt :: {'state', any()}
%% | {'timeout', timeout()}
%% | {'srtimeout', timeout()}
%% | {'length', sockerl_types:length()}
%% | {'packet', sockerl_types:packet()}
%% | {'transporter', module()}
%% | {'socket', sockerl_types:socket()}
%% | {'setopts', list()},
%% Reason :: any().
%% Mandatory when you want to send event to connections ('$gen_event')
%%-callback
%%handle_event(Event, State, Metadata) ->
%% 'ok' |
%% {'ok', Opts} |
%% 'close' |
%% {'close', Opts} |
%% {'stop', Reason} |
%% {'stop', Reason, Opts}
%%when
%% Packet :: binary() | string(),
%% State :: any(),
%% Metadata :: sockerl_types:metadata(),
%% Opts :: [] | [Opt],
%% Opt :: {'state', any()}
%% | {'timeout', timeout()}
%% | {'srtimeout', timeout()}
%% | {'length', sockerl_types:length()}
%% | {'packet', sockerl_types:packet()}
%% | {'transporter', module()}
%% | {'socket', sockerl_types:socket()}
%% | {'setopts', list()},
%% Reason :: any().
%% Useful when you want to use passive sockets (see README file) or
%% you want to use 'timeout' option.
%%-callback
%%timeout(State, Metadata) ->
%% 'ok' |
%% {'ok', Opts} |
%% 'close' |
%% {'close', Opts} |
%% {'stop', Reason} |
%% {'stop', Reason, Opts}
%%when
%% State :: any(),
%% Metadata :: sockerl_types:metadata(),
%% Opts :: [] | [Opt],
%% Opt :: {'state', any()}
%% | {'timeout', timeout()}
%% | {'srtimeout', timeout()}
%% | {'length', sockerl_types:length()}
%% | {'packet', sockerl_types:packet()}
%% | {'transporter', module()}
%% | {'socket', sockerl_types:socket()}
%% | {'setopts', list()},
%% Reason :: any().
%% Useful when you want to use passive sockets (see README file).
%%-callback
%%srtimeout(State, Metadata) ->
%% 'ok' |
%% {'ok', Opts} |
%% 'close' |
%% {'close', Opts} |
%% {'stop', Reason} |
%% {'stop', Reason, Opts}
%%when
%% State :: any(),
%% Metadata :: sockerl_types:metadata(),
%% Opts :: [] | [Opt],
%% Opt :: {'state', any()}
%% | {'timeout', timeout()}
%% | {'srtimeout', timeout()}
%% | {'length', sockerl_types:length()}
%% | {'packet', sockerl_types:packet()}
%% | {'transporter', module()}
%% | {'socket', sockerl_types:socket()}
%% | {'setopts', list()},
%% Reason :: any().
%% Useful when you want to use passive sockets (see README file).
-callback
handle_disconnect(State, Metadata) ->
'ok' |
{'ok', Opts} |
'close' |
{'close', Opts} |
{'stop', Reason} |
{'stop', Reason, Opts}
when
State :: any(),
Metadata :: sockerl_types:metadata(),
Opts :: [] | [Opt],
% Don't use {'packet', Pkt}, {'setopts, Opts} ... because socket has
% been closed and after this terminate/3 will be called.
Opt :: {'state', any()},
Reason :: any().
-callback
terminate(Reason, State, Metadata) ->
any()
when
Reason :: any(),
State :: any(),
Metadata :: sockerl_types:metadata().
-callback
code_change(OldVsn, State, Extra) ->
{'ok', NewState}
when
OldVsn :: any(),
State :: any(),
Extra :: any(),
NewState :: any().
%% -------------------------------------------------------------------------------------------------
%% API functions:
-spec
start_link_server(module(), term(), sockerl_types:port_number()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket server.
%% @end
start_link_server(Mod, InitArg, Port) ->
sockerl_server_sup:start_link(Mod, InitArg, Port).
-spec
start_link_server(sockerl_types:register_name() | module()
,module() | term()
,term() | sockerl_types:port_number()
,sockerl_types:port_number() |
sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket server.
%% @end
start_link_server(Name_or_Mod, Mod_or_InitArg, InitArg_or_Port, Port_or_Opts) ->
sockerl_server_sup:start_link(Name_or_Mod, Mod_or_InitArg, InitArg_or_Port, Port_or_Opts).
-spec
start_link_server(sockerl_types:register_name()
,module()
,term()
,sockerl_types:port_number()
,sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket server.
%% @end
start_link_server(Name, Mod, InitArg, Port, Opts) ->
sockerl_server_sup:start_link(Name, Mod, InitArg, Port, Opts).
-spec
get_server_connections(sockerl_types:name()) ->
[] | [{sockerl_types:socket(), pid()}].
%% @doc
%% Returns all available server connections.
%% @end
get_server_connections(Server) ->
sockerl_server_sup:fetch_connections(Server).
-spec
get_acceptors(sockerl_types:name()) ->
[] | [{pos_integer(), pid()}].
%% @doc
%% Returns all server acceptors.
%% @end
get_acceptors(Server) ->
sockerl_server_sup:fetch_acceptors(Server).
-spec
sleep_acceptors(sockerl_types:name()) ->
'ok'.
%% @doc
%% Turns all server acceptors to sleep mode.
%% @end
sleep_acceptors(Server) ->
sockerl_server_sup:sleep_acceptors(Server).
-spec
wakeup_acceptors(sockerl_types:name()) ->
'ok'.
%% @doc
%% Turns all server acceptors to accept mode.
%% @end
wakeup_acceptors(Server) ->
sockerl_server_sup:wakeup_acceptors(Server).
-spec
get_acceptor_modes(sockerl_types:name()) ->
sockerl_types:acceptor_mode() |
[{pos_integer(), sockerl_types:acceptor_mode()}].
%% @doc
%% Returns mode(s) of server acceptors.
%% @end
get_acceptor_modes(Server) ->
sockerl_server_sup:get_acceptor_modes(Server).
-spec
change_acceptor_modes(sockerl_types:name()) ->
sockerl_types:acceptor_mode() | 'not_allowed'.
change_acceptor_modes(Server) ->
sockerl_server_sup:change_acceptor_modes(Server).
-spec
stop_server(sockerl_types:name()) ->
'ok'.
%% @doc
%% stops server and all connections it has.
%% @end
stop_server(Server) ->
sockerl_server_sup:stop(Server).
-spec
stop_server(sockerl_types:name(), Reason::any()) ->
'ok'.
%% @doc
%% stops server and all connections it has.
%% @end
stop_server(Server, Reason) ->
sockerl_server_sup:stop(Server, Reason).
-spec
start_link_connector_pool(module(), term(), sockerl_types:addresses()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection pool.
%% @end
start_link_connector_pool(Mod, InitArg, Addrs) ->
sockerl_connector_sup:start_link(Mod, InitArg, Addrs).
-spec
start_link_connector_pool(sockerl_types:register_name()|
module()
,module() | term()
,term() | sockerl_types:addresses()
,sockerl_types:addresses() |
sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection pool.
%% @end
start_link_connector_pool(Name_or_Mod, Mod_or_InitArg, InitArg_or_Addrs, Addrs_or_Opts) ->
sockerl_connector_sup:start_link(Name_or_Mod, Mod_or_InitArg, InitArg_or_Addrs, Addrs_or_Opts).
-spec
start_link_connector_pool(sockerl_types:register_name()
,module()
,term()
,sockerl_types:addresses()
,sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection pool.
%% @end
start_link_connector_pool(Name, Mod, InitArg, Addrs, Opts) ->
sockerl_connector_sup:start_link(Name, Mod, InitArg, Addrs, Opts).
-spec
get_pool_connections(sockerl_types:name()) ->
[] | [{sockerl_types:socket(), pid()}].
%% @doc
%% Returns all available pool connections.
%% @end
get_pool_connections(Pool) ->
sockerl_connector_sup:fetch(Pool).
-spec
add_connector(sockerl_types:name(), sockerl_types:host(), sockerl_types:port_number()) ->
sockerl_types:start_return().
%% @doc
%% Adds new connector for Host:Port in pool.
%% @end
add_connector(Pool, Host, Port) ->
sockerl_connector_sup:add(Pool, Host, Port).
-spec
stop_pool(sockerl_types:name()) ->
'ok'.
%% @doc
%% stops pool and all connections it has.
%% @end
stop_pool(Pool) ->
sockerl_connector_sup:stop(Pool).
-spec
stop_pool(sockerl_types:name(), any()) ->
'ok'.
%% @doc
%% stops pool and all connections it has with specific reason.
%% @end
stop_pool(Pool, Reason) ->
sockerl_connector_sup:stop(Pool, Reason).
-spec
start_link_connector(module(), term(), sockerl_types:hostname(), sockerl_types:port_number()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection process.
%% @end
start_link_connector(Mod, InitArg, Host, Port) ->
sockerl_connector:start_link(Mod, InitArg, Host, Port).
-spec
start_link_connector(sockerl_types:register_name() | module()
,module() | term()
,term() | sockerl_types:hostname()
,sockerl_types:hostname() |
sockerl_types:port_number()
,sockerl_types:port_number() |
sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection process.
%% @end
start_link_connector(Name_or_Mod, Mod_or_InitArg, InitArg_or_Host, Host_or_Port, Port_or_Opts) ->
sockerl_connector:start_link(Name_or_Mod
,Mod_or_InitArg
,InitArg_or_Host
,Host_or_Port
,Port_or_Opts).
-spec
start_link_connector(sockerl_types:register_name()
,module()
,term()
,sockerl_types:hostname()
,sockerl_types:port_number()
,sockerl_types:start_options()) ->
sockerl_types:start_return().
%% @doc
%% Starts and links a socket connection process.
%% @end
start_link_connector(Name, Mod, InitArg, Host, Port, Opts) ->
sockerl_connector:start_link(Name, Mod, InitArg, Host, Port, Opts).
-spec
send_sync(sockerl_types:name(), sockerl_types:packet()) ->
'ok' | sockerl_types:error().
%% @doc
%% Sends packet synchronously through connector.
%% @end
send_sync(Con, Packet) ->
sockerl_connector:send_sync(Con, Packet).
-spec
send_sync(sockerl_types:name(), sockerl_types:packet(), timeout()) ->
'ok' | sockerl_types:error().
%% @doc
%% Sends packet synchronously through connector with timeout.
%% @end
send_sync(Con, Packet, Timeout) ->
sockerl_connector:send_sync(Con, Packet, Timeout).
-spec
send_async(sockerl_types:name(), sockerl_types:packet()) ->
'ok'.
%% @doc
%% Sends packet asynchronously through connector.
%% @end
send_async(Con, Packet) ->
sockerl_connector:send_async(Con, Packet).
-spec
stop_connector(sockerl_types:name()) ->
'ok'.
%% @doc
%% Stops connector.
%% @end
stop_connector(Con) ->
sockerl_connector:stop(Con).
-spec
stop_connector(sockerl_types:name(), any()) ->
'ok'.
%% @doc
%% Stops connector with specific reason.
%% @end
stop_connector(Con, Reason) ->
sockerl_connector:stop(Con, Reason).