Skip to content

libtailcat, tailcat: add C bindings for embedding tailcat - #6

Draft
bradfitz wants to merge 1 commit into
mainfrom
bradfitz/libtailcat-c
Draft

libtailcat, tailcat: add C bindings for embedding tailcat#6
bradfitz wants to merge 1 commit into
mainfrom
bradfitz/libtailcat-c

Conversation

@bradfitz

Copy link
Copy Markdown
Member

Add a libtailcat directory that builds tailcat as a C library
(c-archive and c-shared), modeled on github.com/tailscale/libtailscale,
so tailcat can be embedded from C and from languages that link C.

Connections and listeners cross the Go/C boundary as AF_UNIX socketpair
file descriptors: dials and accepts hand C a plain fd it can read,
write, poll, and close, so callers keep their existing netpoll event
loops instead of adopting a callback API. Listeners deliver accepted
connection fds via SCM_RIGHTS, making the listener itself pollable.
Unlike libtailscale's fd plumbing, teardown waits for both copy
directions to finish, preserving tailcat's netcat-style TCP half-close
semantics.

Lifecycle events (client-connected, connected, dial-ok, dial-error)
are delivered per handle through an event fd that becomes readable
when JSON events are queued, again for event loop friendliness.
tailcat_client_dial is asynchronous: it returns the connection fd
immediately, buffers writes in the socketpair, and reports the dial
outcome as an event.

In support of that, tailcat grows three small hooks: an exported
Server.OnClientConnect callback fired when a client's meow handshake
adds it as a peer, a Client.Connected channel accessor, and
Server.WaitDERPConnected. The latter also fixes a real race:
a client meow arriving at the relay before the server's DERP
connection is up was silently lost, costing a 10 second retry.
libtailcat's server start now waits for the relay connection so a
ConnBlob handed out right after start is immediately usable.

The ctest package drives a full C client/server exchange through a
local DERP relay under go test, and CI builds both library flavors.

Updates #5

Add a libtailcat directory that builds tailcat as a C library
(c-archive and c-shared), modeled on github.com/tailscale/libtailscale,
so tailcat can be embedded from C and from languages that link C.

Connections and listeners cross the Go/C boundary as AF_UNIX socketpair
file descriptors: dials and accepts hand C a plain fd it can read,
write, poll, and close, so callers keep their existing netpoll event
loops instead of adopting a callback API. Listeners deliver accepted
connection fds via SCM_RIGHTS, making the listener itself pollable.
Unlike libtailscale's fd plumbing, teardown waits for both copy
directions to finish, preserving tailcat's netcat-style TCP half-close
semantics.

Lifecycle events (client-connected, connected, dial-ok, dial-error)
are delivered per handle through an event fd that becomes readable
when JSON events are queued, again for event loop friendliness.
tailcat_client_dial is asynchronous: it returns the connection fd
immediately, buffers writes in the socketpair, and reports the dial
outcome as an event.

In support of that, tailcat grows three small hooks: an exported
Server.OnClientConnect callback fired when a client's meow handshake
adds it as a peer, a Client.Connected channel accessor, and
Server.WaitDERPConnected. The latter also fixes a real race:
a client meow arriving at the relay before the server's DERP
connection is up was silently lost, costing a 10 second retry.
libtailcat's server start now waits for the relay connection so a
ConnBlob handed out right after start is immediately usable.

The ctest package drives a full C client/server exchange through a
local DERP relay under go test, and CI builds both library flavors.

Updates #5

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I9c4e2f7a8b3d1e5f0a6c9b2d4e7f8a1c3b5d6e9f
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