/* OpenWebSpider
*
 *  Authors:     Stefano Alimonti AND Stefano Fantin
 *  Version:     0.8
 *  E-Mails:     shen139 [at] openwebspider (dot) org AND stefanofantinguz@yahoo.it
*
*
* This file is part of OpenWebSpider
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*/

#ifndef __MISC
#define __MISC

/* --- INIZIO ESTENSIONE HTTPS / SSL --- */
#include <openssl/ssl.h>
#include <openssl/err.h>

/*
 * Contesto SSL globale usato da tutte le connessioni HTTPS.
 * Deve essere inizializzato UNA SOLA VOLTA all'avvio del crawler
 * e rilasciato al termine.
 */
extern SSL_CTX *g_ssl_ctx;
extern int gDb2FatalError;

/*
 * Inizializza la libreria OpenSSL e crea un SSL_CTX client.
 * Ritorna 1 in caso di successo, 0 in caso di errore.
 */
int InitSSL(void)
{
    if (g_ssl_ctx != NULL) {
        /* Già inizializzato */
        return 1;
    }

    /* Inizializzazione "classica" di OpenSSL (compatibile anche con 1.0.x) */
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();

    g_ssl_ctx = SSL_CTX_new(TLS_client_method());
    if (!g_ssl_ctx) {
        fprintf(stderr, "ERROR\r\nFailed to initialize SSL_CTX\r\n");
        ERR_print_errors_fp(stderr);
        return 0;
    }

    /* Opzionale: disabilita protocolli obsoleti */
    SSL_CTX_set_options(g_ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);

    return 1;
}

/*
 * Libera il contesto SSL globale e pulisce le strutture OpenSSL.
 * Va chiamata una sola volta quando si esce dal programma.
 */
void CleanupSSL(void)
{
    if (g_ssl_ctx) {
        SSL_CTX_free(g_ssl_ctx);
        g_ssl_ctx = NULL;
    }

    EVP_cleanup();
    ERR_free_strings();
}
/* --- FINE ESTENSIONE HTTPS / SSL --- */

#ifndef WIN32

int GetTickCount()
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec*1000L+tv.tv_usec/1000L;
}

void SetConsoleTitle(char* msg)
{
	return;
}

int stricmp(const char*a,const char*b)
{
	return strcasecmp(a,b);
}

int strnicmp(const char*a,const char*b,int c)
{
	return strncasecmp(a,b,c);
}

void Sleep(int n)
{
	usleep((unsigned)n*1000);	
	return;
}

char* _strupr(char*a)
{
	int m,i;
	m=strlen(a);
	
	for(i=0;i<m;i++)
		a[i]=(char)toupper(a[i]);
	
	return a;
}

char* _strlwr(char*a)
{
	int m,i;
	m=strlen(a);
	
	for(i=0;i<m;i++)
		a[i]=(char)tolower(a[i]);
	
	return a;
}

int closesocket(int s)
{
	return close(s);
}

int ExitThread(int a)
{
	pthread_exit(&a);
}

int TerminateThread(pthread_t thread,int nothing)
{
	return pthread_cancel(thread);
}

void CloseHandle(HANDLE a)
{
	return;
}

#endif

int InitMysql()
{
	SetConsoleTitle("Connecting to mysql...");
	
	printf("Connecting to Mysql server n.1 (%s)...",MYSQLSERVER1);                 //Hosts
	if(sqlConnect(MYSQLSERVER1, USERDB1, PASSDB1, DB1,&gMysqlDB1, MYSQLSERVER_PORT1)==0)
	{
		fprintf(stderr, "ERROR\r\nFailed to connect to database(%s): Error: %s\r\n",DB1,mysql_error(&gMysqlDB1));
		
		ERROR_LOG(mysql_error(&gMysqlDB1))
			return -1;
	}
	
	printf("OK\r\nConnecting to Mysql server n.2 (%s)...",MYSQLSERVER2);           //Pages
	if(sqlConnect(MYSQLSERVER2, USERDB2, PASSDB2, DB2,&gMysqlDB2, MYSQLSERVER_PORT2)==0)
	{
		fprintf(stderr, "ERROR\r\nFailed to connect to database(%s): Error: %s\r\n",DB2,mysql_error(&gMysqlDB2));
		
		ERROR_LOG(mysql_error(&gMysqlDB2))
			
			mysql_close(&gMysqlDB2);
		return -1;
	}
	
	printf("OK\r\n");
	SetConsoleTitle("Connecting to mysql...OK");

return 1;
}

int InitCrawler(struct sHost currentHst)
{
	memset(iLastPing,0,sizeof(iLastPing));

	printf("\r\n");
	printf("Start Host        : %s\r\n",currentHst.Host);
	printf("Start Page        : %s\r\n", currentHst.Page);
	printf("Scan Mode         : Index\r\n");
	printf("Mode              : %s\r\n",(starthostonly==1)?"Single Host":"Recursive");
	printf("Mysql server n.1  : %s\r\n",MYSQLSERVER1);
	printf("Mysql server n.2  : %s\r\n",MYSQLSERVER2);
    printf(" ---  Global Limits  ---\r\n");
    printf("Max pages         : %i\r\n",CRAWLER_LIMITS.nMaxPagesPerSite);
	printf("Max depth level   : %i\r\n",CRAWLER_LIMITS.nMaxDepthLevel);
    printf("Max seconds       : %i\r\n",CRAWLER_LIMITS.nMaxSecondsPerSite);
	printf("Max bytes         : %llu\r\n",(unsigned long long)CRAWLER_LIMITS.nMaxBytesPerSite);
    printf(" -----------------------\r\n");
	printf("Surfing the net... (press CTRL+C to exit)\r\n");
	printf("Crawler profile   : %s discovery (%s)\r\n",
	       bAggressiveIndexMode ? "wide" : "fast",
	       bAggressiveIndexMode ? "crawler_profile.log" : "attachments scan optimized");
	
	
	if(actAsAServerPort)
	{
		CreateServerThread(actAsAServerPort);
		Sleep(200);
	}

    /*
     * Inizializza la libreria SSL/TLS PRIMA di creare i thread
     * e PRIMA di fare qualsiasi connessione HTTP/HTTPS.
     */
    if (!InitSSL())
    {
        fprintf(stderr,"Error while initializing SSL library\r\n");
        ERROR_LOG("Error while initializing SSL library")
        return -1;
    }
    
    if(!StartUpWinsock())
	{
		fprintf(stderr,"WSAStartup() error\r\n");
		ERROR_LOG("WSAStartup() error")
			return -1;
	}
	
	/* connect to mysql servers */
	if(InitMysql()==-1)
		return -1;
	
	SetConsoleTitle("Creating temp table...");
	
	do
	{
		RandomTable(gTable);
	}
	while(!CreateTmpTable(gTable));    //Loop until creates a new tmp table!!!

   	signal(SIGINT,  sigdie);
	signal(SIGTERM, sigdie);


return 1;
}

