Skip to content

feat: take the socket options callers actually pass - #49

Merged
Taure merged 2 commits into
mainfrom
feat/socket-options-callers-pass
Aug 11, 2026
Merged

feat: take the socket options callers actually pass#49
Taure merged 2 commits into
mainfrom
feat/socket-options-callers-pass

Conversation

@Taure

@Taure Taure commented Aug 11, 2026

Copy link
Copy Markdown
Owner

The accept-list was built from what a socket can be set to. That is how inet came to be refused and an outage came within one merge of production - and fixing that one option left the same shape behind. {ip, _}, {linger, _}, {priority, _}, {tos, _}, {reuseaddr, _} and {bind_to_device, _} were all still refused, waiting for the first caller to pass one.

Now sorted by what an option decides.

Read before connecting, the only moment they mean anything: inet, inet6, and now {ip, _} and {port, _}, which choose the local end to bind - how a multi homed host picks which interface the server sees.

Set on the socket: the four that already were, plus {priority, _}, {reuseaddr, _}, {tos, _}, {bind_to_device, _} and {linger, _} (translating gen_tcp's {OnOff, Seconds} into the struct the socket module wants).

Accepted and ignored, and documented as such: {delay_send, _}, {high_watermark, _}, {low_watermark, _}, {exit_on_close, _}, {show_econnreset, _}. These configure a port's send queue and a port's error reporting, and there is no port here.

Anything else is still refused rather than silently dropped, and the guide now says plainly that hitting that with an option the driver takes is a gap in the list rather than a decision.

Tests

  • every_socket_option_the_list_claims_is_taken - all twenty in one connection, both transports.
  • a_local_address_is_bound_not_ignored - binds TEST-NET-1, which no machine can have, and requires eaddrnotavail. Asking the server which address it sees proves nothing through a NAT, and a container is one.

Both fail without the change. 1398 eunit, 184 ct, and the full static pipeline clean.

Type note

Taking [gen_tcp:connect_option()] instead of [term()] is what made the option values typed at all, and eqWAlizer immediately found that {ip, _} is wider than an address: any, loopback and {local, Path} are all legal. All three are handled now. That would have been a crash on a caller doing something perfectly ordinary.

The list was what a socket happens to be settable to. That is how `inet` came to
be refused, and the fix for it left the same shape behind: `{ip, _}`,
`{linger, _}`, `{priority, _}` and friends were still refused, waiting for the
first caller who passes one.

Sorted by what the option decides rather than by what it looks like.

Read before connecting, because that is the only moment they mean anything:
`inet`, `inet6`, and now `{ip, _}` and `{port, _}`, which choose the local end
to bind - how a multi homed host picks the interface the server sees.

Set on the socket: the four that already were, and now `{priority, _}`,
`{reuseaddr, _}`, `{tos, _}`, `{bind_to_device, _}` and `{linger, _}`, which
takes `m:gen_tcp`'s `{OnOff, Seconds}` and gives the socket module the struct
the OS wants.

Accepted and ignored, and said out loud: `{delay_send, _}`, `{high_watermark,
_}`, `{low_watermark, _}`, `{exit_on_close, _}` and `{show_econnreset, _}`
configure a port's send queue and a port's reporting. There is no port here.

Anything else is still refused rather than dropped. The doc now says that a
refusal for an option the driver takes is a gap in this list rather than a
decision.

Taking `[gen_tcp:connect_option()]` rather than `[term()]` is what let the
option values be typed at all, which is how `{ip, _}` turned out to be wider
than an address: `any`, `loopback` and `{local, Path}` are all legal and now
handled.
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

🟡 Code Coverage — 88.6%

1780 of 2008 lines covered.


✅ ELP Lint

No diagnostics.

Windows found both of these, which is what it is there for.

`priority` and `tos` are Linux's. Setting them on Windows answers
`{invalid, {socket_option, _}}`, and refusing the connection over that would
mean a config that works on one machine breaks on another - the same shape as
refusing `inet`, one layer along. The driver does not fail a connection over an
option the OS has never heard of, and neither does this now.

The refusal case assumed the driver answers `{error, _}` for an option it will
not take. On Windows it raises instead. Either is a refusal; what the case is
about is the transport that has to decide for itself.
@Taure
Taure merged commit 059c48e into main Aug 11, 2026
19 checks passed
@Taure
Taure deleted the feat/socket-options-callers-pass branch August 11, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant