Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Few critical bugs are fixed #97

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
315577e
fix exeptions when RMI non-void method executed so long that 64 new m…
Jun 12, 2015
ba4cf39
fix exceptions when server reads messages some slower than client writes
Jun 14, 2015
7730430
Each Kryo instance now has separate methodCache
Jun 14, 2015
3d0112f
fix building remote methods cache, update kryo version, concurrent in…
Mar 14, 2018
3fcc194
Merge pull request #2 from EsotericSoftware/master
asoboll Mar 14, 2018
33a0052
add copyright
Mar 14, 2018
637937a
Merge branch 'merge_with_esoteric' to master
Mar 14, 2018
dbeabca
Merge branch 'master' into fix_multithreaded_invocations_exceptions
Mar 14, 2018
15e9c8f
simplified test
Mar 15, 2018
a4ffae8
response id possible collision fix
Apr 3, 2018
d8ed136
response id possible collision fix (2)
Apr 3, 2018
3f7e84c
64 parallel remote invocations allowed
Apr 3, 2018
4d88593
response id collision example test
Apr 3, 2018
219ba41
Merge branch 'responseId_collision_test' into responseId_collision_fix
Apr 3, 2018
4027172
style fix
Apr 3, 2018
6066d6e
fixed very rare bug when waiting for wrong responseId
asoboll Jul 3, 2018
3427a77
add dsx version suffix
pchertalev Jul 13, 2018
ef31e53
Check on connect that both client and server has equals registered cl…
Jun 10, 2019
f308dc9
Switch "Check on connect that both client and server has equals regis…
Jun 10, 2019
37435ee
Ignore unstable tests
Jun 10, 2019
f492ba8
Set deploy dsx-2 to nexus
Jun 10, 2019
222365b
Set deploy "dsx" master to nexus
Jun 10, 2019
f8c2dcf
Merge branch 'master' into dsx-2
ai-dsxt Jun 19, 2019
a4b2eda
Merge pull request #3 from dsx-tech/dsx-2
ai-dsxt Jun 19, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<groupId>com.esotericsoftware</groupId>
<artifactId>kryonet</artifactId>
<version>2.22.0-RC1</version>
<version>2.22.0-RC1-dsx-MASTER-SNAPSHOT</version>
<packaging>jar</packaging>

<name>kryonet</name>
Expand Down Expand Up @@ -48,9 +48,9 @@

<dependencies>
<dependency>
<groupId>com.esotericsoftware.kryo</groupId>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>2.24.0</version>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
Expand All @@ -65,4 +65,14 @@
</dependency>
</dependencies>

