You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by jf...@apache.org on 2002/01/05 11:03:43 UTC

cvs commit: jakarta-tomcat-connectors/jk/native2/tomcat UnixSocket.c

jfclere     02/01/05 02:03:43

  Modified:    jk/java/org/apache/jk/server JkMain.java
               jk/native2 build.xml
  Added:       jk/java/org/apache/jk/common ChannelUnixSocket.java
               jk/native2/tomcat UnixSocket.c
  Log:
  Add code for AF_UNIX sockets.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/common/ChannelUnixSocket.java
  
  Index: ChannelUnixSocket.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.jk.common;
  
  import java.io.*;
  
  import java.net.*;
  import java.util.*;
  
  import org.apache.tomcat.util.buf.*;
  import org.apache.tomcat.util.http.*;
  
  import org.apache.tomcat.util.threads.*;
  
  import org.apache.jk.core.*;
  
  
  /* XXX Make the 'message type' pluggable
   */
  
  /* A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
     TCP, Ajp14 API etc.
     As we add other protocols/transports/APIs this will change, the current goal
     is to get the same level of functionality as in the original jk connector.
  */
  
  /**
   *  Jk2 can use multiple protocols/transports.
   *  Various container adapters should load this object ( as a bean ),
   *  set configurations and use it. Note that the connector will handle
   *  all incoming protocols - it's not specific to ajp1x. The protocol
   *  is abstracted by Endpoint/Message/Channel.
   */
  
  
  /** Accept ( and send ) messages via Unix Socket (AF_UNIX).
   * The AF_UNIX is not supported by JAVA so we need a piece of native code.
   *
   * @author Costin Manolache
   * @author Jean-Frederic Clere (Well, I have copied Costin's code and ideas).
   */
  public class ChannelUnixSocket extends Channel {
  
      /* XXX do not have port/Address */
      // int port;
      // InetAddress inet;
      int serverTimeout;
      boolean tcpNoDelay;
      int linger=100;
      int socketTimeout;
  
      Worker worker;
  
      ThreadPool tp=new ThreadPool();
  
      /* ==================== socket options ==================== */
  
      public ThreadPool getThreadPool() {
          return tp;
      }
      
      public void setPort( int port ) {
          // this.port=port;
      }
  
      public void setWorker( Worker w ) {
          worker=w;
      }
  
      public Worker getWorker() {
          return worker;
      }
  
      public void setAddress(InetAddress inet) {
          // this.inet=inet;
          // XXX we have to set the filename for the AF_UNIX socket.
      }
  
      /**
       * Sets the timeout in ms of the server sockets created by this
       * server. This method allows the developer to make servers
       * more or less responsive to having their server sockets
       * shut down.
       *
       * <p>By default this value is 1000ms.
       */
      public void setServerTimeout(int timeout) {
  	this.serverTimeout = timeout;
      }
  
      public void setTcpNoDelay( boolean b ) {
  	tcpNoDelay=b;
      }
  
      public void setSoLinger( int i ) {
  	linger=i;
      }
  
      public void setSoTimeout( int i ) {
  	socketTimeout=i;
      }
      UnixSocketServer sSocket; // File descriptor of the AF_UNIX server socket.
      
  
      /* ==================== ==================== */
      int socketNote=1; // File descriptor.
      int isNote=2; // Input Stream.
      int osNote=3; // Output Stream.
  
      public void accept( Endpoint ep ) throws IOException {
          UnixSocket s =sSocket.accept();
          ep.setNote( socketNote, s );
          if(dL>0 )
              d("Accepted socket " + s );
          if( linger > 0 )
              s.setSoLinger( true, linger);
  
          InputStream is=new UnixSocketIn(s.fd);
          OutputStream os=new UnixSocketOut(s.fd);
          ep.setNote( isNote, is );
          ep.setNote( osNote, os );
      }
  
      public void init() throws IOException {
          // I have put it here...
          // It load libunixsocket.so in jre/lib/i386 in my Linux using a Sun JVM.
          System.loadLibrary("unixsocket");
          sSocket=new UnixSocketServer(); // port );
          if( serverTimeout > 0 )
              sSocket.setSoTimeout( serverTimeout );
  
          // Run a thread that will accept connections.
          tp.start();
          SocketAcceptor acceptAjp=new SocketAcceptor(  this );
          tp.runIt( acceptAjp);
      }
  
      public void open(Endpoint ep) throws IOException {
      }
  
      
      public void close(Endpoint ep) throws IOException {
          Socket s=(Socket)ep.getNote( socketNote );
          s.close();
      }
  
      public void destroy() throws IOException {
          try {
              tp.shutdown();
  
              // Need to create a connection to unlock the accept();
              // I do not if this is needed but the file should be removed.
  /*
              Socket s;
              if (inet == null) {
                  s=new Socket("127.0.0.1", port );
              }else{
                  s=new Socket(inet, port );
                  // setting soLinger to a small value will help shutdown the
                  // connection quicker
                  s.setSoLinger(true, 0);
              }
              s.close();
   */
              sSocket.close(); // XXX?
          } catch(Exception e) {
              e.printStackTrace();
          }
      }
  
      public void write( Endpoint ep, byte[] b, int offset, int len) throws IOException {
          OutputStream os=(OutputStream)ep.getNote( osNote );
  
          os.write( b, offset, len );
      }
      
      /**
       * Read N bytes from the InputStream, and ensure we got them all
       * Under heavy load we could experience many fragmented packets
       * just read Unix Network Programming to recall that a call to
       * read didn't ensure you got all the data you want
       *
       * from read() Linux manual
       *
       * On success, the number of bytes read is returned (zero indicates end of file),
       * and the file position is advanced by this number.
       * It is not an error if this number is smaller than the number of bytes requested;
       * this may happen for example because fewer bytes
       * are actually available right now (maybe because we were close to end-of-file,
       * or because we are reading from a pipe, or  from  a
       * terminal),  or  because  read()  was interrupted by a signal.
       * On error, -1 is returned, and errno is set appropriately. In this
       * case it is left unspecified whether the file position (if any) changes.
       *
       **/
      public int read( Endpoint ep, byte[] b, int offset, int len) throws IOException {
          InputStream is=(InputStream)ep.getNote( isNote );
          int pos = 0;
          int got;
  
          if (dL > 5) {
              d("reading  # " + b + " " + (b==null ? 0: b.length) + " " + offset + " " + len);
          }
          while(pos < len) {
              got = is.read(b, pos + offset, len - pos);
  
              if (dL > 5) {
                  d("read got # " + got);
              }
  
              // connection just closed by remote. 
              if (got <= 0) {
                  // This happens periodically, as apache restarts
                  // periodically.
                  // It should be more gracefull ! - another feature for Ajp14 
                  return -3;
              }
  
              pos += got;
          }
          return pos;
      }
  
      
      
      public Endpoint createEndpoint() {
          return new Endpoint();
      }
  
      boolean running=true;
      
      /** Accept incoming connections, dispatch to the thread pool
       */
      void acceptConnections() {
          if( dL>0 )
              d("Accepting ajp connections");
          while( running ) {
              try {
                  Endpoint ep=this.createEndpoint();
                  this.accept(ep);
                  SocketConnection ajpConn=
                      new SocketConnection(this, ep);
                  tp.runIt( ajpConn );
              } catch( Exception ex ) {
                  ex.printStackTrace();
              }
          }
      }
  
      /** Process a single ajp connection.
       */
      void processConnection(Endpoint ep) {
          if( dL > 0 )
              d( "New ajp connection ");
          try {
              MsgAjp recv=new MsgAjp();
              while( running ) {
                  recv.receive( this, ep );
                  int status=we.processCallbacks( this, ep, recv );
              }
              this.close( ep );
          } catch( Exception ex ) {
              ex.printStackTrace();
          }
      }
      
      private static final int dL=10;
      private static void d(String s ) {
          System.err.println( "ChannelUnixSocket: " + s );
      }
  
  }
  
  class SocketAcceptor implements ThreadPoolRunnable {
      ChannelUnixSocket wajp;
      
      SocketAcceptor(ChannelUnixSocket wajp ) {
          this.wajp=wajp;
      }
  
      public Object[] getInitData() {
          return null;
      }
  
      public void runIt(Object thD[]) {
          wajp.acceptConnections();
      }
  }
  
  class SocketConnection implements ThreadPoolRunnable {
      ChannelUnixSocket wajp;
      Endpoint ep;
  
      SocketConnection(ChannelUnixSocket wajp, Endpoint ep) {
          this.wajp=wajp;
          this.ep=ep;
      }
  
  
      public Object[] getInitData() {
          return null;
      }
      
      public void runIt(Object perTh[]) {
          wajp.processConnection(ep);
      }
  }
  
  /**
   * Native AF_UNIX socket server
   */
  class UnixSocketServer {
      private int fd; // From socket + bind.
  
      private static native int createSocketNative (String filename);
  
      private static native int acceptNative (int fd);
      private static native int closeNative (int fd);
      private static native int setSoTimeoutNative (int fd,int value);
  
      public UnixSocketServer() throws IOException {
          fd = createSocketNative("/usr/tmp/apache_socket");
          if (fd<0) 
              throw new IOException();	
      }
      public UnixSocket accept() throws IOException {
          UnixSocket socket = new UnixSocket();
          socket.fd = acceptNative(this.fd);
          if (socket.fd<0)
              throw new IOException();
          return socket;
      }
      public void setSoTimeout(int value) throws SocketException {
          if (setSoTimeoutNative(this.fd, value)<0)
              throw new SocketException();
      }
      public void close() {
          closeNative(this.fd);
      }
  }
  /**
   * Native AF_UNIX socket
   */
  class UnixSocket {
      public int fd; // From accept.
  
      private static native int setSoLingerNative (int fd, int l_onoff,
                                                   int l_linger);
  
      public void setSoLinger  (boolean bool ,int l_linger) throws IOException {
          int l_onoff=0;
          if (bool)
              l_onoff = 1;
          if (setSoLingerNative(fd,l_onoff,l_linger)<0)
              throw new IOException();
      }
  }
  /**
   * Provide an InputStream for the native socket.
   */
  class UnixSocketIn extends InputStream {
      private int fd; // From openNative.
  
      private static native int readNative (int fd,  byte buf [], int len);
  
      public int read() throws IOException {
          byte buf [] = new byte[1];
          if (readNative(fd,buf,1) < 0)
              throw new IOException();
          return 0xff & buf[0];
      }
      public UnixSocketIn(int fd) {
          this.fd = fd;
      }
  }
  
  /**
   * Provide an OutputStream for the native socket.
   */
  class UnixSocketOut extends OutputStream {
      private int fd; // From openNative.
  
      private static native int writeNative (int fd,  byte buf [], int len);
  
      public void write(int value) throws IOException {
          byte buf [] = new byte[] { (byte) value };
          if (writeNative(fd,buf,1) < 0)
              throw new IOException();
      }
  
      public UnixSocketOut(int fd) {
          this.fd = fd;
      }
  }
  
  
  
  1.2       +3 -0      jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java
  
  Index: JkMain.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JkMain.java	31 Dec 2001 19:09:59 -0000	1.1
  +++ JkMain.java	5 Jan 2002 10:03:43 -0000	1.2
  @@ -87,7 +87,10 @@
       public void start() throws IOException {
           ChannelSocket csocket=new ChannelSocket();
           csocket.setPort( 8009 );
  +        /*
  +        ChannelUnixSocket csocket=new ChannelUnixSocket(); // JFC tests
           wEnv.addChannel( csocket );
  +         */
   
           WorkerDummy wdummy=new WorkerDummy();
           csocket.setWorker( wdummy );
  
  
  
  1.9       +30 -1     jakarta-tomcat-connectors/jk/native2/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/build.xml,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- build.xml	31 Dec 2001 22:25:03 -0000	1.8
  +++ build.xml	5 Jan 2002 10:03:43 -0000	1.9
  @@ -43,7 +43,7 @@
   
     <!-- ==================== Targets ==================== -->
   
  -  <target name="main" depends="init,apache20,jni,apache13">
  +  <target name="main" depends="init,apache20,jni,apache13,unixsocket">
     </target>
   
     <target name="init" >
  @@ -406,4 +406,33 @@
       </delete>
     </target>
   
  +  <target name="unixsocket" depends="init" if="useunixsocket">
  +    <mkdir dir="${jk.build}/WEB-INF/jk2/unixsocket" />
  +    <so sofile="libunixsocket" 
  +	buildDir="${jk.build}/WEB-INF/jk2/unixsocket"
  +	optimize="${so.optimize}"
  +	debug="${so.debug}"
  +	profile="${so.profile}">
  +
  +      <src dir=".">
  +	<include name="tomcat/UnixSocket.c" />
  +        <!-- When APR will provide the AF_UNIX socket support -->
  +        <!--
  +        <include name="common/apr/*.c" if="HAVE_APR" />
  +         -->
  +      </src>
  +      <includes>
  +	<include name="${java.home}/../include" />
  +
  +        <!-- Platform specific includes -->
  +        <include name="${java.home}/../include/netware" if="netware" />
  +        <include name="${java.home}/../include/win32" if="win32" />
  +        <include name="${java.home}/../include/linux" if="linux" />
  +      </includes>
  +      <depends>
  +	<fileset dir="${native.dir}/common" includes="*.h" />
  +      </depends>
  +
  +    </so>
  +  </target>
   </project>
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native2/tomcat/UnixSocket.c
  
  Index: UnixSocket.c
  ===================================================================
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <sys/socket.h>
  #include <fcntl.h>
  #include <errno.h>
  #include <sys/un.h> /* for sockaddr_un */
  #include <unistd.h>
  
  #include <jni.h>
  
  /*
   * Native routines for
   * package org.apache.jk.common
   */
  
  /**
   * createSocketNative: Creates a AF_UNIX socketserver.
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketServer_createSocketNative (
      JNIEnv      *env,
      jobject     ignored,
      jstring     filename
  ) {
      int         sd;
      const char  *real_filename;
      jboolean    flag;
      struct sockaddr_un unix_addr;
      mode_t omask;
      int rc;
  
      // Convert java encoding in machine one.
      real_filename = (*env)->GetStringUTFChars (env, filename, &flag);
      if (real_filename == 0)
          return -EINVAL;
  
      // remove the exist socket.
      if (unlink(real_filename) < 0 && errno != ENOENT) {
          // The socket cannot be remove... Well I hope that no problems ;-)
      }
  
      // create the socket.
      sd = socket(AF_UNIX, SOCK_STREAM, 0);
      if (sd<0)
          return -errno;
  
      memset(&unix_addr, 0, sizeof(unix_addr));
      unix_addr.sun_family = AF_UNIX;
      strcpy(unix_addr.sun_path, real_filename);
  
      omask = umask(0117); /* so that only Apache can use socket */
      rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
      umask(omask); /* can't fail, so can't clobber errno */
      if (rc<0)
         return -errno;
  
      if (listen(sd, 100) < 0) {
          return -errno;
      }
  
      (*env)->ReleaseStringUTFChars (env, filename, real_filename);
  
      return sd;
  }
  
  /**
   * accept(). Accepts incomming calls on socket.
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketServer_acceptNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        sd
  ) {
      struct sockaddr_un unix_addr;
      int sd2;
      int len;
  
      len = sizeof(unix_addr);
      sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
      if (sd2<0)
          return - errno;
      return(sd2);
      
  }
  
  /**
   * set the socket timeout (read/write) or accept() ?
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketServer_setSoTimeoutNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        sd
  ) {
      // setsockopt or setitimer?
  }
  
  /**
   * close the socket (remove the file?)
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketServer_closeNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        sd
  ) {
      close(sd);
  }
  
  /**
   * setSoLinger
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocket_setSoLingerNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        sd,
      jint        l_onoff,
      jint        l_linger
  ) {
      struct linger {
          int   l_onoff;    /* linger active */
          int   l_linger;   /* how many seconds to linger for */
          } lin;
      lin.l_onoff = l_onoff;
      lin.l_linger = l_linger;
      if (setsockopt(sd, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin))<0)
          return -errno;
      return 0;
  }
  
  /**
   * read from the socket.
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketIn_readNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        fd,
      jbyteArray  buf,
      jint        len
  ) {
      int retval;
      jbyte *buffer;
      jboolean    isCopy;
  
      buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
  
      retval = read(fd,buffer,len);
  
      (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
  
      return retval;
  }
  
  /**
   * write to the socket.
   */
  JNIEXPORT jint JNICALL
  Java_org_apache_jk_common_UnixSocketOut_writeNative (
      JNIEnv      *env,
      jobject     ignored,
      jint        fd,
      jbyteArray  buf,
      jint        len
  ) {
      int retval;
      jbyte *buffer;
      jboolean    isCopy;
  
      buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
  
      retval = write(fd,buffer,len);
  
      (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
  
      return retval;
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-connectors/jk/native2/tomcat UnixSocket.c

Posted by jean-frederic clere <jf...@fujitsu-siemens.com>.
cmanolache@yahoo.com wrote:
> 
> I've also wrote the unix socket code, in the jni directory.

APR is going to support unix sockets. So I will wait a little before going on
;-))

