/* tcpserver.c - Used to measure performance of tcp connections. 
   It accepts connections. A child process handles a connection.
   In the connection the child reads MAX_SIZE bytes and replies 
   with a single byte. Then it terminates.
   This server responds on port TCP_PORT and uses a buffer size 
   (both receiving and sending) of BUFSIZE = 32 K bytes, which 
   happens to be the default size of the TCP buffer on my system 
   (as determined using getsockopt). 
   After being compiled with "%gcc -o tcpserver tcpserver.c" it 
   is called with "%tcpserver "
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>

#define TCP_PORT 7621
#define BUFSIZE 32*1024
#define MAX_SIZE 32*BUFSIZE

void tcpserver(int s, void * buf); // function executed by child.

int
main(int argc, char *argv[])
{
	static char buf[BUFSIZE];
	static char hostname[128];
	struct hostent *hp;
	struct sockaddr_in saddr, caddr;
	int sendbuff, recvbuff, tmp;
	int lis_sock, pid;

	gethostname(hostname, sizeof(hostname));
	printf("hostname is %s\n", hostname);
	if ((hp = gethostbyname(hostname)) == NULL) {
		fprintf(stderr,"%s: host unknown.\n",hostname);
		exit(1);
	}

	if ((lis_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		fprintf(stderr,"%s: host unknown.\n",hostname);
		exit(1);
	}

	getsockopt(lis_sock, SOL_SOCKET, SO_SNDBUF, &sendbuff,&tmp);
	getsockopt(lis_sock, SOL_SOCKET, SO_RCVBUF, &recvbuff,&tmp);
	printf("Pre-existing Sending buffer size: %d\n", sendbuff);
	printf("Pre-existing Receive buffer size: %d\n", recvbuff);

        sendbuff = BUFSIZE;
	if (setsockopt(lis_sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, 
		       sizeof(sendbuff)) < 0) {
		perror("server: setsockopt SO_SNDBUF");
		exit(1);
	}
	recvbuff = BUFSIZE;
	if (setsockopt(lis_sock, SOL_SOCKET, SO_RCVBUF, &recvbuff,
		       sizeof(recvbuff)) < 0) {
		perror("server: setsockopt SO_RCVBUF");
		exit(1);
	}
	getsockopt(lis_sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, &tmp);
	getsockopt(lis_sock, SOL_SOCKET, SO_RCVBUF, &recvbuff, &tmp);
	printf("Sending buffer size: %d\n", sendbuff);
	printf("Receive buffer size: %d\n", recvbuff);

	bzero((char*) &saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
	saddr.sin_port = htons(TCP_PORT);

	if (bind(lis_sock, (struct sockaddr *) &saddr, sizeof(saddr))<0) {
		perror("server can't bind local address");
		exit(1);
	}
	listen(lis_sock, 5);
	for (;;) {
		int clen;
		int con_sock;
		clen = sizeof(caddr);
		con_sock = accept(lis_sock, (struct sockaddr *) &caddr, &clen);
		if (con_sock<0) {
			perror("error acceptting");
			exit(1);
		}
		if ((pid = fork())<0) {
			perror("error forking");
			exit(1);
		} else if (pid == 0) {   
			close(lis_sock);
			tcpserver(con_sock, buf);
			exit(0);
		}
		close(con_sock);
	}
	return 0;
}

void tcpserver(int sock, void * buf)
{
	int sum = 0;

	while (sum < MAX_SIZE) {
	        int n;
		n = read(sock, buf, BUFSIZE); 
		if (n<=0) break;
		sum += n;
		//		printf("sum = %d\n", sum);
	}
	*(char *)buf = 'X';
	write(sock, buf, 1);
	close(sock);
	//		printf("child terminates\n");
	return;
}

