/* static char szModuleName__[] = "c:/unix/newer/netcom.c"; jmh 29 May 2001 */
/* static char szLastVersion[] = "Version 0.7"; jmh 29 May 2001 */
/* static char szLastSave[] = "1994-11-17*15:02"; jmh 29 May 2001 */

/************************************************************
Abstract
netcom.c - Host Access Communication Services, TCP/IP Sockets.

(C) Copyright AU-System Communication AB 1994.

Change activity
010525      ARG  Removed obsolete definition of fd_set (was only done for VAXC)
010525      ARG  Modified handling of getsockopt
970908      ARG  Cast in connect added
941227      ARG  Fixed bug in netread
941107      ARG  Removed some compilation warnings
940530 1.00 BBN  Loop counter deactivated in receive
930622 1.00 BBN  Initial version by Björn Brodin.

Part of  Nordrad.

Description
************************************************************                */

#ifdef   VAXC
#include <types.h>
#include <stdio.h>
#include <string.h>
#include <stat.h>
#include <socket.h>
#include <ucx$inetdef.h>
#include <in.h>
#include "netdef.h"
#include "api.h"
#include "net.h"
#include "utl.h"
#include "nradutil.h"
#define TCP_MAXSEG INET$C_TCP_MAXSEG
#else
#ifdef   __MSDOS__

/* #include <sys/socketvar.h>                                               */

#include "netdef.h"
#include "api.h"
#include "net.h"
#include "utl.h"
#include "nradutil.h"
#endif
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/time.h>
#ifndef  __MSDOS__

/* #include <sys/socketvar.h>                                               */

#include "netdef.h"
#include "api.h"
#include "net.h"
#include "utl.h"
#include "nradutil.h"
#endif
#endif

/*----------------------------------------------------------
*       Macros
*---------------------------------------------------------                  */

typedef struct sockaddr SADDR;
typedef struct sockaddr_in SAIN;       /* socket address Internet           */

/*----------------------------------------------------------
*       Function prototypes
*----------------------------------------------------------                 */
/*---------------------------------------------------------
*       Global variables
*---------------------------------------------------------                  */
/* extern       INT32  errno;                                               */
   int bTimeout = FALSE;
/*----------------------------------------------------------
*  Init Net Activity on Socket.
*---------------------------------------------------------                  */

INT32 NetOpenClient(INT16 port,char *pInetAdr,INT32 *piStatus)
{
  SAIN name;
  INT32 i,Sockh;
  /*  INT32 iRc = OK; */
  struct linger linger;

  Sockh = socket(AF_INET, 
                 SOCK_STREAM, 
                 0);
  if (Sockh == -1)
    {
      *piStatus = errno;
      return  NOK;
    } 
  else
    {

      name.sin_family = AF_INET;
      name.sin_addr.s_addr = inet_addr(pInetAdr);
      name.sin_port = htons(port);
      i = 1;
      if ((/*iRc = */setsockopt(Sockh, 
				SOL_SOCKET, 
				SO_KEEPALIVE, 
				&i, 
				sizeof(i))) < 0)
        {
          *piStatus = errno;
          return  NOK;
        } 

      linger.l_onoff  = 1;
      linger.l_linger = 60;
#ifdef DEBUG
 printf ("In NetOpenClient, Calling setsocopt(linger)\n");
#endif
      if ((/*iRc = */setsockopt(Sockh, 
                            SOL_SOCKET, 
                            SO_LINGER,
                            &linger, 
                            sizeof(linger))) < 0)
        {
#ifdef DEBUG
 printf ("In NetOpenClient, Back from linger iRc = %d\n",iRc);
#endif
          *piStatus = errno;
          return  NOK;
        } 

#ifdef DEBUG
 printf ("In NetOpenClient, Back from linger iRc = %d\n",iRc);
#endif
      if (connect(Sockh, 
                  (struct sockaddr *)&name, 
                  sizeof(name)) == -1)
        {
          close(Sockh);
          *piStatus = errno;
          return  NOK;
        } 
    } 

  return (Sockh);
} 

#ifndef  NOSERVER

/*----------------------------------------------------------
*  Open server socket.
*---------------------------------------------------------                  */

INT32 NetOpenServer(void)
{
  SAIN name;
  char *pe = NULL;
  INT32 i,len,Sockh,iRc = OK;
  struct linger linger;

  /**************************************************************************/
  /* * Open socket : UCX$C_AUXS as AUXILIARY SERVER / Internet superserver  */
  /**************************************************************************/

  if ((Sockh = socket(UCX$C_AUXS, 
                      0, 
                      0)) == -1)
    {
      return (Sockh);
    } 
  else
    {
      i = 1;
      if ((iRc = setsockopt(Sockh, 
                            SOL_SOCKET, 
                            SO_REUSEADDR, 
                            &i, 
                            sizeof(i))) < 0)
        return  iRc;

      if ((iRc = setsockopt(Sockh, 
                            SOL_SOCKET, 
                            SO_KEEPALIVE, 
                            &i, 
                            sizeof(i))) < 0)
        return  iRc;

      linger.l_onoff  = 1;
      linger.l_linger = 60;
#ifdef DEBUG
 printf ("In NetOpenServer, Calling linger\n");
#endif
      if ((iRc = setsockopt(Sockh, 
                            SOL_SOCKET, 
                            SO_LINGER,
                            &linger, 
                            sizeof(linger))) < 0)
          {
#ifdef DEBUG
 printf ("In NetOpenServer, Back from linger iRc = %d\n",iRc);
#endif
          return  iRc;
	 }
    } 
#ifdef DEBUG
 printf ("In NetOpenServer, Back from linger iRc = %d\n",iRc);
#endif

  return  Sockh;
} 

#endif

/*============== TEST ENVIRONMENT ================                          */
#ifdef TEST_ENVIRONMENT
INT32 NetListen(INT16 iPort)
{
  SAIN name;
  char InetAdr[60];
  INT32 iRetCode;                      /* return code                       */
  INT32 iOn = 1;
  SAIN sadReq;
  INT32 iSadLength;
  INT32 iId;
  INT32 iSocket;
  INT32 iRc = OK;

  /**************************************************************************/
  /* * Open socket: AF_INET, SOCK_STREAM.                                   */
  /**************************************************************************/

  if ((iSocket = socket(AF_INET, 
                        SOCK_STREAM, 
                        0)) == -1)
    {
      return -1;
    } 

  /**************************************************************************/
  /* * Set socket options                                                   */
  /**************************************************************************/

  iRetCode = setsockopt(iSocket, 
                        SOL_SOCKET, 
                        SO_REUSEADDR, 
                        (char *)&iOn, 
                        sizeof(iOn));
  if ((iRc = setsockopt(iSocket, 
                        SOL_SOCKET, 
                        SO_KEEPALIVE, 
                        &iOn, 
                        sizeof(iOn))) < 0)
    return  iRc;

  if (-1 == iRetCode)
    {
      NetClose(iSocket);
      return -1;
    } 
  memset(&name, 
         0, 
         sizeof(name));
  strcpy(InetAdr, 
         "193.44.80.66");
  name.sin_family = AF_INET;
  name.sin_addr.s_addr = inet_addr(InetAdr);
  name.sin_port = htons(iPort);

  /**************************************************************************/
  /* * Bind name to socket.                                                 */
  /**************************************************************************/

  iRetCode = bind(iSocket, 
                  (struct sockaddr *)&name, 
                  sizeof(name));
  if (-1 == iRetCode)
    {
      NetClose(iSocket);
      return -1;
    } 

  /**************************************************************************/
  /* * Set socket options                                                   */
  /**************************************************************************/

  iRetCode = setsockopt(iSocket, 
                        SOL_SOCKET, 
                        SO_REUSEADDR, 
                        (char *)&iOn, 
                        sizeof(iOn));
  if (-1 == iRetCode)
    {
      NetClose(iSocket);
      return -1;
    } 

  /**************************************************************************/
  /* * Listen on socket for connections.                                    */
  /**************************************************************************/

  iRetCode = listen(iSocket, 
                    5);
  if (-1 == iRetCode)
    {
      NetClose(iSocket);
      return -1;
    } 

  /**************************************************************************/
  /* * Accept connection from socket:                                       */
  /**************************************************************************/

  iSadLength = sizeof(sadReq);
  iId = accept(iSocket, 
               (struct sockaddr *)&sadReq, 
               (int *)&iSadLength);
  if (-1 == iId)
    {
      NetClose(iId);
      return -1;
    } 
  return  iId;
} 

