RCS_ID_C="$Id: amiga_main.c,v 1.39 1993/11/07 00:04:44 ppessi Exp $";
/*
 * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
 *                    Helsinki University of Technology, Finland.
 *                    All rights reserved.
 * 
 * $Log: amiga_main.c,v $
 * Revision 1.39  1993/11/07  00:04:44  ppessi
 * Raised release number to 2.2.
 *
 * Revision 1.38  1993/10/29  02:18:26  ppessi
 * Raised release number to 2.1a.
 *
 * Revision 1.37  1993/10/11  01:43:56  jraja
 * Raised release number to 2.1.
 *
 * Revision 1.36  1993/08/10  16:30:19  too
 * Added version DATE from bumprevved bsdsocket.library_rev.h
 *
 * Revision 1.35  1993/06/04  11:16:15  jraja
 * Fixes for first public release.
 *
 * Revision 1.34  1993/06/01  16:29:51  too
 * Added call to res_init()
 *
 * Revision 1.33  1993/05/17  01:07:47  ppessi
 * Changed RCS version.
 *
 * Revision 1.32  1993/05/14  15:54:06  ppessi
 * Minor prototype fixes.
 *
 * Revision 1.31  93/05/05  16:10:07  16:10:07  puhuri (Markus Peuhkuri)
 * Fixes for final demo.
 * 
 * Revision 1.30  93/05/04  13:32:03  13:32:03  too (Tomi Ollila)
 * Changed global SocketBase to MasterSocketBase
 * 
 * Revision 1.29  93/05/04  13:30:04  13:30:04  ppessi (Pekka Pessi)
 * Changed init_netdv() to readnetdb()
 * 
 * Revision 1.28  93/04/26  11:54:33  11:54:33  too (Tomi Ollila)
 * Changed include paths of amiga_api.h, amiga_libcallentry.h and amiga_raf.h
 * from kern to api
 * 
 * Revision 1.27  93/04/24  14:01:36  14:01:36  jraja (Jarno Tapio Rajahalme)
 * Moved some initializations from the main() to init_all(). Reorganized the
 * structure of the init_all() function.
 * 
 * Revision 1.26  93/04/23  00:27:30  00:27:30  ppessi (Pekka Pessi)
 * Configuration routine added; initialization sequence fixed.
 * 
 * Revision 1.25  93/04/20  18:41:00  18:41:00  puhuri (Markus Peuhkuri)
 * As BOOL is 16-bit, upper word of sanamask was stripped and thus allways
 * zero. Fixed.
 * 
 * Revision 1.24  93/04/17  17:57:35  17:57:35  puhuri (Markus Peuhkuri)
 * Removed _last_ rexx stuff
 * 
 * Revision 1.23  93/04/17  17:18:17  17:18:17  puhuri (Markus Peuhkuri)
 * Removed REXX-stuff (to NETTRACE)
 * 
 * Revision 1.22  93/04/06  15:15:34  15:15:34  jraja (Jarno Tapio Rajahalme)
 * Changed spl function return value storage to spl_t,
 * changed bcopys and bzeros to aligned and/or const when possible,
 * added inclusion of conf.h to every .c file.
 * 
 * Revision 1.21  93/03/20  07:06:13  07:06:13  ppessi (Pekka Pessi)
 * Support multiple instances. Library name, rexx port name and task name fixed.
 * 
 * Revision 1.20  93/03/19  14:14:41  14:14:41  too (Tomi Ollila)
 * Code changes at night 17-18 March 1993
 * 
 * Revision 1.19  93/03/15  14:36:39  14:36:39  jraja (Jarno Tapio Rajahalme)
 * Cosmetic changes.
 * 
 * Revision 1.18  93/03/12  00:42:47  00:42:47  jraja (Jarno Tapio Rajahalme)
 * Added api_hide() to deinit_all().
 * 
 * Revision 1.17  93/03/11  22:20:49  22:20:49  jraja (Jarno Tapio Rajahalme)
 * Changed deinit_all() to return void.
 * 
 * Revision 1.16  93/03/10  23:07:34  23:07:34  jraja (Jarno Tapio Rajahalme)
 * Changed timer_init() to return signal mask.
 * 
 * Revision 1.15  93/03/10  22:04:23  22:04:23  jraja (Jarno Tapio Rajahalme)
 * Moved most of the timeout stuff to amiga_time.c
 * 
 * Revision 1.14  93/03/07  00:51:02  00:51:02  jraja (Jarno Tapio Rajahalme)
 * Added a check to make sure we do NOT exit when someone has library base
 * open.
 * 
 * Revision 1.13  93/03/05  21:11:03  21:11:03  jraja (Jarno Tapio Rajahalme)
 * Fixed includes (again).
 * 
 * Revision 1.12  93/03/05  16:01:21  16:01:21  too (Tomi Ollila)
 * Changed api_init() and api_deinit() to work with new amiga_api.c
 * removed api_hide() (obsolete here)
 * 
 * Revision 1.11  93/03/05  03:25:53  03:25:53  ppessi (Pekka Pessi)
 * Compiles with SASC. Initial test version.
 * 
 * Revision 1.10  93/03/04  10:58:36  10:58:36  jraja (Jarno Tapio Rajahalme)
 * Changed init_all's return type to ULONG.
 * 
 * Revision 1.9  93/03/04  10:01:55  10:01:55  jraja (Jarno Tapio Rajahalme)
 * Fixed includes.
 * 
 * Revision 1.8  93/03/03  12:23:16  12:23:16  jraja (Jarno Tapio Rajahalme)
 * Changed temporary prototypes to prototype file includes.
 * Added SysBase for non GNUC compilers.
 * Added deinit_all() call before returning failure.
 * 
 * Revision 1.7  93/03/02  16:55:51  16:55:51  ppessi (Pekka Pessi)
 * Added SysBase initialization.
 * 
 * Revision 1.6  93/03/02  15:09:40  15:09:40  ppessi (Pekka Pessi)
 * Replaced netinet/if_ether.h with netinet/if_arpsana.h
 * 
 * Revision 1.5  93/02/25  19:07:35  19:07:35  too (Tomi Ollila)
 * moved reference and initialization of AmiTCP_Task here.
 * 
 * Revision 1.4  93/02/25  18:43:41  18:43:41  too (Tomi Ollila)
 * Now Includes kern/amiga_includes.h first. Now gcc doesn't say
 * ../sys/socketvar.h:109: field `so_linger' has incomplete type ...
 * why, we currently don't know
 * 
 * Revision 1.3  93/02/24  12:31:10  12:31:10  jraja (Jarno Tapio Rajahalme)
 * Fixed some prototypes.
 * 
 * Revision 1.2  93/02/19  15:53:26  15:53:26  jraja (Jarno Tapio Rajahalme)
 * fixed ^C signal checking.
 * 
 * Revision 1.1  93/02/04  18:55:53  18:55:53  jraja (Jarno Tapio Rajahalme)
 * Initial revision
 * 
 */

