/*
 * main.c,v 1.1 1994/01/28 17:05:19 franktor Exp
 *
 * This file contains only the main-routine for the server.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sr-general.h>
#include <sr-api.h>
#include <high/eapi.h>
#include <high/sr_structcodec.h>
#include "server.h"

#ifndef __CEXTRACT__
#include "proto.h"
#endif

#define REMOVE_TRACE /* Remove some very verbose output from structcodec */

void
main (int argc, char **argv)
{
  int ref;
  int max_file_descriptors;
  struct rlimit lim;
  int errors = 0;

  facLogLevel (-1, llevTrace);
#ifdef REMOVE_TRACE
  facLogLevel (facStruct, llevDebug); /* Don't want all the trace output */
#endif

  parse_args(argc, argv);

  if (!ttydebug)
  {
    if (!keeplog)
      unlink (debug_logfile);
    initLogger (debug_logfile);
  }

#ifdef RLIMIT_NOFILE
  if (getrlimit(RLIMIT_NOFILE,&lim) == -1) {
    perror("getrlimit");
    exit(1);
  }
  LOG(facHigh, llevTrace, "Max file descriptors changed from %d to %d.",lim.rlim_cur,lim.rlim_max);
  lim.rlim_cur = lim.rlim_max;
  if (setrlimit(RLIMIT_NOFILE,&lim) == -1)
    perror("setrlimit");

  max_file_descriptors = lim.rlim_cur;
#else
  max_file_descriptors = 64;
  LOG(facHigh, llevTrace, "Unable to change number of descriptors, guessing at 64.");
#endif

  initialise();
 
  for(;;)
  {
    SROperation opr;
    ref = (-1);

    set_relevant_bits(); /* Fills eapi_read, write, etc up with bits */

    opr = SR_PollNetwork(0, max_file_descriptors, &eapi_read, &eapi_write,
                         &eapi_exceptions, &ref);
    switch(opr)
    {
    case oprInitialiseRequest:
      handleInitialiseRequest ( ref );
      break;
    case oprCloseRequest:
      handleCloseRequest ( ref );
      break;
    case oprAbort:
      handleAbort( ref );
      break;
    case oprSearchRequest:
      handleSearchRequest ( ref );
      break;
    case oprPresentRequest:
      handlePresentRequest ( ref );
      break;

    case oprDeleteResultSetRequest:
      handleDeleteResultSetRequest ( ref );
      break;
    case oprNone:
    {
      int fd;
      int packets = 0;

      for(fd = 0; fd < max_file_descriptors; fd++)
        if (FD_ISSET(fd, &eapi_read) || FD_ISSET(fd, &eapi_write) ||
            FD_ISSET(fd, &eapi_exceptions))
        {
          Client *client;
          ClientDatabaseServer *server;
          DatabaseServerConnection *conn;

	  if ( FD_ISSET(fd, &eapi_read) )
	     LOG (facHigh, llevTrace,
		  "Connection %d to database server reported read activity", fd );
	  if ( FD_ISSET(fd, &eapi_write) )
	     LOG (facHigh, llevTrace,
		  "Connection %d to database server reported to be able to accept more data",
		  fd );
	  if ( FD_ISSET(fd, &eapi_exceptions) )
	     LOG (facHigh, llevTrace,
		  "Connection %d to database server reported an exception", fd );
	  
          packets++;

          conn = fd2DatabaseServerConnection(fd);
          if (conn == (DatabaseServerConnection *) NULL)
          {
            LOG(facHigh, llevExceptions, "Reference %d not associated to anything.", fd);
            continue;
          }
          switch (handle_socket(fd,
                                FD_ISSET(fd, &eapi_read) ? True : False,
                                FD_ISSET(fd, &eapi_write) ? True : False,
                                FD_ISSET(fd, &eapi_exceptions) ? True : False,
                                &conn->selectOnWrite))
          {
          case sockStatOK:
            LOG(facHigh, llevDebug, "handle_socket(): OK %s", conn->selectOnWrite ? "(Requests select on write)" : "" );
            if (++conn->loopcount > MAX_HLVL_LOOPS)
            {
              LOG(facHigh, llevExceptions, "Too many loops!  Aborting connection.");
              while ((client = fd2client(fd)) != NULL)
              {
                /* Terminate connection to client */
                SR_AbortAssociation(client->ref);
                remove_client(client);
              }
            }
            break;
          case sockStatFailed:
          case sockStatClosed:
            LOG(facHigh, llevDebug, "handle_socket(): False");
            conn->loopcount = 0;
            while ((client = fd2client(fd)) != NULL)
            {
              LOG(facHigh, llevTrace, "Client %d lost connection to server.",client->ref);
              /* Terminate connection to client */
              SR_AbortAssociation(client->ref);
              remove_client(client);
            }
            break;
          case sockStatPacketReady:
            conn->loopcount = 0;
            {
              EapiConnectInfo *connection;
              EapiPacket *eapi_packet;
              Boolean status;

    
              eapi_packet = (EapiPacket *) malloc(sizeof(EapiPacket));
              switch(read_struct(fd, (void **) &eapi_packet))
              {
              case sockStatClosed:
              case sockStatFailed:
              case sockStatPacketReady:
                LOG(facHigh, llevDebug, "Error in receiving struct.");
                break;
              case sockStatOK:
                LOG(facHigh, llevDebug, "Got packet type %d.", eapi_packet->type);
      
                client = ref2client(eapi_packet->ref);
                if (client == (Client *) NULL)
                {
                  LOG(facHigh, llevExceptions, "Found no client for packet.");
                  break;
                }
                client->file_descriptor = fd;
                switch(eapi_packet->type)
                {
                case eapiOpenResponse:
                  handleOpenResponse(client, eapi_packet);
                  break;
                case eapiCloseResponse:
                  handleCloseResponse(client, eapi_packet);
                  break;
                case eapiSearchResponse:
                  handleSearchResponse(client, eapi_packet);
                  break; 
                case eapiDeleteResultSetResponse:
                  handleDeleteResultSetResponse(client, eapi_packet);
                  break;
                case eapiPresentResponse:
                  handlePresentResponse(client, eapi_packet);
                  break;
                case eapiInterruptResponse:
                  handleInterruptResponse(client, eapi_packet);
                  break;
                default:
                  LOG(facHigh, llevDebug, "Got unknown packet type (%d) from eapi server.", eapi_packet->type);
                  break;
                }
              
              }
            }
          }
        }
      if (packets == 0)
      {
        LOG(facHigh, llevExceptions, "Got oprNone from SR_PollNetwork, but had no work.");
        if (++errors)
        {
          LOG(facHigh, llevExceptions, "Seems like endless loop, exiting.");
          exit(1);
        }
      }
      else
        errors = 0;
      break;
    }
    default:
      LOG(facHigh, llevExceptions, "Got unknown packet (%d) from client.",opr);
      break;
    }
  }
}