int setHostExtras(int host_id)
{
char sqlQuery[MAXQUERYSIZE];
MYSQL_ROW row;
MYSQL_RES gRes;
MYSQL_RES** tmpRes=NULL;

    tmpRes=(MYSQL_RES**)malloc(sizeof(MYSQL_RES));
	
	if(tmpRes==NULL)
		MemoryCorruptedHandler("setHostExtras");

    sprintf(sqlQuery,"select hostlist_extras.max_pages,hostlist_extras.max_level,hostlist_extras.max_seconds, hostlist_extras.max_bytes from hostlist left outer join hostlist_extras on hostlist.id = hostlist_extras.host_id WHERE hostlist.id = %d ", host_id);
	
	my_mysql_query_and_store_results(&gMysqlDB1, sqlQuery, tmpRes, &gRes, BLOCKDB1);

    if((row = mysql_fetch_row(&gRes)))
	{
		if(row[0])  /* max_pages */
        {
            if( atoi(row[0]) > 0 )
            {
                EXTRA_LIMITS.nMaxPagesPerSite = atoi(row[0]);
            }
        }

        if(row[1])  /* max_level */
        {
            if( atoi(row[1]) > 0 )
            {
                EXTRA_LIMITS.nMaxDepthLevel = atoi(row[1]);
            }
        }

        if(row[2])  /* max_seconds */
        {
            if( atoi(row[2]) > 0 )
            {
                EXTRA_LIMITS.nMaxSecondsPerSite = atoi(row[2]);
            }
        }

        if(row[3])  /* max_bytes */
        {
            if( atoi(row[3]) > 0 )
            {
                EXTRA_LIMITS.nMaxBytesPerSite = strtoull(row[3], NULL, 10);
            }
        }
	}

    if(*tmpRes)
	{
		mysql_free_result(*tmpRes);
	}
	
	FREE(tmpRes);

return 1;
}

int CrawlerMainLoop(struct sHost currentHst)
{
    /*
     * scan_mode:
     *   1 => Index (modalità -i, singolo host)
     *   2 => Spider (e altre modalità “da DB”)
     *
     * In modalità Index vogliamo SOLO indicizzare l’host che arriva da main()
     * e poi uscire, senza pescare altri host/URL dal DB.
     * Questo evita i loop su :443 con [RECV ERROR] e
     * "Error while calculating HostRank" ripetuti.
     */

    if (scan_mode == 1) {
        /* Modalità -i: indicizza solo currentHst una volta */
        InitIndexing(currentHst);
        DoQuit();
        return 0;
    }

    /* Modalità "crawler" classica: usa ancora ReturnFirstUrl() */
    InitIndexing(currentHst);

    while (1) {
        if (ReturnFirstUrl(&currentHst) == -1) {
            break;
        }

        if (iQuit) {
            break;
        }

        InitIndexing(currentHst);
    }

    DoQuit();
    return 0;
}