#endif  /* #ifdef TEST_ENVIRONMENT */
/*=======================   END TEST ENVIRONMENT =================          */
/*---------------------------------------------------------
*  Read from socket.
*--------------------------------------------------------                   */

void NetReadBuff(INT32 Sockh,char *pBuff,INT32 iSize,INT32 *piStatus)
{
  INT32 iBytesRead = -1,iTotBytesRead = 0;
  INT32 iCurrReadPos;
  /* INT32 iLoopCounter = 0; */
  INT32 iNetStatus = 0;
  INT32 iNetStatusSize;
  fd_set fdSupervHandle;
  INT32 iMaxSuperv = 0;

  iCurrReadPos = 0;

  /**************************************************************************/
  /* wait for incoming data on line before start the read loop              */
  /**************************************************************************/
#ifdef DEBUG
 printf ("In NetReadBuff, iSize = %d\n",iSize);
#endif

  memset((char *)&fdSupervHandle, 
         0, 
         sizeof(fdSupervHandle));
  FD_SET(Sockh, 
         &fdSupervHandle);
  iMaxSuperv = Sockh+1;
#ifdef DEBUG
 printf ("Calling Select in NetReadBuff\n");
#endif
  select(iMaxSuperv, 
         &fdSupervHandle, 
         (fd_set *)0, 
         (fd_set *)0, 
         NULL);
#ifdef DEBUG
 printf ("Back from Select in NetReadBuff\n");
#endif

  /**************************************************************************/
  /* When we come here, there should be some data present                   */
  /**************************************************************************/

  while ((iTotBytesRead < iSize) && (bTimeout == FALSE) && (iNetStatus != 
     ETIMEDOUT))
    {
      iBytesRead = read(Sockh, 
                        &pBuff [iCurrReadPos], 
                        iSize-iTotBytesRead);
#ifdef DEBUG
 printf ("iBytesRead = %d, Wanted to read %d\n",
	 iBytesRead, iSize-iTotBytesRead);
#endif
      if (iBytesRead > 0)
        {
          iCurrReadPos  += iBytesRead;
          iTotBytesRead += iBytesRead;
        } 
      else
        {
          if (iBytesRead == -1)
            {
              *piStatus = NOK;
              return ;
            } 
#ifdef DEBUG
 printf ("iTotBytesRead = %d\n", iTotBytesRead);
#endif

#ifdef   VAXC

          /******************************************************************/
          /* VMS does not have the SIGALARM function So we'll try to detect */
          /* timeout by counting loops                                      */
          /******************************************************************/

          iLoopCounter++;
          if (iLoopCounter > 100)
            bTimeout = TRUE;
#endif
        } 
      iNetStatusSize = sizeof(iNetStatus);
#ifdef DEBUG
 printf ("Calling getsockopt (SO_ERROR)\n");
#endif

      getsockopt(Sockh, 
                 SOL_SOCKET, 
                 SO_ERROR, 
                 (char *)&iNetStatus, 
                 (int *)&iNetStatusSize);
#ifdef DEBUG
 printf ("back from getsockopt, iNetStatus = %d\n");
#endif

      if ((iTotBytesRead < iSize) && (iNetStatus != ETIMEDOUT))
        {
          sleep(1);
        } 
    } 
  if (((bTimeout == TRUE) || (iNetStatus == ETIMEDOUT)) && (iTotBytesRead !=
     iSize))
    *piStatus = NET_TIMEOUT;
  else
    if (iTotBytesRead != iSize)

      *piStatus = NOK;
    else
      *piStatus = OK;
} 


