50 #include "BESInterface.h"
52 #include "TheBESKeys.h"
53 #include "BESResponseHandler.h"
54 #include "BESContextManager.h"
56 #include "BESDapError.h"
58 #include "BESTransmitterNames.h"
59 #include "BESDataNames.h"
60 #include "BESTransmitterNames.h"
61 #include "BESReturnManager.h"
62 #include "BESSyntaxUserError.h"
64 #include "BESInfoList.h"
65 #include "BESXMLInfo.h"
68 #include "BESStopWatch.h"
69 #include "BESTimeoutError.h"
70 #include "BESInternalError.h"
71 #include "BESInternalFatalError.h"
72 #include "ServerAdministrator.h"
77 #define EXCLUDE_FILE_INFO_FROM_LOG "BES.DoNotLogSourceFilenames"
82 static jmp_buf timeout_jump;
83 static bool timeout_jump_valid =
false;
97 volatile int bes_timeout = 0;
99 #define BES_TIMEOUT_KEY "BES.TimeOutInSeconds"
110 static void catch_sig_alarm(
int sig)
112 if (sig == SIGALRM) {
113 LOG(
"BES timeout after " << bes_timeout <<
" seconds." << endl);
118 if (timeout_jump_valid)
119 longjmp(timeout_jump, 1);
124 signal(SIGTERM, SIG_DFL);
130 static void register_signal_handler()
132 struct sigaction act;
133 sigemptyset(&act.sa_mask);
134 sigaddset(&act.sa_mask, SIGALRM);
140 act.sa_handler = catch_sig_alarm;
141 if (sigaction(SIGALRM, &act, 0))
142 throw BESInternalFatalError(
"Could not register a handler to catch alarm/timeout.", __FILE__, __LINE__);
145 static inline void downcase(
string &s)
147 for (
unsigned int i = 0; i < s.length(); i++)
148 s[i] = tolower(s[i]);
153 string error_name =
"";
159 bool only_log_to_verbose =
false;
162 case BES_INTERNAL_FATAL_ERROR:
163 error_name =
"BES Internal Fatal Error";
166 case BES_INTERNAL_ERROR:
167 error_name =
"BES Internal Error";
170 case BES_SYNTAX_USER_ERROR:
171 error_name =
"BES User Syntax Error";
175 case BES_FORBIDDEN_ERROR:
176 error_name =
"BES Forbidden Error";
179 case BES_NOT_FOUND_ERROR:
180 error_name =
"BES Not Found Error";
185 error_name =
"BES Error";
190 LOG(
"ERROR: " << error_name <<
": " << e.
get_message() << endl);
197 if (only_log_to_verbose) {
238 static pthread_t alarm_thread;
240 static void* alarm_wait(
void * )
242 BESDEBUG(
"bes",
"Starting: " << __PRETTY_FUNCTION__ << endl);
246 sigemptyset(&sigset);
247 sigaddset(&sigset, SIGALRM);
248 sigprocmask(SIG_BLOCK, &sigset, NULL);
253 int result = sigwait(&sigset, &sig);
255 BESDEBUG(
"bes",
"Fatal error establishing timeout: " << strerror(result) << endl);
256 throw BESInternalFatalError(
string(
"Fatal error establishing timeout: ") + strerror(result), __FILE__, __LINE__);
258 else if (result == 0 && sig == SIGALRM) {
259 BESDEBUG(
"bes",
"Timeout found in " << __PRETTY_FUNCTION__ << endl);
264 oss <<
"While waiting for a timeout, found signal '" << result <<
"' in " << __PRETTY_FUNCTION__ << ends;
265 BESDEBUG(
"bes", oss.str() << endl);
270 static void wait_for_timeout()
272 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
274 pthread_attr_t thread_attr;
276 if (pthread_attr_init(&thread_attr) != 0)
278 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED ) != 0)
279 throw BESInternalFatalError(
"Failed to complete pthread attribute initialization.", __FILE__, __LINE__);
281 int status = pthread_create(&alarm_thread, &thread_attr, alarm_wait, NULL);
287 BESInterface::BESInterface(ostream *output_stream) :
288 d_strm(output_stream), d_timeout_from_keys(0), d_dhi_ptr(0), d_transmitter(0)
291 throw BESInternalError(
"Output stream must be set in order to output responses", __FILE__, __LINE__);
299 string timeout_key_value;
302 istringstream iss(timeout_key_value);
303 iss >> d_timeout_from_keys;
307 register_signal_handler();
315 extern BESStopWatch *bes_timing::elapsedTimeToReadStart;
316 extern BESStopWatch *bes_timing::elapsedTimeToTransmitStart;
332 string context = BESContextManager::TheManager()->
get_context(
"errors", found);
334 if (found && context == XML_ERRORS)
337 dhi.
error_info = BESInfoList::TheList()->build_info();
342 dhi.
error_info = BESInfoList::TheList()->build_info();
347 string admin_email =
"";
350 admin_email = sd.get_email();
353 admin_email =
"support@opendap.org";
355 if (admin_email.empty()) {
356 admin_email =
"support@opendap.org";
377 string context = BESContextManager::TheManager()->
get_context(
"errors", found);
378 if (context ==
"dap2" || context ==
"dap") {
379 libdap::ErrorCode ec = unknown_error;
382 ec = de->get_error_code();
398 s <<
"libdap exception building response: error_code = " << de->get_error_code() <<
": "
449 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
452 throw BESInternalError(
"DataHandlerInterface can not be null", __FILE__, __LINE__);
456 if (BESISDEBUG(TIMING_LOG)) {
462 bes_timing::elapsedTimeToReadStart =
new BESStopWatch();
463 bes_timing::elapsedTimeToReadStart->
start(
"TIME_TO_READ_START",
d_dhi_ptr->
data[REQUEST_ID]);
465 bes_timing::elapsedTimeToTransmitStart =
new BESStopWatch();
466 bes_timing::elapsedTimeToTransmitStart->
start(
"TIME_TO_TRANSMIT_START",
d_dhi_ptr->
data[REQUEST_ID]);
489 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
" request received" << endl);
494 d_transmitter = BESReturnManager::TheManager()->find_transmitter(BASIC_TRANSMITTER);
496 throw BESInternalError(
string(
"Unable to find transmitter '") + BASIC_TRANSMITTER +
"'", __FILE__, __LINE__);
498 build_data_request_plan();
507 if (setjmp(timeout_jump) == 0) {
508 timeout_jump_valid =
true;
512 string context = BESContextManager::TheManager()->
get_context(
"bes_timeout", found);
514 bes_timeout = strtol(context.c_str(), NULL, 10);
515 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << bes_timeout <<
" seconds (from context)." << endl);
518 else if (d_timeout_from_keys != 0) {
519 bes_timeout = d_timeout_from_keys;
520 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << bes_timeout <<
" seconds (from keys)." << endl);
527 execute_data_request_plan();
530 if (bes_timeout != 0) {
536 timeout_jump_valid =
false;
540 oss <<
"BES listener timeout after " << bes_timeout <<
" seconds." << ends;
546 catch (libdap::Error &e) {
547 timeout_jump_valid =
false;
548 BESInternalFatalError ex(
string(
"BES caught a libdap exception: ") + e.get_error_message(), __FILE__, __LINE__);
552 timeout_jump_valid =
false;
555 catch (bad_alloc &e) {
556 timeout_jump_valid =
false;
560 catch (exception &e) {
561 timeout_jump_valid =
false;
566 timeout_jump_valid =
false;
567 BESInternalError ex(
"An unidentified exception has been thrown", __FILE__, __LINE__);
596 LOG(
"Problem logging status or running end of request cleanup: " << ex.
get_message() << endl);
599 LOG(
"Unknown problem logging status or running end of request cleanup" << endl);
631 strm << BESIndent::LMarg <<
"BESInterface::dump - (" << (
void *)
this <<
")" << endl;
634 strm << BESIndent::LMarg <<
"data handler interface:" << endl;
637 BESIndent::UnIndent();
640 strm << BESIndent::LMarg <<
"transmitter:" << endl;
643 BESIndent::UnIndent();
646 strm << BESIndent::LMarg <<
"transmitter: not set" << endl;
649 BESIndent::UnIndent();
virtual std::string get_context(const std::string &name, bool &found)
retrieve the value of the specified context from the BES
silent informational response object
error object created from libdap error objects and can handle those errors
int convert_error_code(int error_code, int current_error_type)
converts the libdap error code to the bes error type
Structure storing information used by the BES to handle the request.
void dump(std::ostream &strm) const
dumps information about this object
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
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...
Abstract exception class for the BES with basic string message.
virtual int get_bes_error_type()
Return the return code for this error class.
virtual void set_bes_error_type(int type)
Set the return code for this particular error class.
virtual int get_line()
get the line number where the exception was thrown
virtual std::string get_file()
get the file name where the exception was thrown
virtual std::string get_message()
get the error message for this exception
virtual void set_message(const std::string &msg)
set 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(BESError &e, const std::string &admin)
add exception information to this informational object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual int finish(int status)
virtual int execute_request(const std::string &from)
The entry point for command execution; called by BESServerHandler::execute()
static int handleException(BESError &e, BESDataHandlerInterface &dhi)
Make a BESXMLInfo object to hold the error information.
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.
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
represents an xml formatted response object
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
A ServerAdministrator object from the TheBESKeys associated with the string SERVER_ADMIN_KEY.