#include <stdlib.h> /* atexit() */
#include <string.h> /* memset() */
#include <stdio.h> /* printf() */

#if defined(__WIN32__)
#include <winsock.h>
#define	SOCKERR	WSAGetLastError()

#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

#define	closesocket(S)	close(S)
#define	SOCKERR	errno

static int kbhit(void);

#endif

#define	PORT		8080
#define	BACKLOG		5
#define	BUF_SIZE	256

/*****************************************************************************
*****************************************************************************/
int main(void)
{
    /* put big buffer in data segment, so 16-bit DOS program doesn't crash */
	static char buf[BUF_SIZE];
    /* this is the buffer for server-input keystrokes */
    static char keybuf[BUF_SIZE];

    /* this is a boolean flag for whether or not to terminate the listen cycle */
    int flag_terminate = 0;

    /**/
	int l_sock, c_sock, i, count;
#if defined(__WIN32__)
    int sin_size;
#else    
    socklen_t sin_size;
#endif

	struct sockaddr_in my_adr, their_adr;
	struct timeval timeout;
	fd_set read_handles;
#if defined(__WIN32__)
	WSADATA wsdata;

/* Winsock start up */
	WSAStartup(0x0101, &wsdata);
	atexit((void (*)(void))WSACleanup);
#endif
/* create listener socket */
printf("calling socket()...\n");
	l_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(l_sock < 0)
	{
		printf("socket() failed; err=%d\n", SOCKERR);
		return 1;
	}

    /* bind to port */
    printf("calling bind()...\n");
	memset(&my_adr, 0, sizeof(my_adr));
	my_adr.sin_family = AF_INET;
	my_adr.sin_port = htons(PORT);
	my_adr.sin_addr.s_addr = INADDR_ANY;
	i = bind(l_sock, (struct sockaddr *)&my_adr,
		sizeof(struct sockaddr));
	if(i != 0)
	{
		printf("bind() failed; err=%d\n", SOCKERR);
		closesocket(l_sock);
		return 1;
	}

    /* listen on it */
    printf("calling listen()...\n");
	i = listen(l_sock, BACKLOG);
	if(i != 0)
	{
		printf("listen() failed; err=%d\n", SOCKERR);
		closesocket(l_sock);
		return 1;
	}

    /* loop until key pressed or incoming connection. */
    printf("simple server now running on %d\n", PORT);
	count = 1;
    while(!flag_terminate)
	{
        /* use select() to avoid blocking on accept() */
		FD_ZERO(&read_handles);
		FD_SET(l_sock, &read_handles);
		timeout.tv_sec = timeout.tv_usec = 0;
		i = select(l_sock + 1, &read_handles, NULL, NULL, &timeout);
		if(i < 0)
		{
			printf("select(l_sock) failed; err=%d\n", SOCKERR);
            flag_terminate = 1;
            continue;
		}
        /* nothing yet */
		if(i == 0)
			continue;

        /* accept a connection from a client */
        printf("calling accept()\n");
		sin_size = sizeof(struct sockaddr_in);
		c_sock = accept(l_sock, (struct sockaddr *)&their_adr, &sin_size);
		if(c_sock < 0)
		{
			printf("accept() failed; err=%d\n", SOCKERR);
            flag_terminate = 1;
            continue;
		}
        /* someone's there */
		printf("connection from %s\n", inet_ntoa(their_adr.sin_addr));

        while(1)
        {
            /* listen for a short while, dumping out whatever the client sent */
            FD_ZERO(&read_handles);
            FD_SET(c_sock, &read_handles);
            timeout.tv_sec = 0;
            timeout.tv_usec = 100;
            i = select(c_sock + 1, &read_handles, NULL, NULL, &timeout);
            if (i != 0)
            {
                while(1)
                {
                    i = recv(c_sock, buf, BUF_SIZE - 1, 0);
                    if(i < 0)
                    {
                        printf("recv() failed; err=%d\n", SOCKERR);
                        break;
                    }
                    if(i == 0)
                        break;

                    buf[i] = '\0';
                    fputs(buf, stdout);

                    if(i < BUF_SIZE - 1)
                        break;
                }                
            }

            /* grab keystrokes and fill buffer */
            keybuf[0] = '\0';
            if (kbhit())
            {
                fgets(keybuf, BUF_SIZE-1, stdin);
                if (keybuf[0] != '\0')
                {
                    send(c_sock, keybuf, strlen(keybuf), 0);
                }
            }
        }

        /* close this connection session */
		closesocket(c_sock);
    }

    /* close this server listen session */
	closesocket(l_sock);

    return 0;
}


#ifndef __WIN32__

/* god damn this is a really nasty way of testing of a kbd was hit. */

#include <sys/time.h> /* struct timeval, select() */
/* ICANON, ECHO, TCSANOW, struct termios */
#include <termios.h> /* tcgetattr(), tcsetattr() */
#include <stdlib.h> /* atexit(), exit() */
#include <unistd.h> /* read() */
#include <stdio.h> /* printf() */


static int kbhit(void)
{
	struct timeval timeout;
	fd_set read_handles;
	int status;
    struct termios g_old_kbd_mode;
    struct termios new_kbd_mode;

    /* put the damn keyboard in raw mode so we can "peek" */
	tcgetattr(0, &g_old_kbd_mode);
	memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));
	new_kbd_mode.c_lflag &= ~(ICANON | ECHO);
	new_kbd_mode.c_cc[VTIME] = 0;
	new_kbd_mode.c_cc[VMIN] = 1;
	tcsetattr(0, TCSANOW, &new_kbd_mode);

    /* check stdin (fd 0) for activity */
	FD_ZERO(&read_handles);
	FD_SET(0, &read_handles);
	timeout.tv_sec = timeout.tv_usec = 0;
	status = select(0 + 1, &read_handles, NULL, NULL, &timeout);
	if(status < 0)
	{
		printf("select() failed in kbhit()\n");
		exit(1);
	}

    /* put the keyboard back into buffered mode */
    tcsetattr(0, TCSANOW, &g_old_kbd_mode);

	return status;
}


#endif

