XPLOGGER.C
/* 
 -  X P L O G G E R . C 
 - 
 *  Purpose: 
 *      Code to support the Log File for the Sample Transport Provider. 
 * 
 *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved. 
 */ 
 
#include "xppch.h" 
 
static HANDLE hLogHandle = INVALID_HANDLE_VALUE; 
static DWORD dwLogLowWater = 0; 
static DWORD dwLogHiWater = (DWORD) -1; 
static TCHAR chLogFileName[MAX_PATH]; 
 
#define BUFSIZE 255             /* Size of buffer to use for LogPrintf */ 
static TCHAR _xpbuf[BUFSIZE]; 
 
 
/* 
 -  InitTransportLog 
 - 
 *  Purpose: 
 *      Called by TransportLogon() logic to start logging. 
 * 
 *  Parameters: 
 *      lpxpl               Session object. We'll need it 
 *                          to get the logfile name and 
 *                          size constraints. 
 *      ulFlags             Flags. Not used at present. 
 * 
 *  Returns: 
 *      hLogHandle          Handle of open Log File. 
 *      dwLogLowWater       "Low Water Mark" of Log File. 
 *      dwLogHiWater        "High Water Mark" of Log File. 
 *      chLogFileName       Filename of open Log File. 
 * 
 *  Operation: 
 *      If a file is already open, this transport session doesn't want to log 
 *      events, or the filename given is null, return to caller.  Open the  
 *      file and save the filename into chLogFileName. Store water marks into  
 *      the appropriate variables. Save the handle.  We grab the Critical 
 *      Section here because it is possible to Init the logging at times 
 *      other than TransportLogon.  This makes it necessary to protect this 
 *      section of code. 
 */ 
 
void 
InitTransportLog(LPXPL lpxpl, ULONG ulFlags) 
{ 
    LPSPropValue lpPropArray = lpxpl->lpPropArray; 
    ULONG ulSessFlags; 
    LPTSTR lpszFileName; 
    HANDLE hTempHandle; 
    DWORD dwOffset; 
    ULONG ulLow, ulHigh; 
 
    /*  Use the critical section here */ 
 
    EnterCriticalSection(&(lpxpl->lpxppParent->csTransport)); 
 
    /*  Are we already logging? If so there's nothing to do here. */ 
 
    if (hLogHandle != INVALID_HANDLE_VALUE) 
    { 
        DebugTrace("Already logging to %s\n", chLogFileName); 
        goto ret; 
    } 
 
    /*  Logging isn't on. Would this session like it turned on? */ 
 
    ulSessFlags = (ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray)).Value.ul; 
    if (!(ulSessFlags & PR_SAMPLE_FLAG_LOG_EVENTS)) 
    { 
        DebugTrace("Log flag isn't on, logfile won't be opened\n"); 
        goto ret; 
    } 
 
    /*  We're going to log if we can. Get the filename and see if it 
        makes any sense. If so, try to open it. */ 
 
    lpszFileName = (ArrayIndex(PR_SAMPLE_LOGFILE, lpPropArray)).Value.LPSZ; 
    if (!lpszFileName || !*lpszFileName) 
    { 
        DebugTrace("LogFile name wasn't given, logfile won't be opened\n"); 
        goto ret; 
    } 
 
    hTempHandle = CreateFile(lpszFileName, 
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ, 
        NULL, 
        OPEN_ALWAYS, 
        FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS, 
        NULL); 
 
    if (hTempHandle == INVALID_HANDLE_VALUE) 
    { 
        DebugTrace("Error %x opening logfile\n", GetLastError()); 
        goto ret; 
    } 
 
    /*  The log file is open. Seek to the end so we can resume logging. */ 
 
    dwOffset = SetFilePointer(hTempHandle, 0L, NULL, FILE_END); 
    if (dwOffset == -1) 
    { 
        DebugTrace("Error %x seeking to end of logfile\n", GetLastError()); 
        CloseHandle(hTempHandle); 
        goto ret; 
    } 
 
    /*  Get the relevant data into the local structures. */ 
 
    lstrcpy(chLogFileName, lpszFileName); 
    hLogHandle = hTempHandle; 
 
    ulLow = (ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpPropArray)).Value.ul; 
    ulHigh = (ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpPropArray)).Value.ul; 
    if (ulHigh) 
    { 
        dwLogHiWater = ulHigh * 1024; 
        dwLogLowWater = ulLow * 1024; 
    } 
 
