Skip to content

Commit

Permalink
De-static GPGNetServer
Browse files Browse the repository at this point in the history
  • Loading branch information
Brutus5000 committed Dec 9, 2024
1 parent dbad122 commit c67dff3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ public interface FafRpcCallbacks {
void onDisconnectFromPeer(int remotePlayerId);

void close();

void sendToGpgNet(String header, Object... args);
}
46 changes: 18 additions & 28 deletions ice-adapter/src/main/java/com/faforever/iceadapter/IceAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class IceAdapter implements Callable<Integer>, AutoCloseable, FafRpcCallb
@CommandLine.ArgGroup(exclusive = false)
private IceOptions iceOptions;

private GPGNetServer gpgNetServer;

private final ExecutorService executor = ExecutorHolder.getExecutor();
private static final Lock lockGameSession = new ReentrantLock();

Expand Down Expand Up @@ -58,7 +60,8 @@ public void start() {
TrayIcon.create();

PeerIceModule.setForceRelay(iceOptions.isForceRelay());
GPGNetServer.init(iceOptions.getGpgnetPort(), iceOptions.getLobbyPort());
gpgNetServer = new GPGNetServer();
gpgNetServer.init(iceOptions.getGpgnetPort(), iceOptions.getLobbyPort());
RPCService.init(iceOptions.getRpcPort(), this);

debug().startupComplete();
Expand All @@ -68,12 +71,7 @@ public void start() {
public void onHostGame(String mapName) {
log.info("onHostGame");
createGameSession();

GPGNetServer.clientFuture.thenAccept(gpgNetClient -> {
gpgNetClient.getLobbyFuture().thenRun(() -> {
gpgNetClient.sendGpgnetMessage("HostGame", mapName);
});
});
sendToGpgNet("HostGame", mapName);
}

@Override
Expand All @@ -82,43 +80,31 @@ public void onJoinGame(String remotePlayerLogin, int remotePlayerId) {
createGameSession();
int port = GAME_SESSION.connectToPeer(remotePlayerLogin, remotePlayerId, false, 0);

GPGNetServer.clientFuture.thenAccept(gpgNetClient -> {
gpgNetClient.getLobbyFuture().thenRun(() -> {
gpgNetClient.sendGpgnetMessage("JoinGame", "127.0.0.1:" + port, remotePlayerLogin, remotePlayerId);
});
});
sendToGpgNet("JoinGame", "127.0.0.1:" + port, remotePlayerLogin, remotePlayerId);
}

@Override
public void onConnectToPeer(String remotePlayerLogin, int remotePlayerId, boolean offer) {
if (GPGNetServer.isConnected()
&& GPGNetServer.getGameState().isPresent()
&& (GPGNetServer.getGameState().get() == GameState.LAUNCHING
if (gpgNetServer.isConnected()
&& gpgNetServer.getGameState().isPresent()
&& (gpgNetServer.getGameState().get() == GameState.LAUNCHING
|| GPGNetServer.getGameState().get() == GameState.ENDED)) {
log.warn("Game ended or in progress, ABORTING connectToPeer");
return;
}

log.info("onConnectToPeer {} {}, offer: {}", remotePlayerId, remotePlayerLogin, String.valueOf(offer));
log.info("onConnectToPeer {} {}, offer: {}", remotePlayerId, remotePlayerLogin, offer);
int port = GAME_SESSION.connectToPeer(remotePlayerLogin, remotePlayerId, offer, 0);

GPGNetServer.clientFuture.thenAccept(gpgNetClient -> {
gpgNetClient.getLobbyFuture().thenRun(() -> {
gpgNetClient.sendGpgnetMessage("ConnectToPeer", "127.0.0.1:" + port, remotePlayerLogin, remotePlayerId);
});
});
sendToGpgNet("ConnectToPeer", "127.0.0.1:" + port, remotePlayerLogin, remotePlayerId);
}

@Override
public void onDisconnectFromPeer(int remotePlayerId) {
log.info("onDisconnectFromPeer {}", remotePlayerId);
GAME_SESSION.disconnectFromPeer(remotePlayerId);

GPGNetServer.clientFuture.thenAccept(gpgNetClient -> {
gpgNetClient.getLobbyFuture().thenRun(() -> {
gpgNetClient.sendGpgnetMessage("DisconnectFromPeer", remotePlayerId);
});
});
sendToGpgNet("DisconnectFromPeer", remotePlayerId);
}

private static void createGameSession() {
Expand Down Expand Up @@ -159,18 +145,22 @@ public static void close(int status) {
log.info("close() - stopping the adapter. Status: {}", status);

onFAShutdown(); // will close gameSession aswell
GPGNetServer.close();
INSTANCE.gpgNetServer.close();
RPCService.close();
Debug.close();
TrayIcon.close();
INSTANCE.close();

INSTANCE.executor.shutdown();
CompletableFuture.runAsync(
INSTANCE.executor::shutdownNow, CompletableFuture.delayedExecutor(250, TimeUnit.MILLISECONDS))
.thenRunAsync(() -> System.exit(status), CompletableFuture.delayedExecutor(250, TimeUnit.MILLISECONDS));
}

@Override
public void sendToGpgNet(String header, Object... args) {
gpgNetServer.sendToGpgNet(header, args);
}

public static int getId() {
return INSTANCE.iceOptions.getId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,69 @@
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class GPGNetServer {
private static int GPGNET_PORT;
private static int LOBBY_PORT;
private static final Lock lockSocket = new ReentrantLock();
private static ServerSocket serverSocket;
private static volatile GPGNetClient currentClient;
public class GPGNetServer implements AutoCloseable {
private static GPGNetServer INSTANCE;

private final Lock lockSocket = new ReentrantLock();

private int gpgnetPort;
private int lobbyPort;
private ServerSocket serverSocket;
private volatile GPGNetClient currentClient;

// Used by other services to get a callback on FA connecting
public static volatile CompletableFuture<GPGNetClient> clientFuture = new CompletableFuture<>();
private volatile CompletableFuture<GPGNetClient> clientFuture = new CompletableFuture<>();

public void sendToGpgNet(String header, Object... args) {
clientFuture.thenAccept(gpgNetClient ->
gpgNetClient.getLobbyFuture().thenRun(() -> gpgNetClient.sendGpgnetMessage(header, args)));
}

private volatile LobbyInitMode lobbyInitMode = LobbyInitMode.NORMAL;

public static LobbyInitMode getLobbyInitMode() {
return INSTANCE.lobbyInitMode;
}

public static void setLobbyInitMode(LobbyInitMode mode) {
INSTANCE.lobbyInitMode = mode;
}

public static volatile LobbyInitMode lobbyInitMode = LobbyInitMode.NORMAL;
public void init(int gpgnetPort, int lobbyPort) {
INSTANCE = this;

public static void init(int gpgnetPort, int lobbyPort) {
if (gpgnetPort == 0) {
GPGNET_PORT = NetworkToolbox.findFreeTCPPort(20000, 65536);
log.info("Generated GPGNET_PORT: {}", GPGNET_PORT);
this.gpgnetPort = NetworkToolbox.findFreeTCPPort(20000, 65536);
log.info("Generated GPGNET_PORT: {}", this.gpgnetPort);
} else {
GPGNET_PORT = gpgnetPort;
log.info("Using GPGNET_PORT: {}", GPGNET_PORT);
this.gpgnetPort = gpgnetPort;
log.info("Using GPGNET_PORT: {}", this.gpgnetPort);
}

if (lobbyPort == 0) {
LOBBY_PORT = NetworkToolbox.findFreeUDPPort(20000, 65536);
log.info("Generated LOBBY_PORT: {}", LOBBY_PORT);
this.lobbyPort = NetworkToolbox.findFreeUDPPort(20000, 65536);
log.info("Generated LOBBY_PORT: {}", this.lobbyPort);
} else {
LOBBY_PORT = lobbyPort;
log.info("Using LOBBY_PORT: {}", LOBBY_PORT);
this.lobbyPort = lobbyPort;
log.info("Using LOBBY_PORT: {}", this.lobbyPort);
}

try {
serverSocket = new ServerSocket(GPGNET_PORT);
try (ServerSocket Socket = new ServerSocket(gpgnetPort)) {
this.serverSocket = Socket;
} catch (IOException e) {
log.error("Couldn't start GPGNetServer", e);
IceAdapter.close(-1);
}

CompletableFuture.runAsync(GPGNetServer::acceptThread, IceAdapter.getExecutor());
CompletableFuture.runAsync(this::acceptThread, IceAdapter.getExecutor());
log.info("GPGNetServer started");
}

/**
* Represents a client (a game instance) connected to this GPGNetServer
*/
@Getter
public static class GPGNetClient {
public class GPGNetClient {
private volatile GameState gameState = GameState.NONE;

private final Socket socket;
Expand Down Expand Up @@ -144,7 +162,7 @@ public void sendGpgnetMessage(String command, Object... args) {
Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" ")));
} catch (IOException e) {
log.error("Error while communicating with FA (output), assuming shutdown", e);
GPGNetServer.onGpgnetConnectionLost();
GPGNetServer.this.onGpgnetConnectionLost();
}
});
}
Expand All @@ -160,21 +178,21 @@ private void listenerThread() {
try (var inputStream = socket.getInputStream();
var gpgnetIn = new FaDataInputStream(inputStream)) {
while (!Thread.currentThread().isInterrupted()
&& (!triggerActive || GPGNetServer.currentClient == this)
&& (!triggerActive || currentClient == this)
&& !stopping) {
String command = gpgnetIn.readString();
List<Object> args = gpgnetIn.readChunks();

processGpgnetMessage(command, args);

if (!triggerActive && GPGNetServer.currentClient != null) {
if (!triggerActive && currentClient != null) {
triggerActive =
true; // From now on we will check GPGNetServer.currentClient to see if we should stop
}
}
} catch (IOException e) {
log.error("Error while communicating with FA (input), assuming shutdown", e);
GPGNetServer.onGpgnetConnectionLost();
GPGNetServer.this.onGpgnetConnectionLost();
}
log.debug("No longer listening for GPGPNET from FA");
}
Expand All @@ -198,7 +216,7 @@ public void close() {
* or on receiving an incoming connection request while still connected to a different instance.
* THIS TRIGGERS A DISCONNECT FROM ALL PEERS AND AN ICE SHUTDOWN.
*/
private static void onGpgnetConnectionLost() {
private void onGpgnetConnectionLost() {
log.info("GPGNet connection lost");
LockUtil.executeWithLock(lockSocket, () -> {
if (currentClient != null) {
Expand All @@ -220,7 +238,7 @@ private static void onGpgnetConnectionLost() {
/**
* Listens for incoming connections from a game instance
*/
private static void acceptThread() {
private void acceptThread() {
while (!Thread.currentThread().isInterrupted()) {
log.info("Listening for incoming connections from game");
try (Socket socket = serverSocket.accept()) {
Expand Down Expand Up @@ -250,29 +268,29 @@ private static void acceptThread() {
* @return whether the game is connected via GPGNET
*/
public static boolean isConnected() {
return currentClient != null;
return INSTANCE.currentClient != null;
}

public static String getGameStateString() {
return getGameState().map(GameState::getName).orElse("");
}

public static Optional<GameState> getGameState() {
return Optional.ofNullable(currentClient).map(GPGNetClient::getGameState);
return Optional.ofNullable(INSTANCE.currentClient).map(GPGNetClient::getGameState);
}

public static int getGpgnetPort() {
return GPGNET_PORT;
return INSTANCE.gpgnetPort;
}

public static int getLobbyPort() {
return LOBBY_PORT;
return INSTANCE.lobbyPort;
}

/**
* Stops the GPGNetServer and thereby the connection to a currently connected client
*/
public static void close() {
public void close() {
if (currentClient != null) {
currentClient.close();
currentClient = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void disconnectFromPeer(long remotePlayerId) {
}

public void setLobbyInitMode(String lobbyInitMode) {
GPGNetServer.lobbyInitMode = LobbyInitMode.getByName(lobbyInitMode);
GPGNetServer.setLobbyInitMode(LobbyInitMode.getByName(lobbyInitMode));
log.debug("LobbyInitMode set to {}", lobbyInitMode);
}

Expand Down Expand Up @@ -83,12 +83,8 @@ public void iceMsg(long remotePlayerId, Object msg) {
log.info("IceMsg received {}", msg);
}

public void sendToGpgNet(String header, String... chunks) {
GPGNetServer.clientFuture.thenAccept(gpgNetClient -> {
gpgNetClient.getLobbyFuture().thenRun(() -> {
gpgNetClient.sendGpgnetMessage(header, chunks);
});
});
public void sendToGpgNet(String header, Object... args) {
callbacks.sendToGpgNet(header, args);
}

public void setIceServers(List<Map<String, Object>> iceServers) {
Expand Down Expand Up @@ -160,7 +156,7 @@ public String status() {
+ s.getStunAddresses().size())
.sum(),
GPGNetServer.getLobbyPort(),
GPGNetServer.lobbyInitMode.getName(),
GPGNetServer.getLobbyInitMode().getName(),
new IceStatus.IceOptions(
IceAdapter.getId(), IceAdapter.getLogin(), rpcPort, GPGNetServer.getGpgnetPort()),
gpgpnet,
Expand Down

0 comments on commit c67dff3

Please sign in to comment.