Skip to content

ams::mitm::p2p::P2pProxyServer

P2P Proxy Server.

TCP server that hosts direct P2P connections for LDN multiplayer. When a Switch creates a network (hosts), this server accepts connections from other players who join via P2P instead of through the relay server.Thread SafetyAll public methods are thread-safe. Internal state is protected by mutex. serverStart(port) - begin listening- open UPnP port (optional but recommended)Accept connections, validate tokensRoute proxy messages between sessions- cleanup and close

Type: constexpr uint16_t

Type: constexpr int

Type: constexpr uint16_t

Type: constexpr int

Type: constexpr int

Type: constexpr int

Type: constexpr int

Type: constexpr int

Type: os::Mutex

Type: int

Type: uint16_t

Type: uint16_t

Type: bool

Type: bool

Type: os::ThreadType

Type: uint8_t

Type: os::ThreadType

Type: uint8_t

Type: bool

Type: *

Type: int

Type: ryu_ldn::protocol::ExternalProxyToken

Type: int

Type: os::ConditionVariable

Type: uint32_t

Type: MasterSendCallback

Type: void *

Type: constexpr int

void P2pProxyServer(MasterSendCallback master_callback, void * user_data)

Constructor.

Constructor - initializes server state.The constructor initializes all member variables to safe defaults:

Parameters:

  • master_callback (MasterSendCallback)
  • user_data (void *)
void ~P2pProxyServer()

Destructor - stops server and cleans up.

Destructor - cleanup all resources.Ensures clean shutdown:

void P2pProxyServer(const&)

Parameters:

  • param (const&)
& operator=(const&)

Parameters:

  • param (const&)

Returns: &

bool Start(uint16_t port)

Start the TCP server.

Start the TCP server and begin accepting connections.portPort to listen on (default: auto-select from range)paramportSpecific port to bind to, or 0 for auto-select from rangeparamtrue if server started successfullyreturnTries ports 39990-39999 if port is 0notetrue if server started successfully, false on errorreturnSocket Creation Flow1::socket(AF_INET,SOCK_STREAM,0)│├─AF_INET=IPv4├─SOCK_STREAM=TCP(reliable,ordered)└─Protocol0=defaultforstream(TCP)normal2setsockopt(SO_REUSEADDR)│└─Allowbindtorecently-closedport(Importantforquickrestartaftercrash)normal3setsockopt(TCP_NODELAY)│└─DisableNagle’salgorithm(Criticalforlow-latencygametraffic)normal4bind(port)│└─Tryports39990-39999untilonesucceedsnormal5listen(backlog=8)│└─Allowupto8pendingconnectionsnormal6Createacceptthread│└─Threadloopscallingaccept()

Parameters:

  • port (uint16_t)

Returns: bool

void Stop()

Stop the server and disconnect all sessions.

Stop the server and disconnect all clients.Performs clean shutdown:Thread-safe: Can be called from any thread.

bool IsRunning()

Check if server is running.

Check if the server is currently running.true if running, false if stoppedreturn

Returns: bool

uint16_t GetPrivatePort()

Get the private (local) port.

Returns: uint16_t

uint16_t GetPublicPort()

Get the public (UPnP) port.

Returns: uint16_t

uint16_t NatPunch()

Open a public port via UPnP.

Open a public port via UPnP for NAT traversal.Attempts to open a port mapping on the router using UPnP. Tries ports 39990-39999 until one succeeds.If successful, starts a lease renewal thread.The public port number if successful, 0 if UPnP failedreturnUPnP Port Mapping FlowSwitchRouter(IGD)Internet││││SSDPDiscovery──────────►│││◄────────IGDResponse────││││││AddPortMapping──────────►│││(39990,TCP,60s)│││◄─────────────────││││││[Nowport39990onrouterforwardstous]││││││◄────TCP───────││◄──────────────────────────│(torouter:39990)││││ Try Multiple Ports?A port might be:By trying 39990-39999, we increase the chance of finding an available port.

Returns: uint16_t

void ReleaseNatPunch()

Release UPnP port mapping.

Release the UPnP port mapping and stop lease renewal.Called during server shutdown to:Important: We clean up our mappings to be a good network citizen. Abandoned mappings waste router resources and can cause issues for other applications.

void AddWaitingToken(const& token)

Add a waiting token for an expected joiner.

Called when master server notifies us someone is about to connect.tokenToken received from master serverparamToken FlowWhen a player wants to join via P2P, the master server:When the joiner connects, they send the same token in ExternalProxyConfig. We match tokens to validate the connection and assign the virtual IP. Full HandlingIf the token queue is full (MAX_WAITING_TOKENS = 16), we drop the oldest token. This handles edge cases like:

Parameters:

  • token (const&)
bool TryRegisterUser(* session, const ryu_ldn::protocol::ExternalProxyConfig & config, uint32_t remote_ip)

Try to register a connecting user.

