package erjang.epmd; import java.io.*; import java.net.*; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import java.nio.*; import java.nio.channels.*; /** * a simple message switch using NIO based socket i/o part of the pkwnet package * a very simple text message switching program default command line is java * StreamSwitch -p5050 -i600 -p port to listen on -i default idle time in * seconds user commands start with $ and consist of blank seperated arguments * other lines sent by the user are forwarded $on nickname targets sign on as * nickname, sending to targets $to targets change target list, reports current * value $list nicknames list status of specified nicknames $list list all * connected users $off sign off * * @author PKWooster * @version 1.0 June 14,2004 */ public abstract class PacketServer { static final Logger log = Logger.getLogger("erjang.epmd"); private ServerSocket ss; // the listening socket private ServerSocketChannel sschan; // the listening channel private Selector selector; // the only selector private int bufsz = 8192; protected void listen(int port) { int n = 0; Iterator<SelectionKey> it; SelectionKey key; log.info("listening on port=" + port); try { sschan = ServerSocketChannel.open(); sschan.configureBlocking(false); ss = sschan.socket(); ss.bind(new InetSocketAddress(InetAddress.getByAddress(new byte[] {127,0,0,1}), port)); selector = Selector.open(); sschan.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException ie) { ie.printStackTrace(); System.exit(0); } while (true) { // now we select any pending io try { n = selector.select(); } // select catch (Exception e) { log.severe("select failed: " + e.getMessage()); log.log(Level.FINE, "details: ", e); } log.fine("select n=" + n); // process any selected keys Set<SelectionKey> selectedKeys = selector.selectedKeys(); it = selectedKeys.iterator(); while (it.hasNext()) { key = (SelectionKey) it.next(); int kro = key.readyOps(); log.fine("kro=" + kro); if ((kro & SelectionKey.OP_READ) == SelectionKey.OP_READ) doRead(key); if ((kro & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) doWrite(key); if ((kro & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) doAccept(key); if ((kro & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) doConnect(key); if (key.isValid() && key.interestOps() == 0) { it.remove(); // remove the key } } } } private void doAccept(SelectionKey sk) { ServerSocketChannel sc = (ServerSocketChannel) sk.channel(); log.fine("accept"); SocketChannel usc = null; ByteBuffer data; try { usc = sc.accept(); if (usc == null) return; usc.configureBlocking(false); Socket sock = usc.socket(); String nm = sock.getInetAddress() + ":" + sock.getPort(); log.info("connection from " + nm); sock.setKeepAlive(true); data = ByteBuffer.allocate(bufsz); data.position(data.limit()); // looks like write complete SelectionKey dsk = usc.register(selector, SelectionKey.OP_READ, null); Connection conn = newConnection(dsk); // contains socket i/o code conn.setName(nm); dsk.attach(conn); // link it to the key so we can find it } catch (IOException re) { log.severe("registration error: " + re.getMessage()); log.log(Level.FINE, "details: ", re); } } protected abstract PacketConnection newConnection(SelectionKey dsk); private void doRead(SelectionKey sk) { PacketConnection conn = (PacketConnection) sk.attachment(); // get our // connection conn.doRead(); } private void doWrite(SelectionKey sk) { PacketConnection conn = (PacketConnection) sk.attachment(); // get our // connection conn.doWrite(); } private void doConnect(SelectionKey sk) { PacketConnection conn = (PacketConnection) sk.attachment(); // get our // connection conn.doConnect(); } }