#include "check_neocast.h"
#include "protocol.h"
#include "cfgconfig.h"
#include "util.h"
#include <signal.h>
#include <sys/wait.h>
#include <sys/signal.h>

extern int dig_func(int , char **, int *, int *);
extern int Tcp_connect(const char *, const char *);
extern void Send(int, const void *, size_t, int);
extern ssize_t Recv(int, void *, size_t, int);

static char hexchars[] = "0123456789ABCDEF";

void safe_wait()
{
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 100;
	select(0, NULL, NULL, NULL, &tv);
}

#define STAT_STAMP(a)     (((a) + (stat_term - 1)) / stat_term)
void loop_check()
{
	int ret_val = 0;
	int stat_term;
	time_t now, past;
	unsigned long past_stamp = 0;
	unsigned long now_stamp = 0;

	SetIniName(CFGFILE);
	stat_term = GetProfileInt("STAT_TERM", 60);

	now = past = time(NULL);
	now_stamp = past_stamp = STAT_STAMP(now);

	for( ; ; ) {
		now = time(NULL);
		now_stamp = STAT_STAMP(now);

		if (past != now) {
			// whenever 1 minutes (60 seconds)
			ret_val = check_neocast(now, &now_stamp, &past_stamp);
			if (ret_val == 1)
			{
				past = now = time(NULL);
				now_stamp = past_stamp = STAT_STAMP(now);
			}
		}
		safe_wait();
	}
}

