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"
81 static jmp_buf timeout_jump;
82 static bool timeout_jump_valid =
false;
96 volatile int bes_timeout = 0;
98 #define BES_TIMEOUT_KEY "BES.TimeOutInSeconds"
109 static void catch_sig_alarm(
int sig)
111 if (sig == SIGALRM) {
112 LOG(
"BES timeout after " << bes_timeout <<
" seconds." << endl);
117 if (timeout_jump_valid)
118 longjmp(timeout_jump, 1);
123 signal(SIGTERM, SIG_DFL);
129 static void register_signal_handler()
131 struct sigaction act;
132 sigemptyset(&act.sa_mask);
133 sigaddset(&act.sa_mask, SIGALRM);
139 act.sa_handler = catch_sig_alarm;
140 if (sigaction(SIGALRM, &act, 0))
141 throw BESInternalFatalError(
"Could not register a handler to catch alarm/timeout.", __FILE__, __LINE__);
144 static inline void downcase(
string &s)
146 for (
unsigned int i = 0; i < s.length(); i++)
147 s[i] = tolower(s[i]);
152 string error_name =
"";
158 bool only_log_to_verbose =
false;
161 case BES_INTERNAL_FATAL_ERROR:
162 error_name =
"BES Internal Fatal Error";
165 case BES_INTERNAL_ERROR:
166 error_name =
"BES Internal Error";
169 case BES_SYNTAX_USER_ERROR:
170 error_name =
"BES User Syntax Error";
174 case BES_FORBIDDEN_ERROR:
175 error_name =
"BES Forbidden Error";
178 case BES_NOT_FOUND_ERROR:
179 error_name =
"BES Not Found Error";
184 error_name =
"BES Error";
189 LOG(
"ERROR: " << error_name <<
": " << e.
get_message() << endl);
196 if (only_log_to_verbose) {
237 static pthread_t alarm_thread;
239 static void* alarm_wait(
void * )
241 BESDEBUG(
"bes",
"Starting: " << __PRETTY_FUNCTION__ << endl);
245 sigemptyset(&sigset);
246 sigaddset(&sigset, SIGALRM);
247 sigprocmask(SIG_BLOCK, &sigset, NULL);
252 int result = sigwait(&sigset, &sig);
254 BESDEBUG(
"bes",
"Fatal error establishing timeout: " << strerror(result) << endl);
255 throw BESInternalFatalError(
string(
"Fatal error establishing timeout: ") + strerror(result), __FILE__, __LINE__);
257 else if (result == 0 && sig == SIGALRM) {
258 BESDEBUG(
"bes",
"Timeout found in " << __PRETTY_FUNCTION__ << endl);
263 oss <<
"While waiting for a timeout, found signal '" << result <<
"' in " << __PRETTY_FUNCTION__ << ends;
264 BESDEBUG(
"bes", oss.str() << endl);
269 static void wait_for_timeout()
271 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
273 pthread_attr_t thread_attr;
275 if (pthread_attr_init(&thread_attr) != 0)
277 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED ) != 0)
278 throw BESInternalFatalError(
"Failed to complete pthread attribute initialization.", __FILE__, __LINE__);
280 int status = pthread_create(&alarm_thread, &thread_attr, alarm_wait, NULL);
286 BESInterface::BESInterface(ostream *output_stream) :
287 d_strm(output_stream), d_timeout_from_keys(0), d_dhi_ptr(0), d_transmitter(0)
290 throw BESInternalError(
"Output stream must be set in order to output responses", __FILE__, __LINE__);
298 string timeout_key_value;
301 istringstream iss(timeout_key_value);
302 iss >> d_timeout_from_keys;
306 register_signal_handler();
314 extern BESStopWatch *bes_timing::elapsedTimeToReadStart;
315 extern BESStopWatch *bes_timing::elapsedTimeToTransmitStart;
331 string context = BESContextManager::TheManager()->
get_context(
"errors", found);
333 if (found && context == XML_ERRORS)
336 dhi.
error_info = BESInfoList::TheList()->build_info();
341 dhi.
error_info = BESInfoList::TheList()->build_info();
346 string admin_email =
"";
349 admin_email = sd.get_email();
352 admin_email =
"support@opendap.org";
354 if (admin_email.empty()) {
355 admin_email =
"support@opendap.org";
376 string context = BESContextManager::TheManager()->
get_context(
"errors", found);
377 if (context ==
"dap2" || context ==
"dap") {
378 libdap::ErrorCode ec = unknown_error;
381 ec = de->get_error_code();
397 s <<
"libdap exception building response: error_code = " << de->get_error_code() <<
": "
448 BESDEBUG(
"bes",
"Entering: " << __PRETTY_FUNCTION__ << endl);
451 throw BESInternalError(
"DataHandlerInterface can not be null", __FILE__, __LINE__);
455 if (BESISDEBUG(TIMING_LOG)) {
461 bes_timing::elapsedTimeToReadStart =
new BESStopWatch();
462 bes_timing::elapsedTimeToReadStart->
start(
"TIME_TO_READ_START",
d_dhi_ptr->
data[REQUEST_ID]);
464 bes_timing::elapsedTimeToTransmitStart =
new BESStopWatch();
465 bes_timing::elapsedTimeToTransmitStart->
start(
"TIME_TO_TRANSMIT_START",
d_dhi_ptr->
data[REQUEST_ID]);
488 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
" request received" << endl);
493 d_transmitter = BESReturnManager::TheManager()->find_transmitter(BASIC_TRANSMITTER);
495 throw BESInternalError(
string(
"Unable to find transmitter '") + BASIC_TRANSMITTER +
"'", __FILE__, __LINE__);
497 build_data_request_plan();
506 if (setjmp(timeout_jump) == 0) {
507 timeout_jump_valid =
true;
511 string context = BESContextManager::TheManager()->
get_context(
"bes_timeout", found);
513 bes_timeout = strtol(context.c_str(), NULL, 10);
514 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << bes_timeout <<
" seconds (from context)." << endl);
517 else if (d_timeout_from_keys != 0) {
518 bes_timeout = d_timeout_from_keys;
519 VERBOSE(
d_dhi_ptr->
data[REQUEST_FROM] <<
"Set request timeout to " << bes_timeout <<
" seconds (from keys)." << endl);
523 execute_data_request_plan();
526 if (bes_timeout != 0) {
532 timeout_jump_valid =
false;
536 oss <<
"BES listener timeout after " << bes_timeout <<
" seconds." << ends;
542 catch (libdap::Error &e) {
543 timeout_jump_valid =
false;
544 BESInternalFatalError ex(
string(
"BES caught a libdap exception: ") + e.get_error_message(), __FILE__, __LINE__);
548 timeout_jump_valid =
false;
558 status = BESDapError::TheDapHandler()->handleBESError(ex, *
d_dhi_ptr);
560 status = BESDapError::handleException(ex, *
d_dhi_ptr);
564 catch (bad_alloc &e) {
565 timeout_jump_valid =
false;
569 catch (exception &e) {
570 timeout_jump_valid =
false;
575 timeout_jump_valid =
false;
576 BESInternalError ex(
"An unidentified exception has been thrown", __FILE__, __LINE__);
581 delete bes_timing::elapsedTimeToReadStart;
582 bes_timing::elapsedTimeToReadStart = 0;
584 delete bes_timing::elapsedTimeToTransmitStart;
585 bes_timing::elapsedTimeToTransmitStart = 0;
603 BESInternalError ex(
"Finish_with_error called with no error object", __FILE__, __LINE__);
604 status = exception_manager(ex);
622 LOG(
"Problem logging status or running end of request cleanup: " << ex.
get_message() << endl);
625 LOG(
"Unknown problem logging status or running end of request cleanup" << endl);
660 int BESInterface::exception_manager(
BESError &e)
662 return BESExceptionManager::TheEHM()->handle_exception(e, *
d_dhi_ptr);
676 strm << BESIndent::LMarg <<
"BESInterface::dump - (" << (
void *)
this <<
")" << endl;
679 strm << BESIndent::LMarg <<
"data handler interface:" << endl;
682 BESIndent::UnIndent();
685 strm << BESIndent::LMarg <<
"transmitter:" << endl;
688 BESIndent::UnIndent();
691 strm << BESIndent::LMarg <<
"transmitter: not set" << endl;
694 BESIndent::UnIndent();