455 lines
19 KiB
Java
455 lines
19 KiB
Java
package com.eactive.eai.adapter.socket.service;
|
|
|
|
import com.eactive.eai.adapter.socket.common.CommonLib;
|
|
import com.eactive.eai.adapter.socket.common.DiagLogger;
|
|
import com.eactive.eai.adapter.socket.common.SocketAdapterException;
|
|
import com.eactive.eai.adapter.socket.config.ConfigurationContext;
|
|
import com.eactive.eai.adapter.socket.config.SocketAdapterManager;
|
|
import com.eactive.eai.common.property.PropManager;
|
|
import com.eactive.eai.common.util.Logger;
|
|
|
|
import java.io.IOException;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.ServerSocket;
|
|
import java.net.Socket;
|
|
import java.nio.channels.SelectionKey;
|
|
import java.nio.channels.Selector;
|
|
import java.nio.channels.ServerSocketChannel;
|
|
import java.nio.channels.SocketChannel;
|
|
import java.util.Iterator;
|
|
import java.util.Vector;
|
|
|
|
import java.nio.channels.ClosedSelectorException;
|
|
import java.util.HashMap;
|
|
|
|
|
|
public class SocketServer extends Thread implements SocketService {
|
|
|
|
private ConfigurationContext context;
|
|
private Vector<SocketService> threadPool;
|
|
private boolean active;
|
|
private Selector selector;
|
|
private ServerSocketChannel serverSocketChannel;
|
|
private ServerSocket serverSocket;
|
|
private Logger logger;
|
|
private HashMap<String, Integer> ipTable; // IP별 Connection 수 제한이 있는 경우 , KEY-RemoteIP, VALUE-Integer
|
|
|
|
//소켓 관련 프라퍼티 정보
|
|
public static final String PROP_GROUP_SOCKET = "socket";
|
|
public static final String PROP_BLOCK_IP_LIST = "block.ip.list"; //연결 거부 IP 리스트
|
|
public static final String PROP_BLOCK_SLEEP = "sleep.time"; //close 하기 전에 대기 시간
|
|
|
|
public SocketServer(ConfigurationContext context) {
|
|
String name = this.getName();
|
|
this.setName( context.getAdapterName() + "-LISTENER" + name.substring( name.lastIndexOf("-")) );
|
|
|
|
this.context = context;
|
|
active = true;
|
|
threadPool = new Vector<SocketService>();
|
|
logger = (Logger) SocketLogManager.getInstance().getLogger( this.context.getAdapterGroupName() );
|
|
ipTable = new HashMap<String, Integer>();
|
|
}
|
|
|
|
private int getTraceLevel() {
|
|
return context.getTraceLevel();
|
|
}
|
|
|
|
public void run() {
|
|
// Server Socket을 기동하는 순간 Connection없음을 나타내도록 Adapter Status를 false로 변경한다.
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, false);
|
|
try {
|
|
openSelector();
|
|
} catch(IOException e) {
|
|
logger.error(CommonLib.getMessage("BECEAIMSA029", new String[] { context.getAdapterName(), context.getHostName() + ":" + context.getPortNumber(), e.getMessage() } ), e);
|
|
active = false;
|
|
SocketAdapterManager.getInstance().stop( context.getAdapterGroupName(), context.getAdapterName() );
|
|
}
|
|
|
|
Iterator<SelectionKey> it;
|
|
SocketChannel channel;
|
|
SelectionKey key;
|
|
while ( active ) {
|
|
try {
|
|
// select(miliseconds) : 대기시간
|
|
int i = selector.select(2000L);
|
|
if(i == 0) {
|
|
if ( threadPool == null || threadPool.size() == 0 ) {
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, false );
|
|
}
|
|
continue;
|
|
}
|
|
} catch(IOException e) {
|
|
active = false;
|
|
shutdown();
|
|
break;
|
|
} catch( ClosedSelectorException e ) {
|
|
} catch( Exception e ) {
|
|
continue;
|
|
}
|
|
|
|
if ( selector == null || !selector.isOpen() ) break;
|
|
|
|
it = selector.selectedKeys().iterator();
|
|
|
|
while( it.hasNext() ) {
|
|
// 소켓 서버로 연결 요청이 있는 경우.
|
|
try {
|
|
key = it.next();
|
|
it.remove();
|
|
if ( !key.isValid() ) continue;
|
|
ServerSocketChannel server = (ServerSocketChannel)key.channel();
|
|
if ( !server.isOpen() ){
|
|
continue;
|
|
}
|
|
|
|
channel = server.accept();
|
|
|
|
if(channel == null) continue;
|
|
|
|
// L4에서 보내온 세션인 경우
|
|
String remoteIp = channel.socket().getRemoteSocketAddress().toString().substring(1,channel.socket().getRemoteSocketAddress().toString().indexOf(":") );
|
|
String blockIpList = PropManager.getInstance().getProperty(PROP_GROUP_SOCKET, PROP_BLOCK_IP_LIST);
|
|
|
|
if (( blockIpList != null) && ( blockIpList.indexOf(remoteIp) > -1 ) ) {
|
|
|
|
try {
|
|
long delayTime = 1000;
|
|
try {
|
|
delayTime = Long.parseLong(PropManager.getInstance().getProperty(PROP_GROUP_SOCKET, PROP_BLOCK_SLEEP));
|
|
} catch (Exception e) {}
|
|
if ( delayTime > 0 )
|
|
Thread.sleep(delayTime);
|
|
channel.socket().close();
|
|
channel.close();
|
|
} catch(IOException ie) {}
|
|
continue;
|
|
}
|
|
|
|
if ( context.getMaxConnection() > 0 && context.getMaxConnection() <= threadPool.size() ) {
|
|
try {
|
|
for ( int inx = 0; inx < threadPool.size(); inx++){
|
|
SocketService oldService = threadPool.get(inx);
|
|
if ( oldService.isActive()){
|
|
logger.warn( CommonLib.getMessage("BECEAIMSA022", new String[]{ context.getAdapterName(), Integer.toString( context.getMaxConnection() ),this.getSocketInfo( oldService.getCurrentSocket() ) } ) );
|
|
oldService.shutdown();
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
logger.error( e.getMessage(), e);
|
|
}
|
|
}
|
|
// Client Socket별 (REMOTE IP) Connection 수 제한 있는 경우
|
|
if ( context.getConnLimitPerIp() > 0 ) {
|
|
String ip = channel.socket().getInetAddress().getHostAddress();
|
|
Integer connCount = ipTable.get( ip );
|
|
if ( connCount == null ) {
|
|
ipTable.put( ip, new Integer( 1 ) );
|
|
} else if ( connCount.intValue() < context.getConnLimitPerIp() ) {
|
|
int newCount = connCount.intValue() + 1;
|
|
ipTable.put( ip, new Integer( newCount ));
|
|
} else {
|
|
logger.error( CommonLib.getMessage("BECEAIMSA023", new String[]{ context.getAdapterName(), Integer.toString( context.getConnLimitPerIp() ),this.getSocketInfo( channel ) } ) );
|
|
try {
|
|
channel.socket().close();
|
|
channel.close();
|
|
} catch(IOException ie) {}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( getTraceLevel() >= DiagLogger.INFO ) {
|
|
logger.info( CommonLib.getMessage("BICEAIMSA033", new String[]{ context.getAdapterName(), this.getSocketInfo( channel ) } ) );
|
|
}
|
|
|
|
if ( this.context.isSocketReuse() ) {
|
|
channel.socket().setSoLinger(true, 100);
|
|
}
|
|
|
|
// 신규 Connection Process 쓰레드를 생성 후 수행시킨다...
|
|
if ( isForInbound() && context.getSocketType().equals( ConfigurationContext.SERVER_SOCKET ) ) {
|
|
InboundServer aProcess = new InboundServer(context, channel, this);
|
|
logger.debug("# INBOUND SOCKETSERVER CREATED.[" + this.getName() + "]");
|
|
//
|
|
threadPool.addElement( aProcess );
|
|
aProcess.start();
|
|
logger.debug("# INBOUND SOCKETSERVER STARTED.[" + this.getName() + "]");
|
|
synchronized ( threadPool ) {
|
|
if ( threadPool.size() == 1 ) {
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, true );
|
|
}
|
|
}
|
|
} else if ( isForOutbound() ) {
|
|
// OutboundServer aProcess = new OutboundServer(context, channel, this);
|
|
// logger.debug("# OUTBOUND SOCKETSERVER CREATED.[" + this.getName() + "]");
|
|
// if ( !OutboundChannelManager.getInstance().hasChannel( context.getAdapterGroupName() )) {
|
|
// OutboundChannel connection = new OutboundChannel(context.getSessionTimeout()*1000);
|
|
// OutboundChannelManager.getInstance().addConnectionGroup( context.getAdapterGroupName(), connection );
|
|
// }
|
|
// threadPool.addElement( aProcess );
|
|
// aProcess.start();
|
|
// logger.debug("# OUTBOUND SOCKETSERVER STARTED.[" + this.getName() + "]");
|
|
// synchronized ( threadPool ) {
|
|
// if ( threadPool.size() == 1 ) {
|
|
// SocketAdapterManager.getInstance().changeAdapterStatus( this, true );
|
|
// }
|
|
// }
|
|
} else if ( isForIobound() ) {
|
|
IOboundServer aProcess = new IOboundServer(context, channel, this);
|
|
logger.debug("# IOBOUND SOCKETSERVER CREATED.[" + this.getName() + "]");
|
|
if ( !OutboundChannelManager.getInstance().hasChannel( context.getAdapterGroupName() )) {
|
|
OutboundChannel connection = new OutboundChannel(context.getSessionTimeout()*1000);
|
|
OutboundChannelManager.getInstance().addConnectionGroup( context.getAdapterGroupName(), connection );
|
|
}
|
|
threadPool.addElement( aProcess );
|
|
aProcess.start();
|
|
logger.debug("# IOBOUND SOCKETSERVER STARTED.[" + this.getName() + "]");
|
|
synchronized ( threadPool ) {
|
|
if ( threadPool.size() == 1 ) {
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, true );
|
|
}
|
|
}
|
|
// } else {
|
|
// AdminServer aProcess = new AdminServer(context, channel, this);
|
|
// logger.debug("# ADMIN SOCKETSERVER CREATED.[" + this.getName() + "]");
|
|
// threadPool.addElement( aProcess );
|
|
// aProcess.start();
|
|
// logger.debug("# ADMIN SOCKETSERVER STARTED.[" + this.getName() + "]");
|
|
// synchronized ( threadPool ) {
|
|
// if ( threadPool.size() == 1 ) {
|
|
// SocketAdapterManager.getInstance().changeAdapterStatus( this, true );
|
|
// }
|
|
// }
|
|
}
|
|
// Process 쓰레드 Started
|
|
} catch(Exception e) {
|
|
logger.error(CommonLib.getMessage("BECEAIMSA030", new String[] { context.getAdapterName(), e.getMessage() } ), e);
|
|
logger.error( e.getMessage(), e);
|
|
}
|
|
} // End of While - it.hasNext
|
|
} // End of While - active
|
|
|
|
try {
|
|
closeSelector();
|
|
} catch( Throwable e ) {}
|
|
|
|
interrupt();
|
|
} // end of startup ...
|
|
|
|
public String getRemoteIPAddress() {
|
|
return null;
|
|
}
|
|
|
|
public Socket getCurrentSocket() {
|
|
return null;
|
|
}
|
|
|
|
public boolean idle(long timeout) {
|
|
return false;
|
|
}
|
|
|
|
public boolean connect() {
|
|
return true;
|
|
}
|
|
|
|
public void disconnect() {
|
|
}
|
|
|
|
|
|
public int getCurrentState() {
|
|
return CommonLib.PROCESSING_PROTOCOL;
|
|
}
|
|
|
|
public boolean isConnected() {
|
|
return true;
|
|
}
|
|
|
|
public void checkActivity() {
|
|
}
|
|
|
|
public synchronized void shutdown() {
|
|
|
|
active = false;
|
|
if ( threadPool != null ) {
|
|
for ( int i=0; i < threadPool.size(); i++ ) {
|
|
try {
|
|
SocketService service = (SocketService)threadPool.get(i);
|
|
|
|
if ( getTraceLevel() >= DiagLogger.INFO ) {
|
|
try {
|
|
logger.info( CommonLib.getMessage("BICEAIMSA031", new String[]{ context.getAdapterName(), this.getSocketInfo( service.getCurrentSocket() )} ) );
|
|
} catch( Exception e ) {}
|
|
}
|
|
service.shutdown();
|
|
} catch( Throwable e ) {logger.error( e.getMessage(), e);}
|
|
}
|
|
}
|
|
|
|
threadPool = null;
|
|
try {
|
|
closeSelector();
|
|
} catch (Throwable t) {logger.error( t.getMessage(), t);}
|
|
|
|
try {
|
|
serverSocket.close();
|
|
} catch (Throwable t) {logger.error( t.getMessage(), t);}
|
|
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, false );
|
|
//*interrupt();
|
|
}
|
|
/**
|
|
* @return Returns the context.
|
|
*/
|
|
public ConfigurationContext getContext() {
|
|
return context;
|
|
}
|
|
/**
|
|
* @return Returns the active.
|
|
*/
|
|
public boolean isActive() {
|
|
return active;
|
|
}
|
|
|
|
public void notifyMessage() {
|
|
}
|
|
|
|
public void setControl(Object control) {
|
|
}
|
|
|
|
public void setLastActivity() {
|
|
}
|
|
|
|
private String getSocketInfo(SocketChannel channel) {
|
|
StringBuffer connInfo = new StringBuffer();
|
|
|
|
connInfo.append("Local Address=");
|
|
connInfo.append( channel.socket().getLocalAddress().getHostAddress()).append(":").append(channel.socket().getLocalPort()).append(", ");
|
|
connInfo.append("Remote Address=");
|
|
connInfo.append( channel.socket().getInetAddress().getHostAddress()).append(":").append(channel.socket().getPort());
|
|
|
|
return connInfo.toString();
|
|
}
|
|
|
|
private String getSocketInfo(Socket socket) {
|
|
StringBuffer connInfo = new StringBuffer();
|
|
|
|
if ( socket != null ) {
|
|
connInfo.append("Local Address=");
|
|
connInfo.append( socket.getLocalAddress().getHostAddress()).append(":").append(socket.getLocalPort()).append(", ");
|
|
connInfo.append("Remote Address=");
|
|
connInfo.append( socket.getInetAddress().getHostAddress()).append(":").append(socket.getPort());
|
|
}else {
|
|
connInfo.append("SOCKET IS NULL");
|
|
}
|
|
|
|
return connInfo.toString();
|
|
}
|
|
|
|
private boolean isForInbound() {
|
|
return ( this.context.getBoundUsage().equals( ConfigurationContext.INBOUND_SOCKET ));
|
|
}
|
|
|
|
private boolean isForIobound() {
|
|
return ( this.context.getBoundUsage().equals( ConfigurationContext.IOBOUND_SOCKET ));
|
|
}
|
|
|
|
private boolean isForOutbound() {
|
|
return ( this.context.getBoundUsage().equals( ConfigurationContext.OUTBOUND_SOCKET ));
|
|
}
|
|
|
|
public synchronized void quiesceShutdown(SocketService service) {
|
|
if ( threadPool == null ) return;
|
|
|
|
for ( int i=0; i < threadPool.size(); i++) {
|
|
SocketService aService = (SocketService) threadPool.elementAt( i );
|
|
if ( service != aService ) continue;
|
|
//service.shutdown();
|
|
if ( context.getConnLimitPerIp() > 0 ) {
|
|
String ip = service.getRemoteIPAddress();
|
|
if ( ip != null ) {
|
|
Integer connCount = (Integer)ipTable.get( ip );
|
|
if ( connCount != null ) {
|
|
int newCount = connCount.intValue() - 1;
|
|
if ( newCount < 0 ) newCount = 0;
|
|
|
|
ipTable.put( ip, new Integer( newCount ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
threadPool.remove(i);
|
|
break;
|
|
}
|
|
// Adapter status 변경
|
|
if ( threadPool == null || threadPool.size() == 0 ) {
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, false );
|
|
}
|
|
}
|
|
|
|
private void openSelector() throws IOException {
|
|
|
|
serverSocketChannel = ServerSocketChannel.open();
|
|
serverSocket = serverSocketChannel.socket();
|
|
selector = Selector.open();
|
|
|
|
if( context.getHostName() == null || context.getHostName().equals("*") || context.getHostName().equals("") || context.getHostName().equals("localhost")
|
|
|| context.getHostName().equals("0.0.0.0") || context.getHostName().equals("127.0.0.1") ) {
|
|
serverSocket.bind(new InetSocketAddress(context.getPortNumber()), 1024);
|
|
if ( getTraceLevel() >= DiagLogger.INFO ) {
|
|
logger.info( CommonLib.getMessage("BICEAIMSA032", new String[]{ context.getAdapterName(), context.getHostName(), Integer.toString(context.getPortNumber()) }) );
|
|
}
|
|
} else {
|
|
serverSocket.bind(new InetSocketAddress(context.getHostName(), context.getPortNumber()), 1024);
|
|
if ( getTraceLevel() >= DiagLogger.INFO ) {
|
|
logger.info( CommonLib.getMessage("BICEAIMSA032", new String[]{ context.getAdapterName(), context.getHostName(), Integer.toString(context.getPortNumber()) }) );
|
|
}
|
|
}
|
|
|
|
serverSocketChannel.configureBlocking(false);
|
|
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
|
|
|
|
synchronized ( threadPool ) {
|
|
if ( threadPool.size() == 0 ) {
|
|
SocketAdapterManager.getInstance().changeAdapterStatus( this, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
private void closeSelector() throws IOException {
|
|
|
|
if(selector != null) {
|
|
for(Iterator<SelectionKey> iterator = selector.keys().iterator(); iterator.hasNext();)
|
|
try {
|
|
SelectionKey selectionkey = iterator.next();
|
|
ServerSocketChannel serversocketchannel = (ServerSocketChannel)selectionkey.channel();
|
|
selectionkey.cancel();
|
|
serversocketchannel.socket().close();
|
|
serversocketchannel.close();
|
|
iterator.remove();
|
|
}catch(UnsupportedOperationException e) {
|
|
// Do nothing!!!
|
|
}catch(IOException e) {
|
|
logger.error( e.getMessage(), e);
|
|
}catch(Exception e) {
|
|
logger.error( e.getMessage(), e);
|
|
}
|
|
selector.close();
|
|
}
|
|
} // end of closeSelector...
|
|
|
|
public void disconnect(String localHostname, int localPortNumber)
|
|
throws SocketAdapterException {
|
|
}
|
|
|
|
public void setContext(ConfigurationContext context) {
|
|
this.context = context;
|
|
}
|
|
|
|
public long getFirstActivity() {
|
|
return 0;
|
|
}
|
|
|
|
public long getLastActivity() {
|
|
return 0;
|
|
}
|
|
}
|