> 
> I'll check in my version too, and try a merge later ( I've also got the
> jkservlet working with both 3.3 and 4.0, things look pretty good )
> 
> Costin
> 
> On 5 Jan 2002 jfclere@apache.org wrote:
> 
> > jfclere     02/01/05 02:03:43
> >
> >   Modified:    jk/java/org/apache/jk/server JkMain.java
> >                jk/native2 build.xml
> >   Added:       jk/java/org/apache/jk/common ChannelUnixSocket.java
> >                jk/native2/tomcat UnixSocket.c
> >   Log:
> >   Add code for AF_UNIX sockets.
> >
> >   Revision  Changes    Path
> >   1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/common/ChannelUnixSocket.java
> >
> >   Index: ChannelUnixSocket.java
> >   ===================================================================
> >   /*
> >    * ====================================================================
> >    *
> >    * The Apache Software License, Version 1.1
> >    *
> >    * Copyright (c) 1999 The Apache Software Foundation.  All rights
> >    * reserved.
> >    *
> >    * Redistribution and use in source and binary forms, with or without
> >    * modification, are permitted provided that the following conditions
> >    * are met:
> >    *
> >    * 1. Redistributions of source code must retain the above copyright
> >    *    notice, this list of conditions and the following disclaimer.
> >    *
> >    * 2. Redistributions in binary form must reproduce the above copyright
> >    *    notice, this list of conditions and the following disclaimer in
> >    *    the documentation and/or other materials provided with the
> >    *    distribution.
> >    *
> >    * 3. The end-user documentation included with the redistribution, if
> >    *    any, must include the following acknowlegement:
> >    *       "This product includes software developed by the
> >    *        Apache Software Foundation (http://www.apache.org/)."
> >    *    Alternately, this acknowlegement may appear in the software itself,
> >    *    if and wherever such third-party acknowlegements normally appear.
> >    *
> >    * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
> >    *    Foundation" must not be used to endorse or promote products derived
> >    *    from this software without prior written permission. For written
> >    *    permission, please contact apache@apache.org.
> >    *
> >    * 5. Products derived from this software may not be called "Apache"
> >    *    nor may "Apache" appear in their names without prior written
> >    *    permission of the Apache Group.
> >    *
> >    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> >    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> >    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> >    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> >    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> >    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> >    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> >    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> >    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> >    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> >    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >    * SUCH DAMAGE.
> >    * ====================================================================
> >    *
> >    * This software consists of voluntary contributions made by many
> >    * individuals on behalf of the Apache Software Foundation.  For more
> >    * information on the Apache Software Foundation, please see
> >    * <http://www.apache.org/>.
> >    *
> >    * [Additional notices, if required by prior licensing conditions]
> >    *
> >    */
> >
> >   package org.apache.jk.common;
> >
> >   import java.io.*;
> >
> >   import java.net.*;
> >   import java.util.*;
> >
> >   import org.apache.tomcat.util.buf.*;
> >   import org.apache.tomcat.util.http.*;
> >
> >   import org.apache.tomcat.util.threads.*;
> >
> >   import org.apache.jk.core.*;
> >
> >
> >   /* XXX Make the 'message type' pluggable
> >    */
> >
> >   /* A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
> >      TCP, Ajp14 API etc.
> >      As we add other protocols/transports/APIs this will change, the current goal
> >      is to get the same level of functionality as in the original jk connector.
> >   */
> >
> >   /**
> >    *  Jk2 can use multiple protocols/transports.
> >    *  Various container adapters should load this object ( as a bean ),
> >    *  set configurations and use it. Note that the connector will handle
> >    *  all incoming protocols - it's not specific to ajp1x. The protocol
> >    *  is abstracted by Endpoint/Message/Channel.
> >    */
> >
> >
> >   /** Accept ( and send ) messages via Unix Socket (AF_UNIX).
> >    * The AF_UNIX is not supported by JAVA so we need a piece of native code.
> >    *
> >    * @author Costin Manolache
> >    * @author Jean-Frederic Clere (Well, I have copied Costin's code and ideas).
> >    */
> >   public class ChannelUnixSocket extends Channel {
> >
> >       /* XXX do not have port/Address */
> >       // int port;
> >       // InetAddress inet;
> >       int serverTimeout;
> >       boolean tcpNoDelay;
> >       int linger=100;
> >       int socketTimeout;
> >
> >       Worker worker;
> >
> >       ThreadPool tp=new ThreadPool();
> >
> >       /* ==================== socket options ==================== */
> >
> >       public ThreadPool getThreadPool() {
> >           return tp;
> >       }
> >
> >       public void setPort( int port ) {
> >           // this.port=port;
> >       }
> >
> >       public void setWorker( Worker w ) {
> >           worker=w;
> >       }
> >
> >       public Worker getWorker() {
> >           return worker;
> >       }
> >
> >       public void setAddress(InetAddress inet) {
> >           // this.inet=inet;
> >           // XXX we have to set the filename for the AF_UNIX socket.
> >       }
> >
> >       /**
> >        * Sets the timeout in ms of the server sockets created by this
> >        * server. This method allows the developer to make servers
> >        * more or less responsive to having their server sockets
> >        * shut down.
> >        *
> >        * <p>By default this value is 1000ms.
> >        */
> >       public void setServerTimeout(int timeout) {
> >       this.serverTimeout = timeout;
> >       }
> >
> >       public void setTcpNoDelay( boolean b ) {
> >       tcpNoDelay=b;
> >       }
> >
> >       public void setSoLinger( int i ) {
> >       linger=i;
> >       }
> >
> >       public void setSoTimeout( int i ) {
> >       socketTimeout=i;
> >       }
> >       UnixSocketServer sSocket; // File descriptor of the AF_UNIX server socket.
> >
> >
> >       /* ==================== ==================== */
> >       int socketNote=1; // File descriptor.
> >       int isNote=2; // Input Stream.
> >       int osNote=3; // Output Stream.
> >
> >       public void accept( Endpoint ep ) throws IOException {
> >           UnixSocket s =sSocket.accept();
> >           ep.setNote( socketNote, s );
> >           if(dL>0 )
> >               d("Accepted socket " + s );
> >           if( linger > 0 )
> >               s.setSoLinger( true, linger);
> >
> >           InputStream is=new UnixSocketIn(s.fd);
> >           OutputStream os=new UnixSocketOut(s.fd);
> >           ep.setNote( isNote, is );
> >           ep.setNote( osNote, os );
> >       }
> >
> >       public void init() throws IOException {
> >           // I have put it here...
> >           // It load libunixsocket.so in jre/lib/i386 in my Linux using a Sun JVM.
> >           System.loadLibrary("unixsocket");
> >           sSocket=new UnixSocketServer(); // port );
> >           if( serverTimeout > 0 )
> >               sSocket.setSoTimeout( serverTimeout );
> >
> >           // Run a thread that will accept connections.
> >           tp.start();
> >           SocketAcceptor acceptAjp=new SocketAcceptor(  this );
> >           tp.runIt( acceptAjp);
> >       }
> >
> >       public void open(Endpoint ep) throws IOException {
> >       }
> >
> >
> >       public void close(Endpoint ep) throws IOException {
> >           Socket s=(Socket)ep.getNote( socketNote );
> >           s.close();
> >       }
> >
> >       public void destroy() throws IOException {
> >           try {
> >               tp.shutdown();
> >
> >               // Need to create a connection to unlock the accept();
> >               // I do not if this is needed but the file should be removed.
> >   /*
> >               Socket s;
> >               if (inet == null) {
> >                   s=new Socket("127.0.0.1", port );
> >               }else{
> >                   s=new Socket(inet, port );
> >                   // setting soLinger to a small value will help shutdown the
> >                   // connection quicker
> >                   s.setSoLinger(true, 0);
> >               }
> >               s.close();
> >    */
> >               sSocket.close(); // XXX?
> >           } catch(Exception e) {
> >               e.printStackTrace();
> >           }
> >       }
> >
> >       public void write( Endpoint ep, byte[] b, int offset, int len) throws IOException {
> >           OutputStream os=(OutputStream)ep.getNote( osNote );
> >
> >           os.write( b, offset, len );
> >       }
> >
> >       /**
> >        * Read N bytes from the InputStream, and ensure we got them all
> >        * Under heavy load we could experience many fragmented packets
> >        * just read Unix Network Programming to recall that a call to
> >        * read didn't ensure you got all the data you want
> >        *
> >        * from read() Linux manual
> >        *
> >        * On success, the number of bytes read is returned (zero indicates end of file),
> >        * and the file position is advanced by this number.
> >        * It is not an error if this number is smaller than the number of bytes requested;
> >        * this may happen for example because fewer bytes
> >        * are actually available right now (maybe because we were close to end-of-file,
> >        * or because we are reading from a pipe, or  from  a
> >        * terminal),  or  because  read()  was interrupted by a signal.
> >        * On error, -1 is returned, and errno is set appropriately. In this
> >        * case it is left unspecified whether the file position (if any) changes.
> >        *
> >        **/
> >       public int read( Endpoint ep, byte[] b, int offset, int len) throws IOException {
> >           InputStream is=(InputStream)ep.getNote( isNote );
> >           int pos = 0;
> >           int got;
> >
> >           if (dL > 5) {
> >               d("reading  # " + b + " " + (b==null ? 0: b.length) + " " + offset + " " + len);
> >           }
> >           while(pos < len) {
> >               got = is.read(b, pos + offset, len - pos);
> >
> >               if (dL > 5) {
> >                   d("read got # " + got);
> >               }
> >
> >               // connection just closed by remote.
> >               if (got <= 0) {
> >                   // This happens periodically, as apache restarts
> >                   // periodically.
> >                   // It should be more gracefull ! - another feature for Ajp14
> >                   return -3;
> >               }
> >
> >               pos += got;
> >           }
> >           return pos;
> >       }
> >
> >
> >
> >       public Endpoint createEndpoint() {
> >           return new Endpoint();
> >       }
> >
> >       boolean running=true;
> >
> >       /** Accept incoming connections, dispatch to the thread pool
> >        */
> >       void acceptConnections() {
> >           if( dL>0 )
> >               d("Accepting ajp connections");
> >           while( running ) {
> >               try {
> >                   Endpoint ep=this.createEndpoint();
> >                   this.accept(ep);
> >                   SocketConnection ajpConn=
> >                       new SocketConnection(this, ep);
> >                   tp.runIt( ajpConn );
> >               } catch( Exception ex ) {
> >                   ex.printStackTrace();
> >               }
> >           }
> >       }
> >
> >       /** Process a single ajp connection.
> >        */
> >       void processConnection(Endpoint ep) {
> >           if( dL > 0 )
> >               d( "New ajp connection ");
> >           try {
> >               MsgAjp recv=new MsgAjp();
> >               while( running ) {
> >                   recv.receive( this, ep );
> >                   int status=we.processCallbacks( this, ep, recv );
> >               }
> >               this.close( ep );
> >           } catch( Exception ex ) {
> >               ex.printStackTrace();
> >           }
> >       }
> >
> >       private static final int dL=10;
> >       private static void d(String s ) {
> >           System.err.println( "ChannelUnixSocket: " + s );
> >       }
> >
> >   }
> >
> >   class SocketAcceptor implements ThreadPoolRunnable {
> >       ChannelUnixSocket wajp;
> >
> >       SocketAcceptor(ChannelUnixSocket wajp ) {
> >           this.wajp=wajp;
> >       }
> >
> >       public Object[] getInitData() {
> >           return null;
> >       }
> >
> >       public void runIt(Object thD[]) {
> >           wajp.acceptConnections();
> >       }
> >   }
> >
> >   class SocketConnection implements ThreadPoolRunnable {
> >       ChannelUnixSocket wajp;
> >       Endpoint ep;
> >
> >       SocketConnection(ChannelUnixSocket wajp, Endpoint ep) {
> >           this.wajp=wajp;
> >           this.ep=ep;
> >       }
> >
> >
> >       public Object[] getInitData() {
> >           return null;
> >       }
> >
> >       public void runIt(Object perTh[]) {
> >           wajp.processConnection(ep);
> >       }
> >   }
> >
> >   /**
> >    * Native AF_UNIX socket server
> >    */
> >   class UnixSocketServer {
> >       private int fd; // From socket + bind.
> >
> >       private static native int createSocketNative (String filename);
> >
> >       private static native int acceptNative (int fd);
> >       private static native int closeNative (int fd);
> >       private static native int setSoTimeoutNative (int fd,int value);
> >
> >       public UnixSocketServer() throws IOException {
> >           fd = createSocketNative("/usr/tmp/apache_socket");
> >           if (fd<0)
> >               throw new IOException();
> >       }
> >       public UnixSocket accept() throws IOException {
> >           UnixSocket socket = new UnixSocket();
> >           socket.fd = acceptNative(this.fd);
> >           if (socket.fd<0)
> >               throw new IOException();
> >           return socket;
> >       }
> >       public void setSoTimeout(int value) throws SocketException {
> >           if (setSoTimeoutNative(this.fd, value)<0)
> >               throw new SocketException();
> >       }
> >       public void close() {
> >           closeNative(this.fd);
> >       }
> >   }
> >   /**
> >    * Native AF_UNIX socket
> >    */
> >   class UnixSocket {
> >       public int fd; // From accept.
> >
> >       private static native int setSoLingerNative (int fd, int l_onoff,
> >                                                    int l_linger);
> >
> >       public void setSoLinger  (boolean bool ,int l_linger) throws IOException {
> >           int l_onoff=0;
> >           if (bool)
> >               l_onoff = 1;
> >           if (setSoLingerNative(fd,l_onoff,l_linger)<0)
> >               throw new IOException();
> >       }
> >   }
> >   /**
> >    * Provide an InputStream for the native socket.
> >    */
> >   class UnixSocketIn extends InputStream {
> >       private int fd; // From openNative.
> >
> >       private static native int readNative (int fd,  byte buf [], int len);
> >
> >       public int read() throws IOException {
> >           byte buf [] = new byte[1];
> >           if (readNative(fd,buf,1) < 0)
> >               throw new IOException();
> >           return 0xff & buf[0];
> >       }
> >       public UnixSocketIn(int fd) {
> >           this.fd = fd;
> >       }
> >   }
> >
> >   /**
> >    * Provide an OutputStream for the native socket.
> >    */
> >   class UnixSocketOut extends OutputStream {
> >       private int fd; // From openNative.
> >
> >       private static native int writeNative (int fd,  byte buf [], int len);
> >
> >       public void write(int value) throws IOException {
> >           byte buf [] = new byte[] { (byte) value };
> >           if (writeNative(fd,buf,1) < 0)
> >               throw new IOException();
> >       }
> >
> >       public UnixSocketOut(int fd) {
> >           this.fd = fd;
> >       }
> >   }
> >
> >
> >
> >   1.2       +3 -0      jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java
> >
> >   Index: JkMain.java
> >   ===================================================================
> >   RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java,v
> >   retrieving revision 1.1
> >   retrieving revision 1.2
> >   diff -u -r1.1 -r1.2
> >   --- JkMain.java     31 Dec 2001 19:09:59 -0000      1.1
> >   +++ JkMain.java     5 Jan 2002 10:03:43 -0000       1.2
> >   @@ -87,7 +87,10 @@
> >        public void start() throws IOException {
> >            ChannelSocket csocket=new ChannelSocket();
> >            csocket.setPort( 8009 );
> >   +        /*
> >   +        ChannelUnixSocket csocket=new ChannelUnixSocket(); // JFC tests
> >            wEnv.addChannel( csocket );
> >   +         */
> >
> >            WorkerDummy wdummy=new WorkerDummy();
> >            csocket.setWorker( wdummy );
> >
> >
> >
> >   1.9       +30 -1     jakarta-tomcat-connectors/jk/native2/build.xml
> >
> >   Index: build.xml
> >   ===================================================================
> >   RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/build.xml,v
> >   retrieving revision 1.8
> >   retrieving revision 1.9
> >   diff -u -r1.8 -r1.9
> >   --- build.xml       31 Dec 2001 22:25:03 -0000      1.8
> >   +++ build.xml       5 Jan 2002 10:03:43 -0000       1.9
> >   @@ -43,7 +43,7 @@
> >
> >      <!-- ==================== Targets ==================== -->
> >
> >   -  <target name="main" depends="init,apache20,jni,apache13">
> >   +  <target name="main" depends="init,apache20,jni,apache13,unixsocket">
> >      </target>
> >
> >      <target name="init" >
> >   @@ -406,4 +406,33 @@
> >        </delete>
> >      </target>
> >
> >   +  <target name="unixsocket" depends="init" if="useunixsocket">
> >   +    <mkdir dir="${jk.build}/WEB-INF/jk2/unixsocket" />
> >   +    <so sofile="libunixsocket"
> >   +   buildDir="${jk.build}/WEB-INF/jk2/unixsocket"
> >   +   optimize="${so.optimize}"
> >   +   debug="${so.debug}"
> >   +   profile="${so.profile}">
> >   +
> >   +      <src dir=".">
> >   +   <include name="tomcat/UnixSocket.c" />
> >   +        <!-- When APR will provide the AF_UNIX socket support -->
> >   +        <!--
> >   +        <include name="common/apr/*.c" if="HAVE_APR" />
> >   +         -->
> >   +      </src>
> >   +      <includes>
> >   +   <include name="${java.home}/../include" />
> >   +
> >   +        <!-- Platform specific includes -->
> >   +        <include name="${java.home}/../include/netware" if="netware" />
> >   +        <include name="${java.home}/../include/win32" if="win32" />
> >   +        <include name="${java.home}/../include/linux" if="linux" />
> >   +      </includes>
> >   +      <depends>
> >   +   <fileset dir="${native.dir}/common" includes="*.h" />
> >   +      </depends>
> >   +
> >   +    </so>
> >   +  </target>
> >    </project>
> >
> >
> >
> >   1.1                  jakarta-tomcat-connectors/jk/native2/tomcat/UnixSocket.c
> >
> >   Index: UnixSocket.c
> >   ===================================================================
> >   #include <sys/types.h>
> >   #include <sys/stat.h>
> >   #include <sys/socket.h>
> >   #include <fcntl.h>
> >   #include <errno.h>
> >   #include <sys/un.h> /* for sockaddr_un */
> >   #include <unistd.h>
> >
> >   #include <jni.h>
> >
> >   /*
> >    * Native routines for
> >    * package org.apache.jk.common
> >    */
> >
> >   /**
> >    * createSocketNative: Creates a AF_UNIX socketserver.
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketServer_createSocketNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jstring     filename
> >   ) {
> >       int         sd;
> >       const char  *real_filename;
> >       jboolean    flag;
> >       struct sockaddr_un unix_addr;
> >       mode_t omask;
> >       int rc;
> >
> >       // Convert java encoding in machine one.
> >       real_filename = (*env)->GetStringUTFChars (env, filename, &flag);
> >       if (real_filename == 0)
> >           return -EINVAL;
> >
> >       // remove the exist socket.
> >       if (unlink(real_filename) < 0 && errno != ENOENT) {
> >           // The socket cannot be remove... Well I hope that no problems ;-)
> >       }
> >
> >       // create the socket.
> >       sd = socket(AF_UNIX, SOCK_STREAM, 0);
> >       if (sd<0)
> >           return -errno;
> >
> >       memset(&unix_addr, 0, sizeof(unix_addr));
> >       unix_addr.sun_family = AF_UNIX;
> >       strcpy(unix_addr.sun_path, real_filename);
> >
> >       omask = umask(0117); /* so that only Apache can use socket */
> >       rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
> >       umask(omask); /* can't fail, so can't clobber errno */
> >       if (rc<0)
> >          return -errno;
> >
> >       if (listen(sd, 100) < 0) {
> >           return -errno;
> >       }
> >
> >       (*env)->ReleaseStringUTFChars (env, filename, real_filename);
> >
> >       return sd;
> >   }
> >
> >   /**
> >    * accept(). Accepts incomming calls on socket.
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketServer_acceptNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        sd
> >   ) {
> >       struct sockaddr_un unix_addr;
> >       int sd2;
> >       int len;
> >
> >       len = sizeof(unix_addr);
> >       sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
> >       if (sd2<0)
> >           return - errno;
> >       return(sd2);
> >
> >   }
> >
> >   /**
> >    * set the socket timeout (read/write) or accept() ?
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketServer_setSoTimeoutNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        sd
> >   ) {
> >       // setsockopt or setitimer?
> >   }
> >
> >   /**
> >    * close the socket (remove the file?)
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketServer_closeNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        sd
> >   ) {
> >       close(sd);
> >   }
> >
> >   /**
> >    * setSoLinger
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocket_setSoLingerNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        sd,
> >       jint        l_onoff,
> >       jint        l_linger
> >   ) {
> >       struct linger {
> >           int   l_onoff;    /* linger active */
> >           int   l_linger;   /* how many seconds to linger for */
> >           } lin;
> >       lin.l_onoff = l_onoff;
> >       lin.l_linger = l_linger;
> >       if (setsockopt(sd, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin))<0)
> >           return -errno;
> >       return 0;
> >   }
> >
> >   /**
> >    * read from the socket.
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketIn_readNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        fd,
> >       jbyteArray  buf,
> >       jint        len
> >   ) {
> >       int retval;
> >       jbyte *buffer;
> >       jboolean    isCopy;
> >
> >       buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
> >
> >       retval = read(fd,buffer,len);
> >
> >       (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
> >
> >       return retval;
> >   }
> >
> >   /**
> >    * write to the socket.
> >    */
> >   JNIEXPORT jint JNICALL
> >   Java_org_apache_jk_common_UnixSocketOut_writeNative (
> >       JNIEnv      *env,
> >       jobject     ignored,
> >       jint        fd,
> >       jbyteArray  buf,
> >       jint        len
> >   ) {
> >       int retval;
> >       jbyte *buffer;
> >       jboolean    isCopy;
> >
> >       buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
> >
> >       retval = write(fd,buffer,len);
> >
> >       (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
> >
> >       return retval;
> >
> >   }
> >
> >
> >
> >
> > --
> > To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> > For additional commands, e-mail: <ma...@jakarta.apache.org>
> >
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-connectors/jk/native2/tomcat UnixSocket.c

Posted by cm...@yahoo.com.
I've also wrote the unix socket code, in the jni directory.

I'll check in my version too, and try a merge later ( I've also got the
jkservlet working with both 3.3 and 4.0, things look pretty good )


