package org.kne.cloud.network.klalb; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.BindException; import java.net.ConnectException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NoRouteToHostException; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketImpl; import java.net.SocketOptions; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.Iterator; import java.util.Map; import java.util.TimerTask; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.ReentrantLock; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import org.kne.cloud.clock.HighAccuracyClock; import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.PortPair; import org.kne.cloud.network.SpeedLimiter; import org.kne.cloud.network.VirtualSocketImpl; import org.kne.cloud.network.congestion.CongestionAlgorithm; import org.kne.cloud.network.congestion.DCTCP2CongestionAlgorithm; import org.kne.cloud.network.congestion.ReceivePacketSlidingWindow; import org.kne.cloud.network.congestion.SendPacketSlidingWindow; import org.kne.cloud.network.ipv6.IPv6Address; import org.kne.cloud.network.ipv6.PacketID; import org.kne.cloud.network.ipv6.PacketIDGenerator; import org.kne.cloud.network.kltp.KLTPInputStream; import org.kne.cloud.network.kltp.KLTPOutputStream; import org.kne.cloud.network.kltp.KLTPSessionPacket; import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl; import org.kne.concurrent.SpinLock; import org.kne.concurrent.ThreadParker; import org.kne.debug.TimeDebugger; import com.github.f4b6a3.uuid.UuidCreator; public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements BindableConsumer{ private static final boolean debug = false; private static final int DEFAULT_TIMEOUT=10000; private KLALBController controller; protected IPv6Address remoteaddr; protected IPv6Address localaddr=IPv6Address.UNSPECIFIED; private volatile KLTPInputStream vin; private volatile KLTPOutputStream vout; private boolean ignoreBindCheck; private boolean connected; private boolean closed; private BlockingQueue backlogQueue; protected boolean isListening() { return backlogQueue != null; } public KLALBController getController() { return controller; } public KLALBVirtualSocketImpl(KLALBController kc) { super(); this.controller = kc; } @Override public void setOption(int optID, Object value) throws SocketException { switch(optID) { /*case SocketOptions.TCP_NODELAY: nodelay=(boolean) value; break; case SocketOptions.SO_RCVBUF: inputchachesize=(int) value; break; case SocketOptions.SO_SNDBUF: outputchachesize=(int)value; break;*/ case SocketOptions.SO_TIMEOUT: vin.setSoTimeout((int)value); break; } } @Override public Object getOption(int optID) throws SocketException { switch(optID) { /*case SocketOptions.TCP_NODELAY: return nodelay; case SocketOptions.SO_RCVBUF: return inputchachesize; case SocketOptions.SO_SNDBUF: return outputchachesize;*/ case SocketOptions.SO_TIMEOUT: return vin.getSoTimeout(); case SocketOptions.SO_BINDADDR: return localaddr; default: return null; } } @Override protected void create(boolean stream) throws IOException { if (!stream) { throw new RuntimeException("please use KLALBVirtualDatagramSocket to process udp packet"); } } @Override protected void connect(String host, int port) throws IOException { connect(InetAddress.getByName(host), port); } @Override protected void connect(InetAddress address, int port) throws IOException { connect(new InetSocketAddress(address, port), DEFAULT_TIMEOUT); } @Override protected void connect(SocketAddress address, int timeout) throws IOException { if(!ignoreBindCheck) if (!controller.getKLTPregister().checkIsBind(this)) { bind(Inet6Address.getByName("::0"), 0); } port = ((InetSocketAddress) address).getPort(); this.address = (Inet6Address) ((InetSocketAddress) address).getAddress(); this.remoteaddr=IPv6Address.valueOf(this.address); if(connected) throw new SocketException("already connected"); controller.getKLTPregister().connect(this); try { vout=new KLTPOutputStream(controller, remoteaddr, KLALBUtils.createGlobalUUID()); KLTPSessionPacket session=new KLTPSessionPacket(localport,port); session.writeToChannel(vout); vout.flush(); System.out.println("发起连接:"+session+" "+localport); if(timeout==0) { timeout=DEFAULT_TIMEOUT; } long start=System.nanoTime(); while(vin==null) { long curr=System.nanoTime(); if(curr-start>(timeout*1000000L)) { throw new SocketTimeoutException("connect time out"); } } connected=true; }catch(NoRouteToHostException e) { throw e; }catch(SocketException e) { e.printStackTrace(); throw new ConnectException("connect refused"); }finally { //connectionPending=false; } } @Override protected void bind(InetAddress host, int port) throws IOException { bind(host,port,false); } protected void bind(InetAddress host, int port,boolean ignoreBindCheck) throws IOException { if (host.equals(Inet4Address.getByName("0.0.0.0"))) { host = Inet6Address.getByName("::0"); } if (!(host instanceof Inet6Address)) { throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 virtualaddress"); } if ((!host.isAnyLocalAddress()) && (! IPv6Address.valueOf( host).equals(controller.getSelf().getAddress()))) { throw new BindException("must bind to self"); } localaddr = IPv6Address.valueOf( host); localport=port; this.ignoreBindCheck=ignoreBindCheck; if(!ignoreBindCheck) { controller.getKLTPregister().bind(this); } //System.out.println("绑定:"+host.getHostAddress()+":"+localport); } @Override public int getPort() { return super.getPort(); } @Override protected void listen(int backlog) throws IOException { backlogQueue = new ArrayBlockingQueue<>(backlog); controller.getKLTPregister().listen(this); address=localaddr.toInet6Address(); } @Override protected void accept(SocketImpl s) throws IOException { //System.out.println("Enter accept============================="); KLALBVirtualSocketImpl kvsi = (KLALBVirtualSocketImpl) s; KLTPSessionPacket p=null; while(true) { if (isClosed()) throw new SocketException("Socket is closed"); p=backlogQueue.poll(); if(p!=null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(p); KLTPInputStream input=p.getInputstream(); kvsi.address = input.getRemoteAddress().toInet6Address(); kvsi.remoteaddr=input.getRemoteAddress(); kvsi.bind(localaddr.toInet6Address(), localport,true); kvsi.accept(p); kvsi.connect(new InetSocketAddress(kvsi.address, p.getSrcPort()),10); //System.out.println("Exit accept============================="); } @Override public InputStream getInputStream() throws IOException { return vin; } @Override public OutputStream getOutputStream() throws IOException { return vout; } @Override protected int available() throws IOException { return getInputStream().available(); } @Override protected void shutdownInput() throws IOException { throw new UnsupportedOperationException("Unsupported Shutdown Input"); //getInputStream().close0(); } @Override protected void shutdownOutput() throws IOException { throw new UnsupportedOperationException("Unsupported Shutdown Output"); //getOutputStream().close0(); } @Override public String toString() { return "KLALBVirtualSocketImpl [vin=" + vin + ", vout=" + vout + "]"; } @Override protected void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { super.setPerformancePreferences(connectionTime, latency, bandwidth); } @Override protected void close() throws IOException { //new Exception().printStackTrace(); closed=true; try { if(vout!=null) vout.close(); }finally { if(vin!=null) vin.close(); if(!isListening() ) { controller.getKLTPregister().disconnect(this); }else { //System.out.println("unlisten"+getLocalPort()); controller.getKLTPregister().unlisten(this); } if(!ignoreBindCheck) controller.getKLTPregister() .unbind(this); } } private boolean isClosed() {//||(vin!=null&&vin.isClosed())&&(vout!=null&&vout.isClosed()) return closed; } @Override protected void sendUrgentData(int data) throws IOException { throw new UnsupportedOperationException("urgent data unspuuorted"); } @Override public int getLocalPort() { return super.getLocalPort(); } @Override public void accept(KLTPSessionPacket stream) { if(isListening()) { if(!backlogQueue.contains(stream)) { backlogQueue.add(stream); System.out.println("添加到监听队列:"+stream); } }else { System.out.println("匹配反向连接:"+stream); if(this.vin==null) { this.vin=stream.getInputstream(); } } } @Override public InetAddress getRemoteInetAddress() { return remoteaddr.toInet6Address(); } @Override public InetAddress getLocalInetAddress() { return localaddr.toInet6Address(); } @Override public void setLocalPort(int i) { localport=i; } public void setCompress(int i) { // TODO 自动生成的方法存根 } public int getCompress() { // TODO 自动生成的方法存根 return 0; } public boolean isConnectionPending() { // TODO 自动生成的方法存根 return false; } }