RCS_ID_C="$Id: amiga_api.c,v 1.49 1993/08/09 21:28:22 ppessi Exp $";
/*
 * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
 *                    Helsinki University of Technology, Finland.
 *                    All rights reserved.
 *
 * Created: Tue Jan 26 20:44:28 1993 too
 * Last modified: Tue Aug 10 00:22:24 1993 ppessi
 *
 * HISTORY
 * $Log: amiga_api.c,v $
 * Revision 1.49  1993/08/09  21:28:22  ppessi
 * Added revision headers and release string.
 *
 * Revision 1.48  1993/08/06  08:42:44  jraja
 * Removed the version check, since it does not work.
 *
 * Revision 1.47  1993/08/05  10:35:52  jraja
 * Added version check to the ELL_Open(). Now all Open requests with
 * version less than 2 will be rejected.
 * No requester or alert is set up yet (Add later).
 *
 * Revision 1.46  1993/07/15  20:17:25  too
 * Changed library revision to VERSION 2 REVISION 1
 *
 * Revision 1.45  1993/06/12  22:56:08  too
 * Added freeDataBuffer() calls to UL_Close so now selitem and netdb
 * buffers are freed at CloseLIbrary()
 *
 * Revision 1.44  1993/06/07  12:37:20  too
 * Changed inet_ntoa, netdatabase functions and WaitSelect() use
 * separate buffers for their dynamic buffers
 *
 * Revision 1.43  1993/06/04  11:16:15  jraja
 * Fixes for first public release.
 *
 * Revision 1.42  1993/06/02  18:27:26  jraja
 * Moved CloseSocket() calls before any deinitialization in UL_Close(),
 * since closing prosedure uses the socket base.
 *
 * Revision 1.41  1993/05/17  01:07:47  ppessi
 * Changed RCS version.
 *
 * Revision 1.40  1993/05/05  16:09:20  puhuri
 * Fixes for final demo.
 *
 * Revision 1.39  93/05/04  14:08:09  14:08:09  too (Tomi Ollila)
 * Changed local api function names to the same as the names given
 * to API programmer, but w/ starting _
 * Also changed global variable SocketBase to MasterSocketBase
 * 
 * Revision 1.38  93/05/04  12:02:17  12:02:17  jraja (Jarno Tapio Rajahalme)
 * Initialized tlseep_timer node type to NT_UNKNOWN.
 * 
 * Revision 1.37  93/04/26  11:50:58  11:50:58  too (Tomi Ollila)
 * Changed include paths of amiga_api.h, amiga_libcallentry.h and amiga_raf.h
 * from kern to api
 * 
 * Revision 1.36  93/04/25  20:01:25  20:01:25  too (Tomi Ollila)
 * Initialized buffer and bufferSize fields in SocketBase
 * 
 * Revision 1.35  93/04/23  00:25:50  00:25:50  ppessi (Pekka Pessi)
 * nthLibrary changed.
 * 
 * Revision 1.34  93/04/20  16:06:32  16:06:32  jraja (Jarno Tapio Rajahalme)
 * tsleep_timer is not put to the reply port any more.
 * 
 * Revision 1.33  93/04/19  02:22:27  02:22:27  ppessi (Pekka Pessi)
 * Fixed bugs with multiple instances
 * 
 * Revision 1.32  93/04/06  18:02:52  18:02:52  too (Tomi Ollila)
 * Added initialization of newBase->sigIntrMask.
 * Made ELL_Open to return already opened socketbase if caller task has
 * it open and UL_Close checks opencnt before closing the library
 * 
 * Revision 1.31  93/04/06  15:13:56  15:13:56  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.30  93/04/02  01:07:44  01:07:44  jraja (Jarno Tapio Rajahalme)
 * Added prototype for CloseSocket in GCC too.
 * 
 * Revision 1.29  93/03/30  16:57:40  16:57:40  too (Tomi Ollila)
 * Added writeErrnoVAlue, made huge changes to multiple instance support
 * 
 * Revision 1.28  93/03/20  06:56:38  06:56:38  ppessi (Pekka Pessi)
 * Support multiple instances. Library name, rexx port name and task name fixed.
 * 
 * Revision 1.27  93/03/19  14:13:47  14:13:47  too (Tomi Ollila)
 * Code changes at night 17-18 March 1993
 *
 * Revision 1.26  93/03/17  12:09:05  12:09:05  jraja (Jarno Tapio Rajahalme)
 * Set timerPort to PA_IGNORE (at start) and put the timerequest to the 
 * timerPort at ELL_Open().
 * 
 * Revision 1.25  93/03/14  16:05:30  16:05:30  too (Tomi Ollila)
 * Moved declaration of wrongTaskErrorFrm from amiga_libcallentry.h here.
 * 
 * Revision 1.24  93/03/12  15:17:20  15:17:20  too (Tomi Ollila)
 * Added initialization of libPtr->nextDTableSize; in ELL_Open
 * 
 * Revision 1.23  93/03/12  01:03:16  01:03:16  too (Tomi Ollila)
 * Now UL_Close calls CloseSocket for every referenced socket left
 * 
 * Revision 1.22  93/03/11  16:32:59  16:32:59  too (Tomi Ollila)
 * Defined hexadesimal inittype initializers to more human readable form and
 * for easier update (in use of LIbrary_initTable)
 * 
 * Revision 1.21  93/03/10  22:12:41  22:12:41  too (Tomi Ollila)
 * 
 * Changed Errno() to use libPtr->errnoPtr, select now has
 * timeout argument in register A3
 * 
 * Revision 1.20  93/03/09  17:48:02  17:48:02  ppessi (Pekka Pessi)
 *  Close returns now a seglist pointer (NULL) instead of void.
 * 
 * Revision 1.19  93/03/07  14:16:00  14:16:00  too (Tomi Ollila)
 * Added api_state change to API_SCRATCH after api_deinit()
 * And now checks that api_state != API_SCRATCH before continuing api_deinit()
 * 
 * Revision 1.18  93/03/07  00:43:01  00:43:01  jraja (Jarno Tapio Rajahalme)
 * Fixed == to =, added SAVEDS keywords to API function definitions,
 * added REGARGFUN keyword to register argument function declarations and
 * added initialization to global variables.
 * And changed wait() to Wait().
 * 
 * Revision 1.17  93/03/05  15:51:22  15:51:22  too (Tomi Ollila)
 * Api functions greatly changed. changes need to be done in amiga_main.c
 * 
 * Revision 1.16  93/03/05  12:24:50  12:24:50  jraja (Jarno Tapio Rajahalme)
 * Removed amiga_api_protos.h (was obsolete and incorrect for GCC).
 * 
 * Revision 1.15  93/03/05  03:25:18  03:25:18  ppessi (Pekka Pessi)
 * Compiles with SASC. Initial test version.
 * 
 * Revision 1.14  93/03/02  16:54:57  16:54:57  too (Tomi Ollila)
 * added << 8 in INITSTRUCT's byte fields.
 * 
 * Revision 1.13  93/03/02  16:51:51  16:51:51  ppessi (Pekka Pessi)
 * Fixed includes
 * 
 * Revision 1.12  93/03/02  14:32:53  14:32:53  ppessi (Pekka Pessi)
 * Added typecast to Remove in api_hide()
 * 
 * Revision 1.11  93/02/26  13:22:36  13:22:36  too (Tomi Ollila)
 * Code checked w/ too, ppessi and jraja
 * 
 * Revision 1.10  93/02/25  19:21:22  19:21:22  too (Tomi Ollila)
 * Added missing * in one "start of comment"
 * 
 * Revision 1.9  93/02/25  19:10:24  19:10:24  too (Tomi Ollila)
 * moved AmiTCP_Task to amiga_main.c, AmiTCP_Task now extern...
 * 
 * Revision 1.8  93/02/25  18:51:39  18:51:39  too (Tomi Ollila)
 * api_init() now returns BOOL value (always TRUE)
 * 
 * Revision 1.7  93/02/25  17:32:15  17:32:15  too (Tomi Ollila)
 * Compiles without error messages (w/o -Wall)
 * 
 * Revision 1.6  93/02/25  13:00:53  13:00:53  too (Tomi Ollila)
 * Added static inlines, sys/cdefs etc.
 * 
 * Revision 1.5  93/02/25  11:46:11  11:46:11  too (Tomi Ollila)
 * minor changes
 * 
 * Revision 1.4  93/02/24  18:48:15  18:48:15  too (Tomi Ollila)
 * Added for security reasons, problems w/ RCS :(
 * 
 * Revision 1.3  93/02/16  16:08:37  16:08:37  too (Tomi Ollila)
 * moved stuff to amiga_userlib.[ch] for easier update.
 * 
 * Revision 1.2  93/02/15  14:21:59  14:21:59  too (Tomi Ollila)
 * merged amiga_api2.c here
 * 
 * Revision 1.1  93/01/27  03:15:01  03:15:01  too (Tomi Ollila)
 * Initial revision
 * 
 */

