#include "SHSSDK.h"
#include "main.h"
#include "solbox_util.h"
#include "GTS_INFO.h"

#undef HAVE_SSPI

#include "ne_request.h"
#include "ne_socket.h"
#include "ne_string.h"
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#endif

#ifdef WIN32
typedef __int32             int32_t;
typedef unsigned __int32	uint32_t; 
#endif 

#define AUTHPRIME            137897
typedef struct _s_time_sync_t
{
    int32_t sync_info;
}time_sync_t;


#pragma pack(1)
typedef struct {
	char id[32];
	char domain[128];
    char domain2[128];
} SERVICE_STRUCT, *PSERVICE_STRUCT;
#pragma pack()

#pragma pack(1)
typedef struct {
	char    szTranId[52];
	__int32 nMode;
	char    szIssuer[128];
	char    szServiceId[128];
	__int32 nResult;
	__int32 nLength;
} COMMAND_STRUCT, *PCOMMAND_STRUCT;

typedef struct {
	char path[2048];
} PATHINFO_STRUCT, *PPATHINFO_STRUCT;
#pragma pack()

#define CENTER_HOST G_CENTERADDR
#define CENTER_PORT G_CENTERADDR_PORT

#define RCTS_PORT	13104

#define PRIVATE_KEY "I'm your father"
// 2013-12-27 dadamin
// GTS(cc_tsd) 통신 시 이용되는 구분자 변경
// sp-console => SP-Console3
// SHSSDK => SSDK
#ifdef _SP_SDK_
#define SERVER_NAME "SP-Console3"
#else // !_SP_SDK_
#define SERVER_NAME "SSDK"
#endif // _SP_SDK_

#define DELIMITER					0x1b

// cc_tsd
#define MODE_SRV_LST_2ND_REQUEST	0x0080
#define MODE_SRV_TRAFFIC_REQUEST	0x0082

// rc_mngd(rc_tsd)
#define SDK_REQ_VOLUME_INFO			0x0012 // old : MSG_MODE_SPCONS_RCTRAN_VOLUME_SIZE
#define SDK_REQ_SET_ANONY_DIR		0x0014 // old : MSG_MODE_SPCONS_RCTRAN_SET_ANONY
#define SDK_REQ_UNSET_ANONY_DIR		0x0018 // old : MSG_MODE_SPCONS_RCTRAN_UNSET_ANONY
#define SDK_REQ_ANONY_DIR			0x0030 // old : MSG_MODE_SPCONS_RCTRAN_RETRIVE_ANONY

/* Elenoa MOD : START */
/* default timeout 5 second */
#include <fcntl.h>

static int timeout = 5;
static char szCacheFile[MAX_PATH]={0};

static char g_cnthost[255]	= CENTER_HOST;
static int	g_cntport		= CENTER_PORT;
static char g_sntphost[255] = SNTP_DOMAIN;
static int	g_sntpport		= SNTP_PORT;

static int _sh_send(SOCKET s, char *buf, int len);
static int _sh_recv(SOCKET s, char *buf, int len);
const  char *sh_get_rcts_host(const char *userId, const char *password, const char *serviceId);
char* get_address(const char *userId, const char *password, const char *serviceId,int nFlag);
int get_psl_from_cache(PSERVICE_STRUCT *psl);
int set_psl_to_cache(PSERVICE_STRUCT *psl,int nCount);

#ifdef _WIN32
static int __nonblock_win32(SOCKET s)
{
	int ul = 1;
	int result;
	
	result = ioctlsocket( s, FIONBIO, (u_long FAR*)&ul );

	return result;
}
#else
static int __nonblock(int fd)
{
	int result;
	int flags;

	flags = fcntl(fd, F_GETFL, 0);
	result = fcntl(fd, F_SETFL, flags | O_NONBLOCK);

	return result;
}
#endif

void sh_set_timeout(int second)
{
	timeout = second;
}
/* Elenoa MOD : END */

int get_psl_from_cache(PSERVICE_STRUCT *psl)
{
	int nCount = 0;
	FILE* fp=NULL;
	int i=0;
	int numread=0;

	int nErr = GetLastError();

	if (strlen(szCacheFile) == 0)
	{
		if(nErr) SetLastError(nErr);
		return 0;
	}

	fp = fopen(szCacheFile,"rb");

	if(fp)
	{
		fread(&nCount,sizeof(int),1,fp);
		
		*psl = malloc(sizeof(SERVICE_STRUCT) * nCount);
		numread = fread(*psl,sizeof(SERVICE_STRUCT) * nCount,1,fp);

		if (numread < 1)
		{
			SetLastError(SHERRNO_INVALIDCACHEFILE);
			return 0;
		}

		fclose(fp);
	}
	
	if(nErr) SetLastError(nErr);
	
	return nCount;
}

