557 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			557 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Detours Test Program (syelogd.cpp of syelogd.exe)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Microsoft Research Detours Package
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Copyright (c) Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								#include <windows.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stddef.h>
							 | 
						||
| 
								 | 
							
								#pragma warning(push)
							 | 
						||
| 
								 | 
							
								#if _MSC_VER > 1400
							 | 
						||
| 
								 | 
							
								#pragma warning(disable:6102 6103) // /analyze warnings
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#include <strsafe.h>
							 | 
						||
| 
								 | 
							
								#pragma warning(pop)
							 | 
						||
| 
								 | 
							
								#include "syelog.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if (_MSC_VER < 1299)
							 | 
						||
| 
								 | 
							
								typedef ULONG * PULONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef ULONG ULONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef LONG * PLONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef LONG LONG_PTR;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum {
							 | 
						||
| 
								 | 
							
								    CLIENT_AWAITING_PIPE_ACCEPT = 0x21,
							 | 
						||
| 
								 | 
							
								    CLIENT_AWAITING_PIPE_DATA   = 0x22,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct _CLIENT : OVERLAPPED
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE          hPipe;
							 | 
						||
| 
								 | 
							
								    BOOL            fAwaitingAccept;
							 | 
						||
| 
								 | 
							
								    PVOID           Zero;
							 | 
						||
| 
								 | 
							
								    SYELOG_MESSAGE  Message;
							 | 
						||
| 
								 | 
							
								} CLIENT, *PCLIENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								BOOL        s_fLogToScreen  = TRUE;     // Log output to screen.
							 | 
						||
| 
								 | 
							
								BOOL        s_fExitAfterOne = FALSE;
							 | 
						||
| 
								 | 
							
								BOOL        s_fDeltaTime    = FALSE;
							 | 
						||
| 
								 | 
							
								HANDLE      s_hOutFile      = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								LONG        s_nActiveClients = 0;
							 | 
						||
| 
								 | 
							
								LONGLONG    s_llStartTime = 0;
							 | 
						||
| 
								 | 
							
								LONGLONG    s_llLastTime = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL LogMessageV(BYTE nSeverity, PCHAR pszMsg, ...);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								VOID MyErrExit(PCSTR pszMsg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DWORD error = GetLastError();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    LogMessageV(SYELOG_SEVERITY_FATAL, "Error %d in %s.", error, pszMsg);
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "SYELOGD: Error %ld in %s.\n", error, pszMsg);
							 | 
						||
| 
								 | 
							
								    fflush(stderr);
							 | 
						||