/*----------------------------------------------------------
*  Write to socket.
*---------------------------------------------------------                  */

void NetWriteBuff(INT32 Sockh,char *pBuff,INT32 iSize,INT32 *piStatus)
{

/*      INT32  iLen=0;                                                      */

  INT32 iLeft,iWritten;
  char *pOut;

#ifdef DEBUG
 printf ("In NetWriteBuff, iSize= %d\n", iSize);
#endif
  iLeft = iSize;
  pOut = pBuff;
  while (iLeft > 0)
    {
      iWritten = write(Sockh, 
                       pOut, 
                       iLeft);
#ifdef DEBUG
 printf ("iWritten = %d, Wanted to write = %d \n", iWritten, iLeft);
#endif

      if (iWritten <= 0)               /* error                             */
        {
          *piStatus = NOK;
          return ;
        } 
      iLeft -= iWritten;
      pOut += iWritten;
    } 
  *piStatus = OK;

/*       
     iLen = write( Sockh, pBuff, iSize ); 
    if (iLen != iSize)
      *piStatus = NOK;
    else  
      *piStatus = OK;                                                       */

} 


/*----------------------------------------------------------
*  Wait for status buffer of integer type or AviStatus type 
*----------------------------------------------------------                 */

INT32 NetWaitStatus(INT32 Sockh,INT32 iRecSize,char *pchAviStatusBuff)
{
  INT32 iRc = NOK;

  memset(pchAviStatusBuff, 
         0, 
         iRecSize);
  NetReadBuff(Sockh, 
              pchAviStatusBuff, 
              iRecSize, 
              &iRc);
  return  iRc;
} 


/*--------------------------------------------------------
*  NetValidateAccess send userifo to host and await 
*  response of user validation
*---------------------------------------------------------                  */

void NetValidateAccess(INT32 Sockh,char *pAccessCtrl,INT32 *piStatus)
{
  INT32 iRc = OK;
  INT32 iSendSize = 0;
  INT32 iValRespBuff = 0;
  char *pValRespBuff;

  pValRespBuff = (char *)&iValRespBuff;
  iSendSize = strlen(pAccessCtrl);
  NetWriteInt(Sockh, 
              iSendSize, 
              piStatus);
  if (*piStatus != OK)
    {
      *piStatus = NET_CONNECTION_LOST;
      return ;
    } 
  NetWriteBuff(Sockh, 
               pAccessCtrl, 
               iSendSize, 
               piStatus);
  if (*piStatus != NOK)
    {
      if ((iRc = NetWaitStatus(Sockh, 
                               sizeof(iValRespBuff), 
                               pValRespBuff)) == OK)
        *piStatus = UtlIntFromNet(iValRespBuff);
      else
        *piStatus = iRc;
    } 
} 


/*----------------------------------------------------------
*  NetSendReqData send data for a specific req to host, host 
*                 is responding with a structure containing 
*                 acceptance on the data and size and name
*                 of result file if any. 
*--------------------------------------------------------                   */

void NetSendReqData(INT32 Sockh,char *pParDataReqBuff,INT32 iSendSize,INT32 
                    *piStatus)
{
  NetWriteInt(Sockh, 
              iSendSize, 
              piStatus);
  if (*piStatus == OK)
    {
      NetWriteBuff(Sockh, 
                   pParDataReqBuff, 
                   iSendSize, 
                   piStatus);
    } 
  else
    *piStatus = NET_CONNECTION_LOST;
} 


/*-----------------------------------------------------------
*  NetGetFile - A complete file is fetched from host 
*----------------------------------------------------------                 */