#include <bsdsocket.library_rev.h>
#define RELEASESTRING "AmiTCP/IP release 2 "

/*
 * NOTE: Exec has turned off task switching while in Open, Close, Expunge and
 *	 Reserved functions (via Forbid()/Permit()) so we should not take
 *	 too long in them.
 */

#include <conf.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/syslog.h>

#include <kern/amiga_includes.h>

#include <api/amiga_api.h>
#include <api/allocdatabuffer.h>
#include <api/amiga_libcallentry.h>
#include <api/apicalls.h>

#include <kern/amiga_subr.h>

typedef VOID (* REGARGFUN f_void)(...);

#define SOCLIBNAME "bsdsocket.library\0\0" /* space for ".n" at the end */

/*
 *  Semaphore to prevent simultaneous access to library functions.
 */
struct SignalSemaphore syscall_semaphore = { 0 };

/*
 *  some globals.
 */
struct Library *MasterSocketBase = NULL;
struct List	socketBaseList;	     /* list of opened socket library bases */
struct List	garbageSocketBaseList; /* list of libray bases not active
				      anymore (NOT YET IMPLEMENTED) */
struct List	releasedSocketList; /* List for sockets that are in no-one's
				       context, waiting for Obtain */

extern struct Task * AmiTCP_Task; /* reference to AmiTCP/IP task information */

