Package com.taobao.jetty.apr

Source Code of com.taobao.jetty.apr.AprSocketConnector$SocketWrapper

/**
*
*/
package com.taobao.jetty.apr;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.tomcat.jni.Address;
import org.apache.tomcat.jni.Library;
import org.apache.tomcat.jni.OS;
import org.apache.tomcat.jni.Pool;
import org.apache.tomcat.jni.Sockaddr;
import org.apache.tomcat.jni.Socket;
import org.apache.tomcat.jni.Status;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.io.nio.NIOBuffer;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.log.Log;

/**
* @author lovingprince
* @since 2011-5-20
*
*/
public class AprSocketConnector extends AbstractConnector {

  protected final Set<EndPoint> _connections;
  protected volatile int _localPort = -1;

  /**
   * Root APR memory pool.
   */
  protected long rootPool = 0;

  /**
   * Server socket "pointer".
   */
  protected long serverSock = 0;

  /**
   * APR memory pool for the server socket.
   */
  protected long serverSockPool = 0;

  /* ------------------------------------------------------------ */
  /**
   * Constructor.
   *
   */
  public AprSocketConnector() {

    _connections = new HashSet<EndPoint>();
  }

  /* ------------------------------------------------------------ */
  public Object getConnection() {
    return serverSock == 0 ? null : serverSock;
  }