int InitIndexing(struct sHost currentHst)
{
	int condition = 1;
	char* sqlQuery;
	DWORD avgSec;
	time_t long_time;
	struct tm *newtime;
	struct sHost *robots_txt;
	
#ifdef WIN32
	char strTitle[3000];
#endif
	
    iRobCrawlDelay  = 0;
    bRobotsOK       = 0;
    nPagesViewed    = 0;
	bytesDownloaded = 0;
	nErrorPages     = 0;
	startTimeMS     = 0;
    bKillThread     = 0;
    avgSec          = 0;
    EXTRA_LIMITS.nMaxBytesPerSite   = 0;
    EXTRA_LIMITS.nMaxDepthLevel     = 0;
    EXTRA_LIMITS.nMaxPagesPerSite   = 0;
    EXTRA_LIMITS.nMaxSecondsPerSite = 0;
    gProfileDiscoveredTotal = 0;
    gProfileAcceptedTotal = 0;
    gProfileAssetCandidates = 0;
    gProfileDynamicCandidates = 0;
    gProfileCrossHostDiscovered = 0;
    gProfileAssetDepthBypass = 0;
    gProfileExternalAssetsQueued = 0;
    gProfileRawAssetCandidates = 0;
    gProfileCandidateRejectedEmpty = 0;
    gProfileCandidateRejectedNotAsset = 0;
    gProfileCandidateRejectedParse = 0;
    gProfileCandidateRejectedToken = 0;
    gProfileCandidateRejectedType = 0;
    gProfileRejectedRobots = 0;
    gProfileRejectedLimits = 0;
    gProfileRejectedDepth = 0;
    gProfileRejectedSwitch = 0;
    gProfileRejectedDuplicate = 0;
    gProfileQueuedTypeHtml = 0;
    gProfileQueuedTypePlain = 0;
    gProfileQueuedTypeAsset = 0;
    gProfileQueuedTypeOther = 0;
    gProfileSourceTag = 0;
    gProfileSourceSrcset = 0;
    gProfileSourceLoose = 0;
    gProfileSourceBare = 0;
    gProfileSourceHeader = 0;
    gProfileSourceSitemap = 0;
    gProfileSourceSeed = 0;
    gProfileHttpOk = 0;
    gProfileHttpRedirect = 0;
    gProfileHttpError = 0;
    gProfileMimeHtml = 0;
    gProfileMimeXml = 0;
    gProfileMimeJson = 0;
    gProfileMimeCssJs = 0;
    gProfileMimePdf = 0;
    gProfileMimeImage = 0;
    gProfileMimeVideo = 0;
    gProfileMimeAudio = 0;
    gProfileMimeOther = 0;
    gProfileQualityWarnings = 0;
	memset(lstRobotsExclusions,0,sizeof(lstRobotsExclusions));
	{
		char profileMsg[2048];
		snprintf(profileMsg,sizeof(profileMsg),
                         "profile start host=%.100s page=%.255s mode=%s max_pages=%u max_depth=%u max_seconds=%u max_bytes=%llu",
		         currentHst.Host,
		         currentHst.Page,
		         (starthostonly==1) ? "single" : "recursive",
		         CRAWLER_LIMITS.nMaxPagesPerSite,
		         CRAWLER_LIMITS.nMaxDepthLevel,
		         CRAWLER_LIMITS.nMaxSecondsPerSite,
                         (unsigned long long)CRAWLER_LIMITS.nMaxBytesPerSite);
		CRAWLER_PROFILE_LOG(profileMsg);
	}

	sqlQuery = malloc(MAXQUERYSIZE);
	if(sqlQuery==NULL)
		MemoryCorruptedHandler("InitIndexing");

    /* try to free the memory used */
    lstFreeAll(lstFirst);

	
    /* does this host exist? */
    if( currentHst.host_id == 0 )
        currentHst.host_id = GetHostId( currentHst );

    if( currentHst.host_id == 0)   //no
	    //puts current hostname in the db as "Scanning host in progress.." (viewed==2)
		sprintf(sqlQuery,"INSERT INTO hostlist (hostname, port, status, lastvisit) VALUES('%s', %i, 2, curdate());", currentHst.Host, currentHst.port);
	else    //yes
        sprintf(sqlQuery,"UPDATE hostlist SET port=%i, status = 2, lastvisit=curdate() WHERE hostname =\'%s\' limit 1", currentHst.port, currentHst.Host);
		
	
	my_mysql_query(&gMysqlDB1, sqlQuery,NO_BLOCK);
	
    /* 8legs mod */
    if( currentHst.host_id == 0 )
	    currentHst.host_id	= GetHostId( currentHst );

    robots_txt=(struct sHost*)malloc(sizeof(struct sHost));
	
	if(robots_txt==NULL)
		MemoryCorruptedHandler("InitIndexing");
	
	currentHst.viewed = 0;
	memcpy(robots_txt,&currentHst,sizeof(struct sHost));
	strcpy(robots_txt->Page, "/robots.txt");
	robots_txt->level = 1;
	robots_txt->type  = 1;
    robots_txt->host_id = currentHst.host_id;

	lstFirst = lstInit(*robots_txt);
	
	FREE(robots_txt);
	
	currentHst.level = 1;
	lstAddHost(&lstFirst,currentHst);

	{
		static const char *profileSeeds[] = {
				"/sitemap.xml",
				"/sitemaps.xml",
				"/sitemap_index.xml",
				"/sitemap-index.xml",
				"/sitemap1.xml",
				"/sitemap_1.xml",
				"/sitemap-1.xml",
				"/sitemap-index-1.xml",
				"/wp-sitemap.xml",
				"/post-sitemap.xml",
				"/page-sitemap.xml",
				"/category-sitemap.xml",
				"/product-sitemap.xml",
				"/attachment-sitemap.xml",
				"/image-sitemap.xml",
				"/video-sitemap.xml",
				"/news-sitemap.xml",
				"/media-sitemap.xml",
				"/uploads-sitemap.xml",
				"/feed",
				"/feed/",
				"/feeds",
				"/feeds/",
				"/rss",
				"/rss.xml",
				"/atom.xml",
				"/index.xml",
				"/opensearch.xml",
				"/manifest.json",
				"/site.webmanifest",
				"/manifest.webmanifest",
				"/.well-known/assetlinks.json",
				"/.well-known/apple-app-site-association",
				"/browserconfig.xml",
				"/humans.txt",
				"/ads.txt",
				"/app-ads.txt",
				"/uploads/",
				"/upload/",
				"/media/",
				"/assets/",
				"/asset/",
				"/static/",
				"/files/",
				"/file/",
				"/downloads/",
				"/download/",
				"/wp-content/uploads/",
				"/wp-content/plugins/",
				"/wp-content/themes/",
				"\0"
			};
		int seedIndex;
		for(seedIndex=0; profileSeeds[seedIndex][0] != '\0'; seedIndex++)
		{
			struct sHost seedHost;
			memcpy(&seedHost,&currentHst,sizeof(struct sHost));
			strncpy(seedHost.Page, profileSeeds[seedIndex], MAXPAGESIZE-1);
			seedHost.Page[MAXPAGESIZE-1] = '\0';
			seedHost.level = 1;
			seedHost.viewed = 0;
			PageType(&seedHost);
			if(lstGetNodeByHost(lstFirst,seedHost)==NULL)
			{
				char profileMsg[1024];
				lstAddHost(&lstFirst,seedHost);
				gProfileSourceSeed++;
				gProfileAcceptedTotal++;
				snprintf(profileMsg,sizeof(profileMsg),
				         "discover source=profile_seed host=%.100s page=%.255s type=%d",
				         seedHost.Host,seedHost.Page,seedHost.type);
				CRAWLER_PROFILE_LOG(profileMsg);
			}
		}
	}
	
	memcpy(&IndexingHost,&currentHst,sizeof(struct sHost));
	
	{
		int (*modInitFilter)(char*, char*);
		char sError[MAXDESCRIPTIONSIZE];
		int ret;
		unsigned int modInitCount;
		unsigned int modInitIndex;
		
		modInitCount = GetInitModFunctionHandlerCountByName("modFilter");
		for(modInitIndex=0; modInitIndex<modInitCount; modInitIndex++)
		{
			modInitFilter = GetInitModFunctionHandlerByNameAt("modFilter",modInitIndex);
			if(!modInitFilter)
				continue;

			ret=modInitFilter(currentHst.Host,sError);
			if(ret==0)
			{
				FREE(sqlQuery);
				printf("\nmodInitFilter(): %s\n\n",sError);
				ERROR_LOG(sError);
				return 0;
			}
		}
	}
	
	SetConsoleTitle("...");

    setHostExtras( currentHst.host_id );

    printf(" --- This site Limits ---\r\n");
    printf("Max pages         : %i\r\n", (EXTRA_LIMITS.nMaxPagesPerSite==0) ? CRAWLER_LIMITS.nMaxPagesPerSite : EXTRA_LIMITS.nMaxPagesPerSite);
    printf("Max depth level   : %i\r\n", (EXTRA_LIMITS.nMaxDepthLevel==0) ? CRAWLER_LIMITS.nMaxDepthLevel : EXTRA_LIMITS.nMaxDepthLevel);
    printf("Max seconds       : %i\r\n", (EXTRA_LIMITS.nMaxSecondsPerSite==0) ? CRAWLER_LIMITS.nMaxSecondsPerSite : EXTRA_LIMITS.nMaxSecondsPerSite);
    printf("Max bytes         : %llu\r\n", (unsigned long long)((EXTRA_LIMITS.nMaxBytesPerSite==0) ? CRAWLER_LIMITS.nMaxBytesPerSite : EXTRA_LIMITS.nMaxBytesPerSite));
    printf(" -----------------------\r\n");


	if(bUpdate==0)
	{
		printf("Deleting old index for %s...",currentHst.Host);
		fflush(stdout);
		
		sprintf(sqlQuery,"DELETE ii FROM pagelist, ii WHERE pagelist.hostname =\'%s\' AND ii.pageid = pagelist.id ",currentHst.Host);
		my_mysql_query(&gMysqlDB2, sqlQuery,NO_BLOCK);

        sprintf(sqlQuery,"DELETE FROM pagelist WHERE hostname =\'%s\' ",currentHst.Host);
		my_mysql_query(&gMysqlDB2, sqlQuery,NO_BLOCK);
		
		printf("OK\r\n");
		
		printf("Deleting old rels for %s...",currentHst.Host);
		
		sprintf(sqlQuery,"DELETE FROM rels WHERE host_id = %d",currentHst.host_id);
		my_mysql_query(&gMysqlDB1, sqlQuery,NO_BLOCK);
		
		printf("OK\r\n");
		
	}
	
    /* set startTimeMS before creating threads */
    startTimeMS=GetTickCount();

	SetConsoleTitle("Creating threads...");
	
	CreateThreads();
	/**************************MT********************************/
	
	printf("\r\n");
	
	time( &long_time ); 
	newtime=localtime(&long_time);
	
	sprintf(startTime,"%i:%i:%i",newtime->tm_hour ,newtime->tm_min ,newtime->tm_sec );
	
	while(condition)
	{
#ifdef WIN32
		sprintf(strTitle,"OpenWebSpiderV%s | Pages: %i | Time: %i sec | host: %s",VERSION,nPagesViewed,(int)((GetTickCount()-startTimeMS)/1000),currentHst.Host);
		SetConsoleTitle(strTitle);
#endif
		CheckThreads();
		
		Sleep(300);
		
		if(iQuit==1)
		{
			printf("\r\n\r\nQuitting: Killing threads...\n\n");
			
			KillThreads();
			
			iQuit=0;
			bKillThread=0;
			
			sprintf(sqlQuery,"UPDATE hostlist SET status = 1,indexed_pages=%d,time_sec=%d,bytes_downloaded=%llu, error_pages=%d WHERE hostname = \'%s\' limit 1" ,nPagesViewed, (int)((GetTickCount()-startTimeMS)/1000), (unsigned long long)bytesDownloaded, nErrorPages ,currentHst.Host);
			
			printStats(&currentHst,0);
			
			my_mysql_ping(&gMysqlDB1,NO_BLOCK);
			my_mysql_query(&gMysqlDB1, sqlQuery,NO_BLOCK);

			FREE(sqlQuery);
			
			FlushTempTable(gTable);
			
			if( bBuildOwsOwnIndex == 1 )
            {
			    /* all pages are swapped to the table pagelist */
			    /* are we using ows own index? */
			    /* if so: build the index for the current hostname */
			    BuildOwsOwnIndex(&currentHst, 1);
            }
	
			if(!gDb2FatalError)
				CalcPageRank( currentHst );
			else
				printf("\r\nSkipping HostRank/PageRank: DB2 in fatal error state\r\n");
			
			DoQuit();
			
		}/*if(iQuit==1)*/
		
		if(bKillThread==1)
		{
			SetConsoleTitle("Killing threads");
			KillThreads();
			CreateThreads();
		}/*if(bKillThread==1)*/
		
		
		thrdBlock(BLOCKTHRDHST);
		if(/*iDoNextHost==1 ||*/						/*Switching to the next host*/
			(lstGetNodeByVal(lstFirst,0)==NULL &&
			lstGetNodeByVal(lstFirst,2)==NULL))
		{
			char stopReason[160];
			if(checkLimitsReason(stopReason, sizeof(stopReason)) == 1)
				printf("\r\nCrawler stop: %s\r\n", stopReason);
			else if(iDoNextHost==1)
				printf("\r\nCrawler stop: switching to next host\r\n");
			else
				printf("\r\nCrawler stop: URL queue exhausted (no pending/running pages)\r\n");

			/* set the status of the pages to be indexed and of that in indexing as indexed */
			/*lstSetNodeStatus(lstFirst,0,1);
			lstSetNodeStatus(lstFirst,2,1);*/
			
			thrdUnBlock(BLOCKTHRDHST);
			
			SetConsoleTitle("Killing threads");
			
			bKillThread=1;
			
			KillThreads();
			
			if(iDoNextHost==1)
			{
				//sprintf(sqlQuery,"UPDATE hostlist SET status = 1,indexed_pages=%i WHERE hostname =\'%s\' limit 1",nPagesViewed,currentHst.Host);
				sprintf(sqlQuery,"UPDATE hostlist SET status = 1,indexed_pages=%d,time_sec=%d,bytes_downloaded=%llu, error_pages=%d WHERE hostname = \'%s\' limit 1" ,nPagesViewed, (int)((GetTickCount()-startTimeMS)/1000), (unsigned long long)bytesDownloaded, nErrorPages ,currentHst.Host);
				
				my_mysql_ping(&gMysqlDB1,NO_BLOCK);
				my_mysql_query(&gMysqlDB1, sqlQuery,NO_BLOCK);
				
				iDoNextHost=0;
				
			}
			
			FlushTempTable(gTable);
			
            if( bBuildOwsOwnIndex == 1 )
            {
			    /* all pages are swapped to the table pagelist */
			    /* are we using ows own index? */
			    /* if so: build the index for the current hostname */
			    BuildOwsOwnIndex(&currentHst, 1);
            }
			
			if(!gDb2FatalError)
				CalcPageRank(currentHst);
			else
				printf("\r\nSkipping HostRank/PageRank: DB2 in fatal error state\r\n");
			
            /* this host has been indexed! Proceed to the next? */
			break;			
			
		}//if(iDoNextHost==1 || (lstGetNodeByVal(lstFirst,0)==NULL && lstGetNodeByVal(lstFirst,2)==NULL))
		
		thrdUnBlock(BLOCKTHRDHST);
		
	}/*while(condition)*/
	(void)avgSec;
	FREE(sqlQuery);	
	return 1;
}

