#include "StdAfx.h"
#include "PipeClient.h"
#include "Utility.h"
#include "OGCAssist.h"

std::string CPipeClient::m_LastData;
PER_IO_CONTEXT CPipeClient::m_IoRead;
PER_IO_CONTEXT CPipeClient::m_IoWrite;

CPipeClient::CPipeClient(LPCTSTR lpPipeName, DWORD dwMode)
{
    m_hPipeInst = INVALID_HANDLE_VALUE;
    m_bClientStop = FALSE;
    m_dwMode = dwMode;
    memset(m_szPipeName, 0, MAX_PATH*sizeof(TCHAR));
    if ( lpPipeName )
        _stprintf_s(m_szPipeName, _T("%s"), lpPipeName);
}

CPipeClient::~CPipeClient(void)
{
    StopWork();
    if ( m_hPipeInst != INVALID_HANDLE_VALUE )
        CloseHandle(m_hPipeInst);
}

BOOL CPipeClient::StartWork()
{
    if ( !m_bClientStop )
    {
        BOOL bRet = TRUE;
        HANDLE hConnect = CreateThread(NULL, 0, ConnectThread, this, 0, NULL);
        HANDLE hReadMsg = CreateThread(NULL, 0, ReadMsgThread, this, 0, NULL);

        if ( hConnect == NULL || hReadMsg == NULL )
            bRet = FALSE;

        if ( hConnect )
            CloseHandle(hConnect);

        if ( hReadMsg )
            CloseHandle(hReadMsg);

        return bRet;
    }

    return TRUE;
}