#include <conf.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/synch.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/socketvar.h>

#include <kern/amiga_includes.h>

#include <kern/amiga_time.h>
#include <api/amiga_api.h>
#include <kern/amiga_log.h>
/* #include <net/if_sana.h> */

#include <bsdsocket.library_rev.h>

ULONG sana_init(void);
void sana_deinit(void);
BOOL sana_poll(void);

#include <signal.h>		/* from the C compilers includes */

#include <kern/amiga_main_protos.h>
#include <kern/amiga_config.h>
#include <kern/amiga_netdb.h>
#include <api/resolv.h>

/*
 * include prototypes for initialization functions
 */
#include <kern/uipc_domain_protos.h>    /* domaininit() */

/*
 * The main module of the AMITCP/IP.
 */

/*
 * Global variable so AMITCP/IP task information can be utilized.
 */
struct Task * AmiTCP_Task;

extern struct ExecBase * SysBase;
extern struct Library * MasterSocketBase;
extern WORD nthLibrary;

static ULONG sanamask = 0, 
  sig = 0, sigmask = 0, timermask = 0, 
  breakmask = 0;

UBYTE *taskname = NULL;
ULONG EnableDebug = 0;
BOOL  initialized = FALSE;

STRPTR version = "\0$VER: AmiTCP/IP 2.2 (" DATE ")\r\n"
             "Copyright \251 1993 AmiTCP/IP Group.\r\n";

