ccsession.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. //
  16. // todo: generalize this and make it into a specific API for all modules
  17. // to use (i.e. connect to cc, send config and commands, get config,
  18. // react on config change announcements)
  19. //
  20. #include <stdexcept>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <sys/time.h>
  24. #include <iostream>
  25. #include <fstream>
  26. #include <sstream>
  27. #include <cerrno>
  28. #include <boost/foreach.hpp>
  29. #include <cc/data.h>
  30. #include <module_spec.h>
  31. #include <cc/session.h>
  32. #include <exceptions/exceptions.h>
  33. //#include "common.h"
  34. #include "ccsession.h"
  35. #include "config.h"
  36. using namespace std;
  37. using isc::data::Element;
  38. using isc::data::ElementPtr;
  39. using isc::data::ParseError;
  40. namespace isc {
  41. namespace config {
  42. /// Creates a standard config/command protocol answer message
  43. ElementPtr
  44. createAnswer(const int rcode)
  45. {
  46. ElementPtr answer = Element::createFromString("{\"result\": [] }");
  47. ElementPtr answer_content = answer->get("result");
  48. answer_content->add(Element::create(rcode));
  49. return answer;
  50. }
  51. ElementPtr
  52. createAnswer(const int rcode, const ElementPtr arg)
  53. {
  54. ElementPtr answer = Element::createFromString("{\"result\": [] }");
  55. ElementPtr answer_content = answer->get("result");
  56. answer_content->add(Element::create(rcode));
  57. answer_content->add(arg);
  58. return answer;
  59. }
  60. ElementPtr
  61. createAnswer(const int rcode, const std::string& arg)
  62. {
  63. ElementPtr answer = Element::createFromString("{\"result\": [] }");
  64. ElementPtr answer_content = answer->get("result");
  65. answer_content->add(Element::create(rcode));
  66. answer_content->add(Element::create(arg));
  67. return answer;
  68. }
  69. ElementPtr
  70. parseAnswer(int &rcode, const ElementPtr msg)
  71. {
  72. if (!msg->contains("result")) {
  73. // TODO: raise CCSessionError exception
  74. dns_throw(CCSessionError, "No result in answer message");
  75. } else {
  76. ElementPtr result = msg->get("result");
  77. if (result->get(0)->getType() != Element::integer) {
  78. dns_throw(CCSessionError, "First element of result is not an rcode in answer message");
  79. } else if (result->get(0)->intValue() != 0 && result->get(1)->getType() != Element::string) {
  80. dns_throw(CCSessionError, "Rcode in answer message is non-zero, but other argument is not a StringElement");
  81. }
  82. rcode = result->get(0)->intValue();
  83. if (result->size() > 1) {
  84. return result->get(1);
  85. } else {
  86. return ElementPtr();
  87. }
  88. }
  89. }
  90. void
  91. ModuleCCSession::read_module_specification(const std::string& filename) {
  92. std::ifstream file;
  93. // this file should be declared in a @something@ directive
  94. file.open(filename.c_str());
  95. if (!file) {
  96. cout << "error opening " << filename << ": " << strerror(errno) << endl;
  97. exit(1);
  98. }
  99. try {
  100. module_specification_ = moduleSpecFromFile(file, true);
  101. } catch (ParseError pe) {
  102. cout << "Error parsing module specification file: " << pe.what() << endl;
  103. exit(1);
  104. } catch (ModuleSpecError dde) {
  105. cout << "Error reading module specification file: " << dde.what() << endl;
  106. exit(1);
  107. }
  108. file.close();
  109. }
  110. ModuleCCSession::ModuleCCSession(std::string spec_file_name,
  111. isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
  112. isc::data::ElementPtr(*command_handler)(isc::data::ElementPtr command)
  113. ) throw (isc::cc::SessionError):
  114. session_(isc::cc::Session())
  115. {
  116. read_module_specification(spec_file_name);
  117. sleep(1);
  118. module_name_ = module_specification_.getFullSpec()->get("module_spec")->get("module_name")->stringValue();
  119. config_handler_ = config_handler;
  120. command_handler_ = command_handler;
  121. // todo: workaround, let boss wait until msgq is started
  122. // and remove sleep here
  123. sleep(1);
  124. ElementPtr answer, env;
  125. session_.establish();
  126. session_.subscribe(module_name_, "*");
  127. //session_.subscribe("Boss", "*");
  128. //session_.subscribe("statistics", "*");
  129. // send the data specification
  130. session_.group_sendmsg(module_specification_.getFullSpec(), "ConfigManager");
  131. session_.group_recvmsg(env, answer, false);
  132. // get any stored configuration from the manager
  133. if (config_handler_) {
  134. ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
  135. session_.group_sendmsg(cmd, "ConfigManager");
  136. session_.group_recvmsg(env, answer, false);
  137. cout << "[XX] got config: " << endl << answer->str() << endl;
  138. int rcode;
  139. ElementPtr new_config = parseAnswer(rcode, answer);
  140. handleConfigUpdate(new_config);
  141. }
  142. }
  143. /// Validates the new config values, if they are correct,
  144. /// call the config handler
  145. /// If that results in success, store the new config
  146. ElementPtr
  147. ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
  148. {
  149. ElementPtr answer;
  150. if (!config_handler_) {
  151. answer = createAnswer(1, module_name_ + " does not have a config handler");
  152. } else if (!module_specification_.validate_config(new_config)) {
  153. answer = createAnswer(2, "Error in config validation");
  154. } else {
  155. // handle config update
  156. answer = config_handler_(new_config);
  157. int rcode;
  158. parseAnswer(rcode, answer);
  159. if (rcode == 0) {
  160. config_ = new_config;
  161. }
  162. }
  163. return answer;
  164. }
  165. int
  166. ModuleCCSession::getSocket()
  167. {
  168. return (session_.getSocket());
  169. }
  170. int
  171. ModuleCCSession::check_command()
  172. {
  173. cout << "[XX] check for command" << endl;
  174. ElementPtr cmd, routing, data;
  175. if (session_.group_recvmsg(routing, data, true)) {
  176. /* ignore result messages (in case we're out of sync, to prevent
  177. * pingpongs */
  178. if (!data->getType() == Element::map || data->contains("result")) {
  179. return 0;
  180. }
  181. cout << "[XX] got something!" << endl << data->str() << endl;
  182. ElementPtr answer;
  183. if (data->contains("config_update")) {
  184. ElementPtr new_config = data->get("config_update");
  185. answer = handleConfigUpdate(new_config);
  186. }
  187. if (data->contains("command")) {
  188. if (command_handler_) {
  189. answer = command_handler_(data->get("command"));
  190. } else {
  191. answer = Element::createFromString("{ \"result\": [0] }");
  192. }
  193. }
  194. session_.reply(routing, answer);
  195. }
  196. return 0;
  197. }
  198. }
  199. }