int set_psl_to_cache(PSERVICE_STRUCT *psl,int nCount)
{
	FILE* fp=NULL;
	int i=0;

	if (strlen(szCacheFile) == 0)
		return 0;

	fp = fopen(szCacheFile,"wb");

	if (fp)
	{
		fwrite(&nCount,sizeof(int),1,fp);

		fwrite(*psl,sizeof(SERVICE_STRUCT)*nCount,1,fp);
		fclose(fp);
	}

	return 1;
}

time_t get_time_from_sntp()
{
	char szHost[128];
	int  nRecv;
	time_sync_t	tst;
	int nWrite;
	time_sync_t *pSyncInfo = NULL;
#ifdef WIN32
	struct tm *ttm=NULL;
#endif
	SOCKET sock;
	struct sockaddr_in sa;
	long ltime;

	ltime = (long)time(NULL);

	if (ne_sock_init() != NE_OK)
	{
		return ltime;
	}

	// Get server time
	strcpy(szHost, g_sntphost);
	if (isalpha(szHost[0]))
	{
		struct addrinfo *result;
		struct addrinfo hints = {0};
		struct sockaddr_in * addr;

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( szHost, NULL, &hints, &result ) != 0 )
		{
			return ltime;
		}		
		
		sprintf(szHost, "%s", inet_ntoa(((struct sockaddr_in *)result->ai_addr)->sin_addr)); 
		freeaddrinfo(result);
	}

	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET)
	{
		return ltime;
	}

	sa.sin_family      = AF_INET;
	sa.sin_addr.s_addr = inet_addr(szHost);
	sa.sin_port        = htons(g_sntpport);

#ifdef WIN32
	__nonblock_win32(sock);

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			nRecv = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == nRecv || 0 == nRecv)
			{
				int nRet = WSAGetLastError();
				return ltime;
			}
		}
		else
		{
			return ltime;
		}
	}

#else
	__nonblock(sock);
	{
		int i, nRet;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			} else {
				nRet = errno;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0) {
				shutdown(sock, 2);
				//close(sock);
				//fprintf(stderr, "RETRY ");
			}
			usleep(100000);
			//fprintf(stderr, "CLI %d\n", i);
		}

		if (errno != EISCONN && errno != 0)
		{
			return ltime;
		}
 	}
#endif

	tst.sync_info = ltime + AUTHPRIME - (ltime % AUTHPRIME);

	tst.sync_info = htonl(tst.sync_info);
	nWrite = _sh_send(sock, (char *)&tst, sizeof(tst));
	
	if(nWrite < 0)
	{
		closesocket(sock);
		return ltime;
	}

	nRecv = _sh_recv(sock, szHost, sizeof(szHost));
	
	if (nRecv < 4)
	{
		closesocket(sock);
		return ltime;
	}

	pSyncInfo = (time_sync_t *)&szHost;
	pSyncInfo->sync_info = ntohl(pSyncInfo->sync_info);

	closesocket(sock);
	
	return pSyncInfo->sync_info;
}

PSERVICE_STRUCT get_addressex(const char *userId, const char *password, int *cnt)
{
	// define varialbles
	char *pszResult = NULL;

	char      szMD5[256], szVerifyKey[256], szPassword[128], szAuth[256];
	__int64   nRandom;
	struct tm *ptmNow = NULL;
	time_t    tmtNow;

	COMMAND_STRUCT cmd;

	PSERVICE_STRUCT psl = NULL;
	int             i, nServiceCount = 0;

	char   szHost[30];
	SOCKET sock = INVALID_SOCKET;
	struct sockaddr_in sa;
	BOOL	bIsCache = FALSE;

	// get current time & random number
	if (ne_sock_init() != NE_OK)
	{
		SetLastError(GetLastError());
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	tmtNow = get_time_from_sntp();

	srand((unsigned int)tmtNow);
	nRandom = rand() * rand();

	ptmNow = gmtime((const time_t *)&tmtNow);

	tmtNow  %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	// create command struct
#ifdef WIN32
	sprintf(szMD5, "%010d%010I64d%s%s", tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#else
	sprintf(szMD5, "%010d%010lld%s%s", (int)tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#endif
	md5_buffer(szMD5, szVerifyKey);

	md5_buffer(password, szPassword);
	sprintf(szMD5, "%s%s%d", userId, szPassword, (int)tmtNow);
	md5_buffer(szMD5, szPassword);

	sprintf(szAuth, "%s%c%s%c%d", userId, DELIMITER, szPassword, DELIMITER, (int)tmtNow);

	// Make header
#ifdef WIN32
	memset((void *)&cmd, NULL, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010I64d",
#else
	memset((void *)&cmd, 0, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010lld",
#endif
		ptmNow->tm_year + 1900, ptmNow->tm_mon, ptmNow->tm_wday, ptmNow->tm_hour, ptmNow->tm_min, ptmNow->tm_sec,
		szVerifyKey, (int)tmtNow, nRandom);

	cmd.nMode   = htonl(MODE_SRV_LST_2ND_REQUEST);
	strcpy(cmd.szIssuer, SERVER_NAME);
	cmd.nLength = htonl((u_long)strlen(szAuth));

	// create socket
	strcpy(szHost, g_cnthost);
	if (isalpha(szHost[0])) {
		struct addrinfo *result;
		struct addrinfo hints = {0};

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( szHost, NULL, &hints, &result ) != 0 )
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
		}

		sa.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr;
		freeaddrinfo(result);
	}
	else
		sa.sin_addr.s_addr = inet_addr(szHost);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	sa.sin_family      = AF_INET;
	sa.sin_port        = htons(g_cntport);

	/* Elenoa MOD : START */
#ifdef _WIN32
	__nonblock_win32(sock);  

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			int result;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			result = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == result || 0 == result)
			{
				if(result == 0)
				{	
					// time_out	
					SetLastError(WSAETIMEDOUT);
				}
				result = WSAGetLastError();
				bIsCache = TRUE;
				goto CACHE_FUNCTION;
			}
		}
		else
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
		}
	}