ret: 
 
    /*  Release the critical section */ 
 
    LeaveCriticalSection(&(lpxpl->lpxppParent->csTransport)); 
 
    return; 
} 
 
 
/* 
 -  DeInitTransportLog 
 - 
 *  Purpose: 
 *      Called by DeinitTransport() to turn off all session logging. 
 * 
 *  Parameters: 
 *      ulFlags             Flags. Not used at present. 
 * 
 *  Returns: 
 *      none. 
 * 
 *  Operation: 
 *      If we have a file open, try to close it. Reinitialize structures 
 *      whether we succeeded or not. 
 */ 
 
void 
DeInitTransportLog(ULONG ulFlags) 
{ 
    if (hLogHandle != INVALID_HANDLE_VALUE) 
    { 
        if (!CloseHandle(hLogHandle)) 
            DebugTrace("Unable to close logfile %s\n", chLogFileName); 
 
        hLogHandle = INVALID_HANDLE_VALUE; 
        dwLogHiWater = (DWORD) -1L; 
        dwLogLowWater = 0; 
        *chLogFileName = '\0'; 
    } 
} 
 
 
/* 
 -  PrintfTransportLog 
 - 
 *  Purpose: 
 *      Called by various parts of the Transport to log information (if 
 *      logging is currently active). 
 * 
 *  Parameters: 
 *      fmt                 Start of variable argument list. 
 * 
 *  Returns: 
 *      none. 
 * 
 *  Operation: 
 *      Format the input data and call PutsTransportLog to write to logfile. 
 *      Current maximum length permitted is 255 characters (and is NOT 
 *      protected!). 
 */ 
 
void __cdecl 
PrintfTransportLog(LPTSTR fmt,...) 
{ 
    va_list marker; 
 
    va_start(marker, fmt); 
 
    if (hLogHandle != INVALID_HANDLE_VALUE) 
    { 
        if (wvsprintf((LPTSTR) _xpbuf, fmt, marker)) 
            PutsTransportLog((LPTSTR) _xpbuf); 
    } 
 
    va_end(marker); 
} 
 
 
/* 
 -  PutsTransportLog 
 - 
 *  Purpose: 
 *      Called mostly by PrintfTransportLog. Writes a single line to the 
 *      logfile if it's open. 
 * 
 *  Parameters: 
 *      str                 String that wants to be written. 
 * 
 *  Returns: 
 *      none. 
 * 
 *  Operation: 
 *      If we have set a high water mark, get the current logfile size. If it 
 *      exceeds the high water mark, move back by the amount of the low water 
 *      mark, find a line ending, read everything to the end, write to the 
 *      front of the file, and truncate to that location. 
 * 
 *      Create a line consisting of the date and time, the input string, and 
 *      line ending characters. Write this line to the logfile. 
 */ 
 
