Setting up a personal netplay relay server for Libretro / RetroArch

2021-02-06

(last time edited: 2021-05-02)

tags: libretro, networking, server, games, retro, emulation

Libretro API

Libretro is a simple API that allows for the creation of games and emulators. It is very simple in nature, yet very powerful. The simplicity of it all requires some explanation in order to truly grasp how useful it can be to your own projects.

Libretro is the backend API to the wonderful RetroArch cross-platform emulator frontend. You can see the differences and specifications of both software in this brochure .pdf file. I'm not gonna get into details since this guide is specific for netplay.

Libretro Netplay

Netplay is RetroArch's mechanism for emulating local multiplayer over the internet, by continuously synchronizing multiple RetroArch instances running the same emulation core and same content. Currently, this approach is only for emulating classic single-system local multiplayer, not link cable play or network multiplayer modes.

If you are a programmer you can read the source code hosted as GitHub. It's written in C. Take a look at it by click here.

Libretro Netplay is not specifically bound to RetroArch. RetroArch is just one of the many frontends that implement this networking feature, and it's the most well featured one. There are other frontends using similar netcode to Libretro's netplay such as Batocera and Fightcade. Fightcade uses GPPO, a different netcode programmed by Tony Cannon made for arcade fighting games specifically but it can be used for console emulators too. It works amazingly good just as Libretro's Netplay. Having tested both locally and remotely I must say I cannot find any difference between connections with 40ms~90ms latency. Also, RetroArch can be used to play with more than 2 players and it works great too! Games for SNES with Multitap are waiting for you!

Libretro Netplay can be a pain in the ass if you do not know how to set up everything correctly. When you host a game and someone joins (possibly your friend) the connection runs on P2P (using UDP and TCP ports), meaning that it is a direct connection. There are no servers manipulating the data between both parties. Netcode syncronization depends deeply on both connections. Latency is crucial. If one of both parties has a bad connection say goodbye to your game.

There are other factors that play an important role here. If one of both parties is behind double NAT there won't be a single chance for connection. Double NAT basically means that you are not exposed to the Internet correctly; your public IP is hidden behind another private network or router. This usually happens with ISP that for some reason don't want the client to be full control of the connection. Another reason could be misconfiguration between multiple routers.

Keep in mind. Emulators for these systems aren't suitable for netplay:

How can you troubleshoot your connection for Netplay? (No specific order.)

Deploying a personal Libretro Relay Server (MitM)

Relay is a service which relays data between two devices which are not able to connect to each other directly otherwise. This is usually due to both devices being behind a NAT and neither side being able to open a port which would be directly accessible from the internet.

A relay server listens to connected clients and bounce data from one point to another. Of course this server acts as a Man in the Middle (MitM) as we call the same to this network attack method. The relay server is just a man in the middle.

Thankfully the Libretro developers have openly published and licensed (with GPL-3.0) the relay server program. The server is written in C++. You can find it here in the GitHub repository. With this program we can host our server anywhere we want. Keep in mind our server won't be announced publicly to the RetroArch Lobby Browser. You and your partner will have to connect manually via IP and port.

Let's get going. Let's compile the program.

First install the dependencies. And install Git too if you haven't already.

git
qt5-devel
qt5-qmake

Now clone the Git repository.

$ git clone https://github.com/libretro/netplay-mitm-server

Change directory to the cloned repo.

$ cd netplay-mitm-server

Generate a Makefile using QMake.

$ qmake

Compile using Make.

$ make

Run the server.

$ ./mitm

Yes! It's that simple.

Your server will be listening on TCP and UDP 55435 by default for future connections.

Monitor your relay server

There are multiple tools and ways to check if a connection to your server is being established. Tcptrack is one of the many tools. Other tools can be: lsof, termshark, mtr, iproute2's ss, inetutils-traceroute, netstat, zmap, nmap, GNU netcat, openbsd-netcat

A simple command:

# tcptrack -i eth0 tcp port 55435

blogimg

Securing our netplay host using iptables

When you host a game it's common to see people from other places joining and spectating your game. Not only they eat bandwidth and makes the game go bad. Latency goes up and hell can break loose. It can be annoying, but that's just the typical scenario.

Things can get extremely bad is this person knows an specific exploit in your hosted emulator and starts messing your with computer. Everything is possible.

To prevent damage let's secure our system network with a firewall rule. It's easy, fast, secure. You just need to know your friend's IP address. Tell him to open this website called https://whatsmyip.com and share the IP with you.

Using iptables you can allow only certain specific IP address to be able to connect your game that is listening in port 55435.