int checkLimitsReason(char* reason, size_t reasonSize)
{
    unsigned int maxPages = (EXTRA_LIMITS.nMaxPagesPerSite == 0) ? CRAWLER_LIMITS.nMaxPagesPerSite : EXTRA_LIMITS.nMaxPagesPerSite;
    unsigned int maxSeconds = (EXTRA_LIMITS.nMaxSecondsPerSite == 0) ? CRAWLER_LIMITS.nMaxSecondsPerSite : EXTRA_LIMITS.nMaxSecondsPerSite;
    OWS_DOWNLOAD_SIZE maxBytes = (EXTRA_LIMITS.nMaxBytesPerSite == 0) ? CRAWLER_LIMITS.nMaxBytesPerSite : EXTRA_LIMITS.nMaxBytesPerSite;
    unsigned int elapsed = (unsigned int)((GetTickCount()-startTimeMS)/1000);

    if(reason && reasonSize > 0)
        reason[0] = '\0';

    if(maxPages > 0 && nPagesViewed >= maxPages)
    {
        if(reason && reasonSize > 0)
            snprintf(reason, reasonSize, "max pages reached (%u/%u)", nPagesViewed, maxPages);
        return 1;
    }

    if(maxSeconds > 0 && elapsed >= maxSeconds)
    {
        if(reason && reasonSize > 0)
            snprintf(reason, reasonSize, "max seconds reached (%u/%u)", elapsed, maxSeconds);
        return 1;
    }

    if(maxBytes > 0 && bytesDownloaded >= maxBytes)
    {
        if(reason && reasonSize > 0)
            snprintf(reason, reasonSize, "max bytes reached (%llu/%llu)", (unsigned long long)bytesDownloaded, (unsigned long long)maxBytes);
        return 1;
    }

    if(CRAWLER_LIMITS.nMaxErrorPerSite > 0 && nErrorPages >= CRAWLER_LIMITS.nMaxErrorPerSite)
    {
        if(reason && reasonSize > 0)
            snprintf(reason, reasonSize, "max errors reached (%u/%u)", nErrorPages, CRAWLER_LIMITS.nMaxErrorPerSite);
        return 1;
    }

return 0;
}

