#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/stropts.h>
#include <errno.h>
#include <tiuser.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <sys/stream.h>
#include <sys/sockmod.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>

#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <malloc.h>

extern "C" {
	int _socket(int family, int type, int protocol);
	int _connect(int s, struct sockaddr * name, int namelen);
	int _socketpair(int domain, int type, int protocol, int sv[2]);
	int _listen(int s, int backlog);
	int _shutdown(int s, int how);
	int _getsockopt(int s, int level, int optname, 
			char *optval, int *optlen);
	int _setsockopt(int s, int level, int optname, 
			const char *optval, int optlen);

	int _send(int s, const char *msg, int len, int flags);
	int _sendto(int s, const char *msg, int len, int flags, 
			const struct sockaddr *to, int tolen);
	int _sendmsg(int s, const struct msghdr *msg, int flags);
	int _bind(int s, struct sockaddr *name, int namelen);
	int _accept(int s, struct sockaddr *addr, int *addrlen);
	int _getpeername(int s, struct sockaddr *name, int *namelen);
	int _getsockname(int s, struct sockaddr *name, int *namelen);
	int _recv(int s, char *buf, int len, int flags);
	int _recvfrom(int s, char *buf, int len, int flags, 
			struct sockaddr *from, int *fromlen);
	int _recvmsg(int s, struct msghdr *msg, int flags);
	int _close(int fildes);
	int _fclose(FILE *stream);
	int _select(int nfds, fd_set *readfds, fd_set *writefds, 
		fd_set *exceptfds, struct timeval *timeout);
	ssize_t _read(int fildes, void *buf, size_t nbyte);
	ssize_t _write(int fildes, const void *buf, size_t nbyte);
};

// Utility Functions

#define ADDRESS   1
#define SOCKET    2
#define PROTOCOL  3
#define OPT_LEVEL 4
#define OPT_NAME  5

#define MAX_SOCKETS  1024
#define ST_PORT_NO   8888

#define JUST_CREATED 1
#define CONNECTED    2
#define CACHED       3



#ifndef	INADDR_NONE
#define	INADDR_NONE	0xffffffff
#endif	/* INADDR_NONE */

#define	OKAY	0
#define	ERROR	1
#define	TCP	1
#define	UDP	2

#define UC(c)	(((int)c)&0xff)
static int init=0;
struct route_tbl {
	struct sockaddr_in from;	/* address of sender */
	struct sockaddr_in to;		/* address of local destination site */
	struct sockaddr_in hop;		/* emulated site */
	int 	protocol;		/* protocol : UDP/TCP */
	int	s;			/* socket address to to */
	int	s1;			/* socket address to hop  */
};


static struct route_tbl rtbl[64];
static struct route_tbl *rtbl_ep = rtbl;	/* next empty slot pointer */

int debug=1;
int debug1=0;
FILE *fd;

tvsub(register struct timeval *out, register struct timeval *in)
{
	if ( (out->tv_usec -= in->tv_usec) < 0) {	/* subtract microsec */
		out->tv_sec--;
		out->tv_usec += 1000000;
	}
	out->tv_sec -= in->tv_sec;	/* subtract seconds */
}

char *int2name(int family, int value)
{
 switch(family) {
    case ADDRESS:
       switch(value) {
          case AF_UNSPEC:  return("AF_UNSPEC");
          case AF_UNIX:    return("AF_UNIX");
          case AF_INET:    return("AF_INET");
          case AF_IMPLINK: return("AF_IMPLINK");
          default:         return("AF_UNKNOWN");
       }
       break;
    case SOCKET:
       switch(value) {
          case SOCK_STREAM:    return("SOCK_STREAM");
          case SOCK_DGRAM:     return("SOCK_DGRAM");
          case SOCK_RAW:       return("SOCK_RAW");
          case SOCK_RDM:       return("SOCK_RDM");
          case SOCK_SEQPACKET: return("SOCK_SEQPACKET");
          default:             return("SOCK_UNKNOWN");
       }
       break;
    case PROTOCOL:
       switch(value) {
          case IPPROTO_IP:     return("IPPROTO_IP");
          case IPPROTO_ICMP:   return("IPPROTO_ICMP");
          case IPPROTO_IGMP:   return("IPPROTO_IGMP");
          case IPPROTO_GGP:    return("IPPROTO_GGP");
          case IPPROTO_ENCAP:  return("IPPROTO_ENCAP");
          case IPPROTO_TCP:    return("IPPROTO_TCP");
          case IPPROTO_EGP:    return("IPPROTO_EGP");
          case IPPROTO_PUP:    return("IPPROTO_PUP");
          case IPPROTO_UDP:    return("IPPROTO_UDP");
          case IPPROTO_IDP:    return("IPPROTO_IDP");
          case IPPROTO_HELLO:  return("IPPROTO_HELLO");
          case IPPROTO_ND:     return("IPPROTO_ND");
          case IPPROTO_EON:    return("IPPROTO_EON");
          default:             return("IPPROTO_UNKNOWN");
       }
       break;
 }
 return("INVALID");
}

