/*===========================================================================
  Copyright (C) 1995-2005 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        Module
.NAME        atestosx.c
.LANGUAGE    C
.AUTHOR      Carlos Guirao. IPG-ESO Garching
.CATEGORY    Tests of host operating system interfaces. 
.COMMENTS    Automatic osx test. 
	     This test exercises the functions of the module "osx".
	
.REMARKS     A hanged condition has been detected for this test. It happens
	     when a procces is waiting for data to come from a socket, and
	     the connection is already stablished with a sender. If the
	     sender, for any reason, denies the data, the procces will hang
	     forever (or CTRL-C). SIGALRM does not work for this porpose
	     because the system call "read" ignores it when there is a 
	     stablished connection.
.ENVIRONment UNIX

.VERSION 1.1 05-Jul-1990   Implementation     C. Guirao
051021		last modif

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

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <osparms.h>

#ifndef S_IFSOCK		/* defined in stat.h if Unix domain sockets */
  static char socket_name[] = "00"; 	/* for PC/SCO without local sockets */
# define OSX_OPEN_MODE NETW
#else
  static char socket_name[] = "/tmp/mtape";
# define OSX_OPEN_MODE LOCAL
#endif

#define LOWER 0
#define UPPER 1

#define PATTERNA '0'
#define PATTERNB 'a'
#define PATTERNC 'B'
#define PATTERND 'b'

char *osmsg();

#define PERROR { printf("\tERROR: %s\n",osmsg()); ospexit(1); }
#define PRINTF(string) { fflush(stdout); printf(string); fflush(stdout); sleep(1); }

#define SIZEBUF 1024
char *buf;
int sizebuf;

void timeout(k)
int  k;
{
	printf("(TIMEOUT)\n");
	exit(-1);
}

static int readn(fd, ptr, nbytes) 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read "n" bytest from a descriptor. Use in place of 
	 read() when fd is a stream socket
.RETURNS If succesful, the number of bytes actaully read is 
	 returned. Otherwise, a -1 is returned.
.REMARKS System dependencies:
 -- UNIX: read(2)
------------------------------------------------------------*/
register int fd;
register char *ptr;
register int nbytes;
{
	int nleft, nread;
	int st;
	
	nleft = nbytes;
	while (nleft > 0) {
		/*
		if ( (st = osxinfo(fd,0,0)) == -1) PERROR
        	if (st == NODATA) break;
		*/
		nread = osxread(fd, ptr, nleft);
		if (nread < 0)		/* error, return < 0 */
			return(nread);
		
		nleft -= nread;
		ptr += nread;
	}
	return(nbytes - nleft);		/* return >= 0 */
}