int checkLimits()
{
    return checkLimitsReason(NULL, 0);
}

/*
* flag=0 -> complete stats
* flag=1 -> in-complete stats
* flag=2 -> switched to the next host
*/
void printStats(struct sHost* Host,int flag)
{
	time_t long_time;
	struct tm *newtime;
	FILE* file;
	FILE* profileFile;
	int sourceBreadth = 0;
	int mimeBreadth = 0;
	int candidateRejectBreadth = 0;
	int profileHealth = 100;
	
	time( &long_time ); 
	newtime=localtime(&long_time);
	if(gProfileSourceSeed>0) sourceBreadth++;
	if(gProfileSourceSitemap>0) sourceBreadth++;
	if(gProfileSourceTag>0) sourceBreadth++;
	if(gProfileSourceSrcset>0) sourceBreadth++;
	if(gProfileSourceLoose>0) sourceBreadth++;
	if(gProfileSourceBare>0) sourceBreadth++;
	if(gProfileSourceHeader>0) sourceBreadth++;
	if(gProfileMimeHtml>0) mimeBreadth++;
	if(gProfileMimeXml>0) mimeBreadth++;
	if(gProfileMimeJson>0) mimeBreadth++;
	if(gProfileMimeCssJs>0) mimeBreadth++;
	if(gProfileMimePdf>0) mimeBreadth++;
	if(gProfileMimeImage>0) mimeBreadth++;
	if(gProfileMimeVideo>0) mimeBreadth++;
	if(gProfileMimeAudio>0) mimeBreadth++;
	if(gProfileMimeOther>0) mimeBreadth++;
	if(gProfileCandidateRejectedEmpty>0) candidateRejectBreadth++;
	if(gProfileCandidateRejectedNotAsset>0) candidateRejectBreadth++;
	if(gProfileCandidateRejectedParse>0) candidateRejectBreadth++;
	if(gProfileCandidateRejectedToken>0) candidateRejectBreadth++;
	if(gProfileCandidateRejectedType>0) candidateRejectBreadth++;
	if(gProfileAcceptedTotal == 0) profileHealth -= 35;
	if(sourceBreadth < 3) profileHealth -= (3 - sourceBreadth) * 10;
	if(mimeBreadth < 2 && gProfileHttpOk > 0) profileHealth -= 15;
	if(gProfileRejectedDepth > 0 && gProfileAssetDepthBypass == 0) profileHealth -= 10;
	if(gProfileHttpError > gProfileHttpOk && gProfileHttpError > 10) profileHealth -= 10;
	if(gProfileRawAssetCandidates > 0 && gProfileAssetCandidates == 0) profileHealth -= 10;
	if(gProfileCandidateRejectedParse > gProfileAcceptedTotal && gProfileCandidateRejectedParse > 10) profileHealth -= 5;
	if(profileHealth < 0) profileHealth = 0;
	if(gProfileAcceptedTotal == 0)
		gProfileQualityWarnings++;
	if(sourceBreadth < 3)
		gProfileQualityWarnings++;
	if(mimeBreadth < 2 && gProfileHttpOk > 0)
		gProfileQualityWarnings++;
	if(gProfileRejectedDepth > 0 && gProfileAssetDepthBypass == 0)
		gProfileQualityWarnings++;
	if(gProfileRawAssetCandidates > 0 && gProfileAssetCandidates == 0)
		gProfileQualityWarnings++;
	if(gProfileCandidateRejectedParse > gProfileAcceptedTotal && gProfileCandidateRejectedParse > 10)
		gProfileQualityWarnings++;
	
	if(flag==1)
		printf("\r\n + STATS(*)\r\n");
	else if(flag==2)
		printf("\r\n + STATS(2)\r\n");
	else
		printf("\r\n + STATS\r\n");
	
	printf("  - Host:\t\t%s\r\n",Host->Host );
	printf("  - Pages:\t\t%i\r\n",nPagesViewed);
	printf("  - Downloaded:\t\t%llu Kb\r\n",(unsigned long long)(bytesDownloaded/1024));
	printf("  - Profile URLs:\tdiscovered=%llu accepted=%llu asset_candidates=%llu depth_bypass=%llu external_assets=%llu\r\n",
	       gProfileDiscoveredTotal,
	       gProfileAcceptedTotal,
	       gProfileAssetCandidates,
	       gProfileAssetDepthBypass,
	       gProfileExternalAssetsQueued);
	printf("  - Profile scope:\tdynamic_candidates=%llu cross_host=%llu http_ok=%llu redirects=%llu http_errors=%llu\r\n",
	       gProfileDynamicCandidates,
	       gProfileCrossHostDiscovered,
	       gProfileHttpOk,
	       gProfileHttpRedirect,
	       gProfileHttpError);
	printf("  - Profile breadth:\tsources=%d/7 mime_classes=%d/9\r\n", sourceBreadth, mimeBreadth);
	printf("  - Profile health:\t%i/100 warnings=%llu\r\n", profileHealth, gProfileQualityWarnings);
	printf("  - Profile src:\tseed=%llu sitemap=%llu tag=%llu srcset=%llu loose=%llu bare=%llu header=%llu\r\n",
	       gProfileSourceSeed,
	       gProfileSourceSitemap,
	       gProfileSourceTag,
	       gProfileSourceSrcset,
	       gProfileSourceLoose,
	       gProfileSourceBare,
	       gProfileSourceHeader);
	printf("  - Profile reject:\trobots=%llu limits=%llu depth=%llu switch=%llu duplicate=%llu\r\n",
	       gProfileRejectedRobots,
	       gProfileRejectedLimits,
	       gProfileRejectedDepth,
	       gProfileRejectedSwitch,
	       gProfileRejectedDuplicate);
	printf("  - Profile candidates:\traw=%llu rejected_empty=%llu not_asset=%llu parse=%llu token=%llu type=%llu reject_classes=%d/5\r\n",
	       gProfileRawAssetCandidates,
	       gProfileCandidateRejectedEmpty,
	       gProfileCandidateRejectedNotAsset,
	       gProfileCandidateRejectedParse,
	       gProfileCandidateRejectedToken,
	       gProfileCandidateRejectedType,
	       candidateRejectBreadth);
	printf("  - Profile queue mix:\thtml=%llu plain=%llu asset=%llu other=%llu\r\n",
	       gProfileQueuedTypeHtml,
	       gProfileQueuedTypePlain,
	       gProfileQueuedTypeAsset,
	       gProfileQueuedTypeOther);
	printf("  - Profile mime:\thtml=%llu xml=%llu json=%llu cssjs=%llu pdf=%llu image=%llu video=%llu audio=%llu other=%llu\r\n",
	       gProfileMimeHtml,
	       gProfileMimeXml,
	       gProfileMimeJson,
	       gProfileMimeCssJs,
	       gProfileMimePdf,
	       gProfileMimeImage,
	       gProfileMimeVideo,
	       gProfileMimeAudio,
	       gProfileMimeOther);
	printf("  - Scan time: %is (%s - %i:%i:%i)\r\n\r\n",(int)((GetTickCount()-startTimeMS)/1000),startTime,newtime->tm_hour ,newtime->tm_min ,newtime->tm_sec  );
	{
		char profileMsg[4096];
		char jsonMsg[4096];
		char jHost[160];
		snprintf(profileMsg,sizeof(profileMsg),
		         "profile summary host=%.100s health=%d source_breadth=%d mime_breadth=%d candidate_reject_breadth=%d discovered=%llu accepted=%llu asset_candidates=%llu raw_asset_candidates=%llu dynamic_candidates=%llu cross_host=%llu depth_bypass=%llu external_assets=%llu http_ok=%llu redirects=%llu http_errors=%llu src_seed=%llu src_sitemap=%llu src_tag=%llu src_srcset=%llu src_loose=%llu src_bare=%llu src_header=%llu mime_html=%llu mime_xml=%llu mime_json=%llu mime_cssjs=%llu mime_pdf=%llu mime_image=%llu mime_video=%llu mime_audio=%llu mime_other=%llu reject_robots=%llu reject_limits=%llu reject_depth=%llu reject_switch=%llu reject_duplicate=%llu candidate_reject_empty=%llu candidate_reject_not_asset=%llu candidate_reject_parse=%llu candidate_reject_token=%llu candidate_reject_type=%llu queue_html=%llu queue_plain=%llu queue_asset=%llu queue_other=%llu warnings=%llu",
		         Host->Host,
		         profileHealth,
		         sourceBreadth,
		         mimeBreadth,
		         candidateRejectBreadth,
		         gProfileDiscoveredTotal,
		         gProfileAcceptedTotal,
		         gProfileAssetCandidates,
		         gProfileRawAssetCandidates,
		         gProfileDynamicCandidates,
		         gProfileCrossHostDiscovered,
		         gProfileAssetDepthBypass,
		         gProfileExternalAssetsQueued,
		         gProfileHttpOk,
		         gProfileHttpRedirect,
		         gProfileHttpError,
		         gProfileSourceSeed,
		         gProfileSourceSitemap,
		         gProfileSourceTag,
		         gProfileSourceSrcset,
		         gProfileSourceLoose,
		         gProfileSourceBare,
		         gProfileSourceHeader,
		         gProfileMimeHtml,
		         gProfileMimeXml,
		         gProfileMimeJson,
		         gProfileMimeCssJs,
		         gProfileMimePdf,
		         gProfileMimeImage,
		         gProfileMimeVideo,
		         gProfileMimeAudio,
		         gProfileMimeOther,
		         gProfileRejectedRobots,
		         gProfileRejectedLimits,
		         gProfileRejectedDepth,
		         gProfileRejectedSwitch,
		         gProfileRejectedDuplicate,
		         gProfileCandidateRejectedEmpty,
		         gProfileCandidateRejectedNotAsset,
		         gProfileCandidateRejectedParse,
		         gProfileCandidateRejectedToken,
		         gProfileCandidateRejectedType,
		         gProfileQueuedTypeHtml,
		         gProfileQueuedTypePlain,
		         gProfileQueuedTypeAsset,
		         gProfileQueuedTypeOther,
		         gProfileQualityWarnings);
		CRAWLER_PROFILE_LOG(profileMsg);
		OwsJsonEscapeCopy(Host->Host, jHost, sizeof(jHost));
		snprintf(jsonMsg,sizeof(jsonMsg),
		         "{\"event\":\"summary\",\"host\":\"%.100s\",\"health\":%d,\"source_breadth\":%d,\"mime_breadth\":%d,\"candidate_reject_breadth\":%d,\"discovered\":%llu,\"accepted\":%llu,\"asset_candidates\":%llu,\"raw_asset_candidates\":%llu,\"dynamic_candidates\":%llu,\"cross_host\":%llu,\"depth_bypass\":%llu,\"external_assets\":%llu,\"http_ok\":%llu,\"redirects\":%llu,\"http_errors\":%llu,\"candidate_reject_empty\":%llu,\"candidate_reject_not_asset\":%llu,\"candidate_reject_parse\":%llu,\"candidate_reject_token\":%llu,\"candidate_reject_type\":%llu,\"queue_html\":%llu,\"queue_plain\":%llu,\"queue_asset\":%llu,\"queue_other\":%llu,\"warnings\":%llu}",
		         jHost,
		         profileHealth,
		         sourceBreadth,
		         mimeBreadth,
		         candidateRejectBreadth,
		         gProfileDiscoveredTotal,
		         gProfileAcceptedTotal,
		         gProfileAssetCandidates,
		         gProfileRawAssetCandidates,
		         gProfileDynamicCandidates,
		         gProfileCrossHostDiscovered,
		         gProfileAssetDepthBypass,
		         gProfileExternalAssetsQueued,
		         gProfileHttpOk,
		         gProfileHttpRedirect,
		         gProfileHttpError,
		         gProfileCandidateRejectedEmpty,
		         gProfileCandidateRejectedNotAsset,
		         gProfileCandidateRejectedParse,
		         gProfileCandidateRejectedToken,
		         gProfileCandidateRejectedType,
		         gProfileQueuedTypeHtml,
		         gProfileQueuedTypePlain,
		         gProfileQueuedTypeAsset,
		         gProfileQueuedTypeOther,
		         gProfileQualityWarnings);
		CRAWLER_PROFILE_JSONL(jsonMsg);
	}
	if(gProfileAcceptedTotal == 0)
		CRAWLER_PROFILE_LOG("profile warning accepted_total_zero crawler_profile_not_effectively_expanded");
	if(sourceBreadth < 3)
		CRAWLER_PROFILE_LOG("profile warning low_source_breadth expected_multiple_discovery_surfaces");
	if(mimeBreadth < 2 && gProfileHttpOk > 0)
		CRAWLER_PROFILE_LOG("profile warning low_mime_breadth profile_may_be_too_narrow_or_site_sparse");
	if(gProfileRejectedDepth > 0 && gProfileAssetDepthBypass == 0)
		CRAWLER_PROFILE_LOG("profile warning depth_rejections_without_asset_bypass_check_media_detection");
	if(gProfileRawAssetCandidates > 0 && gProfileAssetCandidates == 0)
		CRAWLER_PROFILE_LOG("profile warning raw_candidates_but_no_asset_candidates_check_candidate_filtering");
	if(gProfileCandidateRejectedParse > gProfileAcceptedTotal && gProfileCandidateRejectedParse > 10)
		CRAWLER_PROFILE_LOG("profile warning high_parse_rejects_check_url_normalization_and_escape_handling");
	
	if((file = fopen("stats.log","a"))!=NULL)
	{
		if(flag==1)
			fprintf(file," + STATS(*)\r\n");
		else if(flag==2)
			fprintf(file," + STATS(S)\r\n");
		else
			fprintf(file," + STATS\r\n");
		
		fprintf(file,"  - %i\\%i\\%i %i:%i:%i -- OpenWebSpider version: %s --\r\n",newtime->tm_mday ,newtime->tm_mon +1, newtime->tm_year +1900,newtime->tm_hour ,newtime->tm_min ,newtime->tm_sec,VERSION);
		fprintf(file,"  - Host:\t\t\t%s\r\n",Host->Host );
		fprintf(file,"  - Pages:\t\t%i\r\n",nPagesViewed);
		fprintf(file,"  - Downloaded:\t\t%llu Kb\r\n",(unsigned long long)(bytesDownloaded/1024));
		fprintf(file,"  - Profile URLs:\tdiscovered=%llu accepted=%llu asset_candidates=%llu depth_bypass=%llu external_assets=%llu\r\n",
		        gProfileDiscoveredTotal,
		        gProfileAcceptedTotal,
		        gProfileAssetCandidates,
		        gProfileAssetDepthBypass,
		        gProfileExternalAssetsQueued);
		fprintf(file,"  - Profile scope:\tdynamic_candidates=%llu cross_host=%llu http_ok=%llu redirects=%llu http_errors=%llu\r\n",
		        gProfileDynamicCandidates,
		        gProfileCrossHostDiscovered,
		        gProfileHttpOk,
		        gProfileHttpRedirect,
		        gProfileHttpError);
		fprintf(file,"  - Profile breadth:\tsources=%d/7 mime_classes=%d/9\r\n", sourceBreadth, mimeBreadth);
		fprintf(file,"  - Profile health:\t%i/100 warnings=%llu\r\n", profileHealth, gProfileQualityWarnings);
		fprintf(file,"  - Profile src:\tseed=%llu sitemap=%llu tag=%llu srcset=%llu loose=%llu bare=%llu header=%llu\r\n",
		        gProfileSourceSeed,
		        gProfileSourceSitemap,
		        gProfileSourceTag,
		        gProfileSourceSrcset,
		        gProfileSourceLoose,
		        gProfileSourceBare,
		        gProfileSourceHeader);
		fprintf(file,"  - Profile reject:\trobots=%llu limits=%llu depth=%llu switch=%llu duplicate=%llu\r\n",
		        gProfileRejectedRobots,
		        gProfileRejectedLimits,
		        gProfileRejectedDepth,
		        gProfileRejectedSwitch,
		        gProfileRejectedDuplicate);
		fprintf(file,"  - Profile candidates:\traw=%llu rejected_empty=%llu not_asset=%llu parse=%llu token=%llu type=%llu reject_classes=%d/5\r\n",
		        gProfileRawAssetCandidates,
		        gProfileCandidateRejectedEmpty,
		        gProfileCandidateRejectedNotAsset,
		        gProfileCandidateRejectedParse,
		        gProfileCandidateRejectedToken,
		        gProfileCandidateRejectedType,
		        candidateRejectBreadth);
		fprintf(file,"  - Profile queue mix:\thtml=%llu plain=%llu asset=%llu other=%llu\r\n",
		        gProfileQueuedTypeHtml,
		        gProfileQueuedTypePlain,
		        gProfileQueuedTypeAsset,
		        gProfileQueuedTypeOther);
		fprintf(file,"  - Profile mime:\thtml=%llu xml=%llu json=%llu cssjs=%llu pdf=%llu image=%llu video=%llu audio=%llu other=%llu\r\n",
		        gProfileMimeHtml,
		        gProfileMimeXml,
		        gProfileMimeJson,
		        gProfileMimeCssJs,
		        gProfileMimePdf,
		        gProfileMimeImage,
		        gProfileMimeVideo,
		        gProfileMimeAudio,
		        gProfileMimeOther);
		fprintf(file,"  - Scan time: %is (%s - %i:%i:%i) \r\n",(int)((GetTickCount()-startTimeMS)/1000),startTime,newtime->tm_hour ,newtime->tm_min ,newtime->tm_sec);
		fprintf(file,"============================================================\r\n\r\n");
		fclose(file);
	}

	{
		FILE *profileCheck = fopen("crawler_profile_metrics.tsv","r");
		int writeHeader = (profileCheck == NULL);
		if(profileCheck)
			fclose(profileCheck);
		if((profileFile = fopen("crawler_profile_metrics.tsv","a"))!=NULL)
	{
		if(writeHeader)
		{
			fprintf(profileFile,
			        "date\ttime\thost\tpages\tbytes\thealth\twarnings\tsource_breadth\tmime_breadth\tcandidate_reject_breadth\tdiscovered\taccepted\tasset_candidates\traw_asset_candidates\tdynamic_candidates\tcross_host\tdepth_bypass\texternal_assets\thttp_ok\tredirects\thttp_errors\tsrc_seed\tsrc_sitemap\tsrc_tag\tsrc_srcset\tsrc_loose\tsrc_bare\tsrc_header\tmime_html\tmime_xml\tmime_json\tmime_cssjs\tmime_pdf\tmime_image\tmime_video\tmime_audio\tmime_other\treject_robots\treject_limits\treject_depth\treject_switch\treject_duplicate\tcandidate_reject_empty\tcandidate_reject_not_asset\tcandidate_reject_parse\tcandidate_reject_token\tcandidate_reject_type\tqueue_html\tqueue_plain\tqueue_asset\tqueue_other\n");
		}
		fprintf(profileFile,
		        "%i-%02i-%02i\t%02i:%02i:%02i\t%s\t%i\t%llu\t%d\t%llu\t%d\t%d\t%d\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\n",
		        newtime->tm_year + 1900,
		        newtime->tm_mon + 1,
		        newtime->tm_mday,
		        newtime->tm_hour,
		        newtime->tm_min,
		        newtime->tm_sec,
		        Host->Host,
		        nPagesViewed,
		        (unsigned long long)bytesDownloaded,
		        profileHealth,
		        gProfileQualityWarnings,
		        sourceBreadth,
		        mimeBreadth,
		        candidateRejectBreadth,
		        gProfileDiscoveredTotal,
		        gProfileAcceptedTotal,
		        gProfileAssetCandidates,
		        gProfileRawAssetCandidates,
		        gProfileDynamicCandidates,
		        gProfileCrossHostDiscovered,
		        gProfileAssetDepthBypass,
		        gProfileExternalAssetsQueued,
		        gProfileHttpOk,
		        gProfileHttpRedirect,
		        gProfileHttpError,
		        gProfileSourceSeed,
		        gProfileSourceSitemap,
		        gProfileSourceTag,
		        gProfileSourceSrcset,
		        gProfileSourceLoose,
		        gProfileSourceBare,
		        gProfileSourceHeader,
		        gProfileMimeHtml,
		        gProfileMimeXml,
		        gProfileMimeJson,
		        gProfileMimeCssJs,
		        gProfileMimePdf,
		        gProfileMimeImage,
		        gProfileMimeVideo,
		        gProfileMimeAudio,
		        gProfileMimeOther,
		        gProfileRejectedRobots,
		        gProfileRejectedLimits,
		        gProfileRejectedDepth,
		        gProfileRejectedSwitch,
		        gProfileRejectedDuplicate,
		        gProfileCandidateRejectedEmpty,
		        gProfileCandidateRejectedNotAsset,
		        gProfileCandidateRejectedParse,
		        gProfileCandidateRejectedToken,
		        gProfileCandidateRejectedType,
		        gProfileQueuedTypeHtml,
		        gProfileQueuedTypePlain,
		        gProfileQueuedTypeAsset,
		        gProfileQueuedTypeOther);
		fclose(profileFile);
	}
	}
}

void MemoryCorruptedHandler(char* funct)
{
	printf("\r\n\r\nMemory corrupted\r\n");
	
	if(funct)
		printf("Function: %s\r\n",funct);
	
	printf("Exiting...\r\n\r\n");
	exit(0);
}

void DoQuit()
{
	if(actAsAServerPort)
	{
		printf("\n\nFreeing Sockets...");
		
		closesocket(OWS_Server_fd);
		
		printf("OK\n\n");
	}
	
	iQuit=0;
	bKillThread=0;
	
	DropTempTable(gTable);
	
	mysql_close(&gMysqlDB1);
	mysql_close(&gMysqlDB2);
	mysql_library_end();

    /* Rilascia le risorse SSL/TLS globali */
    CleanupSSL();
	
	Sleep(200);
	
	printf("Bye\n\n");
	//getchar();getchar();getchar();getchar();getchar();
	SetConsoleTitle("Bye byE");

#if defined(__SANITIZE_ADDRESS__)
	fflush(NULL);
	_Exit(0);
#else
	exit(0);
#endif
		
	return;
}


#endif

/*EOF*/