char *opt_level(int value)
{
 static char ret_str[150];

 switch(value) {
    case IPPROTO_IP:     return("IPPROTO_IP");
    case IPPROTO_TCP:    return("IPPROTO_TCP");
    case SOL_SOCKET:     return("SOL_SOCKET");
    default:
       sprintf(ret_str,"OPT_LEVEL_UNKNOWN(%d)", value);
       return(ret_str);
 }
}

char *opt_name(int level, int name)
{
 static char ret_str[150];

 switch (level) {
    case IPPROTO_IP:
       if (name == IP_OPTIONS)
          return("IP_OPTIONS");
       else {
          sprintf(ret_str,"OPT_NAME_UNKNOWN(%d)",name);
          return(ret_str);
       }
       break;
    case IPPROTO_TCP:
       switch(name) {
          case TCP_MAXSEG:     return("TCP_MAXSEG");
          case TCP_NODELAY:    return("TCP_NODELAY");
          default:             
             sprintf(ret_str,"OPT_NAME_UNKNOWN(%d)",name);
             return(ret_str);
       };
       break;
    case SOL_SOCKET:
       switch(name) {
          case SO_DEBUG:       return("SO_DEBUG");
          case SO_ACCEPTCONN:  return("SO_ACCEPTCONN");
          case SO_REUSEADDR:   return("SO_REUSEADDR");
          case SO_KEEPALIVE:   return("SO_KEEPALIVE");
          case SO_DONTROUTE:   return("SO_DONTROUTE");
          case SO_BROADCAST:   return("SO_BROADCAST");
          case SO_USELOOPBACK: return("SO_USELOOPBACK");
          case SO_LINGER:      return("SO_LINGER");
          case SO_OOBINLINE:   return("SO_OOBINLINE");
          case SO_DONTLINGER:  return("SO_DONTLINGER");
          case SO_SNDBUF:      return("SO_SNDBUF");
          case SO_RCVBUF:      return("SO_RCVBUF");
          case SO_SNDLOWAT:    return("SO_SNDLOWAT");
          case SO_RCVLOWAT:    return("SO_RCVLOWAT");
          case SO_SNDTIMEO:    return("SO_SNDTIMEO");
          case SO_RCVTIMEO:    return("SO_RCVTIMEO");
          case SO_ERROR:       return("SO_ERROR");
          case SO_TYPE:        return("SO_TYPE");
          case SO_PROTOTYPE:   return("SO_PROTOTYPE");
          default:             
             sprintf(ret_str,"OPT_NAME_UNKNOWN(%d)",name);
             return(ret_str);
       }
       break; }
 return("OPT_NAME_UNKNOWN");
}

char *get_address(struct sockaddr *name, int a_len)
{
 static char ret_str[150];

 if (name->sa_family == AF_INET) {
    struct sockaddr_in *iaddr = (struct sockaddr_in *)name; 
    sprintf(ret_str, "%s:%u", inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port));
    return(ret_str);
 }
 else
 if (name->sa_family == AF_UNIX) {
    strncpy(ret_str, ((sockaddr_un *)name)->sun_path,a_len-2);
    ret_str[a_len-2] = 0;
    return(ret_str);
 }
 else
    return("AF_UNKNOWN");
}


void get_ipaddr(char *host)
{

	struct hostent	*phe;	/* pointer to host information entry	*/
	struct sockaddr_in sin;	/* an Internet endpoint address		*/
	int	s, type;	/* socket descriptor and socket type	*/

	if(debug)
       		fprintf(stderr,"get_ipaddr()	:	Entered\n");

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;

	if ( phe = gethostbyname(host) )
		memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
	else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
		fprintf(stderr, "get_ipaddr()	:	can't get \"%s\" host entry\n", host);


	if(debug)
		fprintf(stderr,"get_ipaddr()	:	IPADDR %s\n",get_address((struct sockaddr *)&sin, phe->h_length));
}

