/*
 * **********************************************
 * *	                                        *
 * *     IRIS Socket Server Test program        *
 * *                                            *
 * **********************************************
 * File: utils/examples/ss_test.C
 *
 *                   COPYRIGHT (c) 2001, 2002  BY
 *         SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <netdb.h>
#include <netinet/tcp.h>
#ifndef LINUX
#include <signal.h>
#endif  /* #ifndef LINUX */
#include <stdio.h>
#include <stdlib.h>
#ifdef HPUX
#include <string.h>
#endif  /* #ifdef HPUX */
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>

#include "sigtypes.h"
#include "signetwork.h"

#define BUFFER_SIZE (1000)

/* Function prototypes used just in this file */
static int init_tcpip
  ( int iport_a );

static void run_tcpip
( void );

static void MessageToServer
(int iSocket_a,
 const char *sData_a,
 int iSize_a);

static void upi_xmt_sigio_handler
( int signal_a );

/* Shared variables */
static char shost_c[MAXHOSTNAMELEN];
static int socket_c;

/* =====================================================
 * This is an example program showing how to send files to IRIS.
 * This program prompt for a file (or path) name, then sends it to IRIS.
 * It uses RCP to copy the file.
 *
 */
int main( int iargc_a, char** sargv_a )
{
  int ierror, iarg;
  unsigned int iport;
  char *sptr;

  /* ------------------------------------------------------------------- */

  setlocale( LC_ALL, "" );

  iport  = PORT_SOCKET_SERVER;
  ierror = gethostname( shost_c, MAXHOSTNAMELEN );
  if (ierror < 0)
    {
      perror( "gethostname" );
      exit(EXIT_FAILURE);
    }

  for (iarg=1; iarg<iargc_a; iarg++)
    {
      if ( 0 == strcmp( sargv_a[iarg], "-h" ) )
	{
	  printf( "ss_test command line options:\n" );
	  printf( "  -h      : help\n" );
	  printf( "  -n hhhh : specify host name to send to (defaults to localhost)\n" );
	  printf( "  -p pppp : specify port number (default %d)\n", PORT_SOCKET_SERVER );
	  exit(EXIT_SUCCESS);
	}
      else if ( 0 == strcmp( sargv_a[iarg], "-n" ) )
	{
	  iarg++;
	  if (iarg<iargc_a)
	    {
	      /* Process the port number */
	      strncpy( shost_c, sargv_a[iarg], MAXHOSTNAMELEN-1 );
	      shost_c[MAXHOSTNAMELEN-1] = 0;
	    }
	  else
	    {
	      printf( "Missing host name after '-n'\n" );
	      exit(EXIT_FAILURE);
	    }
	}
      else if ( 0 == strcmp( sargv_a[iarg], "-p" ) )
	{
	  iarg++;
	  if (iarg<iargc_a)
	    {
	      /* Process the port number */
	      iport = strtol( sargv_a[iarg], &sptr, 10 );
	      if ((iport<MIN_USER_PORT) || (iport>65535))
		{
		  printf( "Port number %d invalid.\n", iport );
		  exit(EXIT_FAILURE);
		}
	    }
	  else
	    {
	      printf( "Missing port number after '-p'\n" );
	      exit(EXIT_FAILURE);
	    }
	}
      else
	{
	  printf( "Unrecognized command line argument '%s'\n", sargv_a[iarg] );
	  exit(EXIT_FAILURE);
	}
    }

  ierror = init_tcpip( iport );
  if (ierror != 0)
    {
      fprintf( stderr, "init_tcpip returned error\n" );
      exit(EXIT_FAILURE);
    }

  run_tcpip( );

  sleep(1);
  sleep(1);
  sleep(1);
  sleep(1);
  sleep(1);
  sleep(1);

  exit(EXIT_SUCCESS) ;
}

/* ===========================================================
 * Initialize the socket connection.  Returns -1 if there was an error, 0 if OK.
 */