Run this beautiful one liner command as root. Don't forget to replace the 0.0.0.0 IP with your friend's IP.

# iptables -I INPUT \! --src 0.0.0.0 -m tcp -p tcp --dport 55435 -j DROP

INPUT means incoming connections. Dport is destination port. DROP is basically reject, -m is for match and -p for port.

or as an alternative in 2 commands:

# iptables -A INPUT -p tcp --dport 55435 -s 0.0.0.0 -j ACCEPT

# iptables -A INPUT -p tcp --dport 55435 -j DROP

If you're worried you can use Telnet to test the listening port from another host.

$ telnet your_ip port_here

To double-check your current iptables rules.

# iptables --list

To remove all iptables rules.

# iptables --flush

Notice! Rules don't persists across reboots.

Creating a Void Linux pkg template for xbps-src

The Git repository doesn't offer a proper release for the server program but we can still make a package using a _githash constant. Well, variable in this case since it's shell language.

The template dating to the 30th December of 2019 should look like this:

# Template file for 'netplay-mitm-server'
pkgname=netplay-mitm-server
version=0.0.0.20191230
revision=2
_githash="aa8eca67f755ac26493ddcf99c10e62216aca35e"
wrksrc="${pkgname}-${_githash}"
build_style="qmake"
makedepends="qt5-devel qt5-qmake"
short_desc="Relay server for Libretro netplay"
maintainer="me <me@me.com>"
license="GPL-3.0-or-later"
homepage="https://github.com/libretro/netplay-mitm-server"
distfiles="https://github.com/libretro/netplay-mitm-server/archive/${_githash}.tar.gz"
checksum="edc86055172b3f50c566250b97f473c2acf922bee8c9a6a252e6624b4c19fe48"

do_install() {
    vbin mitm netplay-mitm-server
}

If you are familiar with Void Linux xbps-src templates you should know the simple commands to compile, build and install. There is a guide I wrote on how to compile a tabletop online game using xbps-src with all the steps detailed. Click here to read it.

Running RetroArch's Libretro NetPlay via CLI

Load a core and a ROM for homely basic gameplay.

If your Linux distribution does NOT package RetroArch and cores separately in system directories, you must look in the ~/.config/retroarch/cores directory for downloaded cores.

$ retroarch -L /path/to/core.so /path/to/game.rom

For NetPlay as host.

$ retroarch -L /path/to/core.so /path/to/game.rom -H --nick your_username

For NetPlay as client.

$ retroarch -L /path/to/core.so /path/to/game.rom -C 152.43.123.xx --nick peperino

These -L arguments can be used to host games with custom cores too.

There is no need to add port unless the default 55435 has been changed by the host.

If you need to get more info output about errors add the -v argument.

Libretro cores

Emulators (cores) differ completely from each other. They are developed by different people, with different features, different programming languages, etc.

If you wanna look for an extensive documentation on each emulator click here.

These are the most stable emulators I prefer using. These cores filenames end in .so because they are Shared Object files.

Other good standalone Libretro cores: Final Burn Neo to play CPS-2 games and other Capcom arcades.

Cool lightweight emulators: QuickNES (NES), gpSP (GB, GBC), TGB Dual (GBA), SMS Plus GX (MS/GG), PicoDrive (MS/MD/CD/32X)

For more info of each Libretro core, look for each file ending in .info inside /path/to/retroarch/.config/cores directory. Show features, description, BIOS info, etc.

Input configuration

The RetroPad is a joypad abstraction interface defined by the Libretro API. It is the primary input device for a libretro frontend. Unless a core absolutely requires the use of a keyboard with no possible fallback for gamepad-type controls, a Libretro core should always be implemented as such that it is directly controllable by the RetroPad. For more information look at this documentation.

RetroPad is an implementation / standard that is implemented in Libretro. This specification serves as an abstraction to remap all controllers.

You must always remember to configure your controller first in: Settings -> Input -> Port X.

And then remap for every core when you're in-game: Press F1 and go to Main Menu -> Quick Menu -> Controls.

BIOS files for PCSX ReARMed

Filename Description md5sum
scph101.bin Version 4.4 03/24/00 A 6E3735FF4C7DC899EE98981385F6F3D0
scph7001.bin Version 4.1 12/16/97 A 1e68c231d0896b7eadcad1d7d8e76129
scph5501.bin Version 3.0 11/18/96 A 490f666e1afb15b7362b406ed1cea246
scph1001.bin Version 2.0 05/07/95 A dc2b9bf8da62ec93e868cfd29f0d067d