static int strtoinaddr( char *str,struct in_addr *inaddr)
{
    struct hostent *hp;
    extern int h_errno;

    inaddr->s_addr = inet_addr(str);
    if (inaddr->s_addr != -1)
	return (OKAY);

    /* then try host addr */
    hp = gethostbyname(str);
    if (hp) {
	bcopy(hp->h_addr, (caddr_t)&inaddr->s_addr, hp->h_length);
	return (OKAY);
    }

    switch(h_errno){
      case HOST_NOT_FOUND:
	(void) fprintf(stderr, "Unknown host name: %s\n", str);
	break;
      case TRY_AGAIN:
	(void) fprintf(stderr, "No nameserver response.  Try again later.\n");
	break;
      case NO_RECOVERY:
	(void) fprintf(stderr, "Non-recoverable error\n");
	break;
      case NO_ADDRESS:
	(void) fprintf(stderr, "Valid name, but no IP address for %s\n", str);
	break;
    }
    return ( ERROR );
}


/*  routine to get the pointer to the route table entry given the destination name */
struct route_tbl *get_rtbl_ent(struct sockaddr *name, int namelen)
{
 struct route_tbl *prtbl;
 prtbl=rtbl;

	struct sockaddr_in *inaddr=(struct sockaddr_in *)name;
	struct sockaddr_in *inaddr1=(struct sockaddr_in *)name;
 for(prtbl = rtbl; prtbl < rtbl_ep; prtbl++)
	{
	if(debug)
		fprintf(stderr,"get_rtbl_ent()	:	to=%ld name=%ld\n", prtbl->to.sin_addr.s_addr, inaddr->sin_addr.s_addr);
	if(prtbl->to.sin_addr.s_addr == inaddr->sin_addr.s_addr)
		{
		if(debug)
			fprintf(stderr, "get_rtbl_ent()	:	Entry found in route table\n");
		return(prtbl);
		}
	}
return(0);
}
	

struct route_tbl *get_sock_ent(int s)
{
 struct route_tbl *prtbl;
 prtbl=rtbl;

 for(prtbl = rtbl; prtbl < rtbl_ep; prtbl++)
	{
	if(prtbl->s == s)
		{
		if(debug) fprintf(stderr,"get_sock_ent()	:	Entry found in table\n");
		return(prtbl);
		}
	}
return(0);
}
	

/*---------------------------------------------------------------------------
 * init_route_tbl -- initialize, set up the route table
 *---------------------------------------------------------------------------
 */