DWORD CPipeClient::ConnectThread(LPVOID lpParam)
{
    CPipeClient *pInstance = (CPipeClient*)lpParam;
    if ( !pInstance ) 
        return 0L;

    while(!pInstance->m_bClientStop)
    {
        if ( pInstance->m_hPipeInst != INVALID_HANDLE_VALUE ) {
            // 1分钟检测;
            Sleep(10000);
            //Utility::dprintf(_T("m_hPipeInst 已存在\n"));
            continue;
        }

        // 等待10秒;
        if ( !WaitNamedPipe(pInstance->m_szPipeName, 10000) )
        {// 如果管道不存在,会立即返回而不考虑超时值,所以此处仍要Sleep;
            Utility::dprintf(_T("<%ld> WaitNamedPipe 失败\n"), Utility::g_WndInfo.dwProcessId);
            Sleep(10000);
            continue;
        }

		Utility::dprintf(_T("<%ld> WaitNamedPipe 成功\n"), Utility::g_WndInfo.dwProcessId);

        pInstance->m_hPipeInst = CreateFile(
            pInstance->m_szPipeName,        // pipe name 
            GENERIC_READ | GENERIC_WRITE,   // read and write access 
            0,                              // no sharing 
            NULL,                           // default security attributes
            OPEN_EXISTING,                  // opens existing pipe 
            FILE_FLAG_OVERLAPPED,			// default attributes 
            NULL);                          // no template file 

        // 创建成功，退出;
        if ( pInstance->m_hPipeInst != INVALID_HANDLE_VALUE ) 
        {
            // 管道连接成功，修改管道通信模式：message-read mode. 
            BOOL fSuccess = SetNamedPipeHandleState( 
                pInstance->m_hPipeInst,     // pipe handle 
                &pInstance->m_dwMode,       // new pipe mode 
                NULL,                       // don't set maximum bytes 
                NULL);                      // don't set maximum time 

            if (!fSuccess) {
                Utility::dprintf(_T("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError() ); 
                CloseHandle(pInstance->m_hPipeInst);
                pInstance->m_hPipeInst = INVALID_HANDLE_VALUE;
				continue;
            }

			Sleep(1500);
#pragma region 向服务端发送消息:劫持状态+按钮状态;			
			{
				MSG_INFO msg;
				msg.dwClientId = GetCurrentProcessId();
				_stprintf(msg.szClientName, _T("%s"), _T("OGCAssist"));
				// 连接状态;
				msg.byResult = Assist::bConnectStatus;
				_stprintf((TCHAR*)msg.byData, _T("%s"), _T("OGCAssist Connect"));

				DATAHEADER head;
				head.byMsgType = C2S_CONNECT;
				head.dwPackageLen = sizeof(DATAHEADER) + sizeof(MSG_INFO);

				pInstance->SendPackage(head, msg);
			}
#pragma endregion

#pragma region 通知服务端劫持状态;
			{
				MSG_INFO msg;
				msg.dwClientId = GetCurrentProcessId();
				_stprintf(msg.szClientName, _T("%s"), _T("OGCAssist"));
				// 劫持状态;
				msg.byResult = Assist::bHijacked;
				_stprintf((TCHAR*)msg.byData, _T("%s"), _T("OGCAssist Hijact"));

				DATAHEADER head;				
				head.byMsgType = C2S_INJECT;
				head.dwPackageLen = sizeof(DATAHEADER) + sizeof(MSG_INFO);

				Utility::g_pPipeClient->SendPackage(head, msg);
			}
#pragma endregion
        }
        else
        {
            // Exit if an error other than ERROR_PIPE_BUSY occurs. 
            if ( GetLastError() != ERROR_PIPE_BUSY ) 
            {
                Utility::dprintf(_T("Could not open pipe. GLE=%d\n"), GetLastError() ); 
            }
        }
    }

    Utility::dprintf(_T("<%ld> ConnectThread 退出\n"), Utility::g_WndInfo.dwProcessId);

    return 0;
}

DWORD CPipeClient::ReadMsgThread(LPVOID lpParam)
{   
    CPipeClient *pInstance = (CPipeClient*)lpParam;
    if ( !pInstance ) 
        return 0L;

	int i = 0;
	DWORD dwError = 0;
	BOOL bSuccess = FALSE;	
    while(!pInstance->m_bClientStop)
    {
        if ( pInstance->m_hPipeInst == INVALID_HANDLE_VALUE ) {
            Sleep(5000);
            continue;
        }

#if 1 // 分配足够大的缓冲,保证C/S两端通信内容不超过该大小;
        bSuccess = ReadFile(pInstance->m_hPipeInst, m_IoRead.szBuffer, BUFSIZE, &m_IoRead.dwBufferSize,	(OVERLAPPED*)&pInstance->m_IoRead);
        if ( bSuccess )
        {
            // 打印结果;
            //Utility::dprintf(_T("读取数据：Error=%ld, Len=%ld, Data=%s\n"), dwError, m_IoRead.m_Overlapped.InternalHigh, m_IoRead.szBuffer);
            // 处理结果;
        } 
        else
        {          
            // 等待完成;
            if ( !WaitFinish(pInstance->m_hPipeInst, &m_IoRead) )
            {
                // 出现错误;
                Utility::dprintf(_T("CloseHandle\n"));
                CloseHandle(pInstance->m_hPipeInst);
                pInstance->m_hPipeInst = INVALID_HANDLE_VALUE;
            }
            else
            {
                // 打印结果;
				bSuccess = TRUE;
                //Utility::dprintf(_T("读取数据：Error=%ld, Len=%ld, Data=%s\n"), dwError, m_IoRead.m_Overlapped.InternalHigh, m_IoRead.szBuffer);
                // 处理结果;
            }
        }

		if ( bSuccess )
		{
			DATAHEADER header;
			MSG_INFO msg_info;
			memcpy(&header, m_IoRead.szBuffer, sizeof(DATAHEADER));
			memcpy(&msg_info, m_IoRead.szBuffer+sizeof(DATAHEADER), sizeof(MSG_INFO));
			HandleMsg(header, msg_info);
		}
		
        // 重置Buffer;
        memset(m_IoRead.szBuffer, 0, BUFSIZE);
#else // 分配的缓冲区，不足以一次性存储C/S两端的通信内容时;
        do 
        { 
            bSuccess = ReadFile(pInstance->m_hPipeInst, m_IoRead.szBuffer, BUFSIZE, &m_IoRead.dwBufferSize, (OVERLAPPED*)&pInstance->m_IoRead);
            if ( bSuccess )
            {
                // 打印结果;
				dwError = GetLastError();// 此时bSuccess为True,但GetLastError仍为ERROR_MORE_DATA属于正常现象;
				m_LastData.append((char*)m_IoRead.szBuffer, m_IoRead.m_Overlapped.InternalHigh);
                // 处理结果;
            }
            else
            {
                dwError = GetLastError();
				if ( dwError == ERROR_MORE_DATA )
				{// 如果立即返回，没有IO PENDING;
					// 将当前数据保存;
					m_LastData.append((char*)m_IoRead.szBuffer, m_IoRead.m_Overlapped.InternalHigh);
				}
                else if ( dwError == ERROR_IO_PENDING )
				{
					DWORD dwWait = -1;
					DWORD dwTransBytes = -1;

					// 等待读写操作完成;
					dwWait = WaitForSingleObject(m_IoRead.m_Overlapped.hEvent,INFINITE);
					switch(dwWait)
					{
					case 0:
						// 获取Overlapped结果;
						if( GetOverlappedResult(pInstance->m_hPipeInst, &m_IoRead.m_Overlapped, &dwTransBytes, TRUE) == FALSE)
						{
							dwError = GetLastError();
							if ( dwError == ERROR_MORE_DATA )
							{
								m_LastData.append((char*)m_IoRead.szBuffer, m_IoRead.m_Overlapped.InternalHigh);
							}
							else
							{
								Utility::dprintf(_T("GetOverlappedResult：Error=%ld"), dwError);
							}
						}
						else
						{
							bSuccess = TRUE;
							Utility::dprintf(_T("GetOverlappedResult：Error=%ld"), GetLastError());
							m_LastData.append((char*)m_IoRead.szBuffer, m_IoRead.m_Overlapped.InternalHigh);
						}
						break;
						// 读写完成;
					case WAIT_IO_COMPLETION:
						break;
					}
				}
				else if ( dwError == ERROR_PIPE_CONNECTED )
				{// 管道的另一端有一个过程;
					DWORD dwWait = -1;
					DWORD dwTransBytes = -1;
					SetEvent(m_IoRead.m_Overlapped.hEvent);
					Utility::dprintf(_T("管道的另一端有一个过程：ERROR_PIPE_CONNECTED\n"));
					dwWait = WaitForSingleObject(m_IoRead.m_Overlapped.hEvent,INFINITE);
				}
            }           

			// 清空缓存数据;
			memset(m_IoRead.szBuffer, 0, BUFSIZE);
        } while ( !bSuccess );  // repeat loop if ERROR_MORE_DATA 

        
		Utility::dprintf(_T("读取数据：Error=%ld, Len=%ld, Data=%s\n"), dwError, m_LastData.size(), m_LastData.data());
		m_LastData.clear();
#endif
    }

    Utility::dprintf(_T("<%ld> ReadMsgThread 退出\n"),Utility::g_WndInfo.dwProcessId);

    return 0;
}

BOOL CPipeClient::WaitFinish(HANDLE hPipe, PER_IO_CONTEXT *pIoContext)
{
	bool bPendingIO = false;
	switch(GetLastError())
	{
		// 正在连接中;
	case ERROR_IO_PENDING:
		bPendingIO = true;
		break;
    case ERROR_MORE_DATA:
        break;
		// 已经连接;
	case ERROR_PIPE_CONNECTED:
		SetEvent(pIoContext->m_Overlapped.hEvent);
		break;
	}

	DWORD dwWait = -1;
	DWORD dwTransBytes = -1;

	// 等待读写操作完成;
	dwWait = WaitForSingleObject(pIoContext->m_Overlapped.hEvent,INFINITE);
	switch(dwWait)
	{
	case 0:
		if (bPendingIO)
		{
			// 获取Overlapped结果;
			if( GetOverlappedResult(hPipe, &pIoContext->m_Overlapped, &dwTransBytes, TRUE) == FALSE)
			{
				printf("ConnectNamedPipe  failed   %d\n",GetLastError());
				return FALSE;
			}
		}
		break;
		// 读写完成;
	case WAIT_IO_COMPLETION:
		break;
	}

	return TRUE;
}

void CPipeClient::HandleMsg(DATAHEADER &head, MSG_INFO &msg)
{
	if ( head.byProtocol != 0xAC )
	{

	}

	if ( head.dwPackageLen != (sizeof(DATAHEADER)+sizeof(MSG_INFO)) )
	{

	}

	if ( msg.dwClientId != GetCurrentProcessId() )
	{

	}

	if ( _tcscmp(msg.szClientName, _T("OGCAssist")) != 0 )
	{

	}

	Utility::dprintf(_T("接收到服务端消息：Result=%d, Tpye=%d, Proctocl=%d, Len=%ld, Name=%s, Id=%ld, Data=%s"), 
		msg.byResult,
		head.byMsgType, 
		head.byProtocol, 
		head.dwPackageLen, 
		msg.szClientName,
		msg.dwClientId,
		msg.byData
		);

	// 正常处理流程;
	switch(head.byMsgType)
	{
	case S2C_INJECT:		// 劫持dll;
		break;
	case S2C_EJECT:			// 恢复dll;
		break;
	case S2C_CONNECT:		// 触发connect按钮;
		break;
	case S2C_DISCONNECT:	// 触发disconnect按钮;
		break;
	case S2C_CHECKFW:		// 触发checkfw按钮;
		break;
	case S2C_GO:			// 触发go按钮;
		break;
	default:
		break;
	}
}

BOOL CPipeClient::SendPackage(PACKAGE &pak)
{
	std::string data;
	data.append((char*)&pak.header, sizeof(DATAHEADER));
	//data.append((char*)(MSG_INFO*)pak.buf, sizeof(MSG_INFO));
	data.append((char*)pak.buf, sizeof(MSG_INFO));

	return SendData((LPBYTE)data.data(), data.size());
}

BOOL CPipeClient::SendPackage(DATAHEADER &head, MSG_INFO &msg)
{
	std::string data;
	data.append((char*)&head, sizeof(DATAHEADER));
	//data.append((char*)(MSG_INFO*)pak.buf, sizeof(MSG_INFO));
	data.append((char*)&msg, sizeof(MSG_INFO));
	Utility::dprintf(_T("发送消息：Result=%d, Tpye=%d, Proctocl=%d, Len=%ld, Name=%s, Id=%ld, Data=%s"), 
		msg.byResult,
		head.byMsgType, 
		head.byProtocol, 
		head.dwPackageLen, 
		msg.szClientName,
		msg.dwClientId,
		msg.byData
		);
	return SendData((LPBYTE)data.data(), data.size());
}

BOOL CPipeClient::SendData(LPBYTE lpData, DWORD dwDataLen)
{
	if ( m_hPipeInst == INVALID_HANDLE_VALUE ) 
		return FALSE;

	if ( !lpData || dwDataLen == 0 )
		return FALSE;

	// 发送数据使用同步模式;
	DWORD dwNumberOfBytesWritten = 0;
	BOOL fWrite = WriteFile(m_hPipeInst, lpData, dwDataLen, &dwNumberOfBytesWritten, NULL);
	Utility::dprintf(_T("SendData：Error=%ld, %d\n"), GetLastError(), fWrite);

	return fWrite;
}