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 threadPool; private boolean active; private Selector selector; private ServerSocketChannel serverSocketChannel; private ServerSocket serverSocket; private Logger logger; private HashMap 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(); logger = (Logger) SocketLogManager.getInstance().getLogger( this.context.getAdapterGroupName() ); ipTable = new HashMap(); } 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 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 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; } }