#include "StdAfx.h"
#include "PipePair.h"
#include "ThreadSkeleton.h"

////////////////////////////////////////////////////////////////////
//	作成
////////////////////////////////////////////////////////////////////
/*!
	オーバーラップフラグを設定したパイプを作成
*/
int CPipePair::CreateOvrlappedPipe(CString uniqueCode, int bufSize)
{
	//	閉じておく
	Close();

	//	セキュリティ属性
	SECURITY_ATTRIBUTES	sa;
	memset(&sa, 0, sizeof(sa));
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;	//	ハンドル継承可

	// 書き込みパイプの作成の作成
	m_hWritePipe = ::CreateNamedPipe("\\\\.\\pipe\\_04WebServer_SUBPROCESS_" + uniqueCode,
				PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE,
				1, bufSize, bufSize, 1000, &sa);
	if(m_hWritePipe == INVALID_HANDLE_VALUE )
		return(-1);

	//	読み込みパイプの作成
	m_hReadPipe = ::CreateFile("\\\\.\\pipe\\_04WebServer_SUBPROCESS_" + uniqueCode,
				GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
	if(m_hReadPipe == INVALID_HANDLE_VALUE )
	{
		SAFE_CLOSE_HANDLE(m_hWritePipe);
		return(-1);
	}

	//	パイプ接続
	if(!::ConnectNamedPipe(m_hWritePipe, NULL) && GetLastError() != ERROR_PIPE_CONNECTED)
	{
		SAFE_CLOSE_HANDLE(m_hWritePipe);
		SAFE_CLOSE_HANDLE(m_hReadPipe);
		return(-1);
	}

	return(0);
}

///////////////////////////////////////////////////////////////////////
//	通信
///////////////////////////////////////////////////////////////////////
/*!
	出力
*/
int CPipePair::Write(CBinaryData &buf, HANDLE breakEvent, int timeout)
{
	//	イベント初期化
	::ResetEvent(m_rwEvent);

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

	//	プロセスへ送信
	DWORD	sended = 0;
	if(!WriteFile(GetWritePipe(), buf.GetPtr(), buf.GetSize(), &sended, &ovr))
	{
		//	エラー？
		if(GetLastError() != ERROR_IO_PENDING)
			return(-1);

		//	完了を待つ
		if(WaitComplete(GetWritePipe(), &ovr, sended, breakEvent, timeout))
			return(-1);
	}

	return(sended);
}

/*!
	読み出し
*/
int CPipePair::Read(CBinaryData &buf, int blockSize, HANDLE breakEvent, int timeout)
{
	//	バッファ初期化
	buf.ReSize(blockSize);

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

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

	//	プロセスへ送信
	DWORD	readed = 0;
	if(!ReadFile(GetReadPipe(), buf.GetPtr(), buf.GetSize(), &readed, &ovr))
	{
		//	EOF?
		if(GetLastError() == ERROR_HANDLE_EOF)
			readed = 0;
		else
		{
			//	エラー？
			if(GetLastError() != ERROR_IO_PENDING)
				return(-1);

			//	完了を待つ
			if(WaitComplete(GetReadPipe(), &ovr, readed, breakEvent, timeout))
				return(-1);
		}
	}

	//	サイズ設定
	buf.ReSize(readed);
	return(readed);
}

/*!
	読み出し(非破壊)
*/
int CPipePair::Peek(CBinaryData &buf, int blockSize)
{
	//	バッファ初期化
	buf.ReSize(blockSize);

	//	読み出してみる
	DWORD	readed = 0;
	if(!PeekNamedPipe(GetReadPipe(), buf.GetPtr(), buf.GetSize(), &readed, NULL, NULL))
		return(-1);

	//	サイズ設定
	buf.ReSize(readed);
	return(readed);
}


//////////////////////////////////////////////////////////////////////////////////////////////
//	補助関数
//////////////////////////////////////////////////////////////////////////////////////////////
/*!
	イベントを待ちながら、切断チェック

*/
int CPipePair::WaitComplete(HANDLE pipe, LPOVERLAPPED ovr, DWORD &transCount, HANDLE breakEvent, int timeout)
{
	//	終了を待つ
	switch(CThreadSkeleton::WaitForSomeObjects(timeout, m_rwEvent, breakEvent))
	{
	//	正常
	case 1:
		if(!GetOverlappedResult(pipe, ovr, &transCount, FALSE))
			return(0);
		if(GetLastError() == ERROR_HANDLE_EOF)
		{
			transCount = 0;
			return(0);
		}
		return(-1);

	//	タイムアウト or 中断
	case 0:
	case 2:
	default:
		CancelIo(pipe);
		return(-1);
	}
}