Costin


On 5 Jan 2002 jfclere@apache.org wrote:

> jfclere     02/01/05 02:03:43
>
>   Modified:    jk/java/org/apache/jk/server JkMain.java
>                jk/native2 build.xml
>   Added:       jk/java/org/apache/jk/common ChannelUnixSocket.java
>                jk/native2/tomcat UnixSocket.c
>   Log:
>   Add code for AF_UNIX sockets.
>
>   Revision  Changes    Path
>   1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/common/ChannelUnixSocket.java
>
>   Index: ChannelUnixSocket.java
>   ===================================================================
>   /*
>    * ====================================================================
>    *
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 1999 The Apache Software Foundation.  All rights
>    * reserved.
>    *
>    * Redistribution and use in source and binary forms, with or without
>    * modification, are permitted provided that the following conditions
>    * are met:
>    *
>    * 1. Redistributions of source code must retain the above copyright
>    *    notice, this list of conditions and the following disclaimer.
>    *
>    * 2. Redistributions in binary form must reproduce the above copyright
>    *    notice, this list of conditions and the following disclaimer in
>    *    the documentation and/or other materials provided with the
>    *    distribution.
>    *
>    * 3. The end-user documentation included with the redistribution, if
>    *    any, must include the following acknowlegement:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowlegement may appear in the software itself,
>    *    if and wherever such third-party acknowlegements normally appear.
>    *
>    * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
>    *    Foundation" must not be used to endorse or promote products derived
>    *    from this software without prior written permission. For written
>    *    permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache"
>    *    nor may "Apache" appear in their names without prior written
>    *    permission of the Apache Group.
>    *
>    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>    * SUCH DAMAGE.
>    * ====================================================================
>    *
>    * This software consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    *
>    * [Additional notices, if required by prior licensing conditions]
>    *
>    */
>
>   package org.apache.jk.common;
>
>   import java.io.*;
>
>   import java.net.*;
>   import java.util.*;
>
>   import org.apache.tomcat.util.buf.*;
>   import org.apache.tomcat.util.http.*;
>
>   import org.apache.tomcat.util.threads.*;
>
>   import org.apache.jk.core.*;
>
>
>   /* XXX Make the 'message type' pluggable
>    */
>
>   /* A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
>      TCP, Ajp14 API etc.
>      As we add other protocols/transports/APIs this will change, the current goal
>      is to get the same level of functionality as in the original jk connector.
>   */
>
>   /**
>    *  Jk2 can use multiple protocols/transports.
>    *  Various container adapters should load this object ( as a bean ),
>    *  set configurations and use it. Note that the connector will handle
>    *  all incoming protocols - it's not specific to ajp1x. The protocol
>    *  is abstracted by Endpoint/Message/Channel.
>    */
>
>
>   /** Accept ( and send ) messages via Unix Socket (AF_UNIX).
>    * The AF_UNIX is not supported by JAVA so we need a piece of native code.
>    *
>    * @author Costin Manolache
>    * @author Jean-Frederic Clere (Well, I have copied Costin's code and ideas).
>    */
>   public class ChannelUnixSocket extends Channel {
>
>       /* XXX do not have port/Address */
>       // int port;
>       // InetAddress inet;
>       int serverTimeout;
>       boolean tcpNoDelay;
>       int linger=100;
>       int socketTimeout;
>
>       Worker worker;
>
>       ThreadPool tp=new ThreadPool();
>
>       /* ==================== socket options ==================== */
>
>       public ThreadPool getThreadPool() {
>           return tp;
>       }
>
>       public void setPort( int port ) {
>           // this.port=port;
>       }
>
>       public void setWorker( Worker w ) {
>           worker=w;
>       }
>
>       public Worker getWorker() {
>           return worker;
>       }
>
>       public void setAddress(InetAddress inet) {
>           // this.inet=inet;
>           // XXX we have to set the filename for the AF_UNIX socket.
>       }
>
>       /**
>        * Sets the timeout in ms of the server sockets created by this
>        * server. This method allows the developer to make servers
>        * more or less responsive to having their server sockets
>        * shut down.
>        *
>        * <p>By default this value is 1000ms.
>        */
>       public void setServerTimeout(int timeout) {
>   	this.serverTimeout = timeout;
>       }
>
>       public void setTcpNoDelay( boolean b ) {
>   	tcpNoDelay=b;
>       }
>
>       public void setSoLinger( int i ) {
>   	linger=i;
>       }
>
>       public void setSoTimeout( int i ) {
>   	socketTimeout=i;
>       }
>       UnixSocketServer sSocket; // File descriptor of the AF_UNIX server socket.
>
>
>       /* ==================== ==================== */
>       int socketNote=1; // File descriptor.
>       int isNote=2; // Input Stream.
>       int osNote=3; // Output Stream.
>
>       public void accept( Endpoint ep ) throws IOException {
>           UnixSocket s =sSocket.accept();
>           ep.setNote( socketNote, s );
>           if(dL>0 )
>               d("Accepted socket " + s );
>           if( linger > 0 )
>               s.setSoLinger( true, linger);
>
>           InputStream is=new UnixSocketIn(s.fd);
>           OutputStream os=new UnixSocketOut(s.fd);
>           ep.setNote( isNote, is );
>           ep.setNote( osNote, os );
>       }
>
>       public void init() throws IOException {
>           // I have put it here...
>           // It load libunixsocket.so in jre/lib/i386 in my Linux using a Sun JVM.
>           System.loadLibrary("unixsocket");
>           sSocket=new UnixSocketServer(); // port );
>           if( serverTimeout > 0 )
>               sSocket.setSoTimeout( serverTimeout );
>
>           // Run a thread that will accept connections.
>           tp.start();
>           SocketAcceptor acceptAjp=new SocketAcceptor(  this );
>           tp.runIt( acceptAjp);
>       }
>
>       public void open(Endpoint ep) throws IOException {
>       }
>
>
>       public void close(Endpoint ep) throws IOException {
>           Socket s=(Socket)ep.getNote( socketNote );
>           s.close();
>       }
>
>       public void destroy() throws IOException {
>           try {
>               tp.shutdown();
>
>               // Need to create a connection to unlock the accept();
>               // I do not if this is needed but the file should be removed.
>   /*
>               Socket s;
>               if (inet == null) {
>                   s=new Socket("127.0.0.1", port );
>               }else{
>                   s=new Socket(inet, port );
>                   // setting soLinger to a small value will help shutdown the
>                   // connection quicker
>                   s.setSoLinger(true, 0);
>               }
>               s.close();
>    */
>               sSocket.close(); // XXX?
>           } catch(Exception e) {
>               e.printStackTrace();
>           }
>       }
>
>       public void write( Endpoint ep, byte[] b, int offset, int len) throws IOException {
>           OutputStream os=(OutputStream)ep.getNote( osNote );
>
>           os.write( b, offset, len );
>       }
>
>       /**
>        * Read N bytes from the InputStream, and ensure we got them all
>        * Under heavy load we could experience many fragmented packets
>        * just read Unix Network Programming to recall that a call to
>        * read didn't ensure you got all the data you want
>        *
>        * from read() Linux manual
>        *
>        * On success, the number of bytes read is returned (zero indicates end of file),
>        * and the file position is advanced by this number.
>        * It is not an error if this number is smaller than the number of bytes requested;
>        * this may happen for example because fewer bytes
>        * are actually available right now (maybe because we were close to end-of-file,
>        * or because we are reading from a pipe, or  from  a
>        * terminal),  or  because  read()  was interrupted by a signal.
>        * On error, -1 is returned, and errno is set appropriately. In this
>        * case it is left unspecified whether the file position (if any) changes.
>        *
>        **/
>       public int read( Endpoint ep, byte[] b, int offset, int len) throws IOException {
>           InputStream is=(InputStream)ep.getNote( isNote );
>           int pos = 0;
>           int got;
>
>           if (dL > 5) {
>               d("reading  # " + b + " " + (b==null ? 0: b.length) + " " + offset + " " + len);
>           }
>           while(pos < len) {
>               got = is.read(b, pos + offset, len - pos);
>
>               if (dL > 5) {
>                   d("read got # " + got);
>               }
>
>               // connection just closed by remote.
>               if (got <= 0) {
>                   // This happens periodically, as apache restarts
>                   // periodically.
>                   // It should be more gracefull ! - another feature for Ajp14
>                   return -3;
>               }
>
>               pos += got;
>           }
>           return pos;
>       }
>
>
>
>       public Endpoint createEndpoint() {
>           return new Endpoint();
>       }
>
>       boolean running=true;
>
>       /** Accept incoming connections, dispatch to the thread pool
>        */
>       void acceptConnections() {
>           if( dL>0 )
>               d("Accepting ajp connections");
>           while( running ) {
>               try {
>                   Endpoint ep=this.createEndpoint();
>                   this.accept(ep);
>                   SocketConnection ajpConn=
>                       new SocketConnection(this, ep);
>                   tp.runIt( ajpConn );
>               } catch( Exception ex ) {
>                   ex.printStackTrace();
>               }
>           }
>       }
>
>       /** Process a single ajp connection.
>        */
>       void processConnection(Endpoint ep) {
>           if( dL > 0 )
>               d( "New ajp connection ");
>           try {
>               MsgAjp recv=new MsgAjp();
>               while( running ) {
>                   recv.receive( this, ep );
>                   int status=we.processCallbacks( this, ep, recv );
>               }
>               this.close( ep );
>           } catch( Exception ex ) {
>               ex.printStackTrace();
>           }
>       }
>
>       private static final int dL=10;
>       private static void d(String s ) {
>           System.err.println( "ChannelUnixSocket: " + s );
>       }
>
>   }
>
>   class SocketAcceptor implements ThreadPoolRunnable {
>       ChannelUnixSocket wajp;
>
>       SocketAcceptor(ChannelUnixSocket wajp ) {
>           this.wajp=wajp;
>       }
>
>       public Object[] getInitData() {
>           return null;
>       }
>
>       public void runIt(Object thD[]) {
>           wajp.acceptConnections();
>       }
>   }
>
>   class SocketConnection implements ThreadPoolRunnable {
>       ChannelUnixSocket wajp;
>       Endpoint ep;
>
>       SocketConnection(ChannelUnixSocket wajp, Endpoint ep) {
>           this.wajp=wajp;
>           this.ep=ep;
>       }
>
>
>       public Object[] getInitData() {
>           return null;
>       }
>
>       public void runIt(Object perTh[]) {
>           wajp.processConnection(ep);
>       }
>   }
>
>   /**
>    * Native AF_UNIX socket server
>    */
>   class UnixSocketServer {
>       private int fd; // From socket + bind.
>
>       private static native int createSocketNative (String filename);
>
>       private static native int acceptNative (int fd);
>       private static native int closeNative (int fd);
>       private static native int setSoTimeoutNative (int fd,int value);
>
>       public UnixSocketServer() throws IOException {
>           fd = createSocketNative("/usr/tmp/apache_socket");
>           if (fd<0)
>               throw new IOException();
>       }
>       public UnixSocket accept() throws IOException {
>           UnixSocket socket = new UnixSocket();
>           socket.fd = acceptNative(this.fd);
>           if (socket.fd<0)
>               throw new IOException();
>           return socket;
>       }
>       public void setSoTimeout(int value) throws SocketException {
>           if (setSoTimeoutNative(this.fd, value)<0)
>               throw new SocketException();
>       }
>       public void close() {
>           closeNative(this.fd);
>       }
>   }
>   /**
>    * Native AF_UNIX socket
>    */
>   class UnixSocket {
>       public int fd; // From accept.
>
>       private static native int setSoLingerNative (int fd, int l_onoff,
>                                                    int l_linger);
>
>       public void setSoLinger  (boolean bool ,int l_linger) throws IOException {
>           int l_onoff=0;
>           if (bool)
>               l_onoff = 1;
>           if (setSoLingerNative(fd,l_onoff,l_linger)<0)
>               throw new IOException();
>       }
>   }
>   /**
>    * Provide an InputStream for the native socket.
>    */
>   class UnixSocketIn extends InputStream {
>       private int fd; // From openNative.
>
>       private static native int readNative (int fd,  byte buf [], int len);
>
>       public int read() throws IOException {
>           byte buf [] = new byte[1];
>           if (readNative(fd,buf,1) < 0)
>               throw new IOException();
>           return 0xff & buf[0];
>       }
>       public UnixSocketIn(int fd) {
>           this.fd = fd;
>       }
>   }
>
>   /**
>    * Provide an OutputStream for the native socket.
>    */
>   class UnixSocketOut extends OutputStream {
>       private int fd; // From openNative.
>
>       private static native int writeNative (int fd,  byte buf [], int len);
>
>       public void write(int value) throws IOException {
>           byte buf [] = new byte[] { (byte) value };
>           if (writeNative(fd,buf,1) < 0)
>               throw new IOException();
>       }
>
>       public UnixSocketOut(int fd) {
>           this.fd = fd;
>       }
>   }
>
>
>
>   1.2       +3 -0      jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java
>
>   Index: JkMain.java
>   ===================================================================
>   RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java,v
>   retrieving revision 1.1
>   retrieving revision 1.2
>   diff -u -r1.1 -r1.2
>   --- JkMain.java	31 Dec 2001 19:09:59 -0000	1.1
>   +++ JkMain.java	5 Jan 2002 10:03:43 -0000	1.2
>   @@ -87,7 +87,10 @@
>        public void start() throws IOException {
>            ChannelSocket csocket=new ChannelSocket();
>            csocket.setPort( 8009 );
>   +        /*
>   +        ChannelUnixSocket csocket=new ChannelUnixSocket(); // JFC tests
>            wEnv.addChannel( csocket );
>   +         */
>
>            WorkerDummy wdummy=new WorkerDummy();
>            csocket.setWorker( wdummy );
>
>
>
>   1.9       +30 -1     jakarta-tomcat-connectors/jk/native2/build.xml
>
>   Index: build.xml
>   ===================================================================
>   RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/build.xml,v
>   retrieving revision 1.8
>   retrieving revision 1.9
>   diff -u -r1.8 -r1.9
>   --- build.xml	31 Dec 2001 22:25:03 -0000	1.8
>   +++ build.xml	5 Jan 2002 10:03:43 -0000	1.9
>   @@ -43,7 +43,7 @@
>
>      <!-- ==================== Targets ==================== -->
>
>   -  <target name="main" depends="init,apache20,jni,apache13">
>   +  <target name="main" depends="init,apache20,jni,apache13,unixsocket">
>      </target>
>
>      <target name="init" >
>   @@ -406,4 +406,33 @@
>        </delete>
>      </target>
>
>   +  <target name="unixsocket" depends="init" if="useunixsocket">
>   +    <mkdir dir="${jk.build}/WEB-INF/jk2/unixsocket" />
>   +    <so sofile="libunixsocket"
>   +	buildDir="${jk.build}/WEB-INF/jk2/unixsocket"
>   +	optimize="${so.optimize}"
>   +	debug="${so.debug}"
>   +	profile="${so.profile}">
>   +
>   +      <src dir=".">
>   +	<include name="tomcat/UnixSocket.c" />
>   +        <!-- When APR will provide the AF_UNIX socket support -->
>   +        <!--
>   +        <include name="common/apr/*.c" if="HAVE_APR" />
>   +         -->
>   +      </src>
>   +      <includes>
>   +	<include name="${java.home}/../include" />
>   +
>   +        <!-- Platform specific includes -->
>   +        <include name="${java.home}/../include/netware" if="netware" />
>   +        <include name="${java.home}/../include/win32" if="win32" />
>   +        <include name="${java.home}/../include/linux" if="linux" />
>   +      </includes>
>   +      <depends>
>   +	<fileset dir="${native.dir}/common" includes="*.h" />
>   +      </depends>
>   +
>   +    </so>
>   +  </target>
>    </project>
>
>
>
>   1.1                  jakarta-tomcat-connectors/jk/native2/tomcat/UnixSocket.c
>
>   Index: UnixSocket.c
>   ===================================================================
>   #include <sys/types.h>
>   #include <sys/stat.h>
>   #include <sys/socket.h>
>   #include <fcntl.h>
>   #include <errno.h>
>   #include <sys/un.h> /* for sockaddr_un */
>   #include <unistd.h>
>
>   #include <jni.h>
>
>   /*
>    * Native routines for
>    * package org.apache.jk.common
>    */
>
>   /**
>    * createSocketNative: Creates a AF_UNIX socketserver.
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketServer_createSocketNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jstring     filename
>   ) {
>       int         sd;
>       const char  *real_filename;
>       jboolean    flag;
>       struct sockaddr_un unix_addr;
>       mode_t omask;
>       int rc;
>
>       // Convert java encoding in machine one.
>       real_filename = (*env)->GetStringUTFChars (env, filename, &flag);
>       if (real_filename == 0)
>           return -EINVAL;
>
>       // remove the exist socket.
>       if (unlink(real_filename) < 0 && errno != ENOENT) {
>           // The socket cannot be remove... Well I hope that no problems ;-)
>       }
>
>       // create the socket.
>       sd = socket(AF_UNIX, SOCK_STREAM, 0);
>       if (sd<0)
>           return -errno;
>
>       memset(&unix_addr, 0, sizeof(unix_addr));
>       unix_addr.sun_family = AF_UNIX;
>       strcpy(unix_addr.sun_path, real_filename);
>
>       omask = umask(0117); /* so that only Apache can use socket */
>       rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
>       umask(omask); /* can't fail, so can't clobber errno */
>       if (rc<0)
>          return -errno;
>
>       if (listen(sd, 100) < 0) {
>           return -errno;
>       }
>
>       (*env)->ReleaseStringUTFChars (env, filename, real_filename);
>
>       return sd;
>   }
>
>   /**
>    * accept(). Accepts incomming calls on socket.
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketServer_acceptNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        sd
>   ) {
>       struct sockaddr_un unix_addr;
>       int sd2;
>       int len;
>
>       len = sizeof(unix_addr);
>       sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
>       if (sd2<0)
>           return - errno;
>       return(sd2);
>
>   }
>
>   /**
>    * set the socket timeout (read/write) or accept() ?
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketServer_setSoTimeoutNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        sd
>   ) {
>       // setsockopt or setitimer?
>   }
>
>   /**
>    * close the socket (remove the file?)
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketServer_closeNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        sd
>   ) {
>       close(sd);
>   }
>
>   /**
>    * setSoLinger
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocket_setSoLingerNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        sd,
>       jint        l_onoff,
>       jint        l_linger
>   ) {
>       struct linger {
>           int   l_onoff;    /* linger active */
>           int   l_linger;   /* how many seconds to linger for */
>           } lin;
>       lin.l_onoff = l_onoff;
>       lin.l_linger = l_linger;
>       if (setsockopt(sd, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin))<0)
>           return -errno;
>       return 0;
>   }
>
>   /**
>    * read from the socket.
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketIn_readNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        fd,
>       jbyteArray  buf,
>       jint        len
>   ) {
>       int retval;
>       jbyte *buffer;
>       jboolean    isCopy;
>
>       buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
>
>       retval = read(fd,buffer,len);
>
>       (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
>
>       return retval;
>   }
>
>   /**
>    * write to the socket.
>    */
>   JNIEXPORT jint JNICALL
>   Java_org_apache_jk_common_UnixSocketOut_writeNative (
>       JNIEnv      *env,
>       jobject     ignored,
>       jint        fd,
>       jbyteArray  buf,
>       jint        len
>   ) {
>       int retval;
>       jbyte *buffer;
>       jboolean    isCopy;
>
>       buffer = (*env)->GetByteArrayElements (env, buf, &isCopy);
>
>       retval = write(fd,buffer,len);
>
>       (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
>
>       return retval;
>
>   }
>
>
>
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>