| 
								 | 
							
								    exit(1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								static PCSTR FileTimeToString(PCHAR pszBuffer, DWORD cbBuffer, FILETIME ftTime)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    (void)cbBuffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    static BOOL bGotTzi = FALSE;
							 | 
						||
| 
								 | 
							
								    static DWORD dwTzi = TIME_ZONE_ID_UNKNOWN;
							 | 
						||
| 
								 | 
							
								    static TIME_ZONE_INFORMATION tzi;
							 | 
						||
| 
								 | 
							
								    if (!bGotTzi) {
							 | 
						||
| 
								 | 
							
								        dwTzi = GetTimeZoneInformation(&tzi);
							 | 
						||
| 
								 | 
							
								        if (dwTzi == TIME_ZONE_ID_UNKNOWN) {
							 | 
						||
| 
								 | 
							
								            ZeroMemory(&tzi, sizeof(tzi));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        bGotTzi = TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    SYSTEMTIME stUtc;
							 | 
						||
| 
								 | 
							
								    SYSTEMTIME stLocal;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pszBuffer[0] = '\0';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_fDeltaTime) {
							 | 
						||
| 
								 | 
							
								        if (s_llLastTime == 0) {
							 | 
						||
| 
								 | 
							
								            s_llLastTime = s_llStartTime;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ULARGE_INTEGER ul;
							 | 
						||
| 
								 | 
							
								        ul.LowPart = ftTime.dwLowDateTime;
							 | 
						||
| 
								 | 
							
								        ul.HighPart = ftTime.dwHighDateTime;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        LONG64 delta = ul.QuadPart - s_llLastTime;
							 | 
						||
| 
								 | 
							
								        s_llLastTime = ul.QuadPart;
							 | 
						||
| 
								 | 
							
								        delta /= 10000;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        StringCchPrintfA(pszBuffer, cbBuffer, "%7I64d", delta);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        if (!FileTimeToSystemTime(&ftTime, &stUtc)) {
							 | 
						||
| 
								 | 
							
								            StringCchPrintfA(pszBuffer, cbBuffer, "ft:%16I64d", *(LONGLONG *)&ftTime);
							 | 
						||
| 
								 | 
							
								            return pszBuffer;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (!SystemTimeToTzSpecificLocalTime(&tzi, &stUtc, &stLocal)) {
							 | 
						||
| 
								 | 
							
								            CopyMemory(&stLocal, &stUtc, sizeof(stLocal));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        StringCchPrintfA(pszBuffer, cbBuffer, "%4d%02d%02d%02d%02d%02d%03d",
							 | 
						||
| 
								 | 
							
								                         stLocal.wYear,
							 | 
						||
| 
								 | 
							
								                         stLocal.wMonth,
							 | 
						||
| 
								 | 
							
								                         stLocal.wDay,
							 | 
						||
| 
								 | 
							
								                         stLocal.wHour,
							 | 
						||
| 
								 | 
							
								                         stLocal.wMinute,
							 | 
						||
| 
								 | 
							
								                         stLocal.wSecond,
							 | 
						||
| 
								 | 
							
								                         stLocal.wMilliseconds);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return pszBuffer;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL CloseConnection(PCLIENT pClient)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    LogMessageV(SYELOG_SEVERITY_INFORMATION, "Client closed pipe.");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    InterlockedDecrement(&s_nActiveClients);
							 | 
						||
| 
								 | 
							
								    if (pClient != NULL) {
							 | 
						||
| 
								 | 
							
								        if (pClient->hPipe != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								            FlushFileBuffers(pClient->hPipe);
							 | 
						||
| 
								 | 
							
								            if (!DisconnectNamedPipe(pClient->hPipe)) {
							 | 
						||
| 
								 | 
							
								                MyErrExit("DisconnectNamedPipe");
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            CloseHandle(pClient->hPipe);
							 | 
						||
| 
								 | 
							
								            pClient->hPipe = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        GlobalFree(pClient);
							 | 
						||
| 
								 | 
							
								        pClient = NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_fExitAfterOne) {
							 | 
						||
| 
								 | 
							
								        ExitProcess(0);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Creates a pipe instance and initiate an accept request.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								PCLIENT CreatePipeConnection(HANDLE hCompletionPort)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE hPipe = CreateNamedPipe(SYELOG_PIPE_NAME,           // pipe name
							 | 
						||
| 
								 | 
							
								                                   PIPE_ACCESS_INBOUND |       // read-only access
							 | 
						||
| 
								 | 
							
								                                   FILE_FLAG_OVERLAPPED,       // overlapped mode
							 | 
						||
| 
								 | 
							
								                                   PIPE_TYPE_MESSAGE |         // message-type pipe
							 | 
						||
| 
								 | 
							
								                                   PIPE_READMODE_MESSAGE |     // message read mode
							 | 
						||
| 
								 | 
							
								                                   PIPE_WAIT,                   // blocking mode
							 | 
						||
| 
								 | 
							
								                                   PIPE_UNLIMITED_INSTANCES,   // unlimited instances
							 | 
						||
| 
								 | 
							
								                                   0,                          // output buffer size
							 | 
						||
| 
								 | 
							
								                                   0,                          // input buffer size
							 | 
						||
| 
								 | 
							
								                                   20000,                      // client time-out
							 | 
						||
| 
								 | 
							
								                                   NULL);                      // no security attributes
							 | 
						||
| 
								 | 
							
								    if (hPipe == INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreatePipe");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Allocate the client data structure.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    PCLIENT pClient = (PCLIENT) GlobalAlloc(GPTR, sizeof(CLIENT));
							 | 
						||
| 
								 | 
							
								    if (pClient == NULL) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("GlobalAlloc pClient");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ZeroMemory(pClient, sizeof(*pClient));
							 | 
						||
| 
								 | 
							
								    pClient->hPipe = hPipe;
							 | 
						||
| 
								 | 
							
								    pClient->fAwaitingAccept = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Associate file with our complietion port.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    if (!CreateIoCompletionPort(pClient->hPipe, hCompletionPort, (ULONG_PTR)pClient, 0)) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateIoComplietionPort pClient");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!ConnectNamedPipe(hPipe, pClient)) {
							 | 
						||
| 
								 | 
							
								        if (GetLastError() != ERROR_IO_PENDING &&
							 | 
						||
| 
								 | 
							
								            GetLastError() != ERROR_PIPE_LISTENING) {
							 | 
						||
| 
								 | 
							
								            MyErrExit("ConnectNamedPipe");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        LogMessageV(SYELOG_SEVERITY_INFORMATION,
							 | 
						||
| 
								 | 
							
								                    "ConnectNamedPipe accepted immediately.");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return pClient;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL LogMessageV(BYTE nSeverity, PCHAR pszMsg, ...)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    FILETIME ftOccurance;
							 | 
						||
| 
								 | 
							
								    CHAR szTime[64];
							 | 
						||
| 
								 | 
							
								    GetSystemTimeAsFileTime(&ftOccurance);
							 | 
						||
| 
								 | 
							
								    FileTimeToString(szTime, sizeof(szTime), ftOccurance);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_fLogToScreen) {
							 | 
						||
| 
								 | 
							
								        printf(s_fDeltaTime
							 | 
						||
| 
								 | 
							
								               ? "%-7.7s ---- --.%02x: "
							 | 
						||
| 
								 | 
							
								               : "%-17.17s ---- --.%02x: "
							 | 
						||
| 
								 | 
							
								               , szTime, nSeverity);
							 | 
						||
| 
								 | 
							
								        va_list args;
							 | 
						||
| 
								 | 
							
								        va_start(args, pszMsg);
							 | 
						||
| 
								 | 
							
								        vprintf(pszMsg, args);
							 | 
						||
| 
								 | 
							
								        va_end(args);
							 | 
						||
| 
								 | 
							
								        printf("\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (s_hOutFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        DWORD cbWritten = 0;
							 | 
						||
| 
								 | 
							
								        CHAR szBuf[4096] = "";
							 | 
						||
| 
								 | 
							
								        PCHAR pcchEnd = szBuf + ARRAYSIZE(szBuf) - 2;
							 | 
						||
| 
								 | 
							
								        PCHAR pcchCur = szBuf;
							 | 
						||
| 
								 | 
							
								        HRESULT hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        hr = StringCchPrintfExA(pcchCur, pcchEnd - pcchCur,
							 | 
						||
| 
								 | 
							
								                                &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                                s_fDeltaTime
							 | 
						||
| 
								 | 
							
								                                ? "%-7.7s ---- --.%02x: "
							 | 
						||
| 
								 | 
							
								                                : "%-17.17s ---- --.%02x: "
							 | 
						||
| 
								 | 
							
								                                , szTime, nSeverity);
							 | 
						||
| 
								 | 
							
								        if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								            goto Cleanup;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        va_list args;
							 | 
						||
| 
								 | 
							
								        va_start(args, pszMsg);
							 | 
						||
| 
								 | 
							
								        hr = StringCchPrintfExA(pcchCur, pcchEnd - pcchCur,
							 | 
						||
| 
								 | 
							
								                                &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                                pszMsg, args);
							 | 
						||
| 
								 | 
							
								        va_end(args);
							 | 
						||
| 
								 | 
							
								        if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								            goto Cleanup;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        hr = StringCchPrintfExA(pcchCur, (szBuf + ARRAYSIZE(szBuf)) - pcchCur,
							 | 
						||
| 
								 | 
							
								                                &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                                 "\n");
							 | 
						||
| 
								 | 
							
								        if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								            goto Cleanup;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Cleanup:
							 | 
						||
| 
								 | 
							
								        WriteFile(s_hOutFile, szBuf, (DWORD)(pcchCur - szBuf), &cbWritten, NULL);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL LogMessage(PSYELOG_MESSAGE pMessage, DWORD nBytes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Sanity check the size of the message.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    if (nBytes > pMessage->nBytes) {
							 | 
						||
| 
								 | 
							
								        nBytes = pMessage->nBytes;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (nBytes >= sizeof(*pMessage)) {
							 | 
						||
| 
								 | 
							
								        nBytes = sizeof(*pMessage) - 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Don't log message if there isn't and message text.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    if (nBytes <= offsetof(SYELOG_MESSAGE, szMessage)) {
							 | 
						||
| 
								 | 
							
								        return FALSE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CHAR szTime[64];
							 | 
						||
| 
								 | 
							
								    FileTimeToString(szTime, sizeof(szTime), pMessage->ftOccurance);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    PCHAR pszMsg = pMessage->szMessage;
							 | 
						||
| 
								 | 
							
								    while (*pszMsg) {
							 | 
						||
| 
								 | 
							
								        pszMsg++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    while (pszMsg > pMessage->szMessage && isspace(pszMsg[-1])) {
							 | 
						||
| 
								 | 
							
								        *--pszMsg = '\0';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_fLogToScreen) {
							 | 
						||
| 
								 | 
							
								        printf(s_fDeltaTime
							 | 
						||
| 
								 | 
							
								               ? "%-7.7s %4d %02x.%02x: %s\n"
							 | 
						||
| 
								 | 
							
								               : "%-17.17s %4d %02x.%02x: %s\n",
							 | 
						||
| 
								 | 
							
								               szTime,
							 | 
						||
| 
								 | 
							
								               pMessage->nProcessId,
							 | 
						||
| 
								 | 
							
								               pMessage->nFacility,
							 | 
						||
| 
								 | 
							
								               pMessage->nSeverity,
							 | 
						||
| 
								 | 
							
								               pMessage->szMessage);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (s_hOutFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        DWORD cbWritten = 0;
							 | 
						||
| 
								 | 
							
								        CHAR szBuf[4096];
							 | 
						||
| 
								 | 
							
								        PCHAR pcchEnd = szBuf + ARRAYSIZE(szBuf);
							 | 
						||
| 
								 | 
							
								        PCHAR pcchCur = szBuf;
							 | 
						||
| 
								 | 
							
								        HRESULT hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        hr = StringCchPrintfExA(pcchCur, pcchEnd - pcchCur,
							 | 
						||
| 
								 | 
							
								                                &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                                s_fDeltaTime
							 | 
						||
| 
								 | 
							
								                                ? "%-7.7s %4d %02x.%02x: %s\n"
							 | 
						||
| 
								 | 
							
								                                : "%-17.17s %4d %02x.%02x: %s\n",
							 | 
						||
| 
								 | 
							
								                                szTime,
							 | 
						||
| 
								 | 
							
								                                pMessage->nProcessId,
							 | 
						||
| 
								 | 
							
								                                pMessage->nFacility,
							 | 
						||
| 
								 | 
							
								                                pMessage->nSeverity,
							 | 
						||
| 
								 | 
							
								                                pMessage->szMessage);
							 | 
						||
| 
								 | 
							
								        if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								            goto Cleanup;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Cleanup:
							 | 
						||
| 
								 | 
							
								        WriteFile(s_hOutFile, szBuf, (DWORD)(pcchCur - szBuf), &cbWritten, NULL);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DWORD WINAPI WorkerThread(LPVOID pvVoid)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    PCLIENT pClient;
							 | 
						||
| 
								 | 
							
								    BOOL b;
							 | 
						||
| 
								 | 
							
								    LPOVERLAPPED lpo;
							 | 
						||
| 
								 | 
							
								    DWORD nBytes;
							 | 
						||
| 
								 | 
							
								    HANDLE hCompletionPort = (HANDLE)pvVoid;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (BOOL fKeepLooping = TRUE; fKeepLooping;) {
							 | 
						||
| 
								 | 
							
								        pClient = NULL;
							 | 
						||
| 
								 | 
							
								        lpo = NULL;
							 | 
						||
| 
								 | 
							
								        nBytes = 0;
							 | 
						||
| 
								 | 
							
								        b = GetQueuedCompletionStatus(hCompletionPort,
							 | 
						||
| 
								 | 
							
								                                      &nBytes, (PULONG_PTR)&pClient, &lpo, INFINITE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!b || lpo == NULL) {
							 | 
						||
| 
								 | 
							
								            fKeepLooping = FALSE;
							 | 
						||
| 
								 | 
							
								            MyErrExit("GetQueuedCompletionState");
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (!b) {
							 | 
						||
| 
								 | 
							
								            if (pClient) {
							 | 
						||
| 
								 | 
							
								                if (GetLastError() == ERROR_BROKEN_PIPE) {
							 | 
						||
| 
								 | 
							
								                    LogMessageV(SYELOG_SEVERITY_INFORMATION, "Client closed pipe.");
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    LogMessageV(SYELOG_SEVERITY_ERROR,
							 | 
						||
| 
								 | 
							
								                                "GetQueuedCompletionStatus failed %d [%p]",
							 | 
						||
| 
								 | 
							
								                                GetLastError(), pClient);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (pClient->fAwaitingAccept) {
							 | 
						||
| 
								 | 
							
								            InterlockedIncrement(&s_nActiveClients);
							 | 
						||
| 
								 | 
							
								            pClient->fAwaitingAccept = FALSE;
							 | 
						||
| 
								 | 
							
								            b = ReadFile(pClient->hPipe,
							 | 
						||
| 
								 | 
							
								                         &pClient->Message,
							 | 
						||
| 
								 | 
							
								                         sizeof(pClient->Message),
							 | 
						||
| 
								 | 
							
								                         &nBytes,
							 | 
						||
| 
								 | 
							
								                         pClient);
							 | 
						||
| 
								 | 
							
								            if (!b) {
							 | 
						||
| 
								 | 
							
								                if (GetLastError() != ERROR_IO_PENDING) {
							 | 
						||
| 
								 | 
							
								                    LogMessageV(SYELOG_SEVERITY_ERROR,
							 | 
						||
| 
								 | 
							
								                                "ReadFile failed %d.", GetLastError());
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            CreatePipeConnection(hCompletionPort);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            if (nBytes < offsetof(SYELOG_MESSAGE, szMessage)) {
							 | 
						||
| 
								 | 
							
								                CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (pClient->Message.fTerminate) {
							 | 
						||
| 
								 | 
							
								                LogMessageV(SYELOG_SEVERITY_NOTICE,
							 | 
						||
| 
								 | 
							
								                            "Client requested terminate on next connection close.");
							 | 
						||
| 
								 | 
							
								                s_fExitAfterOne = TRUE;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            LogMessage(&pClient->Message, nBytes);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            b = ReadFile(pClient->hPipe,
							 | 
						||
| 
								 | 
							
								                         &pClient->Message,
							 | 
						||
| 
								 | 
							
								                         sizeof(pClient->Message),
							 | 
						||
| 
								 | 
							
								                         &nBytes,
							 | 
						||
| 
								 | 
							
								                         pClient);
							 | 
						||
| 
								 | 
							
								            if (!b && GetLastError() == ERROR_BROKEN_PIPE) {
							 | 
						||
| 
								 | 
							
								                CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL CreateWorkers(HANDLE hCompletionPort)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DWORD dwThread;
							 | 
						||
| 
								 | 
							
								    HANDLE hThread;
							 | 
						||
| 
								 | 
							
								    DWORD i;
							 | 
						||
| 
								 | 
							
								    SYSTEM_INFO SystemInfo;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GetSystemInfo(&SystemInfo);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < 2 * SystemInfo.dwNumberOfProcessors; i++) {
							 | 
						||
| 
								 | 
							
								        hThread = CreateThread(NULL, 0, WorkerThread, hCompletionPort, 0, &dwThread);
							 | 
						||
| 
								 | 
							
								        if (!hThread) {
							 | 
						||
| 
								 | 
							
								            MyErrExit("CreateThread WorkerThread");
							 | 
						||
| 
								 | 
							
								            // Unreachable: return FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        CloseHandle(hThread);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								BOOL WINAPI ControlHandler(DWORD dwCtrlType)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (dwCtrlType) {
							 | 
						||
| 
								 | 
							
								      case CTRL_C_EVENT:
							 | 
						||
| 
								 | 
							
								      case CTRL_BREAK_EVENT:
							 | 
						||
| 
								 | 
							
								      case CTRL_CLOSE_EVENT:
							 | 
						||
| 
								 | 
							
								      case CTRL_LOGOFF_EVENT:
							 | 
						||
| 
								 | 
							
								      case CTRL_SHUTDOWN_EVENT:
							 | 
						||
| 
								 | 
							
								        LogMessageV(SYELOG_SEVERITY_INFORMATION, "User requested stop.");
							 | 
						||
| 
								 | 
							
								        printf("\nSYELOGD: Closing connections.\n");
							 | 
						||
| 
								 | 
							
								        if (s_hOutFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								            printf("Closing file.\n");
							 | 
						||
| 
								 | 
							
								            FlushFileBuffers(s_hOutFile);
							 | 
						||
| 
								 | 
							
								            CloseHandle(s_hOutFile);
							 | 
						||
| 
								 | 
							
								            s_hOutFile = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        ExitProcess(0);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DWORD main(int argc, char **argv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE hCompletionPort;
							 | 
						||
| 
								 | 
							
								    BOOL fNeedHelp = FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GetSystemTimeAsFileTime((FILETIME *)&s_llStartTime);
							 | 
						||
| 
								 | 
							
								    SetConsoleCtrlHandler(ControlHandler, TRUE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int arg = 1;
							 | 
						||
| 
								 | 
							
								    for (; arg < argc; arg++) {
							 | 
						||
| 
								 | 
							
								        if (argv[arg][0] == '-' || argv[arg][0] == '/') {
							 | 
						||
| 
								 | 
							
								            CHAR *argn = argv[arg] + 1;
							 | 
						||
| 
								 | 
							
								            CHAR *argp = argn;
							 | 
						||
| 
								 | 
							
								            while (*argp && *argp != ':') {
							 | 
						||
| 
								 | 
							
								                argp++;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (*argp == ':') {
							 | 
						||
| 
								 | 
							
								                *argp++ = '\0';
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            switch (argn[0]) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								              case 'd':                                 // Delta time.
							 | 
						||
| 
								 | 
							
								              case 'D':
							 | 
						||
| 
								 | 
							
								                s_fDeltaTime = TRUE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								              case 'o':                                 // Only one.
							 | 
						||
| 
								 | 
							
								              case 'O':
							 | 
						||
| 
								 | 
							
								                s_fExitAfterOne = TRUE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								              case 'q':                                 // Quiet.
							 | 
						||
| 
								 | 
							
								              case 'Q':
							 | 
						||
| 
								 | 
							
								                s_fLogToScreen = FALSE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								              case '?':                                 // Help.
							 | 
						||
| 
								 | 
							
								                fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								              default:
							 | 
						||
| 
								 | 
							
								                fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								                printf("SYELOGD: Bad argument: %s:%s\n", argn, argp);
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            if (s_hOutFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								                printf("SYELOGD: Error, more than one output file specified.\n\n");
							 | 
						||
| 
								 | 
							
								                fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            s_hOutFile = CreateFileA(argv[arg],
							 | 
						||
| 
								 | 
							
								                                     GENERIC_WRITE,
							 | 
						||
| 
								 | 
							
								                                     FILE_SHARE_READ,
							 | 
						||
| 
								 | 
							
								                                     NULL,
							 | 
						||
| 
								 | 
							
								                                     CREATE_ALWAYS,
							 | 
						||
| 
								 | 
							
								                                     FILE_ATTRIBUTE_NORMAL |
							 | 
						||
| 
								 | 
							
								                                     FILE_FLAG_SEQUENTIAL_SCAN,
							 | 
						||
| 
								 | 
							
								                                     NULL);
							 | 
						||
| 
								 | 
							
								            if (s_hOutFile == INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								                printf("SYELOGD: Error opening output file: %s: %ld\n\n",
							 | 
						||
| 
								 | 
							
								                       argv[arg], GetLastError());
							 | 
						||
| 
								 | 
							
								                fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                printf("SYELOGD: Logging to %s.\n", argv[arg]);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (fNeedHelp) {
							 | 
						||
| 
								 | 
							
								        printf("Usage:\n"
							 | 
						||
| 
								 | 
							
								               "    syelogd [options] {output_file}\n"
							 | 
						||
| 
								 | 
							
								               "Options:\n"
							 | 
						||
| 
								 | 
							
								               "    /d         List delta time in ms from previous event (not absolute time).\n"
							 | 
						||
| 
								 | 
							
								               "    /o         Exit after one client disconnects.\n"
							 | 
						||
| 
								 | 
							
								               "    /q         Disable event logging to screen (quiet mode).\n"
							 | 
						||
| 
								 | 
							
								               "    /?         Display this help message.\n"
							 | 
						||
| 
								 | 
							
								               "Summary:\n"
							 | 
						||
| 
								 | 
							
								               "    If given, all events will be logged to the output file.\n"
							 | 
						||
| 
								 | 
							
								               "\n");
							 | 
						||
| 
								 | 
							
								        exit(1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Create the completion port.
							 | 
						||
| 
								 | 
							
								    hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
							 | 
						||
| 
								 | 
							
								    if (hCompletionPort == NULL) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateIoCompletionPort");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Create completion port worker threads.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    CreateWorkers(hCompletionPort);
							 | 
						||
| 
								 | 
							
								    CreatePipeConnection(hCompletionPort);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    printf("SYELOGD: Ready for clients.  Press Ctrl-C to stop.\n");
							 | 
						||
| 
								 | 
							
								    while (argc) {
							 | 
						||
| 
								 | 
							
								        Sleep(10000);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    SetConsoleCtrlHandler(ControlHandler, FALSE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_hOutFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        FlushFileBuffers(s_hOutFile);
							 | 
						||
| 
								 | 
							
								        CloseHandle(s_hOutFile);
							 | 
						||
| 
								 | 
							
								        s_hOutFile = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 |