#include	"unpthread.h"
#include	"unpipc.h"
#include	"pre_thread_model.h"
#include	"global.h"
#include	"protocol.h"
#include	<mysql.h>
#include    <libpq-fe.h>

#define		MAXREADLINE			1024
#define		MaxSizeOfSndBuffer	1024*8
#define		GetServStatusCmd        "GET_SERVSTATUS"
#define		RequestServUpdateCmd	"REQUEST_SERV_UPDATE"

#define INSERT      1
#define UPDATE      2
#define DELETE      3

static char HostName[512];
static char report_update_port[16];
static char report_send_port[16];

void vrcd_thread_make(int i)
{
	void	*vrcd_thread_main(void *);

	/* make tcp listen thread (for Update Share Memory. recieve from vrcd) */
	Pthread_create(&vrcd_tptr[i].thread_tid, NULL, &vrcd_thread_main, (void *) i);
	return;		/* main thread returns */
}

void report_thread_make()
{
	int i = 0;
	void    *report_thread_send_main(void *);
	void	*report_thread_update_main(void *);
	void	*report_thread_server_check_main(void *);

	GetProfile("PARAM", "HOSTNAME", HostName, "localhost");
    GetProfile("PARAM", "REPORT_UPDATE_PORT", report_update_port, "22201");
    GetProfile("PARAM", "REPORT_SEND_PORT", report_send_port, "22202");
	
	/* make server list update thread (for changing server information [INSERT, UPDATE, DELETE]) */
	Pthread_create(&report_tptr[i].thread_tid, NULL, &report_thread_update_main, (void *)i);
	i++;
		
	/* make server list send thread (for SMS WEB service */
	Pthread_create(&report_tptr[i].thread_tid, NULL, &report_thread_send_main, (void *)i);
	i++;

	/* make cycling thread (to update server information) */
	Pthread_create(&report_tptr[i].thread_tid, NULL, &report_thread_server_check_main, (void *)i);	
	return;
}

#define PGCONN_STRING	"host=%s port=%d dbname=%s user=%s password=%s"

void * report_thread_server_check_main(void *arg)
{
	int increaseDeadCount(unsigned int, char *);
	int socket_open_with_timeout(int, servinfo_t *);
	int timedCheck(char *, int, int);
	void HandleTimeOut(int signum);
	void processing_server_status(int, int, servinfo_t *);
	char *rcacctFind(char *);
	
	FILE *fp = NULL;
	PGconn *conn = NULL;
    PGresult *result;
	
	servinfo_t *servinfo;
	servinfo_t *i;
	
	time_t now, past;
	char pgsql_conn_str[256];
	char pgsql_query[128];
	char buf[1024];
	char *rccheck_exec;
	int connRes;
	int hcterm = 0;
	int	toRead = 0;
    int sendSMSTerm;
	int	retval;
	int time_cnt=0;
	unsigned int g_CSMErrorCount = 0;
	/* Load conf file */
	
    /* SetIniName(CFGFILE); */	
	hcterm = GetProfileInt("PARAM", "HEALTH_CHECK_TERM", 5);
	sendSMSTerm = (SENDSMSTERM * 60) / hcterm;
	toRead = GetProfileInt("PARAM", "TIME_OUT_READ", 5);

	fprintf(stderr, "report check server status thread(2) starting...\n");

	past = now = time(NULL);
	servinfo = g_servinfo;
	
	while (g_CSMErrorCount < ALLOWED_MAX_ERROR_COUNT)
	{
		report_tptr[(int) arg].thread_count++;
		Pthread_mutex_lock(&report_lock);
		Sem_wait(sem_mutex);
		servinfo = g_servinfo;
		/* update list from SHM */
		for (i = servinfo; strcmp(i->m_pszServName, END_OF_SHM); i = i->next)
		{
			connRes = 0;
			if (i->m_ServType == 0) // RC
			{
				if ((time_cnt % 2) == 0)
					continue;
				
				rccheck_exec = rcacctFind(i->m_szIpString);

				fprintf(stderr, "RETURN RCCHECK QUERY : %s\n", rccheck_exec);
				if ((retval = system(rccheck_exec)) != 0)
					connRes = -1;
				else
					connRes = 1;
				free(rccheck_exec);
			}
			else if (i->m_ServType == 4)	// DATABASE
			{
				snprintf(pgsql_conn_str, 1024, PGCONN_STRING, i->m_szIpString, i->m_sPort, "localdb", "syshost", "alfkzmf!?{}");
				conn = PQconnectdb(pgsql_conn_str);
				if (PQstatus(conn) == CONNECTION_BAD)
				{
					fprintf(stderr, "pgSQL Connection failed(%s), %s\n", PQerrorMessage(conn), i->m_szIpString);
					if (conn != NULL)
						PQfinish(conn);
					connRes = -1;
				}
				else
				{
					snprintf(pgsql_query, 128, "select now()");
					result = PQexec(conn, pgsql_query);
					if (!result)
					{
						fprintf(stderr, "PQexec command failed, no error code(%s)\n", i->m_szIpString);
						connRes = -1;
					}
					else
						connRes = 1;
				}
			}
			else if (i->m_ServType == 9)	// timed
			{
				if (timedCheck(i->m_szIpString, i->m_sPort, toRead) < 0)
				{
					fprintf(stderr, "--- Time Server seems dead ---\n");
					connRes = -1;
				}
				else
				{
					fprintf(stderr, "--- Time Server is Alive!! ---\n");
					connRes = 1;
				}
			}
			else if (i->m_ServType == 1) // Stat
			{
				connRes = -1;
				sprintf(buf, "wget \"http://www.ktsh.co.kr:8080/stat-status/index.html?rcid=%s\" -O /root/%s", i->m_szIpString, i->m_szIpString);
				system(buf);

				sprintf(buf, "/root/%s", i->m_szIpString);
				fprintf(stderr, "HERE TO GO\n");
				
                if ((fp = fopen(buf, "r")))
				{
					memset(buf, 0, 4);
                    fread(buf, 1, 3, fp);
					fprintf(stderr, "%s\n", buf);

					if (buf[0] == 'O') {
					    connRes = 1;
					}
					else
					{
						fprintf(stderr, "!STAT ERR MSG : %c %c %c \n", buf[0], buf[1], buf[2]);
					}
				}
				else
				{
					fprintf(stderr, "!FILE OPEN ERR: %s : %s\n", buf, strerror(errno));
				}
			}
			else  // other Servers included RTS
			{
				fprintf(stderr, "ServType : %d, ServName %s\n", i->m_ServType, i->m_szIpString);
				signal(SIGALRM, HandleTimeOut);
				alarm(toRead);
				connRes = socket_open_with_timeout(toRead, i);
				alarm(0);
			}
			processing_server_status(connRes, sendSMSTerm, i);
		}
#if 1
fprintf(stderr , "report_thread_server_check_main@@@@@@@@@@@@@@\n");
#endif
		Sem_post(sem_mutex);
		Pthread_mutex_unlock(&report_lock);
		now = time(0);

		while((past + hcterm) > now)
		{
			now = time(0);
		}
		past = now;
		time_cnt++;
		fflush(stderr);
	}
	fprintf(stderr, "HERE IS END??\n");
	
	/* close postgreSQL */
	if (conn)
		PQfinish(conn);
}

