// <copyright>
// 
// Copyright (c) 1993-1995
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
// </copyright>

//<file>
//
// Name:       hgunistd.h
//
// Purpose:    syswrite, sysread, hg_signal
//
// Created:    27 Jun 94    Gerald Pani
//
// Description:
//
//
//</file>


#include "hgunistd.h"
#include <errno.h>
#include <signal.h>
#include <fcntl.h>

int syswrite( int fd, const char* buf, int nbyte) {
     register int offset = 0;
     while (nbyte) {
	  int written = ::write( fd, buf + offset, nbyte);
	  if (written < 0) {
	       if (errno != EINTR)
		    return written;
	       else 
		    written = 0;
	  }
	  nbyte -= written;
	  offset += written;
     }
     return offset;
}

int sysread( int fd, char* buf, int nbyte) {
     register int offset = 0;
     while (nbyte) {
	  int readin = ::read( fd, buf + offset, nbyte);
	  if (readin == 0)
	       // eof
	       return offset;
	  if (readin < 0) {
	       if (errno != EINTR)
		    return readin;
	       else 
		    readin = 0;
	  }
	  nbyte -= readin;
	  offset += readin;
     }
     return offset;
}

#ifdef ULTRIX
#  ifdef __GNUC__
     extern "C" int sigfillset(sigset_t*);
#  else
     extern "C" int sigfillset(sigset_t*);
     extern "C" int sigaction(int, struct sigaction*, struct sigaction*);
#  endif
#endif

Sigfunc* hg_signal( int sig, Sigfunc* handler) {
   THREADSTATIC struct sigaction a, ao;
#if defined(__GNUC__)
   a.sa_handler = (void (*)(...))handler;
#elif defined(ULTRIX) || defined (WIN32)
   a.sa_handler = (void (*)())handler;
#else
   a.sa_handler = handler;
#endif

// #if defined(ULTRIX) && !defined(__GNUC__)
//    a.sa_handler = (void (*)())handler;
// #else
// #if defined(SOLARIS) || defined(IRIX) || defined(BSD) && defined(SUN) && defined(__GNUC__)
//    a.sa_handler = (void (*)(...))handler;
// #else
//    a.sa_handler = handler;
// #endif
// #endif
      sigfillset(&a.sa_mask);
   if (sigaction(sig, &a, &ao) < 0)
      return (Sigfunc*)SIG_ERR;
   return (Sigfunc*)ao.sa_handler;
}




// so much for nonblocking IO/connect and POSIX !!!

//            | O_NONBLOCK     O_NDELAY
// -----------------------------------------------------------------
// HPUX       |                                                  
//            |                                                  
// connect()  | ok             ?                                
// read()     | ok             returns ZERO if no data there !!!
//            |                                                  
// -----------------------------------------------------------------
// SUN4       |                                                  
//            |                                                  
// connect()  | blocks!!!      ok                               
// read()     | ok             ok                               
//            |                                                  
// -----------------------------------------------------------------
// SUN5       |                                                  
//            |                                                  
// connect()  | ok             ?                                
// read()     | ok             ?                                
//            |                                                  
// -----------------------------------------------------------------
// LINUX      |                                                  
//            |                                                  
// connect()  | ok             ?                                
// read()     | ok             ?                                
//            |                                                  
// -----------------------------------------------------------------
// SGI        |                                                  
//            |                                                  
// connect()  | ok             ?                                
// read()     | ok             ?                                
//            |                                                  
// -----------------------------------------------------------------
// OSF1       |                                                  
//            |                                                  
// connect()  | ok             ?                                
// read()     | ok             ?                                
//            |                                                  
// -----------------------------------------------------------------
// PMAX       |           
//            |           
// connect()  | ok             ?
// read()     | ok             ?
// -----------------------------------------------------------------
// FreeBSD    | (O_NDELAY is defined to be O_NONBLOCK in <sys/fcntl.h> )
//            |           
// connect()  | ok             ok
// read()     | ok             ok



#if (defined HPUX)
#  define NONBLOCK O_NONBLOCK

#elif (defined SUN) && (HG_OSMaj == 4)
#  define NONBLOCK O_NDELAY

#elif (defined SUN) && (HG_OSMaj == 5)
#  define NONBLOCK O_NONBLOCK

#elif (defined LINUX)
#  define NONBLOCK O_NONBLOCK

#elif (defined IRIX)
#  define NONBLOCK O_NONBLOCK

#elif (defined OSF1)
#  define NONBLOCK O_NONBLOCK

#elif (defined ULTRIX)
#  define NONBLOCK O_NONBLOCK

#elif (defined AIX)
#  define _BSD 44
#  define NONBLOCK O_NONBLOCK

#elif (defined WIN32)

#elif (defined FreeBSD)
#  define NONBLOCK O_NONBLOCK

#elif (defined BSDI)
#  define NONBLOCK O_NONBLOCK

#else 
#  error have to figure out NONBLOCK
#endif

#ifdef WIN32
#include <winsock.h>

// sets blocking state
// if bl TRUE => blocking
ImplementHashTableBase(BlockingStateTable,int,char)

int BlockingStateTable::hash(const int& key) const
{
  return (int)(key%size_);
};

// gorasche 240996 if any problems with blocking will arise:
// the hashtable must be changed to a class without constructor
// to make it TLS compatible!!!!!!!!
static BlockingStateTable BlockArray;

int set_blocking (int fd, int bl)
{
  BlockingStateTableEntry* pTemp;

  // set socket state
  u_long ulParam=bl?0L:1L;
  if(ioctlsocket(fd,FIONBIO,&ulParam)==SOCKET_ERROR)
	  return -(WSAGetLastError());

  // update socket status
  if(pTemp=BlockArray.find(fd))
    pTemp->data_=(char)bl;
  else
    BlockArray.insertEntry(fd,(char)bl);
  return 0 ;
}

// returns blocking state
// TRUE == blocking
int get_blocking (int fd)
{
  BlockingStateTableEntry* pTemp;
  // get blocking state
  if(pTemp=BlockArray.find(fd))
    // yes, we have an entry
    return pTemp->data_;
  else
    // no entry ==> socket is blocking
    return 1;
}

int NetStartup(void)
{
  WSAData ActWSA;
  WORD wVersionRequested=MAKEWORD(1,1);

  // let's start Winsock services
  int iErr=WSAStartup(wVersionRequested,&ActWSA);
  if(iErr!=0)
  {
 	  perror( "WinSock:InitErr");
	  _exit(-1);
  }

  // test Winsock Version (we want 1.1)
  if(LOBYTE(ActWSA.wVersion )!= 1 || 
     HIBYTE(ActWSA.wVersion )!= 1 )
  { 
    WSACleanup(); 
 	  perror( "WinSock:VersionErr");
	  _exit(-1);
  }

  return 0;
}

int NetShutdown(void)
{
  // stop Winsock
  if(WSACleanup()==WSAEINPROGRESS)
  {
    WSACancelBlockingCall();
    WSACleanup();
  }
  return 0;
}

#else
int set_blocking (int fd, int bl) {
   int flags = fcntl (fd, F_GETFL, 0) ;
   if (flags < 0)
      return flags ;

   if (bl)
      flags &= ~NONBLOCK ;
   else
      flags |= NONBLOCK ;

   if ((flags = fcntl (fd, F_SETFL, flags)) < 0)
      return flags ;

   return 0 ;
}

int get_blocking (int fd) {
   int flags = fcntl (fd, F_GETFL, 0);
   if (flags < 0)
      return flags ;
   return (flags & NONBLOCK) ? 0 : 1 ;
}
#endif
