bes  Updated for version 3.20.13
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 "DebugFunctions.h"
39 
40 #include <libdap/ServerFunctionsList.h>
41 #include <libdap/Int32.h>
42 #include <libdap/Structure.h>
43 #include <libdap/Str.h>
44 
45 #include <BESDebug.h>
46 #include <BESError.h>
47 #include <BESInternalError.h>
48 #include <BESInternalFatalError.h>
49 #include <BESSyntaxUserError.h>
50 #include <BESForbiddenError.h>
51 #include <BESNotFoundError.h>
52 #include <BESTimeoutError.h>
53 
54 namespace debug_function {
55 
56 static string getFunctionNames()
57 {
58  vector<string> names;
59  libdap::ServerFunctionsList::TheList()->getFunctionNames(&names);
60 
61  string msg;
62  for (std::vector<string>::iterator it = names.begin(); it != names.end(); ++it) {
63  if (!msg.empty()) msg += ", ";
64 
65  msg += *it;
66  }
67 
68  return msg;
69 }
70 
71 void DebugFunctions::initialize(const string &/*modname*/)
72 {
73  BESDEBUG("DebugFunctions", "initialize() - BEGIN" << std::endl);
74  BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);
75 
77  libdap::ServerFunctionsList::TheList()->add_function(abortFunc);
78 
80  libdap::ServerFunctionsList::TheList()->add_function(sleepFunc);
81 
83  libdap::ServerFunctionsList::TheList()->add_function(sumUntilFunc);
84 
86  libdap::ServerFunctionsList::TheList()->add_function(errorFunc);
87 
88  BESDEBUG("DebugFunctions", "initialize() - function names: " << getFunctionNames() << std::endl);
89 
90  BESDEBUG("DebugFunctions", "initialize() - END" << std::endl);
91 }
92 
93 void DebugFunctions::terminate(const string &/*modname*/)
94 {
95  BESDEBUG("DebugFunctions", "Removing DebugFunctions Modules (this does nothing)." << std::endl);
96 }
97 
104 void DebugFunctions::dump(ostream &strm) const
105 {
106  strm << BESIndent::LMarg << "DebugFunctions::dump - (" << (void *) this << ")" << std::endl;
107 }
108 
109 /*****************************************************************************************
110  *
111  * Abort Function (Debug Functions)
112  *
113  * This server side function calls abort(). (boom)
114  *
115  */
116 string abort_usage = "abort(##) Where ## is the number of milliseconds to sleep before calling abort.";
117 AbortFunc::AbortFunc()
118 {
119  setName("abort");
120  setDescriptionString((string) "This function calls abort() killing the beslistner process.");
121  setUsageString(abort_usage);
122  setRole("http://services.opendap.org/dap4/server-side-function/debug/abort"); // 11/18/20 SBL - https not supported
123  setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
124  setFunction(debug_function::abort_ssf);
125  setVersion("1.0");
126 }
127 
128 void abort_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
129 {
130 
131  std::stringstream msg;
132  libdap::Str *response = new libdap::Str("info");
133  *btpp = response;
134 
135  if (argc != 1) {
136  msg << "Missing time parameter! USAGE: " << abort_usage;
137  }
138  else {
139  libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
140  if (param1) {
141  libdap::dods_int32 milliseconds = param1->value();
142 
143  msg << "abort in " << milliseconds << "ms" << endl;
144  response->set_value(msg.str());
145 
146  usleep(milliseconds * 1000);
147  msg << "abort now. " << endl;
148  abort();
149  return;
150  }
151  else {
152  msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
153  << abort_usage;
154  }
155 
156  }
157 
158  response->set_value(msg.str());
159  return;
160 }
161 
162 /*****************************************************************************************
163  *
164  * Sleep Function (Debug Functions)
165  *
166  * This server side function calls sleep() for the number
167  * of millisecs passed in at argv[0]. (Zzzzzzzzzzzzzzz)
168  *
169  */
170 
171 string sleep_usage = "sleep(##) where ## is the number of milliseconds to sleep.";
172 SleepFunc::SleepFunc()
173 {
174  setName("sleep");
175  setDescriptionString((string) "This function calls sleep() for the specified number of millisecs.");
176  setUsageString(sleep_usage);
177  setRole("http://services.opendap.org/dap4/server-side-function/debug/sleep"); // 11/18/20 SBL - https not supported
178  setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
179  setFunction(debug_function::sleep_ssf);
180  setVersion("1.0");
181 }
182 
183 void sleep_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
184 {
185 
186  std::stringstream msg;
187  libdap::Str *sleep_info = new libdap::Str("info");
188 
189  //libdap::Structure *sleepResult = new libdap::Structure("sleep_result_unwrap");
190  //sleepResult->add_var_nocopy(sleep_info);
191  //*btpp = sleepResult;
192 
193  *btpp = sleep_info;
194 
195  if (argc != 1) {
196  msg << "Missing time parameter! USAGE: " << sleep_usage;
197  }
198  else {
199  libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
200  if (param1) {
201  libdap::dods_int32 milliseconds = param1->value();
202  usleep(milliseconds * 1000);
203  msg << "Slept for " << milliseconds << " ms.";
204  }
205  else {
206  msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
207  << sleep_usage;
208  }
209 
210  }
211 
212  sleep_info->set_value(msg.str());
213 
214  /*
215  for (libdap::DDS::Vars_iter it = dds.var_begin(); it != dds.var_end(); ++it) {
216  libdap::BaseType *pBT = *it;
217  sleepResult->add_var(pBT);
218  }
219  */
220 
221  return;
222 }
223 
224 /*****************************************************************************************
225  *
226  * SumUntil (Debug Functions)
227  *
228  * This server side function computes a sum until the number of
229  * millisecs (passed in at argv[0]) has transpired. (+,+...+).
230  *
231  * @note Modified so that the actual sum value can be printed or not.
232  * When this is used in tests, the value reached can vary, so to make
233  * checking for success/failure, the value can be omitted.
234  *
235  */
236 
237 string sum_until_usage = "sum_until(<val> [,0|<true>]) Compute a sum until <val> of milliseconds has elapsed; 0|<true> print the sum value.";
238 SumUntilFunc::SumUntilFunc()
239 {
240  setName("sum_until");
241  setDescriptionString((string) "This function calls sleep() for the specified number of millisecs.");
242  setUsageString(sum_until_usage);
243  setRole("http://services.opendap.org/dap4/server-side-function/debug/sum_until"); // 11/18/20 SBL - https not supported
244  setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
245  setFunction(debug_function::sum_until_ssf);
246  setVersion("1.0");
247 }
248 
249 void sum_until_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
250 {
251 
252  std::stringstream msg;
253  libdap::Str *response = new libdap::Str("info");
254  *btpp = response;
255 
256  if (!(argc == 1 || argc == 2)) {
257  msg << "Missing time parameter! USAGE: " << sum_until_usage;
258 
259  response->set_value(msg.str());
260  return;
261  }
262 
263  libdap::Int32 *param1 = dynamic_cast<libdap::Int32*>(argv[0]);
264  // param1 is required
265  if (!param1) {
266  msg << "This function only accepts integer values " << "for the time (in milliseconds) parameter. USAGE: "
267  << sum_until_usage;
268 
269  response->set_value(msg.str());
270  return;
271  }
272 
273  bool print_sum_value = true;
274  // argument #2 is optional
275  if (argc == 2) {
276  libdap::Int32 *temp = dynamic_cast<libdap::Int32*>(argv[1]);
277  if (temp && temp->value() == 0)
278  print_sum_value = false;
279  }
280 
281  libdap::dods_int32 milliseconds = param1->value();
282 
283  struct timeval tv;
284  gettimeofday(&tv, NULL);
285  double start_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; // convert tv_sec & tv_usec to millisecond
286  double end_time = start_time;
287 
288  long fib;
289  long one_past = 1;
290  long two_past = 0;
291  long n = 1;
292 
293  bool done = false;
294  while (!done) {
295  n++;
296  fib = one_past + two_past;
297  two_past = one_past;
298  one_past = fib;
299  gettimeofday(&tv, NULL);
300  end_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000; // convert tv_sec & tv_usec to millisecond
301  if (end_time - start_time >= milliseconds) {
302  done = true;
303  }
304  }
305 
306  if (!print_sum_value)
307  msg << "Summed for " << end_time - start_time << " ms.";
308  else
309  msg << "Summed for " << end_time - start_time << " ms. n: " << n;
310 
311  response->set_value(msg.str());
312  return;
313 }
314 
315 /*****************************************************************************************
316  *
317  * Error Function (Debug Functions)
318  *
319  * This server side function calls calls sleep() for the number
320  * of ms passed in at argv[0]. (Zzzzzzzzzzzzzzz)
321  *
322  */
323 string error_usage = "error(##) where ## is the BESError type to generate.";
324 ErrorFunc::ErrorFunc()
325 {
326  setName("error");
327  setDescriptionString((string) "This function triggers a BES Error of the type specified");
328  setUsageString(error_usage);
329  setRole("http://services.opendap.org/dap4/server-side-function/debug/error"); // 11/18/20 SBL - https not supported
330  setDocUrl("https://docs.opendap.org/index.php/Debug_Functions");
331  setFunction(debug_function::error_ssf);
332  setVersion("1.0");
333 }
334 
335 void error_ssf(int argc, libdap::BaseType * argv[], libdap::DDS &, libdap::BaseType **btpp)
336 {
337  std::stringstream msg;
338  auto *response = new libdap::Str("info");
339  *btpp = response;
340 
341  string location = "error_ssf";
342 
343  if (argc != 1) {
344  msg << "Missing error type parameter! USAGE: " << error_usage;
345  }
346  else {
347  auto param1 = dynamic_cast<const libdap::Int32*>(argv[0]);
348  if (param1) {
349  libdap::dods_int32 error_type = param1->value();
350 
351  switch (error_type) {
352 
353  case BES_INTERNAL_ERROR: { // 1
354  msg << "A BESInternalError was requested.";
355  throw BESInternalError(msg.str(), location, 0);
356  }
357 
358  case BES_INTERNAL_FATAL_ERROR: { // 2
359  msg << "A BESInternalFatalError was requested.";
360  throw BESInternalFatalError(msg.str(), location, 0);
361  }
362 
363  case BES_SYNTAX_USER_ERROR: { // ...
364  msg << "A BESSyntaxUserError was requested.";
365  throw BESSyntaxUserError(msg.str(), location, 0);
366  }
367 
368  case BES_FORBIDDEN_ERROR: {
369  msg << "A BESForbiddenError was requested.";
370  throw BESForbiddenError(msg.str(), location, 0);
371  }
372 
373  case BES_NOT_FOUND_ERROR: {
374  msg << "A BESNotFoundError was requested.";
375  throw BESNotFoundError(msg.str(), location, 0);
376  }
377 
378  case BES_TIMEOUT_ERROR: { // 6
379  msg << "A BESTimeOutError was requested.";
380  throw BESTimeoutError(msg.str(), location, 0);
381  }
382 
383  case 666: {
384  msg << "A Segmentation Fault has been requested.";
385  cerr << msg.str() << endl;
386  raise(SIGSEGV);
387  break;
388  }
389 
390  case 314: {
391  msg << "A PIPE signal has been requested.";
392  cerr << msg.str() << endl;
393  raise(SIGPIPE);
394  break;
395  }
396 
397  case 11: {
398  throw std::bad_alloc(); // does not take a 'what()' value. jhrg 3/23/22
399  }
400 
401  default:
402  msg << "An unrecognized error_type parameter was received. Requested error_type: " << error_type;
403  break;
404  }
405 
406  }
407  else {
408  msg << "This function only accepts integer values " << "for the error type parameter. USAGE: "
409  << error_usage;
410  }
411 
412  }
413 
414  response->set_value(msg.str());
415 }
416 
417 } // namespace debug_function
418 
419 extern "C" {
420 BESAbstractModule *maker()
421 {
423 }
424 }
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
error thrown if the resource requested cannot be found
error thrown if there is a user syntax error in the request or any other user error
error thrown if there is a user syntax error in the request or any other user error
virtual void dump(ostream &strm) const
dumps information about this object