/*
 * Declaration of variable to hold message format string when one
 * task tries to use other tasks' library base pointer. moved here
 * from amiga_libcallentry.h so it doens't generate code.
 */
const char wrongTaskErrorFmt[] =
  "Task %ld (%s) attempted to use library base of Task %ld (%s).";

/*
 * Instead of using exec/initializers.h we looked it as a reference
 * and wrote InitTable by hand
 */

/*
 * OFFSET needed to be casted LONG so compiler doesn't give warning
 * about casting pointer to UWORD
 */
#define OFFSET(structName, structEntry) \
  ((LONG)(&(((struct structName *) 0)->structEntry)))

/*
 * original initTable of only UWORD items doesn't work, since compiler
 * doesn't know address of SOCNAME and VSTRING at compile time, and
 * those are broken to 2 WORDS. therefore initTable is a structure
 * constructed by hand, and those (LONG) values are set longword aligned.
 */
#define id_byte 0xe000
#define id_word 0xd000
#define id_long 0xc000

struct {
  UWORD byte1; UWORD offset1; UWORD ln_type;
  UWORD byte2; UWORD offset2; UWORD lib_flags;
  UWORD long3; UWORD offset3; ULONG ln_Name;
  UWORD word4; UWORD offset4; UWORD lib_Version;
  UWORD word5; UWORD offset5; UWORD lib_Revision;
  UWORD long6; UWORD offset6; ULONG lib_IdString;
  UWORD end7; 
  } Library_initTable = {
    id_byte, OFFSET(Node, ln_Type), NT_LIBRARY << 8,
    id_byte, OFFSET(Library, lib_Flags), (LIBF_SUMUSED|LIBF_CHANGED) << 8,
    id_long, OFFSET(Node, ln_Name), (ULONG)SOCLIBNAME,
    id_word, OFFSET(Library, lib_Version), VERSION,
    id_word, OFFSET(Library, lib_Revision), REVISION,
    id_long, OFFSET(Library, lib_IdString), (ULONG)RELEASESTRING VSTRING,
    0x0000
    };
#undef id_byte
#undef id_word
#undef id_long

/*
 * Api show and hide functions.. during these calls system is not
 * inside FOrbid()/Permit() pair
 */

enum {	API_SCRATCH,		/* api not initialized */
	API_INITIALIZED,	/* librarybase created */
	API_SHOWN,		/* librarybase made visible */
	API_HIDDEN,		/* librarybase hidden */
	API_FUNCTIONPATCHED	/* Api functions set to return -1 */
} api_state = API_SCRATCH;

  /*
   * Setting the following variable to FALSE just before making
   * new socket Library base prevents ELL_Expunge, the final
   * expunging function to remove library base from memory
   */
