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.
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.
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:
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:
- Resolve your service hostname, such as
chess.v1@match.spx. - Open a socket and call
connect()with the returned address. - 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.
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
| Detail | Current behavior |
|---|---|
| Service name | 1–32 lowercase letters, digits, ., _, or -, followed by @match.spx. |
| Address lookup | Resolve immediately before connecting. One pending service and one active match per device. |
| Application port | Ignored for matchmaking; the hostname selects the service. |
| SDK address | hostent.h_addr is an IPv4 value, which is why the example assigns it directly. |
| Peer list | Up to nine rows; refreshes about one second after the previous refresh completes. |
| Text input | Blocks list refreshes until input finishes. |
| UDP datagrams | Maximum 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.