void NetGetFile(INT32 Sockh,char *pLocalFileStr,INT32 *piStatus)
{
  INT32 iSizeFetched = 0,iFileSize = 0;
  char GetBuff[4 * FILE_BUFF_SIZE];
  char *pGetBuff;
  INT32 iNextGetSize = FILE_BUFF_SIZE;
  FILE *pLocalFile;
  INT32 iRc = 0;
  INT32 iMaxSeg = FILE_BUFF_SIZE;
  int   iOptLen;
#ifndef  __MSDOS__
/* Ask TCP of its max segment size and adjust the size 		*/
/* we use for reading to it. (There was some problem with an    */
/* OSF/1 system when using smaller readsize than max segment    */
/* size								*/
#ifdef DEBUG
 printf ("In NetGetFile, iMaxSeg = %d\n", iMaxSeg);
#endif

  iOptLen = sizeof (iMaxSeg);
  if (getsockopt (Sockh,
    		  IPPROTO_TCP, 
		  TCP_MAXSEG,
		  (char *) &iMaxSeg,
		  &iOptLen) < 0) 
    ; /* Do nothing */
  else
    if (iMaxSeg == 0)		    /* To compensate for a Linux bug */
       iMaxSeg = FILE_BUFF_SIZE;   
    if (iMaxSeg > sizeof (GetBuff))
      iMaxSeg = sizeof (GetBuff);

    iNextGetSize = iMaxSeg;
#endif

#ifdef DEBUG
 printf ("In NetGetFile after getsockopt, iMaxSeg = %d\n", iMaxSeg);
#endif

  NetReadInt(Sockh, 
             &iFileSize, 
             piStatus);
#ifdef DEBUG
 printf ("In NetGetFile, iFileSize = %d\n", iFileSize);
#endif

  if (*piStatus == NOK)
    return ;
  pLocalFile = fopen(pLocalFileStr, 
                     "wb");
  if (pLocalFile == NULL)
    {
      *piStatus = NET_LOC_FILE_OPEN_ERR;
      return ;
    } 
  iRc = fseek(pLocalFile, 
              iFileSize-1, 
              SEEK_SET);               /* set filesize to increase speed in  
                                          transmission                      */
  if (iRc == 0)
    fwrite(" ", 
           1, 
           1, 
           pLocalFile);
  iRc = fseek(pLocalFile, 
              0L, 
              SEEK_SET);               /* set position to beginning         */
  if (iRc != 0)
    *piStatus = NET_LOC_FILE_OPEN_ERR;
  pGetBuff = &GetBuff[0];
  while ((iSizeFetched < iFileSize) && 
    	 (*piStatus == OK) && 
	 (bTimeout ==  FALSE))
    {
      if ((iFileSize-iSizeFetched) < iNextGetSize)
        iNextGetSize = iFileSize-iSizeFetched;
      NetReadBuff(Sockh, 
                  pGetBuff, 
                  iNextGetSize, 
                  piStatus);
      if (*piStatus == OK)
        {
          iSizeFetched += iNextGetSize;
#ifdef DEBUG
 printf ("In NetGetFile, iSizeFetched = %d\n", iSizeFetched);
#endif

          if (fwrite(pGetBuff, 
                     sizeof(char), 
                     iNextGetSize, 
                     pLocalFile) != iNextGetSize)
            *piStatus = NET_LOC_FILE_WRITE_ERR;
        } 
      else
        {
          *piStatus = NET_SIZE_ERR;
        } 
    }	/* while ... */
  fclose(pLocalFile);
} 


/*----------------------------------------------------------
*  NetPutFile - A complete file is sent  
*---------------------------------------------------------                  */