static int init_tcpip
  ( int iport_a )
{
  int ierror, iflag, iaddrsize;
  struct sockaddr_in servaddr_in;
  struct sockaddr *pservaddr;
  struct hostent *hostptr;
  struct in_addr *paddress;

  /* Convert the server host name to an internet address:
   */
  hostptr = gethostbyname(shost_c);
  printf( "Initializing host:'%s', port:%d\n", shost_c, iport_a );
  if (hostptr != NULL)
    {
      memset( &servaddr_in, 0, sizeof(servaddr_in));
      servaddr_in.sin_family = AF_INET;
      paddress = (struct in_addr *)hostptr->h_addr_list[0];
      servaddr_in.sin_addr = *paddress;
      servaddr_in.sin_port = htons(iport_a);
      
      pservaddr = (struct sockaddr*)(void*)&servaddr_in;
      iaddrsize = sizeof( servaddr_in );
    }
  else
    {
      perror( "gethostbyname" );
      return -1;
    }

  socket_c = socket(AF_INET,SOCK_STREAM,0);
  if (socket_c == -1)
    {
      perror( "socket" );
      return -1;
    }
  /* We now have a valid opened socket, it must be closed if we exit.
   * Set the TCP_NODELAY option.
   */
  iflag = TRUE;
  ierror = setsockopt( socket_c, IPPROTO_TCP, TCP_NODELAY, (char *)&iflag,
		      sizeof(iflag) );
  if (ierror < 0) perror( "setsockopt" );

  ierror = connect(socket_c, pservaddr, iaddrsize);
  if (ierror >= 0)
    {
      struct sigaction action;
      /* Set up the socket to be nonblocking asynchronous mode */
      /* Set up a signal handler for the SIGIO signal */
      printf( "Connected OK\n" );
      action.sa_handler = upi_xmt_sigio_handler;
      sigemptyset( &action.sa_mask );
      action.sa_flags = SA_RESTART;
      ierror = sigaction( SIGIO, &action, NULL );
      if (ierror == -1) perror( "sigaction" );
      
      /* Set up so that i/o causes the SIGIO signal */
#ifdef LINUX
      {
	pid_t iPid = getpid();
	ierror = fcntl( socket_c, F_SETOWN, iPid );
	if (ierror == -1) perror( "fcntl1" );
      }

      ierror = fcntl( socket_c, F_SETFL, FASYNC );
      if (ierror == -1) perror( "fcntl2" );
#else
      iflag = getpid();
      ierror = ioctl( socket_c, SIOCSPGRP, &iflag );
      if (ierror == -1) perror( "ioctl" );

      iflag = 1;
      ierror = ioctl( socket_c, FIOASYNC, &iflag );
      if (ierror == -1) perror( "ioctl" );
#endif
      /* Set up so that i/o is nonblocking */
      iflag = 1;
      ierror = ioctl( socket_c, FIONBIO, &iflag );
      if (ierror == -1) perror( "ioctl" );
      
      return 0;
    }
  else
    {
      perror( "connect" );
    }
  /* Possible errors */
/*	case ECONNREFUSED:
	case ETIMEDOUT:
	case ENETUNREACH:
	case ENETDOWN:
*/
  /* Close the socket, if there was an error before returning */

  ierror = close( socket_c );
  if (ierror == -1) perror( "close" );

  return -1;

}
/* ===========================================
 * Run a loop sending products to the specified machine 
 */
static void run_tcpip
( void )
{
  char smessage[100], *sfile;
  int ilength;

  printf( "Please enter message: " );
  sfile = fgets( smessage, 80, stdin );
  if (NULL == sfile) return;
  
  /* Trim trailing carriage return from string */
  ilength = strlen(smessage)-1;
  MessageToServer( socket_c, smessage, ilength );
  
  return;

}
/* =======================================
 * Send a reply message to the client.
 */
static void MessageToServer
(int iSocket_a,
 const char *sData_a,
 int iSize_a)
{
  int ierror;
  char sSize[20];
  sprintf( sSize, "%09d", iSize_a );
  ierror = send( iSocket_a, sSize, 9, 0 );
  if (ierror==-1) perror( "send" );

  ierror = send( iSocket_a, sData_a, iSize_a, 0 );
  if (ierror==-1) perror( "send" );
  return;
}

/* ================================================================
 * Signal handler for SIGIO signal.  It just does a read, and processes
 * the result.
 */
static void upi_xmt_sigio_handler( int signal_a )
{
  char data[BUFFER_SIZE];
  int isize;

 LOOP:
  isize = recv( socket_c, data, BUFFER_SIZE-1, 0 );
  if (isize > 0)
    {
      /* We got some valid data here.  Add terminating NULL, then process */
      data[isize] = 0;
      printf( "Reply: '%s'\n", data );
      goto LOOP;
    }
  else if (isize < 0)
    {
      /* We an error here, signal all errors except EWOULDBLOCK */
      if (errno != EWOULDBLOCK)
	{
	  perror( "recv" );
	  exit(EXIT_FAILURE);
	}
      else
	{
	  printf( "recv would block\n" );

	}
    }

  else
    {
      /* Zero size indicates that the socket has been closed at the other end */
      printf( "Link broken\n" );
      exit(EXIT_SUCCESS);
    }
  return;

}