int check_neocast(time_t now, unsigned long *now_stamp, unsigned long *past_stamp)
{
	FILE *shLogFile = NULL;
	struct tm *t;
	neo_serv_info *nserv_info, *temp_info;
	MYSQL   mysql, child_mysql;
	MYSQL_RES *res;
	MYSQL_ROW row;

	int		i;
	int     mysql_port, fields;
	long    numRows;
	long	cnt = 0;
	char    mysql_db[8];
	char    mysql_user[16];	
	char    mysql_pass[16];

	char    logString[1024];

	/* check time */
    if (*now_stamp == *past_stamp)
		return 0;

	/* sh log file open */
	shLogFile = fopen(makeLogString(), "a");
	if (!shLogFile)
	{
		fprintf(stderr, "Cannot open SH Log file!!\n");
		exit(EXIT_FAILURE);
	}

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

	// get mysql info
	SetIniName(CFGFILE);

	GetProfile("DATABASE_NAME", mysql_db, "CCDB");
	GetProfile("DATABASE_ACCT", mysql_user, "root");
	GetProfile("DATABASE_PW", mysql_pass, "alfkzmf!?{}");
	mysql_port = GetProfileInt("DATABASE_PORT", 3306);

	fprintf(stderr, "DATABASE_NAME : %s\n", mysql_db);
	fprintf(stderr, "DATABASE_ACCT : %s\n", mysql_user);
	fprintf(stderr, "DATABASE_PW : %s\n", mysql_pass);
	fprintf(stderr, "DATABASE_PORT : %d\n", mysql_port);

	/* connect mysqlDB */
	if (!mysql_real_connect(&mysql, NULL, mysql_user, mysql_pass, mysql_db, mysql_port, (char *)NULL, 0))
	{
		fprintf(stderr, "parent mysql: %s\n", mysql_error(&mysql));
		snprintf(logString, 1024, "%s", mysql_error(&mysql));
		WriteSHLog(logString, shLogFile);
		exit(EXIT_FAILURE);
	}
	if (!mysql_real_connect(&child_mysql, NULL, mysql_user, mysql_pass, mysql_db, mysql_port, (char *)NULL, 0))
	{
		fprintf(stderr, "%s\n", mysql_error(&child_mysql));
		snprintf(logString, 1024, "child mysql: %s", mysql_error(&child_mysql));
		WriteSHLog(logString, shLogFile);
		exit(EXIT_FAILURE);
	}
	/***********************************************************************************************************/
	/* autocommit on */
	mysql_autocommit(&child_mysql, 1);

	snprintf(logString, 1024, "Query to get arranged Server List :: %s", MYQUERY);
	WriteSHLog(logString, shLogFile);

	if (mysql_query(&mysql, MYQUERY) < 0)
	{
		snprintf(logString, 1024, "[error]%s", mysql_error(&mysql));
		WriteSHLog(logString, shLogFile);
		exit(EXIT_FAILURE);
	}
	else
	{
		snprintf(logString, 1024, "%s", "[MySQL]Server List Loading Success!!");
		WriteSHLog(logString, shLogFile);
	}
	res = mysql_store_result(&mysql);
	fields = mysql_num_fields(res);
	numRows = mysql_num_rows(res);

	snprintf(logString, 1024, "numRows --> %ld", numRows);
	WriteSHLog(logString, shLogFile);

	neo_serv_num = numRows;
	nserv_info = (neo_serv_info *)malloc(sizeof(neo_serv_info));
	temp_info = nserv_info;
	
	while((row = mysql_fetch_row(res)))
	{
		memset(temp_info, 0, sizeof(temp_info));
		temp_info->neo_seq	= atol(row[0]);
		strncpy(temp_info->name, row[1], MaxSizeOfServerName);
		strncpy(temp_info->domain, row[2], MaxSizeOfServerAddr);
		strncpy(temp_info->dig_domain, row[3], MaxSizeOfServerAddr);
		strncpy(temp_info->ipaddr, row[4], MaxSizeOfServerIp);
		strncpy(temp_info->type ,row[5], MaxSizeOfServerType);
		temp_info->port = atoi(row[6]);
		temp_info->dead_count = atoi(row[7]);
		temp_info->status = atoi(row[8]);
		temp_info->next = NULL;

		temp_info->next = (neo_serv_info *)malloc(sizeof(neo_serv_info));
		temp_info = temp_info->next;
	}
	temp_info = NULL;

	temp_info = nserv_info;
	for (cnt = 0; cnt < neo_serv_num; cnt++)
    {
		pid_t dpid;
		int status = 0;
		// check neocast STAT
		if (!strcmp(temp_info->type, "STAT"))
		{
			char buf[1024];
			int result;

			// CHG 2010-10-21 huibong KT -> X-CDN
			//sprintf(buf, "wget -T 10 -t 2 -q \"http://222.122.18.6/neo_status\" -O /root/neo_status");
			sprintf(buf, "wget -T 10 -t 2 -q \"http://www.x-cdn.com/neo_status\" -O /root/neo_status");
			
			WriteSHLog(buf, shLogFile);
			result = system(buf);

			if (result == 0)
			{
				FILE *fp = NULL;
				char update_query[1024];
				char msgStr[1024];
				
				sprintf(buf, "/root/neo_status");
				if ((fp = fopen(buf, "r")))
				{
					memset(buf, 0, 4);
					fread(buf, 1, 3, fp);

					if (buf[0] == 'O') {	// wget success
						WriteSHLog("[STAT SUCCESS!]", shLogFile);
						
						if (temp_info->status == 2 || temp_info->dead_count > 0) {
							snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = 0, status = 1, update_datetime = now() WHERE neo_seq = %ld", temp_info->neo_seq);
							
							WriteSHLog(update_query, shLogFile);
							if (mysql_query(&child_mysql, update_query) != 0)
							{
								snprintf(logString, 1024, "[error]%s", mysql_error(&child_mysql));
								WriteSHLog(logString, shLogFile);
								exit(EXIT_FAILURE);
							}
							else
							{
								snprintf(logString, 1024, "%s", "Update STAT query Success!!");
								WriteSHLog(logString, shLogFile);
							}
							
							// SMS BACK and SendToWebServ
							if (temp_info->status == 2) {
								snprintf(msgStr, MaxSizeOfsmsStr, "[NEO][BACK] STAT IS BACK!");
								SendToWebServ(msgStr, shLogFile);
							}

						}
					}
					else if (buf[0] == 'E') {
						WriteSHLog("[!STAT FAIL]", shLogFile);
						// SMS DEAD and SendToWebServ
						if (temp_info->dead_count >= MAX_ALLOWED_DEAD_COUNT && ((int)temp_info->dead_count < MAX_ALLOWED_DEAD_COUNT + 5)) {
							snprintf(msgStr, MaxSizeOfsmsStr, "[NEO][DEAD] STAT IS ERROR!!");
		                    snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = %d, status = 2, update_datetime = now() WHERE neo_seq = %ld", temp_info->dead_count + 1, temp_info->neo_seq);
	        	            SendToWebServ(msgStr, shLogFile);
						}
						else {
							// SMS DEAD but not SendToWebServ
							snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = %d, update_datetime = now() WHERE neo_seq = %ld", temp_info->dead_count + 1, temp_info->neo_seq);
						}
						WriteSHLog(update_query, shLogFile);
						if (mysql_query(&child_mysql, update_query) != 0)
						{
							snprintf(logString, 1024, "[error]%s", mysql_error(&child_mysql));
							WriteSHLog(logString, shLogFile);
							exit(EXIT_FAILURE);
						}
						else
						{
							snprintf(logString, 1024, "%s", "Update STAT query Success!!");
							WriteSHLog(logString, shLogFile);
						}
					}
				}
				if (fp)
					fclose(fp);
			}
		}
		signal(SIGCHLD, SIG_DFL);

		dpid = fork();
		// child must process dig func
		if (dpid == 0)
		{
			int i;
			char dig_cmd[1024];
			char update_query[1024];
			char msgStr[1024];
			char *paraop[512];
			int qrcount = 0;
			int ancount = 0;
			int retval = 0;

			if (!strcmp(temp_info->type, "STAT"))
			{
				fclose(shLogFile);
				exit(EXIT_SUCCESS);
			}

			setproctitle("grandchildren: working for digging...");
			snprintf(dig_cmd, 1024, "dig @%s %s", temp_info->domain, temp_info->dig_domain);
			WriteSHLog(dig_cmd, shLogFile);
			paraop[0] = (char *)malloc(512);
			paraop[1] = (char *)malloc(512);
			paraop[2] = (char *)malloc(512);
			memset(paraop[0], 0, 512);
			memset(paraop[1], 0, 512);
			memset(paraop[2], 0, 512);

			strncpy(paraop[0], "dig", 512);
			snprintf(paraop[1], 512, "@%s", temp_info->domain);
			strncpy(paraop[2], temp_info->dig_domain, 512);

			retval = dig_func(3, paraop, &qrcount, &ancount);

			/* three case */
			/* fail : invaild dns name : retval = -1, ancount = 0 */
			/*fail : invalid domain name, query timout : retval = 0, ancount = 0 */
			/* success : retval = 0, ancount >= 1*/
			snprintf(logString, 1024, "dig result : QUERY: %d, ANSWER: %d", qrcount, ancount);
			WriteSHLog(logString, shLogFile);

			if (retval == -1 || (qrcount == 0 && ancount == 0))
			{
				//if (temp_info->dead_count >= MAX_ALLOWED_DEAD_COUNT && ((int)temp_info->dead_count < MAX_ALLOWED_DEAD_COUNT + 5)) {
				//modify sindong .... 09/12/31
				if (temp_info->dead_count >= 0 && ((int)temp_info->dead_count < MAX_ALLOWED_DEAD_COUNT + 5)) {
					// SMS DEAD and SendToWebServ
					snprintf(msgStr, MaxSizeOfsmsStr, "[NEO][DEAD] %s \n", dig_cmd);
					snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = %d, status = 2, update_datetime = now() WHERE neo_seq = %ld",
							temp_info->dead_count + 1, temp_info->neo_seq);
					SendToWebServ(msgStr, shLogFile);
				}
				else {
					// SMS DEAD but not SendToWebServ
					snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = %d, update_datetime = now() WHERE neo_seq = %ld",
						temp_info->dead_count + 1, temp_info->neo_seq);
				}
			}
			else if (qrcount >= 1 && ancount >= 1)
			{
				if (temp_info->status == 2)
				{
					snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = 0, status = 1, update_datetime = now() WHERE neo_seq = %ld", temp_info->neo_seq);
					// SMS BACK and SendToWebServ
					snprintf(msgStr, MaxSizeOfsmsStr, "[NEO][BACK] %s \n", dig_cmd);
					SendToWebServ(msgStr, shLogFile);
				}
				else if (temp_info->status == 1 && temp_info->dead_count == 0)
					goto free_exit;
				else
					snprintf(update_query, 1024, "UPDATE t_neo_server_index SET dead_count = 0, status = 1, update_datetime = now() WHERE neo_seq = %ld", temp_info->neo_seq);
			}
			else
				goto free_exit;

			WriteSHLog(update_query, shLogFile);
			if (mysql_query(&child_mysql, update_query) != 0)
			{
				snprintf(logString, 1024, "[error]%s", mysql_error(&child_mysql));
				WriteSHLog(logString, shLogFile);
				exit(EXIT_FAILURE);
			}
			else
			{
				snprintf(logString, 1024, "%s", "Update DIG query Success!!");
				WriteSHLog(logString, shLogFile);
			}
free_exit:
			for (i=0; i < 3; i++)
	            free(paraop[i]);

			exit(EXIT_SUCCESS);
		}
		wait(&status);
		temp_info = temp_info->next;
		usleep(1);
	}
	WriteSHLog("----------------------------------------------------- end ---------------------------------------------\n", shLogFile);
	*past_stamp = *now_stamp;
	mysql_free_result(res);
	mysql_close(&mysql);
	mysql_close(&child_mysql);
	fclose(shLogFile);
	for (i=0; i < neo_serv_num; i++)
	{
		free(nserv_info);
		nserv_info = nserv_info->next;
	}
	free(nserv_info);

	return 1;
}

