#include "StdAfx.h"
#include "ProtocolSocket.h"

#define	DEFAULT_TIMEOUT	(3 * 60 * 1000)

CProtocolSocket::CProtocolSocket(void)
{
	SetTimeout(DEFAULT_TIMEOUT);
}

CProtocolSocket::~CProtocolSocket(void)
{
}


//////////////////////////////////////////////////////////////////////////////////
//	入出力(同期)
//////////////////////////////////////////////////////////////////////////////////
/*!
	同期送信

	全てのデータを送信するまでブロック
*/
int CProtocolSocket::Send(char *data, int len)
{
	//	エラー情報クリア
	ClearError();

	//	送信ループ
	while(1)
	{
		//	送信バッファに入れる
		if(len > 0)
		{
			int ret = WriteBuf(data, len);
			data += ret;
			len -= ret;
		}
		else if(GetSendInBuf() == 0)
			return(0);

		//	送信処理
		if(BlockingSend(m_timeoutMS) < 0)
			return(-1);
	}
}

/*!
	同期送信（文字列）

	全てのデータを送信するまでブロック
*/
int CProtocolSocket::SendString(CString str)
{
	int ret = Send(str.GetBuffer(0),str.GetLength());
	str.ReleaseBuffer();

	return(ret);
};

/*!
	同期送信（CBinaryData）
*/
int CProtocolSocket::SendBinary(CBinaryData &data)
{
	return(Send(data.GetPtr(), data.GetSize()));
}

/*!
	同期送信（CBuffer）
*/
int CProtocolSocket::SendBinary(CBuffer &data)
{
	return(Send(data.GetPtr(), data.GetSize()));
}


/*!
	同期受信

	何かデータを受信するまでブロック	
*/
int CProtocolSocket::Recv(char *data, int len)
{
	//	エラー情報クリア
	ClearError();

	//	受信の必要はあるか？
	if(GetRecvInBuf() == 0)
	{
		//	受信
		if(BlockingRecv(m_timeoutMS) < 0)
			return(-1);
	}

	//	バッファから読み出し
	return(ReadBuf(data, len));
}


/*!
	同期受信（文字列）

	何かデータを受信するまでブロック	
*/
int CProtocolSocket::RecvString(CString &str, int maxLen)
{
	int ret = Recv(str.GetBuffer(maxLen + 1), maxLen);
	if(ret < 0)
		str.ReleaseBufferSetLength(0);
	else
		str.ReleaseBufferSetLength(ret);

	return(ret);
}


/*!
	同期受信（CBinaryData）
*/
int CProtocolSocket::RecvBinary(CBinaryData &data, int maxSize)
{
	data.ReSize(maxSize);

	int ret = Recv(data.GetPtr(), maxSize);
	if(ret < 0)
		data.ReSize(0);
	else
		data.ReSize(ret);

	return(ret);
}


/*!
	同期受信（CBuffer）
*/
int CProtocolSocket::RecvBinary(CBuffer &data, int maxSize)
{
	data.ReSize(maxSize);

	int ret = Recv(data.GetPtr(), maxSize);
	if(ret < 0)
		data.ReSize(0);
	else
		data.ReSize(ret);

	return(ret);
}


//////////////////////////////////////////////////////////////////////////////////
//	プロトコル処理
//////////////////////////////////////////////////////////////////////////////////
/*!
	リクエスト受信を待つ
	リクエストを検出するまでブロック

	\return TRUE->検出、FALSE->タイムアウト、切断
*/
int CProtocolSocket::WaitNextRequest(int maxWaitTime)
{
	//	エラー情報クリア
	ClearError();

	//	受信バッファチェック
	if(GetRecvInBuf() > 0)
		return(TRUE);

	//	開始時刻
	DWORD	start = GetTickCount();

	//	受信までループ
	while(1)
	{
		//	受信バッファチェック
		if(GetRecvInBuf() > 0)
			return(TRUE);

		//	切断？
		if(IsDisconnect())
		{
			CloseError(CBS_ERROR_CLOSE, "WaitNextRequest");
			return(FALSE);
		}

		//	待機？
		DWORD	now = GetTickCount();
		if(now < start || start + maxWaitTime <= now)
			return(FALSE);

		//	受信を試みる
		if(BlockingRecv(start + maxWaitTime - now) < 0)
			return(FALSE);
	}
}