#else
	__nonblock(sock);
	{
		int i;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0)
			{
				shutdown(sock, 2);
				//close(sock);
			}
			usleep(100000);
			//fprintf(stderr, "%d\n", i);
		}

		if (errno != EISCONN && errno != 0)
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
			//			goto EXIT_FUNCTION;
		}
	}
#endif
	// Send packet
	if (_sh_send(sock, (char *)&cmd, sizeof(cmd)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_send(sock, szAuth, (int)strlen(szAuth)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_recv(sock, (char*)&cmd, sizeof(cmd)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	cmd.nLength = ntohl(cmd.nLength);
	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000) {
		if (cmd.nResult == 0x3000)
			SetLastError(SHERRNO_UNDEFINED);
		else if (cmd.nResult == 0x3001)
			SetLastError(SHERRNO_AUTHORIZATION);
		else if (cmd.nResult == 0x9000)
			SetLastError(SHERRNO_INTERNAL);

		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_recv(sock, (char*)&nServiceCount, 4) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	nServiceCount = ntohl(nServiceCount);
	if(cnt)	*cnt  = nServiceCount;
	psl           = malloc(sizeof(SERVICE_STRUCT) * nServiceCount);

	if (!psl)
		goto EXIT_FUNCTION;

	if (_sh_recv(sock, (char*)psl, sizeof(SERVICE_STRUCT) * nServiceCount) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		if (psl)
			free(psl);
		goto CACHE_FUNCTION;
	}

	closesocket(sock);
	sock = INVALID_SOCKET;

	set_psl_to_cache(&psl,nServiceCount); // 캐쉬파일에 기록

	if ( nServiceCount == 0 )
		SetLastError(SHERRNO_NOSERVICE);

CACHE_FUNCTION:

	if( bIsCache)
		nServiceCount = get_psl_from_cache(&psl);

EXIT_FUNCTION:
	i = GetLastError();

	//if (psl)
	//	free(psl);

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	SetLastError(i);
	return psl;
}

char* get_address(const char *userId, const char *password, const char *serviceId,int nFlag)
{
	// define varialbles
	char *pszResult = NULL;

	char      szMD5[256], szVerifyKey[256], szPassword[128], szAuth[256];
	__int64   nRandom;
	struct tm *ptmNow = NULL;
	time_t    tmtNow;

	COMMAND_STRUCT cmd;

	PSERVICE_STRUCT psl = NULL;
	int             i, nServiceCount = 0;

	char   szHost[30];
	SOCKET sock = INVALID_SOCKET;
	struct sockaddr_in sa;
	BOOL	bIsCache = FALSE;

	// get current time & random number
	if (ne_sock_init() != NE_OK)
	{
		SetLastError(GetLastError());
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	tmtNow = get_time_from_sntp();

	srand((unsigned int)tmtNow);
	nRandom = rand() * rand();

	ptmNow = gmtime((const time_t *)&tmtNow);

	tmtNow  %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	// create command struct
#ifdef WIN32
	sprintf(szMD5, "%010d%010I64d%s%s", tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#else
	sprintf(szMD5, "%010d%010lld%s%s", (int)tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#endif
	//md5_buffer(szMD5, szVerifyKey);

	md5_buffer(password, szPassword);
	sprintf(szMD5, "%s%s%d", userId, szPassword, (int)tmtNow);
	md5_buffer(szMD5, szPassword);

	sprintf(szAuth, "%s%c%s%c%d", userId, DELIMITER, szPassword, DELIMITER, (int)tmtNow);

	// Make header
#ifdef WIN32
	memset((void *)&cmd, NULL, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010I64d",
#else
	memset((void *)&cmd, 0, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010lld",
#endif
		ptmNow->tm_year + 1900, ptmNow->tm_mon, ptmNow->tm_wday, ptmNow->tm_hour, ptmNow->tm_min, ptmNow->tm_sec,
		szVerifyKey, (int)tmtNow, nRandom);

	cmd.nMode   = htonl(MODE_SRV_LST_2ND_REQUEST);
	strcpy(cmd.szIssuer, SERVER_NAME);
	cmd.nLength = htonl((u_long)strlen(szAuth));

	// create socket
	strcpy(szHost, g_cnthost);
	if (isalpha(szHost[0])) {
		struct addrinfo *result;
		struct addrinfo hints = {0};

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( szHost, NULL, &hints, &result ) != 0 )
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
		}

		sa.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr;
		freeaddrinfo(result);
	}
	else
		sa.sin_addr.s_addr = inet_addr(szHost);
	
	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	sa.sin_family      = AF_INET;
	sa.sin_port        = htons(g_cntport);

	/* Elenoa MOD : START */
#ifdef _WIN32
	__nonblock_win32(sock);  

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			int result;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			result = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == result || 0 == result)
			{
				if(result == 0)
				{	
					// time_out	
					SetLastError(WSAETIMEDOUT);
				}

				result = WSAGetLastError();
				bIsCache = TRUE;
				goto CACHE_FUNCTION;
			}
		}
		else
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
		}
	}

#else
    __nonblock(sock);
	{
		int i;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0)
			{
				shutdown(sock, 2);
				//close(sock);
			}
			usleep(100000);
			//fprintf(stderr, "%d\n", i);
		}

		if (errno != EISCONN && errno != 0)
		{
			bIsCache = TRUE;
			goto CACHE_FUNCTION;
//			goto EXIT_FUNCTION;
		}
 	}
