Skip to content

Commit

Permalink
Refactor: Delegate connection details
Browse files Browse the repository at this point in the history
  • Loading branch information
Bytekeeper committed Oct 2, 2020
1 parent 179fb2d commit 4ee6c22
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 145 deletions.
182 changes: 37 additions & 145 deletions src/main/java/bwapi/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,59 +28,31 @@ of this software and associated documentation files (the "Software"), to deal
import bwapi.ClientData.Command;
import bwapi.ClientData.GameData;
import bwapi.ClientData.Shape;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.linux.Fcntl;
import com.sun.jna.platform.linux.LibC;
import com.sun.jna.platform.linux.LibRT;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.win32.W32APIOptions;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import static com.sun.jna.platform.linux.Mman.*;
import java.nio.ByteBuffer;

class Client {
interface MappingKernel extends Kernel32 {
MappingKernel INSTANCE = Native.load(MappingKernel.class, W32APIOptions.DEFAULT_OPTIONS);

HANDLE OpenFileMapping(int desiredAccess, boolean inherit, String name);
}

interface LibCExt extends LibC {
LibCExt INSTANCE = Native.load(LibCExt.class);

Pointer mmap(Pointer addr, int length, int prot, int flags, int fd, int offset) throws LastErrorException;
}

public interface EventHandler {
void operation(ClientData.Event event);
}

private static final int READ_WRITE = 0x1 | 0x2 | 0x4;

private static final int SUPPORTED_BWAPI_VERSION = 10003;
static final int MAX_COUNT = 19999;
static final int MAX_STRING_SIZE = 1024;

private ClientData clientData;
private ClientData.GameData gameData;
private boolean connected = false;
private RandomAccessFile pipeObjectHandle = null;
private AFUNIXSocket syncSocket = null;
private ByteBuffer mapFileHandle = null;
private ByteBuffer gameTableFileHandle = null;
private ByteBuffer mapShm = null;
private ByteBuffer gameTableShm = null;
private final ClientConnection clientConnector;

private boolean debugConnection = false;

Client(boolean debugConnection) {
this.debugConnection = debugConnection;
boolean windowsOs = System.getProperty("os.name").toLowerCase().contains("win");
clientConnector = windowsOs ? new ClientConnectionW32() : new ClientConnectionPosix();
}

/**
Expand All @@ -89,6 +61,7 @@ public interface EventHandler {
Client(ByteBuffer buffer) {
clientData = new ClientData(buffer);
gameData = clientData.new GameData(0);
clientConnector = null;
}

ClientData clientData() {
Expand Down Expand Up @@ -117,27 +90,9 @@ void disconnect() {
if (!connected) {
return;
}

if (pipeObjectHandle != null) {
try {
pipeObjectHandle.close();
} catch (Exception e) {
e.printStackTrace();
}
pipeObjectHandle = null;
}

if (syncSocket != null) {
try {
syncSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
syncSocket = null;
}

mapFileHandle = null;
gameTableFileHandle = null;
clientConnector.disconnect();
mapShm = null;
gameTableShm = null;
gameData = null;
connected = false;
}
Expand All @@ -152,17 +107,7 @@ boolean connect() {
int gameTableIndex = -1;

try {
try {
gameTableFileHandle = Kernel32.INSTANCE.MapViewOfFile(
MappingKernel.INSTANCE.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE, 0, 0, GameTable.SIZE)
.getByteBuffer(0, GameTable.SIZE);
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
int fd = LibRT.INSTANCE.shm_open("/bwapi_shared_memory_game_list", Fcntl.O_RDWR, 0);
if (fd < 0) throw new IllegalStateException("SHM not found");
gameTableFileHandle = LibCExt.INSTANCE.mmap(Pointer.NULL, GameTable.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
.getByteBuffer(0, GameTable.SIZE);
gameTableFileHandle.order(ByteOrder.LITTLE_ENDIAN);
}
gameTableShm = clientConnector.getGameTable();
}
catch (Exception e) {
System.err.println("Game table mapping not found.");
Expand All @@ -171,7 +116,7 @@ boolean connect() {

GameTable gameTable;
try {
gameTable = new GameTable(gameTableFileHandle);
gameTable = new GameTable(this.gameTableShm);
}
catch (Exception e) {
System.err.println("Unable to map Game table.");
Expand Down Expand Up @@ -202,28 +147,19 @@ boolean connect() {
return false;
}

String sharedMemoryName = "Local\\bwapi_shared_memory_" + serverProcID;
try {
try {
mapFileHandle = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
.OpenFileMapping(READ_WRITE, false, sharedMemoryName), READ_WRITE,
0, 0, GameData.SIZE).getByteBuffer(0, GameData.SIZE);
} catch (NoClassDefFoundError e) {
sharedMemoryName = "/bwapi_shared_memory_" + serverProcID;
mapFileHandle = LibCExt.INSTANCE.mmap(Pointer.NULL, GameData.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, LibRT.INSTANCE.shm_open(sharedMemoryName, Fcntl.O_RDWR, 0),
0).getByteBuffer(0, GameData.SIZE);
}
mapShm = clientConnector.getSharedMemory(serverProcID);
}
catch (Exception e) {
System.err.println("Unable to open shared memory mapping: " + sharedMemoryName);
System.err.println("Unable to open shared memory mapping: " + e.getMessage());
if (debugConnection) {
e.printStackTrace();
}
gameTableFileHandle = null;
this.gameTableShm = null;
return false;
}
try {
clientData = new ClientData(mapFileHandle);
clientData = new ClientData(mapShm);
gameData = clientData.new GameData(0);
} catch (Exception e) {
System.err.println("Unable to map game data.");
Expand All @@ -233,23 +169,15 @@ boolean connect() {
return false;
}

final String communicationPipe = "\\\\.\\pipe\\bwapi_pipe_" + serverProcID;
final String communicationSocket = "/tmp/bwapi_socket_" + serverProcID;

try {
if (new File(communicationPipe).exists()) {
pipeObjectHandle = new RandomAccessFile(communicationPipe, "rw");
} else {
syncSocket = AFUNIXSocket.newInstance();
syncSocket.connect(new AFUNIXSocketAddress(new File(communicationSocket)));
}
clientConnector.connectSharedLock(serverProcID);
} catch (Exception e) {
System.err.println("Unable to open communications pipe or socket: " + communicationPipe + " resp. " + communicationSocket);
System.err.println(e.getMessage());
if (debugConnection) {
e.printStackTrace();
}
gameTableFileHandle = null;
pipeObjectHandle = null;
syncSocket = null;
this.gameTableShm = null;
return false;
}
System.out.println("Connected");
Expand All @@ -263,20 +191,14 @@ boolean connect() {
return false;
}

if (pipeObjectHandle != null) {
byte code = 1;
while (code != 2) {
try {
code = pipeObjectHandle.readByte();
} catch (Exception e) {
System.err.println("Unable to read pipe object.");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return false;
}
try {
clientConnector.waitForServerReady();
} catch (Exception e) {
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return false;
}

System.out.println("Connection successful");
Expand All @@ -285,58 +207,27 @@ boolean connect() {
}

void update(final EventHandler handler) {
if (pipeObjectHandle != null) {
byte code = 1;
try {
pipeObjectHandle.writeByte(code);
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return;
}
while (code != 2) {
try {
code = pipeObjectHandle.readByte();
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return;
}
}
}
if (syncSocket != null) {
int code = 1;
while (code != 2) {
try {
code = syncSocket.getInputStream().read();
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return;
}
try {
clientConnector.waitForServerData();
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return;
}
for (int i = 0; i < gameData.getEventCount(); i++) {
handler.operation(gameData.getEvents(i));
}
try {
syncSocket.getOutputStream().write(1);
clientConnector.submitClientData();
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (debugConnection) {
e.printStackTrace();
}
disconnect();
return;
}
}

Expand Down Expand Up @@ -392,6 +283,7 @@ private void sleep(final int millis) {
Thread.sleep(millis);
}
catch (Exception ignored) {
// Not relevant
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/bwapi/ClientConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bwapi;

import java.io.IOException;
import java.nio.ByteBuffer;

interface ClientConnection {
void disconnect();

ByteBuffer getGameTable();

ByteBuffer getSharedMemory(int serverProcID);

void connectSharedLock(int serverProcID) throws Exception;

void waitForServerReady() throws IOException;

void waitForServerData() throws Exception;

void submitClientData() throws IOException;
}

class SharedMemoryConnectionError extends RuntimeException {
public SharedMemoryConnectionError(String message, Throwable cause) {
super(message, cause);
}
}

class SharedLockConnectionError extends RuntimeException {
public SharedLockConnectionError(String message, Throwable cause) {
super(message, cause);
}
}
Loading

0 comments on commit 4ee6c22

Please sign in to comment.