#include "StdAfx.h"
#include "OverlappedSocket.h"
#include "ThreadSkeleton.h"

COverlappedSocket::COverlappedSocket(void)
{
	//	イベント生成
	m_closeEvent.Create(TRUE,FALSE);
	m_event.Create(TRUE, FALSE);

	m_socket = INVALID_SOCKET;
	m_timeout = INFINITE;
	m_breakEvent = NULL;

	SetLastError(OVRS_ERROR_NO_ERROR);
}

COverlappedSocket::~COverlappedSocket(void)
{
	Close();
}


//////////////////////////////////////////////////////////////////////////////////
//	初期化など
//////////////////////////////////////////////////////////////////////////////////
/*!
	使用開始
*/
int COverlappedSocket::AttachSocket(SOCKET sock)
{
	m_socket = sock;

	//	イベントクリア
	::ResetEvent(m_closeEvent);
	::ResetEvent(m_event);

	//	ソケットが閉じたことをイベントで検出する
	if(::WSAEventSelect(m_socket, m_closeEvent, FD_CLOSE))
	{
		SetLastError(OVRS_ERROR_OTHER);
		return(-1);
	}
	return(0);
}

/*!
	閉じる
*/
void COverlappedSocket::Close()
{
	if(m_socket != INVALID_SOCKET)
	{
		//	ソケットからハンドルを関連付け解除
		::WSAEventSelect(m_socket, m_closeEvent, 0);

		//	ソケット無効化
		shutdown(m_socket,1);

		//	ソケットを閉じる
		closesocket(m_socket);

		m_socket = INVALID_SOCKET;
	}
}


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

	return -1:エラー、0:切断、>0:成功
*/
int COverlappedSocket::BlockingSend(char *buf, int len, int timeOut)
{
	SetLastError(OVRS_ERROR_NO_ERROR);

	//	初期化済み？
	if(m_socket == INVALID_SOCKET)
		return(-1);

	//	タイムアウトは設定されてる？
	if(timeOut == -1)
		timeOut = m_timeout;

	//	イベント初期化
	::ResetEvent(m_event);

	//	オーバーラップ構造体初期化
	WSAOVERLAPPED	ovr;
	INIT_OVERLAPPED(ovr, m_event);

	//	バッファ準備
	WSABUF	wsaBuf;
	wsaBuf.buf = buf;
	wsaBuf.len = len;

	//	送信
	DWORD	sended = 0;
	if(::WSASend(m_socket, &wsaBuf, 1, &sended, 0, &ovr, NULL) == SOCKET_ERROR)
	{
		//	エラー？
		if(WSAGetLastError() != WSA_IO_PENDING)
		{
			SetLastError();
			return(-1);
		}

		//	終了を待つ
		switch(CThreadSkeleton::WaitForSomeObjects(timeOut, m_event, m_closeEvent, m_breakEvent))
		{
		//	タイムアウト
		case 0:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_TIMEOUT);
			return(-1);

		//	切断
		case 2:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_CLOSE);
			return(0);

		//	中断
		case 3:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_BREAK);
			return(-1);

		//	正常
		case 1:
		default:
			break;
		}

		//	結果取得
		DWORD	flags;
		if(!WSAGetOverlappedResult(m_socket, &ovr, &sended, FALSE, &flags))
		{
			SetLastError();
			return(-1);
		}

		//	切断？
		if(sended == 0)
		{
			SetLastError(OVRS_ERROR_CLOSE);
			return(0);
		}
	}

	return(sended);
}

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

	return -1:エラー、0:切断、>0:成功
*/
int COverlappedSocket::BlockingRecv(char *buf, int len, int timeOut)
{
	//	初期化済み？
	if(m_socket == INVALID_SOCKET)
		return(-1);

	//	タイムアウトは設定されてる？
	if(timeOut == -1)
		timeOut = m_timeout;

	//	イベント初期化
	::ResetEvent(m_event);

	//	オーバーラップ構造体初期化
	WSAOVERLAPPED	ovr;
	INIT_OVERLAPPED(ovr, m_event);

	//	バッファ準備
	WSABUF	wsaBuf;
	wsaBuf.buf = buf;
	wsaBuf.len = len;

	//	受信
	DWORD	recved = 0, flags = 0;
	if(::WSARecv(m_socket, &wsaBuf, 1, &recved, &flags, &ovr, NULL) == SOCKET_ERROR)
	{
		if(WSAGetLastError() != WSA_IO_PENDING)
		{
			SetLastError();
			return(-1);
		}

		//	終了を待つ
		switch(CThreadSkeleton::WaitForSomeObjects(timeOut, m_event, m_closeEvent, m_breakEvent))
		{
		//	タイムアウト
		case 0:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_TIMEOUT);
			return(-1);

		//	切断
		case 2:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_CLOSE);
			return(0);

		//	中断
		case 3:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_BREAK);
			return(-1);

		//	正常
		case 1:
		default:
			break;
		}

		//	結果取得
		DWORD	flags;
		if(!WSAGetOverlappedResult(m_socket, &ovr, &recved, FALSE, &flags))
		{
			SetLastError();
			return(-1);
		}

		//	切断？
		if(recved == 0)
		{
			SetLastError(OVRS_ERROR_CLOSE);
			return(0);
		}
	}

	return(recved);
}

/*!
	切断しているか取得
*/
int COverlappedSocket::IsDisconnect()
{
	if(m_socket == INVALID_SOCKET)
		return(TRUE);

	//	イベントを待つ
	switch(CThreadSkeleton::WaitForSomeObjects(0, m_closeEvent))
	{
	case 0:
		return(FALSE);

	case 1:
	default:
		SetLastError(OVRS_ERROR_CLOSE);
		return(TRUE);

	}
}


/*!
	最終エラー設定
*/
void COverlappedSocket::SetLastError(int error)
{
	if(error != OVRS_ERROR_AUTO_SET)
	{
		m_lastError = error;
	}
	else
	{
		switch(WSAGetLastError())
		{
		case WSAECONNRESET:
		case WSAECONNABORTED:
			m_lastError = OVRS_ERROR_CLOSE;
			break;

		default:
			m_lastError = OVRS_ERROR_OTHER;
			break;
		}
	}
}