BOOL AmiTCP_lets_you_do_expunge = FALSE;

BOOL SB_Expunged = FALSE; /* boolean value set by ELL_Expunge */


struct Library * SAVEDS RAF2(ELL_Open,
			     struct Library *,	libPtr,		a6,
			     ULONG,		version,	d0)
#if 0
{
#endif
  
  extern f_void UserLibrary_funcTable[];
  struct SocketBase * newBase;
  LONG error;
  WORD * i;

#if 0
  /*
   * This does not work, since the version argument seems to be a pointer 
   * to the library (same as libPtr).
   * If this functionality cannot be implemented, then this part should be
   * removed.
   */

  /*
   * Check that requested version is at least 2, since the version 2 and 
   * later are incompatible with the version 1. 
   */
  if (version < 2) {
    log(LOG_INFO, "Old version of an application rejected.");
    return NULL;
  }
#endif

  /*
   * One task may open socket library more than once. In that case caller
   * receives the base it has opened already.
   */
  if ((newBase = FindSocketBase(SysBase->ThisTask)) != NULL) {
    newBase->libNode.lib_OpenCnt++;
    return (struct Library *)newBase;
  }
  /*
   * Create new library base.
   * All fields in the base will first be initialized to zero and then
   * modified by initializers in initTable.
   */
  newBase = (struct SocketBase *)MakeLibrary(UserLibrary_funcTable,
					     (UWORD *)&Library_initTable,
					     NULL,
					     sizeof(struct SocketBase),
					     NULL);
  if (newBase == NULL)
    return NULL;

  /*
   * add this newly allocated library base to our list of opened
   * socket libraries
   */	
  AddTail(&socketBaseList, (struct Node *)newBase); 

  /*
   * Modify some MASTER library base fields
   */
  libPtr->lib_OpenCnt++;		/* mark us as having another opener */
  libPtr->lib_Flags&= ~LIBF_DELEXP;	/* prevent delayed expunges */

  /*
   * Initialize new library base
   */
  for (i = (WORD *)((struct Library *)newBase + 1);
       i < (WORD *)(newBase + 1);
       i++)
    *i = 0L;
  newBase->libNode.lib_OpenCnt = 1;
  newBase->errnoPtr = (VOID *)&newBase->defErrno;
  newBase->errnoSize = sizeof newBase->defErrno;
  newBase->thisTask = SysBase->ThisTask;
  newBase->sigIntrMask = SIGBREAKF_CTRL_C;
  
  newBase->dTableSize = FD_SETSIZE;
  if ((newBase->dTable =
       AllocMem(newBase->dTableSize * sizeof(struct socket *),
		MEMF_CLEAR|MEMF_PUBLIC)) != NULL) {
    /*	
     * allocate and initialize the timer message reply port
     */
    newBase->timerPort = CreateMsgPort();
    if (newBase->timerPort != NULL) {
      /*
       * Disable signalling for now
       */
      newBase->timerPort->mp_Flags = PA_IGNORE;
      /*
       * allocate and initialize the timerequest
       */
      newBase->tsleep_timer = (struct timerequest *)
	CreateIORequest(newBase->timerPort, sizeof(struct timerequest));
      if (newBase->tsleep_timer != NULL) {
	error = OpenDevice(TIMERNAME, UNIT_VBLANK, 
			   (struct IORequest *)newBase->tsleep_timer, 0);
	if (error == 0) {
	  /*
	   * Initialize some fields of the IO request to common values
	   */
	  newBase->tsleep_timer->tr_node.io_Command = TR_ADDREQUEST;
	  newBase->tsleep_timer->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN;
	  return (struct Library *)newBase;
	}
      }
    }
  }
  /*
   * There was some error if we reached here. Call Close to clean up.
   */
  {
#if __GNUC__
    extern ULONG* REGARGFUN UL_Close(VOID);
    register struct SocketBase *a6 __asm("a6") = newBase;
    UL_Close();
#elif __SASC
    extern ULONG* REGARGFUN UL_Close(register __a6 struct SocketBase *);
    UL_Close(newBase);
#else 
#error Compiler not supported!
#endif
  }
  return NULL;
}


ULONG * SAVEDS RAF1(ELL_Expunge,
		    struct Library *,	libPtr, a6)
