Documentation
¶
Overview ¶
Package transport implements FDB's TCP wire protocol: framing, handshake, and request/response multiplexing via endpoint tokens.
Index ¶
- Constants
- Variables
- func BuildPingRequest(replyToken UID) []byte
- func CaptureWireLog(w io.Writer) (stop func())
- func LogRecv(token UID, body []byte)
- func LogSend(token UID, body []byte)
- func NetDesign() string
- func NotifySuspend(ctx context.Context)
- func WriteConnectPacket(w io.Writer, localAddr net.Addr, connectionID uint64) error
- func WriteFrame(w io.Writer, token UID, body []byte, tls bool) error
- type Conn
- func (c *Conn) AdaptiveLinger() time.Duration
- func (c *Conn) BytesReceived() int64
- func (c *Conn) ClearSendOrder(order *sendqueue.Queue)
- func (c *Conn) Close() error
- func (c *Conn) CoalesceDelay() (minDelay, maxDelay time.Duration, waits bool)
- func (c *Conn) Done() <-chan struct{}
- func (c *Conn) Flush() error
- func (c *Conn) FlushContext(ctx context.Context) error
- func (c *Conn) HasPendingReply(token UID) bool
- func (c *Conn) IsClosed() bool
- func (c *Conn) PeerProtocolVersion() uint64
- func (c *Conn) PrepareReply() (UID, <-chan Response, *ReplyHandle)
- func (c *Conn) PrepareReplyTo(dest UID) (UID, <-chan Response, *ReplyHandle)
- func (c *Conn) Send(destToken UID, body []byte) (replyToken UID, replyCh <-chan Response, err error)
- func (c *Conn) SendAndWait(ctx context.Context, destToken UID, body []byte) ([]byte, error)
- func (c *Conn) SendFrame(destToken UID, body []byte) error
- func (c *Conn) SendFrameContext(ctx context.Context, token UID, body []byte) (enqueued bool, err error)
- func (c *Conn) SendFrameContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
- func (c *Conn) SendFrameDeferred(destToken UID, body []byte) error
- func (c *Conn) SendFrameDeferredContext(ctx context.Context, token UID, body []byte) (bool, error)
- func (c *Conn) SendFrameDeferredContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
- func (c *Conn) SendFrameEagerContext(ctx context.Context, token UID, body []byte) (bool, error)
- func (c *Conn) SendFrameEagerContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
- func (c *Conn) SetDebug(enabled bool)
- func (c *Conn) SetEndpointNotFoundHandler(fn func(UID))
- type ConnClosedError
- type ConnectFailedError
- type ConnectPacket
- type DialFunc
- type DialOption
- type EndpointNotFoundError
- type FrameReader
- type PeerVerifyError
- type ReplyHandle
- type Response
- type SuspendSignal
- type UID
- type VerifyPeersError
- type VerifyPolicy
- type WireLog
Constants ¶
const ( DefaultMinCoalesceDelay = 10 * time.Microsecond DefaultMaxCoalesceDelay = 20 * time.Microsecond )
MIN_COALESCE_DELAY and MAX_COALESCE_DELAY (flow/Knobs.cpp:211-212).
const ( // ObjectSerializerFlag signals FlatBuffers serialization (always set in modern FDB). ObjectSerializerFlag uint64 = 0x1000000000000000 // CompatibleProtocolVersionMask: top 48 bits must match for compatibility. CompatibleProtocolVersionMask uint64 = 0xFFFFFFFFFFFF0000 // FDB 7.3 protocol version (without flags). ProtocolVersion73 uint64 = 0x0FDB00B073000000 // FLAG_IPV6 in ConnectPacket.flags. FlagIPv6 uint16 = 1 )
Protocol version constants.
const ( // WLTokenFirstAvailable is the first available well-known token ID. WLTokenFirstAvailable = 3 // WLTokenClientLeaderRegGetLeader is the getLeader endpoint. WLTokenClientLeaderRegGetLeader = 3 // WLTokenClientLeaderRegOpenDatabase is the openDatabase endpoint // used for coordinator bootstrap (OpenDatabaseCoordRequest → ClientDBInfo). WLTokenClientLeaderRegOpenDatabase = 4 // WLTokenProtocolInfo is the protocol info endpoint (stable value). WLTokenProtocolInfo = 10 )
Well-known endpoint token IDs. These are deterministic UIDs that FDB coordinators listen on. From fdbrpc/include/fdbrpc/WellKnownEndpoints.h
const ConnectPacketSize = 44
ConnectPacketSize is the wire size of the ConnectPacket both sides exchange on TCP connection establishment. Packed struct (no padding), 44 bytes total.
Layout:
Offset Size Field 0 4 connectPacketLength (uint32 LE) = 40 (excludes itself) 4 8 protocolVersion (uint64 LE, with objectSerializerFlag bit 60) 12 2 canonicalRemotePort (uint16 LE) 14 8 connectionId (uint64 LE) 22 4 canonicalRemoteIp4 (uint32 LE) 26 2 flags (uint16 LE, bit 0 = FLAG_IPV6) 28 16 canonicalRemoteIp6 (16 bytes, only meaningful if FLAG_IPV6)
Total: 4 + 40 = 44 bytes.
const WLTokenEndpointNotFound = 0
WLTokenEndpointNotFound is WLTOKEN_ENDPOINT_NOT_FOUND (FlowTransport.h:39).
const WLTokenPingPacket = 1
WLTokenPingPacket is the well-known token for PING keepalive.
Variables ¶
var DefaultVerifyPolicy = &VerifyPolicy{rules: []verifyRule{{verifyCert: true}}}
DefaultVerifyPolicy is libfdb_c's default, Check.Valid=1: the chain must verify against the configured roots, and nothing else is checked.
var ErrConnClosed = errors.New("connection closed")
ErrConnClosed is the identity sentinel for a connection teardown. Every error this package delivers for a torn-down connection matches it via errors.Is(err, ErrConnClosed).
Exported so a caller can tell a TRANSPORT teardown apart from an answer the cluster actually gave. The delivered error additionally carries FDB code 1030 request_maybe_delivered (see ConnClosedError), so downstream code has two structural handles: errors.Is against this sentinel while the transport error travels as-is, and the 1030 code once a facade has converted it to its own error type (which drops wrap-chain identity) — matching the rendered message is not one.
var ErrEndpointNotFound = errors.New("endpoint not found")
ErrEndpointNotFound identifies a reply failed because the server no longer has the request's endpoint. It is NOT a connection teardown.
Functions ¶
func BuildPingRequest ¶
BuildPingRequest builds a PingRequest FlatBuffers body. ReplyPromise's object-serializer trait emits a nested table with an inline UID.
func CaptureWireLog ¶
CaptureWireLog writes the wire log to w in the binary format until the returned stop is called. Once stop returns, nothing more is written to w, even by a frame logged concurrently, so w may then be read. It replaces any log already set (FDB_WIRE_LOG); stop removes the capture, leaving none.
func NetDesign ¶
func NetDesign() string
NetDesign reports the writer design new connections use by default: "" for the legacy writer, "d" for timer-coalesced design D, or "ng" for D-NG.
func NotifySuspend ¶
NotifySuspend fires ctx's signal, if it carries one: the caller is about to wait.
func WriteConnectPacket ¶
WriteConnectPacket sends a ConnectPacket to the connection.
Types ¶
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn is a multiplexed FDB connection. Multiple concurrent requests share one TCP connection, matched by endpoint tokens.
Lifecycle: after Close() returns, zero goroutines are running. If the server kills the connection, readLoop cancels the context and IsClosed() returns true — the connection pool will evict it.
func Dial ¶
func Dial(ctx context.Context, addr string, tlsConfig *tls.Config, dialFn DialFunc, opts ...DialOption) (*Conn, error)
Dial connects to an FDB process, exchanges ConnectPackets, and starts the read/write/monitor loops.
tlsConfig is the single source of truth for transport security: non-nil wraps the connection in TLS using that standard *crypto/tls.Config (bring any config — in-memory certs, rotation via GetClientCertificate, custom VerifyPeerCertificate, cipher/version policy); nil means plaintext. There is no separate "use TLS" bool to disagree with it, so a connection can never be silently downgraded. dialFn overrides the dialer (nil → net.Dialer).
func (*Conn) AdaptiveLinger ¶
AdaptiveLinger reports the connection's active adaptive linger window (0 when disabled or when using the legacy writer).
func (*Conn) BytesReceived ¶
BytesReceived returns the socket bytes received since the handshake, frame headers and partial frames included. The connection monitor watches it.
func (*Conn) ClearSendOrder ¶
ClearSendOrder detaches a drained dial generation. The writer retains its finite prefix and held channels until those accepted frames have drained.
func (*Conn) Close ¶
Close closes the connection and waits for its loop goroutines to exit. Safe to call multiple times. After Close returns, zero goroutines are running on this connection.
Shutdown sequence (matches C++ connectionKeeper):
- Cancel context — signals all waiters that conn is dead
- Close TCP socket — unblocks readLoop's ReadFrame
- failConnection delivers errors to all pending requests
- readLoop, naLoop/writeLoop, connectionMonitor and coldControlLoop exit and signal loopWG; the monitor first releases its PING reply (RFC-269)
- Close returns
func (*Conn) CoalesceDelay ¶
CoalesceDelay reports the connection's write delay bounds and whether it waits.
func (*Conn) Done ¶
func (c *Conn) Done() <-chan struct{}
Done returns a channel that is closed when the connection is dead. Use in select statements to detect connection death.
func (*Conn) Flush ¶
Flush checks cold-dial admission and liveness on D-NG, or waits for a flush marker acknowledgment when WithLegacyWriter() is active.
func (*Conn) FlushContext ¶
FlushContext checks ctx, cold-dial order, and connection liveness on D-NG (or waits for an ordered flush marker when WithLegacyWriter() is active).
func (*Conn) HasPendingReply ¶
HasPendingReply reports whether token still owns a reply registration.
func (*Conn) IsClosed ¶
IsClosed returns true if the connection has been closed or the server killed it. Uses context cancellation — works for both shutdown paths.
func (*Conn) PeerProtocolVersion ¶
PeerProtocolVersion returns the peer's protocol version.
func (*Conn) PrepareReply ¶
func (c *Conn) PrepareReply() (UID, <-chan Response, *ReplyHandle)
PrepareReply allocates a reply token and registers it for response routing. Use this when you need the token BEFORE building the request body (e.g., to embed it in the FDB request's Reply field).
Returns a ReplyHandle whose Cancel() removes the pending token. Call handle.Release() when done to return it to the pool.
func (*Conn) PrepareReplyTo ¶
func (c *Conn) PrepareReplyTo(dest UID) (UID, <-chan Response, *ReplyHandle)
PrepareReplyTo is PrepareReply for a request that will be sent to dest, so an ENDPOINT_NOT_FOUND for dest fails this reply instead of leaving it to time out.
func (*Conn) Send ¶
func (c *Conn) Send(destToken UID, body []byte) (replyToken UID, replyCh <-chan Response, err error)
Send sends a request and returns a channel that will receive the response. The destToken identifies the remote endpoint (e.g., a StorageServer's getValue endpoint). The replyToken is a fresh token for routing the response back.
func (*Conn) SendAndWait ¶
SendAndWait sends a request and blocks until the response arrives.
func (*Conn) SendFrame ¶
SendFrame queues a raw frame on the connection's writer (returning once appended on D-NG, or after write/tail handoff on WithLegacyWriter()).
func (*Conn) SendFrameContext ¶
func (c *Conn) SendFrameContext(ctx context.Context, token UID, body []byte) (enqueued bool, err error)
SendFrameContext enqueues a frame (or waits for its flush on WithLegacyWriter); cancelling ctx ends admission/high-water/flush wait without retracting queued bytes.
func (*Conn) SendFrameContextOrdered ¶
func (c *Conn) SendFrameContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
SendFrameContextOrdered sends using a place reserved before a cold peer dial. The place is released on acceptance, before any flush or reply wait. Its owner must pass it here: a nil-permit send on the same connection can wait for that still-owned place and deadlock. Release abandoned places instead.
func (*Conn) SendFrameDeferred ¶
SendFrameDeferred queues a raw frame without waiting for a socket write.
func (*Conn) SendFrameDeferredContext ¶
SendFrameDeferredContext transfers an immutable copy to the write queue without waiting for a socket write acknowledgment (the bool reports enqueue, not wire delivery).
func (*Conn) SendFrameDeferredContextOrdered ¶
func (c *Conn) SendFrameDeferredContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
SendFrameDeferredContextOrdered is the deferred form with a cold dial place.
func (*Conn) SendFrameEagerContext ¶
SendFrameEagerContext is SendFrameDeferredContext for a frame nothing is about to join (enqueues on D-NG; writes directly when idle on WithLegacyWriter()).
func (*Conn) SendFrameEagerContextOrdered ¶
func (c *Conn) SendFrameEagerContextOrdered(ctx context.Context, token UID, body []byte, permit *sendqueue.Permit) (bool, error)
SendFrameEagerContextOrdered is the eager form with a cold dial place.
func (*Conn) SetEndpointNotFoundHandler ¶
SetEndpointNotFoundHandler installs fn to observe every ENDPOINT_NOT_FOUND token this connection receives, whether or not a reply is still waiting.
type ConnClosedError ¶
type ConnClosedError struct {
// contains filtered or unexported fields
}
ConnClosedError is the teardown error delivered to in-flight requests and queued senders when the connection is torn down (by Close, the monitor, a read error, or a write error). It matches BOTH errors.Is(err, ErrConnClosed) (teardown identity) and errors.As(err, **wire.FDBError) with code 1030 request_maybe_delivered, so the client's retry machinery sees the same coded, C++-faithful condition libfdb_c's loadBalance sees. Cause (the underlying read/write error, when there is one) is carried in the message only — NOT in the Unwrap chain — so a teardown can never spuriously match errors.Is/As probes aimed at its cause (e.g. a context error check).
func (*ConnClosedError) Error ¶
func (e *ConnClosedError) Error() string
func (*ConnClosedError) Unwrap ¶
func (e *ConnClosedError) Unwrap() []error
type ConnectFailedError ¶
type ConnectFailedError struct {
Addr string
// contains filtered or unexported fields
}
ConnectFailedError is a failed connect to a peer, as a request waiting on that connect observes it. C++ connectionKeeper turns any connect or handshake failure, including its CONNECTION_MONITOR_TIMEOUT, into connection_failed (FlowTransport.actor.cpp:819-869, Net2.actor.cpp:363-391 and 413-430), discards the peer's unsent unreliable packets and fires peer->disconnect (FlowTransport.actor.cpp:933, 1001-1004). Every tryGetReply queued on the peer then completes with request_maybe_delivered (fdbrpc.h:797-816, genericactors.actor.h:380-385), whether or not its packet ever left the client. So this matches errors.As(err, **wire.FDBError) with code 1030 and nothing else: the dial error is message-only, so a dial timeout cannot match a caller's context probes.
func NewConnectFailedError ¶
func NewConnectFailedError(addr string, cause error) *ConnectFailedError
NewConnectFailedError codes cause, the error of a failed dial to addr.
func (*ConnectFailedError) Cause ¶
func (e *ConnectFailedError) Cause() error
Cause returns the dial error, for diagnostics.
func (*ConnectFailedError) Error ¶
func (e *ConnectFailedError) Error() string
func (*ConnectFailedError) Unwrap ¶
func (e *ConnectFailedError) Unwrap() error
type ConnectPacket ¶
type ConnectPacket struct {
ProtocolVersion uint64
CanonicalRemotePort uint16
ConnectionID uint64
CanonicalRemoteIP4 uint32
Flags uint16
CanonicalRemoteIP6 [16]byte
}
ConnectPacket represents the FDB connection handshake packet.
func ReadConnectPacket ¶
func ReadConnectPacket(r io.Reader) (*ConnectPacket, error)
ReadConnectPacket reads a ConnectPacket from the connection.
func (*ConnectPacket) HasObjectSerializerFlag ¶
func (p *ConnectPacket) HasObjectSerializerFlag() bool
HasObjectSerializerFlag returns true if the protocol version uses FlatBuffers.
func (*ConnectPacket) IsCompatible ¶
func (p *ConnectPacket) IsCompatible(ourVersion uint64) bool
IsCompatible returns true if the peer's protocol version is compatible.
func (*ConnectPacket) IsIPv6 ¶
func (p *ConnectPacket) IsIPv6() bool
IsIPv6 returns true if the canonical address is IPv6.
func (*ConnectPacket) Marshal ¶
func (p *ConnectPacket) Marshal() []byte
Marshal serializes the ConnectPacket to wire format (44 bytes).
func (*ConnectPacket) Unmarshal ¶
func (p *ConnectPacket) Unmarshal(buf []byte) error
Unmarshal deserializes a ConnectPacket from wire format.
type DialFunc ¶
DialFunc is the signature for custom dialers. Same as net.Dialer.DialContext. Default is net.Dialer{}.DialContext. Override for testing (fault injection, custom Docker networking, traffic shaping).
type DialOption ¶
type DialOption func(*Conn)
DialOption configures a Conn before its loop goroutines start.
func WithAdaptiveLinger ¶
func WithAdaptiveLinger(d time.Duration) DialOption
WithAdaptiveLinger configures Nagle-style adaptive linger on the D-NG writer (0 disables; the last linger/coalesce option wins; RFC-282).
func WithCoalesceDelay ¶
func WithCoalesceDelay(minDelay, maxDelay time.Duration) DialOption
WithCoalesceDelay sets the connection's timer-based batch delay bounds (default 0, 0 on D-NG; 10/20 µs on WithLegacyWriter(); the last linger/coalesce option wins).
func WithLegacyWriter ¶
func WithLegacyWriter() DialOption
WithLegacyWriter pins the legacy writer (writeLoop, direct writes, writer turns) whatever FDBGO_NET_DESIGN says. Tests of those mechanics use it.
func WithSendOrder ¶
func WithSendOrder(order *sendqueue.Queue) DialOption
WithSendOrder attaches one finite cold cohort before the connection loops start. Prefix and held frames have independent bounded admission channels.
type EndpointNotFoundError ¶
type EndpointNotFoundError struct {
Token UID
}
EndpointNotFoundError is delivered to every pending reply whose request went to Token. It matches ErrEndpointNotFound and FDB code 1030: C++ tryGetReply completes such a request with request_maybe_delivered (genericactors.actor.h:375-378) and leaves the connection alone.
func (*EndpointNotFoundError) Error ¶
func (e *EndpointNotFoundError) Error() string
func (*EndpointNotFoundError) Unwrap ¶
func (e *EndpointNotFoundError) Unwrap() []error
type FrameReader ¶
type FrameReader struct {
// contains filtered or unexported fields
}
FrameReader reads framed messages with a persistent header buffer to avoid per-frame heap allocations for the 4-byte length + 8-byte checksum reads. Not safe for concurrent use — intended for single-goroutine readLoop.
type PeerVerifyError ¶
type PeerVerifyError struct {
Reason string
Err error // the chain error, when the chain did not verify
}
PeerVerifyError reports a peer certificate the policy rejects.
func (*PeerVerifyError) Error ¶
func (e *PeerVerifyError) Error() string
func (*PeerVerifyError) Unwrap ¶
func (e *PeerVerifyError) Unwrap() error
type ReplyHandle ¶
type ReplyHandle struct {
// contains filtered or unexported fields
}
ReplyHandle holds state for a pending reply. Pooled to avoid closure allocation in PrepareReply (the cancel closure captured conn+token+ch, causing a heap alloc on every RPC call — ~9% of total allocs in SaveRecord benchmarks).
func (*ReplyHandle) Cancel ¶
func (h *ReplyHandle) Cancel()
Cancel removes the pending reply from the connection's pending map and returns the reply channel to the pool. Safe to call on a handle with a nil conn (no-op).
func (*ReplyHandle) KeepReadyOrCancel ¶
func (h *ReplyHandle) KeepReadyOrCancel() bool
KeepReadyOrCancel leaves a published response for the caller's normal receive, or cancels an unpublished reply atomically. Like TakeReadyOrCancel, this needs exclusive handle ownership. It never adds a second channel producer.
func (*ReplyHandle) NotifyWait ¶
func (h *ReplyHandle) NotifyWait(ctx context.Context)
NotifyWait marks suspension only when the response is not already published. The caller owns the handle and has not received from its channel yet.
func (*ReplyHandle) Release ¶
func (h *ReplyHandle) Release()
Release returns the handle to the pool. Call EITHER after a successful receive (no Cancel) OR after Cancel. On the success path h.ch is still set and is pooled here: response publication and token deletion share the token's pendingShard.mu lock, in that order. Once the caller receives the response, that publisher has no further channel send, and the lock excludes another publisher until deletion. Cancel nils h.ch, so the cancel path never double-pools.
func (*ReplyHandle) TakeReadyOrCancel ¶
func (h *ReplyHandle) TakeReadyOrCancel() (Response, bool)
TakeReadyOrCancel chooses response publication or cancellation under the connection's reply lock. The caller must exclusively own this handle and channel (no concurrent receive/Cancel/Release). Release is still required.
type Response ¶
type Response struct {
Body []byte
Err error
// RecvAt is when the read loop delivered this reply (≈ arrival time). Set only
// on a successful body delivery; lets a caller measure send→receive latency
// independent of when it gets around to consuming the reply (RFC-114).
RecvAt time.Time
}
Response is a received message from the peer.
type SuspendSignal ¶
type SuspendSignal struct {
// contains filtered or unexported fields
}
SuspendSignal marks the first wait of a goroutine that carries it in its context: the point where a flow actor would suspend at its first wait that is not ready. The client's NativeAPI getRange fallback starts end's resolveKey there, after begin's (NativeAPI.actor.cpp:4465-4469). Every wait on a request's path fires it before blocking: the dial wait, high-water backpressure (or on the legacy writer a full write queue, the flush acknowledgment, and the writer turn's coalescing delay), the reply wait, and delays.
func WithSuspendHandoff ¶
func WithSuspendHandoff(ctx context.Context, resume <-chan struct{}, beforeWait func()) (context.Context, *SuspendSignal)
WithSuspendHandoff also holds the notifying worker until resume closes. Fire remains nonblocking so completion and panic cleanup cannot wait on a successor. beforeWait optionally observes an unready gate, outside the signal's Once.
func WithSuspendSignal ¶
func WithSuspendSignal(ctx context.Context) (context.Context, *SuspendSignal)
WithSuspendSignal returns ctx carrying a new signal. The owner must Fire it when the goroutine ends, whether or not it waited.
func (*SuspendSignal) Done ¶
func (s *SuspendSignal) Done() <-chan struct{}
Done is closed at the first wait, or when the owner fires it.
type UID ¶
UID is a 128-bit identifier (two uint64s). Used for endpoint tokens.
func NewUID ¶
func NewUID() UID
NewUID generates a random 128-bit UID for endpoint tokens. Uses a single atomic progression on fastRNGState per 128-bit UID.
func ReadFrame ¶
ReadFrame reads one framed message from r. Returns the endpoint token and the message body (without token). Deprecated: Use FrameReader.Read for reduced allocations.
func WellKnownToken ¶
WellKnownToken returns the UID for a well-known endpoint token. In C++: Endpoint::wellKnownToken(id) = UID(-1, id). The first part is all-ones (0xFFFFFFFFFFFFFFFF), second part is the token ID.
type VerifyPeersError ¶
VerifyPeersError reports a verify-peers string libfdb_c refuses to parse.
func (*VerifyPeersError) Error ¶
func (e *VerifyPeersError) Error() string
type VerifyPolicy ¶
type VerifyPolicy struct {
// contains filtered or unexported fields
}
VerifyPolicy is a parsed verify-peers setting, the policy libfdb_c applies to a peer certificate (flow/TLSConfig.actor.cpp TLSPolicy). Any rule that matches accepts the peer.
func ParseVerifyPeers ¶
func ParseVerifyPeers(s string) (*VerifyPolicy, error)
ParseVerifyPeers parses a verify-peers string as set_verify_peers and TLSPolicy::Rule do (TLSConfig.actor.cpp:503-611): rules split on '|', each a comma-separated list of term[<>]?=value.
func (*VerifyPolicy) Verify ¶
func (p *VerifyPolicy) Verify(certs []*x509.Certificate, roots *x509.CertPool) error
Verify applies the policy to the peer's certificates, leaf first, as TLSPolicy::verify_peer does: a rule with Check.Valid=0 accepts any peer; otherwise the chain must verify against roots and one rule must match it. Nil roots trust nothing, as libfdb_c with no CA; never the system roots.
func (*VerifyPolicy) VerifyConnection ¶
func (p *VerifyPolicy) VerifyConnection(roots *x509.CertPool) func(tls.ConnectionState) error
VerifyConnection returns a tls.Config.VerifyConnection hook applying the policy against roots, reading no host name; the config needs InsecureSkipVerify.
type WireLog ¶
type WireLog struct {
// contains filtered or unexported fields
}
WireLog records every frame sent/received on FDB connections. Enable via FDB_WIRE_LOG=/path/to/file.bin (binary format) or FDB_WIRE_LOG=stderr (human-readable hex to stderr).
Binary format per entry:
[1] direction: 'S' = send, 'R' = recv [8] timestamp: nanoseconds since Unix epoch, little-endian uint64 [8] token.First: little-endian uint64 [8] token.Second: little-endian uint64 [4] body length: little-endian uint32 [N] body bytes
Use cmd/fdb-wirelog-dump to convert binary logs to human-readable form or diff two logs.