Skip to content

Commit 1d673f6

Browse files
committed
Introduce protocol versions.
We're now sending serialized Gameboy state, so it's important that both emulators have the same protocol (and serialization) version.
1 parent 340ca86 commit 1d673f6

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

controller/src/main/java/eu/rekawek/coffeegb/controller/network/Connection.kt

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ import eu.rekawek.coffeegb.core.GameboyType
88
import eu.rekawek.coffeegb.core.events.Event
99
import eu.rekawek.coffeegb.core.events.EventBus
1010
import eu.rekawek.coffeegb.core.joypad.Button
11-
import org.slf4j.Logger
12-
import org.slf4j.LoggerFactory
11+
import java.io.IOException
1312
import java.io.InputStream
1413
import java.io.OutputStream
1514
import java.nio.ByteBuffer
1615
import kotlin.concurrent.Volatile
16+
import org.slf4j.Logger
17+
import org.slf4j.LoggerFactory
1718

1819
class Connection(
1920
private val inputStream: InputStream,
2021
private val outputStream: OutputStream,
2122
mainEventBus: EventBus,
23+
private val server: Boolean,
2224
) : Runnable, AutoCloseable {
2325

2426
private val eventBus: EventBus = mainEventBus.fork("connection")
@@ -87,6 +89,7 @@ class Connection(
8789
}
8890

8991
override fun run() {
92+
handshake()
9093
while (!doStop) {
9194
val command = inputStream.read()
9295
if (command == -1) {
@@ -190,6 +193,36 @@ class Connection(
190193
outputStream.close()
191194
}
192195

196+
private fun handshake() {
197+
val buf = ByteBuffer.allocate(PROTOCOL_NAME.length + 1)
198+
if (server) {
199+
buf.put(PROTOCOL_NAME.toByteArray())
200+
buf.put(PROTOCOL_VERSION)
201+
outputStream.write(buf.array())
202+
LOG.atInfo().log("Sent protocol name {} and version {}", PROTOCOL_NAME, PROTOCOL_VERSION)
203+
} else {
204+
inputStream.read(buf.array())
205+
val receivedProtocolName = String(buf.array().take(PROTOCOL_NAME.length).toByteArray())
206+
if (receivedProtocolName != PROTOCOL_NAME) {
207+
throw IOException(
208+
"Protocol mismatch: expected $PROTOCOL_NAME, received $receivedProtocolName"
209+
)
210+
}
211+
val receivedProtocolVersion = buf.array()[PROTOCOL_NAME.length]
212+
if (receivedProtocolVersion != PROTOCOL_VERSION) {
213+
throw IOException(
214+
"Protocol mismatch: expected $PROTOCOL_VERSION, received $receivedProtocolVersion"
215+
)
216+
}
217+
LOG.atInfo()
218+
.log(
219+
"Received protocol name {} and version {}",
220+
receivedProtocolName,
221+
receivedProtocolVersion,
222+
)
223+
}
224+
}
225+
193226
data class PeerLoadedGameEvent(
194227
val rom: ByteArray,
195228
val battery: ByteArray?,
@@ -209,5 +242,7 @@ class Connection(
209242

210243
companion object {
211244
private val LOG: Logger = LoggerFactory.getLogger(Connection::class.java)
245+
private const val PROTOCOL_NAME: String = "CoffeeGB NETPLAY"
246+
private const val PROTOCOL_VERSION: Byte = 0x01
212247
}
213248
}

controller/src/main/java/eu/rekawek/coffeegb/controller/network/TcpClient.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package eu.rekawek.coffeegb.controller.network
22

33
import eu.rekawek.coffeegb.core.events.EventBus
4-
import org.slf4j.Logger
5-
import org.slf4j.LoggerFactory
64
import java.io.IOException
75
import java.net.Socket
86
import java.net.SocketException
7+
import org.slf4j.Logger
8+
import org.slf4j.LoggerFactory
99

1010
class TcpClient(
1111
private val host: String,
@@ -18,9 +18,8 @@ class TcpClient(
1818
clientSocket = createSocket(host)
1919
LOG.info("Connected to {}", clientSocket!!.inetAddress)
2020
eventBus.post(ConnectionController.ClientConnectedToServerEvent())
21-
Connection(clientSocket!!.getInputStream(), clientSocket!!.getOutputStream(), eventBus).use {
22-
it.run()
23-
}
21+
Connection(clientSocket!!.getInputStream(), clientSocket!!.getOutputStream(), eventBus, false)
22+
.use { it.run() }
2423
LOG.info("Disconnected from {}", clientSocket!!.inetAddress)
2524
} catch (e: SocketException) {
2625
if (e.message == "Socket closed") {

controller/src/main/java/eu/rekawek/coffeegb/controller/network/TcpServer.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package eu.rekawek.coffeegb.controller.network
22

33
import eu.rekawek.coffeegb.core.events.EventBus
4-
import org.slf4j.Logger
5-
import org.slf4j.LoggerFactory
64
import java.io.IOException
75
import java.net.ServerSocket
86
import java.net.Socket
97
import java.net.SocketException
108
import java.net.SocketTimeoutException
119
import kotlin.concurrent.Volatile
10+
import org.slf4j.Logger
11+
import org.slf4j.LoggerFactory
1212

1313
class TcpServer(private val eventBus: EventBus) : Runnable {
1414
@Volatile private var doStop = false
@@ -28,7 +28,9 @@ class TcpServer(private val eventBus: EventBus) : Runnable {
2828
LOG.info("Got new connection: {}", socket.inetAddress)
2929
eventBus.post(ConnectionController.ServerGotConnectionEvent(socket.inetAddress.hostName))
3030
try {
31-
Connection(socket.getInputStream(), socket.getOutputStream(), eventBus).use { it.run() }
31+
Connection(socket.getInputStream(), socket.getOutputStream(), eventBus, true).use {
32+
it.run()
33+
}
3234
} finally {
3335
LOG.info("Client disconnected: {}", socket.inetAddress)
3436
eventBus.post(ConnectionController.ServerLostConnectionEvent())

0 commit comments

Comments
 (0)