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;
 | |
| }
 | |
| //
 | |
| //////////////////////////////////////////////////////////////////////////////
 |