#endif
	// Send packet
	if (_sh_send(sock, (char *)&cmd, sizeof(cmd)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_send(sock, szAuth, (int)strlen(szAuth)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_recv(sock, (char*)&cmd, sizeof(cmd)) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	cmd.nLength = ntohl(cmd.nLength);
	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000) {
		if (cmd.nResult == 0x3000)
			SetLastError(SHERRNO_UNDEFINED);
		else if (cmd.nResult == 0x3001)
			SetLastError(SHERRNO_AUTHORIZATION);
		else if (cmd.nResult == 0x9000)
			SetLastError(SHERRNO_INTERNAL);

		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	if (_sh_recv(sock, (char*)&nServiceCount, 4) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		goto CACHE_FUNCTION;
	}

	nServiceCount = ntohl(nServiceCount);
	psl           = malloc(sizeof(SERVICE_STRUCT) * nServiceCount);

	if (!psl)
		goto EXIT_FUNCTION;

	if (_sh_recv(sock, (char*)psl, sizeof(SERVICE_STRUCT) * nServiceCount) == SOCKET_ERROR)
	{
		bIsCache = TRUE;
		if (psl)
			free(psl);
		goto CACHE_FUNCTION;
	}

	closesocket(sock);
	sock = INVALID_SOCKET;

	set_psl_to_cache(&psl,nServiceCount); // 캐쉬파일에 기록

	if (!pszResult)
		SetLastError(SHERRNO_NOSERVICE);

CACHE_FUNCTION:

	if( bIsCache)
		nServiceCount = get_psl_from_cache(&psl);

	for (i = 0; i < nServiceCount; i++) {
		if (strcmp((const char *)psl[i].id, serviceId) == 0)
		{
			switch(nFlag)
			{
			case 0: // dav address
				strcat(psl[i].domain2, "/dav");
				pszResult = strdup((const char *)psl[i].domain2);
				break;
			case 1: // rcts adress
				pszResult = strdup((const char *)psl[i].domain);
				break;
			}
			break;
		}
	}

EXIT_FUNCTION:
	i = GetLastError();

	if (psl)
		free(psl);

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	SetLastError(i);

	return pszResult;
}

const char *sh_get_service_host(const char *userId, const char *password, const char *serviceId)
{
	return get_address(userId,password,serviceId,0);
}

const char *sh_get_rcts_host(const char *userId, const char *password, const char *serviceId)
{
	return get_address(userId,password,serviceId,1);
}

void sh_mem_free(void* pData)
{
	free(pData);
}

const int sh_get_service_info(const char *userId, const char *password, const char *serviceId, PINT64 totalSpace, PINT64 freeSpace)
{
	// define varialbles
	int nResult = 0;

	char      szMD5[256], szVerifyKey[256], szPassword[128], szAuth[256];
	__int64   nRandom;
	struct tm *ptmNow = NULL;
	time_t    tmtNow;
	char*	pdata;

	COMMAND_STRUCT cmd;

	char szRecvBuf[1024], *pszUsedSpace;
	int  i;

	SOCKET sock = INVALID_SOCKET;
	struct sockaddr_in sa; 

	char* pszHost = (char *)sh_get_rcts_host(userId, password, serviceId);

	if (!pszHost)
		return 0;

	pdata = strstr(pszHost,"/");

	if (pdata)
		*pdata = 0x00;

	// get current time & random number
	tmtNow = get_time_from_sntp();


	srand((unsigned int)tmtNow);
	nRandom = rand() * rand();

	ptmNow = gmtime((const time_t *)&tmtNow);

	tmtNow  %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	// create command struct
#ifdef WIN32
	sprintf(szMD5, "%010d%010I64d%s%s", tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#else
	sprintf(szMD5, "%010d%010lld%s%s", (int)tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#endif
	md5_buffer(szMD5, szVerifyKey);

	md5_buffer(password, szPassword);
	sprintf(szMD5, "%s@%s%s%d", serviceId, userId, szPassword, (int)tmtNow);
	md5_buffer(szMD5, szPassword);

	sprintf(szAuth, "%s@%s%c%s%c%d", serviceId, userId, DELIMITER, szPassword, DELIMITER, (int)tmtNow);

	// Make header

#ifdef WIN32
	memset((void *)&cmd, NULL, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010I64d",
#else
	memset((void *)&cmd, 0, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010lld",
#endif
		ptmNow->tm_year + 1900, ptmNow->tm_mon+1, ptmNow->tm_mday, ptmNow->tm_hour, ptmNow->tm_min, ptmNow->tm_sec,
		szVerifyKey, (int)tmtNow, nRandom);
	cmd.nMode   = htonl(SDK_REQ_VOLUME_INFO);
	strcpy(cmd.szIssuer,    SERVER_NAME);
	strcpy(cmd.szServiceId, serviceId);
	cmd.nLength = htonl((u_long)strlen(szAuth));

	// create socket
	if (isalpha(pszHost[0])) {
		struct addrinfo *result;
		struct addrinfo hints = {0};

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( pszHost, NULL, &hints, &result ) != 0 )
			goto EXIT_FUNCTION;	

		sa.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr;
		freeaddrinfo(result);		
	}
	else
		sa.sin_addr.s_addr = inet_addr(pszHost);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
		goto EXIT_FUNCTION;

	sa.sin_family      = AF_INET;
	sa.sin_port        = htons(RCTS_PORT);
	
	/* Elenoa MOD : START */
#ifdef _WIN32
	__nonblock_win32(sock);  

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			int result;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			result = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == result || 0 == result)
			{
				int nRet = WSAGetLastError();
				goto EXIT_FUNCTION;
			}
		}
		else
			goto EXIT_FUNCTION;
	}

#else
    __nonblock(sock);
	{
		int i;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0)
			{
				shutdown(sock, 2);
				close(sock);
			}
			usleep(100000);
			//fprintf(stderr, "%d\n", i);
		}

		if (errno != EISCONN && errno != 0)
			goto EXIT_FUNCTION;
 	}
