
#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>
#include  <strings.h>
#include  <sys/time.h>
#include  <errno.h>
#include  <signal.h>
#include  <sys/socket.h>
#include  <netdb.h>
#include  <netinet/in.h>
#include  <arpa/inet.h>
#include  <sys/types.h>
#include <unistd.h>
#include  <fcntl.h>


#define FD_SET_SIZE    8
#define BUFFER_SIZE    1024
#define INVALID_SOCKET -1

struct  fd_list{
    int   fd; 			// ソケットのFD
    int   module;		// モジュールID
};

/*
#define MYPORT         800
*/
#define MYPORT         3333
#define BACKLOG        10

int main(void)
{
	static struct  fd_list fd_tbl[FD_SET_SIZE];

	
	fd_set rfds;

	sigset_t mask;

	int timeout ;

	struct timespec ts;

	int sockfd, new_fd;
	struct sockaddr_in my_addr ;
	struct sockaddr_in their_addr ;
	int sin_size;

	char string_read[1024];

	int   n,i;
	int   last_fd;
	int   ret;
	int   fd,start_fd,end_fd;

	memset( fd_tbl, (INVALID_SOCKET), sizeof(fd_tbl));
	memset ( &rfds, 0x00, sizeof( rfds ) );
	memset( &mask, 0x00, sizeof( mask ) );
	memset( &ts, 0x00, sizeof( ts ) );


	/*  timeount */
	timeout = 5000;
	ts.tv_sec = timeout / 1000;
	ts.tv_nsec = ( timeout % 1000 ) * 1000 * 1000;
		
	
	if ((sockfd=socket (AF_INET, SOCK_STREAM, 0))==-1) {
		perror ("socket") ;
		exit (1);
	}
	
	last_fd=sockfd;

	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons (MYPORT) ;
	my_addr.sin_addr. s_addr = INADDR_ANY;

	bzero(&(my_addr. sin_zero), 8);
	
	if ( bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
		close(sockfd);
		perror ("bind") ;
		exit (1);
	}
		
	if ( listen(sockfd, BACKLOG) == -1) {
		close(sockfd);
		perror("listen") ;
		exit (1);
	}

	fcntl( last_fd, F_SETFL, O_NONBLOCK );

	printf ("server fd = %d.\n", last_fd) ;
	while(1) {

		FD_ZERO( &rfds );

		end_fd = last_fd;
		start_fd = last_fd;
		FD_SET( sockfd, &rfds );
		for (i=0; i<FD_SET_SIZE; i++ ) {
			if (fd_tbl[i].fd != INVALID_SOCKET ){
				FD_SET( fd_tbl[i].fd, &rfds );
				if ( fd_tbl[i].fd >end_fd  ){
					end_fd = fd_tbl[i].fd;
				}
				if ( fd_tbl[i].fd <start_fd  ){
					start_fd = fd_tbl[i].fd;
				}
			}
		}
		// ret = pselect( end_fd + 1, &rfds, NULL, NULL, &ts, &mask );
		ret = pselect( end_fd + 1, &rfds, NULL, NULL, &ts, &mask );
		if( ret == -1) {
			perror("pselect") ;
			exit(1);
		}else if( ret == 0) {
			continue;
		}			
			
		for (fd=start_fd; fd<=end_fd; fd++) {
			if( FD_ISSET( fd, &rfds ) !=0) {
				if ( fd == sockfd ) {
					sin_size = sizeof(struct sockaddr_in);
					if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size )) == -1) {
						perror ("accept");
						exit (1);
					}

					for (i=0; i<FD_SET_SIZE; i++ ) {
						if (fd_tbl[i].fd == INVALID_SOCKET ){
							fd_tbl[i].fd = new_fd;
							break;
						}
					}
					if ( i>=FD_SET_SIZE ){
						printf ("warning: client connection > ( %d )\n", FD_SET_SIZE) ;
					}
					else{
						printf ("server: got connection from %s  fd = %d \n", inet_ntoa(their_addr. sin_addr), new_fd) ;
						fcntl( new_fd, F_SETFL, O_NONBLOCK );
					}
					break;
				}else{
					n = recv(fd, string_read, sizeof (string_read), MSG_DONTWAIT);
					if(n<1){
						for (i=0; i<FD_SET_SIZE; i++ ) {
							if (fd_tbl[i].fd == fd){
								fd_tbl[i].fd=INVALID_SOCKET;
							}
						}
						close(fd);
						printf("client disconnected (fd = %d )\n",fd);
						// perror("recv - non blocking \n");
						//printf ("Round %d, and the data read size is: n=%d \n", i, n);
					}
					else{
						string_read[n] ='\0';
						printf("The string is: %s \n", string_read);
						if (send( new_fd, "Hello, world! \n", 14, 0) == -1) {
							perror ("send") ;
						}
					}
				}
			}
		}
	}
}
	