enum
{
W3CLOG_date = 0x00000001,
W3CLOG_time = 0x00000002,
W3CLOG_c_ip = 0x00000004,
W3CLOG_cs_username = 0x00000008,
W3CLOG_s_sitename = 0x00000010,
W3CLOG_s_computername = 0x00000020,
W3CLOG_s_ip = 0x00000040,
W3CLOG_s_port = 0x00000080,
W3CLOG_cs_method = 0x00000100,
W3CLOG_cs_uri_stem = 0x00000200,
W3CLOG_cs_uri_query = 0x00000400,
W3CLOG_sc_status = 0x00000800,
W3CLOG_sc_win32_status = 0x00001000,
W3CLOG_sc_bytes = 0x00002000,
W3CLOG_cs_bytes = 0x00004000,
W3CLOG_time_taken = 0x00008000,
W3CLOG_cs_version = 0x00010000,
W3CLOG_cs_host = 0x00020000,
W3CLOG_cs_user_agent = 0x00040000,
W3CLOG_cs_cookie = 0x00080000,
W3CLOG_cs_referer = 0x00100000,
W3CLOG_sc_substatus = 0x00200000,
};
class CW3CLogHandler :
public IltmsLogHandler
{
protected:
BOOL m_enable;
CAtlFile m_file;
DWORD m_fields;
BOOL m_localtime;
COleDateTime m_dtfile;
CString m_software;
CString m_folder;
CString m_prefix;
CString escape(LPCOLESTR s);
BOOL CreateLog(DATE timestamp);
CString GetLogPath(DATE timestamp);
HRESULT WriteString(LPCTSTR s);
COleDateTime GetTime(DATE timestamp);
HRESULT ResolvePath(LPCTSTR key, CString& resolved);
public:
CW3CLogHandler(LPCTSTR prefix = _T("ltms_"), LPCTSTR software = _T("LEAD Media Server"), BOOL enable = TRUE, LPCTSTR folder = _T("%ltmsLogFolder%"), DWORD fields = 0xffffffffUL, BOOL localtime = FALSE);
virtual ~CW3CLogHandler(void);
virtual HRESULT STDMETHODCALLTYPE QueryInterface(/* [in] */ REFIID riid, /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef( void);
virtual ULONG STDMETHODCALLTYPE Release( void);
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE InitializeLog(DATE timestamp);
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TerminateLog(void);
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE LogInformation(/* [in] */ IltmsLogInformation *info);
};
CW3CLogHandler::CW3CLogHandler(LPCTSTR prefix, LPCTSTR software, BOOL enable, LPCTSTR folder, DWORD fields, BOOL localtime) : m_fields(fields),
m_enable(enable), m_prefix(prefix), m_folder(folder), m_software(software), m_localtime(localtime)
{
}
CW3CLogHandler::~CW3CLogHandler(void)
{
}
HRESULT STDMETHODCALLTYPE CW3CLogHandler::QueryInterface(/* [in] */ REFIID riid, /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
{
if(riid == IID_IUnknown || riid == __uuidof(IltmsLogHandler))
{
*ppvObject = (void*) (IltmsLogHandler*) this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE CW3CLogHandler::AddRef( void)
{
return 1;
}
ULONG STDMETHODCALLTYPE CW3CLogHandler::Release( void)
{
return 1;
}
HRESULT CW3CLogHandler::WriteString(LPCTSTR s)
{
CStringA t(s);
return m_file.Write(t, t.GetLength());
}
COleDateTime CW3CLogHandler::GetTime(DATE timestamp)
{
COleDateTime dt(timestamp);
if(m_localtime)
{
SYSTEMTIME timeUTC;
dt.GetAsSystemTime(timeUTC);
SYSTEMTIME timeLocal;
SystemTimeToTzSpecificLocalTime(NULL, &timeUTC, &timeLocal);
dt = COleDateTime(timeLocal);
}
return dt;
}
HRESULT CW3CLogHandler::ResolvePath(LPCTSTR key, CString& resolved)
{
HRESULT hr;
CComPtr<IltmsPathResolver> resolver;
hr = CoCreateInstance(__uuidof(ltmsPathResolver), NULL, CLSCTX_ALL, __uuidof(IltmsPathResolver), (void**) &resolver);
if(FAILED(hr))
return hr;
CComBSTR v;
hr = resolver->Resolve(CComBSTR(key), &v);
if(FAILED(hr))
return hr;
resolved = v;
return S_OK;
}
CString CW3CLogHandler::GetLogPath(DATE timestamp)
{
COleDateTime dt = GetTime(timestamp);
CString fullpath;
HRESULT hr = ResolvePath(m_folder, fullpath);
if(FAILED(hr))
return _T("");
fullpath += _T("\\");
fullpath += m_prefix;
if(!m_localtime)
fullpath += dt.Format(_T("%y%m%d%H%M%SUTC.log"));
else
fullpath += dt.Format(_T("%y%m%d%H%M%S.log"));
return fullpath;
}
BOOL CW3CLogHandler::CreateLog(DATE timestamp)
{
if(m_file.m_h != NULL)
m_file.Close();
if(!m_enable)
return FALSE;
HRESULT hr = m_file.Create(GetLogPath(timestamp), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, OPEN_ALWAYS);
if(FAILED(hr))
return FALSE;
CString s;
m_dtfile = GetTime(timestamp);
m_file.Seek(0, FILE_END);
s.Format(_T("#Software: %s\r\n"), (LPCTSTR) m_software);
WriteString(s);
WriteString(_T("#Version: 1.0\r\n"));
COleDateTime dt = GetTime(timestamp);
s = dt.Format(_T("#Date: %Y-%m-%d %H:%M:%S\r\n"));
WriteString(s);
s = _T("#Fields:");
if(m_fields & W3CLOG_date)
{
s += _T(" date");
}
if(m_fields & W3CLOG_time)
{
s += _T(" time");
}
if(m_fields & W3CLOG_s_sitename)
{
s += _T(" s-sitename");
}
if(m_fields & W3CLOG_s_computername)
{
s += _T(" s-computername");
}
if(m_fields & W3CLOG_s_ip)
{
s += _T(" s-ip");
}
if(m_fields & W3CLOG_cs_method)
{
s += _T(" cs-method");
}
if(m_fields & W3CLOG_cs_uri_stem)
{
s += _T(" cs-uri-stem");
}
if(m_fields & W3CLOG_cs_uri_query)
{
s += _T(" cs-uri-query");
}
if(m_fields & W3CLOG_s_port)
{
s += _T(" s-port");
}
if(m_fields & W3CLOG_cs_username)
{
s += _T(" cs-username");
}
if(m_fields & W3CLOG_c_ip)
{
s += _T(" c-ip");
}
if(m_fields & W3CLOG_cs_version)
{
s += _T(" cs-version");
}
if(m_fields & W3CLOG_cs_user_agent)
{
s += _T(" cs(User-Agent)");
}
if(m_fields & W3CLOG_cs_cookie)
{
s += _T(" cs(Cookie)");
}
if(m_fields & W3CLOG_cs_referer)
{
s += _T(" cs(Referer)");
}
if(m_fields & W3CLOG_cs_host)
{
s += _T(" cs-host");
}
if(m_fields & W3CLOG_sc_status)
{
s += _T(" sc-status");
}
if(m_fields & W3CLOG_sc_substatus)
{
s += _T(" sc-substatus");
}
if(m_fields & W3CLOG_sc_win32_status)
{
s += _T(" sc-win32-status");
}
if(m_fields & W3CLOG_sc_bytes)
{
s += _T(" sc-bytes");
}
if(m_fields & W3CLOG_cs_bytes)
{
s += _T(" cs-bytes");
}
if(m_fields & W3CLOG_time_taken)
{
s += _T(" time-taken");
}
s += _T("\r\n");
WriteString(s);
m_file.Flush();
return TRUE;
}
CString CW3CLogHandler::escape(LPCOLESTR s)
{
CStringW t;
for(; *s; s++)
{
if(iswprint(*s) && !iswspace(*s))
t += *s;
else
t += L"+";
}
return CString(t);
}
HRESULT STDMETHODCALLTYPE CW3CLogHandler::InitializeLog(DATE timestamp)
{
CreateLog(timestamp);
return S_OK;
}
HRESULT STDMETHODCALLTYPE CW3CLogHandler::TerminateLog(void)
{
if(m_file.m_h != NULL)
m_file.Close();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CW3CLogHandler::LogInformation(/* [in] */ IltmsLogInformation *info)
{
CString s;
if(!m_enable)
return S_OK;
// check if we need to roll to a new file
{
DATE v;
info->get_TimeStamp(&v);
COleDateTime dt = GetTime(v);
if(m_file.m_h == NULL || dt.GetDay() != m_dtfile.GetDay()
|| dt.GetMonth() != m_dtfile.GetMonth()
|| dt.GetYear() != m_dtfile.GetYear())
{
if(!CreateLog(v))
return S_OK;
}
}
if(m_fields & W3CLOG_date)
{
DATE v;
info->get_TimeStamp(&v);
COleDateTime dt = GetTime(v);
if(!s.IsEmpty())
s += L" ";
s += dt.Format(_T("%Y-%m-%d"));
}
if(m_fields & W3CLOG_time)
{
DATE v;
info->get_TimeStamp(&v);
COleDateTime dt = GetTime(v);
if(!s.IsEmpty())
s += _T(" ");
s += dt.Format(_T("%H:%M:%S"));
}
if(m_fields & W3CLOG_s_sitename)
{
CComBSTR v;
info->get_SiteName(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_s_computername)
{
CComBSTR v;
info->get_ComputerName(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_s_ip)
{
CComBSTR v;
info->get_ServerIP(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += v;
}
if(m_fields & W3CLOG_cs_method)
{
CComBSTR v;
info->get_Method(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_uri_stem)
{
CComBSTR v;
info->get_URIStem(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_uri_query)
{
CComBSTR v;
info->get_URIQuery(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_s_port)
{
LONG v;
info->get_ServerPort(&v);
if(!s.IsEmpty())
s += _T(" ");
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
if(m_fields & W3CLOG_cs_username)
{
CComBSTR v;
info->get_UserName(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_c_ip)
{
CComBSTR v;
info->get_ClientIP(&v);
if(!s.IsEmpty())
s += _T(" ");
if(s.IsEmpty())
s += _T("-");
else
s += v;
}
if(m_fields & W3CLOG_cs_version)
{
CComBSTR v;
info->get_ProtocolVersion(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_user_agent)
{
CComBSTR v;
info->get_UserAgent(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_cookie)
{
CComBSTR v;
info->get_Cookie(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_referer)
{
CComBSTR v;
info->get_Referrer(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_cs_host)
{
CComBSTR v;
info->get_Host(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v.Length() == 0)
s += _T("-");
else
s += escape(v);
}
if(m_fields & W3CLOG_sc_status)
{
LONG v;
info->get_Status(&v);
if(!s.IsEmpty())
s += _T(" ");
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
if(m_fields & W3CLOG_sc_substatus)
{
LONG v;
info->get_ProtocolSubStatus(&v);
if(!s.IsEmpty())
s += _T(" ");
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
if(m_fields & W3CLOG_sc_win32_status)
{
LONG v;
info->get_Win32Status(&v);
if(!s.IsEmpty())
s += _T(" ");
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
if(m_fields & W3CLOG_sc_bytes)
{
LONG v;
info->get_BytesSent(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v < 0)
{
s += _T("-");
}
else
{
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
}
if(m_fields & W3CLOG_cs_bytes)
{
LONG v;
info->get_BytesReceived(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v < 0)
{
s += _T("-");
}
else
{
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
}
if(m_fields & W3CLOG_time_taken)
{
LONG v;
info->get_TimeTaken(&v);
if(!s.IsEmpty())
s += _T(" ");
if(v < 0)
{
s += _T("-");
}
else
{
CString t;
t.Format(_T("%u"), (UINT) v);
s += t;
}
}
s += _T("\r\n");
WriteString(s);
m_file.Flush();
return S_OK;
}
HRESULT RunServerWithLogging(void)
{
CComPtr<IltmsServer> server;
HRESULT hr;
CW3CLogHandler loghandler;
// create an instance of the server object
hr = CoCreateInstance(__uuidof(ltmsServer), NULL, CLSCTX_ALL, __uuidof(IltmsServer), (void**) &server);
if(FAILED(hr))
goto error;
// set the log handler
hr = server->putref_LogHandler(&loghandler);
if(FAILED(hr))
goto error;
{
// for demonstration, compare the interface we just set
CComPtr<IltmsLogHandler> ihandler;
hr = server->get_LogHandler(&ihandler);
if(FAILED(hr))
goto error;
if(ihandler != (IltmsLogHandler*) &loghandler)
{
hr = E_UNEXPECTED;
goto error;
}
}
// load the configuration file located in the config subfolder under the executable folder
// or comment this section out to run with the server's default settings
hr = server->ImportConfigFile(CComBSTR(L"%ltmsConfigFolder%\\ltmsServer.xml"));
if(FAILED(hr))
goto error;
// start the server
hr = server->Start();
if(FAILED(hr))
goto error;
// display a message that the server is running and wait for a key
_tprintf(_T("The server has started. Hit any key to stop.\n"));
_gettc(stdin);
// stop the server
hr = server->Stop();
if(FAILED(hr))
goto error;
// remove the log handler
hr = server->putref_LogHandler(NULL);
if(FAILED(hr))
return hr;
error:
return hr;
}