Try to authenticate a connecting client.Called bywhen a client sends ExternalProxyConfig. Validates the token, assigns virtual IP, and adds to player list.sessionTheattempting to authenticateconfigThe ExternalProxyConfig sent by the clientremote_ipThe client’s physical IP address (network byte order)paramtrue if authentication succeeded, false if no matching token foundreturnAuthentication ProcessWait up to AUTH_WAIT_SECONDS (1 second) for a matching tokenFor each waiting token, check:If match found: IP HandlingThe master server sends all-zeros for PhysicalIP if the client has a private IP address (192.168.x.x, 10.x.x.x, etc.). This allows clients behind NAT to connect without IP validation. SafetyUses condition variable (m_token_cv) to efficiently wait for new tokens. The thread sleeps until either:

Parameters:

  • session (*)
  • config (const ryu_ldn::protocol::ExternalProxyConfig &)
  • remote_ip (uint32_t)

Returns: bool

void Configure(const& config)

Configure broadcast address from ProxyConfig.

Calculates the broadcast address for the virtual network. Formula: broadcast = IP | ~maskExample for 10.114.0.1 with /16 mask:

Parameters:

  • config (const&)
void HandleProxyData(* sender, ryu_ldn::protocol::ProxyDataHeader & header, const uint8_t * data, size_t data_len)

Handle ProxyData message from a session.

ProxyData is the main data transfer message used for UDP game traffic. Routes the data to the destination session(s) based on ProxyInfo.

Parameters:

  • sender (*)
  • header (ryu_ldn::protocol::ProxyDataHeader &)
  • data (const uint8_t *)
  • data_len (size_t)
void HandleProxyConnect(* sender, ryu_ldn::protocol::ProxyConnectRequest & request)

Handle ProxyConnect message from a session.

ProxyConnect initiates a virtual TCP connection between two players. The target responds with ProxyConnectReply (accept/reject).

Parameters:

  • sender (*)
  • request (ryu_ldn::protocol::ProxyConnectRequest &)
void HandleProxyConnectReply(* sender, ryu_ldn::protocol::ProxyConnectResponse & response)

Handle ProxyConnectReply message from a session.

Response to ProxyConnect - indicates whether the connection was accepted.

Parameters:

  • sender (*)
  • response (ryu_ldn::protocol::ProxyConnectResponse &)
void HandleProxyDisconnect(* sender, ryu_ldn::protocol::ProxyDisconnectMessage & message)

Handle ProxyDisconnect message from a session.

Notifies the target that a virtual connection has been closed.

Parameters:

  • sender (*)
  • message (ryu_ldn::protocol::ProxyDisconnectMessage &)
void OnSessionDisconnected(* session)

Called when a session disconnects.

Handles cleanup when a client disconnects:The master server notification allows it to:

Parameters:

  • session (*)
void AcceptLoop()

Accept loop thread function.

Main loop for accepting incoming TCP connections.This function runs in a dedicated thread and loops continuously:The loop exits when:Accept Behavioraccept() is a blocking call. Whencloses the listen socket, accept() returns with an error (EBADF or similar), which we detect and break out of the loop.

void RouteMessage(* sender, ryu_ldn::protocol::ProxyInfo & info, SendFunc send_func)

Route a message to appropriate session(s)

Route a proxy message to appropriate destination(s)senderThe session that sent the messageinfoProxy info with source/dest IPssend_funcFunction to call for each target sessionparamSendFuncCallable type for sending to a sessiontemplateparamsenderThe session that sent the messageinfoProxyInfo containing source and destination IPssend_funcFunction to call for each target sessionparamRouting LogicFix source IP if zero (unbound socket sends as 0.0.0.0)Reject spoofing (source IP must match sender’s virtual IP)Translate legacy broadcast (0xc0a800ff -> actual broadcast)Route to destination: NoteWe validate that the source IP matches the sender’s virtual IP. This prevents a malicious client from impersonating another player.

Parameters:

  • sender (*)
  • info (ryu_ldn::protocol::ProxyInfo &)
  • send_func (SendFunc)
void NotifyMasterDisconnect(uint32_t virtual_ip)

Notify master server of connection state change.

Notify master server of a client disconnection.Sends ExternalProxyConnectionState with Connected=false to the master server. This allows the server to update its records and notify other players.

Parameters:

  • virtual_ip (uint32_t)
void LeaseRenewalLoop()

Lease renewal thread function.

Lease renewal thread main loop.Runs continuously until m_lease_thread_running is set to false. Wakes up every PORT_LEASE_RENEW seconds (50s) to refresh the UPnP port mapping.Why 50 seconds?The lease duration is 60 seconds. By renewing at 50 seconds, we have a 10-second safety margin. If renewal fails, we have time to retry before the mapping expires.This matches Ryujinx’s timing exactly for compatibility.

void StartLeaseRenewal()

Start lease renewal background thread.

Start the UPnP lease renewal background thread.Internal helper called after successful. Creates a low-priority thread that periodically refreshes the UPnP port mapping.