/** * MDC Connector * * @author yjiang */ public abstract class MDCConnector extends IoHandlerAdapter { static final Log log = LogFactory.getLog(MDCConnector.class); /** the the max size of a packet, 32KB */ static int MAX_SIZE = MDCServer.MAX_SIZE; protected Selector selector; protected IoConnector connector; protected static Configuration _conf; protected static boolean inited = false; /** Close. */ public void close() { if (selector != null) { selector.wakeup(); try { selector.close(); } catch (IOException e1) { log.warn("close selector fails", e1); } finally { selector = null; } } if (connector != null) { connector.dispose(); connector = null; } } /** Instantiates a new MDC connector. */ protected MDCConnector() {} /** Inits the. */ public static synchronized void init() { if (inited) { return; } _conf = Config.getConfig(); /** initialize app command */ Command.init(); /** initialize the RSA key, hardcode 2048 bits */ TConn.pub_key = SystemConfig.s("pub_key", null); if (TConn.pub_key == null) { Key k = RSA.generate(2048); TConn.pri_key = k.pri_key; TConn.pub_key = k.pub_key; /** set back in database */ SystemConfig.setConfig("pri_key", TConn.pri_key); SystemConfig.setConfig("pub_key", TConn.pub_key); } else { /** get from the database */ TConn.pri_key = SystemConfig.s("pri_key", null); } inited = true; } /** * Service. * * @param o the o * @param session the session */ void service(IoBuffer o, IoSession session) { try { // System.out.println(o.remaining() + "/" + o.capacity()); session.setAttribute("last", System.currentTimeMillis()); SimpleIoBuffer in = (SimpleIoBuffer) session.getAttribute("buf"); if (in == null) { in = SimpleIoBuffer.create(4096); session.setAttribute("buf", in); } byte[] data = new byte[o.remaining()]; o.get(data); in.append(data); // log.debug("recv: " + data.length + ", " + // session.getRemoteAddress()); while (in.length() > 5) { in.mark(); /** * Byte 1: head of the package<br> * bit 7-6: "01", indicator of MDC<br> * bit 5: encrypt indicator, "0": no; "1": encrypted<br> * bit 4: zip indicator, "0": no, "1": ziped<br> * bit 0-3: reserved<br> * Byte 2-5: length of data<br> * Byte[…]: data array<br> */ byte head = in.read(); /** test the head indicator, if not correct close it */ if ((head & 0xC0) != 0x40) { log.info("flag is not correct! flag:" + head + ",from: " + session.getRemoteAddress()); session.close(true); return; } int len = in.getInt(); if (len <= 0 || len > MAX_SIZE) { log.error( "mdcconnector.Wrong lendth: " + len + "/" + MAX_SIZE + " - " + session.getRemoteAddress()); session.close(true); break; } if (in.length() < len) { in.reset(); break; } else { // do it // log.info("stub.package.size: " + len); byte[] b = new byte[len]; in.read(b); if (TConn.DEBUG) { log.debug("recv: " + Bean.toString(b)); } /** test the zip flag */ if ((head & 0x10) > 0) { b = Zip.unzip(b); } final TConn d = (TConn) session.getAttribute("conn"); if (d != null) { /** test the encrypted flag */ if ((head & 0x20) > 0) { b = DES.decode(b, d.deskey); } final byte[] bb = b; /** test if the packet is for mdc or app */ new WorkerTask() { @Override public void onExecute() { d.process(bb); } }.schedule(0); session.setAttribute("last", System.currentTimeMillis()); } } } } catch (Throwable e) { log.error("closing stub: " + session.getRemoteAddress(), e); session.close(true); } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionCreated(org.apache * .mina.core.session.IoSession) */ public void sessionCreated(IoSession session) throws Exception { String remote = session.getRemoteAddress().toString(); log.info("stub created:" + remote); /** check the allow ip */ if (TConn.ALLOW_IP == null || "*".equals(TConn.ALLOW_IP) || remote.matches(TConn.ALLOW_IP)) { TConn d = new TConn(session); session.setAttribute("conn", d); } else { log.warn("deny the connection:" + remote + ", allow ip:" + TConn.ALLOW_IP); session.close(true); } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionClosed(org.apache * .mina.core.session.IoSession) */ public void sessionClosed(IoSession session) throws Exception { log.debug("closed stub: " + session.getRemoteAddress()); TConn d = (TConn) session.getAttribute("conn"); if (d != null) { d.close(); } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionIdle(org.apache. * mina.core.session.IoSession, org.apache.mina.core.session.IdleStatus) */ public void sessionIdle(IoSession session, IdleStatus status) throws Exception { if (IdleStatus.BOTH_IDLE.equals(status)) { Long l = (Long) session.getAttribute("last"); if (l != null && System.currentTimeMillis() - l > 60 * 1000) { session.close(true); } } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#messageReceived(org.apache * .mina.core.session.IoSession, java.lang.Object) */ public void messageReceived(IoSession session, Object message) throws Exception { // System.out.println(message); if (message instanceof IoBuffer) { service((IoBuffer) message, session); } } private static MDCConnector tcpconnector; private static MDCConnector udpconnector; /** * @param host * @param port * @return TConn */ public static synchronized TConn connectByTcp(String host, int port) { return connectByTcp(host, port, X.AMINUTE); } /** * Connect by tcp. * * @param host the host * @param port the port * @return the t conn */ public static synchronized TConn connectByTcp(String host, int port, long timeout) { TimeStamp t = TimeStamp.create(); try { if (tcpconnector == null) { tcpconnector = new TDCConnector(); } tcpconnector.connector.setConnectTimeoutMillis(timeout); ConnectFuture connFuture = tcpconnector.connector.connect(new InetSocketAddress(host, port)); connFuture.awaitUninterruptibly(timeout); IoSession session = connFuture.getSession(); TConn c = new TConn(session); session.setAttribute("conn", c); return c; } catch (Exception e) { log.error( "error, [" + host + ":" + port + "], cost: " + t.past() + "ms, timeout=" + timeout, e); } return null; } /** * Connect by udp. * * @param host the host * @param port the port * @return the t conn */ public static synchronized TConn connectByUdp(String host, int port) { try { if (udpconnector == null) { udpconnector = new UDCConnector(); } ConnectFuture connFuture = udpconnector.connector.connect(new InetSocketAddress(host, port)); connFuture.awaitUninterruptibly(); IoSession session = connFuture.getSession(); TConn c = new TConn(session); session.setAttribute("conn", c); return c; } catch (Exception e) { log.error("[" + host + ":" + port + "]", e); } return null; } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#exceptionCaught(org.apache * .mina.core.session.IoSession, java.lang.Throwable) */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { log.error(cause.getMessage(), cause); } }
/** * MDC server * * @author yjiang */ public abstract class MDCServer extends IoHandlerAdapter { static final Log log = LogFactory.getLog(MDCServer.class); static final AtomicInteger counter = new AtomicInteger(0); /** the the max size of a packet, 32KB */ static int MAX_SIZE = 10240 * 1024; // test protected InetSocketAddress address; protected Selector selector; protected ServerSocketChannel server; protected final int PROCESS_NUMBER = 4; protected static Configuration _conf; protected IoAcceptor acceptor; protected boolean isRunning = false; protected boolean testKey() { String data = UID.random(24); byte[] bb = RSA.encode(data.getBytes(), TConn.pub_key); if (bb != null) { bb = RSA.decode(bb, TConn.pri_key); if (bb != null && data.equals(new String(bb))) { return true; } } return false; } /** Close. */ public void close() { if (selector != null) { selector.wakeup(); try { selector.close(); } catch (IOException e1) { log.warn("close selector fails", e1); } finally { selector = null; } } if (server != null) { try { server.socket().close(); server.close(); } catch (IOException e) { log.warn("close socket server fails", e); } finally { server = null; } } } /** * Instantiates a new MDC server. * * @param host the host * @param port the port */ protected MDCServer(String host, int port) { _conf = Config.getConfig(); address = (host == null) ? new InetSocketAddress(port) : new InetSocketAddress(host, port); /** initialize app command */ Command.init(); /** initialize the connection center */ TConnCenter.init(_conf, port); synchronized (_conf) { /** load public key from database */ TConn.pub_key = SystemConfig.s("pub_key", null); TConn.pri_key = SystemConfig.s("pri_key", null); /** initialize the RSA key, hardcode 2048 bits */ if (TConn.pub_key == null || TConn.pri_key == null || "".equals(TConn.pub_key) || "".equals(TConn.pri_key)) { /** print out the old state */ log.warn( "the pub_key or pri_key missed, the old state are pub_key:[" + TConn.pub_key + "], pri_key:[" + TConn.pri_key + "]"); Key k = RSA.generate(2048); TConn.pri_key = k.pri_key; TConn.pub_key = k.pub_key; /** print out the new public key */ log.warn("create new RSA key pair, pub_key:[" + TConn.pub_key + ']'); /** set back in database */ SystemConfig.setConfig("pri_key", TConn.pri_key); SystemConfig.setConfig("pub_key", TConn.pub_key); } MAX_SIZE = SystemConfig.i("mdc.max_size", MAX_SIZE); } } /** * Start. * * @return the MDC server */ public abstract MDCServer start(); /** Stop. */ public void stop() { acceptor.unbind(); } /** * Service. * * @param o the o * @param session the session */ void service(IoBuffer o, IoSession session) { try { // System.out.println(o.remaining() + "/" + o.capacity()); session.setAttribute("last", System.currentTimeMillis()); SimpleIoBuffer in = (SimpleIoBuffer) session.getAttribute("buf"); if (in == null) { in = SimpleIoBuffer.create(4096); session.setAttribute("buf", in); } byte[] data = new byte[o.remaining()]; o.get(data); in.append(data); // log.debug("recv: " + data.length + ", " + // session.getRemoteAddress()); while (in.length() > 5) { in.mark(); /** * Byte 1: head of the package<br> * bit 7-6: "01", indicator of MDC<br> * bit 5: encrypt indicator, "0": no; "1": encrypted<br> * bit 4: zip indicator, "0": no, "1": ziped<br> * bit 0-3: reserved<br> * Byte 2-5: length of data<br> * Byte[…]: data array<br> */ byte head = in.read(); /** test the head indicator, if not correct close it */ if ((head & 0xC0) != 0x40) { log.info("flag is not correct! flag:" + head + ",from: " + session.getRemoteAddress()); session.write("error.head"); session.close(true); return; } int len = in.getInt(); if (len <= 0 || len > MAX_SIZE) { log.error( "mdcserver.Wrong lendth: " + len + "/" + MAX_SIZE + " - " + session.getRemoteAddress()); session.write("error.packet.size"); session.close(true); break; } // log.info("packet.len:" + len + ", len in buffer:" + // in.length()); if (in.length() < len) { in.reset(); break; } else { // do it byte[] b = new byte[len]; in.read(b); // log.info("stub.package.size: " + len + ", head:" + head + // ", cmd:" + Bean.toString(b)); // log.info("stub.package.size: " + len + ", head:" + head); /** test the zip flag */ if ((head & 0x10) != 0) { b = Zip.unzip(b); } final TConn d = (TConn) session.getAttribute("conn"); if (d != null) { /** test the encrypted flag */ if ((head & 0x20) != 0) { b = DES.decode(b, d.deskey); } final byte[] bb = b; /** test if the packet is for mdc or app */ new WorkerTask() { @Override public void onExecute() { d.process(bb); } }.schedule(0); session.setAttribute("last", System.currentTimeMillis()); } else { session.write("error.getconnection"); log.error("error to get connection: " + session.getRemoteAddress()); session.close(true); } } } } catch (Throwable e) { log.error("closing stub: " + session.getRemoteAddress(), e); session.write("exception." + e.getMessage()); session.close(true); } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionCreated(org.apache * .mina.core.session.IoSession) */ public void sessionCreated(IoSession session) throws Exception { log.info("stub created:" + session.getRemoteAddress()); Counter.add("mdc", "connection", 1); TConn d = new TConn(session); d.set("x-forwarded-for", session.getRemoteAddress().toString()); session.setAttribute("conn", d); } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionClosed(org.apache * .mina.core.session.IoSession) */ public void sessionClosed(IoSession session) throws Exception { log.info("closed stub: " + session.getRemoteAddress()); TConn d = (TConn) session.getAttribute("conn"); if (d != null) { d.close(); session.removeAttribute("conn"); } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#sessionIdle(org.apache. * mina.core.session.IoSession, org.apache.mina.core.session.IdleStatus) */ public void sessionIdle(IoSession session, IdleStatus status) throws Exception { if (IdleStatus.BOTH_IDLE.equals(status)) { Long l = (Long) session.getAttribute("last"); if (l != null && System.currentTimeMillis() - l > 60 * 1000) { session.close(true); } } } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#messageReceived(org.apache * .mina.core.session.IoSession, java.lang.Object) */ public void messageReceived(IoSession session, Object message) throws Exception { // System.out.println(message); if (message instanceof IoBuffer) { service((IoBuffer) message, session); } } /** * Creates the tcp server. * * @param host the host * @param port the port * @return the MDC server */ public static synchronized MDCServer createTcpServer(String host, int port) { return new TDCServer(host, port); } /** * Creates the udp server. * * @param host the host * @param port the port * @return the MDC server */ public static synchronized MDCServer createUdpServer(String host, int port) { return new UDCServer(host, port); } /* * (non-Javadoc) * * @see * org.apache.mina.core.service.IoHandlerAdapter#exceptionCaught(org.apache * .mina.core.session.IoSession, java.lang.Throwable) */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { TConn d = (TConn) session.getAttribute("conn"); if (d != null && d.valid()) { App.bye(d); } } }