/************************************************************/
/*                                                          */
/*  The header file of Connection Management for the server */
/*  For CS 145 (Fall 2003) Lab 1                            */
/*  Author: Xiaoliang (David) Wei                           */
/*  Date:   Oct 10, 2003                                    */
/*                                                          */
/************************************************************/
#ifndef CONNECTION_H
#define CONNECTION_H

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>

#define MAX_CONNECTION_NUMBER 3

#define GET_INT_FROM_SOCKADDR_PTR(addr) (uint32_t)(((sockaddr_in*)addr)->sin_addr.s_addr)
/*This is a macro to translate the sockaddr to int */


/* The class Connection is to describe the behaviour of a connection, including the timer, echoing behaviour and the IP/port information.
*/

class Connection
{
	struct timeval tv;
	/* The last active time. */

	uint32_t peer; 
	/* The ip address of the remote host */

	int sock;
	/* The socket handler we are using */

	int stopped;
	/* stopped: a flag indicating if the connection is dead or not. stopped==0 means the connection is alvie, stopped==1 means the connection is dead */
	
	public:
	Connection(struct sockaddr *newPeer, int newSock) 
	/*the new Peer is the ip information of the remote host, newSock is the socket handler the connection is using. */
	{
		gettimeofday(&tv, NULL);
		peer=GET_INT_FROM_SOCKADDR_PTR(newPeer);
		sock=newSock;
		stopped=0;
	}
	
	struct timeval* getActiveTime() {return &tv;}; /* return the latest timestamp that the connection was active */
	
	int getSock() {return sock;}; /* return the socket handler that the connection is using. */

	void refreshActiveTime() 
	{
		gettimeofday(&tv, NULL);
	};


	int sameAddress(struct sockaddr *addr)	
	/* To check if the addr has a same IP as this connection */
	{
		return (peer==GET_INT_FROM_SOCKADDR_PTR(addr));
	};

	void run();
	/* socket operation: here is echoing */

	~Connection() { close(sock); };

	int inactive() { return stopped;};
	/*to see if the socket is alive or dead*/

	void stop() {stopped=1;}
	/* stop (kill) the connection */
};

/*ConnectionList is a class to manage a list of TCP Connection, including the identical IP checking, maximum connection checking, and timeout checking... */
class ConnectionList
{
	Connection *connList[MAX_CONNECTION_NUMBER];
	/*list to store connections */

	int connNumber;
	/* number of connections */
	
public:	
	ConnectionList()
	{
		connNumber=0;
		for (int i=0;i<MAX_CONNECTION_NUMBER;i++) connList[i]=NULL;
	};

	~ConnectionList()
	{
		for (int i=0;i<connNumber;i++) delete connList[i];
		connNumber=0;
	};

	int allow(struct sockaddr *addr); 
	//return 1 if it's allowed. otherwise return 0
	
	
	int addNewConnection(struct sockaddr *addr, int newSock);
	//return 1 when there is an error, otherwise, return 0.
	
	int delConnection(int sock);
	//remove a connection from the list
	
	void checkExpire(struct timeval *now, int sec); // clean the expired connection
	
	void clean();	// clean the disconnected (by client) or dead connection 
	
	int nearestExpire(struct timeval *timeout, struct timeval *now, int sec); // return the active time of the connection which is the nearest to expire
	
	int selectParam(fd_set *set);
	/* return the "max" parameter for "select", and also the fd set for select reading */
	
	void run(fd_set *set);
	/* trigger the activity of each connection in the list */
};
#endif /*CONNECTION_H*/