char *rcacctFind(char *ipString)
{
	static char *rccheck_exec;
	char delim = ':';
	int i, num;
	
	char *buffer[512];
	char rcacct_buf[1024];
	
	GetProfile("RCACCT", ipString, rcacct_buf, "");
	
	/* extraction information */
	num = devide(buffer, rcacct_buf, delim);
	
	rccheck_exec = (char *)malloc(1024);
	memset(rccheck_exec, 0, 1024);
	snprintf(rccheck_exec, 1024, "%s/rccheck %s %s %s %s %s %s", DEFAULT_RC_CHECK_BIN, DEFAULT_LOGFILE_PATH, ipString, buffer[0], buffer[1], buffer[2], buffer[3]);

	/*
	for (i=0; i < num; i++)
		fprintf(stderr, "buffer[%d] ::> %s\n", i, buffer[i]);
	*/

	for (i=0; i < num; i++)
		free(buffer[i]);
	return rccheck_exec;
}

#define MaxSizeOfBuffer 1024*4
void processing_server_status(int connRes, int sendSMSTerm, servinfo_t *i)
{
	int increaseDeadCount(unsigned int, char *);
	void UpdateStatus(unsigned int, unsigned int, char *);
	void SendToWebServ(const char *);
		
	struct tm *t;
	time_t timer;
	int nDeadCount;
	char szMsgBuffer[MaxSizeOfBuffer];

	timer = time(NULL);
	t = localtime(&timer);

	if (connRes < 0)
    {
		nDeadCount = increaseDeadCount(i->m_ServType, i->m_pszServName);
		fprintf(stderr, "%d connRes \n", connRes);
		fprintf(stderr, "%d m_ServType \n", i->m_ServType);
	    fprintf(stderr, "%s seems dead \n", i->m_pszServName);
		fprintf(stderr, "Dead count : %d\n", nDeadCount);

		if (nDeadCount >= MAX_ALLOWED_DEAD_COUNT) {
			i->m_Status = SERV_DEAD;
			UpdateStatus(i->m_ServType, SERV_DEAD, i->m_pszServName);
			snprintf(szMsgBuffer, MaxSizeOfBuffer, "[ %s ] DEAD :: %s ",  i->m_pszServName, timeToString(t));

			if (((int)nDeadCount < (sendSMSTerm * (MAXSENDSMSCOUNT))) &&
					(nDeadCount == MAX_ALLOWED_DEAD_COUNT || (nDeadCount % sendSMSTerm) == 0))
			{
				fprintf(stderr, "*********** Here is SendToWebServ ************\n");
				SendToWebServ(szMsgBuffer);
			}
		}
	}
	else
	{
		/* To Cleaning Up DEAD COUNT */
		if (i->m_Status == SERV_DEAD) {
			i->m_Status = SERV_ALIVE;
			snprintf(szMsgBuffer, MaxSizeOfBuffer, "[ %s ] IS BACK :: %s ",  i->m_pszServName, timeToString(t));
			SendToWebServ(szMsgBuffer);
		}
		UpdateStatus(i->m_ServType, SERV_ALIVE, i->m_pszServName);
	}
}

