#include "StdAfx.h"
#include ".\bufferdsocket.h"
#include "threadskeleton.h"
#include <ws2tcpip.h>

#ifndef BUFFERD_SOCKET_BUF_SIZE
	#define	BUFFERD_SOCKET_BUF_SIZE	(64 * 1024)
#endif

CBufferdSocket::CBufferdSocket(void)
{
	//	メモリの確保
	m_recvBuf.InitBuf(BUFFERD_SOCKET_BUF_SIZE);
	m_sendBuf.InitBuf(BUFFERD_SOCKET_BUF_SIZE);
}


CBufferdSocket::~CBufferdSocket(void)
{
	Close();
	m_recvBuf.Close();
	m_sendBuf.Close();
}

//////////////////////////////////////////////////////////////////////////////////
//	初期化など
//////////////////////////////////////////////////////////////////////////////////
/*!
	使用開始
*/
int CBufferdSocket::AttachSocket(SOCKET sock)
{
	//	終了
	Close();

	//	バッファクリア
	m_recvBuf.Clear();
	m_sendBuf.Clear();

	//	変数設定
	m_socket.AttachSocket(sock);
	ClearError();


	return(0);
}


/*!
	閉じる
*/
void CBufferdSocket::Close()
{
	if(m_socket.GetSocket() != INVALID_SOCKET)
	{
		//	閉じる
		m_socket.Close();
	}


	//	閉じた後も読み出す可能性があるので、バッファはオブジェクトが削除されるまで開放しない
}

//////////////////////////////////////////////////////////////////////////////////
//	中断インターフェース
//////////////////////////////////////////////////////////////////////////////////
/*!
	中断イベントを設定
*/
void CBufferdSocket::SetBreakEvent(HANDLE breakEvent)
{
	m_socket.SetBreakEvent(breakEvent);
}


//////////////////////////////////////////////////////////////////////////////////
//	バッファアクセス
//////////////////////////////////////////////////////////////////////////////////
/*!
	送信
*/
int CBufferdSocket::WriteBuf(char *data,int len)
{
	//	エラー情報クリア
	ClearError();

	return(m_sendBuf.WriteBuf(data,len));
}


/*!
	受信
*/
int CBufferdSocket::ReadBuf(char *data,int len)
{
	//	エラー情報クリア
	ClearError();

	return(m_recvBuf.ReadBuf(data,len));
}


/*!
	受信(バッファを消さない)
*/
int CBufferdSocket::PeekBuf(char *data,int len)
{
	//	エラー情報クリア
	ClearError();

	return(m_recvBuf.PeekBuf(data,len));
}



//////////////////////////////////////////////////////////////////////////////////
//	通信ステータス
//////////////////////////////////////////////////////////////////////////////////
/*!
	切断しているか取得
*/
int CBufferdSocket::IsDisconnect()
{
	//	エラー情報クリア
	ClearError();

	return m_socket.IsDisconnect();
};


/*!
	切断イベントを取得
*/
HANDLE CBufferdSocket::GetDisconnectEvent()
{
	return m_socket.GetCloseEvent();
}


/*!
	バッファサイズ取得
*/
int CBufferdSocket::GetSendRecvBufSize()
{
	return(BUFFERD_SOCKET_BUF_SIZE);
}

//////////////////////////////////////////////////////////////////////////////////
//	通信処理
//////////////////////////////////////////////////////////////////////////////////
/*!
	バッファ内のデータを送信(ブロッキングされる)

	\return	-1:エラー、0:送信完了、>0:残りデータ量
*/
int CBufferdSocket::BlockingSend(int timeOut)
{
	//	データがある?
	if(m_sendBuf.GetInBuf() == 0)
		return(0);

	//	送信用バッファ取得
	int		bufLen;
	char	*sendBuf = m_sendBuf.GetReadBuffer(&bufLen);

	//	送信
	int sended = m_socket.BlockingSend(sendBuf, bufLen, timeOut);
	if(sended < 0)
	{
		switch(m_socket.GetLastError())
		{
		case COverlappedSocket::OVRS_ERROR_TIMEOUT:
			CloseError(CBS_ERROR_TIMEOUT, _T("BlockingSend"));
			break;

		case COverlappedSocket::OVRS_ERROR_CLOSE:
			CloseError(CBS_ERROR_CLOSE, _T("BlockingSend"));
			break;

		case COverlappedSocket::OVRS_ERROR_BREAK:
			CloseError(CBS_ERROR_BREAK, _T("BlockingSend"));
			break;

		case COverlappedSocket::OVRS_ERROR_OTHER:
		default:
			CloseError(CBS_ERROR_OTHER, _T("BlockingSend"));
			break;
		}
		return(-1);
	}

	//	送信したデータ量を設定
	m_sendBuf.SetReadedLen(sended);
	return(m_sendBuf.GetInBuf());
}


