# `Aerospike.Transport.Tls`
[🔗](https://github.com/luisgabrielroldan/aerospike_driver/blob/v0.3.1/lib/aerospike/transport/tls.ex#L1)

TLS (`:ssl`) implementation of `Aerospike.Cluster.NodeTransport`.

The only real difference between this transport and
`Aerospike.Transport.Tcp` is how the socket is opened: `connect/3`
performs a plain TCP handshake and immediately upgrades the socket via
`:ssl.connect/3` with the caller-supplied verification / cert / key
opts. Once the TLS handshake completes the connection handle is an
`Aerospike.Transport.Tcp{}` struct whose `socket_mod` is `:ssl` rather
than `:gen_tcp`, so every post-connect operation — framing, auth,
compression, telemetry, stream framing — is shared with the plaintext
path. The other callbacks (`command/4`, `command_stream/4`, `info/2`,
`stream_open/4`, `stream_read/2`, `stream_close/1`, `close/1`,
`login/2`) therefore delegate straight to `Aerospike.Transport.Tcp`.

Callers select TLS by setting `transport: Aerospike.Transport.Tls` on
`Aerospike.start_link/1`. Three deployment shapes are supported:

  * **Standard TLS** — server certificate verified against a CA bundle,
    no client cert. Set `:tls_cacertfile` and `:tls_name`.
  * **mTLS** — client presents a cert and key in addition to verifying
    the server. Set `:tls_certfile` / `:tls_keyfile` alongside the CA
    bundle.
  * **PKI** — the server accepts the client cert as auth; `:user` /
    `:password` may be omitted. Same opt shape as mTLS; auth is a
    server-side configuration concern, not a transport one.

## `connect/3` options

Every option lives in the `opts` keyword list. Keys that `Transport.Tcp`
also accepts (`:connect_timeout_ms`, `:info_timeout`, `:node_name`,
`:user`, `:password`, `:session_token`, TCP tuning knobs) flow through
unchanged — the TCP handshake uses them before the TLS upgrade, and the
login RPC runs on top of the upgraded socket if credentials are set.

TLS-specific keys:

  * `:tls_name` — string compared against the server certificate's
    subject / SAN. When set, enables Server Name Indication (SNI) and
    hostname verification. When absent, falls back to the `host`
    argument passed to `connect/3`; callers that connect by IP must
    set `:tls_name` explicitly because OTP's default `:verify_peer`
    rejects an IP as a host name.
  * `:tls_cacertfile` — path to a PEM-encoded CA bundle used to verify
    the server certificate. Required when `:tls_verify` is
    `:verify_peer` (the default).
  * `:tls_certfile` / `:tls_keyfile` — PEM-encoded client certificate
    and private key. Required for mTLS and PKI; omitted for standard
    one-way TLS.
  * `:tls_verify` — `:verify_peer` (default) or `:verify_none`. The
    latter is test-only and logs a `:warning` at connect time.
  * `:tls_opts` — extra keyword list passed through to `:ssl.connect/3`
    verbatim after the plan-level keys above have been translated.
    Use for rarely-tuned knobs (cipher suites, depth, CRL files) that
    the plan does not expose as first-class options.

## Security notes

OTP does not verify hostnames by default even with `:verify_peer` —
the caller must supply `:server_name_indication` and a `:customize_hostname_check`
configuration. This module builds both from `:tls_name` so a caller
who sets the CA bundle and the expected name automatically gets
hostname verification. Callers who need stricter verification (CRL,
OCSP, pinning) pass extra opts through `:tls_opts`.

# `connect_option`

```elixir
@type connect_option() ::
  Aerospike.Transport.Tcp.connect_option()
  | {:tls_name, String.t() | nil}
  | {:tls_cacertfile, Path.t() | nil}
  | {:tls_certfile, Path.t() | nil}
  | {:tls_keyfile, Path.t() | nil}
  | {:tls_verify, :verify_peer | :verify_none}
  | {:tls_opts, keyword()}
```

TLS connection option accepted by `connect/3`.

Includes the plaintext TCP options documented by
`Aerospike.Transport.Tcp` plus TLS verification and certificate keys.

# `connect_opts`

```elixir
@type connect_opts() :: [connect_option()]
```

Keyword list accepted by `connect/3`.

# `close`

```elixir
@spec close(Aerospike.Transport.Tcp.conn()) :: :ok
```

Closes the TLS socket.

# `command`

```elixir
@spec command(
  Aerospike.Transport.Tcp.conn(),
  iodata(),
  non_neg_integer(),
  Aerospike.Transport.Tcp.command_opts()
) :: {:ok, binary()} | {:error, Aerospike.Error.t()}
```

Sends one pre-encoded command frame over TLS and returns one decoded response body.

Accepts `:use_compression`, `:message_type`, and `:attempt` in `opts`.

# `command_stream`

```elixir
@spec command_stream(
  Aerospike.Transport.Tcp.conn(),
  iodata(),
  non_neg_integer(),
  Aerospike.Transport.Tcp.command_opts()
) :: {:ok, binary()} | {:error, Aerospike.Error.t()}
```

Sends one pre-encoded command frame over TLS and reads a bounded multi-frame response.

Accepts the same options as `command/4`.

# `connect`

```elixir
@spec connect(String.t(), :inet.port_number(), connect_opts()) ::
  {:ok, Aerospike.Transport.Tcp.conn()} | {:error, Aerospike.Error.t()}
```

Opens a TCP connection, upgrades it with TLS, and returns a transport handle.

TLS-specific options are documented in the module docs. After the handshake,
command framing and optional auth use `Aerospike.Transport.Tcp`. See
`t:connect_option/0` for supported keys.

# `info`

```elixir
@spec info(Aerospike.Transport.Tcp.conn(), [String.t()]) ::
  {:ok, %{required(String.t()) =&gt; String.t()}} | {:error, Aerospike.Error.t()}
```

Sends one or more info commands over TLS and returns the decoded response map.

# `login`

```elixir
@spec login(
  Aerospike.Transport.Tcp.conn(),
  Aerospike.Cluster.NodeTransport.login_opts()
) ::
  {:ok, Aerospike.Cluster.NodeTransport.login_reply()}
  | {:error, Aerospike.Error.t()}
```

Runs the admin-protocol login or authenticate handshake over TLS.

See `t:Aerospike.Cluster.NodeTransport.login_opts/0` for supported keys.

# `stream_close`

```elixir
@spec stream_close(Aerospike.Transport.Tcp.stream()) :: :ok
```

Closes a TLS stream handle.

# `stream_open`

```elixir
@spec stream_open(
  Aerospike.Transport.Tcp.conn(),
  iodata(),
  non_neg_integer(),
  Aerospike.Transport.Tcp.stream_opts()
) :: {:ok, Aerospike.Transport.Tcp.stream()} | {:error, Aerospike.Error.t()}
```

Sends a streaming TLS request and returns a stream handle for incremental reads.

Accepts `:use_compression` and `:attempt` in `opts`.

# `stream_read`

```elixir
@spec stream_read(Aerospike.Transport.Tcp.stream(), non_neg_integer()) ::
  {:ok, binary()} | :done | {:error, Aerospike.Error.t()}
```

Reads the next frame from a TLS stream.

---

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