int init_route_tbl()
{
  char *rtfile = (char *)getenv("RAID_ROUTE_TABLE");
  FILE *f;
  char buf[128], from[25], to[25], hopname[32], protocol[4];
  char myname[32];
  int portnum;


    fd = fopen ("timelog", "w");
    if(fd == NULL)
	printf("error in opening timelog file \n");
   else fprintf(stderr,"init_route_tbl()	:	timelog file opened\n");

    if (! rtfile) {
	if(debug)
	    fprintf (stderr, "init_route_rbl()	:	No route table file defined\n");
	return (1);
    }
    f = fopen (rtfile, "r");
    if (! f) {
	if(debug)
	    fprintf (stderr, "init_route_tbl()	:	Unable to open route table file %s: error %d\n",
		rtfile, errno);
	return (1);
    }
    else 
	if(debug)
		fprintf(stderr, "Route Table File read\n");
	

	gethostname(myname, 25);
	if(debug) fprintf(stderr, "init_route_tbl()	:	Hostname  %s\n", myname);

    rtbl_ep = rtbl;
    while (fgets(buf, 128, f)) {
	if (sscanf(buf, "%s%s%s%s", from , to, hopname, protocol) != 4)
		{
		if(debug)
		    fprintf(stderr, "init_route_tbl() 	:	In loop\n");
		    continue;
		}



	if(strcmp(myname, from) != NULL)
		{
		fprintf(stderr, "init_route_tbl()	:	From doesnot match myname\n");
		continue;
		}
        else
		fprintf(stderr, "init_route_tbl()	 :	From matches myname\n");

	if (strtoinaddr (from, &rtbl_ep->from.sin_addr) != OKAY);
	    /* wrong address 
	    continue; */
	if (strtoinaddr (to, &rtbl_ep->to.sin_addr) != OKAY);
	    /* wrong address 
	    continue; */
	if (strtoinaddr (hopname, &rtbl_ep->hop.sin_addr) != OKAY);
	    /* wrong address 
	    continue; */
	if(strcmp(protocol, "TCP")==0)
		rtbl_ep->protocol = TCP;
	if(strcmp(protocol, "UDP")==0)
		rtbl_ep->protocol = UDP;

	rtbl_ep->from.sin_family = AF_INET;
	rtbl_ep->to.sin_family = AF_INET;
	rtbl_ep->hop.sin_family = AF_INET;
	rtbl_ep->hop.sin_port = htons(7);   /* 7 is the echo port */

	    u_char *p1 = (u_char *)&rtbl_ep->from.sin_addr;
	    u_char *p2 = (u_char *)&rtbl_ep->to.sin_addr;
	    u_char *p3 = (u_char *)&rtbl_ep->hop.sin_addr;

	    fprintf (stderr, "init_route_tbl()	:	Added route (%d.%d.%d.%d)=>(%d.%d.%d.%d) : (%d.%d.%d.%d)\n",
		 UC(p1[0]), UC(p1[1]), UC(p1[2]), UC(p1[3]),
		 UC(p2[0]), UC(p2[1]), UC(p2[2]), UC(p2[3]), 
		 UC(p3[0]), UC(p3[1]), UC(p3[2]), UC(p3[3]));

	if(debug)
		fprintf(stderr, "init_route_tbl()	:	from_fam = %d, to_fam =%d, hop_fam = %d\n", rtbl_ep->from.sin_family, rtbl_ep->to.sin_family, rtbl_ep->hop.sin_family);
	if(debug)
		fprintf(stderr, "init_route_tbl()	:	protocol = %d\n", rtbl_ep->protocol);
	rtbl_ep->s=rtbl_ep->s1=0;
	rtbl_ep ++;
	if (rtbl_ep > rtbl + 64)
	    break;	/* then too much lines, abort */
    }

if(debug)
	fprintf (stderr, "init_route_tbl()	:	Route table initialised\n");

    return (0);
}

UDPecho(int s1, char *msg, int len, int flags, struct sockaddr *hop, int hoplen)
{

 struct sockaddr_in	cli_addr, serv_addr, from_addr;
 int fromlen, c;
 char *buf;
 struct timeval		in, out;
 int triptime;
 int i, len1, c1;

struct sockaddr_in to_name;
int addrlen;

if(debug)
	fprintf(stderr, "UDPecho()	:	UDPEcho called\n");
if((buf=malloc(len) )== NULL)
	fprintf(stderr, "UDPecho()	:	Error in malloc\n");
for(c=0; c<len; c++)
	buf[c]='\0';
gettimeofday(&in, (struct timezone *) 0);
for(i=0, c=0, len1=0; i <len; i=i+1024)
	{
	if((len-i) > 1024) len1=1024;
	else len1=len-i;
	c=_sendto(s1, msg+i, len1, flags, (struct sockaddr *)hop, hoplen);
	c=_recvfrom(s1, buf+i, len1, flags, (struct sockaddr *)&from_addr, &fromlen);
	c=c+c1;
	if(debug) fprintf(stderr, "UDPecho()	:	len1=%d c1=%d, c=%d\n", len1,c1,c);
	}
/*
c=_sendto(s1, msg, len, flags, (struct sockaddr *)hop, hoplen);
c=_recvfrom(s1, buf, len, flags, (struct sockaddr *)&from_addr, &fromlen);
*/
if(debug)
	fprintf(stderr, "UDPecho()	:	Received from %s\n",get_address((struct sockaddr *)&from_addr, fromlen)); 
if(debug)
	fprintf(stderr, "UDPecho()	:	%s\n", buf);
gettimeofday(&out, (struct timezone *) 0);
tvsub(&out, &in);
triptime = out.tv_sec * 1000 + (out.tv_usec / 1000);
fprintf(stderr, "UDPecho()	:	TIME=%d. ms\n", triptime);	/* milliseconds */
fprintf(fd, "%d bytes %d ms\n", len, triptime); 
fflush(fd);

return(c);
}



/*
 * Read "n" bytes from a descriptor.
 * Use in place of read() when fd is a stream socket.
 */

