31 #include <sys/types.h>
32 #include <sys/socket.h>
69 void DaemonCommandHandler::load_include_files(vector<string> &files,
const string &keys_file_name)
71 vector<string>::iterator i = files.begin();
72 while (i != files.end())
73 load_include_file(*i++, keys_file_name);
85 void DaemonCommandHandler::load_include_file(
const string &files,
const string &keys_file_name)
92 if (!files.empty() && files[0] ==
'/') {
93 newdir = allfiles.getDirName();
99 string currdir = currfile.getDirName();
101 string alldir = allfiles.getDirName();
103 if ((currdir ==
"./" || currdir ==
".") && (alldir ==
"./" || alldir ==
".")) {
107 if (alldir ==
"./" || alldir ==
".") {
111 newdir = currdir +
"/" + alldir;
118 BESFSDir fsd(newdir, allfiles.getFileName());
121 for (; i != e; i++) {
122 d_pathnames.insert(make_pair((*i).getFileName(), (*i).getFullPath()));
130 string d_bes_name = d_bes_conf.substr(d_bes_conf.find_last_of(
'/') + 1);
131 d_pathnames.insert(make_pair(d_bes_name, d_bes_conf));
138 BESDEBUG(
"besdaemon",
"DaemonCommandHandler() - Found BES.Include: " << found << endl);
142 load_include_files(vals, config);
147 map<string, string>::iterator i = d_pathnames.begin();
148 while (i != d_pathnames.end()) {
150 "DaemonCommandHandler() - d_pathnames: [" << (*i).first <<
"]: " << d_pathnames[(*i).first] << endl);
158 if (!found) d_log_file_name =
"";
167 DaemonCommandHandler::hai_command DaemonCommandHandler::lookup_command(
const string &command)
169 if (command ==
"StopNow")
171 else if (command ==
"Start")
173 else if (command ==
"Exit")
175 else if (command ==
"GetConfig")
176 return HAI_GET_CONFIG;
177 else if (command ==
"SetConfig")
178 return HAI_SET_CONFIG;
179 else if (command ==
"TailLog")
181 else if (command ==
"GetLogContexts")
182 return HAI_GET_LOG_CONTEXTS;
183 else if (command ==
"SetLogContext")
184 return HAI_SET_LOG_CONTEXT;
194 static char *read_file(
const string &name)
197 ifstream::pos_type size;
199 ifstream file(name.c_str(), ios::in | ios::binary | ios::ate);
200 if (file.is_open()) {
202 memblock =
new char[((
unsigned long) size) + 1];
203 file.seekg(0, ios::beg);
204 file.read(memblock, size);
207 memblock[size] =
'\0';
212 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
225 static void write_file(
const string &name,
const string &buffer)
228 string tmp_name = name +
".tmp";
229 ofstream outfile(tmp_name.c_str(), std::ios_base::out);
230 if (outfile.is_open()) {
232 outfile.write(buffer.data(), buffer.length());
237 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
243 ostringstream backup_name;
244 backup_name << name <<
"." << getpid();
245 if (access(backup_name.str().c_str(), F_OK) == -1) {
246 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - No backup file yet" << endl);
248 if (rename(name.c_str(), backup_name.str().c_str()) == -1) {
249 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not backup file " << name <<
" to " << backup_name.str() << endl);
251 err <<
"(" << errno <<
") " << strerror(errno);
252 throw BESInternalError(
"Could not backup config file: " + name +
": " + err.str(), __FILE__, __LINE__);
257 if (rename(tmp_name.c_str(), name.c_str()) == -1) {
258 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not complete write " << name <<
" to " << backup_name.str() << endl);
260 err <<
"(" << errno <<
") " << strerror(errno);
261 throw BESInternalError(
"Could not write config file:" + name +
": " + err.str(), __FILE__, __LINE__);
279 #define BES_LOG_CHARS_EST_PER_LINE 126
281 static char *get_bes_log_lines(
const string &log_file_name,
long num_lines)
283 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
284 if (!infile.is_open())
285 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
288 static ifstream::pos_type prev_end_pos = 0;
291 ifstream::pos_type start_from_pos = 0;
297 infile.seekg(0, ios::end);
298 ifstream::pos_type end_pos = infile.tellg();
299 long est_num_lines = end_pos / BES_LOG_CHARS_EST_PER_LINE;
300 if (num_lines >= est_num_lines)
301 infile.seekg(0, ios::beg);
303 infile.seekg((est_num_lines - num_lines) * BES_LOG_CHARS_EST_PER_LINE, ios::beg);
304 ifstream::pos_type start_from_pos = infile.tellg();
306 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::get_bes_log_lines() - end_pos: " << end_pos <<
" start_from_pos: " << start_from_pos << endl);
312 while (!infile.eof() && !infile.fail())
314 infile.ignore(1024,
'\n');
322 if (count < num_lines) {
323 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::get_bes_log_lines() - Retrying; Log length (count)" << count <<
", num_lines " << num_lines << endl);
325 long size = start_from_pos;
326 size -= ((num_lines - count + 10) * BES_LOG_CHARS_EST_PER_LINE);
327 infile.seekg(size, ios::beg);
328 start_from_pos = infile.tellg();
332 infile.seekg(start_from_pos, ios::beg);
334 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::get_bes_log_lines() - Log length (count)" << count << endl);
336 if (count > num_lines)
339 long skip = count - num_lines;
340 while (skip > 0 && !infile.eof() && !infile.fail())
342 infile.ignore(1024,
'\n');
351 ifstream::pos_type start_pos = infile.tellg();
352 infile.seekg(0, ios::end);
353 ifstream::pos_type end_pos = infile.tellg();
355 unsigned long size = end_pos - start_pos;
356 char *memblock =
new char[size + 1];
358 infile.seekg(start_pos, ios::beg);
359 infile.read(memblock, size);
362 memblock[size] =
'\0';
376 static char *get_bes_log_lines(
const string &log_file_name,
long num_lines)
378 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
379 if (!infile.is_open())
380 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
383 static ifstream::pos_type prev_end_pos = 0;
384 static long prev_line_count = 0;
386 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::get_bes_log_lines() - prev_line_count: " << prev_line_count << endl);
391 infile.seekg(prev_end_pos, ios::beg);
392 long count = prev_line_count;
393 while (!infile.eof() && !infile.fail())
395 infile.ignore(1024,
'\n');
401 prev_end_pos = infile.tellg();
402 prev_line_count = count - 1;
404 infile.seekg(0, ios::beg);
406 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::get_bes_log_lines() - Log length " << count << endl);
408 if (count > num_lines)
411 long skip = count - num_lines;
414 infile.ignore(1024,
'\n');
416 }
while (skip > 0 && !infile.eof() && !infile.fail());
423 ifstream::pos_type start_pos = infile.tellg();
424 infile.seekg(0, ios::end);
425 ifstream::pos_type end_pos = infile.tellg();
427 unsigned long size = end_pos - start_pos;
428 char *memblock =
new char[size + 1];
430 infile.seekg(start_pos, ios::beg);
431 infile.read(memblock, size);
434 memblock[size] =
'\0';
444 static unsigned long move_forward_lines(ifstream &infile,
unsigned long lines)
446 unsigned long count = 0;
447 while (count < lines && !infile.eof() && !infile.fail()) {
448 infile.ignore(1024,
'\n');
458 static unsigned long count_lines(ifstream &infile, ifstream::pos_type pos)
460 infile.seekg(pos, ios::beg);
461 unsigned long count = 0;
462 while (!infile.eof() && !infile.fail()) {
463 infile.ignore(1024,
'\n');
474 static char *read_file_data(ifstream &infile)
477 ifstream::pos_type start_pos = infile.tellg();
478 infile.seekg(0, ios::end);
479 ifstream::pos_type end_pos = infile.tellg();
481 unsigned long size = (end_pos > start_pos) ? end_pos - start_pos : 0;
482 char *memblock =
new char[size + 1];
484 infile.seekg(start_pos, ios::beg);
485 infile.read(memblock, size);
488 memblock[size] =
'\0';
494 static ifstream::pos_type last_start_pos = 0;
495 static unsigned long last_start_line = 0;
504 static char *get_bes_log_lines(
const string &log_file_name,
unsigned long num_lines)
506 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
507 if (!infile.is_open())
508 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
511 static ifstream::pos_type last_start_pos = 0;
512 static unsigned long last_start_line = 0;
514 BESDEBUG(
"besdaemon",
"besdaemon: last_start_line " << last_start_line << endl);
515 if (num_lines == 0) {
517 infile.seekg(0, ios::beg);
518 return read_file_data(infile);
522 unsigned long count = count_lines(infile, last_start_pos) + last_start_line;
523 BESDEBUG(
"besdaemon",
"besdaemon: Log length " << count <<
" (started at " << last_start_line <<
")" << endl);
526 unsigned long new_start_line = (count >= num_lines) ? count - num_lines + 1 : 0;
528 infile.seekg(last_start_pos, ios::beg);
530 count = move_forward_lines(infile, new_start_line - last_start_line);
531 BESDEBUG(
"besdaemon",
"besdaemon: count forward " << count <<
" lines." << endl);
533 last_start_line = new_start_line;
534 last_start_pos = infile.tellg();
536 return read_file_data(infile);
547 void DaemonCommandHandler::execute_command(
const string &command,
BESXMLWriter &writer)
550 xmlNode *root_element = NULL;
551 xmlNode *current_node = NULL;
555 vector<string> parseerrors;
560 doc = xmlParseDoc((
const xmlChar*) command.c_str());
562 doc = xmlParseDoc((xmlChar*) command.c_str());
567 vector<string>::const_iterator i = parseerrors.begin();
568 vector<string>::const_iterator e = parseerrors.end();
569 for (; i != e; i++) {
570 if (!isfirst && (*i).compare(0, 6,
"Entity") == 0) {
581 root_element = xmlDocGetRootElement(doc);
583 throw BESSyntaxUserError(
"There is no root element in the xml document", __FILE__, __LINE__);
588 map<string, string> props;
590 if (root_name !=
"BesAdminCmd") {
591 string err = (string)
"The root element should be a BesAdminCmd element, name is "
592 + (
char *) root_element->name;
595 if (root_val !=
"") {
596 string err = (string)
"The BesAdminCmd element must not contain a value, " + root_val;
602 current_node = root_element->children;
604 while (current_node) {
605 if (current_node->type == XML_ELEMENT_NODE) {
606 string node_name = (
char *) current_node->name;
607 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Looking for command " << node_name << endl);
615 switch (lookup_command(node_name)) {
617 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received StopNow" << endl);
625 "Received Stop command but the master beslistener was likely already stopped",
630 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
632 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
638 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Start" << endl);
643 throw BESSyntaxUserError(
"Received Start command but the master beslistener is already running",
649 "DaemonCommandHandler::execute_command() - Error starting; master_beslistener_status = " <<
master_beslistener_status << endl);
652 "Received Start command but the master beslistener is already running", __FILE__,
666 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
668 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
675 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Exit" << endl);
681 case HAI_GET_CONFIG: {
682 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetConfig" << endl);
684 if (d_pathnames.empty()) {
691 map<string, string>::iterator i = d_pathnames.begin();
692 while (i != d_pathnames.end()) {
694 "DaemonCommandHandler::execute_command() - Retrieving " << (*i).first <<
": " << d_pathnames[(*i).first] << endl);
696 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BesConfig") < 0)
699 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"module",
700 (
const xmlChar*) (*i).first.c_str()) < 0)
703 char *content = read_file(d_pathnames[(*i).first]);
705 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - content: " << content << endl);
706 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)
"\n") < 0)
709 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*) content) < 0)
721 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
729 case HAI_SET_CONFIG: {
730 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig" << endl);
731 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"module");
732 if (!xml_char_module) {
735 string module = (
const char *) xml_char_module;
736 xmlFree(xml_char_module);
738 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig; module: " << module << endl);
740 xmlChar *file_content = xmlNodeListGetString(doc, current_node->children,
true);
744 string content = (
const char *) file_content;
745 xmlFree(file_content);
747 "DaemonCommandHandler::execute_command() - Received SetConfig; content: " << endl << content << endl);
749 write_file(d_pathnames[module], content);
751 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
754 if (xmlTextWriterWriteString(writer.
get_writer(),
755 (
const xmlChar*)
"\nPlease restart the server for these changes to take affect.\n") < 0)
758 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
765 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received TailLog" << endl);
767 xmlChar *xml_char_lines = xmlGetProp(current_node, (
const xmlChar*)
"lines");
768 if (!xml_char_lines) {
773 long num_lines = strtol((
const char *) xml_char_lines, &endptr, 10 );
774 if (num_lines == 0 && endptr == (
const char *) xml_char_lines) {
776 err <<
"(" << errno <<
") " << strerror(errno);
777 throw BESSyntaxUserError(
"TailLog lines attribute bad value: " + err.str(), __FILE__, __LINE__);
780 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BesLog") < 0)
784 "DaemonCommandHandler::execute_command() - TailLog: log file:" << d_log_file_name <<
", lines: " << num_lines << endl);
786 char *content = get_bes_log_lines(d_log_file_name, num_lines);
788 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - Returned lines: " << content << endl);
789 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)
"\n") < 0)
792 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*) content) < 0)
804 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
810 case HAI_GET_LOG_CONTEXTS: {
811 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetLogContexts" << endl);
814 "DaemonCommandHandler::execute_command() - There are " <<
BESDebug::debug_map().size() <<
" Contexts" << endl);
818 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:LogContext") < 0)
822 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"name",
823 (
const xmlChar*) (*i).first.c_str()) < 0)
826 string state = (*i).second ?
"on" :
"off";
827 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"state",
828 (
const xmlChar*) state.c_str()) < 0)
831 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
842 case HAI_SET_LOG_CONTEXT: {
843 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetLogContext" << endl);
845 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"name");
846 if (!xml_char_module) {
849 string name = (
const char *) xml_char_module;
850 xmlFree(xml_char_module);
852 xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"state");
853 if (!xml_char_module) {
856 bool state = strcmp((
const char *) xml_char_module,
"on") == 0;
857 xmlFree(xml_char_module);
859 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Before setting " << name <<
" to " << state << endl);
869 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - After setting " << name <<
" to " << state << endl);
871 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
873 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
886 current_node = current_node->next;
903 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BESError") < 0)
908 if (xmlTextWriterWriteElement(writer.
get_writer(), (
const xmlChar*)
"hai:Type", (
const xmlChar*) oss.str().c_str())
911 if (xmlTextWriterWriteElement(writer.
get_writer(), (
const xmlChar*)
"hai:Message",
915 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
934 string from = strm.str();
936 map<string, string> extensions;
941 done = c->
receive(extensions, &ss);
943 if (extensions[
"status"] == c->
exit()) {
947 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Received PPT_EXIT_NOW in an extension chunk." << endl);
955 std::streambuf *holder;
956 holder = cout.rdbuf();
962 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - cmd: " << ss.str() << endl);
964 execute_command(ss.str(), writer);
965 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Transmitting response." << endl);
967 cout << writer.
get_doc() << endl;
978 map<string, string> extensions;
979 extensions[
"status"] =
"error";
984 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Internal/Fatal ERROR: " << e.
get_message() << endl);
985 extensions[
"exit"] =
"true";
987 send_bes_error(writer, e);
992 cout << writer.
get_doc() << endl;
1001 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Syntax ERROR: " << e.
get_message() << endl);
1004 send_bes_error(writer, e);
1008 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - ERROR (unknown command): " << ss.str() << endl);
1009 extensions[
"exit"] =
"true";
1012 send_bes_error(writer, e);
1017 cout << writer.
get_doc() << endl;
1027 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Closing client connection." << endl);
1029 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Client connection has been closed." << endl);
1031 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Command Processing completed. " << endl);
1043 strm <<
BESIndent::LMarg <<
"DaemonCommandHandler::dump - (" << (
void *)
this <<
")" << endl;
#define BES_SYNTAX_USER_ERROR
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
virtual void dump(ostream &strm) const
dumps information about this object
static void Set(const string &flagName, bool value)
set the debug context to the specified value
#define BESLISTENER_RUNNING
#define BES_INTERNAL_ERROR
static void GetNodeInfo(xmlNode *node, string &name, string &value, map< string, string > &props)
get the name, value if any, and any properties for the specified node
static const DebugMap & debug_map()
int start_master_beslistener()
Start the 'master beslistener' and return its PID.
virtual void sendExtensions(map< string, string > &extensions)=0
virtual void closeConnection()=0
int master_beslistener_status
error thrown if there is a user syntax error in the request or any other user error ...
bool stop_all_beslisteners(int)
Stop all of the listeners (both the master listener and all of the child listeners that actually proc...
virtual int get_error_type()
Return the return code for this error class.
virtual string get_message()
get the error message for this exception
static void XMLErrorFunc(void *context, const char *msg,...)
error function used by libxml2 to report errors
Abstract exception class for the BES with basic string message.
virtual unsigned int getSendChunkSize()=0
static ostream & LMarg(ostream &strm)
#define BES_INTERNAL_FATAL_ERROR
DebugMap::const_iterator debug_citer
static bool IsSet(const string &flagName)
see if the debug context flagName is set to true
xmlTextWriterPtr get_writer()
list< BESFSFile >::iterator fileIterator
virtual int getSocketDescriptor()
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
virtual void handle(Connection *c)
This particular handle() method is special because it will accept only a single command transmission ...
DaemonCommandHandler(const string &config)
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
void get_values(const string &s, vector< string > &vals, bool &found)
Retrieve the values of a given key, if set.
virtual Socket * getSocket()
static BESKeys * TheKeys()
virtual bool receive(map< string, string > &extensions, ostream *strm=0)=0
void unblock_signals()
See block_signals()