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"));elsefullpath += 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;elset += 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("-");elses += 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("-");elses += 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("-");elses += v;}if(m_fields & W3CLOG_cs_method){CComBSTR v;info->get_Method(&v);if(!s.IsEmpty())s += _T(" ");if(v.Length() == 0)s += _T("-");elses += 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("-");elses += 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("-");elses += 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("-");elses += escape(v);}if(m_fields & W3CLOG_c_ip){CComBSTR v;info->get_ClientIP(&v);if(!s.IsEmpty())s += _T(" ");if(s.IsEmpty())s += _T("-");elses += v;}if(m_fields & W3CLOG_cs_version){CComBSTR v;info->get_ProtocolVersion(&v);if(!s.IsEmpty())s += _T(" ");if(v.Length() == 0)s += _T("-");elses += 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("-");elses += 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("-");elses += 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("-");elses += 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("-");elses += 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 objecthr = CoCreateInstance(__uuidof(ltmsServer), NULL, CLSCTX_ALL, __uuidof(IltmsServer), (void**) &server);if(FAILED(hr))goto error;// set the log handlerhr = server->putref_LogHandler(&loghandler);if(FAILED(hr))goto error;{// for demonstration, compare the interface we just setCComPtr<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 settingshr = server->ImportConfigFile(CComBSTR(L"%ltmsConfigFolder%\\ltmsServer.xml"));if(FAILED(hr))goto error;// start the serverhr = 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 serverhr = server->Stop();if(FAILED(hr))goto error;// remove the log handlerhr = server->putref_LogHandler(NULL);if(FAILED(hr))return hr;error:return hr;}