Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.refinitiv.eta.transport;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.ServerSocketChannel;
import java.util.Objects;
import com.refinitiv.eta.codec.Codec;
import static com.refinitiv.eta.transport.WebSocketFrameParser._WS_MAX_HEADER_LEN;
class ServerImpl extends EtaNode implements Server
{
public static final String OS_NAME = System.getProperty("os.name");
public static final String JAVA_VERSION = System.getProperty("java.version");
class SharedPool extends Pool
{
SharedPool(Object o)
{
super(o);
_isSharedPoolBuffer = true;
}
int _currentUse = 0; // number of shared buffers currently in use.
int _peakUse = 0; // peak number of shared buffers used.
int _sharedPoolBufferCount = 0; // number of shared pool buffers created.
Lock _sharedPoolLock;
@Override
void add(EtaNode node)
{
try
{
_sharedPoolLock.lock();
super.add(node);
--_currentUse;
}
finally
{
_sharedPoolLock.unlock();
}
}
EtaNode poll()
{
_sharedPoolLock.lock();
SocketBuffer buffer = null;
try
{
buffer = (SocketBuffer)super.poll();
if (buffer != null)
{
++_currentUse;
}
else if (_sharedPoolBufferCount < _bindOpts.sharedPoolSize())
{
// first create one buffer and use it
buffer = new SocketBuffer(this, bufferSize());
++_peakUse;
++_currentUse;
++_sharedPoolBufferCount;
// then create more buffers, as they should be added to pool in bulk
int buffersToAdd = ADDED_BUFFERS - 1;
if (buffersToAdd > _bindOpts.sharedPoolSize() - _currentUse)
buffersToAdd = _bindOpts.sharedPoolSize() - _currentUse;
for (int i = 0; i < buffersToAdd; i++)
{
EtaNode node;
node = new SocketBuffer(this, bufferSize());
++_sharedPoolBufferCount;
super.add(node);
}
}
if (_currentUse > _peakUse)
{
_peakUse = _currentUse;
}
}
finally
{
_sharedPoolLock.unlock();
}
return buffer;
}
int info(ServerInfo info, Error error)
{
int ret = TransportReturnCodes.SUCCESS;
try
{
_sharedPoolLock.lock();
if (_state == ChannelState.ACTIVE)
{
((ServerInfoImpl)info).currentBufferUsage(_currentUse);
((ServerInfoImpl)info).peakBufferUsage(_peakUse);
}
else
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("server not in active state ");
ret = TransportReturnCodes.FAILURE;
}
}
finally
{
_sharedPoolLock.unlock();
}
return ret;
}
int bufferUsage(Error error)
{
int ret;
try
{
_sharedPoolLock.lock();
if (_state == ChannelState.ACTIVE)
ret = _currentUse;
else
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("server not in active state ");
ret = TransportReturnCodes.FAILURE;
}
}
finally
{
_sharedPoolLock.unlock();
}
return ret;
}
void resetPeakUse()
{
_peakUse = _currentUse;
}
}
private static final int ADDED_BUFFERS = 100;
// memory management
final ProtocolInt _transport;
final Pool _sharedPool = new SharedPool(this);
final Lock _realSharedPoolLock = new ReentrantLock();
final Lock _dummySharedPoolLock = new DummyLock();
int _numChannels;
@SuppressWarnings("unused")
final private ServerInfo _serverInfo = new ServerInfoImpl(); // RsslServerInfo
BindOptionsImpl _bindOpts = new BindOptionsImpl();
private ServerSocketChannel _srvrScktChannel;
private Object _userSpecObject;
int _state;
private int _portNumber;
private int _connType;
ComponentInfo _componentInfo = new ComponentInfoImpl();
int _sessionId = 1;
private EncryptedContextHelper _context;
ServerImpl(ProtocolInt transport, Pool pool)
{
pool(pool);
_transport = transport;
_state = ChannelState.INACTIVE;
_componentInfo.componentVersion().data(Transport._defaultComponentVersionBuffer, 0,
Transport._defaultComponentVersionBuffer.limit());
_context = null;
}
int bind(BindOptions options, Error error)
{
int ret = TransportReturnCodes.SUCCESS;
// copy the bind options to data member
((BindOptionsImpl)options).copyTo(_bindOpts);
if(options.protocolType() == Codec.JSON_PROTOCOL_TYPE)
{
String errorText = "JSON Protocol Type not supported with options.protocolType()";
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text(errorText);
return TransportReturnCodes.FAILURE;
}
// validate specified WS protocols
final String protocols = _bindOpts.wSocketOpts().protocols();
final String wsProtocolCheckStr = WebSocketSupportedProtocols.validateProtocolList(protocols);
if (Objects.nonNull(wsProtocolCheckStr)) {
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("Invalid protocol found in protocol list. protocol: " + wsProtocolCheckStr);
return TransportReturnCodes.FAILURE;
}
_bindOpts.wSocketOpts().protocols(WebSocketHandlerImpl.constructProtocolList(protocols, true));
if (!checkServerSharedSocketProperty(options, error)){
return TransportReturnCodes.FAILURE;
}
_portNumber = _bindOpts.port();
_connType = _bindOpts.connectionType();
try
{
// first check if it's encrypted. If so, initialize the encrypted context helper
if(options.connectionType() == ConnectionTypes.ENCRYPTED)
{
_context = new EncryptedContextHelper(options);
}
// if configured, specify the interface name
InetSocketAddress socketAddress = null;
String interfaceName = _bindOpts.interfaceName();
if (interfaceName == null)
socketAddress = new InetSocketAddress(_portNumber);
else if (interfaceName.isEmpty())
socketAddress = new InetSocketAddress(_portNumber);
else if (interfaceName.equals("0") || interfaceName.equals("localhost")) {
socketAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), _portNumber);
} else {
socketAddress = new InetSocketAddress(interfaceName, _portNumber);
}
// create ServerSocketChannel
_srvrScktChannel = ServerSocketChannel.open();
if(options.serverSharedSocket())
{
enableServerSharedSocket();
}
_srvrScktChannel.configureBlocking(options.serverBlocking());
// sendBufSize will be set in accept via AcceptOptions
// for values larger than 64K, recvBufSize must be set prior to bind.
if (options.sysRecvBufSize() > 0)
_srvrScktChannel.socket().setReceiveBufferSize(options.sysRecvBufSize());
else if (_srvrScktChannel.socket().getReceiveBufferSize() > RsslSocketChannel.READ_RECEIVE_BUFFER_SIZE)
_srvrScktChannel.socket().setReceiveBufferSize(_srvrScktChannel.socket().getReceiveBufferSize());
else
_srvrScktChannel.socket().setReceiveBufferSize(RsslSocketChannel.READ_RECEIVE_BUFFER_SIZE);
_srvrScktChannel.socket().bind(socketAddress);
_state = ChannelState.ACTIVE;
// set shared pool lock
if (_bindOpts.sharedPoolLock())
((SharedPool)_sharedPool)._sharedPoolLock = _realSharedPoolLock;
else
((SharedPool)_sharedPool)._sharedPoolLock = _dummySharedPoolLock;
if(_bindOpts.componentVersion() != null)
{
try
{
Transport._globalLock.lock();
// user specified info was passed in through the bind Opts
byte divider = (byte)'|';
ByteBuffer connectOptsCompVerBB = ByteBuffer.wrap(_bindOpts.componentVersion().getBytes());
int totalLength = connectOptsCompVerBB.limit() + 1 + Transport._defaultComponentVersionBuffer.limit();
if (totalLength > 253)
{
// the total component data length is too long, so truncate the user defined data
totalLength = 253;
connectOptsCompVerBB.limit(253 - Transport._defaultComponentVersionBuffer.limit() - 1);
}
// append the user defined connect opts componentVersionInfo to the default value
ByteBuffer combinedBuf = ByteBuffer.allocate(totalLength);
Transport._defaultComponentVersionBuffer.mark();
combinedBuf.put(Transport._defaultComponentVersionBuffer);
Transport._defaultComponentVersionBuffer.reset();
combinedBuf.put(divider);
combinedBuf.put(connectOptsCompVerBB);
// the combined length of the new buffer includes the user defined data, the '|', and the default component version data
_componentInfo.componentVersion().data(combinedBuf, 0, totalLength);
}
finally
{
Transport._globalLock.unlock();
}
}
}
catch (Exception e)
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text(e.getMessage());
ret = TransportReturnCodes.FAILURE;
}
return ret;
}
private boolean checkServerSharedSocketProperty(BindOptions options, Error error)
{
if (options.serverSharedSocket() && System.getProperty("os.name").toLowerCase().contains("windows") &&
Boolean.parseBoolean(System.getProperty("sun.net.useExclusiveBind", "true")))
{
String errorText = "Failed to initialize Server. " +
"serverSharedSocket option is set to true, but system property " +
"sun.net.useExclusiveBind is not set to false on Windows platform. " +
"sun.net.useExclusiveBind property must be set to false " +
"when serverSharedSocket option is enabled.";
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text(errorText);
return false;
}
return true;
}
private void enableServerSharedSocket() throws SocketException
{
if (OS_NAME.toLowerCase().contains("windows"))
{
enableServerSharedSocketWindows();
}
else if (OS_NAME.toLowerCase().contains("linux"))
{
enableServerSharedSocketLinux();
}
}
private void enableServerSharedSocketLinux() throws SocketException
{
try
{
Class> optionsClass = Class.forName("java.net.StandardSocketOptions");
Field field = optionsClass.getDeclaredField("SO_REUSEPORT");
@SuppressWarnings("unchecked")
SocketOption optionValue = (SocketOption) field.get(null);
_srvrScktChannel.setOption(optionValue, true);
}
catch (ClassCastException | NoSuchFieldException | ClassNotFoundException | IllegalAccessException | IOException e)
{
throw new SocketException("Error occurred when trying to set SO_REUSEPORT: " + e + "."
+ " Flag serverSharedSocket is not supported by OS " + OS_NAME + " with java version " + JAVA_VERSION);
}
}
private void enableServerSharedSocketWindows() throws SocketException
{
_srvrScktChannel.socket().setReuseAddress(true);
}
@Override
public Channel accept(AcceptOptions options, Error error)
{
if (_state != ChannelState.ACTIVE)
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket not in active state");
return null;
}
RsslSocketChannel channel = null;
java.nio.channels.SocketChannel socketChannel = null;
try
{
Transport._globalLock.lock();
socketChannel = _srvrScktChannel.accept();
if (socketChannel == null) {
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("This channel is in non-blocking mode and no connection is available to be accepted");
return null;
}
// sysRecvBufSize would have been set in bind(), no need to repeat.
if (options.sysSendBufSize() > 0)
socketChannel.socket().setSendBufferSize(options.sysSendBufSize());
else if (socketChannel.socket().getSendBufferSize() > RsslSocketChannel.READ_RECEIVE_BUFFER_SIZE)
// set send buffer size to system default.
socketChannel.socket().setSendBufferSize(socketChannel.socket().getSendBufferSize());
else
// set send buffer size to default.
socketChannel.socket().setSendBufferSize(RsslSocketChannel.READ_RECEIVE_BUFFER_SIZE);
if (_bindOpts.channelsBlocking())
{
socketChannel.configureBlocking(true);
}
else
{
socketChannel.configureBlocking(false);
}
if (_bindOpts.tcpOpts().tcpNoDelay())
{
socketChannel.socket().setTcpNoDelay(true);
}
channel = (RsslSocketChannel)_transport.channel(options, this, socketChannel, error);
/* Give our Component Info to the Channel.
* No need for deep copies here since the channel will never re-connect.
* The channel can simply use our Component Info. */
if (channel != null)
{
channel._componentInfo = ((ComponentInfoImpl)_componentInfo).clone();
if (channel._providerSessionId == null)
{
channel._providerSessionId = Integer.valueOf(_sessionId);
_sessionId++;
}
}
}
catch (Exception e)
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket IO Exception");
try
{
socketChannel.close();
}
catch (IOException e1)
{
}
socketChannel = null;
channel = null;
}
finally
{
Transport._globalLock.unlock();
}
return channel;
}
BindOptions bindOptions()
{
return _bindOpts;
}
@Override
public String toString()
{
return "Server" + "\n" +
"\tsrvrScktChannel: " + _srvrScktChannel + "\n" +
"\tstate: " + _state + "\n" +
"\tportNumber: " + _portNumber + "\n" +
"\tuserSpecObject: " + _userSpecObject + "\n";
}
@Override
public int info(ServerInfo info, Error error)
{
return ((SharedPool)_sharedPool).info(info, error);
}
@Override
public int ioctl(int code, Object value, Error error)
{
int retCode = TransportReturnCodes.FAILURE;
try
{
((SharedPool)_sharedPool)._sharedPoolLock.lock();
// return FAILURE if channel not active or not initializing
if ((_state != ChannelState.ACTIVE) && (_state != ChannelState.INITIALIZING))
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket channel is not in the active or initializing state");
return TransportReturnCodes.FAILURE;
}
switch (code)
{
case IoctlCodes.COMPONENT_INFO:
{
if (value != null && (value.getClass() == ComponentInfoImpl.class))
{
_componentInfo = ((ComponentInfoImpl)value).clone();
retCode = TransportReturnCodes.SUCCESS;
}
else
{
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("Code is not valid.");
}
break;
}
case IoctlCodes.SERVER_PEAK_BUF_RESET:
((SharedPool)_sharedPool).resetPeakUse();
retCode = TransportReturnCodes.SUCCESS;
break;
default:
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("Code is not valid.");
}
}
finally
{
((SharedPool)_sharedPool)._sharedPoolLock.unlock();
}
return retCode;
}
@Override
public int ioctl(int code, int value, Error error)
{
int retCode = TransportReturnCodes.FAILURE;
try
{
((SharedPool)_sharedPool)._sharedPoolLock.lock();
// return FAILURE if channel not active or not initializing
if ((_state != ChannelState.ACTIVE) && (_state != ChannelState.INITIALIZING))
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket channel is not in the active or initializing state");
return TransportReturnCodes.FAILURE;
}
switch (code)
{
case IoctlCodes.SERVER_NUM_POOL_BUFFERS:
{
/* SERVER_NUM_POOL_BUFFERS: the per server number of
* sharedPool buffers that ETAJ will share with channels of a server. */
if (value > 0)
{
retCode = adjustSharedPoolBuffers(value);
}
else
{
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("value must be greater than zero");
}
break;
}
case IoctlCodes.SYSTEM_READ_BUFFERS:
{
if (value >= 0)
{
_srvrScktChannel.socket().setReceiveBufferSize(value);
retCode = TransportReturnCodes.SUCCESS;
}
else
{
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("value must be (0 >= value < 2^31");
}
break;
}
default:
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("Code is not valid.");
}
}
catch (SocketException e)
{
_state = ChannelState.CLOSED;
error.channel(null);
error.errorId(retCode);
error.sysError(0);
error.text("failed to set SYSTEM_WRITE_BUFFERS, " + e.toString());
}
finally
{
((SharedPool)_sharedPool)._sharedPoolLock.unlock();
}
return retCode;
}
/* Shrink the sharedPool by numToShrink.
* Do this by adding numToShrink sharedPool to global pool (SocketProtocol).
*
* Returns the number actually shrunk, which may not be the numToShrink.
*/
int shrinkSharedPoolBuffers(int numToShrink)
{
Pool bufferPool = _transport.getPool(bufferSize());
return bufferPool.add(_sharedPool, numToShrink);
}
/* 1) If the value is larger than the current value, update the sharedPoolSize only.
* 2) If the new value is smaller than the current value,
* attempt to shrink the buffers by returning them to the global pool.
* If the number of available buffers (not in use) is smaller than
* what needs to be returned (because the buffers are being used),
* just shrink by that number.
*
* Returns the new value of sharedPoolSize
*/
int adjustSharedPoolBuffers(int value)
{
int diff = value - _bindOpts._sharedPoolSize;
if (diff > 0)
{
// the new value is larger, update sharedPoolSize.
return _bindOpts._sharedPoolSize = value;
}
else if (diff < 0)
{
// shrink buffers
return _bindOpts._sharedPoolSize -= shrinkSharedPoolBuffers(diff * -1);
}
else
{
// nothing changed.
return _bindOpts._sharedPoolSize;
}
}
@Override
public int bufferUsage(Error error)
{
return ((SharedPool)_sharedPool).bufferUsage(error);
}
@Override
public int close(Error error)
{
if (_state != ChannelState.INACTIVE)
{
_state = ChannelState.INACTIVE;
}
else
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket channel is already inactive ");
return TransportReturnCodes.FAILURE;
}
int ret = TransportReturnCodes.SUCCESS;
try
{
_state = ChannelState.INACTIVE;
_srvrScktChannel.close();
if (_numChannels == 0)
releaseServer();
}
catch (IOException e)
{
error.channel(null);
error.errorId(TransportReturnCodes.FAILURE);
error.sysError(0);
error.text("socket server close failed ");
ret = TransportReturnCodes.FAILURE;
}
return ret;
}
@Override @Deprecated
public ServerSocketChannel srvrScktChannel()
{
return _srvrScktChannel;
}
@Override
public SelectableChannel selectableChannel()
{
return _srvrScktChannel;
}
@Override
public int portNumber()
{
return _portNumber;
}
public int connectionType()
{
return _connType;
}
@Override
public Object userSpecObject()
{
return _userSpecObject;
}
int bufferSize()
{
/* This buffer size is used internal and represents the size of the buffers that are used internally.
* The size will be the RIPC MAX_USER_MSG_SIZE + RIPC_HDR_SIZE + _WS_MAX_HEADER_LEN.
* The RIPC MAX_USER_MSG_SIZE is the bindOps.maxFragmentSize().
* Note that this value is different from _channelInfo._maxFragmentSize,
* which is returned to the user and is RIPC MAX_USER_MSG_SIZE - RIPC PACKED_HDR_SIZE - _WS_MAX_HEADER_LEN. */
return _bindOpts.jsonMaxFragmentSize() + RsslSocketChannel.RIPC_HDR_SIZE + _WS_MAX_HEADER_LEN;
}
SocketBuffer getBufferFromServerPool()
{
return (SocketBuffer)((SharedPool)_sharedPool).poll();
}
void socketBufferToRecycle(SocketBuffer buffer)
{
buffer.returnToPool();
}
void removeChannel(Channel chnl)
{
_numChannels--;
if (_numChannels == 0)
{
if (_state == ChannelState.INACTIVE)
releaseServer();
}
}
void removeChannel()
{
_numChannels--;
if (_numChannels == 0)
{
if (_state == ChannelState.INACTIVE)
releaseServer();
}
}
private void releaseServer()
{
try
{
Transport._globalLock.lock();
// return buffers from the shared pool to global pool
Pool pool = _transport.getPool(bufferSize());
pool.add(_sharedPool, _sharedPool.size());
// return this server to server pool
returnToPool();
}
finally
{
Transport._globalLock.unlock();
}
}
@Override
public int state()
{
return _state;
}
public EncryptedContextHelper context() {
return _context;
}
}