package pctelelog; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ChannelFactory; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.oio.OioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.oio.OioDatagramChannel; import io.netty.util.concurrent.GlobalEventExecutor; import java.net.*; import java.util.Enumeration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class TeleLogServer { public enum RESULT { TCP_BIND_EXCEPTION, MULTI_BIND_EXCEPTION, OTHER_EXCEPTION, SUCCESS; /** * Set the throwable cause for the current status */ private Throwable m_cause = null; public RESULT cause(Throwable cause) { this.m_cause = cause; return this; } public Throwable getCause() { return m_cause; } } private static final Logger logger = LogManager.getLogger(TeleLogServer.class); public static final int TCP_LISTEN_PORT = 43212; public static final int MULTI_LIST_PORT = 43213; private DefaultChannelGroup m_pool = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); private ChannelFuture m_tcpFuture = null; private ChannelFuture m_multiFuture = null; private NioEventLoopGroup m_tcpEventLoop = new NioEventLoopGroup(); private OioEventLoopGroup m_multiEventLoop = new OioEventLoopGroup(); public RESULT start() { logger.entry(); RESULT result = RESULT.SUCCESS; try { // TCP Server ServerBootstrap server = new ServerBootstrap(); server.channel(NioServerSocketChannel.class) .group(m_tcpEventLoop) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { m_pool.add(ch); ch.pipeline().addFirst(new PacketHandler()); ch.pipeline().addLast(new HandshakeHandler()); }; @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { m_pool.remove(ctx.channel()); } }) .option(ChannelOption.SO_BACKLOG, 3) .childOption(ChannelOption.SO_KEEPALIVE, true); m_tcpFuture = server.bind(TCP_LISTEN_PORT).sync(); // MultiCast Server InetSocketAddress remoteAddr = new InetSocketAddress(InetAddress.getByName("224.1.1.1"), MULTI_LIST_PORT); Bootstrap b = new Bootstrap(); b.group(m_multiEventLoop) .option(ChannelOption.SO_BROADCAST, true) .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.IP_MULTICAST_TTL, 2) .option(ChannelOption.SO_RCVBUF, 1048576) .channelFactory(new ChannelFactory<OioDatagramChannel>() { @Override public OioDatagramChannel newChannel() { OioDatagramChannel ch = new OioDatagramChannel(); return ch; } }); b.handler(new ChannelInitializer<OioDatagramChannel>() { @Override protected void initChannel(OioDatagramChannel ch) throws Exception { ch.pipeline().addFirst(new PacketHandler()); ch.pipeline().addLast(new MulticastInbound()); } }); m_multiFuture = b.bind(MULTI_LIST_PORT).sync(); DatagramChannel ch = (DatagramChannel)m_multiFuture.channel(); // Join Group on all active interfaces Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); while(nics.hasMoreElements()) { NetworkInterface nic = nics.nextElement(); if(nic.isUp() && !nic.isVirtual()) { ch.joinGroup(remoteAddr, nic); } } EventOperator.instance().setMultiCast(ch); // Set multi in order to relay TCP events logger.info("Servers started."); } catch(BindException e) { shutdown(); // If the TCP side was successful then the error must have occurred on // UDP multicast result = (m_tcpFuture != null && m_tcpFuture.isSuccess()) ? RESULT.MULTI_BIND_EXCEPTION.cause(e) : RESULT.TCP_BIND_EXCEPTION.cause(e); } catch(Throwable e) { shutdown(); result = RESULT.OTHER_EXCEPTION.cause(e); } logger.exit(result); return result; } public void shutdown() { logger.entry(); if(m_tcpFuture != null && m_tcpFuture.channel().isActive()) { m_tcpFuture.channel().close(); logger.debug("TCP server shutdown"); } if(m_multiFuture != null && m_multiFuture.channel().isActive()) { m_multiFuture.channel().close(); logger.debug("UDP socket shutdown"); } if(!m_pool.isEmpty()) { m_pool.close(); logger.debug("TCP Sockets closed"); } if(!m_tcpEventLoop.isShutdown()) { m_tcpEventLoop.shutdownGracefully(); logger.debug("TCP Event loop shutdown"); } if(!m_multiEventLoop.isShutdown()) { m_multiEventLoop.shutdownGracefully(); logger.debug("UDP Event loop shutdown"); } logger.exit(); } public void addEventListener(EventListener listener) { EventOperator.instance().addEventListener(listener); } public void removeEventListener(EventListener listener) { EventOperator.instance().removeEventListener(listener); } }