readn(int fd, char *ptr, int nbytes)
{
	int	nleft, nread;

	nleft = nbytes;
	while (nleft > 0) {
		nread = _read(fd, ptr, nleft);
		if (nread < 0)
			return(nread);		/* error, return < 0 */
		else if (nread == 0)
			break;			/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(nbytes - nleft);		/* return >= 0 */
}


/*
 * Write "n" bytes to a descriptor.
 * Use in place of write() when fd is a stream socket.
 */

writen(int fd, char *ptr, int nbytes)
{
	int	nleft, nwritten;

	nleft = nbytes;
	while (nleft > 0) {
		nwritten = _write(fd, ptr, nleft);
		if (nwritten <= 0)
			return(nwritten);		/* error */

		nleft -= nwritten;
		ptr   += nwritten;
	}
	return(nbytes - nleft);
}

TCPecho(int s1, char *msg, int len)
{

char *buf;
int c;
struct sockaddr_in to_name;
int addrlen;
struct timeval		in, out;
int triptime;

if((buf=malloc(len) )== NULL)
	fprintf(stderr,"TCPecho()	:	Error in malloc\n");
for(c=0; c<len; c++)
	buf[c]=0;

if(debug) fprintf(stderr, "TCPecho()	:	TCPecho called \n");
gettimeofday(&in, (struct timezone *) 0);
c=writen(s1,msg,len);
c=readn(s1,buf,len);
printf("buf=%s\n", buf);
gettimeofday(&out, (struct timezone *) 0);
tvsub(&out, &in);
triptime = out.tv_sec * 1000 + (out.tv_usec / 1000);
fprintf(stderr, "TCPecho()	:	TIME=%d. ms\n", triptime);	/* milliseconds */
fprintf(fd, "%d bytes %d ms\n", len, triptime); 
fflush(fd);


return(c);
}


UDPecho1(int s1, char *msg, int len)
{

char *buf;
int c;
struct sockaddr_in to_name;
int addrlen;
struct timeval		in, out;
int triptime;
struct sockaddr_in	from_addr;
int fromlen;
int i, len1, c1;

if((buf=malloc(len) )== NULL)
	fprintf(stderr,	"UDPecho1()	:	error in malloc\n");
for(c=0; c<len; c++)
	buf[c]=0;

if(debug) fprintf(stderr, "UDPecho1()	:	UDPecho1 called \n");
gettimeofday(&in, (struct timezone *) 0);
for(i=0, c=0, len1=0; i <len; i=i+1024)
	{
	if((len-i) > 1024) len1=1024;
	else len1=len-i;
	c1=writen(s1,msg+i,len1);
	c1=_recvfrom(s1, buf+i, len1, 0, (struct sockaddr *)&from_addr, &fromlen);
	c=c+c1;
	if(debug) fprintf(stderr, "UDPecho1()	:	len1=%d c1=%d, c=%d\n", len1,c1,c);
	}
printf("received from %s\n",get_address((struct sockaddr *)&from_addr, fromlen)); 
/*
c=readn(s1,buf,len);
*/
printf("buf=%s\n", buf);
gettimeofday(&out, (struct timezone *) 0);
tvsub(&out, &in);
triptime = out.tv_sec * 1000 + (out.tv_usec / 1000);
fprintf(stderr, "UDPecho1()	:	TIME=%d. ms\n", triptime);	/* milliseconds */
fprintf(fd, "%d bytes %d ms\n", len, triptime); 
fflush(fd);


return(c);
}



extern "C" int
socket(int family, int type, int protocol)
{

 if(init == 0) 
	{
	init_route_tbl();
	init=1;
	}

 	fprintf(stderr, "socket()	:	family=%s type=%s protocol=%s\n", 
         int2name(ADDRESS,family), 
         int2name(SOCKET,type), 
         int2name(PROTOCOL,protocol));
 int s = _socket(family, type, protocol);
 	fprintf(stderr, "socket()	:	socket value = %d\n", s );
 return s;
}

extern "C" int
connect(int s, struct sockaddr *name, int namelen)
{

 struct route_tbl *rtbl_ptr = 0;	/* next empty slot pointer */
 int s1;
 struct	sockaddr_in	to_addr;
 int addrlen;


 rtbl_ptr=get_rtbl_ent(name, namelen);
 if(rtbl_ptr != 0)
	{
	if((rtbl_ptr->protocol == TCP) && (rtbl_ptr->s1 == 0))
		{
		if(debug)
			fprintf(stderr, "connect() 	:	TCP to \n");
		s1 = _socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
		_connect(s1, (struct sockaddr *)&(rtbl_ptr->hop), sizeof(struct sockaddr));
		if(debug)
 			fprintf(stderr, "connect()	:	s1=%d name=%s namelen=%d \n ", 
         		s, get_address((struct sockaddr *)&(rtbl_ptr->hop),sizeof(struct sockaddr)), sizeof(struct sockaddr));
		rtbl_ptr->s=s;
		rtbl_ptr->s1=s1;
		}
	if((rtbl_ptr->protocol == UDP) && (rtbl_ptr->s1 == 0))
		{
		if(debug)
			fprintf(stderr, " connect() 	:	UDP \n");
		s1 = _socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		_connect(s1, (struct sockaddr *)&(rtbl_ptr->hop), sizeof(struct sockaddr));
		if(debug)
 			fprintf(stderr, "connect()	:	s1=%d name=%s namelen=%d\n ", 
         		s, get_address((struct sockaddr *)&(rtbl_ptr->hop),sizeof(struct sockaddr)), sizeof(struct sockaddr));
		rtbl_ptr->s=s;
		rtbl_ptr->s1=s1;
		}

	}
 else 
	if(debug)
		fprintf(stderr,"connect()	:	Table entry not found\n");
 
if(debug)
	 fprintf(stderr, "connect()	:	s=%d name=%s namelen=%d \n", 
         s, get_address(name,namelen), namelen);


    int c = _connect(s, name, namelen);
    fprintf(stderr, "connect()	:	return value = %d\n", c );
    return c;
}


extern "C" int
socketpair(int domain, int type, int protocol, int sv[2])
{
 	fprintf(stderr, "socketpair()	:	domain=%s type=%s protocol=%s \n", 
         int2name(ADDRESS,domain),
         int2name(SOCKET,type),
         int2name(PROTOCOL,protocol));

 int c = _socketpair(domain, type, protocol, sv);
 	fprintf(stderr, "socketpair()	:	values are %d(sv[0]=%d sv[1]=%d)\n", c, sv[0], sv[1]);

 return c;
}

extern "C" int
listen(int s, int backlog)
{
 	fprintf(stderr, "listen()	:	s=%d backlog=%d \n ", s, backlog);

 int c = _listen(s, backlog);
 	fprintf(stderr, "listen()	:	return value = %d\n", c );

 return c;
}

extern "C" int
shutdown(int s, int how)
{
 char *shutdown_how[] = 
    { "further receives disallowed", // 0
      "further sends disallowed",    // 1
      "further sends and receives disallowed"};   // 2 

 	fprintf(stderr, "shutdown()	:	s=%d how=%s\n ", s, shutdown_how[how]);

   int c = _shutdown(s, how);
    fprintf(stderr, "shutdown(0	:	return value = %d\n", c );
 
}

extern "C" int
getsockopt(int s, int level, int optname, char *optval, int *optlen)
{
 	fprintf(stderr, "getsockopt()	:	s=%d level=%s optname=%s optval=0x%x *optlen=%d\n", s, opt_level(level), opt_name(level,optname), optval, *optlen);

 int c = _getsockopt(s, level, optname, optval, optlen);
 	fprintf(stderr, "getsockopt()	:	return value = %d\n", c );

 return c;
}

extern "C" int
setsockopt(int s, int level, int optname, const char *optval, int optlen)
{
 	fprintf(stderr, "setsockopt()	:	s=%d level=%s optname=%s optval=0x%x optlen=%d\n ", s, opt_level(level), opt_name(level,optname), optval, optlen);

 int c = _setsockopt(s, level, optname, optval, optlen);
 	fprintf(stderr, "setsockopt()	:	return value = %d\n", c );

 return c;
}

extern "C" int
send(int s, const char *msg, int len, int flags)
{
 struct route_tbl *rtbl_ptr = 0;	/* next empty slot pointer */
 	fprintf(stderr, "send()		:	s=%d msg=0x%x len=%d flags=%d\n", s, msg, len, flags);

 rtbl_ptr=get_sock_ent(s); /* get_sock_ent is enough because in case of send, 					the connect must have been done already and 					hence it must have been adssigned in the 					route_tbl */
 if(rtbl_ptr != 0)
	{
	if(rtbl_ptr->protocol == TCP) 
		{
		if(debug)
			fprintf(stderr, "send() 	:	TCP \n");
		TCPecho(rtbl_ptr->s1, msg, len);
		}
	if(rtbl_ptr->protocol == UDP)
		{
		if(debug)
			fprintf(stderr, "send()		:	UDP \n");
		UDPecho(rtbl->s1, msg, len, flags, (struct sockaddr *)&(rtbl_ptr->hop), sizeof(struct sockaddr));
		}
	}

 int c = _send(s, msg, len, flags);
 	fprintf(stderr, "send()		:	return value = %d\n", c );

 return c;
}

int junk=0;
extern "C" int
sendto(int s, const char *msg, int len, int flags, const struct sockaddr *to, int tolen)
{
 int c;
 struct sockaddr_in	cli_addr, serv_addr, from_addr;
 int fromlen;
 char buf[100];
 struct route_tbl *rtbl_ptr=0;

 rtbl_ptr = get_rtbl_ent(to, tolen);
if(debug)
	fprintf(stderr, "sendto() 	:	rtbl_ptr=%x\n", rtbl_ptr);
 if(rtbl_ptr !=0)
	{
	if(rtbl_ptr->protocol == TCP) 
		{
		if(debug)
			fprintf(stderr, "sendto()	:	TCP \n");
		TCPecho(rtbl_ptr->s1, msg, len);
		}
	if(rtbl_ptr->protocol == UDP)
		{
		if(debug)
			fprintf(stderr, "sendto()	:	UDP \n");
		if(rtbl_ptr->s1 != 0)
			{
			if(debug)
				fprintf(stderr, "sendto()	:	s1!=0\n");
			UDPecho(rtbl->s1, msg, len, flags, (struct sockaddr *)&(rtbl_ptr->hop), sizeof(struct sockaddr));
			}
		else
			{
			if(debug)
				fprintf(stderr, "sendto()	:	s1=0\n");
			UDPecho(s, msg, len, flags, (struct sockaddr *)&(rtbl_ptr->hop), sizeof(struct sockaddr));
			}
			
		}
	}

/*
 fprintf(stderr,"sendto(s=%d msg=0x%x len=%d flags=%d to=%s tolen=%d) = ",
         s, msg, len, flags, get_address(to,tolen), tolen);

	bzero((char *) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family      = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr("128.10.5.4");
	serv_addr.sin_port        = htons(7);

printf("***1***\n");
UDPecho(s, msg, len, flags, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
*/
 c = _sendto(s, msg, len, flags, to, tolen);
if(debug)
 fprintf(stderr, "sendto()	:	Returning from sendto\n");
 	fprintf(stderr, "sendto()	:	return value = %d\n", c );

 return c;
}


extern "C" int
sendmsg(int s, const struct msghdr *msg, int flags)
{
 struct route_tbl *rtbl_ptr = 0;	/* next empty slot pointer */
 struct msghdr echomsg;

 	fprintf(stderr,"sendmsg()	:	s=%d msg=0x%x flags=%d\n ", s, msg, flags);

 rtbl_ptr=get_rtbl_ent((struct sockaddr *)msg->msg_name, msg->msg_namelen);
 if(rtbl_ptr != 0)
 	{


	bcopy(msg, &echomsg,sizeof(struct msghdr)); 
	if(rtbl_ptr->protocol == TCP) 
		{
		if(debug)
			fprintf(stderr, "sendmsg()	:	TCP \n");
		_sendmsg(rtbl_ptr->s1, &echomsg, flags);
		_recvmsg(rtbl_ptr->s1, &echomsg, flags);
		}
	if((rtbl_ptr->protocol == UDP) && (rtbl_ptr->s1 == 0))
		{
		if(debug)
			fprintf(stderr, "sendmsg()	:	 UDP \n");
		if(rtbl_ptr->s1 == 0)      /* connect was not called  */
			{
			_sendmsg(s, &echomsg, flags);
			_recvmsg(s, &echomsg, flags);
			}
		else
			{
			_sendmsg(rtbl_ptr->s1, &echomsg, flags);
			_recvmsg(rtbl_ptr->s1, &echomsg, flags);
			}
		}
 	}

 	int c = _sendmsg(s, msg, flags);
 	fprintf(stderr, "sendmsg()	:	return value = %d\n", c );

 return c;   
}

extern "C" int
bind(int s, struct sockaddr *name, int namelen)
{
 	fprintf(stderr,"bind()		:	s=%d name=%s namelen=%d\n", 
         s, get_address(name,namelen), namelen);

 	int c = _bind(s, name, namelen);
 	fprintf(stderr, "bind()		:	return value = %d\n", c );

 return c;      
}

int accept_now = 0;

extern "C" int
accept(int s, struct sockaddr *addr, int *addrlen)
{
 int c;

 	fprintf(stderr,"accept()	:	s=%d *addrlen=%d)\n", s, *addrlen); 

    	c = _accept(s, addr, addrlen);
    	fprintf(stderr, "accept()	:	%d(addr=<%s>,*addrlen=%d)\n", 
            c, get_address(addr, *addrlen), *addrlen);
 return c;       
}

extern "C" int
getpeername(int s, struct sockaddr *name, int *namelen)
{
 	fprintf(stderr,"getpeername()	:	s=%d *namelen=%d = ", s, *namelen);

 	int c = _getpeername(s, name, namelen);
 	fprintf(stderr, "%d(name=%s *namelen=%d)\n", 
         c, get_address(name,*namelen), *namelen);

 return c; 
}

extern "C" int
getsockname(int s, struct sockaddr *name, int *namelen)
{
 	fprintf(stderr,"getsockname()	:	s=%d *namelen=%d = ", s, *namelen);

 int c = _getsockname(s, name, namelen);
 	fprintf(stderr, "%d(name=%s *namelen=%d)\n", 
         c, get_address(name,*namelen), *namelen);

 return c; 
}

extern "C" int
recv(int s, char *buf, int len, int flags)
{
 	fprintf(stderr,"recv()	:	s=%d buf=0x%x len=%d flags=%d = ", s, buf, len, flags);

 int c = _recv(s, buf, len, flags);
 	fprintf(stderr, "%d\n", c );

 return c;  
}

extern "C" int
recvfrom(int s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
{
 int c;
if(debug)
	 fprintf(stderr, "recvfrom()	:	Recvfrom called\n");
/*
 printf("s=%d, buf =%x, len=%d, flags=%d, from=%s, fromlen=%d\n", s, buf, len, flags, get_address((struct sockaddr *)from, fromlen), fromlen);
*/
 c = _recvfrom(s, buf, len, flags, from, fromlen);

if(debug)
	fprintf(stderr, "recvfrom()	:	Returning from recvfrom\n");
 return c;                 
}

extern "C" int
recvmsg(int s, struct msghdr *msg, int flags)
{
 	fprintf(stderr,"recvmsg()	:	s=%d msg=0x%x flags=%d = ", s, msg, flags);

 	int c = _recvmsg(s, msg, flags);
 	fprintf(stderr, "%d\n", c );

 return c;      
}

extern "C" int
close(int fildes)
{
 struct stat buf;
 int c;

 /* Solaris treat the socket as character-special files. It is very
    strange that S_ISSOCK(buf.st_mode) always fail for socket descriptor, 
    but S_ISCHR(buf.st_mode) always success  for socket descriptor.
    Therefore I have to use S_ISCHR instead of S_ISSOCK to decide
    whether to print things out or not. Of course this will generate
    more data than necessary. However, it is acceptable to me.
  */
    c = _close(fildes);
    fprintf(stderr, "close()		:	%d\n", c );
    return c;
 }
 

extern "C" int
select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 
	struct timeval *timeout)
{

 int c = _select(nfds, readfds, writefds, exceptfds, timeout);
 	fprintf(stderr, "select()	:	%d\n", c );

 return c;
}


extern "C" ssize_t 
read(int fildes, void *buf, size_t nbyte)
{
 ssize_t st;
 int new_fildes;
   st = _read(fildes, buf, nbyte);

 return st;
}

extern "C" ssize_t 
write(int fildes, const void *buf, size_t nbyte)
{
 ssize_t st;
 int new_fildes;
 struct route_tbl *rtbl_ptr=0;

if(debug)
	fprintf(stderr, "write()	:	write called\n");
	rtbl_ptr = get_sock_ent(fildes);  /* write can be used on;ly if connect 						has been called and hence 							get_sock_ent is enough */
	if(debug)
		fprintf(stderr, "write()	:	rtbl_ptr=%x\n", rtbl_ptr);
	if(rtbl_ptr != 0)
		{
		if(rtbl_ptr->s1 !=0)
			{
			if(debug)
				fprintf(stderr, "write()	:	s1=%d\n", rtbl_ptr->s1);
			if(rtbl_ptr->protocol == TCP)
				TCPecho(rtbl_ptr->s1, buf, nbyte);
			else if(rtbl_ptr->protocol == UDP)
				UDPecho1(rtbl_ptr->s1, buf, nbyte);
			}
				
		}
    st = _write(fildes, buf, nbyte);

 return st;
}