  /* ------------------------------------------------------------ */
  public void open() throws IOException {
    if (!AprLifecycle.isAprAvailable()) {
      throw new RuntimeException("apr is not Available!");
    }
    try {
      // Create the root APR memory pool
      try {
        rootPool = Pool.create(0);
      } catch (UnsatisfiedLinkError e) {
        throw new IOException(
            "AprSocketConnector create rootPool error");
      }

      // Create the pool for the server socket
      serverSockPool = Pool.create(rootPool);
      // Create the APR address that will be bound
      String addressStr = null;
      if (getHost() != null) {
        addressStr = getHost();
      }
      int family = Socket.APR_INET;
      if (Library.APR_HAVE_IPV6) {
        if (addressStr == null) {
          if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64)
            family = Socket.APR_UNSPEC;
        } else if (addressStr.indexOf(':') >= 0) {
          family = Socket.APR_UNSPEC;
        }
      }

      long inetAddress = Address.info(addressStr, family, getPort(), 0,
          rootPool);
//      Sockaddr serverSockaddr = Address.getInfo(inetAddress);
      // Create the APR server socket
      serverSock = Socket.create(family,
          Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, rootPool);
      if (OS.IS_UNIX) {
        Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
      }
      // Deal with the firewalls that tend to drop the inactive sockets
      Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
      // Bind the server socket
      int ret = Socket.bind(serverSock, inetAddress);
      if (ret != Status.APR_SUCCESS) {
        throw new Exception("AprSocketConnector bind error");
      }
      // Start listening on the server socket
      ret = Socket.listen(serverSock, getAcceptQueueSize());
      if (ret != Status.APR_SUCCESS) {
        throw new Exception("AprSocketConnector listen error");
      }
      if (OS.IS_WIN32 || OS.IS_WIN64) {
        // On Windows set the reuseaddr flag after the bind/listen
        Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR,
            getReuseAddress() ? 1 : 0);
      }
      long sa = Address.get(Socket.APR_LOCAL, serverSock);
      Sockaddr laddr = new Sockaddr();
      if (Address.fill(laddr, sa)) {
        _localPort = laddr.port;
      }
    } catch (Exception e) {
      throw new IOException(e);
    }

  }

  /* ------------------------------------------------------------ */
  public void close() throws IOException {
    // if (serverSock != 0) {
    // Socket.shutdown(serverSock, Socket.APR_SHUTDOWN_READ);
    // serverSock = 0;
    // }
    // Destroy pool if it was initialised
    if (serverSockPool != 0) {
      Pool.destroy(serverSockPool);
      serverSockPool = 0;
    }

    // Close server socket if it was initialised
    if (serverSock != 0) {
      Socket.close(serverSock);
      serverSock = 0;
    }

    // Close all APR memory pools and resources if initialised
    if (rootPool != 0) {
      Pool.destroy(rootPool);
      rootPool = 0;
    }
  }

  /* ------------------------------------------------------------ */
  @Override
  public void accept(int acceptorID) throws IOException, InterruptedException {
    long socket = 0;
    try {
      socket = Socket.accept(serverSock);
    } catch (Exception e) {
      throw new IOException(e);
    }
    configure(socket);
    AprEndPoint connection = new AprEndPoint(socket);
    connection.dispatch();
  }

  /**
   * Process the specified connection.
   */
  protected void configure(long socket) {
    try {
      // Process the connection
      Socket.optSet(socket, Socket.APR_TCP_NODELAY, 1);
      Socket.optSet(socket, Socket.APR_SO_NONBLOCK, 0);//blocking
      // 1: Set socket options: timeout, linger, etc
      if (_soLingerTime >= 0)
        Socket.optSet(socket, Socket.APR_SO_LINGER, _soLingerTime);
    } catch (Exception e) {
      Log.warn("socket configure exception", e);
    }

  }

  /*
   * --------------------------------------------------------------------------
   * -----
   */
  /**
   * Allows subclass to override Conection if required.
   */
  protected Connection newConnection(EndPoint endpoint) {
    return new HttpConnection(this, endpoint, getServer());
  }

  /*
   * --------------------------------------------------------------------------
   * -----
   */
  @Override
  public void customize(EndPoint endpoint, Request request)
      throws IOException {
    AprEndPoint connection = (AprEndPoint) endpoint;
    int lrmit = isLowResources() ? _lowResourceMaxIdleTime : _maxIdleTime;
    connection.setMaxIdleTime(lrmit);

    super.customize(endpoint, request);
  }

  /*
   * --------------------------------------------------------------------------
   * -----
   */
  public int getLocalPort() {
    return _localPort;
  }

  /*
   * --------------------------------------------------------------------------
   * -----
   */
  @Override
  protected void doStart() throws Exception {
    _connections.clear();
    super.doStart();
  }

  /*
   * --------------------------------------------------------------------------
   * -----
   */
  @SuppressWarnings({ "rawtypes", "unchecked" })
  @Override
  protected void doStop() throws Exception {
    super.doStop();
    Set set = null;

    synchronized (_connections) {
      set = new HashSet(_connections);
    }

    Iterator iter = set.iterator();
    while (iter.hasNext()) {
      AprEndPoint connection = (AprEndPoint) iter.next();
      connection.close();
    }
   
    if (AprLifecycle.aprAvailable) {
       try {
         AprLifecycle.terminateAPR();
             } catch (Throwable t) {
                 Log.info("aprListener.aprDestroy");
             }
     
    }
  }

  protected class AprEndPoint implements Runnable, ConnectedEndPoint,
      EndPoint {
    private long _sock = 0;
    int _maxIdleTime;
    boolean _dispatched = false;
    volatile Connection _connection;
    SocketWrapper remote = null;
    SocketWrapper local = null;

    public AprEndPoint(long sock) {
      _connection = newConnection(this);
      _sock = sock;
      try {
        long sa = Address.get(Socket.APR_REMOTE, _sock);
        Sockaddr raddr = new Sockaddr();
        if (Address.fill(raddr, sa)) {
          remote = new SocketWrapper();
          remote.setHost(raddr.hostname);
          remote.setAddr(Address.getip(sa));
          remote.setPort(raddr.port);

        }
        sa = Address.get(Socket.APR_LOCAL, _sock);
        Sockaddr laddr = new Sockaddr();
        if (Address.fill(laddr, sa)) {
          local = new SocketWrapper();
          local.setHost(laddr.hostname);
          local.setAddr(Address.getip(sa));
          local.setPort(laddr.port);
        }

      } catch (Exception e) {
        // Ignore
        Log.warn("", e);
      }
    }

    @Override
    public boolean blockReadable(long arg0) throws IOException {
      return true;
    }

    @Override
    public boolean blockWritable(long arg0) throws IOException {
      return true;
    }

    @Override
    public void close() throws IOException {
      if (_sock == 0)
        return;

      if (_connection instanceof HttpConnection)
        ((HttpConnection) _connection).getRequest()
            .getAsyncContinuation().cancel();
      Socket.destroy(_sock);
      _sock = 0;

    }

    @Override
    public int fill(Buffer buffer) throws IOException {
      int space = buffer.space();
      if (space <= 0) {
        if (buffer.hasContent())
          return 0;
        throw new IOException("FULL");
      }
     
      try {
        ByteBuffer bb = ((NIOBuffer) buffer).getByteBuffer();
        int b=-1;
        if(bb.isDirect()){
          b = Socket.recvb(_sock, bb, buffer.putIndex(), space);
        }else{
          b=Socket.recv(_sock, bb.array(), buffer.putIndex(), space);
        }
        if (b <= 0) {
          if ((-b) == Status.ETIMEDOUT || (-b) == Status.TIMEUP) {
            throw new SocketTimeoutException("iib.failed read");
          } else if ((-b) == Status.APR_EOF||b==0) {
            return -1;
          } else {
            throw new IOException("iib.failed read");
          }
        } else {
          buffer.setPutIndex(buffer.getIndex()+b);
        }
        return b;
      } catch (Exception e) {
        Log.ignore(e);
        return -1;
      }

    }

    @Override
    public void flush() throws IOException {
    }

    @Override
    public int flush(Buffer buffer) throws IOException {
      int length = buffer.length();
      if (length > 0) {
        ByteBuffer bb = ((NIOBuffer) buffer).getByteBuffer();
        try {
          int loop = 0;
          while (buffer.hasContent()) {
            bb.position(buffer.getIndex());
            bb.limit(buffer.putIndex());
            int len = 0;
            if (bb.isDirect()) {
              len = Socket
                  .sendb(_sock, bb, bb.position(), length);
            } else {
              len = Socket.send(_sock, bb.array(), bb.position(),
                  length);
            }
            if (len < 0)
              break;
            else if (len > 0) {
              buffer.skip(len);
              loop = 0;
            } else if (loop++ > 1)
              break;
          }
        } catch (Exception e) {
          throw new IOException(e);
        } finally {
          bb.position(0);
          bb.limit(bb.capacity());
        }
      }
      if (!buffer.isImmutable())
        buffer.clear();
      return length;
    }

    @Override
    public int flush(Buffer header, Buffer buffer, Buffer trailer)
        throws IOException {
      int len = 0;

      if (header != null) {
        int tw = header.length();
        if (tw > 0) {
          int f = flush(header);
          len = f;
          if (f < tw)
            return len;
        }
      }

      if (buffer != null) {
        int tw = buffer.length();
        if (tw > 0) {
          int f = flush(buffer);
          if (f < 0)
            return len > 0 ? len : f;
          len += f;
          if (f < tw)
            return len;
        }
      }

      if (trailer != null) {
        int tw = trailer.length();
        if (tw > 0) {
          int f = flush(trailer);
          if (f < 0)
            return len > 0 ? len : f;
          len += f;
        }
      }
      return len;
    }

    @Override
    public String getLocalAddr() {
      if (local != null && local.getAddr() != null) {
        return local.getAddr();
      }

      return Address.APR_ANYADDR;
    }

    @Override
    public String getLocalHost() {
      if (local != null && local.getHost() != null) {
        return local.getHost();
      }
      return Address.APR_ANYADDR;
    }

    @Override
    public int getLocalPort() {
      if (local != null) {
        return local.getPort();
      }
      return -1;
    }

    @Override
    public int getMaxIdleTime() {
      return _maxIdleTime;
    }

    @Override
    public String getRemoteAddr() {
      if (remote != null) {
        return remote.getAddr();
      }
      return null;
    }

    @Override
    public String getRemoteHost() {
      if (remote != null) {
        return remote.getHost();
      }
      return null;
    }

    @Override
    public int getRemotePort() {
      if (remote != null) {
        return remote.getPort();
      }
      return -1;
    }

    @Override
    public Object getTransport() {
      return _sock;
    }

    @Override
    public boolean isBlocking() {
      return true;
    }

    @Override
    public boolean isBufferingInput() {
      return false;
    }

    @Override
    public boolean isBufferingOutput() {
      return false;
    }

    @Override
    public boolean isBufferred() {
      return false;
    }

    @Override
    public boolean isOpen() {
      return _sock != 0;
    }

    @Override
    public void setMaxIdleTime(int maxIdleTime) throws IOException {
      Socket.timeoutSet(_sock, maxIdleTime * 1000);
      this._maxIdleTime = maxIdleTime;
    }

    @Override
    public void shutdownOutput() throws IOException {
      if (isOpen())
        Socket.shutdown(_sock, Socket.APR_SHUTDOWN_WRITE);

    }

    @Override
    public Connection getConnection() {

      return this._connection;
    }

    @Override
    public void setConnection(Connection arg0) {
      this._connection = arg0;

    }

    public void dispatch() throws IOException {
      if (getThreadPool() == null || !getThreadPool().dispatch(this)) {
        Log.warn("dispatch failed for {}", _connection);
        close();
      }
    }

    @Override
    public void run() {
      try {
        connectionOpened(_connection);
        synchronized (_connections) {
          _connections.add(this);
        }

        while (isStarted() && isOpen()) {
          if (_connection.isIdle()) {
            if (isLowResources())
              setMaxIdleTime(getLowResourcesMaxIdleTime());
          }

          _connection = _connection.handle();
        }
      } catch (EofException e) {
        Log.debug("EOF", e);
        try {
          close();
        } catch (IOException e2) {
          Log.ignore(e2);
        }
      } catch (HttpException e) {
        Log.debug("BAD", e);
        try {
          close();
        } catch (IOException e2) {
          Log.ignore(e2);
        }
      } catch (Exception e) {
        Log.warn("handle failed?", e);
        try {
          close();
        } catch (IOException e2) {
          Log.ignore(e2);
        }
      } finally {
        connectionClosed(_connection);
        synchronized (_connections) {
          _connections.remove(this);
        }

        // wait for client to close, but if not, close ourselves.
        try {
          if (isOpen()) {
            long timestamp = System.currentTimeMillis();
            int max_idle = getMaxIdleTime();
            Socket.timeoutSet(_sock, getMaxIdleTime() * 1000);
            byte[] cc = new byte[1];
            int c = 0;
            do {
              c = Socket.recv(_sock, cc, 0, 1);
            } while (c >= 0
                && (System.currentTimeMillis() - timestamp) < max_idle);
            if (isOpen())
              close();
          }
        } catch (IOException e) {
          Log.ignore(e);
        }
      }

    }

  }

  public class SocketWrapper {
    private String host;
    private int port = -1;
    private String addr;

    public void setAddr(String addr) {
      this.addr = addr;
    }

    public void setHost(String host) {
      this.host = host;
    }

    public void setPort(int port) {
      this.port = port;
    }

    public String getAddr() {
      return addr;
    }

    public String getHost() {
      return host;
    }

    public int getPort() {
      return port;
    }
  }
 
 
     private boolean _useDirectBuffers=true;//Ĭ����ֱ��buffer
    
      /* ------------------------------------------------------------------------------- */
      public boolean getUseDirectBuffers()
      {
          return _useDirectBuffers;
      }

      /* ------------------------------------------------------------------------------- */
      /**
       * @param direct If True (the default), the connector can use NIO direct buffers.
       * Some JVMs have memory management issues (bugs) with direct buffers.
       */
      public void setUseDirectBuffers(boolean direct)
      {
          _useDirectBuffers=direct;
      }

      /* ------------------------------------------------------------------------------- */
      @Override
      public Buffer newRequestBuffer(int size)
      {
          return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
      }
     
      /* ------------------------------------------------------------------------------- */
      @Override
      public Buffer newRequestHeader(int size)
      {
          return new IndirectNIOBuffer(size);
      }

      /* ------------------------------------------------------------------------------- */
      @Override
      public Buffer newResponseBuffer(int size)
      {
          return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
      }
     
      /* ------------------------------------------------------------------------------- */
      @Override
      public Buffer newResponseHeader(int size)
      {
          return new IndirectNIOBuffer(size);
      }

      /* ------------------------------------------------------------------------------- */
      @Override
      protected boolean isRequestHeader(Buffer buffer)
      {
          return buffer instanceof IndirectNIOBuffer;
      }

      /* ------------------------------------------------------------------------------- */
      @Override
      protected boolean isResponseHeader(Buffer buffer)
      {
          return buffer instanceof IndirectNIOBuffer;
      }

}
TOP

Related Classes of com.taobao.jetty.apr.AprSocketConnector$SocketWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.