Skip to main content

Connection matchmaking

Peer to peer connections, when it comes to multiplayer games is a complex topic. Pretty much all internet users, however typically are behind NAT firewall, which makes it impractical for most users, as games cannot expect users to open their ports into internet just to have a gameplayer.

[Spectrum A] <-> Router NAT <-> Internet <-> Router NAT <-> [Spectrum B]

On the example above, it is not practical to assume that direct connection can be established, unless one of them opens a port and exposes its IP to the other one, which has its own set of issues.

Spectranext provides a special matchmaking process, that lets two devices connect their programs automatically. It works for games, chat, file exchange, and other software that connects two peers.

Blue matchmaking menu for tank, showing your name Alex and peer Mira on row 1, with Code access and keyboard controls at the bottom.

From user/program perspective, socket API is not changed, it is just that programs tries to connecto to chess@match.spx hostname that is special. Under the hood, however, that prompts a system menu that resolves the connection channel. By the end of the connection, connect() already has had resolved to a working channel to remote machine.

You do not need to implement a browser, joining mechanism, address exchange, or port-forwarding instructions. The system supplies those parts. The public matchmaking service is provided by Spectranext; using it does not require deploying your own backend.

Local testing needs different public IPs

The default public matchmaking setup does not support localhost connections. Test with endpoints on different public IP addresses, rather than two instances on the same PC or two PCs sharing a router. Connections through the same public IP depend on NAT hairpinning and may fail.

For example, connect one test PC to a VPN while leaving the other on its normal connection. Make sure the VPN changes that PC's public IP and allows direct UDP traffic; a VPN alone does not guarantee connectivity.

The user experience​

Opening the menu makes the device visible and shows other people running the same service. Either person can choose the other; the second person can simply wait.

  • 1–9: connect to the peer on that row.
  • N: change your name. Leave it blank to use the device serial.
  • C: turn the joining-code requirement on or off. The system generates and displays the code.
  • Enter: leave the main menu and return to the application.

The list refreshes automatically. There are no accounts to create. If a peer requires a code, selecting them opens this prompt:

Joining-code screen: Your name Alex, Peer Mira, a blank row before This peer requires a code, another blank row before Code, and Enter instructions at the bottom.

Enter the code to connect, or leave it blank and press Enter to go back.

Add it to your application​

Both programs follow the same steps:

  1. Resolve your service hostname, such as chess.v1@match.spx.
  2. Open a socket and call connect() with the returned address.
  3. On success, exchange data as usual and close the socket when finished.

connect() blocks while the system handles the menu and connection setup, then restores your application's screen. Neither application needs bind(), listen(), or accept(). You can agree on player roles or other application roles after connecting.

Firmware and connection information​

Require Spectranext firmware 1.2 or newer and an up-to-date SDK. Read the firmware version with spectranext_get_version(); keep that existing call for compatibility checks. Early 1.2 beta builds may predate the string metadata extension; handle an unavailable string gracefully.

After connecting, one bounded getter exposes connection information:

#include <spectranext.h>

char value[65];
if (spectranext_get_string(SPECTRANEXT_STRING_MATCH_PEER_NAME,
value, sizeof(value)) == 0) {
printf("Connected to %s\n", value);
}

The same call reads your serial, firmware version, matchmaking display name, peer serial, and the serial of whoever initiated the match. The initiator is agreed by the service, even when both users select each other at once; it is independent of the TCP role. Compare it with your serial to assign application roles automatically. Treat an unavailable initiator as a reason to negotiate roles through your application protocol.

See controller interaction and string IDs for the complete interface, including how to implement your own matchmaking menu. The peer-to-peer chat example shows the connected peer's name, serial, and match initiator.

For two devices on the same network, use your application's DIRECT mode with the destination's LAN IP. Matchmaking currently exchanges public endpoints; it has neither LAN candidate discovery nor a relay fallback.

TCP example​

Using the Spectranext SDK's libsocket interface:

#include <string.h>
#include <sys/socket.h>
#include <netdb.h>

/* Returns a connected socket, or -1 if cancelled or unsuccessful. */
int connect_peer(void)
{
struct hostent *host;
struct sockaddr_in peer;
int fd;

host = gethostbyname("chess.v1@match.spx");
if (!host)
return -1;

memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_addr.s_addr = host->h_addr;
peer.sin_port = 0; /* Matchmaking ignores the application port. */

fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
return -1;

/* Blocks while the system menu is open and the peer connects. */
if (connect(fd, &peer, sizeof(peer)) < 0) {
sockclose(fd);
return -1;
}

return fd;
}

Use the returned descriptor with send(), recv(), and the socket polling API. Handle partial reads and writes and provide your own message framing, as with any TCP stream.

If the user cancels or setup fails, connect() returns an error. Close the socket; to retry, resolve the hostname again and open a fresh socket. The menu displays the failure reason.

Matchmaking failure screen showing Connection failed, Peer UDP unreachable, and Enter to return to program at the bottom.

Choose your service name​

The part before @match.spx groups compatible applications. For example:

chess.v1@match.spx
myapp.chat.v2@match.spx

Choose a name specific to your application, and include a version when releases have incompatible protocols. You do not need to register a domain. Only peers using the same service and socket transport appear together.

Using UDP​

Open SOCK_DGRAM instead of SOCK_STREAM and use the same lookup and connect() flow. After connecting, use the SDK's sendto() and recvfrom(), retaining the lookup's destination structure. Datagram boundaries are preserved; your application handles packet loss, duplication, and reordering.

Details and current limits​

How the magic works​

The system uses STUN to discover a UDP endpoint, exchanges it through the matchmaking service, and attempts a direct path between the devices. Application traffic then travels directly between them.

Matchmade TCP is TCP over IP over GRE over UDP, rather than a plain TCP connection to a public server. Your application still gets a reliable, ordered byte stream. Since both endpoints run the same compatible application through matchmaking, this encapsulation needs no changes to your application protocol. An ordinary TCP server cannot accept the tunnel as a normal TCP connection.

See STUN and connection setup for the sequence and transport details. The system calls the matchmaking HTTP API automatically; ordinary SDK applications do not need it.

Developer reference​

DetailCurrent behavior
Service name1–32 lowercase letters, digits, ., _, or -, followed by @match.spx.
Address lookupResolve immediately before connecting. One pending service and one active match per device.
Application portIgnored for matchmaking; the hostname selects the service.
SDK addresshostent.h_addr is an IPv4 value, which is why the example assigns it directly.
Peer listUp to nine rows; refreshes about one second after the previous refresh completes.
Text inputBlocks list refreshes until input finishes.
UDP datagramsMaximum 1200 bytes, including support for empty datagrams. A short receive buffer discards the remainder.

Requirements​

  • Requires matchmaking-capable Spectranext firmware 1.2; classic Spectranet hardware is not supported.
  • Both devices need access to the service and a working direct UDP path, even for TCP applications. Some routers, firewalls, and VPNs prevent this. There is currently no relay fallback.
  • Discovery covers people currently in the menu. Scheduling, reminders, hosted-server destinations, and multiple concurrent matches are not implemented.
  • Display names and joining codes are not authenticated identities or encryption. Applications requiring either must supply their own protocol.