// **********************************************************************
//
// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
package IceInternal;
final class TcpTransceiver implements Transceiver
{
public java.nio.channels.SelectableChannel
fd()
{
assert(_fd != null);
return _fd;
}
public int
initialize()
{
if(_state == StateNeedConnect)
{
_state = StateConnectPending;
return SocketOperation.Connect;
}
else if(_state <= StateConnectPending)
{
try
{
Network.doFinishConnect(_fd);
_state = StateConnected;
_desc = Network.fdToString(_fd);
}
catch(Ice.LocalException ex)
{
if(_traceLevels.network >= 2)
{
String s = "failed to establish tcp connection\n" + _desc + "\n" + ex;
_logger.trace(_traceLevels.networkCat, s);
}
throw ex;
}
if(_traceLevels.network >= 1)
{
String s = "tcp connection established\n" + _desc;
_logger.trace(_traceLevels.networkCat, s);
}
}
assert(_state == StateConnected);
return SocketOperation.None;
}
public void
close()
{
if(_state == StateConnected && _traceLevels.network >= 1)
{
String s = "closing tcp connection\n" + toString();
_logger.trace(_traceLevels.networkCat, s);
}
assert(_fd != null);
try
{
_fd.close();
}
catch(java.io.IOException ex)
{
Ice.SocketException se = new Ice.SocketException();
se.initCause(ex);
throw se;
}
finally
{
_fd = null;
}
}
public boolean
write(Buffer buf)
{
final int size = buf.b.limit();
int packetSize = size - buf.b.position();
//
// Limit packet size to avoid performance problems on WIN32
//
if(_maxSendPacketSize > 0 && packetSize > _maxSendPacketSize)
{
packetSize = _maxSendPacketSize;
buf.b.limit(buf.b.position() + packetSize);
}
while(buf.b.hasRemaining())
{
try
{
assert(_fd != null);
int ret = _fd.write(buf.b);
if(ret == -1)
{
throw new Ice.ConnectionLostException();
}
else if(ret == 0)
{
//
// Writing would block, so we reset the limit (if necessary) and return true to indicate
// that more data must be sent.
//
if(packetSize == _maxSendPacketSize)
{
buf.b.limit(size);
}
return false;
}
if(_traceLevels.network >= 3)
{
String s = "sent " + ret + " of " + packetSize + " bytes via tcp\n" + toString();
_logger.trace(_traceLevels.networkCat, s);
}
if(_stats != null)
{
_stats.bytesSent(type(), ret);
}
if(packetSize == _maxSendPacketSize)
{
assert(buf.b.position() == buf.b.limit());
packetSize = size - buf.b.position();
if(packetSize > _maxSendPacketSize)
{
packetSize = _maxSendPacketSize;
}
buf.b.limit(buf.b.position() + packetSize);
}
}
catch(java.io.InterruptedIOException ex)
{
continue;
}
catch(java.io.IOException ex)
{
Ice.SocketException se = new Ice.SocketException();
se.initCause(ex);
throw se;
}
}
return true;
}
public boolean
read(Buffer buf, Ice.BooleanHolder moreData)
{
int packetSize = buf.b.remaining();
moreData.value = false;
while(buf.b.hasRemaining())
{
try
{
assert(_fd != null);
int ret = _fd.read(buf.b);
if(ret == -1)
{
throw new Ice.ConnectionLostException();
}
if(ret == 0)
{
return false;
}
if(ret > 0)
{
if(_traceLevels.network >= 3)
{
String s = "received " + ret + " of " + packetSize + " bytes via tcp\n" + toString();
_logger.trace(_traceLevels.networkCat, s);
}
if(_stats != null)
{
_stats.bytesReceived(type(), ret);
}
}
packetSize = buf.b.remaining();
}
catch(java.io.InterruptedIOException ex)
{
continue;
}
catch(java.io.IOException ex)
{
Ice.ConnectionLostException se = new Ice.ConnectionLostException();
se.initCause(ex);
throw se;
}
}
return true;
}
public String
type()
{
return "tcp";
}
public String
toString()
{
return _desc;
}
public Ice.ConnectionInfo
getInfo()
{
assert(_fd != null);
Ice.TCPConnectionInfo info = new Ice.TCPConnectionInfo();
java.net.Socket socket = _fd.socket();
info.localAddress = socket.getLocalAddress().getHostAddress();
info.localPort = socket.getLocalPort();
if(socket.getInetAddress() != null)
{
info.remoteAddress = socket.getInetAddress().getHostAddress();
info.remotePort = socket.getPort();
}
else
{
info.remoteAddress = "";
info.remotePort = -1;
}
return info;
}
public void
checkSendSize(Buffer buf, int messageSizeMax)
{
if(buf.size() > messageSizeMax)
{
Ex.throwMemoryLimitException(buf.size(), messageSizeMax);
}
}
//
// Only for use by TcpConnector, TcpAcceptor
//
TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd, boolean connected)
{
_fd = fd;
_traceLevels = instance.traceLevels();
_logger = instance.initializationData().logger;
_stats = instance.initializationData().stats;
_state = connected ? StateConnected : StateNeedConnect;
_desc = Network.fdToString(_fd);
_maxSendPacketSize = 0;
if(System.getProperty("os.name").startsWith("Windows"))
{
//
// On Windows, limiting the buffer size is important to prevent
// poor throughput performances when transfering large amount of
// data. See Microsoft KB article KB823764.
//
_maxSendPacketSize = Network.getSendBufferSize(_fd) / 2;
if(_maxSendPacketSize < 512)
{
_maxSendPacketSize = 0;
}
}
}
protected synchronized void
finalize()
throws Throwable
{
IceUtilInternal.Assert.FinalizerAssert(_fd == null);
super.finalize();
}
private java.nio.channels.SocketChannel _fd;
private TraceLevels _traceLevels;
private Ice.Logger _logger;
private Ice.Stats _stats;
private String _desc;
private int _state;
private int _maxSendPacketSize;
private static final int StateNeedConnect = 0;
private static final int StateConnectPending = 1;
private static final int StateConnected = 2;
}