int
main(int argc, char *argv[])
{
  BYTE oldpri;
  STRPTR oldname;
  int retval;

  SysBase = *(struct ExecBase **)4;

  /*
   * Disable CTRL-C(D) Break signal.
   */
  signal(SIGINT, SIG_IGN);

  /*
   * Initialize AmiTCP_Task to point the Task structure of this task.
   */
  AmiTCP_Task = FindTask(NULL);

  /*
   * Save pointer to this tasks old name
   */
  oldname = AmiTCP_Task->tc_Node.ln_Name;

  if (init_all()) {
    /*
     * Set our priority 
     */
    oldpri = SetTaskPri(AmiTCP_Task, 5);

    /*
     * Set our Task name 
     */
    if (!taskname) {
#ifdef DEBUG
      if (nthLibrary) {
	if (taskname = bsd_malloc(16, M_CFGVAR, M_WAITOK)) {
	  strcpy(taskname, "AmiTCP");
	  taskname[6] = '.'; taskname[7] = '0' + nthLibrary;
	}
      } else {
#endif
	taskname = "AmiTCP";
#ifdef DEBUG
      }
#endif
    }
    if (taskname)
      AmiTCP_Task->tc_Node.ln_Name = taskname;

    /* 
     * Global initialization flag;
     */
    initialized = TRUE;

#ifdef DEBUG
    /* 
     * Show our task address
     */
    printf("%s Task address : %lx\n", taskname, (long) AmiTCP_Task);
#endif

    /*
     * Initialize signal mask for the wait
     */
    breakmask = SIGBREAKF_CTRL_C;
    sigmask = timermask | breakmask | sanamask;

    /*
     * Now when everything else is succesfully initialized,
     * let the timeouts roll!
     */
    timer_send();

    for(;;) {
      /*
       * Sleep until we are signalled.
       */
      sig = Wait(sigmask);

      do {
	if (sig & sanamask) {
	  if (!sana_poll())
	    sig &= ~sanamask;
	}

	if (sig & timermask) {
	  if (!timer_poll()) 
	    sig &= ~timermask;
	}

	sig |= SetSignal(0L, sigmask) & sigmask;
      } while (sig && sig != breakmask);

      if (sig & breakmask) {
	/*
	 * We got CTRL-C
	 */
	Forbid();
	if (MasterSocketBase->lib_OpenCnt > 1) {
  	  Permit();
	  log(LOG_ERR, "Got CTRL-C while %ld %s still open.\n",
	      MasterSocketBase->lib_OpenCnt - 1,
	      (MasterSocketBase->lib_OpenCnt == 2) ? "library" : "libraries");
	} else {
	  api_hide(); /* hides the API from users */
	  Permit();
	  break;
	}
      }
    }
    retval = 0;
  } else
    retval = 20;

  /*
   * free all resources
   */
  deinit_all();
  initialized = FALSE;

  SetTaskPri(AmiTCP_Task, oldpri);
  AmiTCP_Task->tc_Node.ln_Name = oldname;

  return retval;
}

/*
 * Do all initializations
 */
BOOL
init_all(void)
{
  /*
   * Initialize malloc semaphore
   */
  malloc_init();

  /*
   * initialize concurrency control subsystem
   */  
  spl_init();
  
  /*
   * initialize sleep queues
   */
  sleep_init();
  
  /* 
   * Read command line arguments and configuration file
   */
  if (!readconfig())
    return FALSE;

  /*
   * initialize logging system
   */
  if (!log_init())
    return FALSE;

  /* 
   * initialize the mbuf subsystem
   */
  if (!mbinit())
    return FALSE;

  /*
   * initialize timer
   */
  if ((timermask = timer_init()) == 0L)
    return FALSE;

  /*
   * initialize API
   */
  if (!api_init())
    return FALSE;
	
  /*
   * initialize SANA-II subsystem
   */
  if ((sanamask = sana_init()) == 0L)
    return FALSE;
	    
  /*
   * initialize domains (initializes all protocols)
   */
  domaininit();
	    
  /*
   * Initialize NetDataBase
   */
  if (init_netdb() != 0)
    return FALSE;

  /*
   * Initialize Resolver
   */
  res_init();
   
  /*
   * Make API visible
   */
  if (api_show() == FALSE)
    return FALSE;

  if (Nettrace_Task)
    Signal(Nettrace_Task, SIGBREAKF_CTRL_F);
  else
    return FALSE;

  return TRUE;
}

/*
 * clean up everything
 */
void
deinit_all(void)
{
  /*
   * make sure we are out of critical section
   */
  spl0();

  api_hide();			/* hides the API from users */

  /*
   * Deinitialize network interfaces
   */
  sana_deinit();

  /*
   * Deinitialize timers
   */
  timer_deinit();

  /*
   * Free all resources allocated by mbufs.
   */
  mbdeinit();

  log_deinit();

  /*
   * Check that there are no libraries open (to our API). We can continue only
   * if all bases are closed.
   */
  api_deinit();  /* NOTICE: this waits until every api user has exited */
}

/*
 * Notification function for taskname
 */ 
int taskname_changed(void *p, LONG new)
{
  UBYTE *newname = (UBYTE *)new;
  
  AmiTCP_Task->tc_Node.ln_Name = newname;
  if (initialized)
    printf("New task name %s\n", newname);

  return TRUE;
}
