bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
DebugFunctions.cc
1// UgridFunctions.cc
2
3// This file is part of bes, A C++ back-end server implementation framework
4// for the OPeNDAP Data Access Protocol.
5
6// Copyright (c) 2013 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <sstream> // std::stringstream
28#include <iostream>
29#include <stdexcept>
30
31#include <csignal>
32#include <cstdlib> /* abort, NULL */
33#include <ctime>
34#include <unistd.h>
35
36#include <sys/time.h>
37
38#include <curl/curl.h>
39#include <curl/easy.h>
40
41
42#include "DebugFunctions.h"
43
44#include <libdap/ServerFunctionsList.h>
45#include <libdap/Int32.h>
46#include <libdap/Structure.h>
47#include <libdap/Str.h>
48
49#include <BESDebug.h>
50#include <BESError.h>
51#include <BESInternalError.h>
52#include <BESInternalFatalError.h>
53#include <BESSyntaxUserError.h>
54#include <BESForbiddenError.h>
55#include <BESNotFoundError.h>
56#include <BESTimeoutError.h>
57#include <HttpError.h>
58
59namespace debug_function {
60
61static string getFunctionNames()
62{
63 vector<string> names;
64 libdap::ServerFunctionsList::TheList()->getFunctionNames(&names);
65
66 string msg;
67 for (std::vector<string>::iterator it = names.begin(); it != names.end(); ++it) {
68 if (!msg.empty()) msg += ", ";
69
70 msg += *it;
71 }
72
73 return msg;
74}
75
76void DebugFunctions::initialize(const string &/*modname*/)
77{
78 BESDEBUG("DebugFunctions", "initialize() - BEGIN" << std::endl);
79 BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);
80
81 debug_function::AbortFunc *abortFunc = new debug_function::AbortFunc();
82 libdap::ServerFunctionsList::TheList()->add_function(abortFunc);
83
84 debug_function::SleepFunc *sleepFunc = new debug_function::SleepFunc();
85 libdap::ServerFunctionsList::TheList()->add_function(sleepFunc);
86
87 debug_function::SumUntilFunc *sumUntilFunc = new debug_function::SumUntilFunc();
88 libdap::ServerFunctionsList::TheList()->add_function(sumUntilFunc);
89
90 debug_function::ErrorFunc *errorFunc = new debug_function::ErrorFunc();
91 libdap::ServerFunctionsList::TheList()->add_function(errorFunc);
92
93 BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);
94
95 BESDEBUG("DebugFunctions", "initialize() - END" << std::endl);
96}
97
98void DebugFunctions::terminate(const string &/*modname*/)
99{
100 BESDEBUG("DebugFunctions", "Removing DebugFunctions Modules (this does nothing)." << std::endl);
101}
102
110{
111 strm << BESIndent::LMarg << "DebugFunctions::dump - (" << (void *) this << ")" << std::endl;
112}
113
114/*****************************************************************************************
115 *
116 * Abort Function (Debug Functions)
117 *
118 * This server side function calls abort(). (boom)
119 *
120 */
121string abort_usage = "abort(##) Where ## is the number of milliseconds to sleep before calling abort.";
122AbortFunc::AbortFunc()
123{
124 setName("abort");
125 setDescriptionString((string) "This function calls abort() killing the beslistner process.");
126 setUsageString(abort_usage);
127 setRole("http://services.opendap.org/dap4/server-side-function/debug/abort"); // 11/18/20 SBL - https not supported
128 setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
129 setFunction(debug_function::abort_ssf);
130 setVersion("1.0");
131}
132
133void abort_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
134{
135
136 std::stringstream msg;
137 libdap::Str *response = new libdap::Str("info");
138 *btpp = response;
139
140 if (argc != 1) {
141 msg << "Missing time parameter! USAGE: " << abort_usage;
142 }
143 else {
144 libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
145 if (param1) {
146 libdap::dods_int32 milliseconds = param1->value();
147
148 msg << "abort in " << milliseconds << "ms" << endl;
149 response->set_value(msg.str());
150
151 usleep(milliseconds * 1000);
152 msg << "abort now. " << endl;
153 abort();
154 return;
155 }
156 else {
157 msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
158 << abort_usage;
159 }
160
161 }
162
163 response->set_value(msg.str());
164 return;
165}
166
167/*****************************************************************************************
168 *
169 * Sleep Function (Debug Functions)
170 *
171 * This server side function calls sleep() for the number
172 * of millisecs passed in at argv[0]. (Zzzzzzzzzzzzzzz)
173 *
174 */
175
176string sleep_usage = "sleep(##) where ## is the number of milliseconds to sleep.";
177SleepFunc::SleepFunc()
178{
179 setName("sleep");
180 setDescriptionString((string) "This function calls sleep() for the specified number of millisecs.");
181 setUsageString(sleep_usage);
182 setRole("http://services.opendap.org/dap4/server-side-function/debug/sleep"); // 11/18/20 SBL - https not supported
183 setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
184 setFunction(debug_function::sleep_ssf);
185 setVersion("1.0");
186}
187
188void sleep_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
189{
190
191 std::stringstream msg;
192 libdap::Str *sleep_info = new libdap::Str("info");
193
194 //libdap::Structure *sleepResult = new libdap::Structure("sleep_result_unwrap");
195 //sleepResult->add_var_nocopy(sleep_info);
196 //*btpp = sleepResult;
197
198 *btpp = sleep_info;
199
200 if (argc != 1) {
201 msg << "Missing time parameter! USAGE: " << sleep_usage;
202 }
203 else {
204 libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
205 if (param1) {
206 libdap::dods_int32 milliseconds = param1->value();
207 usleep(milliseconds * 1000);
208 msg << "Slept for " << milliseconds << " ms.";
209 }
210 else {
211 msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
212 << sleep_usage;
213 }
214
215 }
216
217 sleep_info->set_value(msg.str());
218
219 /*
220 for (libdap::DDS::Vars_iter it = dds.var_begin(); it != dds.var_end(); ++it) {
221 libdap::BaseType *pBT = *it;
222 sleepResult->add_var(pBT);
223 }
224 */
225
226 return;
227}
228
229/*****************************************************************************************
230 *
231 * SumUntil (Debug Functions)
232 *
233 * This server side function computes a sum until the number of
234 * millisecs (passed in at argv[0]) has transpired. (+,+...+).
235 *
236 * @note Modified so that the actual sum value can be printed or not.
237 * When this is used in tests, the value reached can vary, so to make
238 * checking for success/failure, the value can be omitted.
239 *
240 */
241
242string sum_until_usage = "sum_until(<val> [,0|<true>]) Compute a sum until <val> of milliseconds has elapsed; 0|<true> print the sum value.";
243SumUntilFunc::SumUntilFunc()
244{
245 setName("sum_until");
246 setDescriptionString((string) "This function calls sleep() for the specified number of millisecs.");
247 setUsageString(sum_until_usage);
248 setRole("http://services.opendap.org/dap4/server-side-function/debug/sum_until"); // 11/18/20 SBL - https not supported
249 setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
250 setFunction(debug_function::sum_until_ssf);
251 setVersion("1.0");
252}
253
254void sum_until_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
255{
256
257 std::stringstream msg;
258 libdap::Str *response = new libdap::Str("info");
259 *btpp = response;
260
261 if (!(argc == 1 || argc == 2)) {
262 msg << "Missing time parameter! USAGE: " << sum_until_usage;
263
264 response->set_value(msg.str());
265 return;
266 }
267
268 libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
269 // param1 is required
270 if (!param1) {
271 msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
272 << sum_until_usage;
273
274 response->set_value(msg.str());
275 return;
276 }
277
278 bool print_sum_value = true;
279 // argument #2 is optional
280 if (argc == 2) {
281 libdap::Int32 *temp = dynamic_cast<libdap::Int32*>(argv[1]);
282 if (temp && temp->value() == 0)
283 print_sum_value = false;
284 }
285
286 libdap::dods_int32 milliseconds = param1->value();
287
288 struct timeval tv;
289 gettimeofday(&tv, NULL);
290 double start_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; // convert tv_sec & tv_usec to millisecond
291 double end_time = start_time;
292
293 uint64_t fib;
294 uint64_t one_past = 1;
295 uint64_t two_past = 0;
296 uint64_t n = 1;
297
298 bool done = false;
299 while (!done) {
300 n++;
301 fib = one_past + two_past;
302 two_past = one_past;
303 one_past = fib;
304 gettimeofday(&tv, NULL);
305 end_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; // convert tv_sec & tv_usec to millisecond
306 if (end_time - start_time >= milliseconds) {
307 done = true;
308 }
309 }
310
311 if (!print_sum_value)
312 msg << "Summed for " << end_time - start_time << " ms.";
313 else
314 msg << "Summed for " << end_time - start_time << " ms. n: " << n;
315
316 response->set_value(msg.str());
317 return;
318}
319
320/*****************************************************************************************
321 *
322 * Error Function (Debug Functions)
323 *
324 * This server side function calls calls sleep() for the number
325 * of ms passed in at argv[0]. (Zzzzzzzzzzzzzzz)
326 *
327 */
328string error_usage = "error(##) where ## is the BESError type to generate.";
329ErrorFunc::ErrorFunc()
330{
331 setName("error");
332 setDescriptionString((string) "This function triggers a BES Error of the type specified");
333 setUsageString(error_usage);
334 setRole("http://services.opendap.org/dap4/server-side-function/debug/error"); // 11/18/20 SBL - https not supported
335 setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
336 setFunction(debug_function::error_ssf);
337 setVersion("1.0");
338}
339
340void error_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
341{
342 std::stringstream msg;
343 auto *response = new libdap::Str("info");
344 *btpp = response;
345
346 string location = "error_ssf";
347
348 if (argc < 1 || argc>2) {
349 msg << "Missing error type parameter(s)! USAGE: " << error_usage;
350 response->set_value(msg.str());
351 return;
352 }
353
354 auto param1 = dynamic_cast<const libdap::Int32*>(argv[0]);
355 if (!param1) {
356 msg << "This function only accepts integer values for the error type parameter(s). USAGE: "
357 << error_usage;
358 response->set_value(msg.str());
359 return;
360 }
361
362 // Optional second parameter, http status value to return for HttpError
363 const libdap::Int32 *param2=nullptr;
364 if(argc == 2){
365 param2 = dynamic_cast<const libdap::Int32 *>(argv[1]);
366 }
367
368 libdap::dods_int32 error_type = param1->value();
369 switch (error_type) {
370
371 case BES_INTERNAL_ERROR: { // 1
372 msg << "A BESInternalError was requested.";
373 throw BESInternalError(msg.str(), location, 0);
374 }
375
376 case BES_INTERNAL_FATAL_ERROR: { // 2
377 msg << "A BESInternalFatalError was requested.";
378 throw BESInternalFatalError(msg.str(), location, 0);
379 }
380
381 case BES_SYNTAX_USER_ERROR: { // ...
382 msg << "A BESSyntaxUserError was requested.";
383 throw BESSyntaxUserError(msg.str(), location, 0);
384 }
385
386 case BES_FORBIDDEN_ERROR: {
387 msg << "A BESForbiddenError was requested.";
388 throw BESForbiddenError(msg.str(), location, 0);
389 }
390
391 case BES_NOT_FOUND_ERROR: {
392 msg << "A BESNotFoundError was requested.";
393 throw BESNotFoundError(msg.str(), location, 0);
394 }
395
396 case BES_TIMEOUT_ERROR: { // 6
397 msg << "A BESTimeOutError was requested.";
398 throw BESTimeoutError(msg.str(), location, 0);
399 }
400
401 case BES_HTTP_ERROR: { // 7
402 string http_err_msg("An HttpError was requested.");
403 CURLcode curl_code = CURLE_OK;
404 unsigned int http_status;
405 if(param2) {
406 http_status = param2->value();
407 }
408 else {
409 http_status=502;
410 }
411
412 string origin_url("https://www.opendap.org");
413 string redirect_url("https://www.opendap.org/");
414 vector<string> rsp_hdrs;
415 rsp_hdrs.emplace_back("server: bes.error.functions");
416 rsp_hdrs.emplace_back("location: orbit-0");
417 string rsp_body("Every HTTP request includes an HTTP response. An HTTP response "
418 "is a set of metadata and a response body, where the body can "
419 "occasionally be zero bytes and thus nonexistent. An HTTP response "
420 "however always has response headers.");
421
422 throw http::HttpError(http_err_msg,
423 curl_code,
424 http_status,
425 origin_url,
426 redirect_url,
427 rsp_hdrs,
428 rsp_body,
429 __FILE__, __LINE__);
430 }
431
432 case 666: {
433 msg << "A Segmentation Fault has been requested.";
434 cerr << msg.str() << endl;
435 raise(SIGSEGV);
436 break;
437 }
438
439 case 314: {
440 msg << "A PIPE signal has been requested.";
441 cerr << msg.str() << endl;
442 raise(SIGPIPE);
443 break;
444 }
445
446 case 11: {
447 throw std::bad_alloc(); // does not take a 'what()' value. jhrg 3/23/22
448 }
449
450 default:
451 msg << "An unrecognized error_type parameter was received. Requested error_type: " << error_type;
452 response->set_value(msg.str());
453 break;
454 }
455
456}
457
458} // namespace debug_function
459
460extern "C" {
461BESAbstractModule *maker()
462{
464}
465}
virtual void dump(ostream &strm) const
dumps information about this object
STL class.