void UpdateStatus(unsigned int servtype, unsigned int status, char *servname)
{
	servinfo_t *i;

	for (i = g_servinfo; strcmp(i->m_pszServName, END_OF_SHM); i = i->next)
	{
		if (!strcmp(i->m_pszServName, servname) && i->m_ServType == servtype)
		{
			i->m_Status = status;
			break;
		}
	}
}

int timedCheck(char *ip, int port, int toRead)
{
	void HandleTimeOut(int signum);
    int res = 0;
    int nRead = -1;
    int nWrite = -1;
    int sSocket = -1;
    char szRcvBuf[32];
    time_sync_t ctime;
    time_sync_t *recv_time = NULL;
    struct sockaddr_in serv_addr;

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = inet_addr(ip);
    ctime.sync_info = htonl(AuthPrime);
    sSocket = socket(AF_INET, SOCK_STREAM, 0);

	fprintf(stderr, "------ Check Time Server [port] : %d, [ip] : %s\n", port, ip);
    signal(SIGALRM, HandleTimeOut);
    alarm(toRead);
	
    res = connect(sSocket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (res < 0) {
        fprintf(stderr, "connect :: %s\n", strerror(errno));
        return -1;
    }
    alarm(0);

    nWrite = send(sSocket, (char *)&ctime, sizeof(ctime), 0);
    if (nWrite < 0) {
        fprintf(stderr, "send :: %s\n", strerror(errno));
        shutdown(sSocket, SHUT_RDWR);
        close(sSocket);
        return -2;
    }

    nRead = recv(sSocket, szRcvBuf, sizeof(szRcvBuf), 0);
    if (nRead < 0) {
#ifdef __DEBUG__
        fprintf(stderr, "recv :: %s\n", strerror(errno));
#endif
        shutdown(sSocket, SHUT_RDWR);
        close(sSocket);
        return -3;
    }
    shutdown(sSocket, SHUT_RDWR);
    close(sSocket);
    recv_time = (time_sync_t *)&szRcvBuf;

#ifdef __DEBUG__
    fprintf(stderr, "TIME = %ld\n", ntohl(recv_time->sync_info));
#endif
    return 0;
}	

int socket_open_with_timeout(int toRead, servinfo_t *servinfo)
{
	struct sockaddr_in serveraddr;
	struct timeval tv;
	int len;
	int twsfd;
	
	tv.tv_sec = toRead;
	tv.tv_usec = 0;

	if ( (twsfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
	{
		perror("error");
		close(twsfd);
		return -1;		
	}
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(servinfo->m_szIpString); 
	serveraddr.sin_port = htons(servinfo->m_sPort);
	
	setsockopt(twsfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(tv));
	setsockopt(twsfd, SOL_SOCKET, SO_SNDTIMEO, (struct timeval *)&tv, sizeof(tv));

	len = sizeof(serveraddr);

	if (connect(twsfd, (struct sockaddr *)&serveraddr, len) < 0)
	{
		if (errno == EINTR)
	    {
			close(twsfd);
			return -1;
		}					
		close(twsfd);
		return -1;
	}
	else
	{
		printf("Connect Success\n");
		close(twsfd);
		return 1;
	}
	close(twsfd);
	return 1;
}

void HandleTimeOut(int signum)
{
	fprintf(stderr, "HandleTimeOut exceeded\n");
	return;
}
		
int increaseDeadCount(unsigned int _ServType, char *servname)
{
    int fFound = 0;
    int retCount = 0;

	servinfo_t *i;

	for (i = g_servinfo; strcmp(i->m_pszServName, END_OF_SHM); i = i->next)
	{
		if ((i->m_ServType == _ServType) && !strcmp(i->m_pszServName, servname)) {
			fprintf(stderr, "SERVER IP[1] : %s\n", i->m_szIpString);
			fFound = 1;
			// Sem_wait(sem_mutex);
			i->m_DeadCount++;
			fprintf(stderr, "[%s]i->m_DeadCount = %d\n", i->m_pszServName, i->m_DeadCount);
			// Sem_post(sem_mutex);
			break;
		}
	}
	retCount = i->m_DeadCount;
	return (fFound)?retCount:-1;
}

void * report_thread_update_main(void *arg)
{
	int	update_report_func();

	char * make_status_string(char *status_str);
	struct sockaddr_storage cliaddr;
	int res = 0;
	int SndBlockSize = 1024;
	socklen_t len;
	ssize_t n;

	char rcvBuff[MAXREADLINE];
	char sndBuff[128];

	/* ToDo thread : UDP connection */
	update_reportfd = Udp_server((char *)HostName, (char *)report_update_port, NULL);
	fprintf(stderr, "report serverList update thread(0) starting\n");
	
	for ( ; ; ) {
		SndBlockSize = 1024;
        len = sizeof(cliaddr);
		
		n = Recvfrom(update_reportfd, rcvBuff, MAXREADLINE, 0, (SA *)&cliaddr, &len);
		
		fprintf(stderr, "[UPDATE] receive contents : %s\n", rcvBuff);
        fprintf(stderr, "datagram from %s\n", Sock_ntop((SA *)&cliaddr, len));
        report_tptr[(int) arg].thread_count++;

		if (strncmp(rcvBuff, RequestServUpdateCmd, 19))
		{
			memset(sndBuff, 0, MaxSizeOfSndBuffer);
			snprintf(sndBuff, MaxSizeOfSndBuffer, "Invalid Argument!");
			Sendto(update_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
			continue;
		}
		
		/* Update server list from DB */
		Pthread_mutex_lock(&report_lock);
		Sem_wait(sem_mutex);
		res = update_report_func();
#if 1
fprintf(stderr , "report_thread_update_main@@@@@@@@@@@@@@\n");
#endif

		Sem_post(sem_mutex);
		Pthread_mutex_unlock(&report_lock);
		if (res == 0)
		{
			fprintf(stderr, "\nreport(update) Job Fail!!!!\n");
			strncpy(sndBuff, "FAILURE!", sizeof(sndBuff));
		}
		else
		{
			fprintf(stderr, "\nreport(update) Job Success!\n");
			strncpy(sndBuff, "SUCCESS_0222", sizeof(sndBuff));
		}
		Sendto(update_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
		fflush(stderr);
		usleep(100);
	}
}

int update_report_func()
{
	int	 get_sizeof_shm();
	void update_server_list(servinfo_t *, servinfo_t *);
	void addServerToList(servinfo_t *, MYSQL_ROW);

	MYSQL   mysql;
	MYSQL_RES *res;
	MYSQL_ROW row;

	servinfo_t	*temp_servinfo, *servinfo_head;
	servinfo_t	*init_servinfo, *start_servinfo;
	char    mysql_db[8];
	char    mysql_user[16];
	char    mysql_pass[16];

	int		fd;
	int		shm_size;
	int		mysql_port, fields;
	int		cnt;
	long	numRows;

	/* initialize mysqlDB */
    mysql_init(&mysql);

	GetProfile("MYSQL", "DATABASE_NAME", mysql_db, "CCDB");
	GetProfile("MYSQL", "DATABASE_ACCT", mysql_user, "root");
	GetProfile("MYSQL", "DATABASE_PW", mysql_pass, "alfkzmf!?{}");
	mysql_port = GetProfileInt("MYSQL", "DATABASE_PORT", 3306);
	/* connect mysql */
	if (!mysql_real_connect(&mysql, NULL, mysql_user, mysql_pass, mysql_db, mysql_port, (char *)NULL, 0))
	{
		fprintf(stderr, "%s\n", mysql_error(&mysql));
		return 0;
	}
	/* start transaction */
	mysql_autocommit(&mysql, 0);
	if (mysql_query(&mysql, MYQUERY))
	{
		fprintf(stderr, "[error]%s\n", mysql_error(&mysql));
		mysql_rollback(&mysql);
		mysql_close(&mysql);
		return 0;
	}
	else
	{
		fprintf(stderr, "%s\n", "[MySQL]Query Success!!");
		mysql_commit(&mysql);
	}

	/****************** store old SHM to Temporary ************************/
	temp_servinfo = (servinfo_t *)malloc(sizeof(servinfo_t)+128);
	memset(temp_servinfo, 0, sizeof(servinfo_t)+128);
	start_servinfo = g_servinfo;
	servinfo_head = temp_servinfo;
	while (strcmp(start_servinfo->m_pszServName, END_OF_SHM))
	{
		/* tmporary servinfo_t */
		memcpy(temp_servinfo, start_servinfo, sizeof(servinfo_t)+128);
		temp_servinfo->next = (servinfo_t *)malloc(sizeof(servinfo_t)+128);
		memset(temp_servinfo->next, 0, sizeof(servinfo_t)+128);
		temp_servinfo = temp_servinfo->next;
		start_servinfo = start_servinfo->next;
	}
	strncpy(temp_servinfo->m_pszServName, END_OF_SHM, 11);
	/********************************************************************/

	/****************** delete old SHM and create new SHM ******************/
	shm_size = get_sizeof_shm();
	munmap((void *)g_servinfo, shm_size);
	shm_unlink(SHM_NAME);
	/***********************************************************************/
	
	/****************** GET new server list from mysql *********************/
	res = mysql_store_result(&mysql);
	fields = mysql_num_fields(res);
	numRows = mysql_num_rows(res);
	fprintf(stderr, "[NEW LIST] numRows --> %ld\n", numRows);
	
	fd = Shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, FILE_MODE);
	Ftruncate(fd, (sizeof(servinfo_t)+128));
	g_servinfo = Mmap(NULL, (sizeof(servinfo_t)+128), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	memset(g_servinfo, 0, sizeof(servinfo_t)+128);
	init_servinfo = g_servinfo;
	cnt = 1;
	while((row = mysql_fetch_row(res)))
	{
		addServerToList(g_servinfo, row);
		Ftruncate(fd, (sizeof(servinfo_t)+128)*(cnt+1));
		g_servinfo->next = Mmap(NULL, (sizeof(servinfo_t)+128), PROT_READ | PROT_WRITE, MAP_SHARED, fd, (sizeof(servinfo_t)+128)*cnt);
		memset(g_servinfo->next, 0, sizeof(servinfo_t)+128);
		g_servinfo = g_servinfo->next;
		cnt++;
	}
	strncpy(g_servinfo->m_pszServName, END_OF_SHM, 11);
	g_servinfo = init_servinfo;
	Close(fd);
	/* close mysqlDB */
	mysql_free_result(res);
	mysql_close(&mysql);
	/**********************************************************************/

	/* update server list */
	update_server_list(init_servinfo, servinfo_head);

	free(temp_servinfo);
	fflush(stderr);
	return 1;
}

void update_server_list(servinfo_t *new, servinfo_t *old)
{
	servinfo_t	*ii;
	
	while (strcmp(new->m_pszServName, END_OF_SHM))
	{
		fprintf(stderr, "SERvname : %s\n", new->m_pszServName);
		for (ii = old; strcmp(ii->m_pszServName, END_OF_SHM); ii = ii->next)
		{
			if (!strcmp(new->m_pszServName, ii->m_pszServName))
			{
				memcpy((char *)&(new->ss), (char *)&(ii->ss), sizeof(struct svr_status));
				break;
			}
		}
		new = new->next;
	}
}

void * report_thread_send_main(void *arg)
{
	char * make_status_string(char *status_str);
	struct sockaddr_storage cliaddr;
	int offset;
	int nLeft, nWrite;
	int SndBlockSize = 1024;
	static char *status_str = NULL;
	char *pTmpData = NULL;
	char szLineBuffer[1024];
	socklen_t len;
	ssize_t	n;
	
	char rcvBuff[MAXREADLINE];
	char sndBuff[MaxSizeOfSndBuffer];

	fprintf(stderr, "report server list send thread(1) starting..\n");

	/* ToDo thread : UDP connection */
	send_reportfd = Udp_server((char *)HostName, (char *)report_send_port, NULL);	
	for ( ; ; )
	{
		SndBlockSize = 1024;
		len = sizeof(cliaddr);
		n = Recvfrom(send_reportfd, rcvBuff, MAXREADLINE, 0, (SA *)&cliaddr, &len);
		fprintf(stderr, "receive contents : %s\n", rcvBuff);
		fprintf(stderr, "datagram from %s\n", Sock_ntop((SA *)&cliaddr, len));
		report_tptr[(int) arg].thread_count++;
		
		if (strncmp(rcvBuff, GetServStatusCmd, 14))
		{
			memset(sndBuff, 0, MaxSizeOfSndBuffer);
			snprintf(sndBuff, MaxSizeOfSndBuffer, "Invalid Argument!");
			Sendto(send_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
			continue;			
		}
	
		/* send to SMS server */
		
		status_str = (char *)malloc(0);
		if (!status_str)
		{
			fprintf(stderr, "Cannot allocation status_str!\n");
			exit(0);
		}

		Pthread_mutex_lock(&report_lock);
		Sem_wait(sem_mutex);
		pTmpData = make_status_string(status_str);
		Sem_post(sem_mutex);
		nLeft = strlen(pTmpData);
		Pthread_mutex_unlock(&report_lock);
		
		/* view udp data */
		//fprintf(stderr, "%s(%d)\n", pTmpData, nLeft);
		fflush(stderr);
		do
		{
			offset = 0;
			memset(szLineBuffer, 0, 1024);
			if(nLeft < SndBlockSize)
				SndBlockSize = nLeft;
			
			while(offset < SndBlockSize) 
				szLineBuffer[offset++] = *pTmpData++;
			szLineBuffer[offset] = '\0';
			usleep(100);
			nWrite = sendto(send_reportfd, szLineBuffer, offset + 1, 0, (SA *)&cliaddr, len);
			nWrite -= 1;

			if(nWrite < 0)
			{
				fprintf(stderr, "Error! send to sms web. sendto : %s\n", strerror(errno));
				break;
			}
			else if(nWrite == 0)
			{
				break;
			}
			nLeft -= nWrite;

		}while(nLeft >= 0);
		free(status_str);
	}
	fflush(stderr);
}

void * vrcd_thread_main(void *arg)
{
	int				connfd;
	int				res;
	int				vrcd_func(int);
	socklen_t		clilen;
	struct sockaddr	*cliaddr;

	cliaddr = Malloc(vrcd_addrlen);

	fprintf(stderr, "vrcd thread %d starting..\n", (int) arg);
	for ( ; ; ) {
		clilen = vrcd_addrlen;
    	Pthread_mutex_lock(&vrcd_lock);
		connfd = Accept(vrcdfd, cliaddr, &clilen);
		Pthread_mutex_unlock(&vrcd_lock);
		vrcd_tptr[(int) arg].thread_count++;
		
		res = vrcd_func(connfd);
		if (res == 0)
			fprintf(stderr, "\nOne vrcd Job Success!\n");
		else
			fprintf(stderr, "\nOne vrcd Job Fail!!\n");
		
		Close(connfd);
		fflush(stderr);
		usleep(100);
	}
}

int vrcd_func(int cfd)
{
	void view_header_packet(struct common_message_header *);
	void view_serv_status_pakcet(struct svr_status *);
	void updateShm(struct svr_status *, int);
	
	struct common_message_header *cheader;
	struct svr_status *recv_serv;
	
	int nread;
	int bodylen;
	int svr_num;
	char header_buf[1024];
	char vrcd_buf[4096];
	char sndResult[32];

	if ((nread = Readn(cfd, header_buf, MaxSizeOfCMH)) == 0)
		return 1;

	fprintf(stderr, "Receive Size(header) : %d\n", nread);
	/* Casting receiving string */
	cheader = (struct common_message_header *)header_buf;

	/* view common message header */
	/* view_header_packet(cheader); */
	bodylen = ntohl(cheader->ulBodyLength);
	
	if ((nread = Readn(cfd, vrcd_buf, bodylen) == 0))
		return 1;
	
	fprintf(stderr, "\n\nReceive Size(body) : %d(%d)\n", nread, bodylen);
	/* Casting receiving string */
	svr_num = *((int *)vrcd_buf);
	recv_serv = (struct svr_status *)(vrcd_buf + sizeof(int));

	/* view body packet */
	fprintf(stderr, "server number : %d\n", svr_num);

	/*
	int i;
	for (i=0; i < svr_num; i++)
	{
		view_serv_status_pakcet(recv_serv);
		recv_serv++;
	}
	*/
	
	/* Update changed server status to Share Memory to */
	Sem_wait(sem_mutex);
	updateShm(recv_serv, svr_num);
	Sem_post(sem_mutex);

	/* Send Result */
	sprintf(sndResult, "%d", 1);
	Writen(cfd, sndResult, 32);

	fflush(stderr);	
	/* Sem_post(sem_mutex); */
	return 0;
}

void updateShm(struct svr_status *r_ss, int r_ss_num)
{
	servinfo_t *servinfo,  *ii;
	struct hostent *he = NULL;
	int i, j;
	int retval;
	int dflag;
	char *addr = NULL;

	servinfo = g_servinfo;
	for (i = 0; i < r_ss_num; i++) {
		dflag = 0;
		for (ii = servinfo; strcmp(ii->m_pszServName, END_OF_SHM); ii = ii->next) {
			//fprintf(stderr, "[SHM]domainName: %s, [packet]domain: %s\n", ii->m_pszDomainName, (r_ss + i)->du.domain);
			if (ii->m_pszDomainName != NULL) {
				if (!strcmp(ii->m_pszDomainName, (r_ss + i)->du.domain)) {
					memcpy((char *)&(ii->ss), (char *)(r_ss + i), sizeof(struct svr_status));
					dflag = 1;
				}
				if (!strcmp(ii->m_pszDomainName, (r_ss + i)->du.hostname)) {
					memcpy((char *)&(ii->ss), (char *)(r_ss + i), sizeof(struct svr_status));
					dflag = 1;
				}
			}
		}
		//fprintf(stderr, "flag = %d\n", dflag);
		if (dflag == 0)
		{
			addr = (r_ss + i)->du.hostname[0] == '\0' ? (r_ss + i)->du.domain : (r_ss + i)->du.hostname;
			fprintf(stderr, "du.hostname -> %s\n", addr);
		}
		/* Check If IP */
		if (((retval = inet_addr((r_ss + i)->du.domain)) != INADDR_NONE) && dflag == 0) {
			for (ii = servinfo; strcmp(ii->m_pszServName, END_OF_SHM); ii = ii->next) {
				if (!strcmp(ii->m_szIpString, (r_ss + i)->du.domain)) {
					strncpy(ii->m_pszDomainName, (r_ss + i)->du.domain, MAX_DOMAIN_NAME);
					memcpy((char *)&(ii->ss), (char *)(r_ss + i), sizeof(struct svr_status));
					dflag = 1;
				}
			}
		}
		/* Check If Domain */

		if (addr != NULL)
	        he = gethostbyname(addr);
		if (!he)
			continue;
		if (dflag == 0)
		{
			for (ii = servinfo; strcmp(ii->m_pszServName, END_OF_SHM); ii = ii->next)
			{
				for (j = 0; he->h_addr_list[j]; j++)
				{
					//fprintf(stderr, "IP addr of hostname : %s\n", inet_ntoa(*(struct in_addr *)he->h_addr_list[j]));
					if (!strcmp(ii->m_szIpString, inet_ntoa(*(struct in_addr *)he->h_addr_list[j])))
					{
						strncpy(ii->m_pszDomainName, addr, MAX_DOMAIN_NAME);
						memcpy((char *)&(ii->ss), (char *)(r_ss + i), sizeof(struct svr_status));
					}
				}
			}		
		}
	}	
	fflush(stderr);	
}

char *make_status_string(char *status_str)
{
	servinfo_t *servinfo_head, *i;
	
	char sztmpBuffer[1024];
	int len;
	int cnt;
	int adding=0;

	char host[128], host2[128], *p;
	cnt = 0;

	servinfo_head = g_servinfo;
	for (i = servinfo_head; i != NULL; i = i->next)
    {
		if (i->next == NULL)
			break;

		memset(sztmpBuffer, 0, 1024);
		len = snprintf(sztmpBuffer, 1024, "%d|%d|%s|%s|%d|%d|"
				,i->m_Status
				,i->m_ServType
				,i->m_pszServName
				,i->m_szIpString
				,i->m_sPort
				,i->m_StatChgTime);

		if (i->m_pszDomainName && strlen(i->m_pszDomainName) > 0) {
			if (!strcmp(i->ss.du.domain, i->ss.du.hostname) || i->ss.du.hostname[0] == '\0') 
			{
				strcpy(host, i->ss.du.domain);
			} 
			else 
			{
				strcpy(host2, i->ss.du.hostname);
				p = strchr(host2, '.');
				if (p) {
					*p = '\0';
				}
				sprintf(host, "%s(%s)", i->ss.du.domain, host2);
			}
			snprintf(sztmpBuffer + len, 1024 - len,
					"%d|%s|%llu|%llu|%d|%d|%d|%d|%d|%d|%lu|%lu|%lu|%lu|\r\n"
					,(time_t)(ntohl(i->ss.stamp))
					,host
					,(unsigned long long)(ntohl(i->ss.du.total))
					,(unsigned long long)(ntohl(i->ss.du.free))
					,(int)(ntohl(i->ss.du.manual_disable))
					,(int)(ntohl(i->ss.du.upload_level))
					,(int)(ntohl(i->ss.du.disk_backlog))
					,(int)(ntohl(i->ss.du.disk_percent))
					,(int)(ntohl(i->ss.du.connection_established))
					,(int)(ntohl(i->ss.du.connection_total))
					,(unsigned long)(ntohl(i->ss.du.traffic_ip))
					,(unsigned long)(ntohl(i->ss.du.traffic_ib))
					,(unsigned long)(ntohl(i->ss.du.traffic_op))
					,(unsigned long)ntohl(i->ss.du.traffic_ob));
		}
		else {
			snprintf(sztmpBuffer + len, 1024 - len,
					"%s", "-|-|-|-|-|-|-|-|-|-|-|-|-|-|\r\n");
		}
		/* realloc status_str */
		status_str = (char *)realloc(status_str, strlen(sztmpBuffer)+adding);
		//string = realloc(string, strlen(sztmpBuffer)*(cnt+1));
		if (!status_str)
		//if (!string)
		{
			fprintf(stderr, "Cannot reallocation heap!\n");
			exit(0);
		}			
		//strncat(status_str, sztmpBuffer, strlen(sztmpBuffer));
		memcpy(status_str + adding, sztmpBuffer, strlen(sztmpBuffer));
		adding += strlen(sztmpBuffer);
		
		//fprintf(stderr, "buff : %s(%d)\n", status_str, adding);
		cnt++;
	}
	/*
	sndSize = strlen(string);
	tmpBuffer = malloc(sndSize);
	memset(tmpBuffer, 0, sndSize);
	memcpy(tmpBuffer, string, sndSize);	
	memcpy(status_str, tmpBuffer, sndSize);
	*/
	fflush(stderr);
	//free(tmpBuffer);

	return status_str;
}

int get_sizeof_shm()
{
	struct stat stat;
	
	int memsize;
	int filed;
		
	/***        Posix Semaphore         ***/
	filed = Shm_open(SHM_NAME, O_RDWR, FILE_MODE);
	Fstat(filed, &stat);	
	Close(filed);	
	/* get size of mapping memory */
	memsize = stat.st_size;
	return memsize;
}

void SendToWebServ(const char *pszMesg)
{
	fprintf(stderr, "[MESSAGE] ::: %s\n", pszMesg);
}

void view_header_packet(struct common_message_header *cheader)
{
	/******************************************************************************/
	/**************************** View receive packet(header) *********************/
	/******************************************************************************/
	fprintf(stderr, "Transaction ID -> [ %s ]\n", cheader->szTransactionID);
	fprintf(stderr, "Mode           -> [ %u ]\n", ntohl(cheader->ulMode));
	fprintf(stderr, "Issuer         -> [ %s ]\n", cheader->szIssuer);
	fprintf(stderr, "Service ID     -> [ %s ]\n", cheader->szServiceID);
	fprintf(stderr, "Result         -> [ %u ]\n", ntohl(cheader->ulResult));
	fprintf(stderr, "Body Length    -> [ %u ]\n\n", ntohl(cheader->ulBodyLength));
	fflush(stderr);
}

void view_serv_status_pakcet(struct svr_status *recv_serv)
{
	/******************************************************************************/
	/**************************** View receive packet(body) ***********************/
	/******************************************************************************/
	fprintf(stderr, "Time stamp     -> [ %u ]\n", ntohl(recv_serv->stamp));
	fprintf(stderr, "Domain         -> [ %s ]\n", recv_serv->du.domain);
	fprintf(stderr, "Total          -> [ %u ]\n", ntohl(recv_serv->du.total));
	fprintf(stderr, "Free           -> [ %u ]\n", ntohl(recv_serv->du.free));
	fprintf(stderr, "Manual y/n     -> [ %d ]\n", ntohl(recv_serv->du.manual_disable));
	fprintf(stderr, "upload level   -> [ %d ]\n", ntohl(recv_serv->du.upload_level));
	fprintf(stderr, "disk backlog   -> [ %d ]\n", ntohl(recv_serv->du.disk_backlog));
	fprintf(stderr, "disk percent   -> [ %d ]\n", ntohl(recv_serv->du.disk_percent));
	fprintf(stderr, "conn establish -> [ %d ]\n", ntohl(recv_serv->du.connection_established));
	fprintf(stderr, "conn total     -> [ %d ]\n", ntohl(recv_serv->du.connection_total));
	fprintf(stderr, "traffic ip     -> [ %u ]\n", ntohl(recv_serv->du.traffic_ip));
	fprintf(stderr, "traffic ib     -> [ %u ]\n", ntohl(recv_serv->du.traffic_ib));
	fprintf(stderr, "traffic op     -> [ %u ]\n", ntohl(recv_serv->du.traffic_op));
	fprintf(stderr, "traffic ob     -> [ %u ]\n", ntohl(recv_serv->du.traffic_ob));
	fprintf(stderr, "Hostname       -> [ %s ]\n\n", recv_serv->du.hostname);
	fflush(stderr);
}

void view_rcmng_header_packet(rcmng_cheader_t *cheader)
{
	fprintf(stderr, "***************** Common Header *******************\n");
	fprintf(stderr, "RCID : %s\n", cheader->rcmng_rcid);
	fprintf(stderr, "SERVER NAME : %s\n", cheader->rcmng_servName);
	fprintf(stderr, "SERVICE TYPE : %d\n", cheader->rcmng_serviceType);
	fprintf(stderr, "BODY LENGTH : %lu\n", cheader->bodylength);
	fprintf(stderr, "***************************************************\n");
}

void view_servinfo_t_packet(servinfo_t *ch_server)
{
	fprintf(stderr, "***************** Server info Body ****************\n");
	fprintf(stderr, "SERVER NAME : %s\n", ch_server->m_pszServName);
	fprintf(stderr, "IP Address : %s\n", ch_server->m_szIpString);
	fprintf(stderr, "PORT : %d\n", ch_server->m_sPort);
	fprintf(stderr, "SERVER TYPE : %d\n", ch_server->m_ServType);
	fprintf(stderr, "Dead Count : %d\n", ch_server->m_DeadCount);
	fprintf(stderr, "Monitoring Y/N : %s\n", ch_server->m_monitorYN);
	fprintf(stderr, "***************************************************\n");
}
