2013-03-10 03:09:01 +01:00
/******************************************************************************
* Icinga 2 *
* Copyright ( C ) 2012 Icinga Development Team ( http : //www.icinga.org/) *
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation ; either version 2 *
* of the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the Free Software Foundation *
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-03-17 20:19:29 +01:00
# include "livestatus/query.h"
2013-07-11 15:52:01 +02:00
# include "livestatus/countaggregator.h"
2013-07-11 17:52:06 +02:00
# include "livestatus/sumaggregator.h"
2013-07-12 12:07:32 +02:00
# include "livestatus/minaggregator.h"
# include "livestatus/maxaggregator.h"
# include "livestatus/avgaggregator.h"
# include "livestatus/stdaggregator.h"
# include "livestatus/invsumaggregator.h"
# include "livestatus/invavgaggregator.h"
2013-03-17 20:19:29 +01:00
# include "livestatus/attributefilter.h"
# include "livestatus/negatefilter.h"
# include "livestatus/orfilter.h"
# include "livestatus/andfilter.h"
# include "icinga/externalcommandprocessor.h"
2013-08-28 08:18:58 +02:00
# include "base/debug.h"
2013-03-16 21:18:53 +01:00
# include "base/convert.h"
# include "base/objectlock.h"
# include "base/logger_fwd.h"
2013-07-10 16:11:40 +02:00
# include "base/exception.h"
2013-03-15 18:21:29 +01:00
# include <boost/algorithm/string/classification.hpp>
2013-03-16 21:18:53 +01:00
# include <boost/smart_ptr/make_shared.hpp>
# include <boost/foreach.hpp>
2013-03-18 11:02:18 +01:00
# include <boost/algorithm/string/split.hpp>
2013-03-10 03:09:01 +01:00
using namespace icinga ;
2013-03-10 09:23:13 +01:00
using namespace livestatus ;
2013-03-10 03:09:01 +01:00
2013-07-19 15:42:00 +02:00
static int l_ExternalCommands = 0 ;
static boost : : mutex l_QueryMutex ;
2013-03-16 21:18:53 +01:00
Query : : Query ( const std : : vector < String > & lines )
2013-03-10 15:14:14 +01:00
: m_KeepAlive ( false ) , m_OutputFormat ( " csv " ) , m_ColumnHeaders ( true ) , m_Limit ( - 1 )
2013-03-10 05:10:51 +01:00
{
2013-07-12 18:25:18 +02:00
if ( lines . size ( ) = = 0 ) {
m_Verb = " ERROR " ;
m_ErrorCode = LivestatusErrorQuery ;
m_ErrorMessage = " Empty Query. Aborting. " ;
return ;
}
2013-07-29 19:37:58 +02:00
/* default separators */
m_Separators . push_back ( " \n " ) ;
m_Separators . push_back ( " ; " ) ;
m_Separators . push_back ( " , " ) ;
m_Separators . push_back ( " | " ) ;
2013-03-10 05:10:51 +01:00
String line = lines [ 0 ] ;
2013-03-10 03:09:01 +01:00
size_t sp_index = line . FindFirstOf ( " " ) ;
if ( sp_index = = String : : NPos )
2013-03-16 21:18:53 +01:00
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Livestatus header must contain a verb. " ) ) ;
2013-03-10 03:09:01 +01:00
String verb = line . SubStr ( 0 , sp_index ) ;
String target = line . SubStr ( sp_index + 1 ) ;
2013-03-10 05:10:51 +01:00
m_Verb = verb ;
2013-03-10 03:09:01 +01:00
2013-03-10 05:10:51 +01:00
if ( m_Verb = = " COMMAND " ) {
m_Command = target ;
} else if ( m_Verb = = " GET " ) {
m_Table = target ;
2013-03-10 03:09:01 +01:00
} else {
2013-03-10 15:11:32 +01:00
m_Verb = " ERROR " ;
2013-07-12 18:25:18 +02:00
m_ErrorCode = LivestatusErrorQuery ;
2013-03-10 15:11:32 +01:00
m_ErrorMessage = " Unknown livestatus verb: " + m_Verb ;
return ;
2013-03-10 03:09:01 +01:00
}
2013-03-16 21:18:53 +01:00
std : : deque < Filter : : Ptr > filters , stats ;
2013-07-11 15:52:01 +02:00
std : : deque < Aggregator : : Ptr > aggregators ;
2013-03-10 15:11:32 +01:00
for ( unsigned int i = 1 ; i < lines . size ( ) ; i + + ) {
2013-03-10 05:10:51 +01:00
line = lines [ i ] ;
2013-03-10 03:09:01 +01:00
size_t col_index = line . FindFirstOf ( " : " ) ;
String header = line . SubStr ( 0 , col_index ) ;
2013-07-12 10:54:57 +02:00
String params ;
2013-07-29 19:37:58 +02:00
std : : vector < String > separators ;
2013-07-12 10:54:57 +02:00
if ( line . GetLength ( ) > col_index + 2 )
params = line . SubStr ( col_index + 2 ) ;
2013-03-10 03:09:01 +01:00
if ( header = = " ResponseHeader " )
2013-03-10 05:10:51 +01:00
m_ResponseHeader = params ;
2013-03-10 09:23:13 +01:00
else if ( header = = " OutputFormat " )
m_OutputFormat = params ;
else if ( header = = " Columns " )
2013-03-18 11:02:18 +01:00
boost : : algorithm : : split ( m_Columns , params , boost : : is_any_of ( " " ) ) ;
2013-07-29 19:37:58 +02:00
else if ( header = = " Separators " )
boost : : algorithm : : split ( separators , params , boost : : is_any_of ( " " ) ) ;
/* ugly ascii long to char conversion, but works */
if ( separators . size ( ) > 0 )
m_Separators [ 0 ] = String ( 1 , static_cast < char > ( Convert : : ToLong ( separators [ 0 ] ) ) ) ;
if ( separators . size ( ) > 1 )
m_Separators [ 1 ] = String ( 1 , static_cast < char > ( Convert : : ToLong ( separators [ 1 ] ) ) ) ;
if ( separators . size ( ) > 2 )
m_Separators [ 2 ] = String ( 1 , static_cast < char > ( Convert : : ToLong ( separators [ 2 ] ) ) ) ;
if ( separators . size ( ) > 3 )
m_Separators [ 3 ] = String ( 1 , static_cast < char > ( Convert : : ToLong ( separators [ 3 ] ) ) ) ;
2013-03-10 15:11:32 +01:00
else if ( header = = " ColumnHeaders " )
m_ColumnHeaders = ( params = = " on " ) ;
2013-07-11 17:52:06 +02:00
else if ( header = = " Filter " ) {
2013-07-11 15:52:01 +02:00
Filter : : Ptr filter = ParseFilter ( params ) ;
2013-07-11 17:52:06 +02:00
2013-07-11 15:52:01 +02:00
if ( ! filter ) {
2013-03-10 15:11:32 +01:00
m_Verb = " ERROR " ;
2013-07-12 18:25:18 +02:00
m_ErrorCode = LivestatusErrorQuery ;
2013-07-12 10:54:57 +02:00
m_ErrorMessage = " Invalid filter specification: " + line ;
2013-03-10 15:11:32 +01:00
return ;
}
2013-07-12 10:54:57 +02:00
filters . push_back ( filter ) ;
} else if ( header = = " Stats " ) {
2013-07-11 17:52:06 +02:00
std : : vector < String > tokens ;
boost : : algorithm : : split ( tokens , params , boost : : is_any_of ( " " ) ) ;
2013-07-12 10:54:57 +02:00
if ( tokens . size ( ) < 2 ) {
m_Verb = " ERROR " ;
2013-07-12 18:25:18 +02:00
m_ErrorCode = LivestatusErrorQuery ;
2013-07-12 10:54:57 +02:00
m_ErrorMessage = " Missing aggregator column name: " + line ;
return ;
}
2013-07-11 17:52:06 +02:00
String aggregate_arg = tokens [ 0 ] ;
String aggregate_attr = tokens [ 1 ] ;
2013-07-12 10:54:57 +02:00
Aggregator : : Ptr aggregator ;
Filter : : Ptr filter ;
2013-07-11 17:52:06 +02:00
if ( aggregate_arg = = " sum " ) {
2013-07-12 10:54:57 +02:00
aggregator = boost : : make_shared < SumAggregator > ( aggregate_attr ) ;
} else if ( aggregate_arg = = " min " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < MinAggregator > ( aggregate_attr ) ;
2013-07-12 10:54:57 +02:00
} else if ( aggregate_arg = = " max " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < MaxAggregator > ( aggregate_attr ) ;
2013-07-12 10:54:57 +02:00
} else if ( aggregate_arg = = " avg " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < AvgAggregator > ( aggregate_attr ) ;
2013-07-12 10:54:57 +02:00
} else if ( aggregate_arg = = " std " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < StdAggregator > ( aggregate_attr ) ;
2013-07-12 10:54:57 +02:00
} else if ( aggregate_arg = = " suminv " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < InvSumAggregator > ( aggregate_attr ) ;
2013-07-12 10:54:57 +02:00
} else if ( aggregate_arg = = " avginv " ) {
2013-07-12 12:07:32 +02:00
aggregator = boost : : make_shared < InvAvgAggregator > ( aggregate_attr ) ;
2013-07-11 17:52:06 +02:00
} else {
2013-07-12 10:54:57 +02:00
filter = ParseFilter ( params ) ;
2013-07-11 17:52:06 +02:00
if ( ! filter ) {
m_Verb = " ERROR " ;
2013-07-12 18:25:18 +02:00
m_ErrorCode = LivestatusErrorQuery ;
2013-07-12 10:54:57 +02:00
m_ErrorMessage = " Invalid filter specification: " + line ;
2013-07-11 17:52:06 +02:00
return ;
}
2013-07-12 10:54:57 +02:00
aggregator = boost : : make_shared < CountAggregator > ( ) ;
2013-07-11 15:52:01 +02:00
}
2013-07-11 17:52:06 +02:00
2013-07-12 10:54:57 +02:00
aggregator - > SetFilter ( filter ) ;
aggregators . push_back ( aggregator ) ;
stats . push_back ( filter ) ;
2013-03-10 15:11:32 +01:00
} else if ( header = = " Or " | | header = = " And " ) {
2013-03-16 21:18:53 +01:00
std : : deque < Filter : : Ptr > & deq = ( header = = " Or " | | header = = " And " ) ? filters : stats ;
2013-03-10 17:54:46 +01:00
2013-03-10 15:11:32 +01:00
int num = Convert : : ToLong ( params ) ;
CombinerFilter : : Ptr filter ;
2013-03-10 17:54:46 +01:00
if ( header = = " Or " | | header = = " StatsOr " )
2013-03-10 15:11:32 +01:00
filter = boost : : make_shared < OrFilter > ( ) ;
else
filter = boost : : make_shared < AndFilter > ( ) ;
2013-03-10 17:54:46 +01:00
if ( num > deq . size ( ) ) {
m_Verb = " ERROR " ;
m_ErrorCode = 451 ;
2013-08-20 12:50:24 +02:00
m_ErrorMessage = " Or/StatsOr is referencing " + Convert : : ToString ( num ) + " filters; stack only contains " + Convert : : ToString ( static_cast < long > ( deq . size ( ) ) ) + " filters " ;
2013-03-10 17:54:46 +01:00
return ;
}
while ( num - - ) {
filter - > AddSubFilter ( deq . back ( ) ) ;
deq . pop_back ( ) ;
2013-03-10 15:11:32 +01:00
}
2013-03-10 17:54:46 +01:00
deq . push_back ( filter ) ;
} else if ( header = = " Negate " | | header = = " StatsNegate " ) {
2013-03-16 21:18:53 +01:00
std : : deque < Filter : : Ptr > & deq = ( header = = " Negate " ) ? filters : stats ;
2013-03-10 15:27:55 +01:00
2013-03-10 17:54:46 +01:00
if ( deq . empty ( ) ) {
m_Verb = " ERROR " ;
m_ErrorCode = 451 ;
m_ErrorMessage = " Negate/StatsNegate used, however the filter stack is empty " ;
return ;
2013-03-10 15:27:55 +01:00
}
2013-03-10 17:54:46 +01:00
Filter : : Ptr filter = deq . back ( ) ;
2013-07-12 10:54:57 +02:00
deq . pop_back ( ) ;
if ( ! filter ) {
m_Verb = " ERROR " ;
m_ErrorCode = 451 ;
m_ErrorMessage = " Negate/StatsNegate used, however last stats doesn't have a filter " ;
return ;
}
2013-03-10 17:54:46 +01:00
deq . push_back ( boost : : make_shared < NegateFilter > ( filter ) ) ;
2013-07-11 17:52:06 +02:00
2013-07-11 15:52:01 +02:00
if ( deq = = stats ) {
Aggregator : : Ptr aggregator = aggregators . back ( ) ;
aggregator - > SetFilter ( filter ) ;
}
2013-03-10 15:11:32 +01:00
}
2013-03-10 09:23:13 +01:00
}
2013-03-10 15:11:32 +01:00
2013-03-10 15:23:08 +01:00
/* Combine all top-level filters into a single filter. */
AndFilter : : Ptr top_filter = boost : : make_shared < AndFilter > ( ) ;
BOOST_FOREACH ( const Filter : : Ptr & filter , filters ) {
top_filter - > AddSubFilter ( filter ) ;
}
m_Filter = top_filter ;
2013-07-11 15:52:01 +02:00
m_Aggregators . swap ( aggregators ) ;
}
2013-07-19 15:42:00 +02:00
int Query : : GetExternalCommands ( void )
{
boost : : mutex : : scoped_lock lock ( l_QueryMutex ) ;
return l_ExternalCommands ;
}
2013-07-11 15:52:01 +02:00
Filter : : Ptr Query : : ParseFilter ( const String & params )
{
std : : vector < String > tokens ;
boost : : algorithm : : split ( tokens , params , boost : : is_any_of ( " " ) ) ;
if ( tokens . size ( ) = = 2 )
tokens . push_back ( " " ) ;
if ( tokens . size ( ) < 3 )
return Filter : : Ptr ( ) ;
String op = tokens [ 1 ] ;
bool negate = false ;
if ( op = = " != " ) {
op = " = " ;
negate = true ;
} else if ( op = = " !~ " ) {
op = " ~ " ;
negate = true ;
} else if ( op = = " !=~ " ) {
op = " =~ " ;
negate = true ;
} else if ( op = = " !~~ " ) {
op = " ~~ " ;
negate = true ;
}
Filter : : Ptr filter = boost : : make_shared < AttributeFilter > ( tokens [ 0 ] , op , tokens [ 2 ] ) ;
if ( negate )
filter = boost : : make_shared < NegateFilter > ( filter ) ;
return filter ;
2013-03-10 09:23:13 +01:00
}
2013-03-17 20:19:29 +01:00
void Query : : PrintResultSet ( std : : ostream & fp , const std : : vector < String > & columns , const Array : : Ptr & rs )
2013-03-10 09:23:13 +01:00
{
2013-03-10 15:11:32 +01:00
if ( m_OutputFormat = = " csv " & & m_Columns . size ( ) = = 0 & & m_ColumnHeaders ) {
2013-03-10 09:23:13 +01:00
bool first = true ;
BOOST_FOREACH ( const String & column , columns ) {
if ( first )
first = false ;
else
2013-07-29 19:37:58 +02:00
fp < < m_Separators [ 1 ] ;
2013-03-10 09:23:13 +01:00
fp < < column ;
}
2013-07-29 19:37:58 +02:00
fp < < m_Separators [ 0 ] ;
2013-03-10 09:23:13 +01:00
}
if ( m_OutputFormat = = " csv " ) {
ObjectLock olock ( rs ) ;
BOOST_FOREACH ( const Array : : Ptr & row , rs ) {
bool first = true ;
ObjectLock rlock ( row ) ;
BOOST_FOREACH ( const Value & value , row ) {
if ( first )
first = false ;
else
2013-07-29 19:37:58 +02:00
fp < < m_Separators [ 1 ] ;
2013-03-10 09:23:13 +01:00
2013-07-15 10:50:41 +02:00
if ( value . IsObjectType < Array > ( ) )
PrintCsvArray ( fp , value , 0 ) ;
else
2013-07-23 08:57:22 +02:00
fp < < value ;
2013-03-10 09:23:13 +01:00
}
2013-07-29 19:37:58 +02:00
fp < < m_Separators [ 0 ] ;
2013-03-10 09:23:13 +01:00
}
} else if ( m_OutputFormat = = " json " ) {
fp < < Value ( rs ) . Serialize ( ) ;
2013-03-10 03:09:01 +01:00
}
}
2013-07-15 10:50:41 +02:00
void Query : : PrintCsvArray ( std : : ostream & fp , const Array : : Ptr & array , int level )
{
bool first = true ;
ObjectLock olock ( array ) ;
BOOST_FOREACH ( const Value & value , array ) {
if ( first )
first = false ;
else
2013-07-29 19:37:58 +02:00
fp < < ( ( level = = 0 ) ? m_Separators [ 2 ] : m_Separators [ 3 ] ) ;
2013-07-15 10:50:41 +02:00
if ( value . IsObjectType < Array > ( ) )
PrintCsvArray ( fp , value , level + 1 ) ;
else
2013-07-23 08:57:22 +02:00
fp < < value ;
2013-07-15 10:50:41 +02:00
}
}
2013-03-10 09:23:13 +01:00
void Query : : ExecuteGetHelper ( const Stream : : Ptr & stream )
2013-03-10 03:09:01 +01:00
{
2013-03-16 21:18:53 +01:00
Log ( LogInformation , " livestatus " , " Table: " + m_Table ) ;
2013-03-10 09:23:13 +01:00
Table : : Ptr table = Table : : GetByName ( m_Table ) ;
if ( ! table ) {
2013-07-12 18:25:18 +02:00
SendResponse ( stream , LivestatusErrorNotFound , " Table ' " + m_Table + " ' does not exist. " ) ;
2013-03-10 09:23:13 +01:00
return ;
}
2013-07-10 16:11:40 +02:00
std : : vector < Value > objects = table - > FilterRows ( m_Filter ) ;
2013-03-16 21:18:53 +01:00
std : : vector < String > columns ;
2013-03-10 09:23:13 +01:00
if ( m_Columns . size ( ) > 0 )
columns = m_Columns ;
else
columns = table - > GetColumnNames ( ) ;
Array : : Ptr rs = boost : : make_shared < Array > ( ) ;
2013-07-11 15:52:01 +02:00
if ( m_Aggregators . empty ( ) ) {
2013-07-10 16:11:40 +02:00
BOOST_FOREACH ( const Value & object , objects ) {
2013-03-10 17:54:46 +01:00
Array : : Ptr row = boost : : make_shared < Array > ( ) ;
2013-03-10 09:23:13 +01:00
2013-03-10 18:49:14 +01:00
BOOST_FOREACH ( const String & columnName , columns ) {
Column column = table - > GetColumn ( columnName ) ;
2013-03-10 17:54:46 +01:00
2013-03-10 18:49:14 +01:00
row - > Add ( column . ExtractValue ( object ) ) ;
2013-03-10 09:23:13 +01:00
}
2013-03-10 17:54:46 +01:00
rs - > Add ( row ) ;
}
} else {
2013-07-11 15:52:01 +02:00
std : : vector < double > stats ( m_Aggregators . size ( ) , 0 ) ;
2013-03-10 17:54:46 +01:00
2013-07-11 15:52:01 +02:00
int index = 0 ;
BOOST_FOREACH ( const Aggregator : : Ptr aggregator , m_Aggregators ) {
BOOST_FOREACH ( const Value & object , objects ) {
aggregator - > Apply ( table , object ) ;
2013-03-10 17:54:46 +01:00
}
2013-07-11 15:52:01 +02:00
stats [ index ] = aggregator - > GetResult ( ) ;
index + + ;
2013-03-10 09:23:13 +01:00
}
2013-03-10 17:54:46 +01:00
Array : : Ptr row = boost : : make_shared < Array > ( ) ;
2013-07-11 15:52:01 +02:00
for ( int i = 0 ; i < m_Aggregators . size ( ) ; i + + )
2013-03-10 17:54:46 +01:00
row - > Add ( stats [ i ] ) ;
2013-03-10 09:23:13 +01:00
rs - > Add ( row ) ;
2013-03-10 17:54:46 +01:00
m_ColumnHeaders = false ;
2013-03-10 09:23:13 +01:00
}
2013-03-16 21:18:53 +01:00
std : : ostringstream result ;
2013-03-10 09:23:13 +01:00
PrintResultSet ( result , columns , rs ) ;
2013-07-12 18:25:18 +02:00
SendResponse ( stream , LivestatusErrorOK , result . str ( ) ) ;
2013-03-10 03:09:01 +01:00
}
2013-03-10 09:23:13 +01:00
void Query : : ExecuteCommandHelper ( const Stream : : Ptr & stream )
2013-03-10 03:09:01 +01:00
{
2013-07-19 15:42:00 +02:00
{
boost : : mutex : : scoped_lock lock ( l_QueryMutex ) ;
l_ExternalCommands + + ;
}
2013-03-16 21:18:53 +01:00
Log ( LogInformation , " livestatus " , " Executing command: " + m_Command ) ;
2013-03-10 15:11:32 +01:00
ExternalCommandProcessor : : Execute ( m_Command ) ;
2013-07-12 18:25:18 +02:00
SendResponse ( stream , LivestatusErrorOK , " " ) ;
2013-03-10 03:09:01 +01:00
}
2013-03-10 09:23:13 +01:00
void Query : : ExecuteErrorHelper ( const Stream : : Ptr & stream )
2013-03-10 03:09:01 +01:00
{
2013-03-10 17:54:46 +01:00
SendResponse ( stream , m_ErrorCode , m_ErrorMessage ) ;
2013-03-10 03:09:01 +01:00
}
2013-03-10 09:23:13 +01:00
void Query : : SendResponse ( const Stream : : Ptr & stream , int code , const String & data )
2013-03-10 03:09:01 +01:00
{
if ( m_ResponseHeader = = " fixed16 " )
PrintFixed16 ( stream , code , data ) ;
2013-03-10 05:10:51 +01:00
2013-07-12 18:25:18 +02:00
if ( m_ResponseHeader = = " fixed16 " | | code = = LivestatusErrorOK )
2013-03-10 03:09:01 +01:00
stream - > Write ( data . CStr ( ) , data . GetLength ( ) ) ;
}
2013-03-10 09:23:13 +01:00
void Query : : PrintFixed16 ( const Stream : : Ptr & stream , int code , const String & data )
2013-03-10 03:09:01 +01:00
{
ASSERT ( code > = 100 & & code < = 999 ) ;
String sCode = Convert : : ToString ( code ) ;
2013-08-20 12:50:24 +02:00
String sLength = Convert : : ToString ( static_cast < long > ( data . GetLength ( ) ) ) ;
2013-03-10 03:09:01 +01:00
2013-07-29 19:37:58 +02:00
String header = sCode + String ( 16 - 3 - sLength . GetLength ( ) - 1 , ' ' ) + sLength + m_Separators [ 0 ] ;
2013-03-10 03:09:01 +01:00
stream - > Write ( header . CStr ( ) , header . GetLength ( ) ) ;
}
2013-07-04 09:45:44 +02:00
bool Query : : Execute ( const Stream : : Ptr & stream )
2013-03-10 03:09:01 +01:00
{
2013-03-10 15:11:32 +01:00
try {
2013-07-10 16:11:40 +02:00
Log ( LogInformation , " livestatus " , " Executing livestatus query: " + m_Verb ) ;
if ( m_Verb = = " GET " )
ExecuteGetHelper ( stream ) ;
else if ( m_Verb = = " COMMAND " )
ExecuteCommandHelper ( stream ) ;
else if ( m_Verb = = " ERROR " )
ExecuteErrorHelper ( stream ) ;
else
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Invalid livestatus query verb. " ) ) ;
2013-03-10 15:11:32 +01:00
} catch ( const std : : exception & ex ) {
2013-07-10 16:11:40 +02:00
StackTrace * st = Exception : : GetLastStackTrace ( ) ;
std : : ostringstream info ;
st - > Print ( info ) ;
2013-07-29 11:22:56 +02:00
Log ( LogDebug , " livestatus " , info . str ( ) ) ;
2013-07-12 18:25:18 +02:00
SendResponse ( stream , LivestatusErrorQuery , boost : : diagnostic_information ( ex ) ) ;
2013-03-10 15:11:32 +01:00
}
2013-03-10 05:10:51 +01:00
2013-07-04 09:45:44 +02:00
if ( ! m_KeepAlive ) {
2013-03-10 05:10:51 +01:00
stream - > Close ( ) ;
2013-07-04 09:45:44 +02:00
return false ;
}
return true ;
2013-03-10 03:09:01 +01:00
}