// CHG 2010-10-20 huibong KT -> X-CDN
//#define SMSServAddr           "222.122.136.110"
//#define SMSServerHost         "sh.0x31.com"
//#define SMSServPort           "80"
//#define MaxSizeOfTRxBuffer    1024

#define SMSServAddr           "www.x-cdn.com"
#define SMSServerHost         "gms.x-cdn.com"
#define SMSServPort           "8080"
#define MaxSizeOfTRxBuffer    1024


void SendToWebServ(const char *pszMesg, FILE *shLogFile)
{
    char *PostDataEncode(const char *);

    char *strURI;
    char szSndBuffer[MaxSizeOfTRxBuffer];
    char szRcvBuffer[MaxSizeOfTRxBuffer];
    char logString[1024];
	char sms_admin[32];

    int fd, n, k, param_num;

    bzero(szSndBuffer, MaxSizeOfTRxBuffer);
    bzero(szRcvBuffer, MaxSizeOfTRxBuffer);

    strURI = PostDataEncode(pszMesg);

	SetIniName(CFGFILE);
	GetProfile("SMS_ADMIN", sms_admin, "ADMIN");
    snprintf(szSndBuffer, MaxSizeOfTRxBuffer, "GET /sms/send_sms.html?id=%s&msg=%s HTTP/1.0\n"\
            "Content-Type: text/plain\n"\
            "User-Agent: SeanZilla/1.0\n"\
            "Host: %s\n"\
            "Connection: close\n"\
            "Cache-Control: no-cache\n\n"
            , sms_admin, strURI, SMSServerHost);

	snprintf(logString, 1024, "[SMS Result]::id=%s :: msg=%s", sms_admin, pszMesg);
    WriteSHLog(logString, shLogFile);

    /* tcp connection, send, receive */
    fd = Tcp_connect(SMSServAddr, SMSServPort);
    /* send sndMessage to SMS WEB SERV */
    Send(fd, szSndBuffer, strlen(szSndBuffer), 0);
    usleep(1);
    /* receive result from new sh_statusd */
    if ( (n = Recv(fd, szRcvBuffer, strlen(szRcvBuffer), 0)) == 0)
    {
#if 0
        snprintf(logString, 1024, "[SMS] server : %s", strURI);
        WriteSHLog(logString, shLogFile);
#endif
    }
    free(strURI);
    close(fd);
}

