QEMU GameZIP Server
The server allows accessing zipped game contents, also known as GameZIPs, as well as merged htdocs. This page aims to cover the details of the Flashpoint implementation.
Glossary
- GameZIP: A zipped curation content folder, according to the GameZIP specification.
- merged htdocs: The root folder where web content is served from, contains matching file structure for hostnames used by games in Flashpoint.
- FUSE: Filesystem in Userspace
- union mount: A union mount is a mount which can appear to merge the contents of several directories, while keeping their physical content separate. [1]
Introduction
In the past, Flashpoint's server was an Apache httpd installation running on Windows. The GameZIP implementation still uses Apache but it runs on Alpine Linux instead. This allows the use of FUSE file systems to achieve a simulated view of "merged htdocs" without the extraction of GameZIPs. This instance of Alpine Linux is emulated under QEMU. QEMU was chosen because it requires no driver installation or special privileges and Alpine Linux because of its low file size and overhead. The Linux guest cannot directly access files on the host file system, so an FTP server runs on the host to share needed files.
Why emulate Linux?
For our purposes, Apache is limited to a single web root and cannot serve files from ZIPs. Custom file systems require custom Windows drivers and are less mature or performant than FUSE. In addition, the use of Linux allows for the use of the entire GNU/Linux toolkit which is very flexible. It also provides a security advantage, as it sandboxes potentially untrusted PHP scripts.
How does it work?
The Apache installation has a single web root, found at /var/www/localhost/htdocs
.
This path is the target of a union mount, which merges the following paths:
- /root/base: Contains the PHP scripts required for mounting game ZIPs and the
.htaccess
that rewrites the HTTP Host header into a subfolder. - /tmp/htdocs: (Initially unmounted) Contains the contents of the existing merged htdocs, for non-GameZIP games.
- /tmp/_
[game]
.zip: (Initially unmounted) Contains the contents of a single GameZIP.
When the emulated Alpine Linux instance starts, only /root/base
is part of the union.
Mount API
The scripts found in /root/base
make up the API used for controlling the union mount.
This endpoint must receive a request at least once before games in the old htdocs folder can be played. The launcher should send a request to it on startup.
This performs the following actions:
1. Mounts Server\htdocs
from Flashpoint into /mnt/htdocs
via FTP (using curlftpfs)
2. Mounts Games
from Flashpoint into /mnt/games
via FTP (using curlftpfs)
3. Mounts /mnt/htdocs
into /tmp/htdocs
as a case-insensitive mirror (using fuzzyfs)
4. Adds /tmp/htdocs
to the union mount.
- [GET]
http://127.0.0.1:22500/mount.php?file=[filename]
This endpoint allows mounting a game ZIP file into the virtual htdocs. The specified file must be located in the Games folder under the Flashpoint directory. It has a few possible outcomes which it will print in plain text:
“OK” (200): The file was mounted successfully. “ALREADY_MOUNTED” (200): The file was already previously mounted and remains available. “NO_SUCH_FILE” (400): The specified file was not found under the Games folder. “NO_CONTENT_FOLDER” (400): The specified file was not mounted because it did not contain a content folder. “BAD_ZIP” (400): The specified file was not mounted because it was not a valid ZIP file.
This performs the following actions:
1. If wake.php
has not run yet. It will run first.
2. Mounts /mnt/games/[filename]
to /tmp/[filename]
as a ZIP file (using fuse-zip)
3. Mounts /tmp/[filename]
to /tmp/_[filename]
as a case-insensitive mirror (using fuzzyfs)
4. Adds /tmp/_[filename]
to the union mount.
Shell access
Open Data\services.json
with a text editor. Remove "-display", "none"
from the arguments array in Apache Webserver and save.
The next time you run Flashpoint, you'll get a terminal to Alpine Linux. The root user has a blank password.
Press Ctrl+C to terminate the tail command, this is used to pipe the contents of the Apache access log to the Flashpoint Launcher.
To avoid the Linux boot time when starting the launcher, a QEMU savestate is used.
- Press Ctrl+Alt+2 to access the QEMU console. Type
loadvm quick
to reset the state of the machine. - Press Ctrl+Alt+1 to go back to return to the Alpine Linux shell.