[svn] commit: r394 - in /branches/jelte-datadef/src/bin/parkinglot: ccsession.cc ccsession.h main.cc parkinglot.h
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Dec 21 12:45:14 UTC 2009
Author: jelte
Date: Mon Dec 21 12:45:14 2009
New Revision: 394
Log:
common module-side API for commands and configuration
Modified:
branches/jelte-datadef/src/bin/parkinglot/ccsession.cc
branches/jelte-datadef/src/bin/parkinglot/ccsession.h
branches/jelte-datadef/src/bin/parkinglot/main.cc
branches/jelte-datadef/src/bin/parkinglot/parkinglot.h
Modified: branches/jelte-datadef/src/bin/parkinglot/ccsession.cc
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/ccsession.cc (original)
+++ branches/jelte-datadef/src/bin/parkinglot/ccsession.cc Mon Dec 21 12:45:14 2009
@@ -71,23 +71,48 @@
file.close();
}
-CommandSession::CommandSession() :
+CommandSession::CommandSession(std::string module_name,
+ std::string spec_file_name,
+ ISC::Data::ElementPtr(*config_handler)(ISC::Data::ElementPtr new_config),
+ ISC::Data::ElementPtr(*command_handler)(ISC::Data::ElementPtr command)
+ ) :
+ module_name_(module_name),
session_(ISC::CC::Session())
{
+ config_handler_ = config_handler;
+ command_handler_ = command_handler;
+
try {
// todo: workaround, let boss wait until msgq is started
// and remove sleep here
sleep(1);
+
+ ElementPtr answer, env;
+
session_.establish();
- session_.subscribe("ParkingLot", "*");
+ session_.subscribe(module_name, "*");
session_.subscribe("Boss", "*", "meonly");
session_.subscribe("ConfigManager", "*", "meonly");
session_.subscribe("statistics", "*", "meonly");
- read_data_definition("parkinglot.spec");
+ read_data_definition(spec_file_name);
sleep(1);
- ElementPtr cmd = Element::create_from_string("{ \"config_manager\": 1}");
- // why does the msgq seem to kill this msg?
+ // send the data specification
session_.group_sendmsg(data_definition_.getDefinition(), "ConfigManager");
+ session_.group_recvmsg(env, answer, false);
+
+ // get any stored configuration from the manager
+ if (config_handler_) {
+ ElementPtr cmd = Element::create_from_string("{ \"command\": [ \"get_config\", \"" + module_name + "\" ] }");
+ session_.group_sendmsg(cmd, "ConfigManager");
+ session_.group_recvmsg(env, answer, false);
+ cout << "[XX] got config: " << endl << answer->str() << endl;
+ // replace string_value and "0" with int_value and 0 with new cc after merge */
+ if (answer->contains("result") && answer->get("result")->get(0)->string_value() == "0") {
+ config_handler(answer->get("result")->get(1));
+ } else {
+ cout << "[XX] no result in answer" << endl;
+ }
+ }
} catch (...) {
throw std::runtime_error("SessionManager: failed to open sessions");
}
@@ -99,58 +124,37 @@
return (session_.getSocket());
}
-std::pair<std::string, ElementPtr>
-CommandSession::getCommand(int counter) {
- ElementPtr cmd, routing, data, ep;
- string s;
- session_.group_recvmsg(routing, data, false);
- string channel = routing->get("group")->string_value();
-
- if (channel == "statistics") {
- cmd = data->get("command");
- if (cmd != NULL && cmd->string_value() == "getstat") {
- struct timeval now;
- ElementPtr resp = Element::create(std::map<std::string,
- ElementPtr>());
- gettimeofday(&now, NULL);
- resp->set("sent", Element::create(now.tv_sec +
- (double)now.tv_usec / 1000000));
- resp->set("counter", Element::create(counter));
- session_.group_sendmsg(resp, "statistics");
+int
+CommandSession::check_command()
+{
+ cout << "[XX] check for command" << endl;
+ ElementPtr cmd, routing, data;
+ if (session_.group_recvmsg(routing, data, true)) {
+ /* ignore result messages (in case we're out of sync, to prevent
+ * pingpongs */
+ if (!data->get_type() == Element::map || data->contains("result")) {
+ return 0;
}
- } else {
- cout << "[parkinglot] saw message: " << data << endl;
- // todo: common interface for config updates?
- cmd = data->get("config_update");
- if (cmd != NULL) {
- return std::pair<string, ElementPtr>("config_update", cmd);
+ cout << "[XX] got something!" << endl << data->str() << endl;
+ ElementPtr answer;
+ if (data->contains("config_update")) {
+ if (config_handler_) {
+ // handle config update
+ answer = config_handler_(data->get("config_update"));
+ } else {
+ answer = Element::create_from_string("{ \"result\": [0] }");
+ }
}
- // todo: common interface for command handling
- cmd = data->get("command");
- // the format is defined partly by convention;
- // { "command": [ "module", "command", args... ]
- // args is defined in the .spec file
- // we could do checking here as well if we want
- if (cmd != NULL && cmd->get(1)->string_value() == "print_message") {
- cout << "[parkinglot] " << cmd->get(2)->string_value() << endl;
- ElementPtr answer = Element::create_from_string("{ \"result\": [0] }");
- session_.reply(routing, answer);
+ if (data->contains("command")) {
+ if (command_handler_) {
+ answer = command_handler_(data->get("command"));
+ } else {
+ answer = Element::create_from_string("{ \"result\": [0] }");
+ }
}
+ session_.reply(routing, answer);
}
-
- return std::pair<string, ElementPtr>("unknown", ElementPtr());
+
+ return 0;
}
-// should be replaced by the general config-getter in cc setup
-std::vector<std::string>
-CommandSession::getZones() {
- ElementPtr cmd, result, env;
- std::vector<std::string> zone_names;
- cmd = Element::create_from_string("{ \"command\": [ \"zone\", \"list\" ] }");
- session_.group_sendmsg(cmd, "ConfigManager");
- session_.group_recvmsg(env, result, false);
- BOOST_FOREACH(ElementPtr zone_name, result->get("result")->list_value()) {
- zone_names.push_back(zone_name->string_value());
- }
- return zone_names;
-}
Modified: branches/jelte-datadef/src/bin/parkinglot/ccsession.h
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/ccsession.h (original)
+++ branches/jelte-datadef/src/bin/parkinglot/ccsession.h Mon Dec 21 12:45:14 2009
@@ -25,16 +25,61 @@
class CommandSession {
public:
- CommandSession();
+ /**
+ * Initialize a config/command session
+ * @param module_name: The name of this module. This is not a
+ * reference because we expect static strings
+ * to be passed here.
+ * @param spec_file_name: The name of the file containing the data
+ * definition.
+ */
+ CommandSession(std::string module_name, std::string spec_file_name,
+ ISC::Data::ElementPtr(*config_handler)(ISC::Data::ElementPtr new_config) = NULL,
+ ISC::Data::ElementPtr(*command_handler)(ISC::Data::ElementPtr command) = NULL
+ );
int getSocket();
- std::pair<std::string, ISC::Data::ElementPtr> getCommand(int counter);
- std::vector<std::string> getZones();
+
+ /**
+ * Check if there is a command or config change on the command
+ * session. If so, the appropriate handler is called if set.
+ * If not set, a default answer is returned.
+ * This is a non-blocking read; if there is nothing this function
+ * will return 0.
+ */
+ int check_command();
+
+ /**
+ * The config handler function should expect an ElementPtr containing
+ * the full configuration where non-default values have been set.
+ * Later we might want to think about more granular control
+ * (i.e. this does not scale to for instance lists containing
+ * 100000 zones, where the whole list is passed every time a single
+ * thing changes)
+ */
+ void set_config_handler(ISC::Data::ElementPtr(*config_handler)(ISC::Data::ElementPtr new_config)) { config_handler_ = config_handler; };
+
+ /**
+ * Set a command handler; the function that is passed takes an
+ * ElementPtr, pointing to a list element, containing
+ * [ module_name, command_name, arg1, arg2, ... ]
+ * The returned ElementPtr should look like
+ * { "result": [ return_value, result_value ] }
+ * result value here is optional and depends on the command
+ *
+ * This protocol is very likely to change.
+ */
+ void set_command_handler(ISC::Data::ElementPtr(*command_handler)(ISC::Data::ElementPtr command)) { command_handler_ = command_handler; };
+
private:
- void read_data_definition(const std::string& filename);
-
+ void read_data_definition(const std::string& filename);
+
+ std::string module_name_;
ISC::CC::Session session_;
ISC::Data::DataDefinition data_definition_;
ISC::Data::ElementPtr config_;
+
+ ISC::Data::ElementPtr(*config_handler_)(ISC::Data::ElementPtr new_config);
+ ISC::Data::ElementPtr(*command_handler_)(ISC::Data::ElementPtr command);
};
#endif // __CCSESSION_H
Modified: branches/jelte-datadef/src/bin/parkinglot/main.cc
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/main.cc (original)
+++ branches/jelte-datadef/src/bin/parkinglot/main.cc Mon Dec 21 12:45:14 2009
@@ -39,15 +39,55 @@
#include "common.h"
+#include <boost/foreach.hpp>
+
using namespace std;
-const string PROGRAM = "parkinglot";
-const int DNSPORT = 53;
+const string PROGRAM = "ParkingLot";
+const string SPECFILE = "parkinglot.spec";
+const int DNSPORT = 5300;
+
+/* need global var for config/command handlers.
+ * todo: turn this around, and put handlers in the parkinglot
+ * class itself */
+ParkingLot plot = ParkingLot(DNSPORT);
static void
usage() {
cerr << "Usage: parkinglot [-p port]" << endl;
exit(1);
+}
+
+ISC::Data::ElementPtr
+my_config_handler(ISC::Data::ElementPtr config)
+{
+ cout << "[XX] Handle config: " << endl << config->str() << endl;
+ if (config->contains("zones")) {
+ plot.clear_zones();
+ BOOST_FOREACH(ISC::Data::ElementPtr zone_el, config->get("zones")->list_value()) {
+ plot.serve(zone_el->string_value());
+ }
+ }
+ if (config->contains("port")) {
+ // todo: what to do with port change. restart automatically?
+ // ignore atm
+ }
+ return ISC::Data::Element::create_from_string("{ \"result\": [0] }");
+}
+
+ISC::Data::ElementPtr
+my_command_handler(ISC::Data::ElementPtr command)
+{
+ ISC::Data::ElementPtr answer = ISC::Data::Element::create_from_string("{ \"result\": [0] }");
+
+ cout << "[XX] Handle command: " << endl << command->str() << endl;
+ if (command->get(1)->string_value() == "print_message") {
+ cout << command->get(2)->string_value() << endl;
+ /* let's add that message to our answer as well */
+ answer->get("result")->add(command->get(2));
+ }
+
+ return answer;
}
int
@@ -70,18 +110,20 @@
usage();
// initialize parking lot
- ParkingLot plot(port);
+ //plot = ParkingLot(port);
// initialize command channel
- CommandSession cs;
-
+ CommandSession cs = CommandSession(PROGRAM, SPECFILE, my_config_handler, my_command_handler);
+ //cs.set_config_handler(my_config_handler);
+ //cs.set_command_handler(my_command_handler);
+
// main server loop
fd_set fds;
int ps = plot.getSocket();
int ss = cs.getSocket();
- BOOST_FOREACH(std::string zone, cs.getZones()) {
+ /*BOOST_FOREACH(std::string zone, cs.getZones()) {
plot.serve(zone);
- }
+ }*/
int nfds = max(ps, ss) + 1;
int counter = 0;
@@ -100,9 +142,11 @@
plot.processMessage();
}
+ /* isset not really necessary, but keep it for now */
if (FD_ISSET(ss, &fds)) {
- pair<string, ISC::Data::ElementPtr> cmd = cs.getCommand(counter);
- plot.command(cmd);
+ cs.check_command();
+ //pair<string, ISC::Data::ElementPtr> cmd = cs.getCommand(counter);
+ //plot.command(cmd);
}
}
Modified: branches/jelte-datadef/src/bin/parkinglot/parkinglot.h
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/parkinglot.h (original)
+++ branches/jelte-datadef/src/bin/parkinglot/parkinglot.h Mon Dec 21 12:45:14 2009
@@ -28,6 +28,7 @@
void processMessage();
void command(std::pair<std::string,ISC::Data::ElementPtr>);
void serve(std::string zone_name);
+ void clear_zones() { zones.clear_zones(); };
private:
isc::dns::Rdata::RdataPtr ns1, ns2, ns3, a, aaaa, soa;
More information about the bind10-changes
mailing list