smppex v0.3.1 SMPPEX.MC behaviour

Module for implementing custom SMPP MC entities.

In general, an SMPP MC entity represents a TCP server, which accepts connections and handles them. The TCP server is represented by a Ranch listener started by start/2 call. On new connection the listener spawns SMPPEX.Session process coupled with SMPPEX.MC GenServer handler. The session interacts with the socket while the MC handler keeps state and does actual PDU handling. One also interacts with MC handler to send PDUs, PDU replies, etc.

The session makes all requests to the MC handler process syncronously (via GenServer.call), while the MC handler process makes only asyncronous(via GenServer.cast) requests to the session.

This is made intentionally since this allows:

  • to avoid any kind of deadlocks while the session and the MC handler process interact actively;
  • to control incoming SMPP message rate to avoid overflooding;
  • not to lose any control over connection because of the asyncronous nature of TCP implementation in OTP.

To implement an MC entitiy, one should implement several callbacks for MC handler processes (SMPPEX.MC behaviour). The most proper way to do it is to use SMPPEX.MC:

defmodule MyMC do
  use SMPPEX.MC

  # ...Callback implementation

end

In this case all callbacks have reasonable defaults.

Note that SMPPEX.MC does not have a start_link method since SMPPEX.MC instances (handler processes) are launched when a Ranch listener created by start/2 receives a new incoming connection.

Summary

Functions

Makes a syncronous call to MC handler

Makes an asyncronous call to MC handler

Sends reply to previously received PDU from the MC handler

Sends outcoming PDU from the MC handler

Starts listener for MC entitiy

Stops MC listener and all its sessions

Stops MC handler asyncronously

Callbacks

Invoked for handling call/3 calls

Invoked for handling cast/2 calls

Invoked for handling generic messages sent to the MC handler process

Invoked when MC session was stopped abnormally and wasn’t able to handle sent PDUs without resps in handle_stop

Invoked when the MC handler receives an incoming PDU (which is not a response PDU)

Invoked when the MC handler receives a response to a previously sent PDU

Invoked when the MC handler does not receive a response to a previously sent PDU for the specified timeout

Invoked when the SMPP session successfully sent PDU to transport or failed to do this

Invoked when the SMPP session is about to stop

Invoked when the listener has accepted a connection and tries to created an SMPPEX.MC. The Ranch acceptor handling the connection is busy till the function returns

Types

request :: term
send_pdu_result :: :ok | {:error, term}
socket :: port | :ssl.sslsocket
state :: term
transport :: module

Functions

call(mc, request, timeout \\ 5000)

Specs

call(pid, term, timeout) :: term

Makes a syncronous call to MC handler.

The call is handled by handle_call/3 MC callback.

cast(mc, request)

Specs

cast(pid, term) :: :ok

Makes an asyncronous call to MC handler.

The call is handled by handle_cast/2 MC callback.

reply(mc, pdu, reply_pdu)

Specs

reply(mc :: pid, pdu :: SMPPEX.Pdu.t, reply_pdu :: SMPPEX.Pdu.t) :: :ok

Sends reply to previously received PDU from the MC handler.

The whole command is sent to the MC handler asyncronously. The further lifecycle of the response PDU can be traced through callbacks.

send_pdu(mc, pdu)

Specs

send_pdu(mc :: pid, pdu :: SMPPEX.Pdu.t) :: :ok

Sends outcoming PDU from the MC handler.

The whole command is sent to the MC handler asyncronously. The further lifecycle of the PDU can be traced through callbacks.

start(mod_with_args, opts \\ [])

Specs

start({module, args :: term}, opts :: Keyword.t) ::
  {:ok, listener_ref :: :ranch.ref} |
  {:error, reason :: term}

Starts listener for MC entitiy.

module is the callback module which should implement SMPPEX.MC behaviour. args is the argument passed to the init callback. opts is a keyword list of different options:

  • :transport is Ranch transport used for TCP connections: either ranch_tcp (the default) or ranch_ssl;
  • :transport_opts is a list of Ranch transport options. The major option is {:port, port}. The port is set to 0 by default, which means that the listener will accept connections on a random free port.
  • :acceptor_count is the number of Ranch listener acceptors, 50 by default.
  • :gen_server_opts is a list of options passed directly to the underlying GenServer.start_link call, the default is [];
  • :mc_opts is a keyword list of MC options:

    • :timer_resolution is interval of internal ticks on which time related events happen, like checking timeouts for pdus, checking SMPP timers, etc. The default is 100 ms;
    • :session_init_limit is the maximum time for which the MC handler waits an incoming bind request. If no bind request is received within this interval of time, MC handler stops. The default value is 10000 ms;
    • :enquire_link_limit is value for enquire_link SMPP timer, i.e. the interval of SMPP session inactivity after which enquire_link PDU is send to “ping” the connetion. The default value is 30000 ms;
    • :enquire_link_resp_limit is the maximum time for which MC handler waits for enquire_link PDU response. If the response is not received within this interval of time and no activity from the peer occurs, the session is then considered dead and the MC handler stops. The default value is 30000 ms;
    • :inactivity_limit is the maximum time for which the peer is allowed not to send PDUs (which are not response PDUs). If no such PDUs are received within this interval of time, MC handler stops. The default is infinity ms;
    • :response_limit is the maximum time to wait for a response for a previously sent PDU. If the response is not received within this interval, handle_resp_timeout callback is triggered for the original pdu. If the response is received later, it is discarded. The default value is 60000 ms. If :mc_opts list of options is ommited, all options take their default values.

The returned value is either {:ok, ref} or {:error, reason}. The ref can be later used to stop the whole MC listener and all sessions received by it.

stop(mc_server)

Specs

stop(:ranch.ref) :: :ok

Stops MC listener and all its sessions.

The very moment of the SMPP session termination can be traced via handle_stop callback.

stop_session(mc)

Specs

stop_session(pid) :: :ok

Stops MC handler asyncronously.

The very moment of the SMPP session termination can be traced via handle_stop callback.

Callbacks

handle_call(request, from, state)

Specs

handle_call(request, from :: GenServer.from, state) ::
  {:reply, reply :: term, state} |
  {:noreply, state}

Invoked for handling call/3 calls.

The callback is called syncronously for handling.

The returned values have the same meaning as in GenServer handle_call callback (but note that only two kinds of responses are possible). In case of delaying a reply ({:noreply, state} callback result) it can be later send using GenServer.reply(from, reply)

handle_cast(request, state)

Specs

handle_cast(request, state) :: state

Invoked for handling cast/2 calls.

The callback is called asyncronously.

The returned value is used as the new state.

handle_info(request, state)

Specs

handle_info(request, state) :: state

Invoked for handling generic messages sent to the MC handler process.

The returned value is used as the new state.

handle_lost_pdus(mc_conn, reason, pdus)

Specs

handle_lost_pdus(mc_conn :: pid, reason :: term, pdus :: [SMPPEX.Pdu.t]) :: any

Invoked when MC session was stopped abnormally and wasn’t able to handle sent PDUs without resps in handle_stop.

Since the MC session is already stopped, the callback does not receive state, but the former pid of MC session, the reason of its termination and unconfirmed PDUs.

The returned value is ignored.

handle_pdu(pdu, state)

Specs

handle_pdu(pdu :: SMPPEX.Pdu.t, state) :: state

Invoked when the MC handler receives an incoming PDU (which is not a response PDU).

The returned value is used as the new state.

handle_resp(pdu, original_pdu, state)

Specs

handle_resp(pdu :: SMPPEX.Pdu.t, original_pdu :: SMPPEX.Pdu.t, state) :: state

Invoked when the MC handler receives a response to a previously sent PDU.

pdu argument contains the received response PDU, original_pdu contains the previously sent pdu for which the handled response is received.

The returned value is used as the new state.

handle_resp_timeout(pdu, state)

Specs

handle_resp_timeout(pdu :: SMPPEX.Pdu.t, state) :: state

Invoked when the MC handler does not receive a response to a previously sent PDU for the specified timeout.

pdu argument contains the PDU for which no response was received. If the response will be received later it will be dropped (with an info log message).

The returned value is used as the new state.

handle_send_pdu_result(pdu, send_pdu_result, state)

Specs

handle_send_pdu_result(pdu :: SMPPEX.Pdu.t, send_pdu_result :: SMPPEX.SMPPHandler.send_pdu_result, state) :: state

Invoked when the SMPP session successfully sent PDU to transport or failed to do this.

pdu argument contains the PDU for which send status is reported. send_pdu_result can be either :ok or {:error, reason}.

The returned value is used as the new state.

handle_stop(reason, lost_pdus, state)

Specs

handle_stop(reason :: term, lost_pdus :: [SMPPEX.Pdu.t], state) :: {exit_reason :: term, state}

Invoked when the SMPP session is about to stop.

lost_pdus contains sent PDUs which have not received resps (and will never receive since the session terminates).

reason contains one of the following:

  • :custom — session manually stopped by call to MC.stop_session;
  • {:parse_error, error} — error in parsing incoming SMPP packet occured;
  • :socket_closed — peer closed socket;
  • {:socket_error, error} — socket error occured;
  • {:timers, reason} — session closed by timers.

The return value is {stop_reason, new_state}. The session GenServer will stop with stop_reason.

init(socket, transport, args)

Specs

init(socket, transport, args :: term) ::
  {:ok, state} |
  {:stop, reason :: term}

Invoked when the listener has accepted a connection and tries to created an SMPPEX.MC. The Ranch acceptor handling the connection is busy till the function returns.

args argument is taken directly from start/2 call. socket and transport arguments are Ranch socket and transport respectively. They can be used, for example, to inspect peer address, etc. The return value should be either {:ok, state}, then MC handler will successfully start and returned state will be later passed to the other callbacks, or {:stop, reason}, then MC handler GenServer will stop and the connection closed.