void 
PutsTransportLog(LPTSTR str) 
{ 
    DWORD cWritten; 
    SYSTEMTIME stOurTime; 
    TCHAR tchData[512]; 
    HGLOBAL hGlobal = (HGLOBAL) 0L; 
    LPVOID lpvBuf = NULL; 
 
    if (hLogHandle == INVALID_HANDLE_VALUE) 
        return; 
 
    /*  See if we want to be adjusting the file size. */ 
 
    if (dwLogHiWater != -1) 
    { 
        DWORD finfo; 
 
        /*  Get the current file size */ 
 
        finfo = GetFileSize(hLogHandle, NULL); 
 
        if (finfo == 0xFFFFFFFF) 
        { 
            DebugTrace("Error %x getting logfile info\n", GetLastError()); 
            DeInitTransportLog(LOG_DEINIT_HURRY); 
            return; 
        } 
 
        /*  Is it time to trim back? If so, let's do it. */ 
 
        if (finfo > dwLogHiWater) 
        { 
            DWORD dwOffset; 
            ULONG ulT, ulLowWater; 
            char *lpbT; 
 
            /*  Allocate a buffer to read dwLogLowWater bytes. If 
                dwLogLowWater > 32K, use 32K. */ 
 
            ulLowWater = (dwLogLowWater > 32000L ? 32000L : dwLogLowWater); 
            if (ulLowWater == 0L) 
                goto Truncate; 
 
            hGlobal = GlobalAlloc(GPTR, (UINT) ulLowWater); 
            if (hGlobal == NULL) 
            { 
                DebugTrace("Attempt to GlobalAlloc %l bytes for lowwater buffer failed\n", ulLowWater); 
                goto Truncate; 
            } 
 
            lpvBuf = (LPVOID) GlobalLock(hGlobal); 
            if (lpvBuf == NULL) 
            { 
                DebugTrace("Attempt to Lock allocated memory buffer failed\n"); 
                goto Truncate; 
            } 
 
            /*  Reposition the pointer back by the size of ulLowWater. */ 
 
            dwOffset = SetFilePointer(hLogHandle, 0L - ulLowWater, NULL, FILE_CURRENT); 
            if (dwOffset == -1) 
            { 
                DebugTrace("Error %x seeking to low water mark\n", GetLastError()); 
                DeInitTransportLog(LOG_DEINIT_HURRY); 
                return; 
            } 
 
            /*  Read (ulLowWater) bytes from that position. */ 
 
            if (!ReadFile(hLogHandle, lpvBuf, ulLowWater, &cWritten, NULL)) 
            { 
                DebugTrace("Attempt to read %l bytes for low water copy failed, error = %lx\n", ulLowWater, GetLastError()); 
                goto Truncate; 
            } 
 
            Assert(cWritten == ulLowWater); 
 
            /*  Find the first newline from that point */ 
 
            for (ulT = 0, lpbT = (char *)lpvBuf; ulT < ulLowWater; lpbT++, ulT++) 
            { 
                if (*lpbT == '\n') 
                    break; 
            } 
 
            /* Did the search fail? If so, truncate the file to zero. */ 
 
            if (ulT == ulLowWater) 
            { 
                ulLowWater = 0L; 
Truncate: 
                /*  We failed for some reason. Deallocate the buffer if 
                    any and truncate the file to ulLowWater. */ 
 
                if (lpvBuf) 
                    GlobalUnlock(hGlobal); 
                if (hGlobal) 
                    (void)GlobalFree(hGlobal); 
 
                dwOffset = SetFilePointer(hLogHandle, ulLowWater, NULL, FILE_BEGIN); 
                if (dwOffset == -1) 
                { 
                    DebugTrace("Error %x seeking to low water mark\n", GetLastError()); 
                    DeInitTransportLog(LOG_DEINIT_HURRY); 
                    return; 
                } 
                goto Adjusted; 
            } 
 
            /*  We found a newline. Skip over it and write the remaining 
                data from the file start, if any. */ 
 
            ulT++; 
            lpbT++; 
 
            dwOffset = SetFilePointer(hLogHandle, 0L, NULL, FILE_BEGIN); 
            if (dwOffset == -1) 
            { 
                if (lpvBuf) 
                    GlobalUnlock(hGlobal); 
                if (hGlobal) 
                    (void)GlobalFree(hGlobal); 
 
                DebugTrace("Error %x seeking to file start\n", GetLastError()); 
                DeInitTransportLog(LOG_DEINIT_HURRY); 
                return; 
            } 
 
            if (ulT < ulLowWater) 
            { 
                cWritten = 0; 
                WriteFile(hLogHandle, (LPVOID) lpbT, (DWORD) (ulLowWater - ulT), &cWritten, NULL); 
                Assert((cWritten + ulT) == ulLowWater); 
            } 
 
            GlobalUnlock(hGlobal); 
            GlobalFree(hGlobal); 
 
Adjusted: 
            if (!SetEndOfFile(hLogHandle)) 
            { 
                DebugTrace("Error %x setting EOF\n", GetLastError()); 
                DeInitTransportLog(LOG_DEINIT_HURRY); 
                return; 
            } 
        } 
    } 
 
    /* We can't handle more than 490 characters on a input line. */ 
 
    Assert(lstrlen(str) < 490L); 
 
    GetLocalTime(&stOurTime); 
    wsprintf(tchData, TEXT("%04d/%02d/%02d %02d:%02d:%02d %s\r\n"), 
        stOurTime.wYear, stOurTime.wMonth, stOurTime.wDay, 
        stOurTime.wHour, stOurTime.wMinute, stOurTime.wSecond, 
        str); 
 
    WriteFile(hLogHandle, tchData, (DWORD) (lstrlen(tchData) * sizeof(TCHAR)), &cWritten, NULL); 
}