47#include "BESInterface.h"
49#include "TheBESKeys.h"
50#include "BESContextManager.h"
52#include "BESTransmitterNames.h"
53#include "BESDataNames.h"
54#include "BESReturnManager.h"
56#include "BESInfoList.h"
57#include "BESXMLInfo.h"
61#include "BESStopWatch.h"
62#include "BESInternalError.h"
63#include "BESInternalFatalError.h"
64#include "ServerAdministrator.h"
65#include "RequestServiceTimer.h"
70#define EXCLUDE_FILE_INFO_FROM_LOG "BES.DoNotLogSourceFilenames"
71#define prolog std::string("BESInterface::").append(__func__).append("() - ")
88volatile int bes_timeout = 0;
91#define BES_TIMEOUT_KEY "BES.TimeOutInSeconds"
93static inline void downcase(
string &s)
95 transform(s.begin(), s.end(), s.begin(), [](
int c) { return std::toupper(c); });
102ostream &add_memory_info(ostream &out)
106 out <<
", current memory usage is " << mem_size <<
" KB.";
109 out <<
", current memory usage is unknown.";
115static void log_error(
const BESError &e)
120 case BES_INTERNAL_FATAL_ERROR:
121 error_name =
"BES Internal Fatal Error";
124 case BES_INTERNAL_ERROR:
125 error_name =
"BES Internal Error";
128 case BES_SYNTAX_USER_ERROR:
129 error_name =
"BES User Syntax Error";
132 case BES_FORBIDDEN_ERROR:
133 error_name =
"BES Forbidden Error";
136 case BES_NOT_FOUND_ERROR:
137 error_name =
"BES Not Found Error";
141 error_name =
"BES Error";
146 ERROR_LOG(
"ERROR: " << error_name <<
": " << e.
get_message() << add_memory_info << endl);
149 ERROR_LOG(
"ERROR: " << error_name <<
": " << e.
get_message()
151 << add_memory_info << endl);
182static pthread_t alarm_thread;
184static void* alarm_wait(
void * )
186 BESDEBUG(
"bes",
"Starting: " << __PRETTY_FUNCTION__ << endl);
190 sigemptyset(&sigset);
191 sigaddset(&sigset, SIGALRM);
192 sigprocmask(SIG_BLOCK, &sigset, NULL);
197 int result = sigwait(&sigset, &sig);
199 BESDEBUG(
"bes",
"Fatal error establishing timeout: " << strerror(result) << endl);
200 throw BESInternalFatalError(
string(
"Fatal error establishing timeout: ") + strerror(result), __FILE__, __LINE__);
202 else if (result == 0 && sig == SIGALRM) {
203 BESDEBUG(
"bes",
"Timeout found in " << __PRETTY_FUNCTION__ << endl);
208 oss <<
"While waiting for a timeout, found signal '" << result <<
"' in " << __PRETTY_FUNCTION__ << ends;
209 BESDEBUG(
"bes", oss.str() << endl);
214static void wait_for_timeout()
216 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
218 pthread_attr_t thread_attr;
220 if (pthread_attr_init(&thread_attr) != 0)
222 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED ) != 0)
223 throw BESInternalFatalError(
"Failed to complete pthread attribute initialization.", __FILE__, __LINE__);
225 int status = pthread_create(&alarm_thread, &thread_attr, alarm_wait, NULL);
231BESInterface::BESInterface(ostream *output_stream) :
232 d_strm(output_stream)
235 throw BESInternalError(
"Output stream must be set in order to output responses", __FILE__, __LINE__);
247 string timeout_key_value;
250 istringstream iss(timeout_key_value);
251 iss >> d_timeout_from_keys;
269 string context = BESContextManager::TheManager()->
get_context(
"errors", found);
271 if (found && context == XML_ERRORS)
274 dhi.
error_info = BESInfoList::TheList()->build_info();
281 admin_email = sd.get_email();
284 admin_email =
"support@opendap.org";
286 if (admin_email.empty()) {
287 admin_email =
"support@opendap.org";
308 string context = BESContextManager::TheManager()->
get_context(
"bes_timeout", found);
310 d_bes_timeout = strtol(context.c_str(), NULL, 10);
311 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << d_bes_timeout <<
" seconds (from context)." << endl);
323 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << d_bes_timeout <<
" seconds (from keys)." << endl);
378 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
381 throw BESInternalError(
"DataHandlerInterface can not be null", __FILE__, __LINE__);
409 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
" request received" << endl);
414 d_transmitter = BESReturnManager::TheManager()->find_transmitter(BASIC_TRANSMITTER);
416 throw BESInternalError(
string(
"Unable to find transmitter '") + BASIC_TRANSMITTER +
"'", __FILE__, __LINE__);
418 build_data_request_plan();
436 execute_data_request_plan();
444 BESDEBUG(
"bes",
string(__PRETTY_FUNCTION__) +
" - Caught BESError. msg: " << e.
get_message() << endl );
447 catch (
const bad_alloc &e) {
449 msg << __PRETTY_FUNCTION__ <<
" - BES out of memory. msg: " << e.
what() << endl;
450 BESDEBUG(
"bes", msg.str() << endl );
454 catch (
const exception &e) {
456 msg << __PRETTY_FUNCTION__ <<
" - Caught C++ Exception. msg: " << e.
what() << endl;
457 BESDEBUG(
"bes", msg.str() << endl );
462 string msg = string(__PRETTY_FUNCTION__) +
" - An unidentified exception has been thrown.";
463 BESDEBUG(
"bes", msg << endl );
493 ERROR_LOG(
"Problem logging status or running end of request cleanup: " << ex.
get_message() << endl);
496 ERROR_LOG(
"Unknown problem logging status or running end of request cleanup" << endl);
528 strm << BESIndent::LMarg <<
"BESInterface::dump - (" << (
void *)
this <<
")" << endl;
531 strm << BESIndent::LMarg <<
"data handler interface:" << endl;
534 BESIndent::UnIndent();
537 strm << BESIndent::LMarg <<
"transmitter:" << endl;
540 BESIndent::UnIndent();
543 strm << BESIndent::LMarg <<
"transmitter: not set" << endl;
546 BESIndent::UnIndent();
virtual std::string get_context(const std::string &name, bool &found)
retrieve the value of the specified context from the BES
Structure storing information used by the BES to handle the request.
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
void dump(std::ostream &strm) const override
dumps information about this object
void first_container()
set the container pointer to the first container in the containers list
BESContainer * container
pointer to current container in this interface
BESInfo * error_info
error information object
void next_container()
set the container pointer to the next * container in the list, null if at the end or no containers in...
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Base exception class for the BES with basic string message.
unsigned int get_line() const
get the line number where the exception was thrown
unsigned int get_bes_error_type() const
Return the return code for this error class.
const char * what() const noexcept override
Return a brief message about the exception.
std::string get_file() const
get the file name where the exception was thrown
std::string get_message() const
get the error message for this exception
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
virtual void print(std::ostream &strm)
print the information from this informational object to the specified stream
virtual void add_exception(const BESError &e, const std::string &admin)
add exception information to this informational object
static int handleException(const BESError &e, BESDataHandlerInterface &dhi)
Make a BESXMLInfo object to hold the error information.
virtual int finish(int status)
virtual int execute_request(const std::string &from)
The entry point for command execution; called by BESServerHandler::execute()
virtual void end_request()
End the BES request.
BESDataHandlerInterface * d_dhi_ptr
Allocated by the child class.
BESTransmitter * d_transmitter
The Transmitter to use for the result.
void clear_bes_timeout()
Clear the bes timeout.
void dump(std::ostream &strm) const override
dumps information about this object
void set_bes_timeout()
Set the int 'd_bes_timeout' Use either the value of a 'bes_timeout' context or the value set in the B...
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
virtual bool start(std::string name)
error thrown if there is a user syntax error in the request or any other user error
virtual void dump(std::ostream &strm) const
dumps information about this object
static long get_current_memory_usage() noexcept
Get the Resident Set Size in KB.
represents an xml formatted response object
static RequestServiceTimer * TheTimer()
Return a pointer to a singleton timer instance. If an instance does not exist it will create and init...
void start(std::chrono::milliseconds timeout_ms)
Set/Reset the timer start_time to now().
void disable_timeout()
Set the time_out is disabled.
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
int read_int_key(const std::string &key, int default_value)
Read an integer-valued key from the bes.conf file.
A ServerAdministrator object from the TheBESKeys associated with the string SERVER_ADMIN_KEY.