/*!
	ヘッダ受信
	ヘッダを受信するまでブロック	

	\return 0->正常、-1->エラー
*/
int CProtocolSocket::RecvProtocolHeader(CString &head, CString endToken, int maxHeaderSize, int isPeek)
{
	//	エラー情報クリア
	ClearError();

	//	最大サイズは
	if(maxHeaderSize >= GetSendRecvBufSize())
		maxHeaderSize = GetSendRecvBufSize()-1;

	//	受信ループ
	while(1)
	{
		//	受信?
		int ret = GetHeaderFromBuf(head, endToken, maxHeaderSize, isPeek);
		if(ret < 0)
			return(-1);
		else if(ret > 0)
			return(0);	//	完了

		//	受信を試みる
		if(BlockingRecv(m_timeoutMS) < 0)
			return(-1);

		//	ヘッダが見つからない上に切断？
		if(IsDisconnect())
		{
			CloseError(CBS_ERROR_CLOSE, "RecvProtocolHeader");
			return(-1);
		}
	}
}

/*!
	ヘッダチェック
*/
int CProtocolSocket::GetHeaderFromBuf(CString &head, CString endToken, int maxHeaderSize, int isPeek)
{
	//	受信データを取得
	if(PeekBufString(head, maxHeaderSize + 1) < 0)
		return(-1);

	//	ヘッダサイズチェック
	if(head.GetLength() > maxHeaderSize)
	{
		CloseError(CPS_ERROR_RECV_HEADER_OVER_SIZE, "RecvProtocolHeader");
		return(-1);
	}

	//	検索してみる
	int index = head.Find(endToken);
	if(index != -1 && index <= maxHeaderSize - endToken.GetLength())
	{
		//	tokenも含む
		index += endToken.GetLength();

		//	PeekMode?
		if(isPeek)
		{
			head = head.Left(index);
		}
		else
		{
			//	読み出し
			if(ReadBufString(head,index) < 0)
				return(-1);
		}

		return(1);	//	完了
	}

	return(0);	//	無し
}

//////////////////////////////////////////////////////////////////////////////////
//	バッファアクセス（文字列)
//////////////////////////////////////////////////////////////////////////////////
/*!
	受信(文字列)
*/
int CProtocolSocket::ReadBufString(CString &str,int maxLen)
{
	//	文字列に
	int ret = ReadBuf(str.GetBuffer(maxLen+1), maxLen);
	if(ret < 0)
		str.ReleaseBufferSetLength(0);
	else
		str.ReleaseBufferSetLength(ret);

	return(ret);
}

/*!
	バッファを消さない受信(文字列)
*/
int CProtocolSocket::PeekBufString(CString &str,int maxLen)
{
	//	文字列に
	int ret = PeekBuf(str.GetBuffer(maxLen+1),maxLen);
	if(ret < 0)
		str.ReleaseBufferSetLength(0);
	else
		str.ReleaseBufferSetLength(ret);

	return(ret);
}



//////////////////////////////////////////////////////////////////////////////////
//	エラー
//////////////////////////////////////////////////////////////////////////////////
/*!
	エラーコードから文字列を取得
*/
CString CProtocolSocket::GetErrorString(int errorCode)
{
	switch(errorCode)
	{
	case CPS_ERROR_RECV_HEADER_OVER_SIZE:
		return(_T("不正なヘッダを受信しました"));

	default:
		return(CBufferdSocket::GetErrorString(errorCode));
	}
}