void NetPutFile(INT32 Sockh,char *pLocalFileStr,INT32 *piStatus)
{
  INT32 iFileSize,iBytesSent = 0,iBytesRead = 0,iBytesToSend = 0;
  char PutBuff[FILE_BUFF_SIZE];
  char *pPutBuff;
  FILE *pLocalFile;
  struct stat FileInfo;

  pPutBuff = &PutBuff[0];
#ifdef   VMS                
  pLocalFile = fopen(pLocalFileStr, 
                     "rb", 
                     "ctx=stm");
#else
  pLocalFile = fopen(pLocalFileStr, 
                     "rb");
#endif
  if (pLocalFile == NULL)
    {
      *piStatus = NET_SOURCE_FILE_ERR;
      return ;
    } 
  *piStatus = fstat(fileno(pLocalFile), 
                    &FileInfo);
  iFileSize = FileInfo.st_size;
#ifdef DEBUG
 printf ("In NetPutFile, iFileSize = %d\n", iFileSize);
#endif

  NetWriteInt(Sockh, 
              FileInfo.st_size, 
              piStatus);
  while ((feof(pLocalFile) == 0) && (*piStatus == OK) && (bTimeout == FALSE)
     )
    {
      iBytesRead = fread(pPutBuff, 
                         1, 
                         FILE_BUFF_SIZE, 
                         pLocalFile);
      if (iBytesRead > 0)
        {
          NetWriteBuff(Sockh, 
                       pPutBuff, 
                       iBytesRead, 
                       piStatus);
          iBytesSent = iBytesSent+iBytesRead;
        } 
    } 
#ifdef DEBUG
 printf ("EOF in NetPutFile, iBytesSent = %d\n", iBytesSent);
#endif

  if (iBytesSent < iFileSize)
    {

      /**********************************************************************/
      /* We don't want to hang the other side waiting for more filedata     */
      /* let's send some null-data                                          */
      /**********************************************************************/

      memset(PutBuff, 
             0, 
             FILE_BUFF_SIZE);
      while ((iBytesSent < iFileSize) && (*piStatus == OK) && (bTimeout == 
         FALSE))
        {
          if ((iFileSize-iBytesSent) > FILE_BUFF_SIZE)
            iBytesToSend = FILE_BUFF_SIZE;
          else
            iBytesToSend = iFileSize-iBytesSent;
          NetWriteBuff(Sockh, 
                       pPutBuff, 
                       iBytesToSend, 
                       piStatus);
          iBytesSent = iBytesSent+iBytesToSend;
        } 
    } 
  fclose(pLocalFile);
} 


/*----------------------------------------------------------
*  NetReadInt - Read integer value from peer
*---------------------------------------------------------                  */

void NetReadInt(INT32 Sockh,INT32 *piValue,INT32 *piRc)
{
  INT32 iRecInt = 0;
  char *pRecInt;

  pRecInt = (char *)&iRecInt;
  NetReadBuff(Sockh, 
              pRecInt, 
              sizeof(INT32), 
              piRc);
  if (*piRc != NOK)
    *piValue = UtlIntFromNet(iRecInt);
} 


/*----------------------------------------------------------
*  NetWriteInt - Send integer value to peer
*---------------------------------------------------------                  */

void NetWriteInt(INT32 Sockh,INT32 iSendInt,INT32 *piRc)
{
  *piRc = OK;
  if (*piRc == OK)
    {
      iSendInt = UtlIntToNet(iSendInt);/* convert integer to internet format*/
      NetWriteBuff(Sockh, 
                   (char *)&iSendInt, 
                   sizeof(INT32), 
                   piRc);
      if ((*piRc != NOK) || (bTimeout == TRUE))
        {
          if (bTimeout == TRUE)
            *piRc = NET_TIMEOUT;
        } 
    } 
} 


/*----------------------------------------------------------
*  NetClose - Releases a net connection
*---------------------------------------------------------                  */

void NetClose(INT32 Sockh)
{
  /* INT32 iRc = OK; */

  if (Sockh > 0)
    /* iRc = */close(Sockh);
} 


/****************************************************************************
*                                           UtlIntFromNet()                             
*   Convert word/integer to internet format when fetching from net
*****************************************************************************
                                                                            */

INT32 UtlIntFromNet(INT32 iLocalInt)
{
  INT32 iRc = OK;

  if (sizeof(INT32) > 2)
    iRc = ntohl(iLocalInt);
  else
    iRc = ntohs(iLocalInt);
  return  iRc;
} 


/****************************************************************************
*                                           UtlIntToNet()                               
*   Convert word/integer to internet format when sending to net
*****************************************************************************
                                                                            */

INT32 UtlIntToNet(INT32 iLocalInt)
{
  INT32 iRc = OK;

  if (sizeof(INT32) > 2)
    iRc = htonl(iLocalInt);
  else
    iRc = htons(iLocalInt);
  return  iRc;
} 