/*!
	バッファへデータを受信(ブロッキングされる)

	\return	-1:エラー、0:受信しなかった、>0:受信データ量
*/
int CBufferdSocket::BlockingRecv(int timeOut)
{
	//	バッファがあるか？
	if(m_recvBuf.GetFreeBuf() == 0)
		return(m_recvBuf.GetInBuf());	//	データ受信済みなら終了

	//	受信用バッファ取得
	int		bufLen;
	char	*recvBuf = m_recvBuf.GetWriteBuffer(&bufLen);

	//	受信
	int recved = m_socket.BlockingRecv(recvBuf, bufLen, timeOut);
	if(recved < 0)
	{
		switch(m_socket.GetLastError())
		{
		case COverlappedSocket::OVRS_ERROR_TIMEOUT:
			CloseError(CBS_ERROR_TIMEOUT, _T("BlockingRecv"));
			break;

		case COverlappedSocket::OVRS_ERROR_CLOSE:
			CloseError(CBS_ERROR_CLOSE, _T("BlockingRecv"));
			break;

		case COverlappedSocket::OVRS_ERROR_BREAK:
			CloseError(CBS_ERROR_BREAK, _T("BlockingRecv"));
			break;

		case COverlappedSocket::OVRS_ERROR_OTHER:
		default:
			CloseError(CBS_ERROR_OTHER, _T("BlockingRecv"));
			break;
		}
		return(-1);
	}

	//	受信したデータ量を設定
	m_recvBuf.SetWritedLen(recved);
	return(m_recvBuf.GetInBuf());
}



//////////////////////////////////////////////////////////////////////////////////
//	接続情報
//////////////////////////////////////////////////////////////////////////////////
/*!
	自分のアドレスを取得する
*/
CIPAddress CBufferdSocket::GetAddres()
{
	sockaddr_in	addr;
	memset(&addr, 0, sizeof(sockaddr_in));
	int nSockAddrLen = sizeof(sockaddr_in);

	getsockname(m_socket.GetSocket(),(SOCKADDR*)&addr,&nSockAddrLen);
	return(addr.sin_addr);
}

/*!
	相手のアドレスを取得する
*/
CIPAddress CBufferdSocket::GetPeerAddres()
{
	sockaddr_in	addr;
	memset(&addr, 0, sizeof(sockaddr_in));
	int nSockAddrLen = sizeof(sockaddr_in);

	getpeername(m_socket.GetSocket(),(SOCKADDR*)&addr,&nSockAddrLen);
	return(addr.sin_addr);
}

/*!
	自分のポートを取得する	
*/
int CBufferdSocket::GetPort()
{
	sockaddr_in	addr;
	memset(&addr, 0, sizeof(sockaddr_in));
	int nSockAddrLen = sizeof(sockaddr_in);

	getsockname(m_socket.GetSocket(),(SOCKADDR*)&addr,&nSockAddrLen);
	return(ntohs(addr.sin_port));
}

/*!
	相手のポートを取得する
*/
int CBufferdSocket::GetPeerPort()
{
	sockaddr_in	addr;
	memset(&addr, 0, sizeof(sockaddr_in));
	int nSockAddrLen = sizeof(sockaddr_in);

	getpeername(m_socket.GetSocket(),(SOCKADDR*)&addr,&nSockAddrLen);
	return(ntohs(addr.sin_port));
}



//////////////////////////////////////////////////////////////////////////////////
//	エラー
//////////////////////////////////////////////////////////////////////////////////
/*!
	エラーで閉じる
*/
void CBufferdSocket::CloseError(int code, CString debugInfo)
{
	TRACE("SocketError : %d:%s [%s] (SocketError : %d)\n", code, GetErrorString(code), debugInfo, WSAGetLastError());
	m_lastError = code;

	//	ソケットを閉じる
	if(m_socket.GetSocket() != INVALID_SOCKET)
		Close();
}

/*!
	エラーを文字列で取得
*/
CString CBufferdSocket::GetLastErrorString()
{
	return(GetErrorString(GetLastError()));
}

/*!
	エラーコードから文字列を取得
*/
CString CBufferdSocket::GetErrorString(int errorCode)
{
	switch(errorCode)
	{
	case CBS_ERROR_TIMEOUT:
		return(_T("タイムアウトしました"));

	case CBS_ERROR_CLOSE:
		return(_T("接続が切断されました"));

	case CBS_ERROR_BREAK:
		return(_T("処理を中断しました"));

	case CBS_ERROR_OTHER:
		return(_T("ネットワークエラーが発生しました"));


	case CBS_NO_ERROR:
	default:
		return(_T("不明なエラーが発生しました"));
	}
}