<distributionManagement>
<snapshotRepository>
<id>nexus-snapshot</id>
<url>https://nexus.dsx.cool/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>nexus-release</id>
<url>https://nexus.dsx.cool/repository/maven-releases/</url>
</repository>
</distributionManagement>
</project>
9 changes: 9 additions & 0 deletions src/com/esotericsoftware/kryonet/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class Client extends Connection implements EndPoint {
private int connectUdpPort;
private boolean isClosed;
private ClientDiscoveryHandler discoveryHandler;
private boolean checkRegisteredClasses;

/** Creates a Client with a write buffer size of 8192 and an object buffer size of 2048. */
public Client () {
Expand Down Expand Up @@ -123,6 +124,14 @@ public Kryo getKryo () {
return serialization instanceof KryoSerialization ? ((KryoSerialization)serialization).getKryo() : null;
}

public void setCheckRegisteredClasses(boolean value) {
checkRegisteredClasses = value;
}

public boolean checkRegisteredClasses() {
return checkRegisteredClasses;
}

/** Opens a TCP only client.
* @see #connect(int, InetAddress, int, int) */
public void connect (int timeout, String host, int tcpPort) throws IOException {
Expand Down
52 changes: 51 additions & 1 deletion src/com/esotericsoftware/kryonet/Connection.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
import java.nio.channels.SocketChannel;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Registration;
import com.esotericsoftware.kryonet.FrameworkMessage.Ping;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisteredClassesInfo;
import com.esotericsoftware.minlog.Log;

import static com.esotericsoftware.minlog.Log.*;

Expand Down Expand Up @@ -256,7 +259,7 @@ void notifyIdle () {
}
}

void notifyReceived (Object object) {
void notifyReceived (Object object) throws IOException {
if (object instanceof Ping) {
Ping ping = (Ping)object;
if (ping.isReply) {
Expand All @@ -268,6 +271,10 @@ void notifyReceived (Object object) {
ping.isReply = true;
sendTCP(ping);
}
} else if (object instanceof RegisteredClassesInfo) {
if (endPoint.checkRegisteredClasses())
checkRegisteredClasses((RegisteredClassesInfo) object);
return;
}
Listener[] listeners = this.listeners;
for (int i = 0, n = listeners.length; i < n; i++)
Expand Down Expand Up @@ -337,4 +344,47 @@ void setConnected (boolean isConnected) {
this.isConnected = isConnected;
if (isConnected && name == null) name = "Connection " + id;
}

public void sendRegisteredClasses () {
RegisteredClassesInfo info = new RegisteredClassesInfo();
info.classes = getRegisteredClasses(endPoint.getKryo());
sendTCP(info);
}

private String getRegisteredClasses(Kryo kryo) {
if (kryo == null)
return null;
StringBuffer buffer = new StringBuffer();
for(int i = 0; i < Integer.MAX_VALUE; i++) {
Registration registration = kryo.getRegistration(i);
if (registration == null)
break;
buffer.append(';');
buffer.append(registration.getType().getCanonicalName());
}
return buffer.toString();
}

private void checkRegisteredClasses(RegisteredClassesInfo info) throws IOException {
String classes = getRegisteredClasses(endPoint.getKryo());
if (info.classes != null && classes != null && !info.classes.equals(classes)) {
String[] otherClasses = info.classes.split(";");
String[] thisClasses = classes.split(";");
for(int i = 0; i < otherClasses.length; i++) {
if (thisClasses.length == i) {
Log.error("kryonet", "Connection.notifyReceived. Registered classes mismatch. Not all other classes are registered. First unregistered class= '" + otherClasses[i] + "'");
throw new IOException("Registered classes mismatch. Not all other classes are registered. First unregistered class= '" + otherClasses[i] + "'");
} else if (!otherClasses[i].equals(thisClasses[i])) {
Log.error("kryonet", "Connection.notifyReceived. Registered classes mismatch. First difference at index " + i + " this class = '" + thisClasses[i] + "' other class = '" + otherClasses[i] + "'");
throw new IOException("Registered classes mismatch. First difference at index " + i + " this class = '" + thisClasses[i] + "' other class = '" + otherClasses[i] + "'");
}
}
if (thisClasses.length > otherClasses.length) {
Log.error("kryonet", "Connection.notifyReceived. Registered classes mismatch. Not all this classes are registered. First unregistered class= '" + thisClasses[otherClasses.length] + "'");
throw new IOException("Registered classes mismatch. Not all this classes are registered. First unregistered class= '" + thisClasses[otherClasses.length] + "'");
} else {
Log.error("kryonet", "Connection.notifyReceived. It looks like registered classes mismatch, but no difference found");
}
}
}
}
4 changes: 4 additions & 0 deletions src/com/esotericsoftware/kryonet/EndPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,8 @@ public interface EndPoint extends Runnable {
* not being used.
* @return May be null. */
public Kryo getKryo ();

public void setCheckRegisteredClasses(boolean value);

public boolean checkRegisteredClasses();
}
5 changes: 5 additions & 0 deletions src/com/esotericsoftware/kryonet/FrameworkMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ static public class Ping implements FrameworkMessage {
public int id;
public boolean isReply;
}

/** Internal message to check are registered classes on client and server side equal. */
static public class RegisteredClassesInfo implements FrameworkMessage {
public String classes;
}
}
2 changes: 2 additions & 0 deletions src/com/esotericsoftware/kryonet/JsonSerialization.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.esotericsoftware.kryonet.FrameworkMessage.Ping;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisterTCP;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisterUDP;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisteredClassesInfo;

public class JsonSerialization implements Serialization {
private final Json json = new Json();
Expand All @@ -48,6 +49,7 @@ public JsonSerialization () {
json.addClassTag("KeepAlive", KeepAlive.class);
json.addClassTag("DiscoverHost", DiscoverHost.class);
json.addClassTag("Ping", Ping.class);
json.addClassTag("RegisteredClassesInfo", RegisteredClassesInfo.class);

json.setWriter(writer);
}
Expand Down
2 changes: 2 additions & 0 deletions src/com/esotericsoftware/kryonet/KryoSerialization.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.esotericsoftware.kryonet.FrameworkMessage.Ping;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisterTCP;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisterUDP;
import com.esotericsoftware.kryonet.FrameworkMessage.RegisteredClassesInfo;

import java.nio.ByteBuffer;

Expand All @@ -51,6 +52,7 @@ public KryoSerialization (Kryo kryo) {
kryo.register(KeepAlive.class);
kryo.register(DiscoverHost.class);
kryo.register(Ping.class);
kryo.register(RegisteredClassesInfo.class);

input = new ByteBufferInput();
output = new ByteBufferOutput();
Expand Down
11 changes: 11 additions & 0 deletions src/com/esotericsoftware/kryonet/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class Server implements EndPoint {
private Object updateLock = new Object();
private Thread updateThread;
private ServerDiscoveryHandler discoveryHandler;
private boolean checkRegisteredClasses;

private Listener dispatchListener = new Listener() {
public void connected (Connection connection) {
Expand Down Expand Up @@ -136,6 +137,14 @@ public Kryo getKryo () {
return serialization instanceof KryoSerialization ? ((KryoSerialization)serialization).getKryo() : null;
}

public void setCheckRegisteredClasses(boolean value) {
checkRegisteredClasses = value;
}

public boolean checkRegisteredClasses() {
return checkRegisteredClasses;
}

/** Opens a TCP only server.
* @throws IOException if the server could not be opened. */
public void bind (int tcpPort) throws IOException {
Expand Down Expand Up @@ -431,6 +440,8 @@ private void acceptOperation (SocketChannel socketChannel) {
RegisterTCP registerConnection = new RegisterTCP();
registerConnection.connectionID = id;
connection.sendTCP(registerConnection);
if (checkRegisteredClasses)
connection.sendRegisteredClasses();

if (udp == null) connection.notifyConnected();
} catch (IOException ex) {
Expand Down
21 changes: 19 additions & 2 deletions src/com/esotericsoftware/kryonet/TcpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ class TcpConnection {
private volatile long lastWriteTime, lastReadTime;
private int currentObjectLength;
private final Object writeLock = new Object();
private final int objectBufferSize;
private final int lengthLength;

public TcpConnection (Serialization serialization, int writeBufferSize, int objectBufferSize) {
this.serialization = serialization;
writeBuffer = ByteBuffer.allocate(writeBufferSize);
this.objectBufferSize = objectBufferSize;
lengthLength = serialization.getLengthLength();
writeBuffer = ByteBuffer.allocate(Math.max(writeBufferSize, lengthLength + objectBufferSize));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the write buffer size that was passed in?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because bufferSize >= lengthLength + objectSize must be true in all cases.
If it is not so, user has entered incorrect values. We can react on that two ways:
first - throw an exception, second - use max(bufferSize, lengthLength + objectSize).
We have chosen second one, but we can change to exception.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I prefer an exception to using a buffer size other than what was specified.

readBuffer = ByteBuffer.allocate(objectBufferSize);
readBuffer.flip();
}
Expand Down Expand Up @@ -199,8 +203,21 @@ public int send (Connection connection, Object object) throws IOException {
SocketChannel socketChannel = this.socketChannel;
if (socketChannel == null) throw new SocketException("Connection is closed.");
synchronized (writeLock) {
int start = writeBuffer.position();
int lengthLength = serialization.getLengthLength();

//wait while buffer has enough free space.
//thats because message length will be put only after the whole message will be serialized
while (writeBuffer.capacity() < writeBuffer.position() + lengthLength + objectBufferSize) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
break;
}
writeToSocket();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't just sleep the writing thread, this would have to be a feature, disabled by default. The right way to handle this is to not send data so fast or to use a larger buffer.

Comment should be "wait until buffer".

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you pass 0 as value of objectSize, feature will be disabled. We can set 0 as default value.

Concerning "The right way", it's the matter of dispute. If so user should select unique buffer size for each system installation on different computers, in different configurations and so on. Or make buffer too large to avoid problems that are very rare.


// Leave room for length.
int start = writeBuffer.position();
try {
// Leave room for length.
writeBuffer.position(writeBuffer.position() + lengthLength);
Expand Down
Loading