* Program Name:  multecho.c
 * This program implements an echo server that can handle several clients
 * simultaneously by multiplexing requests on a single exchange and using
 * nonblocking accept and recv.
 * Run only on CTOS.
 *

*  HISTORY OF CHANGES *
*  UCF 17648039: Socket example used to not compile under BTOS C. *

	 
include <systypes.h>
include syssocket.h
include netinetin.h
include netdb.h
	
define send ssend

define ECHOPORT    3000	 
define RECBUFFSZ   2000	 

if defined(__BTOSC__)
int AllocExch plm far (int *);
int Wait plm far (int , char **);
int Request plm far (char *);
elif defined( __CTOS__)
define AllocExch @
define Wait @
define Request @
include <ctos.lib.h>
else
error Unknown C compiler
endif

extern unsigned int errno;  * global error code returned from system calls *
int Erc;  


main ()
{
int S;                  * file descriptor returned by socket call      *
int N;                  * variable used as a return value of calls     *
int Ns;                 * accepted socket file descriptor              *
int Na;
int numbytes;
char Buf[RECBUFFSZ];    * data recvd is stored here                  *
struct sockaddr_in Server, Client; * local and remote host addresses   *
int ClientAddrLen;      * Client Address Length                        *
char **exchptr;
char **pReqPtr;
int unb_sk;             * unblocked socket *
int st;                 * state returned by getsockstate *
int n;
int Exch;

ifdef DEBUG
	printf(server initializing...\n);
endif

	Erc=AllocExch(Exch);

	CheckZ(Erc,AllocExch);

ifdef DEBUG
	printf(exch is d\n,Exch);
endif

	S = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	CheckP (S , socket);
	
	n=setctostcpexchange (S, Exch, (char ***)pReqPtr);
	CheckP (n, setctostcpexchange for well known socket);

	Server.sin_family = AF_INET;            * assign server attributes *
	Server.sin_port =  htons(ECHOPORT);
	Server.sin_addr.s_addr = htonl(INADDR_ANY);
	N = bind (S, Server, sizeof (Server));
	CheckP (N , bind );
	
	N = listen (S, 1);
	CheckP (N , listen);
	 
	Client.sin_family = AF_INET;            * assign domain            *
	Client.sin_addr.s_addr = htonl(INADDR_ANY);    * accept any valid address *
	Client.sin_port = htons(0);                    * accept any valid port    *
	ClientAddrLen = sizeof (Client);
	 
	printf(Server ready... \n);
	printf(\n\tThis server reports:\n);
	printf(\tA: Connection Accepted\n);
	printf(\tR: Data Received\n);
	printf(\tT: Data Echoed\n);
	printf(\tT: Connection Closed\n\n);
    Ns = accept (S, Client, ClientAddrLen);  
	if (errno==EWOULDBLOCK){
		Ns=0;
ifdef DEBUG
		printf(Accept would block\n);
endif
	}
    CheckP (Ns, accept);

	for (;;) {

ifdef DEBUG
		printf(Waiting in Exch d\n,Exch);
endif
		Erc=Wait(Exch,pReqPtr);
		CheckZ(Erc,Main Loop: Waiting in the exchange);

		unb_sk = whatsocket(*pReqPtr);
		CheckP(unb_sk,whatsocket);

ifdef DEBUG
		printf (unblocked socket = d\n,unb_sk);
endif

		st = getsockstate(unb_sk);		

ifdef DEBUG
		printf (state from getsockstate = x\n,st);
endif 
		switch(st0xff){
		
			case TCPLISTEN:
			
		    Ns = accept (unb_sk, Client, ClientAddrLen); 
		    CheckP (Ns, accepting in main loop);
			printf (A);				

			n = setctostcpexchange (Ns, Exch, (char ***)exchptr);
			CheckP (n, setctostcpexchange for a new socket);

			Na = accept (S, Client, ClientAddrLen);  
			if (errno==EWOULDBLOCK){
			Na=0;
ifdef DEBUG
			printf(Accept would block\n);
endif
			}
			CheckP (Na, Posting accept in main loop);
			
			n = recv(Ns, Buf, sizeof(Buf), MSG_NOBLOCK | MSG_POSTREQ);
			if (errno==EWOULDBLOCK) n=0;
			CheckP (n, Posting recv for a new socket);
			break;


			

		case TCPCONNECT:

			n = recv(unb_sk, Buf, sizeof(Buf), MSG_TCPREQ);
			if (n<1 ){
				sclose(unb_sk);
				printf(C);
				break;
			}
			numbytes=n;	
			CheckP (n, recv);
			printf (R);

			n = recv(unb_sk, Buf, sizeof(Buf), MSG_NOBLOCK | MSG_POSTREQ);
			if (errno==EWOULDBLOCK) n=0;
			CheckP (n, Posting recv);

	        n= send(unb_sk, Buf, numbytes, 0);
			printf(T);
ifdef DEBUG
			printf(Sending data back to the client: socket d\n,unb_sk);
endif
			CheckP (n, Send);

			break;

		DEFAULT:
 			printf (No way you will make it here\n);

	    }
	} 
}

CheckP (n, msg)
**************
 * check n positive else display msg  quit
 *
int n;
char *msg;
{
	if (n<0){
		printf ( Program terminated: error u in s\n, errno, msg);
		exit (1);
	} else {
ifdef DEBUG
		printf (Trace OK: s\n, msg);
endif
	}
} 


CheckZ (int n, char *msg)
*****************************
 * check n zero else display msg
 *
{
	if (n){
		printf( Program terminated: CTOS erc u in s\n, n, msg);
		exit(1);
	}
}

