/*!
	OverlappedSocket.cpp

	オーバーラップI/O対応ソケットクラス
*/
#include "StdAfx.h"
#include "OverlappedSocket.h"
#include "ThreadSkeleton.h"

//////////////////////////////////////////////////////////////////////////////////
//	コンストラクタ
//////////////////////////////////////////////////////////////////////////////////
COverlappedSocket::COverlappedSocket(void)
{
	m_event.Create(TRUE, FALSE);
	m_socket = INVALID_SOCKET;
	m_timeout = INFINITE;
	m_breakEvent = NULL;

	SetLastError(OVRS_ERROR_NO_ERROR);
}

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

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

/*!
	閉じる
*/
void COverlappedSocket::Close()
{
	if(m_socket != INVALID_SOCKET)
	{
		//	ソケット無効化
		shutdown(m_socket,1);

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

		m_socket = INVALID_SOCKET;
	}
}

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

	return -1:エラー、>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_breakEvent))
		{
		//	タイムアウト
		case 0:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_TIMEOUT);
			return(-1);

		//	中断
		case 2:
			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);
		}
	}

	return(sended);
}

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

	return -1:エラー、0:タイムアウト or 中断、>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_breakEvent))
		{
		//	タイムアウト
		case 0:
			CancelIo((HANDLE)m_socket);
			SetLastError(OVRS_ERROR_TIMEOUT);
			return(-1);

		//	中断
		case 2:
			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);
		}
	}

	return(recved);
}

/*!
	最終エラー設定
*/
void COverlappedSocket::SetLastError(int error)
{
	if(error != OVRS_ERROR_AUTO_SET)
	{
		m_lastError = error;

	}
	else
	{
		switch(WSAGetLastError())
		{
		case WSAECONNRESET:
			m_lastError = OVRS_ERROR_CLOSE;
			break;

		default:
			m_lastError = OVRS_ERROR_OTHER;
			break;
		}
	}
}