main(argc,argv)
int argc;
int **argv;
{

	char input[80], name[80], *pname;
	int fdn, fd;
	int nbytes;
	static char *channame[2];
	static struct stat statbuf;
	int childpid;
	int st;

	channame[1]="localhost";
	signal(SIGALRM,timeout);

	printf("**********************************************\n");
	printf("****** AUTOMATIC TEST FOR OSX INTERFACE ******\n");
	printf("****** LOCAL MODE. USING SOCKETS.       ******\n");
	printf("**********************************************\n\n");

	printf("Deleting socket files: %s if existing... ", 
		socket_name);
	if (stat(socket_name,&statbuf) == 0 )
		if (unlink(socket_name) < 0)  PERROR
	PRINTF("OK\n");

	sizebuf=SIZEBUF;
	printf("Allocating memory for buffers...");
	if ( (buf = (char *)malloc((size_t)(sizebuf+1))) == (char *)0)  PERROR
	else 	printf("OK\n");

	/* First step: open & close mode*/
	printf("\n************** Testing open & close\n");

	printf("Opening a normal file.... ");
	if ( (fdn = open(socket_name,O_CREAT,S_IREAD|S_IWRITE)) < 0) PERROR
	else	PRINTF("OK\n");

	printf("Opening a socket in READ mode, over a normal file.... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,LOCAL|IPC_READ)) != -1) {
		printf("ERROR: Return code != -1\n");
		osxclose(fd);
		ospexit(1);
		}
	else	PRINTF("OK\n");

	printf("Opening a socket in WRITE mode, over a normal file.... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,LOCAL|IPC_WRITE)) != -1) {
		printf("ERROR: Return code != -1\n");
		osxclose(fd);
		ospexit(1);
		}
	else	PRINTF("OK\n");

	printf("Closing and unlinking the normal file.... ");
	if ( close(fdn) < 0) PERROR 
	if (unlink(socket_name) < 0) PERROR
	PRINTF("OK\n");

	printf("\nOpening a socket in READ mode.... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_READ)) == -1) PERROR
	else	PRINTF("OK\n");

	printf("Reading status from socket.... ");
	if ( (st = osxinfo(fd,0,0)) == -1) PERROR
        if (st == NOCONN) { PRINTF("OK\n"); }
	else printf("ERROR: Return code != %d\n",NOCONN);

	printf("Closing the socket in READ mode.... ");
	if ( osxclose(fd) == -1) PERROR
	else	PRINTF("OK\n");

	printf("\nTrying to open a socket in WRITE mode.... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_WRITE)) != -1) {
		printf("ERROR: Return code != -1\n");
		osxclose(fd);
		ospexit(1);
		}
	else	PRINTF("OK\n");

	printf("\nOpening a socket (once).... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_READ)) == -1) PERROR
	else	PRINTF("OK\n");

	/* PC/SCO with NETW socket returns -1 Address already in use 
	printf("Trying to open the same socket mode (twice).... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_READ)) == -1) PERROR
	else	PRINTF("OK\n");
	*/

	printf("Closing the socket (once).... ");
	if ( osxclose(fd) == -1) PERROR
	else	PRINTF("OK\n");

	printf("Trying to close the same socket (twice).... ");
	if ( osxclose(fd) != -1) {
		PRINTF("ERROR: Return code != -1\n");
		ospexit(1);
		}
	else	PRINTF("OK\n");

	printf("\nOpening a socket in READ mode.... ");
	channame[0]=socket_name;
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_READ)) == -1) PERROR
	else	PRINTF("OK\n");

	printf("Trying to read something... ");
	fflush(stdout);
	alarm(5);
	if ( osxread(fd,buf,1) != -1) {
		PRINTF("ERROR: Return code != -1\n");
		ospexit(1);
		}
	else	PRINTF("OK\n");
	alarm(0);

	printf("Trying to write something... ");
	if ( osxwrite(fd,buf,1) != -1) {
		PRINTF("ERROR: Return code != -1n");
		ospexit(1);
		}
	else	PRINTF("OK\n");

	printf("Closing the socket in READ mode.... ");
	if ( osxclose(fd) == -1) PERROR
	else	PRINTF("OK\n");
	
	printf("\nDoing a fork for server & client \n");
	
	if ( (childpid = fork()) < 0) PERROR
	else if (childpid == 0) {
		child_task();
		ospexit(0);
		}

	father_task();
	printf("**********************************************\n");
	printf("****** END OF AUTOMATIC TEST FOR OSX    ******\n");
	printf("****** LOCAL MODE. USING SOCKETS.       ******\n");
	printf("**********************************************\n\n");
}

