Skip to content

Commit 4ee6c22

Browse files
author
Bytekeeper
committed
Refactor: Delegate connection details
1 parent 179fb2d commit 4ee6c22

File tree

4 files changed

+250
-145
lines changed

4 files changed

+250
-145
lines changed

src/main/java/bwapi/Client.java

Lines changed: 37 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -28,59 +28,31 @@ of this software and associated documentation files (the "Software"), to deal
2828
import bwapi.ClientData.Command;
2929
import bwapi.ClientData.GameData;
3030
import bwapi.ClientData.Shape;
31-
import com.sun.jna.LastErrorException;
32-
import com.sun.jna.Native;
33-
import com.sun.jna.Pointer;
34-
import com.sun.jna.platform.linux.Fcntl;
35-
import com.sun.jna.platform.linux.LibC;
36-
import com.sun.jna.platform.linux.LibRT;
37-
import com.sun.jna.platform.win32.Kernel32;
38-
import com.sun.jna.win32.W32APIOptions;
39-
import org.newsclub.net.unix.AFUNIXSocket;
40-
import org.newsclub.net.unix.AFUNIXSocketAddress;
41-
42-
import java.io.File;
43-
import java.io.RandomAccessFile;
44-
import java.nio.ByteBuffer;
45-
import java.nio.ByteOrder;
4631

47-
import static com.sun.jna.platform.linux.Mman.*;
32+
import java.nio.ByteBuffer;
4833

