summaryrefslogtreecommitdiff
path: root/java/src/IceInternal/UdpTransceiver.java
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2009-10-27 12:00:32 +0100
committerBenoit Foucher <benoit@zeroc.com>2009-10-27 12:00:32 +0100
commit1fdb973182e589b0d20e987360bd694ae783b0a2 (patch)
treea94cbbcc0d078bcf7aa4427951799e09feb80826 /java/src/IceInternal/UdpTransceiver.java
parentadd support for number protocol in Python (diff)
downloadice-1fdb973182e589b0d20e987360bd694ae783b0a2.tar.bz2
ice-1fdb973182e589b0d20e987360bd694ae783b0a2.tar.xz
ice-1fdb973182e589b0d20e987360bd694ae783b0a2.zip
Cleaned up UDP transceivers, fixes for bug 4223 and 4320
Diffstat (limited to 'java/src/IceInternal/UdpTransceiver.java')
-rw-r--r--java/src/IceInternal/UdpTransceiver.java196
1 files changed, 120 insertions, 76 deletions
diff --git a/java/src/IceInternal/UdpTransceiver.java b/java/src/IceInternal/UdpTransceiver.java
index bd18ad77678..2001f8e0e67 100644
--- a/java/src/IceInternal/UdpTransceiver.java
+++ b/java/src/IceInternal/UdpTransceiver.java
@@ -32,7 +32,7 @@ final class UdpTransceiver implements Transceiver
{
assert(_fd != null);
- if(!_connect && _traceLevels.network >= 1)
+ if(_state >= StateConnected && _traceLevels.network >= 1)
{
String s = "closing udp connection\n" + toString();
_logger.trace(_traceLevels.networkCat, s);
@@ -52,40 +52,28 @@ final class UdpTransceiver implements Transceiver
write(Buffer buf)
{
assert(buf.b.position() == 0);
- final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead);
- if(packetSize < buf.size())
- {
- //
- // We don't log a warning here because the client gets an exception anyway.
- //
- throw new Ice.DatagramLimitException();
- }
+ assert(_fd != null && _state >= StateConnected);
+
+ // The caller is supposed to check the send size before by calling checkSendSize
+ assert(java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size());
- while(buf.b.hasRemaining())
+ int ret = 0;
+ while(true)
{
try
{
- assert(_fd != null);
-
- int ret = _fd.write(buf.b);
-
- if(ret == 0)
+ if(_state == StateConnected)
{
- return false;
- }
-
- if(_traceLevels.network >= 3)
- {
- String s = "sent " + ret + " bytes via udp\n" + toString();
- _logger.trace(_traceLevels.networkCat, s);
+ ret = _fd.write(buf.b);
}
-
- if(_stats != null)
+ else
{
- _stats.bytesSent(type(), ret);
+ if(_peerAddr == null)
+ {
+ throw new Ice.SocketException(); // No peer has sent a datagram yet.
+ }
+ ret = _fd.send(buf.b, _peerAddr);
}
-
- assert(ret == buf.b.limit());
break;
}
catch(java.nio.channels.AsynchronousCloseException ex)
@@ -112,6 +100,23 @@ final class UdpTransceiver implements Transceiver
}
}
+ if(ret == 0)
+ {
+ return false;
+ }
+
+ if(_traceLevels.network >= 3)
+ {
+ String s = "sent " + ret + " bytes via udp\n" + toString();
+ _logger.trace(_traceLevels.networkCat, s);
+ }
+
+ if(_stats != null)
+ {
+ _stats.bytesSent(type(), ret);
+ }
+
+ assert(ret == buf.b.limit());
return true;
}
@@ -122,18 +127,6 @@ final class UdpTransceiver implements Transceiver
moreData.value = false;
final int packetSize = java.lang.Math.min(_maxPacketSize, _rcvSize - _udpOverhead);
- if(packetSize < buf.size())
- {
- //
- // We log a warning here because this is the server side -- without the
- // the warning, there would only be silence.
- //
- if(_warn)
- {
- _logger.warning("DatagramLimitException: maximum size of " + packetSize + " exceeded");
- }
- throw new Ice.DatagramLimitException();
- }
buf.resize(packetSize, true);
buf.b.position(0);
@@ -142,31 +135,14 @@ final class UdpTransceiver implements Transceiver
{
try
{
- java.net.InetSocketAddress sender = (java.net.InetSocketAddress)_fd.receive(buf.b);
-
- if(sender == null || buf.b.position() == 0)
+ java.net.SocketAddress peerAddr = _fd.receive(buf.b);
+ if(peerAddr == null || buf.b.position() == 0)
{
return false;
}
+ _peerAddr = (java.net.InetSocketAddress)peerAddr;
ret = buf.b.position();
-
- if(_connect)
- {
- //
- // If we must connect, then we connect to the first peer that
- // sends us a packet.
- //
- Network.doConnect(_fd, sender);
- _connect = false; // We're connected now
-
- if(_traceLevels.network >= 1)
- {
- String s = "connected udp socket\n" + toString();
- _logger.trace(_traceLevels.networkCat, s);
- }
- }
-
break;
}
catch(java.nio.channels.AsynchronousCloseException ex)
@@ -193,6 +169,21 @@ final class UdpTransceiver implements Transceiver
}
}
+ if(_state == StateNeedConnect)
+ {
+ //
+ // If we must connect, we connect to the first peer that sends us a packet.
+ //
+ Network.doConnect(_fd, _peerAddr);
+ _state = StateConnected;
+
+ if(_traceLevels.network >= 1)
+ {
+ String s = "connected udp socket\n" + toString();
+ _logger.trace(_traceLevels.networkCat, s);
+ }
+ }
+
if(_traceLevels.network >= 3)
{
String s = "received " + ret + " bytes via udp\n" + toString();
@@ -219,14 +210,31 @@ final class UdpTransceiver implements Transceiver
public String
toString()
{
- if(_mcastAddr != null && _fd != null)
+ if(_fd == null)
{
- return Network.fdToString(_fd) + "\nmulticast address = " + Network.addrToString(_mcastAddr);
+ return "<closed>";
+ }
+
+ String s;
+ if(_state == StateNotConnected)
+ {
+ java.net.DatagramSocket socket = ((java.nio.channels.DatagramChannel)_fd).socket();
+ s = "local address = " + Network.addrToString((java.net.InetSocketAddress)socket.getLocalSocketAddress());
+ if(_peerAddr != null)
+ {
+ s += "\nremote address = " + Network.addrToString(_peerAddr);
+ }
}
else
{
- return Network.fdToString(_fd);
+ s = Network.fdToString(_fd);
+ }
+
+ if(_mcastAddr != null)
+ {
+ s += "\nmulticast address = " + Network.addrToString(_mcastAddr);
}
+ return s;
}
public Ice.ConnectionInfo
@@ -238,15 +246,31 @@ final class UdpTransceiver implements Transceiver
java.net.DatagramSocket socket = _fd.socket();
info.localAddress = socket.getLocalAddress().getHostAddress();
info.localPort = socket.getLocalPort();
- if(socket.getInetAddress() != null)
+ if(_state == StateNotConnected)
{
- info.remoteAddress = socket.getInetAddress().getHostAddress();
- info.remotePort = socket.getPort();
+ if(_peerAddr != null)
+ {
+ info.remoteAddress = _peerAddr.getAddress().getHostAddress();
+ info.remotePort = _peerAddr.getPort();
+ }
+ else
+ {
+ info.remoteAddress = "";
+ info.remotePort = -1;
+ }
}
else
{
- info.remoteAddress = "";
- info.remotePort = -1;
+ if(socket.getInetAddress() != null)
+ {
+ info.remoteAddress = socket.getInetAddress().getHostAddress();
+ info.remotePort = socket.getPort();
+ }
+ else
+ {
+ info.remoteAddress = "";
+ info.remotePort = -1;
+ }
}
if(_mcastAddr != null)
{
@@ -268,6 +292,11 @@ final class UdpTransceiver implements Transceiver
{
Ex.throwMemoryLimitException(buf.size(), messageSizeMax);
}
+
+ //
+ // The maximum packetSize is either the maximum allowable UDP packet size, or
+ // the UDP send buffer size (which ever is smaller).
+ //
final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead);
if(packetSize < buf.size())
{
@@ -289,8 +318,7 @@ final class UdpTransceiver implements Transceiver
_traceLevels = instance.traceLevels();
_logger = instance.initializationData().logger;
_stats = instance.initializationData().stats;
- _connect = true;
- _warn = instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0;
+ _state = StateNeedConnect;
_addr = addr;
try
@@ -299,7 +327,7 @@ final class UdpTransceiver implements Transceiver
setBufSize(instance);
Network.setBlock(_fd, false);
Network.doConnect(_fd, _addr);
- _connect = false; // We're connected now
+ _state = StateConnected; // We're connected now
if(_addr.getAddress().isMulticastAddress())
{
configureMulticast(null, mcastInterface, mcastTtl);
@@ -326,8 +354,7 @@ final class UdpTransceiver implements Transceiver
_traceLevels = instance.traceLevels();
_logger = instance.initializationData().logger;
_stats = instance.initializationData().stats;
- _connect = connect;
- _warn = instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0;
+ _state = connect ? StateNeedConnect : StateNotConnected;
try
{
@@ -344,7 +371,20 @@ final class UdpTransceiver implements Transceiver
{
Network.setReuseAddress(_fd, true);
_mcastAddr = _addr;
- _addr = Network.doBind(_fd, Network.getAddress("0.0.0.0", port, Network.EnableIPv4));
+ if(System.getProperty("os.name").startsWith("Windows"))
+ {
+ //
+ // Windows does not allow binding to the mcast address itself
+ // so we bind to INADDR_ANY (0.0.0.0) instead. As a result,
+ // bi-directional connection won't work because the source
+ // address won't be the multicast address and the client will
+ // therefore reject the datagram.
+ //
+ int protocol =
+ _mcastAddr.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : Network.EnableIPv6;
+ _addr = Network.getAddressForServer("", port, protocol);
+ }
+ _addr = Network.doBind(_fd, _addr);
if(port == 0)
{
_mcastAddr = new java.net.InetSocketAddress(_mcastAddr.getAddress(), _addr.getPort());
@@ -425,7 +465,7 @@ final class UdpTransceiver implements Transceiver
// Get property for buffer size and check for sanity.
//
int sizeRequested = instance.initializationData().properties.getPropertyAsIntWithDefault(prop, dfltSize);
- if(sizeRequested < _udpOverhead)
+ if(sizeRequested < (_udpOverhead + IceInternal.Protocol.headerSize))
{
_logger.warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " + dfltSize);
sizeRequested = dfltSize;
@@ -570,13 +610,13 @@ final class UdpTransceiver implements Transceiver
private TraceLevels _traceLevels;
private Ice.Logger _logger;
private Ice.Stats _stats;
- private boolean _connect;
- private final boolean _warn;
+ private int _state;
private int _rcvSize;
private int _sndSize;
private java.nio.channels.DatagramChannel _fd;
private java.net.InetSocketAddress _addr;
private java.net.InetSocketAddress _mcastAddr = null;
+ private java.net.InetSocketAddress _peerAddr = null;
//
// The maximum IP datagram size is 65535. Subtract 20 bytes for the IP header and 8 bytes for the UDP header
@@ -584,4 +624,8 @@ final class UdpTransceiver implements Transceiver
//
private final static int _udpOverhead = 20 + 8;
private final static int _maxPacketSize = 65535 - _udpOverhead;
+
+ private static final int StateNeedConnect = 0;
+ private static final int StateConnected = 1;
+ private static final int StateNotConnected = 2;
}