#endif

	// Send packet
	if (_sh_send(sock, (char *)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_send(sock, szAuth, (int)strlen(szAuth)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_recv(sock, (char*)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	cmd.nLength = ntohl(cmd.nLength);
	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000) {
		if (cmd.nResult == 0x3000)
			SetLastError(SHERRNO_UNDEFINED);
		else if (cmd.nResult == 0x3001)
			SetLastError(SHERRNO_AUTHORIZATION);
		else if (cmd.nResult == 0x9000)
			SetLastError(SHERRNO_INTERNAL);
		goto EXIT_FUNCTION;
	}

	if (_sh_recv(sock, szRecvBuf, cmd.nLength) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	closesocket(sock);
	sock = INVALID_SOCKET;

	pszUsedSpace = strchr(szRecvBuf, DELIMITER);
	*(pszUsedSpace++) = (char)NULL;

#ifdef WIN32
	*totalSpace = _atoi64(szRecvBuf);
	*freeSpace  = *totalSpace - _atoi64(pszUsedSpace);
#else
	*totalSpace = strtoll(szRecvBuf, NULL, 10);
	*freeSpace  = *totalSpace - strtoll(pszUsedSpace, NULL, 10);
#endif

	nResult = 1;

EXIT_FUNCTION:
	i = GetLastError();

	if (pszHost)
		free(pszHost);

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	SetLastError(i);

	return nResult;
}

#ifndef WIN32
void SetLastError(int nErrCode)
{
	errno = nErrCode;
}

#endif

/* Elenoa MOD START */
static int _sh_send(SOCKET s, char *pszBuf, int nLen)
{
	int iSent = 0, nSentLen;
	fd_set wset;
	struct timeval tv;

	FD_ZERO(&wset);
	FD_SET(s, &wset);
	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	do {
		//if (select(s + 1, NULL, &wset, NULL, &tv) < 0) break;

		int n = select(s + 1, NULL, &wset, NULL, &tv);

		if(n == 0)
		{	
			// time_out	
#ifdef WIN32
			SetLastError(WSAETIMEDOUT);
#else // WIN32
			SetLastError(ETIMEDOUT);
#endif // WIN32
			break;
		}
		else if ( n < 0 )
		{
			// error
			SetLastError(GetLastError());
			break;
		}


		if (!FD_ISSET(s, &wset)) break;

		nSentLen = send(s, pszBuf + iSent, nLen, 0);

		iSent += nSentLen;
		nLen  -= nSentLen;
	} while (nLen > 0 && nSentLen > 0);

	return nLen > 0 ? SOCKET_ERROR : iSent;
}

static int _sh_recv(SOCKET s, char *pszBuf, int nLen)
{
	int iRecv = 0, nRecvLen;
	fd_set rset;
	struct timeval tv;
	int nRet;

	FD_ZERO(&rset);
	FD_SET(s, &rset);
	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	do {
		nRet = select(s + 1, &rset, NULL, NULL, &tv);
		
		if (nRet == 0)
		{
			// time out
#ifdef WIN32
			SetLastError(WSAETIMEDOUT);
#else // WIN32
			SetLastError(ETIMEDOUT);
#endif // WIN32
			break;
		}
		else if (nRet < 0)
		{
			// error
			SetLastError(GetLastError());
			break;
		}

		if (!FD_ISSET(s, &rset)) break;

		nRecvLen = recv(s, pszBuf + iRecv, nLen, 0);

		iRecv += nRecvLen;
		nLen  -= nRecvLen;
	} while (nLen > 0 && nRecvLen > 0);

	return nLen < 0 ? SOCKET_ERROR : iRecv;
}


void sh_set_cache_file(const char *file_path)
{
	strncpy(szCacheFile,file_path,sizeof(szCacheFile));
}

void * sh_get_service_list(const char *userId, const char *password, int *cnt)
{
	PSERVICE_STRUCT psl = NULL;
	
	if(cnt)
		*cnt = 0;

	psl = get_addressex(userId, password, cnt);
	return (void*) psl;
}

void sh_set_center_info ( const char *host, int port )
{
	if(host && strlen(host) > 0 ) 
		strcpy(g_cnthost, host);
	else 
		strcpy(g_cnthost, CENTER_HOST);

	if(port > 0)
		g_cntport = port;
	else
		g_cntport = CENTER_PORT;
}

void sh_set_sntp_info ( const char *host, int port )
{
	if(host && strlen(host) > 0 ) 
		strcpy(g_sntphost, host);
	else 
		strcpy(g_sntphost, SNTP_DOMAIN);

	if(port > 0)
		g_sntpport = port;
	else
		g_sntpport = SNTP_PORT;
}

void* sh_get_anonyauth(	const char *userId,	const char *password, const char *serviceId, int * cnt)
{
	PPATHINFO_STRUCT ppl = NULL;
	char      szMD5[256], szVerifyKey[256], szPassword[128], szAuth[256];
	__int64   nRandom;
	struct tm *ptmNow = NULL;
	time_t    tmtNow;
	char*	pdata;

	COMMAND_STRUCT cmd;

	char szRecvBuf[1024], *pszUsedSpace;
	int  i;
	int nCount = 0;

	SOCKET sock = INVALID_SOCKET;
	struct sockaddr_in sa; 

	char* pszHost = (char *)sh_get_rcts_host(userId, password, serviceId);

	if (!pszHost)
		return 0;

	pdata = strstr(pszHost,"/");

	if (pdata)
		*pdata = 0x00;

	// get current time & random number
	tmtNow = get_time_from_sntp();


	srand((unsigned int)tmtNow);
	nRandom = rand() * rand();

	ptmNow = gmtime((const time_t *)&tmtNow);

	tmtNow  %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	// create command struct
#ifdef WIN32
	sprintf(szMD5, "%010d%010I64d%s%s", tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#else
	sprintf(szMD5, "%010d%010lld%s%s", (int)tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#endif
	md5_buffer(szMD5, szVerifyKey);

	md5_buffer(password, szPassword);
	sprintf(szMD5, "%s@%s%s%d", serviceId, userId, szPassword, (int)tmtNow);
	md5_buffer(szMD5, szPassword);

	sprintf(szAuth, "%s@%s%c%s%c%d", serviceId, userId, DELIMITER, szPassword, DELIMITER, (int)tmtNow);

	// Make header

#ifdef WIN32
	memset((void *)&cmd, NULL, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010I64d",
#else
	memset((void *)&cmd, 0, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010lld",
#endif
		ptmNow->tm_year + 1900, ptmNow->tm_mon+1, ptmNow->tm_mday, ptmNow->tm_hour, ptmNow->tm_min, ptmNow->tm_sec,
		szVerifyKey, (int)tmtNow, nRandom);
	cmd.nMode   = htonl(SDK_REQ_ANONY_DIR);
	strcpy(cmd.szIssuer,    SERVER_NAME);
	strcpy(cmd.szServiceId, serviceId);
	cmd.nLength = htonl((u_long)strlen(szAuth));

	// create socket
	if (isalpha(pszHost[0])) {
		struct addrinfo *result;
		struct addrinfo hints = {0};

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( pszHost, NULL, &hints, &result ) != 0 )
			goto EXIT_FUNCTION;	

		sa.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr;
		freeaddrinfo(result);		
	}
	else
		sa.sin_addr.s_addr = inet_addr(pszHost);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
		goto EXIT_FUNCTION;

	sa.sin_family      = AF_INET;
	sa.sin_port        = htons(RCTS_PORT);

	/* Elenoa MOD : START */
#ifdef _WIN32
	__nonblock_win32(sock);  

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			int result;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			result = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == result || 0 == result)
			{
				int nRet = WSAGetLastError();
				goto EXIT_FUNCTION;
			}
		}
		else
			goto EXIT_FUNCTION;
	}

#else
	__nonblock(sock);
	{
		int i;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0)
			{
				shutdown(sock, 2);
				close(sock);
			}
			usleep(100000);
			//fprintf(stderr, "%d\n", i);
		}

		if (errno != EISCONN && errno != 0)
			goto EXIT_FUNCTION;
	}
#endif

	// Send packet
	if (_sh_send(sock, (char *)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_send(sock, szAuth, (int)strlen(szAuth)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_recv(sock, (char*)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	cmd.nLength = ntohl(cmd.nLength);
	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000) {
		if (cmd.nResult == 0x3000)
			SetLastError(SHERRNO_UNDEFINED);
		else if (cmd.nResult == 0x3001)
			SetLastError(SHERRNO_AUTHORIZATION);
		else if (cmd.nResult == 0x9000)
			SetLastError(SHERRNO_INTERNAL);
		goto EXIT_FUNCTION;
	}

	if (_sh_recv(sock, (char*)&nCount, 4) == SOCKET_ERROR)
	{
		goto EXIT_FUNCTION;
	}

	nCount = ntohl(nCount);
	if(cnt)	*cnt  = nCount;
	
	if(nCount > 0)
	{
		ppl           = malloc(sizeof(PATHINFO_STRUCT) * nCount);	

		if (!ppl)
			goto EXIT_FUNCTION;


		if (_sh_recv(sock, (char*)ppl, sizeof(PATHINFO_STRUCT) * nCount) == SOCKET_ERROR)
		{
			if (ppl)
			{
				free(ppl);
				ppl = NULL;
			}
			goto EXIT_FUNCTION;
		}
	}


	closesocket(sock);
	sock = INVALID_SOCKET;

EXIT_FUNCTION:
	i = GetLastError();

	if (pszHost)
		free(pszHost);

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	SetLastError(i);
	return ppl;
}

int sh_set_anonyauth(const char *userId, const char *password, const char *serviceId, int set, int sendlen, const void *sendmsg)
{
	char      szMD5[256], szVerifyKey[256], szPassword[128], szAuth[256];
	__int64   nRandom;
	struct tm *ptmNow = NULL;
	time_t    tmtNow;
	char*	pdata;
	char*	pSendData = NULL;

	COMMAND_STRUCT cmd;

	char szRecvBuf[1024], *pszUsedSpace;
	int  i;
	int nCount = 0, ret = 0;

	SOCKET sock = INVALID_SOCKET;
	struct sockaddr_in sa; 

	int nCommand = (set ? SDK_REQ_SET_ANONY_DIR : SDK_REQ_UNSET_ANONY_DIR);
	char* pszHost = (char *)sh_get_rcts_host(userId, password, serviceId);

	if (!pszHost)
		return 0;

	pdata = strstr(pszHost,"/");

	if (pdata)
		*pdata = 0x00;

	// get current time & random number
	tmtNow = get_time_from_sntp();


	srand((unsigned int)tmtNow);
	nRandom = rand() * rand();

	ptmNow = gmtime((const time_t *)&tmtNow);

	tmtNow  %= 10000000000;	// MAX 10
	nRandom %= 10000000000;	// MAX 10

	// create command struct
#ifdef WIN32
	sprintf(szMD5, "%010d%010I64d%s%s", tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#else
	sprintf(szMD5, "%010d%010lld%s%s", (int)tmtNow, nRandom, PRIVATE_KEY, SERVER_NAME);
#endif
	md5_buffer(szMD5, szVerifyKey);

	md5_buffer(password, szPassword);
	sprintf(szMD5, "%s@%s%s%d", serviceId, userId, szPassword, (int)tmtNow);
	md5_buffer(szMD5, szPassword);

	sprintf(szAuth, "%s@%s%c%s%c%d", serviceId, userId, DELIMITER, szPassword, DELIMITER, (int)tmtNow);

	// Make header

#ifdef WIN32
	memset((void *)&cmd, NULL, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010I64d",
#else
	memset((void *)&cmd, 0, sizeof(cmd));
	sprintf(cmd.szTranId, "%04d%02d%02d%02d%02d%02d-%.10s-%010d-%010lld",
#endif
		ptmNow->tm_year + 1900, ptmNow->tm_mon+1, ptmNow->tm_mday, ptmNow->tm_hour, ptmNow->tm_min, ptmNow->tm_sec,
		szVerifyKey, (int)tmtNow, nRandom);
		
	cmd.nMode   = htonl(nCommand);	
	strcpy(cmd.szIssuer,    SERVER_NAME);
	strcpy(cmd.szServiceId, serviceId);
	cmd.nLength = htonl((u_long)strlen(szAuth) + sendlen);

	if(sendlen > 0)
	{
		pSendData = malloc(strlen(szAuth) + sendlen);
		memcpy(pSendData, szAuth, strlen(szAuth));
		memcpy(pSendData+strlen(szAuth), sendmsg, sendlen);
	}

	// create socket
	if (isalpha(pszHost[0])) {
		struct addrinfo *result;
		struct addrinfo hints = {0};

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = PF_UNSPEC;

		if( getaddrinfo( pszHost, NULL, &hints, &result ) != 0 )
			goto EXIT_FUNCTION;	

		sa.sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr;
		freeaddrinfo(result);		
	}
	else
		sa.sin_addr.s_addr = inet_addr(pszHost);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
		goto EXIT_FUNCTION;

	sa.sin_family      = AF_INET;
	sa.sin_port        = htons(RCTS_PORT);

	/* Elenoa MOD : START */
#ifdef _WIN32
	__nonblock_win32(sock);  

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
	{

		if (WSAEWOULDBLOCK == WSAGetLastError())
		{
			fd_set wfd, efd;
			struct timeval tv;
			int result;
			FD_ZERO(&wfd);
			FD_ZERO(&efd);
			FD_SET(sock, &wfd);
			FD_SET(sock, &efd);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			result = select(0, 0, &wfd, &efd,&tv);
			if (SOCKET_ERROR == result || 0 == result)
			{
				int nRet = WSAGetLastError();
				goto EXIT_FUNCTION;
			}
		}
		else
			goto EXIT_FUNCTION;
	}

#else
	__nonblock(sock);
	{
		int i;
		for (i = 0; i < (timeout * 10); i++) {
			if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
				errno = 0;
				break;
			}
			if (errno == EISCONN)
				break;

			if (((i + 1) % 10) == 0)
			{
				shutdown(sock, 2);
				close(sock);
			}
			usleep(100000);
			//fprintf(stderr, "%d\n", i);
		}

		if (errno != EISCONN && errno != 0)
			goto EXIT_FUNCTION;
	}
#endif

	// Send packet
	if (_sh_send(sock, (char *)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_send(sock, pSendData, strlen(szAuth)+sendlen) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	if (_sh_recv(sock, (char*)&cmd, sizeof(cmd)) == SOCKET_ERROR)
		goto EXIT_FUNCTION;

	cmd.nLength = ntohl(cmd.nLength);
	cmd.nResult = ntohl(cmd.nResult);
	if (cmd.nResult != 0x1000) {
		if (cmd.nResult == 0x3000)
			SetLastError(SHERRNO_UNDEFINED);
		else if (cmd.nResult == 0x3001)
			SetLastError(SHERRNO_AUTHORIZATION);
		else if (cmd.nResult == 0x9000)
			SetLastError(SHERRNO_INTERNAL);
		goto EXIT_FUNCTION;
	}

	closesocket(sock);
	sock = INVALID_SOCKET;
	ret = 1;

EXIT_FUNCTION:
	i = GetLastError();
	
	if (pszHost)
		free(pszHost);

	if(pSendData)
		free(pSendData);

	if (sock != INVALID_SOCKET)
		closesocket(sock);

	SetLastError(i);
	return ret;
}

int sh_get_lasterror()
{
	return GetLastError();
}

void sh_get_error_msg( int code, char* errstr)
{
	if (code >= SHERRNO_UNDEFINED && code < SHERRNO_INVALIDCACHEFILE) {
		switch (code) {
		case SHERRNO_UNDEFINED:
			strcpy(errstr, "알 수 없는 오류입니다.");
			break;
		case SHERRNO_AUTHORIZATION:
			strcpy(errstr, "인증 실패입니다.");
			break;
		case SHERRNO_INTERNAL:
			strcpy(errstr, "내부 오류 입니다.");
			break;
		case SHERRNO_NOSERVICE:
			strcpy(errstr, "서비스가 존재하지 않습니다.");
			break;
		case SHERRNO_NOCACHEFILE:
			strcpy(errstr, "캐쉬 파일이 없습니다.");
			break;
		case SHERRNO_INVALIDCACHEFILE:
			strcpy(errstr, "올바르지 않는 캐쉬 파일입니다.");
			break;
		}
	}
	else {
#ifdef WIN32
		char * tmp;
		if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL))
			strcpy(errstr, "알 수 없는 오류입니다.");	
		else
			strcpy(errstr, tmp);

		LocalFree(tmp);
#else
		strcpy(errstr, strerror(code));
#endif
	}
}