/*====================================================================

	tcp.c    included in tlayer.c if used with -DTCP
			if used with Windows 95/NT, use flag -DWINDOWS

			Version: 1.0    July 12, 1996
			Version: 1.1	June 30, 1997
	Author:  Knut Odman, Telelogic.
		 		knut.odman@telelogic.com
			

======================================================================*/


SOCKET tcpsocket[3];  /* SERVER_LISTEN, HOST, TARGET */
static fd_set active_fd_set, read_fd_set;
static struct timeval timeOut;
typedef unsigned short int PORT;


int tcpsend(int ret, int event, char *data, 
		int size, int fromPid, int toPid)
{
	int timeStamp = 0,mlen;
	char localbuf[DEFAULTBUFSIZE],*bufp = localbuf;
	memset(localbuf,0,DEFAULTBUFSIZE);
	sprintf(bufp,"%5d %5d %5d %5d %5d %5d ",
		ret,event,size,fromPid,toPid,timeStamp);  /* 36 characters */
	localbuf[36]='\0';
	mlen =36;
	if(data !=NULL && size>1){
		strcat(bufp,DELIMIT);
		strcat(bufp,data);
		mlen += strlen(DELIMIT) + strlen(data);
	}
	strcpy(globuf,localbuf);
	comerror = xOutSocket(globuf,xSOCK,mlen);
	return(comerror?SPERROR:SPOK);
}
	

int tcpread(int *reP,int *evP, int *siP, int *frP, int *toP, int *stP, 
			int timeout)
{
	char *bufp, *readbuf;
	static int re,ev,si,fr,to,st;   
	readbuf = databuf;
	comerror=xInSocket(timeout,xSOCK);
	if(comerror) return SPERROR;
	sscanf(GlobalBuffer,"%d %d %d %d %d %d %s",
						&re,&ev,&si,&fr,&to,&st,readbuf);

	if(si>0 &&readbuf!=NULL)
		if((bufp = (char*)strstr(GlobalBuffer,DELIMIT))!=NULL){
			bufp+=strlen(DELIMIT);
			if(bufp!=NULL)strcpy(readbuf,bufp);
		}
	*reP = re; *evP = ev; *siP = si; *frP = fr; *toP = to; *stP = st;
	return SPOK; 
}                       


/****+***************************************************************
   TCP socket functions
********************************************************************/

/* below functions have predefined macros in tlayer.h */

/*---+---------------------------------------------------------------
     make_socket (local)
-------------------------------------------------------------------*/
#ifdef TARGET
SOCKET make_socket (PORT port)
#else
SOCKET make_socket (void)
#endif
{
	SOCKET sock;
	sock = socket (PROTOCOL, SOCK_STREAM, 0);
#ifdef TARGET
	{
   	struct sockaddr_in name;
		int ret;
		int on = 1;
		name.sin_family = PROTOCOL;
		name.sin_addr.s_addr = htonl (INADDR_ANY);
		name.sin_port = htons (port);
		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,(char*) &on, sizeof(on));
		ret = bind (sock, (LPSOCKADDR) &name, sizeof (name));
		BIND_ERROR_TEST
	}
#endif /*TARGET*/
	return sock;
}

/*---+---------------------------------------------------------------
     xInitSocket
-------------------------------------------------------------------*/

int xInitSocket(void)
{
	int ret;
#ifdef WINDOWS
	WSADATA wsaData;
#endif
	struct sockaddr_in peer;
	int peerlen = sizeof(peer);
#ifdef TARGET
	SOCKET make_socket(PORT port);
#else
	SOCKET make_socket(void);
#endif
	int init_sockaddr(struct sockaddr_in *name,
		char *hostname, PORT port);

#ifdef TARGET
STARTUP_TARGET
	tcpsocket[0]=make_socket((PORT) TARGETPORT);
	if(tcpsocket[0]==INVALID_SOCKET )return CE_SOCKETERROR;
	FD_ZERO (&active_fd_set);
	FD_SET (tcpsocket[0], &active_fd_set);
	timeOut.tv_sec=5*60;
	timeOut.tv_usec=0;
LISTEN
SELECT_SERVER
ACCEPT(xSOCK)

#else /* HOST */
	
STARTUP_HOST
	if((tcpsocket[1]=make_socket() )==INVALID_SOCKET)
      	return CE_SOCKETERROR;
	FD_ZERO (&active_fd_set);
	FD_SET (tcpsocket[1], &active_fd_set);
      if(!init_sockaddr(&peer,TARGETIPNR,(PORT)TARGETPORT)){
         	return CE_UNKNOWNHOST; /* FATAL */
      }
SIGNAL_DISPATCH
	ret = connect(tcpsocket[1],(struct sockaddr *)&peer,peerlen);
	if(ret!=0){
		WAIT(1000)
		ret = connect(tcpsocket[1],(struct sockaddr *)&peer,peerlen);
	}
CONNECT_ERROR_TEST /* if error returns CE_CONNECTREFUSED */

#endif /*HOST || TARGET*/
	return CE_OK;
}


