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

Pure Erlang/OTP ICMP ping library using the modern `:socket` API.

No NIFs, no external dependencies. Requires Elixir 1.17+ (OTP 25+).

## Usage

    # Single ping
    {:ok, rtt_ms} = RawPing.ping("8.8.8.8")
    {:ok, rtt_ms} = RawPing.ping({8, 8, 8, 8})

    # With options
    {:ok, rtt_ms} = RawPing.ping("8.8.8.8", timeout: 2000)

    # Multiple pings with stats
    {:ok, stats} = RawPing.ping_stats("8.8.8.8", count: 5)
    # => {:ok, %{min: 10.5, max: 15.2, avg: 12.3, success_rate: 1.0, ...}}

    # Batch ping multiple hosts
    results = RawPing.ping_batch(["8.8.8.8", "1.1.1.1", "192.168.1.1"])
    # => %{"8.8.8.8" => {:ok, 12.5}, "1.1.1.1" => {:ok, 8.2}, ...}

## Privileges

Raw ICMP sockets typically require elevated privileges. Options:
- Run as root/sudo
- Set CAP_NET_RAW capability on the BEAM: `setcap cap_net_raw+ep /path/to/beam.smp`
- Use a setuid wrapper

## How It Works

Uses Erlang's `:socket` module to open a raw ICMP socket, builds ICMP echo
request packets manually, sends them, and parses the echo replies to calculate
round-trip time.

# `ip_address`

```elixir
@type ip_address() :: String.t() | :inet.ip_address() | [integer()]
```

# `ping_result`

```elixir
@type ping_result() :: {:ok, float()} | {:error, term()}
```

# `ping_stats`

```elixir
@type ping_stats() :: %{
  min: float() | nil,
  max: float() | nil,
  avg: float() | nil,
  success_rate: float(),
  success_count: non_neg_integer(),
  failure_count: non_neg_integer(),
  rtts: [float()]
}
```

# `ping`

```elixir
@spec ping(
  ip_address(),
  keyword()
) :: ping_result()
```

Ping a host and return the round-trip time in milliseconds.

## Options

  * `:timeout` - Timeout in milliseconds (default: 5000)
  * `:payload_size` - Size of ICMP payload in bytes (default: 56)

## Examples

    {:ok, rtt} = RawPing.ping("8.8.8.8")
    {:ok, rtt} = RawPing.ping({8, 8, 8, 8}, timeout: 1000)
    {:error, :timeout} = RawPing.ping("10.255.255.1", timeout: 100)

# `ping_batch`

```elixir
@spec ping_batch(
  [ip_address()],
  keyword()
) :: %{required(String.t()) =&gt; ping_result()}
```

Ping multiple hosts concurrently.

Returns a map of host => result.

## Options

  * `:timeout` - Timeout per ping in milliseconds (default: 5000)
  * `:max_concurrency` - Maximum concurrent pings (default: 50)

## Examples

    results = RawPing.ping_batch(["8.8.8.8", "1.1.1.1"])
    # %{"8.8.8.8" => {:ok, 12.5}, "1.1.1.1" => {:ok, 8.2}}

# `ping_stats`

```elixir
@spec ping_stats(
  ip_address(),
  keyword()
) :: {:ok, ping_stats()} | {:error, term()}
```

Ping a host multiple times and return statistics.

## Options

  * `:count` - Number of pings to send (default: 1)
  * `:timeout` - Timeout per ping in milliseconds (default: 5000)
  * `:payload_size` - Size of ICMP payload in bytes (default: 56)

## Examples

    {:ok, stats} = RawPing.ping_stats("8.8.8.8", count: 5)
    # %{min: 10.2, max: 15.8, avg: 12.5, success_rate: 1.0, ...}

---

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