449 lines
11 KiB
C
449 lines
11 KiB
C
/*++
|
|
|
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
errlogp.h driver wide Error Logging module
|
|
|
|
Abstract:
|
|
|
|
Private header file for the Error Logging.
|
|
|
|
Author:
|
|
|
|
Ali E. Turkoglu (aliTu) 30-Jan-2002
|
|
|
|
Revision History:
|
|
|
|
---
|
|
|
|
--*/
|
|
|
|
#ifndef _ERRLOGP_H_
|
|
#define _ERRLOGP_H_
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private definitions for the HTTP Error Logging Module
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Version numbers for the original raw binary format.
|
|
//
|
|
|
|
#define MAJOR_ERROR_LOG_FILE_VERSION (1)
|
|
#define MINOR_ERROR_LOG_FILE_VERSION (0)
|
|
|
|
//
|
|
// FileName specific constants
|
|
//
|
|
|
|
#define ERROR_LOG_FILE_NAME_PREFIX L"\\httperr"
|
|
|
|
#define ERROR_LOG_FILE_NAME_EXTENSION L"log"
|
|
#define ERROR_LOG_FILE_NAME_EXTENSION_PLUS_DOT L".log"
|
|
|
|
#define ERROR_LOG_FIELD_SEPERATOR_CHAR ' '
|
|
|
|
#define ERROR_LOG_FIELD_NOT_EXISTS_CHAR '-'
|
|
|
|
#define ERROR_LOG_FIELD_BAD_CHAR '+'
|
|
|
|
//
|
|
// Macro for a max err log file (i.e. "\httperr1234567890.log")
|
|
//
|
|
|
|
#define ERROR_LOG_MAX_FULL_FILE_NAME_LENGTH \
|
|
( \
|
|
WCSLEN_LIT(ERROR_LOG_FILE_NAME_PREFIX) \
|
|
+ \
|
|
MAX_ULONG_STR \
|
|
+ \
|
|
WCSLEN_LIT(ERROR_LOG_FILE_NAME_EXTENSION_PLUS_DOT) \
|
|
)
|
|
|
|
#define ERROR_LOG_MAX_FULL_FILE_NAME_SIZE \
|
|
(ERROR_LOG_MAX_FULL_FILE_NAME_LENGTH * sizeof(WCHAR))
|
|
|
|
C_ASSERT(UL_MAX_FILE_NAME_SUFFIX_LENGTH >= ERROR_LOG_MAX_FULL_FILE_NAME_LENGTH);
|
|
|
|
C_ASSERT(WCSLEN_LIT(DEFAULT_ERROR_LOGGING_DIR) <= MAX_PATH);
|
|
|
|
|
|
#define ERR_DATE_FIELD_LEN (10)
|
|
|
|
#define ERR_TIME_FIELD_LEN (8)
|
|
|
|
/*
|
|
|
|
Error logging Format
|
|
|
|
1. Date-Time (W3C Format)
|
|
2. Client IP:port
|
|
3. Server IP:port
|
|
4. Protocol-version
|
|
5. Verb
|
|
6. URL & Query
|
|
7. Protocol-status-code (401, etc)
|
|
8. SiteId
|
|
9. Information field
|
|
10. \r\n
|
|
|
|
*/
|
|
|
|
#define MAX_ERROR_LOG_FIX_FIELD_OVERHEAD \
|
|
( ERR_DATE_FIELD_LEN + 1 /* Date */ \
|
|
+ ERR_TIME_FIELD_LEN + 1 /* Time */ \
|
|
+ UL_HTTP_VERSION_LENGTH + 1 /* Protocol Version */ \
|
|
+ MAX_VERB_LENGTH + 1 /* Verb */ \
|
|
+ 3 + 1 /* Protocol Status */ \
|
|
+ MAX_IP_ADDR_STRING_LEN + 1 + MAX_PORT_LENGTH + 1 /* Client Ip Port */ \
|
|
+ MAX_IP_ADDR_STRING_LEN + 1 + MAX_PORT_LENGTH + 1 /* Server Ip Port */ \
|
|
+ 1 + 1 /* For empty Uri plus seperator */ \
|
|
+ MAX_ULONG_STR + 1 /* For SiteId plus seperator */ \
|
|
+ 1 + 1 /* For empty Info plus seperator */ \
|
|
+ 2 /* \r\n */ \
|
|
)
|
|
|
|
//
|
|
// Error Log file entry
|
|
//
|
|
|
|
typedef struct _UL_ERROR_LOG_FILE_ENTRY
|
|
{
|
|
//
|
|
// Must be UL_ERROR_LOG_FILE_ENTRY_POOL_TAG.
|
|
//
|
|
|
|
ULONG Signature;
|
|
|
|
//
|
|
// This lock protects the shared writes and exclusive flushes.
|
|
// It has to be push lock since the ZwWrite operation
|
|
// cannot run at APC_LEVEL.
|
|
//
|
|
|
|
UL_PUSH_LOCK PushLock;
|
|
|
|
//
|
|
// The name of the file. Full path including the directory.
|
|
//
|
|
|
|
UNICODE_STRING FileName;
|
|
PWSTR pShortName;
|
|
|
|
//
|
|
// Following will be NULL until a request comes in to the
|
|
// site that this entry represents.
|
|
//
|
|
|
|
PUL_LOG_FILE_HANDLE pLogFile;
|
|
|
|
//
|
|
// Recycling information.
|
|
//
|
|
|
|
ULONG TruncateSize;
|
|
|
|
ULONG SequenceNumber;
|
|
|
|
ULARGE_INTEGER TotalWritten;
|
|
|
|
//
|
|
// For Log File ReCycling based on GMT time.
|
|
// And periodic buffer flushing.
|
|
//
|
|
|
|
UL_LOG_TIMER BufferTimer;
|
|
UL_WORK_ITEM WorkItem; // For the pasive worker
|
|
LONG WorkItemScheduled; // To protect against multiple queueing
|
|
|
|
union
|
|
{
|
|
//
|
|
// Flags to show the entry states mostly. Used by
|
|
// recycling.
|
|
//
|
|
|
|
ULONG Value;
|
|
struct
|
|
{
|
|
ULONG StaleSequenceNumber:1;
|
|
ULONG RecyclePending:1;
|
|
ULONG Active:1;
|
|
|
|
ULONG WriteFailureLogged:1;
|
|
ULONG CreateFileFailureLogged:1;
|
|
};
|
|
|
|
} Flags;
|
|
|
|
//
|
|
// The default buffer size is g_AllocationGranularity.
|
|
// The operating system's allocation granularity.
|
|
//
|
|
|
|
PUL_LOG_FILE_BUFFER LogBuffer;
|
|
|
|
} UL_ERROR_LOG_FILE_ENTRY, *PUL_ERROR_LOG_FILE_ENTRY;
|
|
|
|
#define IS_VALID_ERROR_LOG_FILE_ENTRY( pEntry ) \
|
|
( (pEntry != NULL) && ((pEntry)->Signature == UL_ERROR_LOG_FILE_ENTRY_POOL_TAG) )
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private function calls
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
UlpErrorLogBufferTimerDpcRoutine(
|
|
PKDPC Dpc,
|
|
PVOID DeferredContext,
|
|
PVOID SystemArgument1,
|
|
PVOID SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
UlpErrorLogBufferTimerHandler(
|
|
IN PUL_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpCreateErrorLogFile(
|
|
IN OUT PUL_ERROR_LOG_FILE_ENTRY pEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpFlushErrorLogFile(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpDisableErrorLogEntry(
|
|
IN OUT PUL_ERROR_LOG_FILE_ENTRY pEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpRecycleErrorLogFile(
|
|
IN OUT PUL_ERROR_LOG_FILE_ENTRY pEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpHandleErrorLogFileRecycle(
|
|
IN OUT PVOID pContext
|
|
);
|
|
|
|
PUL_ERROR_LOG_BUFFER
|
|
UlpAllocErrorLogBuffer(
|
|
IN ULONG BufferSize
|
|
);
|
|
|
|
VOID
|
|
UlpFreeErrorLogBuffer(
|
|
IN OUT PUL_ERROR_LOG_BUFFER pErrorLogBuffer
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpBuildErrorLogRecord(
|
|
IN PUL_ERROR_LOG_INFO pLogInfo
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpWriteToErrorLogFileDebug(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry,
|
|
IN ULONG RecordSize,
|
|
IN PUCHAR pUserRecord
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpWriteToErrorLogFileShared(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry,
|
|
IN ULONG RecordSize,
|
|
IN PUCHAR pUserRecord
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpWriteToErrorLogFileExclusive(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry,
|
|
IN ULONG RecordSize,
|
|
IN PUCHAR pUserRecord
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpWriteToErrorLogFile(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry,
|
|
IN ULONG RecordSize,
|
|
IN PUCHAR pUserRecord
|
|
);
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Error log files are always recycled based on size.
|
|
|
|
Arguments:
|
|
|
|
pEntry: The error log file entry.
|
|
NewRecordSize: The size of the new record going to the buffer. (Bytes)
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
BOOLEAN
|
|
UlpIsErrorLogFileOverFlow(
|
|
IN PUL_ERROR_LOG_FILE_ENTRY pEntry,
|
|
IN ULONG NewRecordSize
|
|
)
|
|
{
|
|
//
|
|
// If infinite then no rollover.
|
|
//
|
|
if (pEntry->TruncateSize == HTTP_LIMIT_INFINITE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// BufferUsed: Amount of log buffer we are >currently< using.
|
|
//
|
|
|
|
ULONG BufferUsed = 0;
|
|
|
|
if (pEntry->LogBuffer)
|
|
{
|
|
BufferUsed = pEntry->LogBuffer->BufferUsed;
|
|
}
|
|
|
|
//
|
|
// TotalWritten get updated >only< with buffer flush. Therefore
|
|
// we have to pay attention to the buffer used.
|
|
//
|
|
|
|
if ((pEntry->TotalWritten.QuadPart
|
|
+ (ULONGLONG) BufferUsed
|
|
+ (ULONGLONG) NewRecordSize
|
|
) >= (ULONGLONG) pEntry->TruncateSize)
|
|
{
|
|
UlTrace(ERROR_LOGGING,
|
|
("Http!UlpIsErrorLogFileOverFlow: pEntry %p FileBuffer %p "
|
|
"TW:%I64d B:%d R:%d T:%d\n",
|
|
pEntry,
|
|
pEntry->LogBuffer,
|
|
pEntry->TotalWritten.QuadPart,
|
|
BufferUsed,
|
|
NewRecordSize,
|
|
pEntry->TruncateSize
|
|
));
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Error log files are always recycled based on size.
|
|
|
|
Arguments:
|
|
|
|
pRequest: Internal request structure.
|
|
|
|
Returns
|
|
|
|
# of bytes of the picked url. Zero if nothing needs to be logged.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
ULONG
|
|
UlpCalculateUrlSize(
|
|
IN PUL_INTERNAL_REQUEST pRequest,
|
|
OUT PBOOLEAN pbLogRawUrl
|
|
)
|
|
{
|
|
|
|
//
|
|
// Following macro is to test whether Abs Path is really pointing to
|
|
// the original Url buffer rather than to an arbitrary buffer like g_SlashPath.
|
|
// See 527947 and 765769.
|
|
//
|
|
|
|
#define ABS_PATH_SAFE(pUrl,pAbs,length) \
|
|
((pAbs) && \
|
|
(pUrl) && \
|
|
((pAbs) >= (pUrl)) && \
|
|
(((ULONG_PTR) (length)) > \
|
|
DIFF_ULONGPTR((PUCHAR)(pAbs) - (PUCHAR)(pUrl)) ) \
|
|
)
|
|
|
|
ULONG UrlSize = 0;
|
|
|
|
//
|
|
// CookedUrl length and UrlLength are in bytes. Pick cooked url if it
|
|
// exists. Otherwise use the raw url, but only if it is clean enough
|
|
// for us (State >= ParseVersionState) and pAbsPath is really pointing
|
|
// into Url buffer. In raw url case, parser sometimes init the pAbsPath
|
|
// to a global string. (when there's no abs path in the raw url).
|
|
//
|
|
|
|
ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
|
|
|
|
if (pRequest->CookedUrl.pAbsPath)
|
|
{
|
|
ASSERT(pRequest->CookedUrl.pUrl);
|
|
|
|
UrlSize = pRequest->CookedUrl.Length
|
|
-
|
|
(ULONG) (DIFF(pRequest->CookedUrl.pAbsPath
|
|
-
|
|
pRequest->CookedUrl.pUrl
|
|
) * sizeof(WCHAR));
|
|
|
|
ASSERT(wcslen(pRequest->CookedUrl.pAbsPath)
|
|
== UrlSize/sizeof(WCHAR));
|
|
|
|
*pbLogRawUrl = FALSE;
|
|
|
|
}
|
|
else if (pRequest->RawUrl.pAbsPath)
|
|
{
|
|
if (pRequest->ParseState > ParseUrlState)
|
|
{
|
|
ASSERT(pRequest->RawUrl.pUrl);
|
|
|
|
if (ABS_PATH_SAFE(pRequest->RawUrl.pUrl,
|
|
pRequest->RawUrl.pAbsPath,
|
|
pRequest->RawUrl.Length))
|
|
{
|
|
UrlSize = pRequest->RawUrl.Length
|
|
-
|
|
(ULONG) DIFF(pRequest->RawUrl.pAbsPath
|
|
-
|
|
pRequest->RawUrl.pUrl
|
|
);
|
|
|
|
*pbLogRawUrl = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
UrlSize = MIN(UrlSize, MAX_LOG_EXTEND_FIELD_LEN);
|
|
|
|
return UrlSize;
|
|
}
|
|
|
|
#endif // _ERRLOGP_H_
|