/*---+---------------------------------------------------------------
     xCloseSocket
-------------------------------------------------------------------*/

void xCloseSocket(void)

{       /* macro CLOSE is close on Unix and closesocket on NT*/
#ifdef TARGET
	shutdown(tcpsocket[0],2);
	CLOSE(tcpsocket[0]);
#endif
	shutdown(tcpsocket[xSOCK],2);
	CLOSE(tcpsocket[xSOCK]);
	PRE_EXIT
}

#ifndef TARGET

/*---+---------------------------------------------------------------
     init_sockaddr (local)
-------------------------------------------------------------------*/

int init_sockaddr (struct sockaddr_in *name, char *hostname,PORT port)
{
       /* macro LPHOSTENT is NT predefined struct hostent*  */
	LPHOSTENT  hostinfo; 
	name->sin_family = PROTOCOL;
	name->sin_port = htons (port);
      if(FORCEIP == FALSE){
	  hostinfo = convertIP (hostname);  /*defined in parser.c */
	  if (hostinfo == NULL) return 0;
	  name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
      }else{
       {
        unsigned long ip_bin = 0;
        unsigned int ip_part[4];
        char ipbuf[20];
	  strcpy(ipbuf,hostname);
	  sscanf(ipbuf,"%u.%u.%u.%u",&ip_part[0],&ip_part[1],&ip_part[2],&ip_part[3]);
	  ip_bin += (unsigned long)ip_part[0] << 24;
	  ip_bin += (unsigned long)ip_part[1] << 16;
	  ip_bin += (unsigned long)ip_part[2] <<  8;
	  ip_bin += (unsigned long)ip_part[3];
	  ip_bin = htonl(ip_bin);
        name->sin_addr.s_addr = ip_bin;
       }
      }/*if FORCEIP*/
	return 1;
}
#endif /*!TARGET*/
	

/*-------------------------------------------------------------------
	xOutSocket
--------------------------------------------------------------------*/
int xOutSocket(char *buffer, int sock, int mlen)
{

	char localbuf[DEFAULTBUFSIZE],*bufp = localbuf;
	char lenheader[5];
	int nbytes, bytesleft;
	memset(localbuf,0,DEFAULTBUFSIZE);
	if(buffer!=NULL){
SIGNAL_DISPATCH
		strcpy(localbuf,buffer);
		localbuf[strlen(buffer)]='\0';
		sprintf(lenheader,"%4d",mlen);
		lenheader[4]='\0';
SEND_HEADER
		bytesleft = mlen;
SEND_MESSAGE /* returns SPOK or CE_WRITEERROR */
	}
	return SPERROR;
}

/*---+---------------------------------------------------------------
     xInSocket
-------------------------------------------------------------------*/

int xInSocket( int wTime, int sock )
{
	static int ret;
	char b[DEFAULTBUFSIZE],lenheader[5];
	struct timeval *tp = &timeOut;
	int nbytes, bytesleft, bytesread = 0;
	char *buffer = (char*) b;
	memset(b,0,DEFAULTBUFSIZE);
	memset(lenheader,0,5);
	read_fd_set = active_fd_set;
	if(wTime>0){
		timeOut.tv_sec = wTime/1000;
		timeOut.tv_usec = (wTime%1000)*1000;
	}
	else if(wTime==0){
		timeOut.tv_sec = 0;
		timeOut.tv_usec = 5000;
	}
	else tp = NULL;

SELECT_READ  /* if fail/timeout returns CE_READERROR */
     if(ret){
READ_HEADER
		if(lenheader == NULL || nbytes != 4)return CE_READERROR;
		bytesleft = atoi((char*)lenheader);
READ_MESSAGE
		if(b != NULL && bytesread > 0){
			strcpy(GlobalBuffer,b);
			return CE_OK;
		}
		else return CE_READERROR;
	}
return CE_TIMEOUT;
}
