aboutsummaryrefslogtreecommitdiffhomepage
path: root/samples/syelog/syelogd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'samples/syelog/syelogd.cpp')
-rw-r--r--samples/syelog/syelogd.cpp556
1 files changed, 556 insertions, 0 deletions
diff --git a/samples/syelog/syelogd.cpp b/samples/syelog/syelogd.cpp
new file mode 100644
index 0000000..c3db446
--- /dev/null
+++ b/samples/syelog/syelogd.cpp
@@ -0,0 +1,556 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// 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;
+}
+//
+//////////////////////////////////////////////////////////////////////////////