Skip to content

Client: add --connectdirectory for directory-assisted hole punch on --connect#3815

Draft
mcfnord wants to merge 4 commits into
jamulussoftware:mainfrom
mcfnord:connect-directory-holepunch
Draft

Client: add --connectdirectory for directory-assisted hole punch on --connect#3815
mcfnord wants to merge 4 commits into
jamulussoftware:mainfrom
mcfnord:connect-directory-holepunch

Conversation

@mcfnord

@mcfnord mcfnord commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Short description of changes

Adds an optional --connectdirectory <host:port> client option and gives CClient::Connect an optional directory argument. When a directory is supplied, the client first asks that directory for its server list — which makes the directory tell its registered servers to send an "empty message" toward the client's socket (the same directory-assisted UDP hole punch the GUI directory list relies on) — waits HOLE_PUNCH_CONNECT_DELAY_MS, then connects.

Today -c / --connect connects straight to the address and never contacts a directory, so a server behind a cloud firewall/NAT that the GUI reaches fine is silently unreachable via -c. The server address is connected to verbatim and need not appear in the directory's server list, so this also lets you reach a server that isn't in any built-in directory by naming the (possibly custom/private) directory it is registered with.

CHANGELOG: Client: Added --connectdirectory to hole-punch through a directory when connecting on startup with --connect

Context: Fixes an issue?

Relates to jamulussoftware/jamuluswebsite#1122, which documents this -c reachability limitation. This is the code side of that gap.

Stacked on #3805 — it uses the CClient::Connect refactor introduced there, so the diff currently includes #3805's commit; the single top commit is the change in this PR. Please review/merge #3805 first.

Does this change need documentation? What needs to be documented and how?

Yes — a short website entry for --connectdirectory next to the -c text (a companion to the -c note added in jamuluswebsite#1156). A draft on the website repo will follow.

Status of this Pull Request

Working implementation. Verified with a UDP capture: with --connectdirectory the client sends CLM_REQ_SERVER_LIST to the directory and connects ~400 ms later; without it there is no directory traffic and behaviour is unchanged. Clean SIGTERM shutdown, including when interrupted during the hole-punch delay.

What is missing until this pull request can be merged?

Depends on #3805 merging first. Otherwise ready for review.

Checklist

  • I've verified that this Pull Request follows the general code principles
  • I tested my code and it does what I want
  • My code follows the style guide
  • I waited some time after this Pull Request was opened and all GitHub checks completed without errors.
  • I've filled all the content above

pgScorpio and others added 2 commits July 19, 2026 01:01
This is an extract from jamulussoftware#2550
Co-authored-by: ann0see <20726856+ann0see@users.noreply.github.com>
Introduce EConnectionState (disconnected / connecting / connected) owned
by CClient as the single source of truth. A connection is 'requested'
when the audio stream starts (CS_CONNECTING) and 'established' once the
server assigns our channel ID (CS_CONNECTED). Every transition emits
ConnectionStateChanged.

Rename the Connected(name) signal emitted from Start() to
Connecting(name), since at that point the connection is only requested,
not established. CClient::Connect() now terminates any current
connection first, so connecting while connected behaves as a reconnect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jrd and others added 2 commits July 21, 2026 05:55
- SIGTERM/SIGINT: route through Disconnect() instead of a raw Stop(),
  and guard Disconnect() on the connection state rather than IsRunning()
  (which tracks the audio device). IsRunning() is false while connecting
  and in headless mode, so the old guard could skip notifying the server
  on shutdown; the raw Stop() worked around that but also fired a
  spurious disconnect when idle. Now the server is notified iff a
  connection is pending or established, via the single Disconnect() path.
- Move EConnectionState from util.h to client.h (it is client specific).
- Add a doc-comment to SetConnectionState; reword two member comments.

Addresses review feedback on jamulussoftware#3805.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-c / --connect connects straight to the given address and, unlike
selecting a server from the GUI directory list, never asks a directory
to open the target's firewall. Servers behind a cloud firewall/NAT that
the GUI reaches fine are therefore silently unreachable via -c.

Give CClient::Connect an optional directory argument: when set it sends
a CLM_REQ_SERVER_LIST to that directory (which makes the directory poke
its registered servers towards our socket -- the same UDP hole punch the
GUI relies on), waits HOLE_PUNCH_CONNECT_DELAY_MS, then connects. The
server address is used verbatim and need not be listed by the directory.

Expose it on the command line as --connectdirectory <host:port>, wired
through both the GUI and headless connect-on-startup paths in main.cpp.

Relates to jamulussoftware/jamuluswebsite#1122

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mcfnord
mcfnord force-pushed the connect-directory-holepunch branch from 1339edc to 1e9a6b3 Compare July 21, 2026 06:01
@ann0see

ann0see commented Jul 21, 2026

Copy link
Copy Markdown
Member

Best case -c would fall back automatically to this after some timeout imo. This doesn't exclude an explicit option but would be more user friendly

@mcfnord

mcfnord commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Best case -c would fall back automatically to this after some timeout imo. This doesn't exclude an explicit option but would be more user friendly

The client would need to know which directory to use, and that will have to be specified by the CLI parameters. It would be too sloppy and nuts to guess all 7, and even if we do, it might be some other directory entirely.

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.

3 participants