char *PostDataEncode(const char *pszCommand)
{
    int i = 0;
    char tmpBuffer[MaxSizeOfTRxBuffer];
    static char *strReturn;

    if(pszCommand == NULL)
    {
        return NULL;
    }

    while(*pszCommand != '\0')
    {
        if(*pszCommand == ' ')
        {
            tmpBuffer[i++] = '+';
            *pszCommand++;
        }
        else if((*pszCommand < '0' && *pszCommand != '-' && *pszCommand != '.' && *pszCommand !='%') ||
                (*pszCommand < 'A' && *pszCommand > '9' && *pszCommand !='%') ||
                (*pszCommand > 'Z' && *pszCommand < 'a' && *pszCommand != '_' && *pszCommand !='%') ||
                (*pszCommand > 'z' && *pszCommand !='%'))
        {
            tmpBuffer[i++] = '%';
            tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand >> 4];
            tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand & 15];
            *pszCommand++;
        }
        else if(*pszCommand == '%')
        {
            tmpBuffer[i++] = '%';
            tmpBuffer[i++] = '%';
            *pszCommand++;
        }
        else
        {
            tmpBuffer[i++] = *pszCommand++;
        }
    }
    tmpBuffer[i] = '\0';

    // allocate heap
    strReturn = (char *)malloc(strlen(tmpBuffer));
    memset(strReturn, 0, strlen(tmpBuffer));
    strncpy(strReturn, tmpBuffer, strlen(tmpBuffer)+1);
    return strReturn;
}
