# `RawPing.Socket`
[🔗](https://github.com/awksedgreep/raw_ping/blob/v0.3.1/lib/raw_ping/socket.ex#L1)

Low-level socket operations for ICMP using Erlang's `:socket` API.

This module handles opening ICMP sockets, sending packets, and receiving
replies with proper timeout handling.

## Socket modes

Two kernel interfaces can carry ICMP echo:

  * `:dgram` — unprivileged ICMP datagram sockets (`SOCK_DGRAM`/`IPPROTO_ICMP`).
    Needs **no capability**. On Linux, availability is gated by
    `net.ipv4.ping_group_range`, which must include the running process's GID;
    many distributions ship this wide open. macOS permits it by default.

  * `:raw` — raw sockets (`SOCK_RAW`). Requires root or `CAP_NET_RAW`.

`:auto` (the default) tries `:dgram` first and falls back to `:raw`, so a
process gets the least-privileged interface that works on the host.

The mode matters to callers because the two deliver different bytes: raw
sockets include the IP header on receive, datagram sockets do not, and the
kernel rewrites the ICMP identifier on the datagram path. `open/1` returns the
negotiated mode so parsing and reply matching can adapt. See
`RawPing.Packet.parse_echo_reply/2`.

# `mode`

```elixir
@type mode() :: :dgram | :raw
```

# `close`

```elixir
@spec close(:socket.socket()) :: :ok | {:error, term()}
```

Close an ICMP socket.

# `open`

```elixir
@spec open(keyword()) :: {:ok, :socket.socket(), mode()} | {:error, term()}
```

Open an ICMP socket.

## Options

  * `:mode` - `:auto` (default), `:dgram`, or `:raw`

Returns `{:ok, socket, mode}` or `{:error, reason}`, where `mode` is the
interface actually negotiated.

With `:auto`, no elevated privileges are needed as long as datagram ICMP is
permitted for this process; otherwise it falls back to `:raw`, which requires
root or `CAP_NET_RAW`.

# `recv`

```elixir
@spec recv(:socket.socket(), non_neg_integer()) :: {:ok, binary()} | {:error, term()}
```

Receive an ICMP reply with timeout.

Returns `{:ok, data}` or `{:error, :timeout}` / `{:error, reason}`.

On `:raw` sockets `data` begins with the IP header. On `:dgram` sockets the
kernel strips it and `data` is the ICMP message alone.

# `send`

```elixir
@spec send(:socket.socket(), binary(), :inet.ip_address()) :: :ok | {:error, term()}
```

Send an ICMP packet to a destination IP.

---

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