<!--
{
  "availability" : [

  ],
  "documentType" : "symbol",
  "framework" : "Tor",
  "identifier" : "/documentation/Tor/ControlSocket",
  "metadataVersion" : "0.1.0",
  "role" : "Class",
  "symbol" : {
    "kind" : "Class",
    "modules" : [
      "Tor"
    ],
    "preciseIdentifier" : "s:3Tor13ControlSocketC"
  },
  "title" : "ControlSocket"
}
-->

# ControlSocket

Cross-platform, `Sendable` line-oriented wrapper around a Tor control
socket file descriptor.

```
final class ControlSocket
```

## Overview

`ControlSocket` is the POSIX-level plumbing that sits under
[`TorControlClient`](/documentation/Tor/TorControlClient). It provides the three operations the
control protocol demands (control-spec.txt §2): write a
CRLF-terminated command line, read back a CRLF-terminated reply
line, and assemble multi-line (`250-`, `250+`, `650+`) replies into a
single `[String]`. The underlying FD is either the pre-authenticated
socket from `tor_main_configuration_setup_control_socket()` (embedded
mode) or a freshly-opened TCP connection to a listening `ControlPort`.

Platform plumbing is abstracted across Darwin (`Darwin`), Linux
(`Glibc`, `Musl`), and Windows (`WinSDK`) via `#if canImport(…)`
guards. Sockets are configured with `SO_RCVTIMEO` so blocking `recv`
calls honour [`readTimeout`](/documentation/Tor/ControlSocket/readTimeout) without requiring a polling loop.

> Note: Conformance is `Sendable` (compiler-verified, no `@unchecked`).
> All mutable state lives inside a `Mutex<State>` from the
> `Synchronization` module (SE-0410); callers may share instances
> across concurrency domains and call methods concurrently — each
> operation acquires the mutex for its own critical section.

> Important: The `deinit` calls `close(2)` (or `closesocket()` on
> Windows) **only** when ``doc://Tor/documentation/Tor/ControlSocket/init(fileDescriptor:ownsDescriptor:)`` was
> invoked with `ownsDescriptor: true`. Embedded control sockets from
> `tor_api` are owned by Tor; swift-tor must not close them.

## Topics

### Creating

[`init(fileDescriptor:ownsDescriptor:)`](/documentation/Tor/ControlSocket/init(fileDescriptor:ownsDescriptor:))

Wrap an already-open file descriptor.

[`init(host:port:)`](/documentation/Tor/ControlSocket/init(host:port:))

Open a TCP connection to a control port and wrap it.

[`init(endpoint:)`](/documentation/Tor/ControlSocket/init(endpoint:))

Open a TCP connection to a typed [`HostPort`](/documentation/Tor/HostPort) endpoint.

### I/O

[`writeLine(_:)`](/documentation/Tor/ControlSocket/writeLine(_:))

Send a single protocol command line.

[`writeData(_:)`](/documentation/Tor/ControlSocket/writeData(_:))

Send a raw byte payload, looping until every byte is written.

[`readLine()`](/documentation/Tor/ControlSocket/readLine())

Read one CRLF-terminated line, buffering residual bytes for the
next call.

[`readReply()`](/documentation/Tor/ControlSocket/readReply())

Read a complete control-protocol reply as an ordered `[String]`.

[`sendCommand(_:)`](/documentation/Tor/ControlSocket/sendCommand(_:))

Send a command and return the parsed reply.

[`readLineAsync()`](/documentation/Tor/ControlSocket/readLineAsync())

`readLine()` hoisted off the cooperative thread pool.

### State

[`readTimeout`](/documentation/Tor/ControlSocket/readTimeout)

Read timeout in seconds, applied to every [`readLine()`](/documentation/Tor/ControlSocket/readLine()) call.

[`isValid`](/documentation/Tor/ControlSocket/isValid)

`true` if the wrapped FD is non-negative, i.e. structurally valid.