#if 0
{
#endif
  /*
   * Since every user gets her own library base, Major library base
   * can be removed immediately after 
   */ 
  if (libPtr->lib_OpenCnt == 0 && AmiTCP_lets_you_do_expunge) {
    VOID * freestart;
    ULONG  size;

#if 0	/* Currently done already  */
    /*
     * unlink SocketBase from System Library list
     */
    Remove((struct Node *)libPtr);
#endif
    
    freestart = (void *)((ULONG)libPtr - (ULONG)libPtr->lib_NegSize);
    size = libPtr->lib_NegSize + libPtr->lib_PosSize;
    FreeMem(freestart, size);
    MasterSocketBase = NULL; 

    SB_Expunged = TRUE;
    Signal(AmiTCP_Task, SIGBREAKF_CTRL_F);
    return NULL; /* no AmigaDos seglist there (for system use) */
  }
  /*
   * here if someone still have us open, or AmiTCP don't let us expunge yet
   */
  libPtr->lib_Flags |= LIBF_DELEXP;	/* set delayed expunge flag */
  SB_Expunged = FALSE;
  return NULL;
}

LONG /* SAVEDS */ Null(void)
{
  return 0L;
}

LONG /* SAVEDS */ Garbage(void)
{     
  return -1L;
}


ULONG * SAVEDS RAF1(UL_Close,
	  struct SocketBase *,	libPtr, a6)
#if 0
{
#endif
  
  VOID * freestart;
  ULONG  size;
  int	 i;

  /*
   * one task may have SocketLibrary opened more than once.
   */
  if (--libPtr->libNode.lib_OpenCnt > 0)
    return NULL;
#ifdef DEBUG
  log(LOG_DEBUG, "Closing proc 0x%lx base 0x%lx\n", 
      libPtr->thisTask, libPtr);
#endif
  /*
   * Since library base is to be closed, all sockets referenced by this
   * library base must be closed too. Next piece of code searches for open
   * sockets and calls CloseSocket() on our own library base. It is safe
   * to call since Forbid() state is broken if semaphore needs to be waited.
   *
   * Note that the close may linger. In such case the linger time will be
   * waited. The linger may be interrupted by any signal in sigIntrMask.
   */
  for (i = 0; i < libPtr->dTableSize; i++)
    if (libPtr->dTable[i] != NULL)
      CloseSocket(libPtr, i);
  
  Remove((struct Node *)libPtr); /* remove this librarybase from our list
				    of opened library bases */

  if (libPtr->tsleep_timer) {
    if (libPtr->tsleep_timer->tr_node.io_Device != NULL) {
      AbortIO((struct IORequest *)(libPtr->tsleep_timer));
      CloseDevice((struct IORequest *)libPtr->tsleep_timer);
    }
    DeleteIORequest((struct IORequest *)libPtr->tsleep_timer);
  }
  if (libPtr->timerPort)
    DeleteMsgPort(libPtr->timerPort);

  freeDataBuffer(&libPtr->selitems);
  freeDataBuffer(&libPtr->hostents);
  freeDataBuffer(&libPtr->netents);
  freeDataBuffer(&libPtr->protoents);
  freeDataBuffer(&libPtr->servents);
  
  if (libPtr->dTable) 
    FreeMem(libPtr->dTable, libPtr->dTableSize * sizeof(struct socket *));

  freestart = (void *)((ULONG)libPtr - (ULONG)libPtr->libNode.lib_NegSize);
  size = libPtr->libNode.lib_NegSize + libPtr->libNode.lib_PosSize;
  bzero(freestart, size);
  FreeMem(freestart, size);

  MasterSocketBase->lib_OpenCnt--;
  /*
   * If no more libraries are open and delayed expunge is asked,
   * ELL_expunge() is called.
   */
  if (MasterSocketBase->lib_OpenCnt == 0 &&
      (MasterSocketBase->lib_Flags & LIBF_DELEXP)) {
#if __GNUC__
    register struct Library *a6 __asm("a6") = MasterSocketBase;
    return ELL_Expunge();
#elif __SASC
    return ELL_Expunge(MasterSocketBase);
#else 
#error Compiler not supported!
#endif
  }

  return NULL; /* allways return null */
}

