package com.enete.caffeinecafe;
import java.net.*;
import java.io.*;
import com.enete.caffeinecafe.*;

/***************************************************************************

    <p><i>CaffeineCafe</i>

    This is the entry point for the CaffeineCafe web server.  It listens 
    to a ServerSocket for connections.  When it receives a connection, it 
    launches a connection object in a new thread.  The connection object 
    receives the service requests from the Web client and launches the 
    appropriate server extension ('Dripper') object to service the request.

    <p>Use the following syntax to invoke this server from the command line:

    * <pre>
    *    java com.enete.caffeinecafe.CaffeineCafe [portnumber]
    * </pre>

    <p>The <i>portnumber</i> is an optional parameter that allows the user
    to specify a specific port upon which to start the browser.  To exit 
    the program, press control-C.

    <p>History:<p><ul>

      <li>12/04/97 (NDE): Reworked the mainline of this server so it
      could more easily be launched from a DMON type process and provided
      a mechanism to start and stop it.</li>

      <li>01/13/97 (NDE): Rewrote the start logic in the constructor so 
      it would select the port based on an array of possible port numbers 
      or an optional port number provided by the user.</li>

    </ul><p>

    * @author    Noel Enete
    * @version   1.1.0, 12/2/97

 ***************************************************************************/

    public class CaffeineCafe implements Runnable, Launchable
    {
    final String sTag = "Copyright (c) 1998 Noel Enete";

    CaffeineCafeDefaults defs;         /* System wide default properties.  */
    ServerSocket ssock;                /* Server listening socket.         */
    int iListenPort;                   /* Port to which to listen.         */
    int iSockTimeoutMs;                /* Timeout for socket read.         */
    boolean bRunning;                  /* Shared variable to stop server.  */
    int iRunningCounter;               /* Increments on each listen cycle. */
    Thread thListeningLoop;            /* Loop that listens for a connectn */

/***************************************************************************/


    public CaffeineCafe (int iPortRequest)
      {
      iListenPort = iPortRequest;
      defs = new CaffeineCafeDefaults ();
      iSockTimeoutMs = 1000;
      }


    public int start ()
      {
      iRunningCounter = 0;
      thListeningLoop = new Thread (this);
      thListeningLoop.start ();
      return (0);
      }


    public int stop ()
      {
      bRunning = false;
      return (0);
      }


    public boolean isRunning ()
      {
      int iSaveCounter;

      iSaveCounter = iRunningCounter;
      try {Thread.sleep ((int) (iSockTimeoutMs * 1.5));} 
      catch (Exception e) {}

      if (iSaveCounter == iRunningCounter)
        {
        return (false);
        }
      else
        {
        return (true);
        }
      }


    public void run ()
      {
      Socket sock;
      Thread thConn;
      SConnection conn;

      defs.fetchPreloads ();
      ssock = openServerSocket (iListenPort);
      if (ssock == null) return;

      try
        {
        ssock.setSoTimeout (iSockTimeoutMs);
        }
      catch (Exception e)
        {
        System.out.println ("Cafe: Unable to set socket timeout");
        return;
        }

      System.out.println ("\n    Welcome to CaffeineCafe (version " 
        + defs.getVersion () + ")\n");
      System.out.println ("Cafe: Waiting for a connection...");

      try
        {
        bRunning = true;
        while (bRunning)
          {
          try
            {
            sock = ssock.accept ();
            System.out.println ("Cafe: Received a connection");

            conn = new SConnection (sock);
            conn.setDefaults (defs);
            thConn = new Thread (conn);
            thConn.start ();
            }
          catch (InterruptedIOException ie)
            {
//          ...timed out...
            }

          if (++iRunningCounter > 64000)
            {
            iRunningCounter = 0;
            }
          }
        }
      catch (Exception e)
        {
        System.err.println ("Cafe: Exception in main loop: " + e);
        }
      }


    ServerSocket openServerSocket (int iPortRequest)
      {
      int i;
      int iPort = 0;
      InetAddress ia;
      Socket sockTest;
      ServerSocket ssock = null;
      int[] aiPorts = 
        {
        0,                             /* Reserve a slot for requested port*/
        80,                            /* Try the well known port first.   */
        8000,                          /* For unix boxes, try 8000 next.   */
        8001,                          /* If they already have a server... */
        8002,                          /* ...iterate through several       */
        8003                           /* ......other possibilities.       */
        };


/*    Get the local IP address.
      =========================  */
      
      try
        {
        ia = InetAddress.getLocalHost ();
        }
      catch (Exception e)
        {
        System.out.println ("Cafe: Unable to get the local IP address");
        return (null);
        }


/*    If a port number was requested, then use that port in the first
      attempt to open a ServerSocket.
      ===============================================================  */

      i = 1;
      if (iPortRequest != 0)
        {
        aiPorts[0] = iPortRequest;
        i = 0;
        }


/*    Each cycle of this loop tries to open a ServerSocket on one port
      number.  If a port was requested, that is the only one that is
      tried.
      ================================================================  */

      for ( ; i < aiPorts.length; i++)
        {
        iPort = aiPorts[i];
        try
          {

/*        If the following socket opens, then another process already
          has the port.  In this case, recycle to the top of the loop
          with a new port number.
          ===========================================================  */

          sockTest = new Socket ("localhost", iPort);  
          sockTest.close ();
          sockTest = null;
          System.out.println ("Cafe: Port " + iPort + " is already taken");
          if ((i == 0) || (i == aiPorts.length - 1)) 
            {
            System.out.println ("Cafe: Exiting...");
            return (null);
            }
          continue;
          }
        catch (Exception e)
          {
          // If the port is available, go on to open a ServerSocket on it.
          }

        try
          {
          ssock = new ServerSocket (iPort);
          break;
          }
        catch (Exception e)
          {
          System.out.println ("Cafe: Unable to open a server on port "
            + iPort);
          if ((i == 0) || (i == aiPorts.length - 1)) 
            {
            System.out.println (e);
            return (null);
            }
          }
        }

      System.out.println ("Cafe: Initializing to -->PORT " + iPort
          + "<-- on " + ia);
      iListenPort = iPort;
      return (ssock);
      }


    public CaffeineCafeDefaults getDefaults ()
      {
      return (defs);
      }


    public static void main (String argv[])
      {
      int iPort;
      CaffeineCafe server;

      iPort = 0;
      if (argv.length > 0) 
        {
        try
          {
          iPort = Integer.parseInt(argv[0]);
          }
        catch (NumberFormatException e)
          {
          iPort = 0;
          }
        }

      server = new CaffeineCafe (iPort);
      server.start ();

      while (true)
        {
        try {Thread.sleep (1000);} catch (Exception e) {}
//      server.stop ();
        }
      }

    }


/*==========================(  End of Source  )============================*/