4934
class Client {
50-
interface MappingKernel extends Kernel32 {
51-
MappingKernel INSTANCE = Native.load(MappingKernel.class, W32APIOptions.DEFAULT_OPTIONS);
52-
53-
HANDLE OpenFileMapping(int desiredAccess, boolean inherit, String name);
54-
}
55-
56-
interface LibCExt extends LibC {
57-
LibCExt INSTANCE = Native.load(LibCExt.class);
58-
59-
Pointer mmap(Pointer addr, int length, int prot, int flags, int fd, int offset) throws LastErrorException;
60-
}
61-
6235
public interface EventHandler {
6336
void operation(ClientData.Event event);
6437
}
6538

66-
private static final int READ_WRITE = 0x1 | 0x2 | 0x4;
67-
6839
private static final int SUPPORTED_BWAPI_VERSION = 10003;
6940
static final int MAX_COUNT = 19999;
7041
static final int MAX_STRING_SIZE = 1024;
7142

7243
private ClientData clientData;
7344
private ClientData.GameData gameData;
7445
private boolean connected = false;
75-
private RandomAccessFile pipeObjectHandle = null;
76-
private AFUNIXSocket syncSocket = null;
77-
private ByteBuffer mapFileHandle = null;
78-
private ByteBuffer gameTableFileHandle = null;
46+
private ByteBuffer mapShm = null;
47+
private ByteBuffer gameTableShm = null;
48+
private final ClientConnection clientConnector;
7949

8050
private boolean debugConnection = false;
8151

8252
Client(boolean debugConnection) {
8353
this.debugConnection = debugConnection;
54+
boolean windowsOs = System.getProperty("os.name").toLowerCase().contains("win");
55+
clientConnector = windowsOs ? new ClientConnectionW32() : new ClientConnectionPosix();
8456
}
8557

8658
/**
@@ -89,6 +61,7 @@ public interface EventHandler {
8961
Client(ByteBuffer buffer) {
9062
clientData = new ClientData(buffer);
9163
gameData = clientData.new GameData(0);
64+
clientConnector = null;
9265
}
9366

9467
ClientData clientData() {
@@ -117,27 +90,9 @@ void disconnect() {
11790
if (!connected) {
11891
return;
11992
}
120-
121-
if (pipeObjectHandle != null) {
122-
try {
123-
pipeObjectHandle.close();
124-
} catch (Exception e) {
125-
e.printStackTrace();
126-
}
127-
pipeObjectHandle = null;
128-
}
129-
130-
if (syncSocket != null) {
131-
try {
132-
syncSocket.close();
133-
} catch (Exception e) {
134-
e.printStackTrace();
135-
}
136-
syncSocket = null;
137-
}
138-
139-
mapFileHandle = null;
140-
gameTableFileHandle = null;
93+
clientConnector.disconnect();
94+
mapShm = null;
95+
gameTableShm = null;
14196
gameData = null;
14297
connected = false;
14398
}
@@ -152,17 +107,7 @@ boolean connect() {
152107
int gameTableIndex = -1;
153108

154109
try {
155-
try {
156-
gameTableFileHandle = Kernel32.INSTANCE.MapViewOfFile(
157-
MappingKernel.INSTANCE.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE, 0, 0, GameTable.SIZE)
158-
.getByteBuffer(0, GameTable.SIZE);
159-
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
160-
int fd = LibRT.INSTANCE.shm_open("/bwapi_shared_memory_game_list", Fcntl.O_RDWR, 0);
161-
if (fd < 0) throw new IllegalStateException("SHM not found");
162-
gameTableFileHandle = LibCExt.INSTANCE.mmap(Pointer.NULL, GameTable.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
163-
.getByteBuffer(0, GameTable.SIZE);
164-
gameTableFileHandle.order(ByteOrder.LITTLE_ENDIAN);
165-
}
110+
gameTableShm = clientConnector.getGameTable();
166111
}
167112
catch (Exception e) {
168113
System.err.println("Game table mapping not found.");
@@ -171,7 +116,7 @@ boolean connect() {
171116

172117
GameTable gameTable;
173118
try {
174-
gameTable = new GameTable(gameTableFileHandle);
119+
gameTable = new GameTable(this.gameTableShm);
175120
}
176121
catch (Exception e) {
177122
System.err.println("Unable to map Game table.");
@@ -202,28 +147,19 @@ boolean connect() {
202147
return false;
203148
}
204149

205-
String sharedMemoryName = "Local\\bwapi_shared_memory_" + serverProcID;
206150
try {
207-
try {
208-
mapFileHandle = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
209-
.OpenFileMapping(READ_WRITE, false, sharedMemoryName), READ_WRITE,
210-
0, 0, GameData.SIZE).getByteBuffer(0, GameData.SIZE);
211-
} catch (NoClassDefFoundError e) {
212-
sharedMemoryName = "/bwapi_shared_memory_" + serverProcID;
213-
mapFileHandle = LibCExt.INSTANCE.mmap(Pointer.NULL, GameData.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, LibRT.INSTANCE.shm_open(sharedMemoryName, Fcntl.O_RDWR, 0),
214-
0).getByteBuffer(0, GameData.SIZE);
215-
}
151+
mapShm = clientConnector.getSharedMemory(serverProcID);
216152
}
217153
catch (Exception e) {
218-
System.err.println("Unable to open shared memory mapping: " + sharedMemoryName);
154+
System.err.println("Unable to open shared memory mapping: " + e.getMessage());
219155
if (debugConnection) {
220156
e.printStackTrace();
221157
}
222-
gameTableFileHandle = null;
158+
this.gameTableShm = null;
223159
return false;
224160
}
225161
try {
226-
clientData = new ClientData(mapFileHandle);
162+
clientData = new ClientData(mapShm);
227163
gameData = clientData.new GameData(0);
228164
} catch (Exception e) {
229165
System.err.println("Unable to map game data.");
@@ -233,23 +169,15 @@ boolean connect() {
233169
return false;
234170
}
235171

236-
final String communicationPipe = "\\\\.\\pipe\\bwapi_pipe_" + serverProcID;
237-
final String communicationSocket = "/tmp/bwapi_socket_" + serverProcID;
172+
238173
try {
239-
if (new File(communicationPipe).exists()) {
240-
pipeObjectHandle = new RandomAccessFile(communicationPipe, "rw");
241-
} else {
242-
syncSocket = AFUNIXSocket.newInstance();
243-
syncSocket.connect(new AFUNIXSocketAddress(new File(communicationSocket)));
244-
}
174+
clientConnector.connectSharedLock(serverProcID);
245175
} catch (Exception e) {
246-
System.err.println("Unable to open communications pipe or socket: " + communicationPipe + " resp. " + communicationSocket);
176+
System.err.println(e.getMessage());
247177
if (debugConnection) {
248178
e.printStackTrace();
249179
}
250-
gameTableFileHandle = null;
251-
pipeObjectHandle = null;
252-
syncSocket = null;
180+
this.gameTableShm = null;
253181
return false;
254182
}
255183
System.out.println("Connected");
@@ -263,20 +191,14 @@ boolean connect() {
263191
return false;
264192
}
265193

266-
if (pipeObjectHandle != null) {
267-
byte code = 1;
268-
while (code != 2) {
269-
try {
270-
code = pipeObjectHandle.readByte();
271-
} catch (Exception e) {
272-
System.err.println("Unable to read pipe object.");
273-
if (debugConnection) {
274-
e.printStackTrace();
275-
}
276-
disconnect();
277-
return false;
278-
}
194+
try {
195+
clientConnector.waitForServerReady();
196+
} catch (Exception e) {
197+
if (debugConnection) {
198+
e.printStackTrace();
279199
}
200+
disconnect();
201+
return false;
280202
}
281203

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

287209
void update(final EventHandler handler) {
288-
if (pipeObjectHandle != null) {
289-
byte code = 1;
290-
try {
291-
pipeObjectHandle.writeByte(code);
292-
} catch (Exception e) {
293-
System.err.println("failed, disconnecting");
294-
if (debugConnection) {
295-
e.printStackTrace();
296-
}
297-
disconnect();
298-
return;
299-
}
300-
while (code != 2) {
301-
try {
302-
code = pipeObjectHandle.readByte();
303-
} catch (Exception e) {
304-
System.err.println("failed, disconnecting");
305-
if (debugConnection) {
306-
e.printStackTrace();
307-
}
308-
disconnect();
309-
return;
310-
}
311-
}
312-
}
313-
if (syncSocket != null) {
314-
int code = 1;
315-
while (code != 2) {
316-
try {
317-
code = syncSocket.getInputStream().read();
318-
} catch (Exception e) {
319-
System.err.println("failed, disconnecting");
320-
if (debugConnection) {
321-
e.printStackTrace();
322-
}
323-
disconnect();
324-
return;
325-
}
210+
try {
211+
clientConnector.waitForServerData();
212+
} catch (Exception e) {
213+
System.err.println("failed, disconnecting");
214+
if (debugConnection) {
215+
e.printStackTrace();
326216
}
217+
disconnect();
218+
return;
327219
}
328220
for (int i = 0; i < gameData.getEventCount(); i++) {
329221
handler.operation(gameData.getEvents(i));
330222
}
331223
try {
332-
syncSocket.getOutputStream().write(1);
224+
clientConnector.submitClientData();
333225
} catch (Exception e) {
334226
System.err.println("failed, disconnecting");
335227
if (debugConnection) {
336228
e.printStackTrace();
337229
}
338230
disconnect();
339-
return;
340231
}
341232
}
342233

@@ -392,6 +283,7 @@ private void sleep(final int millis) {
392283
Thread.sleep(millis);
393284
}
394285
catch (Exception ignored) {
286+
// Not relevant
395287
}
396288
}
397289
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package bwapi;
2+
3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
6+
interface ClientConnection {
7+
void disconnect();
8+
9+
ByteBuffer getGameTable();
10+
11+
ByteBuffer getSharedMemory(int serverProcID);
12+
13+
void connectSharedLock(int serverProcID) throws Exception;
14+
15+
void waitForServerReady() throws IOException;
16+
17+
void waitForServerData() throws Exception;
18+
19+
void submitClientData() throws IOException;
20+
}
21+
22+
class SharedMemoryConnectionError extends RuntimeException {
23+
public SharedMemoryConnectionError(String message, Throwable cause) {
24+
super(message, cause);
25+
}
26+
}
27+
28+
class SharedLockConnectionError extends RuntimeException {
29+
public SharedLockConnectionError(String message, Throwable cause) {
30+
super(message, cause);
31+
}
32+
}

0 commit comments

Comments
 (0)