BOOL api_init()
{
  extern void select_init(void);
  extern f_void ExecLibraryList_funcTable[];
  
  if (api_state != API_SCRATCH)
    return TRUE;

  AmiTCP_lets_you_do_expunge = FALSE;
  
  MasterSocketBase = MakeLibrary(ExecLibraryList_funcTable,
				 (UWORD *)&Library_initTable,
				 NULL,
				 sizeof(struct Library),
				 NULL);
  if (MasterSocketBase == NULL)
    return FALSE;

  InitSemaphore(&syscall_semaphore);
  select_init(); /* initializes data Select() needs */
  NewList(&socketBaseList);
  NewList(&garbageSocketBaseList);
  NewList(&releasedSocketList);

  api_state = API_INITIALIZED;
  return TRUE;
}

LONG nthLibrary = 0;

BOOL api_show()
{
  int i = 0;
  struct Node * libNode;
  STRPTR libName = (STRPTR)Library_initTable.ln_Name;

  if (api_state == API_SHOWN)
    return TRUE;
  if (api_state == API_SCRATCH)
    return FALSE;

  Forbid();
  for (libNode = SysBase->LibList.lh_Head; libNode->ln_Succ;
       libNode = libNode->ln_Succ) {
    if (!strncmp(libNode->ln_Name, libName, sizeof (SOCLIBNAME) - 3)) {
#ifdef DEBUG
      if (libNode->ln_Name[sizeof (SOCLIBNAME) - 3] == '\0') 
	i = 1;
      else 
	i = (BYTE)(libNode->ln_Name[sizeof (SOCLIBNAME) - 2] - '0' + 1);
      if (nthLibrary < i)
	nthLibrary = i;
#else
      Permit();
      return FALSE;
#endif
    }
  }
  Permit();
#ifdef DEBUG
  if (nthLibrary > 8)
    return FALSE;
  if (nthLibrary) {
    libName[sizeof (SOCLIBNAME) - 3] = '.'; 
    libName[sizeof (SOCLIBNAME) - 2] = '0' + nthLibrary;
    libName[sizeof (SOCLIBNAME) - 1] = '\0';
    MasterSocketBase->lib_Node.ln_Name = libName;
  }
#endif
  AddLibrary(MasterSocketBase);
  api_state = API_SHOWN;
  
  return TRUE;
}

VOID api_hide()
{
  if (api_state != API_SHOWN)
    return;
  Forbid();
  /* unlink Master SocketBase from System Library list */
  Remove((struct Node*)MasterSocketBase);	
  Permit();
  api_state = API_HIDDEN;
}

VOID api_setfunctions() /* DOES NOTHING NOW */
{
/*  struct Node *node2move; */
  
  if (api_state == API_SCRATCH)
    return;
  Forbid();
  if (api_state == API_SHOWN)
    /* unlink Master SocketBase from System Library list */
    Remove((struct Node*)MasterSocketBase);	

  /* here SetFunction()s to patch libray calls (forbid()/permit()) */
  /*  while(node2move = RemHead(&socketBaseList))
      AddTail(&garbageSocketBaseList, node2move); */
  Permit();
  api_state = API_FUNCTIONPATCHED;
}


VOID api_deinit()
{
#if DIAGNOSTIC
  if (FindTask(NULL) != AmiTCP_Task)
    log(LOG_ERR, "The calling task of api_deinit() was not AmiTCP/IP");
#endif  
  if (api_state == API_SHOWN || api_state == API_HIDDEN)
    api_setfunctions();
  if (api_state == API_SCRATCH)
    return;
  
  Forbid();
  AmiTCP_lets_you_do_expunge = TRUE;
  {
#if __GNUC__
    register struct Library *a6 __asm("a6") = MasterSocketBase;
    ELL_Expunge();
#elif __SASC
    ELL_Expunge(MasterSocketBase);
#else 
#error Compiler not supported!
#endif
  }
  Permit();

  /*
   * if SB_Expunged == FALSE, waiting until last UL_Close() expunges
   * our library.
   */
  while(SB_Expunged == FALSE)
    Wait(SIGBREAKF_CTRL_F);

  api_state = API_SCRATCH;
}

void writeErrnoValue(struct SocketBase * libPtr, int errno)
{
  int erri = (int)(libPtr->errnoSize) - 1;

  if (erri < 0)
    return;
  
  bzero(libPtr->errnoPtr, erri);
  libPtr->errnoPtr[erri] = (UBYTE)errno;
}
