Expand description
Socket construction with pre-bind options: the one place in the workspace that opens a socket, sets the address-reuse/broadcast options a protocol needs, and only then binds or connects it.
§Why this exists, and why here
socket2 — the obvious way to set an option on an unbound socket — does not
build for armv7-rtems-eabihf or the *-wrs-vxworks* triples (20 compile
errors on the former: ip_mreqn, IovLen, and friends are Linux shapes the
target’s libc has no equivalent for). So every reactor-free driver that
needed a pre-bind option grew its own raw-libc copy of the same twenty
lines. At the time this module was written there were two, byte-for-byte
alike in everything but their error strings:
epics-ca-rs::server::blocking::bind_udp_search_socketepics-pva-rs::server_native::blocking’s UDP search responder
and asyn-rs’s IP drivers were about to be the third. epics-ca-rs does not
depend on epics-pva-rs and must not, and asyn-rs depends on neither, so
there is exactly one crate all three can reach: this one. A primitive
promoted into any protocol crate is one the other two structurally cannot
call — the same reasoning that put runtime::blocking_io here, for the same
reason.
The second reason is coverage. epics-libcom-rs is the first entry in
CRATES in both scripts/rtems-check.sh and scripts/vxworks-check.sh, so
target-only unsafe placed here is compiled for both triples by the gates
that already run. The same code in a crate outside those lists is compiled
by nothing.
§Why the option must precede the bind
SO_REUSEPORT is what lets several IOCs share one UDP port and have the
kernel fan each datagram out to all of them. The kernel only honours it on
an unbound socket, so UdpSocket::bind() followed by a setsockopt is
not a slower version of this — it is a version that silently does nothing.
That ordering constraint is the whole reason std’s constructors are not
enough and a raw socket()/setsockopt()/bind() sequence is.
§The C authority for each branch
Option selection follows EPICS base
libcom/src/osi/os/default/osdSockAddrReuse.cpp: the datagram-fanout helper
sets SO_REUSEPORT (where defined) and then SO_REUSEADDR; the
time-wait helper sets SO_REUSEADDR alone. Both SO_REUSEPORT constants
exist on the two embedded targets (0x0200 on newlib/RTEMS and on VxWorks),
so neither takes the #ifndef SO_REUSEPORT fallback the C comment describes
for older systems.
Connect behaviour follows asyn drvAsynIPPort.c, whose three branches this
module reproduces exactly:
| target | connect | timeout honoured | C authority |
|---|---|---|---|
| hosted | non-blocking, then poll(POLLOUT) | yes | :511, :523, :544 under USE_POLL |
| VxWorks | non-blocking, then select() via FAKE_POLL | yes | :76, :139-164, :178 |
| RTEMS | blocking | no | :71-72 — __rtems__ takes USE_SOCKTIMEOUT, and both setNonBlock and the poll block sit inside #ifdef USE_POLL |
The RTEMS row is not an omission. C genuinely has no connect timeout there;
it bounds the transfer instead, with SO_RCVTIMEO/SO_SNDTIMEO
(:652-664, :778-790). Honouring the deadline there anyway would be a
deviation invented by the port, so tcp_connect documents the difference
rather than papering over it.
Structs§
- Socket
Options - Options applied to a fresh socket before it is bound or connected.
Functions§
- tcp_
connect - Open a TCP socket, apply
opts, optionally bind it tolocal, and connect it toremotewithintimeout. - tcp_
listener - Open a TCP socket, apply
opts, bind it tolocal, and start listening. - udp_
socket - Open a UDP socket, apply
opts, and bind it tolocal.