# `snmpm_user`
[🔗](https://github.com/erlang/otp/blob/master/lib/snmp/src/manager/snmpm_user.erl#L23)

Behaviour module for the SNMP manager user.

This module defines the behaviour of the manager user. A `snmpm_user` compliant
module must export the following functions:

- `c:handle_error/3`
- `c:handle_agent/5`
- `c:handle_pdu/4`
- `c:handle_trap/3`
- `c:handle_inform/3`
- `c:handle_report/3`
- `c:handle_invalid_result/2`

The semantics of them and their exact signatures are explained below.

Some of the function has no defined return value (`void()`), they can of course
return anything. But the functions that do have specified return value(s) _must_
adhere to this. None of the functions can use exit of throw to return.

If the manager is not configured to use any particular transport domain, the
behaviour `handle_agent/5` will for backwards copmpatibility reasons be called
with the old `IpAddr` and `PortNumber` arguments

# `ip_address`
*not exported* 

```elixir
-type ip_address() :: inet:ip_address().
```

# `port_number`
*not exported* 

```elixir
-type port_number() :: inet:port_number().
```

# `snmp_gen_info`

```elixir
-type snmp_gen_info() ::
          {ErrorStatus :: atom(), ErrorIndex :: pos_integer(), Varbinds :: [snmp:varbind()]}.
```

General error information (does not _have_ to indicate an error)..

# `snmp_v1_trap_info`

```elixir
-type snmp_v1_trap_info() ::
          {Enteprise :: snmp:oid(),
           Generic :: integer(),
           Spec :: integer(),
           Timestamp :: integer(),
           Varbinds :: [snmp:varbind()]}.
```

Trap related information.

# `handle_agent`

```elixir
-callback handle_agent(Domain :: atom(),
                       Address :: term(),
                       Type :: pdu | trap | inform | report,
                       SnmpInfo :: snmp_gen_info() | snmp_v1_trap_info(),
                       UserData :: term()) ->
                          Reply ::
                              ignore |
                              {register,
                               UserId :: term(),
                               RTargetName :: snmpm:target_name(),
                               AgentConfig :: [snmpm:agent_config()]}.
```

This function is called when a message is received from an unknown agent.

Note that this will always be the default user that is called.

For more info about the `agent_config()`, see `snmpm:register_agent/3`.

The arguments `Type` and `SnmpInfo` relates in the following way:

- `pdu` \- `SnmpPduInfo` (see `c:handle_pdu/4` for more
  info).
- `trap` \- `SnmpTrapInfo` (see `c:handle_trap/3` for
  more info).
- `report` \- `SnmpReportInfo` (see `c:handle_report/3` for more info).
- `inform` \- `SnmpInformInfo` (see `c:handle_inform/3` for more info).

The only user which would return `{register, UserId, TargetName, AgentConfig}`
is the _default user_.

# `handle_error`

```elixir
-callback handle_error(ReqId :: netif | integer(),
                       Reason ::
                           {unexpected_pdu, SnmpInfo :: snmp_gen_info()} |
                           {invalid_sec_info, SecInfo :: term(), SnmpInfo :: snmp_gen_info()} |
                           {failed_processing_message,
                            {securityError, SecurityError :: atom(), Info :: proplists:proplist()}} |
                           {empty_message,
                            TransportDomain :: atom(),
                            {Addr :: ip_address(), Port :: port_number()}} |
                           term(),
                       UserData :: term()) ->
                          snmp:void().
```

This function is called when the manager needs to communicate an "asynchronous"
error to the user: e.g. failure to send an asynchronous message (i.e. encoding
error), a received message was discarded due to security error, the manager
failed to generate a response message to a received inform-request, or when
receiving an unexpected PDU from an agent (could be an expired async request).

If `ReqId` is less then 0, it means that this information was not available to
the manager (that info was never retrieved before the message was discarded).

For `SnmpInfo` see handle_agent below.

When `Reason` is `{failed_processing_message, {securityError, SecurityError, Opts}}`,
the `Opts` proplist may contain a `sec_data` entry with USM security parameters
from the received message. In particular, when `SecurityError` is
`usmStatsUnknownEngineIDs`, the `sec_data` proplist contains
`msgAuthoritativeEngineID` and `msgUserName`, which can be used for
SNMPv3 USM EngineID discovery (RFC 3414, Section 4).

Note that there is a special case when the value of `ReqId` has the value of the
atom `netif`. This means that the NetIF process has suffered a "fatal" error and
been restarted. With possible loss of traffic\!

# `handle_inform`

```elixir
-callback handle_inform(TargetName :: snmpm:target_name(),
                        SnmpInform :: snmp_gen_info(),
                        UserData :: term()) ->
                           Reply ::
                               ignore | no_reply | unregister |
                               {register,
                                UserId :: term(),
                                RTargetName :: snmpm:target_name(),
                                AgentConfig :: [snmpm:agent_config()]}.
```

Handle a inform message.

For more info about the `agent_config()`, see `snmpm:register_agent/3`.

The only user which would return `{register, UserId, TargetName2, AgentConfig}`
is the _default user_.

If the [inform request behaviour](snmp_config.md#manager_irb) configuration
option is set to `user` or `{user, integer()}`, the response (acknowledgment) to
this inform-request will be sent when this function returns.

# `handle_invalid_result`
*since OTP R16B03* *optional* 

```elixir
-callback handle_invalid_result(In, Out) -> no_return()
                                   when
                                       In :: {Fun :: atom(), Args :: list()},
                                       Out :: {crash, CrashInfo} | {result, InvalidResult :: term()},
                                       CrashInfo ::
                                           {ErrorType :: atom(),
                                            Error :: term(),
                                            Stacktrace :: erlang:stacktrace()}.
```

If _any_ of the _other_ callback functions crashes (exit, throw or a plain
crash) or return an invalid result (if a valid return has been specified), this
function is called. The purpose is to allow the user handle this error (for
instance to issue an error report).

`IN` reprecents the function called (and its arguments). `OUT` represents the
unexpected/invalid result.

# `handle_pdu`

```elixir
-callback handle_pdu(TargetName :: snmpm:target_name(),
                     ReqId :: term(),
                     SnmpResponse :: snmp_gen_info(),
                     UserData :: term()) ->
                        snmp:void().
```

Handle the reply to an asynchronous request, such as
[async_get](`snmpm:async_get2/4`), [async_get_next](`snmpm:async_get_next2/4`)
or [async_set](`snmpm:async_set2/4`).

It could also be a late reply to a synchronous request.

`ReqId` is returned by the asynchronous request function.

# `handle_report`

```elixir
-callback handle_report(TargetName :: snmpm:target_name(),
                        SnmpReport :: snmp_gen_info(),
                        UserData :: term()) ->
                           Reply ::
                               ignore | unregister |
                               {register,
                                UserId :: term(),
                                RTargetName :: snmpm:target_name(),
                                AgentConfig :: [snmpm:agent_config()]}.
```

Handle a report message.

For more info about the `agent_config()`, see `snmpm:register_agent/3`.

The only user which would return `{register, UserId, TargetName2, AgentConfig}`
is the _default user_.

# `handle_trap`

```elixir
-callback handle_trap(TargetName :: snmpm:target_name(),
                      SnmpTrapInfo :: snmp_gen_info() | snmp_v1_trap_info(),
                      UserData :: term()) ->
                         Reply ::
                             ignore | unregister |
                             {register,
                              UserId :: term(),
                              RTargetName :: snmpm:target_name(),
                              AgentConfig :: [snmpm:agent_config()]}.
```

Handle a trap/notification message from an agent.

For more info about the `agent_config()`, see `snmpm:register_agent/3`.

The only user which would return `{register, UserId, TargetName2, agent_info()}`
is the _default user_.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
