package erjang.net; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.atomic.AtomicLong; import erjang.NotImplemented; import erjang.driver.efile.Posix; public class LazyInetSocket extends InetSocket { static final int OPEN_FLAG = 0x01; int status = OPEN_FLAG; static AtomicLong next_id = new AtomicLong(); private final long id; private final ProtocolFamily domain; private final ProtocolType type; private final Protocol protocol; private InetSocket delegate; InetSocketAddress bindingAddress; // Server, Client, Datagram public Integer so_rcv_buf; public Integer so_snd_buf; public Integer so_timeout; public Boolean so_reuse_addr; // Client public Boolean so_keep_alive; public Boolean so_oob_inline; public Boolean so_nodelay; public Integer so_traffic_class; public Integer so_linger; // Datagram, Multicast private Boolean so_broadcast; private Boolean blocking; void init(InetSocket s) throws IOException { if (blocking != null) { s.configureBlocking(blocking); } if (so_rcv_buf != null) { s.setReceiveBufferSize(so_rcv_buf); } if (so_snd_buf != null) { s.setSendBufferSize(so_snd_buf); } if (so_timeout != null) { setTimeout(so_timeout); } if (so_reuse_addr != null) { s.setReuseAddress(so_reuse_addr); } if (so_keep_alive != null) { s.setKeepAlive(so_keep_alive); } if (so_oob_inline != null) { s.setOOBInline(so_oob_inline); } if (so_nodelay != null) { s.setTcpNoDelay(so_nodelay); } if (so_broadcast != null) { s.setBroadcast(so_broadcast); } if (so_traffic_class != null) { s.setTrafficClass(so_traffic_class); } if (so_linger != null) { if (so_linger > 0) { s.setLinger(true, so_linger); } else { s.setLinger(false, 0); } } if (bindingAddress != null) { s.bind(bindingAddress); } } LazyInetSocket(ProtocolFamily domain, ProtocolType type, Protocol protocol) { this.domain = domain; this.type = type; this.protocol = protocol; this.id = next_id.incrementAndGet(); } public void bind(InetSocketAddress localAddress) throws IOException { if (delegate != null) { delegate.bind(localAddress); return; } else { this.bindingAddress = localAddress; } } /** * try to connect * * @see SocketChannel#connect(SocketAddress) */ public boolean connect(InetSocketAddress remote) throws IOException { if (delegate == null) { if (protocol == Protocol.TCP) { delegate = new InetClientSocket(this); } else if (protocol == Protocol.UDP) { delegate = new InetDatagramSocket(this); } else { throw new NotImplemented(); } } if (delegate.connect(remote)) { return true; } else { return false; } } @Override public boolean finishConnect() throws IOException { if (delegate == null) { if (protocol == Protocol.TCP) { delegate = new InetClientSocket(this); } else if (protocol == Protocol.UDP) { delegate = new InetDatagramSocket(this); } else { throw new NotImplemented(); } } return delegate.finishConnect(); } /** this is the signifier, that we are a server socket */ public void listen(int backlog) throws IOException { if (delegate == null) { switch (protocol) { case TCP: delegate = new InetServerSocket(this, new Integer(backlog)); break; default: throw new PosixIOException(Posix.EOPNOTSUPP, "socket is not of type SOCK_STREAM and thus does not accept connections"); } } delegate.listen(backlog); } /** * May return null if non-blocking * * @see ServerSocketChannel#accept() */ @Override public InetSocket accept() throws IOException { if (delegate == null) { switch (protocol) { case TCP: delegate = new InetServerSocket(this, null); break; default: throw new PosixIOException(Posix.EOPNOTSUPP, "socket is not of type SOCK_STREAM and thus does not accept connections"); } } return delegate.accept(); } @Override public int send(ByteBuffer packet, SocketAddress target) throws IOException { if (delegate == null) { delegate = new InetDatagramSocket(this); } return delegate.send(packet, target); } @Override public InetSocketAddress getLocalSocketAddress() { if (delegate == null) return bindingAddress; return delegate.getLocalSocketAddress(); } @Override public SelectableChannel channel() { if (delegate == null) { return null; } return delegate.channel(); } @Override public void configureBlocking(boolean block) throws IOException { if (delegate == null) { this.blocking = Boolean.valueOf(block); return; } delegate.channel().configureBlocking(block); } @Override public void setKeepAlive(boolean val) throws IOException { if (delegate == null) { so_keep_alive = Boolean.valueOf(val); } else { delegate.setKeepAlive(val); } } @Override public boolean getKeepAlive() throws IOException { if (delegate == null) { return delegate.getKeepAlive(); } else { return so_keep_alive == null ? false : so_keep_alive.booleanValue(); } } @Override public void setOOBInline(boolean val) throws IOException { if (delegate == null) { so_oob_inline = Boolean.valueOf(val); } else { delegate.setOOBInline(val); } } @Override public void setReuseAddress(boolean val) throws IOException { if (delegate == null) { so_reuse_addr = Boolean.valueOf(val); } else { delegate.setReuseAddress(val); } } @Override public boolean getReuseAddress() throws IOException { if (delegate == null) { return delegate.getReuseAddress(); } else { return so_reuse_addr == null ? false : so_reuse_addr.booleanValue(); } } @Override public void setTcpNoDelay(boolean val) throws IOException { if (delegate == null) { so_nodelay = Boolean.valueOf(val); } else { delegate.setTcpNoDelay(val); } } @Override public boolean getNoDelay() throws IOException { if (delegate == null) { return delegate.getNoDelay(); } else { return so_nodelay == null ? false : so_nodelay.booleanValue(); } } @Override public void setBroadcast(boolean val) throws IOException { if (delegate == null) { so_broadcast = Boolean.valueOf(val); } else { delegate.setBroadcast(val); } } @Override public void setTrafficClass(int ival) throws IOException { if (delegate == null) { so_traffic_class = new Integer(ival); } else { delegate.setTrafficClass(ival); } } @Override public void setReceiveBufferSize(int size) throws IOException { if (delegate == null) { so_rcv_buf = new Integer(size); } else { delegate.setReceiveBufferSize(size); } } @Override public int getReceiveBufferSize() throws IOException { if (delegate == null) { return delegate.getReceiveBufferSize(); } else { return so_rcv_buf == null ? 0 : so_rcv_buf.intValue(); } } @Override public int getLinger() throws IOException { if (delegate == null) { return delegate.getLinger(); } else { return so_linger == null ? 0 : so_linger.intValue(); } } @Override public void setSendBufferSize(int size) throws IOException { if (delegate == null) { so_snd_buf = new Integer(size); } else { delegate.setSendBufferSize(size); } } @Override public int getSendBufferSize() throws IOException { if (delegate == null) { return delegate.getSendBufferSize(); } else { return so_snd_buf == null ? 0 : so_snd_buf.intValue(); } } @Override public void setTimeout(int timeout) throws IOException { if (delegate == null) { so_timeout = new Integer(timeout); } else { delegate.setTimeout(timeout); } } @Override public void setLinger(boolean on, int timeout) throws IOException { if (delegate == null) { if (on == false) { so_linger = new Integer(-1); } else { so_linger = new Integer(timeout); } } else { delegate.setLinger(on, timeout); } } @Override public void close() throws IOException { if (delegate != null) { delegate.close(); } else { status &= ~OPEN_FLAG; } } public boolean isBound() { if (delegate != null) { return delegate.isBound(); } return this.bindingAddress != null; } @Override public boolean isOpen() { if (delegate != null) { return delegate.isOpen(); } return (this.status & OPEN_FLAG) == OPEN_FLAG; } @Override public String toString() { if (delegate == null) { return "LazySocket[" + "bound="+this.bindingAddress + "; linger="+this.so_linger + "; rcvbuf="+this.so_rcv_buf + "; sndbuf="+this.so_snd_buf + "; timeout="+this.so_timeout + "; reuse="+this.so_reuse_addr + "; keepalive="+this.so_keep_alive + "]"; } else { return delegate.toString(); } } }