father_task()
{
	int fd;
	int nbytes;
	char *channame[2];

	/* This is the father procces */
	printf("I am the father.\n");
	channame[0]=socket_name;
	channame[1]="localhost";

	printf("\n************** Using client ---> server transfer\n");
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_READ)) == -1) {
		printf("Open socket in read mode... FAILED.\n");
		PERROR
		}
	else	printf("Open socket in read mode... OK\n");

	PRINTF("Waiting connection from client\n");
	alarm(10);
	while( osxinfo(fd,0,0) == NOCONN ) ;
	PRINTF("Connection from client... OK\n");
	alarm(0);

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNA,LOWER)) != SIZEBUF) {
		PRINTF("Reading pattern A in socket... FAILED.\n");
		if (nbytes != -1) 
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern A in socket... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNB,LOWER)) != SIZEBUF) {
		PRINTF("Reading pattern B in socket... FAILED.\n");
		if (nbytes != -1) 
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern B in socket... OK\n");

	if ( (nbytes=testread(fd,buf,SIZEBUF/2,PATTERNC,LOWER)) != SIZEBUF/2) {
		PRINTF("Reading (1/2) pattern C in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern C (1/2) in socket... OK\n");

	if ( (nbytes=testread(fd,buf,SIZEBUF/2,PATTERNC,LOWER)) != SIZEBUF/2) {
		PRINTF("Reading (2/2) pattern C in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern C (2/2) in socket... OK\n");

	if ((nbytes=testwrite(fd,buf,SIZEBUF,PATTERNA,LOWER)) != SIZEBUF) {
		printf("Writting pattern A in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern A in socket... OK\n");

        alarm(10);
        if ( (nbytes = osxread(fd,buf,SIZEBUF)) != 0) {
                PRINTF("Reading EOF in socket... FAILED.\n");
                if (nbytes != -1)
                        printf("%d bytes read !!!\n",nbytes);
                else    PERROR
                ospexit(1);
                }
        else    PRINTF("Reading EOF in socket... OK\n");
        alarm(0);

	printf("\n************** Using server ---> client transfer\n");

	PRINTF("Waiting connection from client\n");
	alarm(10);
	while( osxinfo(fd,0,0) == NOCONN ) ;
	PRINTF("Connection from client... OK\n");
	alarm(0);

	if ((nbytes=testwrite(fd,buf,SIZEBUF/2,PATTERNA,LOWER)) != SIZEBUF/2) {
		printf("Writting pattern A (1/2) in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern A (1/2) in socket... OK\n");

	if ((nbytes=testwrite(fd,buf,SIZEBUF/2,PATTERNA,LOWER)) != SIZEBUF/2) {
		printf("Writting pattern A (2/2) in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern A (2/2) in socket... OK\n");

	if ((nbytes=testwrite(fd,buf,SIZEBUF,PATTERNB,LOWER)) != SIZEBUF) {
		printf("Writting pattern B in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern B in socket... OK\n");

	if ((nbytes=testwrite(fd,buf,SIZEBUF,PATTERNC,LOWER)) != SIZEBUF) {
		printf("Writting pattern C in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern C in socket... OK\n");

        alarm(10);
        if ( (nbytes = osxread(fd,buf,SIZEBUF)) != 0) {
                PRINTF("Reading EOF in socket... FAILED.\n");
                if (nbytes != -1)
                        printf("%d bytes read !!!\n",nbytes);
                else    PERROR
                ospexit(1);
                }
        else    PRINTF("Reading EOF in socket... OK\n");
        alarm(0);

	printf("\n************** Using server <--> client transfer\n");
	
	PRINTF("Waiting connection from client\n");
	alarm(10);
	while (osxinfo(fd,0,0) == NOCONN) ;
	PRINTF("Connection from client... OK\n");
        alarm(0);

	if ((nbytes=testwrite(fd,buf,SIZEBUF,PATTERNB,UPPER)) != SIZEBUF) {
		printf("Writting pattern B in socket... FAILED.\n");
		if (nbytes != -1) 
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern B in socket... OK\n");

	if ( (nbytes=testread(fd,buf,SIZEBUF,PATTERNC,LOWER)) != SIZEBUF) {
		PRINTF("Reading pattern C in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern C in socket... OK\n");

	if ( (nbytes=testread(fd,buf,SIZEBUF,PATTERNA,LOWER)) != SIZEBUF) {
		PRINTF("Reading pattern A in socket... FAILED.\n");
		if (nbytes != -1)
			printf("\tError: Only %d bytes read !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("Reading pattern A in socket... OK\n");

	if ((nbytes=testwrite(fd,buf,SIZEBUF,PATTERNC,UPPER)) != SIZEBUF) {
		printf("Writting pattern C in socket... FAILED.\n");
		if (nbytes != -1) 
			printf("\tError: only %d bytes written!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("Writting pattern C in socket... OK\n");

        alarm(10);
        if ( (nbytes = osxread(fd,buf,SIZEBUF)) != 0) {
                PRINTF("Reading EOF in socket... FAILED.\n");
                if (nbytes != -1)
                        printf("%d bytes read !!!\n",nbytes);
                else    PERROR
                ospexit(1);
                }
        else    PRINTF("Reading EOF in socket... OK\n");
        alarm(0);

	if ( osxclose(fd) == -1) {
		printf("Closing socket write mode... FAILED.\n");
		PERROR
		}
	printf("Closing socket write mode... OK\n\n");
	sleep(2);

	/* Wait for child to finish */
	printf("****** Waiting for child proccess to die\n");
	wait(0);
	printf("****** End of father proccess\n");
}

child_task()
{
	int fd;
	int nbytes;
	char *channame[2];

	printf("I AM THE CHILD.\n");
	channame[0]=socket_name;
	channame[1]="localhost";

	alarm(10);
	while ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_WRITE)) == -1) ;
	alarm(0);
	printf("OPEN SOCKET IN WRITE MODE... OK\n");

	if ( (nbytes = testwrite(fd,buf,SIZEBUF,PATTERNA,UPPER)) != SIZEBUF) {
		printf("WRITING PATTERN A IN SOCKET... FAILED.\n");
		if (nbytes != -1)
			printf("\tERROR: ONLY %d BYTES WRITTEN!!!\n",nbytes);
		ospexit(1);
	}
	else	printf("WRITING PATTERN A IN SOCKET... OK\n");
	
	if ( (nbytes = testwrite(fd,buf,SIZEBUF,PATTERNB,UPPER)) != SIZEBUF) {
		printf("WRITING PATTERN B IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES WRITTEN!!!\n",nbytes);
		ospexit(1);
	}
	else	printf("WRITING PATTERN B IN SOCKET... OK\n");

	if ( (nbytes = testwrite(fd,buf,SIZEBUF,PATTERNC,UPPER)) != SIZEBUF) {
		printf("WRITING PATTERN C IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES WRITTEN!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("WRITING PATTERN C IN SOCKET... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNA,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN A IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN A IN SOCKET... OK\n");

	if ( osxclose(fd) == -1) {
		printf("CLOSING THE SOCKET WRITE MODE ... FAILED.\n");
		PERROR
		}
	printf("CLOSING THE SOCKET WRITE MODE... OK\n");

	alarm(10);
	while ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_WRITE)) == -1) ;
	printf("OPEN SOCKET IN WRITE MODE... OK\n");
	alarm(0);

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNA,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN A IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN A IN SOCKET... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNB,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN B IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN B IN SOCKET... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNC,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN C IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN C IN SOCKET... OK\n");

	if ( osxclose(fd) == -1) {
		printf("CLOSING THE SOCKET WRITE MODE ... FAILED.\n");
		PERROR
		}
	printf("CLOSING THE SOCKET WRITE MODE... OK\n");

	/*
	alarm(10);
	PRINTF("WAITING DISCONNECTION FROM SERVER... ");
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_WRITE)) == -1) PERROR
	while( osxread(fd,buf,1) != -1 ) ;
	PRINTF("OK\n");
	alarm(0);
	*/

	sleep(2);
	if ( (fd = osxopen(channame,OSX_OPEN_MODE|IPC_WRITE)) == -1) {
		printf("OPEN SOCKET IN WRITE MODE...  FAILED.\n");
		PERROR
		}
	else	printf("OPEN SOCKET 0 IN WRITE MODE... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNB,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN B IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN B IN SOCKET... OK\n");


	if ( (nbytes = testwrite(fd,buf,SIZEBUF,PATTERNC,UPPER)) != SIZEBUF) {
		printf("WRITING PATTERN C IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES WRITTEN!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("WRITING PATTERN C IN SOCKET... OK\n");

	if ( (nbytes = testwrite(fd,buf,SIZEBUF,PATTERNA,UPPER)) != SIZEBUF) {
		printf("WRITING PATTERN A IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES WRITTEN!!!\n",nbytes);
		ospexit(1);
		}
	else	printf("WRITING PATTERN A IN SOCKET... OK\n");

	if ( (nbytes = testread(fd,buf,SIZEBUF,PATTERNC,UPPER)) != SIZEBUF) {
		PRINTF("READING PATTERN C IN SOCKET... FAILED.\n");
		if (nbytes != -1) 
			printf("\tERROR: ONLY %d BYTES READ !!!\n",nbytes);
		ospexit(1);
		}
	else	PRINTF("READING PATTERN C IN SOCKET... OK\n");

	if ( osxclose(fd) == -1) {
		printf("CLOSING THE SOCKET WRITE MODE ... FAILED.\n");
		PERROR
		}
	printf("CLOSING THE SOCKET WRITE MODE... OK\n");

	sleep(2);
	printf("****** END OF CHILD PROCCESS\n");
}


testread(fd,buffer,size,pattern,type)
int fd;
char *buffer;
int size;
char pattern;
int type;
{
	int i, j, nbytes;
	for(i=0; i<size; i++) buffer[i] = 0;

	if ( (nbytes = readn(fd,buffer,size)) < 0) {	
		if (type == UPPER)
			printf("\tERROR READING A BUFFER: %s\n",osmsg());
		else 	printf("\tError reading a buffer: %s\n",osmsg());
		return(-1);
		}
	else	{
		for(i=0; i<nbytes; i++) {
		if ( buf[i] != pattern ) {
			if (type == UPPER)
				printf("\tPATTERN MISTMATCH: READ[%d]='%c'; EXPECTED '%c'\n", i, buf[i], pattern);
			else
				printf("\tPattern mistmatch: read[%d]='%c'; expected '%c'\n", i, buf[i], pattern);
			return(-1);
			}
		}
	}
	return(nbytes);
}

testwrite(fd,buffer,size,pattern,type)
int fd;
char *buffer;
int size;
char pattern;
int type;
{
	int i, j, nbytes;
	for(i=0; i<size; i++) buffer[i] = pattern;

	if ( (nbytes = osxwrite(fd,buffer,size)) != size) {	
		if (type == UPPER)
			printf("\tERROR WRITING A BUFFER: %s\n",osmsg());
		else 	printf("\tError writing a buffer: %s\n",osmsg());
		return(-1);
		}
	return(nbytes);
}
