1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 
27 #include "log_module.hxx"
28 #include "methodguard.hxx"
29 #include "loghandler.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/logging/XConsoleHandler.hpp>
33 #include <com/sun/star/lang/XServiceInfo.hpp>
34 #include <com/sun/star/logging/LogLevel.hpp>
35 #include <com/sun/star/lang/XInitialization.hpp>
36 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/beans/NamedValue.hpp>
39 /** === end UNO includes === **/
40 
41 #include <tools/diagnose_ex.h>
42 
43 #include <comphelper/componentcontext.hxx>
44 
45 #include <cppuhelper/compbase3.hxx>
46 #include <cppuhelper/basemutex.hxx>
47 
48 #include <rtl/strbuf.hxx>
49 #include <osl/process.h>
50 #include <osl/socket.hxx>
51 #include <osl/time.h>
52 
53 #include <stdio.h>
54 
55 //........................................................................
56 namespace logging
57 {
58 //........................................................................
59 
60 	/** === begin UNO using === **/
61     using ::com::sun::star::logging::XLogHandler;
62     using ::com::sun::star::lang::XServiceInfo;
63     using ::com::sun::star::uno::Reference;
64     using ::com::sun::star::uno::XComponentContext;
65     using ::com::sun::star::uno::RuntimeException;
66     using ::com::sun::star::logging::XLogFormatter;
67     using ::com::sun::star::uno::Sequence;
68     using ::com::sun::star::logging::LogRecord;
69     using ::com::sun::star::uno::UNO_QUERY_THROW;
70     using ::com::sun::star::uno::Exception;
71     using ::com::sun::star::uno::Any;
72     using ::com::sun::star::uno::XInterface;
73     using ::com::sun::star::lang::XInitialization;
74     using ::com::sun::star::ucb::AlreadyInitializedException;
75     using ::com::sun::star::lang::IllegalArgumentException;
76     using ::com::sun::star::beans::NamedValue;
77 	/** === end UNO using === **/
78     namespace LogLevel = ::com::sun::star::logging::LogLevel;
79 
80 	//====================================================================
81 	//= SyslogHandler - declaration
82 	//====================================================================
83 	//--------------------------------------------------------------------
84     typedef ::cppu::WeakComponentImplHelper3    <   XLogHandler
85                                                 ,   XServiceInfo
86                                                 ,   XInitialization
87                                                 >   SyslogHandler_Base;
88     class SyslogHandler    :public ::cppu::BaseMutex
89                             ,public SyslogHandler_Base
90 	{
91     private:
92         ::comphelper::ComponentContext  m_aContext;
93         LogHandlerHelper                m_aHandlerHelper;
94         ::osl::SocketAddr               m_aSocketAddress;
95         ::osl::DatagramSocket           m_aSocket;
96 
97     protected:
98         SyslogHandler( const Reference< XComponentContext >& _rxContext );
99         virtual ~SyslogHandler();
100 
101         // XLogHandler
102         virtual ::rtl::OUString SAL_CALL getEncoding() throw (RuntimeException);
103         virtual void SAL_CALL setEncoding( const ::rtl::OUString& _encoding ) throw (RuntimeException);
104         virtual Reference< XLogFormatter > SAL_CALL getFormatter() throw (RuntimeException);
105         virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) throw (RuntimeException);
106         virtual ::sal_Int32 SAL_CALL getLevel() throw (RuntimeException);
107         virtual void SAL_CALL setLevel( ::sal_Int32 _level ) throw (RuntimeException);
108         virtual void SAL_CALL flush(  ) throw (RuntimeException);
109         virtual ::sal_Bool SAL_CALL publish( const LogRecord& Record ) throw (RuntimeException);
110 
111         // XInitialization
112         virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
113 
114         // XServiceInfo
115 		virtual ::rtl::OUString SAL_CALL getImplementationName() throw(RuntimeException);
116         virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException);
117         virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException);
118 
119         // OComponentHelper
120         virtual void SAL_CALL disposing();
121 
122     public:
123         // XServiceInfo - static version
124 		static ::rtl::OUString SAL_CALL getImplementationName_static();
125         static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static();
126         static Reference< XInterface > Create( const Reference< XComponentContext >& _rxContext );
127 
128     public:
129         typedef ComponentMethodGuard< SyslogHandler > MethodGuard;
130         void    enterMethod( MethodGuard::Access );
131         void    leaveMethod( MethodGuard::Access );
132 	};
133 
134     //====================================================================
135 	//= SyslogHandler - implementation
136 	//====================================================================
137 	//--------------------------------------------------------------------
SyslogHandler(const Reference<XComponentContext> & _rxContext)138     SyslogHandler::SyslogHandler( const Reference< XComponentContext >& _rxContext )
139         :SyslogHandler_Base( m_aMutex )
140         ,m_aContext( _rxContext )
141         ,m_aHandlerHelper( _rxContext, m_aMutex, rBHelper )
142         ,m_aSocketAddress()
143         ,m_aSocket()
144     {
145     }
146 
147     //--------------------------------------------------------------------
~SyslogHandler()148     SyslogHandler::~SyslogHandler()
149     {
150         if ( !rBHelper.bDisposed )
151         {
152             acquire();
153             dispose();
154         }
155     }
156 
157     //--------------------------------------------------------------------
disposing()158     void SAL_CALL SyslogHandler::disposing()
159     {
160         m_aHandlerHelper.setFormatter( NULL );
161     }
162 
163     //--------------------------------------------------------------------
enterMethod(MethodGuard::Access)164     void SyslogHandler::enterMethod( MethodGuard::Access )
165     {
166         m_aHandlerHelper.enterMethod();
167     }
168 
169     //--------------------------------------------------------------------
leaveMethod(MethodGuard::Access)170     void SyslogHandler::leaveMethod( MethodGuard::Access )
171     {
172         m_aMutex.release();
173     }
174 
175     //--------------------------------------------------------------------
getEncoding()176     ::rtl::OUString SAL_CALL SyslogHandler::getEncoding() throw (RuntimeException)
177     {
178         MethodGuard aGuard( *this );
179         ::rtl::OUString sEncoding;
180         OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) );
181         return sEncoding;
182     }
183 
184     //--------------------------------------------------------------------
setEncoding(const::rtl::OUString & _rEncoding)185     void SAL_CALL SyslogHandler::setEncoding( const ::rtl::OUString& _rEncoding ) throw (RuntimeException)
186     {
187         MethodGuard aGuard( *this );
188         OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) );
189     }
190 
191     //--------------------------------------------------------------------
getFormatter()192     Reference< XLogFormatter > SAL_CALL SyslogHandler::getFormatter() throw (RuntimeException)
193     {
194         MethodGuard aGuard( *this );
195         return m_aHandlerHelper.getFormatter();
196     }
197 
198     //--------------------------------------------------------------------
setFormatter(const Reference<XLogFormatter> & _rxFormatter)199     void SAL_CALL SyslogHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) throw (RuntimeException)
200     {
201         MethodGuard aGuard( *this );
202         m_aHandlerHelper.setFormatter( _rxFormatter );
203     }
204 
205     //--------------------------------------------------------------------
getLevel()206     ::sal_Int32 SAL_CALL SyslogHandler::getLevel() throw (RuntimeException)
207     {
208         MethodGuard aGuard( *this );
209         return m_aHandlerHelper.getLevel();
210     }
211 
212     //--------------------------------------------------------------------
setLevel(::sal_Int32 _nLevel)213     void SAL_CALL SyslogHandler::setLevel( ::sal_Int32 _nLevel ) throw (RuntimeException)
214     {
215         MethodGuard aGuard( *this );
216         m_aHandlerHelper.setLevel( _nLevel );
217     }
218 
219     //--------------------------------------------------------------------
flush()220     void SAL_CALL SyslogHandler::flush(  ) throw (RuntimeException)
221     {
222         MethodGuard aGuard( *this );
223         fflush( stdout );
224         fflush( stderr );
225     }
226 
227     //--------------------------------------------------------------------
publish(const LogRecord & _rRecord)228     ::sal_Bool SAL_CALL SyslogHandler::publish( const LogRecord& _rRecord ) throw (RuntimeException)
229     {
230         MethodGuard aGuard( *this );
231 
232         ::rtl::OString sEntry;
233         if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) )
234             return sal_False;
235 
236         ::rtl::OStringBuffer buffer;
237         // PRI
238         const sal_Int32 facility = 1; // USER
239         sal_Int32 severity;
240         switch ( _rRecord.Level )
241         {
242             case LogLevel::SEVERE:
243                 severity = 3; // error
244                 break;
245             case LogLevel::WARNING:
246                 severity = 4; // warning
247                 break;
248             case LogLevel::INFO:
249             case LogLevel::CONFIG:
250                 severity = 5; // notice
251                 break;
252             default:
253                 severity = 7; // debug
254         }
255         buffer.append( '<' );
256         buffer.append( ( facility * 8 ) + severity );
257         buffer.append( '>' );
258 
259         // VERSION
260         buffer.append( '1' );
261         buffer.append( ' ' );
262 
263         // TIMESTAMP
264         char timestampBuffer[256];
265         snprintf( timestampBuffer, sizeof( timestampBuffer ),
266             "%04i-%02i-%02iT%02i:%02i:%02i.%02iZ",
267             (int)_rRecord.LogTime.Year, (int)_rRecord.LogTime.Month, (int)_rRecord.LogTime.Day,
268             (int)_rRecord.LogTime.Hours, (int)_rRecord.LogTime.Minutes, (int)_rRecord.LogTime.Seconds,
269             (int)_rRecord.LogTime.HundredthSeconds );
270         buffer.append( timestampBuffer );
271         buffer.append( ' ' );
272 
273         // HOSTNAME
274         ::rtl::OUString hostname = ::osl::SocketAddr::getLocalHostname( 0 );
275         if ( !hostname.isEmpty() )
276             buffer.append( ::rtl::OUStringToOString( hostname, RTL_TEXTENCODING_UTF8 ) );
277         else
278             buffer.append( '-' );
279         buffer.append( ' ' );
280 
281         // APP-NAME
282         buffer.append( "soffice" );
283         buffer.append( ' ' );
284 
285         // PROC-ID
286         oslProcessInfo pInfo;
287         pInfo.Size = sizeof(oslProcessInfo);
288         oslProcessError prerr = osl_getProcessInfo( NULL, osl_Process_IDENTIFIER, &pInfo );
289         if ( prerr == osl_Process_E_None )
290             buffer.append( (sal_Int64) pInfo.Ident );
291         else
292             buffer.append( '-' );
293         buffer.append( ' ' );
294 
295         // MESSAGE-ID
296         buffer.append( '-' );
297         buffer.append( ' ' );
298 
299         // STRUCTURED DATA
300         buffer.append( '-' );
301         buffer.append( ' ' );
302 
303         // MESSAGE
304         buffer.append( sEntry );
305 
306         sal_Int32 sockRes = m_aSocket.sendTo( m_aSocketAddress, buffer.getStr(), buffer.getLength() );
307 
308         return sockRes == osl_Socket_MsgNormal;
309     }
310 
311     //--------------------------------------------------------------------
initialize(const Sequence<Any> & _rArguments)312     void SAL_CALL SyslogHandler::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException)
313     {
314         ::osl::MutexGuard aGuard( m_aMutex );
315 
316         if ( m_aHandlerHelper.getIsInitialized() )
317             throw AlreadyInitializedException();
318 
319         if ( _rArguments.getLength() != 1 )
320             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
321 
322         Sequence< NamedValue > aSettings;
323         if ( !( _rArguments[0] >>= aSettings ) )
324             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
325 
326         // createWithSettings( [in] sequence< ::com::sun::star::beans::NamedValue > Settings )
327         ::comphelper::NamedValueCollection aTypedSettings( aSettings );
328         m_aHandlerHelper.initFromSettings( aTypedSettings );
329 
330         ::rtl::OUString host;
331         if ( !aTypedSettings.get_ensureType( "Host", host ) )
332             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
333         sal_Int32 port;
334         if ( !aTypedSettings.get_ensureType( "Port", port ) )
335             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
336         ::osl::SocketAddr address( host, port );
337         if ( address.is() )
338             m_aSocketAddress = address;
339         else
340             throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
341 
342         m_aHandlerHelper.setIsInitialized();
343     }
344 
345     //--------------------------------------------------------------------
getImplementationName()346     ::rtl::OUString SAL_CALL SyslogHandler::getImplementationName() throw(RuntimeException)
347     {
348         return getImplementationName_static();
349     }
350 
351     //--------------------------------------------------------------------
supportsService(const::rtl::OUString & _rServiceName)352     ::sal_Bool SAL_CALL SyslogHandler::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException)
353     {
354         const Sequence< ::rtl::OUString > aServiceNames( getSupportedServiceNames() );
355         for (   const ::rtl::OUString* pServiceNames = aServiceNames.getConstArray();
356                 pServiceNames != aServiceNames.getConstArray() + aServiceNames.getLength();
357                 ++pServiceNames
358             )
359             if ( _rServiceName == *pServiceNames )
360                 return sal_True;
361         return sal_False;
362     }
363 
364     //--------------------------------------------------------------------
getSupportedServiceNames()365     Sequence< ::rtl::OUString > SAL_CALL SyslogHandler::getSupportedServiceNames() throw(RuntimeException)
366     {
367         return getSupportedServiceNames_static();
368     }
369 
370     //--------------------------------------------------------------------
getImplementationName_static()371     ::rtl::OUString SAL_CALL SyslogHandler::getImplementationName_static()
372     {
373         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.SyslogHandler" ) );
374     }
375 
376     //--------------------------------------------------------------------
getSupportedServiceNames_static()377     Sequence< ::rtl::OUString > SAL_CALL SyslogHandler::getSupportedServiceNames_static()
378     {
379         Sequence< ::rtl::OUString > aServiceNames(1);
380         aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.logging.SyslogHandler" ) );
381         return aServiceNames;
382     }
383 
384     //--------------------------------------------------------------------
Create(const Reference<XComponentContext> & _rxContext)385     Reference< XInterface > SyslogHandler::Create( const Reference< XComponentContext >& _rxContext )
386     {
387         return *( new SyslogHandler( _rxContext ) );
388     }
389 
390     //--------------------------------------------------------------------
createRegistryInfo_SyslogHandler()391     void createRegistryInfo_SyslogHandler()
392     {
393         static OAutoRegistration< SyslogHandler > aAutoRegistration;
394     }
395 
396 //........................................................................
397 } // namespace logging
398 //........................................................................
399