/*=============================================================================
 * Project:	Course on Foundations of the World Wide Web
 * Version:	Summer 2007
 * Module:	server1.c
 * Purpose:	Example of Network Programming: Simple Server
 * Last Change:	29.04.2008
 * Language: C	
 * Authors:	Stefan Brass, Christian Goldberg
 * Email:	brass@informatik.uni-halle.de
 * Address:	Martin-Luther-Univiversitaet Halle,
 *          Von-Seckendorff-Platz 1
 *          D-06120 Halle (Saale), GERMANY
 * Copyright:	free
 * Copying:	Do with this what you want, but don't make me responsible!
 *		There are no warrenties whatsoever.
 *=============================================================================
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
extern int errno;

#define BACKLOG 10 /* Number of queued connection requests from clients */

/*=============================================================================
 * Example of Server Function:
 *=============================================================================
 */

void serve(int connected_socket, struct sockaddr_in *client_addr)
{
	const char *p;
	int n;
	int written;

	/* Print information about client (for debugging purposes): */
	printf("Connect request from %s, port %d\n",
		inet_ntoa(client_addr->sin_addr),
		client_addr->sin_port);

	/* Send string to client (fixed string for illustration only): */
	p = "Hallo WWW-Kurs!\n";
	n = strlen(p);
	while(n > 0) {
		written = write(connected_socket, p, n);
		if(written < 0) {
			perror("Error while writing to client");
			exit(1);
		}
		else if (written == 0) {
			fprintf(stderr, "Impossible. 0 Bytes written!\n");
			exit(1);
		}
		else {
			p = p + written;
			n = n - written;
		}
	}

	/* Don't forget to close socket: */
	if(close(connected_socket) != 0) {
		perror("Error closing socket");
		exit(1);
	}

}

/*=============================================================================
 * Main Function (Sets up Server, Accepts Connection Requests):
 *=============================================================================
 */

int main()
{
	int s; /* Listening Socket Descriptor */
	int c; /* Connected Socket Descriptor */
	struct sockaddr_in addr; /* Internet address */
		/* struct sockaddr_in is defined in <netinet/in.h>,
		 * which is included via <netdb.h>.
		 * It must be compatible with / will be casted to
		 * struct sockaddr, defined in <sys/socket.h>.
		 */
	struct sockaddr_in client; /* Internet address */
	socklen_t len; /* Length of address data structure */

	/*---------------------------------------------------------------------
	 * First Step: Create/Allocate TCP/IP Socket.
	 *---------------------------------------------------------------------
	 */

	s = socket(AF_INET, SOCK_STREAM, 0);
	if(s == -1) {
		perror("Error creating socket");
		exit(1);
	}

	/*---------------------------------------------------------------------
	 * Second Step: Create data structure with address of server (port).
	 *---------------------------------------------------------------------
	 */

	memset(&addr, 0, sizeof(addr));
		/* Initialize structure to zero */
		/* Alternative: Field sin_zero (8 bytes) at the end */
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(58500);

	/*---------------------------------------------------------------------
	 * Third Step: Bind socket to port.
	 *---------------------------------------------------------------------
	 */

	if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
		perror("Error binding socket");
		exit(1);
	}

	/*---------------------------------------------------------------------
	 * Fourth Step: Turn this socket into a listening socket.
	 *---------------------------------------------------------------------
	 */

	if(listen(s, BACKLOG) != 0) {
		perror("Error making socket listening");
		exit(1);
	}

	/*---------------------------------------------------------------------
	 * Fifth Step: Accept connections.
	 *---------------------------------------------------------------------
	  */

	for(;;) { /* FOR EVER */
		len = sizeof(client);
		if((c = accept(s, (struct sockaddr *) &client, &len)) < 0) {
			perror("Error accepting connection");
			exit(1);
		}
		serve(c, &client);
	}

	/* Program ends: */
	return(0);
}

