ccsession.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  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. #ifndef CCSESSION_H
  15. #define CCSESSION_H 1
  16. #include <config/config_data.h>
  17. #include <config/module_spec.h>
  18. #include <cc/session.h>
  19. #include <cc/data.h>
  20. #include <cc/proto_defs.h>
  21. #include <string>
  22. #include <list>
  23. #include <boost/function.hpp>
  24. namespace isc {
  25. namespace config {
  26. ///
  27. /// \brief Creates a standard config/command level success answer message
  28. /// (i.e. of the form { "result": [ 0 ] }
  29. /// \return Standard command/config success answer message
  30. isc::data::ConstElementPtr createAnswer();
  31. ///
  32. /// \brief Creates a standard config/command level answer message
  33. /// (i.e. of the form { "result": [ rcode, arg ] }
  34. /// If rcode != 0, arg must be a StringElement
  35. ///
  36. /// \param rcode The return code (0 for success)
  37. /// \param arg For rcode == 0, this is an optional argument of any
  38. /// Element type. For rcode == 1, this argument is mandatory,
  39. /// and must be a StringElement containing an error description
  40. /// \return Standard command/config answer message
  41. isc::data::ConstElementPtr createAnswer(const int rcode,
  42. isc::data::ConstElementPtr arg);
  43. ///
  44. /// \brief Creates a standard config/command level answer message
  45. /// (i.e. of the form { "result": [ rcode, arg ] }
  46. ///
  47. /// \param rcode The return code (0 for success)
  48. /// \param arg A string to put into the StringElement argument
  49. /// \return Standard command/config answer message
  50. isc::data::ConstElementPtr createAnswer(const int rcode,
  51. const std::string& arg);
  52. ///
  53. /// Parses a standard config/command level answer message
  54. ///
  55. /// \param rcode This value will be set to the return code contained in
  56. /// the message
  57. /// \param msg The message to parse
  58. /// \return The optional argument in the message, or an empty ElementPtr
  59. /// if there was no argument. If rcode != 0, this contains a
  60. /// StringElement with the error description.
  61. isc::data::ConstElementPtr parseAnswer(int &rcode,
  62. isc::data::ConstElementPtr msg);
  63. ///
  64. /// \brief Creates a standard config/command command message with no
  65. /// argument (of the form { "command": [ "my_command" ] }
  66. ///
  67. /// \param command The command string
  68. /// \return The created message
  69. isc::data::ConstElementPtr createCommand(const std::string& command);
  70. ///
  71. /// \brief Creates a standard config/command command message with the
  72. /// given argument (of the form { "command": [ "my_command", arg ] }
  73. ///
  74. /// \param command The command string
  75. /// \param arg The optional argument for the command. This can be of
  76. /// any Element type, but it should conform to the .spec file.
  77. /// \return The created message
  78. isc::data::ConstElementPtr createCommand(const std::string& command,
  79. isc::data::ConstElementPtr arg);
  80. ///
  81. /// \brief Parses the given command into a string containing the actual
  82. /// command and an ElementPtr containing the optional argument.
  83. ///
  84. /// Raises a CCSessionError if this is not a well-formed command
  85. ///
  86. /// Example code: (command_message is a ConstElementPtr that is
  87. /// passed here)
  88. /// \code
  89. /// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
  90. /// try {
  91. /// ConstElementPtr args;
  92. /// std::string command_str = parseCommand(args, command_message);
  93. /// if (command_str == "foo") {
  94. /// std::cout << "The command 'foo' was given" << std::endl;
  95. /// if (args->contains("bar")) {
  96. /// std::cout << "It had argument name 'bar' set, which has"
  97. /// << "value "
  98. /// << args->get("bar")->intValue();
  99. /// }
  100. /// } else {
  101. /// std::cout << "Unknown command '" << command_str << std::endl;
  102. /// }
  103. /// } catch (CCSessionError cse) {
  104. /// std::cerr << "Bad command in CC Session: "
  105. /// << cse.what() << std::endl;
  106. /// }
  107. /// \endcode
  108. ///
  109. /// \param arg This value will be set to the ElementPtr pointing to
  110. /// the argument, or to an empty Map (ElementPtr) if there was none.
  111. /// \param command The command message containing the command (as made
  112. /// by createCommand()
  113. /// \return The command name
  114. std::string parseCommand(isc::data::ConstElementPtr& arg,
  115. isc::data::ConstElementPtr command);
  116. ///
  117. /// \brief A standard cc session exception that is thrown if a function
  118. /// is there is a problem with one of the messages
  119. ///
  120. // todo: include types and called function in the exception
  121. class CCSessionError : public isc::Exception {
  122. public:
  123. CCSessionError(const char* file, size_t line, const char* what) :
  124. isc::Exception(file, line, what) {}
  125. };
  126. ///
  127. /// \brief This exception is thrown if the constructor fails
  128. ///
  129. class CCSessionInitError : public isc::Exception {
  130. public:
  131. CCSessionInitError(const char* file, size_t line, const char* what) :
  132. isc::Exception(file, line, what) {}
  133. };
  134. /// \brief Exception thrown when there's a problem with the remote call.
  135. ///
  136. /// This usually means either the command couldn't be called or the remote
  137. /// side sent an error as a response.
  138. class RPCError: public CCSessionError {
  139. public:
  140. RPCError(const char* file, size_t line, const char* what, int rcode) :
  141. CCSessionError(file, line, what),
  142. rcode_(rcode)
  143. {}
  144. /// \brief The error code for the error.
  145. int rcode() const {
  146. return (rcode_);
  147. }
  148. private:
  149. const int rcode_;
  150. };
  151. /// \brief Specific version of RPCError for the case the recipient of command
  152. /// doesn't exist.
  153. class RPCRecipientMissing: public RPCError {
  154. public:
  155. RPCRecipientMissing(const char* file, size_t line, const char* what) :
  156. RPCError(file, line, what, isc::cc::CC_REPLY_NO_RECPT)
  157. {}
  158. };
  159. ///
  160. /// \brief This module keeps a connection to the command channel,
  161. /// holds configuration information, and handles messages from
  162. /// the command channel
  163. ///
  164. class ModuleCCSession : public ConfigData {
  165. public:
  166. /**
  167. * Initialize a config/command session
  168. *
  169. * @param spec_file_name The name of the file containing the
  170. * module specification.
  171. * @param session A Session object over which configuration and command
  172. * data are exchanged.
  173. * @param config_handler A callback function pointer to be called when
  174. * configuration of the local module needs to be updated.
  175. * This must refer to a valid object of a concrete derived class of
  176. * AbstractSession without establishing the session.
  177. *
  178. * Note: the design decision on who is responsible for establishing the
  179. * session is in flux, and may change in near future.
  180. *
  181. * \exception CCSessionInitError when the initialization fails,
  182. * either because the file cannot be read or there is
  183. * a communication problem with the config manager.
  184. *
  185. * @param command_handler A callback function pointer to be called when
  186. * a control command from a remote agent needs to be performed on the
  187. * local module.
  188. * @param start_immediately If true (default), start listening to new commands
  189. * and configuration changes asynchronously at the end of the constructor;
  190. * if false, it will be delayed until the start() method is explicitly
  191. * called. (This is a short term workaround for an initialization trouble.
  192. * We'll need to develop a cleaner solution, and then remove this knob)
  193. * @param handle_logging If true, the ModuleCCSession will automatically
  194. * take care of logging configuration through the virtual Logging config
  195. * module. Defaults to true.
  196. */
  197. ModuleCCSession(const std::string& spec_file_name,
  198. isc::cc::AbstractSession& session,
  199. isc::data::ConstElementPtr(*config_handler)(
  200. isc::data::ConstElementPtr new_config) = NULL,
  201. isc::data::ConstElementPtr(*command_handler)(
  202. const std::string& command,
  203. isc::data::ConstElementPtr args) = NULL,
  204. bool start_immediately = true,
  205. bool handle_logging = true
  206. );
  207. ///
  208. /// Destructor
  209. ///
  210. /// The destructor automatically calls sendStopping(), which sends
  211. /// a message to the ConfigManager that this module is stopping
  212. ///
  213. virtual ~ModuleCCSession();
  214. /// Start receiving new commands and configuration changes asynchronously.
  215. ///
  216. /// This method must be called only once, and only when the ModuleCCSession
  217. /// was constructed with start_immediately being false. Otherwise
  218. /// CCSessionError will be thrown.
  219. ///
  220. /// As noted in the constructor, this method should be considered a short
  221. /// term workaround and will be removed in future.
  222. void start();
  223. /**
  224. * Optional optimization for checkCommand loop; returns true
  225. * if there are unhandled queued messages in the cc session.
  226. * (if either this is true or there is data on the socket found
  227. * by the select() call on getSocket(), run checkCommand())
  228. *
  229. * @return true if there are unhandled queued messages
  230. */
  231. bool hasQueuedMsgs() const;
  232. /**
  233. * Check if there is a command or config change on the command
  234. * session. If so, the appropriate handler is called if set.
  235. * If not set, a default answer is returned.
  236. * This is a non-blocking read; if there is nothing this function
  237. * will return 0.
  238. */
  239. int checkCommand();
  240. /**
  241. * The config handler function should expect an ElementPtr containing
  242. * the full configuration where non-default values have been set.
  243. * Later we might want to think about more granular control
  244. * (i.e. this does not scale to for instance lists containing
  245. * 100000 zones, where the whole list is passed every time a single
  246. * thing changes)
  247. */
  248. void setConfigHandler(isc::data::ConstElementPtr(*config_handler)(
  249. isc::data::ConstElementPtr new_config))
  250. {
  251. config_handler_ = config_handler;
  252. }
  253. /**
  254. * Set a command handler; the function that is passed takes an
  255. * ElementPtr, pointing to a list element, containing
  256. * [ module_name, command_name, arg1, arg2, ... ]
  257. * The returned ElementPtr should look like
  258. * { "result": [ return_value, result_value ] }
  259. * result value here is optional and depends on the command
  260. *
  261. * This protocol is very likely to change.
  262. */
  263. void setCommandHandler(isc::data::ConstElementPtr(*command_handler)(
  264. const std::string& command,
  265. isc::data::ConstElementPtr args))
  266. {
  267. command_handler_ = command_handler;
  268. }
  269. /**
  270. * Gives access to the configuration values of a different module
  271. * Once this function has been called with the name of the specification
  272. * file or the module you want the configuration of, you can use
  273. * \c getRemoteConfigValue() to get a specific setting.
  274. * Changes are automatically updated, and you can specify handlers
  275. * for those changes. This function will subscribe to the relevant module
  276. * channel.
  277. *
  278. * This method must be called before calling the \c start() method on the
  279. * ModuleCCSession (it also implies the ModuleCCSession must have been
  280. * constructed with start_immediately being false).
  281. *
  282. * \param spec_name This specifies the module to add. It is either a
  283. * filename of the spec file to use or a name of module
  284. * (in case it's a module name, the spec data is
  285. * downloaded from the configuration manager, therefore
  286. * the configuration manager must know it). If
  287. * spec_is_filename is true (the default), then a
  288. * filename is assumed, otherwise a module name.
  289. * \param handler The handler functor called whenever there's a change.
  290. * Called once initially from this function. May be NULL
  291. * if you don't want any handler to be called and you're
  292. * fine with requesting the data through
  293. * getRemoteConfigValue() each time.
  294. *
  295. * The handler should not throw, or it'll fall through and
  296. * the exception will get into strange places, probably
  297. * aborting the application.
  298. * \param spec_is_filename Says if spec_name is filename or module name.
  299. * \return The name of the module specified in the given specification
  300. * file
  301. */
  302. typedef boost::function<void(const std::string&,
  303. isc::data::ConstElementPtr,
  304. const ConfigData&)> RemoteHandler;
  305. std::string addRemoteConfig(const std::string& spec_name,
  306. RemoteHandler handler = RemoteHandler(),
  307. bool spec_is_filename = true);
  308. /**
  309. * Removes the module with the given name from the remote config
  310. * settings. If the module was not added with \c addRemoteConfig(),
  311. * nothing happens. If there was a handler for this config, it is
  312. * removed as well.
  313. */
  314. void removeRemoteConfig(const std::string& module_name);
  315. /**
  316. * Returns the current configuration value for the given module
  317. * name at the given identifier. See \c ConfigData::getValue() for
  318. * more details.
  319. * Raises a ModuleCCSessionError if the module name is unknown
  320. * Raises a DataNotFoundError if the identifier does not exist
  321. * in the specification.
  322. *
  323. * \param module_name The name of the module to get a config value for
  324. * \param identifier The identifier of the config value
  325. * \return The configuration setting at the given identifier
  326. */
  327. isc::data::ConstElementPtr getRemoteConfigValue(
  328. const std::string& module_name,
  329. const std::string& identifier) const;
  330. /**
  331. * Send a message to the underlying CC session.
  332. * This has the same interface as isc::cc::Session::group_sendmsg()
  333. *
  334. * \param msg see isc::cc::Session::group_sendmsg()
  335. * \param group see isc::cc::Session::group_sendmsg()
  336. * \param instance see isc::cc::Session::group_sendmsg()
  337. * \param to see isc::cc::Session::group_sendmsg()
  338. * \param want_answer see isc::cc::Session::group_sendmsg()
  339. * \return see isc::cc::Session::group_sendmsg()
  340. */
  341. int groupSendMsg(isc::data::ConstElementPtr msg,
  342. std::string group,
  343. std::string instance = isc::cc::CC_INSTANCE_WILDCARD,
  344. std::string to = isc::cc::CC_TO_WILDCARD,
  345. bool want_answer = false) {
  346. return (session_.group_sendmsg(msg, group, instance, to, want_answer));
  347. };
  348. /// \brief Receive a message from the underlying CC session.
  349. /// This has the same interface as isc::cc::Session::group_recvmsg()
  350. ///
  351. /// NOTE: until #2804 is resolved this method wouldn't work except in
  352. /// very limited cases; don't try to use it until then.
  353. ///
  354. /// \param envelope see isc::cc::Session::group_recvmsg()
  355. /// \param msg see isc::cc::Session::group_recvmsg()
  356. /// \param nonblock see isc::cc::Session::group_recvmsg()
  357. /// \param seq see isc::cc::Session::group_recvmsg()
  358. /// \return see isc::cc::Session::group_recvmsg()
  359. bool groupRecvMsg(isc::data::ConstElementPtr& envelope,
  360. isc::data::ConstElementPtr& msg,
  361. bool nonblock = true,
  362. int seq = -1) {
  363. return (session_.group_recvmsg(envelope, msg, nonblock, seq));
  364. }
  365. /// \brief Send a command message and wait for the answer.
  366. ///
  367. /// NOTE: until #2804 is resolved this method wouldn't work except in
  368. /// very limited cases; don't try to use it until then.
  369. ///
  370. /// This is mostly a convenience wrapper around groupSendMsg
  371. /// and groupRecvMsg, with some error handling.
  372. ///
  373. /// \param command Name of the command to call.
  374. /// \param group Name of the remote module to call the command on.
  375. /// \param instance Instance part of recipient address.
  376. /// \param to The lname to send it to. Can be used to override the
  377. /// addressing and use a direct recipient.
  378. /// \param params Parameters for the command. Can be left NULL if
  379. /// no parameters are needed.
  380. /// \return Return value of the successfull remote call. It can be
  381. /// NULL if the remote command is void function (returns nothing).
  382. /// \throw RPCError if the call fails (for example when the other
  383. /// side responds with error code).
  384. /// \throw RPCRecipientMissing if the recipient doesn't exist.
  385. /// \throw CCSessionError if some lower-level error happens (eg.
  386. /// the response was malformed).
  387. isc::data::ConstElementPtr rpcCall(const std::string& command,
  388. const std::string& group,
  389. const std::string& instance =
  390. isc::cc::CC_INSTANCE_WILDCARD,
  391. const std::string& to =
  392. isc::cc::CC_TO_WILDCARD,
  393. const isc::data::ConstElementPtr&
  394. params =
  395. isc::data::ConstElementPtr());
  396. /// \brief Send a notification to subscribed users
  397. ///
  398. /// Send a notification message to all users subscribed to the given
  399. /// notification group.
  400. ///
  401. /// This method does not not block.
  402. ///
  403. /// See docs/design/ipc-high.txt for details about notifications and
  404. /// the format of messages sent.
  405. ///
  406. /// \throw CCSessionError for low-level communication errors.
  407. /// \param notification_group This parameter (indirectly) signifies what
  408. /// users should receive the notification. Only the users that
  409. /// subscribed to notifications on the same group receive it.
  410. /// \param name The name of the event to notify about (for example
  411. /// `new_group_member`).
  412. /// \param params Other parameters that describe the event. This might
  413. /// be, for example, the ID of the new member and the name of the
  414. /// group. This can be any data element, but it is common for it to be
  415. /// map.
  416. void notify(const std::string& notification_group,
  417. const std::string& name,
  418. const isc::data::ConstElementPtr& params =
  419. isc::data::ConstElementPtr());
  420. /// \brief Convenience version of rpcCall
  421. ///
  422. /// This is exactly the same as the previous version of rpcCall, except
  423. /// that the instance and to parameters are at their default. This
  424. /// allows to sending a command with parameters to a named module
  425. /// without long typing of the parameters.
  426. isc::data::ConstElementPtr rpcCall(const std::string& command,
  427. const std::string& group,
  428. const isc::data::ConstElementPtr&
  429. params)
  430. {
  431. return rpcCall(command, group, isc::cc::CC_INSTANCE_WILDCARD,
  432. isc::cc::CC_TO_WILDCARD, params);
  433. }
  434. /// \brief Forward declaration of internal data structure.
  435. ///
  436. /// This holds information about one asynchronous request to receive
  437. /// a message. It is declared as public to allow declaring other derived
  438. /// types, but without showing the internal representation.
  439. class AsyncRecvRequest;
  440. /// \brief List of all requests for asynchronous reads.
  441. typedef std::list<AsyncRecvRequest> AsyncRecvRequests;
  442. /// \brief Identifier of single request for asynchronous read.
  443. typedef AsyncRecvRequests::iterator AsyncRecvRequestID;
  444. /// \brief Callback which is called when an asynchronous receive finishes.
  445. ///
  446. /// This is the callback used by groupRecvMsgAsync() function. It is called
  447. /// when a matching message arrives. It receives following parameters when
  448. /// called:
  449. /// - The envelope of the message
  450. /// - The message itself
  451. /// - The ID of the request, as returned by corresponding groupRecvMsgAsync
  452. /// call.
  453. ///
  454. /// It is possible to throw exceptions from the callback, but they will not
  455. /// be caught and they will get propagated out through the checkCommand()
  456. /// call. This, if not handled on higher level, will likely terminate the
  457. /// application. However, the ModuleCCSession internals will be in
  458. /// well-defined state after the call (both the callback and the message
  459. /// will be removed from the queues as already called).
  460. typedef boost::function3<void, const isc::data::ConstElementPtr&,
  461. const isc::data::ConstElementPtr&,
  462. const AsyncRecvRequestID&>
  463. AsyncRecvCallback;
  464. /// \brief Receive a message from the CC session asynchronously.
  465. ///
  466. /// This registers a callback which is called when a matching message
  467. /// is received. This message returns immediately.
  468. ///
  469. /// Once a matching message arrives, the callback is called with the
  470. /// envelope of the message, the message itself and the result of this
  471. /// function call (which might be useful for identifying which of many
  472. /// events the recipient is waiting for this is). This makes the callback
  473. /// used and is not called again even if a message that would match
  474. /// arrives later (this is a single-shot callback).
  475. ///
  476. /// The callback is never called from within this function. Even if there
  477. /// are queued messages, the callback would be called once checkCommand()
  478. /// is invoked (possibly from start() or the constructor).
  479. ///
  480. /// The matching is as follows. If is_reply is true, only replies are
  481. /// considered. In that case, if seq is -1, any reply is accepted. If
  482. /// it is something else than -1, only the reply with matching seq is
  483. /// taken. This may be used to receive replies to commands
  484. /// asynchronously.
  485. ///
  486. /// In case the is_reply is false, the function looks for command messages.
  487. /// The seq parameter is ignored, but the recipient one is considered. If
  488. /// it is an empty string, any command is taken. If it is non-empty, only
  489. /// commands addressed to the recipient channel (eg. group - instance is
  490. /// ignored for now) are taken. This can be used to receive foreign commands
  491. /// or notifications. In such case, it might be desirable to call the
  492. /// groupRecvMsgAsync again from within the callback, to receive any future
  493. /// commands or events of the same type.
  494. ///
  495. /// The interaction with other receiving functions is slightly complicated.
  496. /// The groupRecvMsg call takes precedence. If the message matches its
  497. /// parameters, it steals the message and no callback matching it as well
  498. /// is called. Then, all the queued asynchronous receives are considered,
  499. /// with the oldest active ones taking precedence (they work as FIFO).
  500. /// If none of them matches, generic command and config handling takes
  501. /// place. If it is not handled by that, the message is dropped. However,
  502. /// it is better if there's just one place that wants to receive each given
  503. /// message.
  504. ///
  505. /// \exception std::bad_alloc if there isn't enough memory to store the
  506. /// callback.
  507. /// \param callback is the function to be called when a matching message
  508. /// arrives.
  509. /// \param is_reply specifies if the desired message should be a reply or
  510. /// a command.
  511. /// \param seq specifies the reply sequence number in case a reply is
  512. /// desired. The default -1 means any reply is OK.
  513. /// \param recipient is the CC channel to which the command should be
  514. /// addressed to match (in case is_reply is false). Empty means any
  515. /// command is good one.
  516. /// \return An identifier of the request. This will be passed to the
  517. /// callback or can be used to cancel the request by cancelAsyncRecv.
  518. /// \todo Decide what to do with instance and what was it meant for anyway.
  519. AsyncRecvRequestID groupRecvMsgAsync(const AsyncRecvCallback& callback,
  520. bool is_reply, int seq = -1,
  521. const std::string& recipient =
  522. std::string());
  523. /// \brief Removes yet unused request for asynchronous receive.
  524. ///
  525. /// This function cancels a request previously queued by
  526. /// groupRecvMsgAsync(). You may use it only before the callback was
  527. /// already triggered. If you call it with an ID of callback that
  528. /// already happened or was already canceled, the behaviour is undefined
  529. /// (but something like a crash is very likely, as the function removes
  530. /// an item from a list and this would be removing it from a list that
  531. /// does not contain the item).
  532. ///
  533. /// It is important to cancel requests that are no longer going to happen
  534. /// for some reason, as the request would occupy memory forever.
  535. ///
  536. /// \param id The id of request as returned by groupRecvMsgAsync.
  537. void cancelAsyncRecv(const AsyncRecvRequestID& id);
  538. typedef boost::function<void (const std::string& event_name,
  539. const data::ConstElementPtr& params)>
  540. NotificationCallback;
  541. typedef std::list<NotificationCallback> NotificationCallbacks;
  542. typedef std::map<std::string, NotificationCallbacks>
  543. SubscribedNotifications;
  544. typedef std::pair<SubscribedNotifications::iterator,
  545. NotificationCallbacks::iterator>
  546. NotificationID;
  547. NotificationID subscribeNotification(const std::string& notification_group,
  548. const NotificationCallback& callback);
  549. void unsubscribeNotification(const NotificationID& notification);
  550. /// \brief Subscribe to a group
  551. ///
  552. /// Wrapper around the CCSession::subscribe.
  553. void subscribe(const std::string& group) {
  554. session_.subscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
  555. }
  556. /// \brief Unsubscribe from a group.
  557. ///
  558. /// Wrapper around the CCSession::unsubscribe.
  559. void unsubscribe(const std::string& group) {
  560. session_.unsubscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
  561. }
  562. /// \brief Callback type for unhandled commands
  563. ///
  564. /// The type of functions that are not handled by the ModuleCCSession
  565. /// because they are not aimed at the module.
  566. ///
  567. /// The parameters are:
  568. /// - Name of the command.
  569. /// - The module it was aimed for (may be empty).
  570. /// - The parameters of the command.
  571. typedef boost::function<void (const std::string&, const std::string&,
  572. const isc::data::ConstElementPtr&)>
  573. UnhandledCallback;
  574. /// \brief Register a callback for messages sent to foreign modules.
  575. ///
  576. /// Usually, a command aimed at foreign module (or sent directly)
  577. /// is discarded. By registering a callback here, these can be
  578. /// examined.
  579. ///
  580. /// \note A callback overwrites the previous one set.
  581. /// \todo This is a temporary, unclean, solution. A more generic
  582. /// one needs to be designed. Also, a solution that is able
  583. /// to send an answer would be great.
  584. ///
  585. /// \param callback The new callback to use. It may be an empty
  586. /// function.
  587. void setUnhandledCallback(const UnhandledCallback& callback) {
  588. unhandled_callback_ = callback;
  589. }
  590. private:
  591. ModuleSpec readModuleSpecification(const std::string& filename);
  592. void startCheck();
  593. void sendStopping();
  594. /// \brief Check if the message is wanted by asynchronous read
  595. ///
  596. /// It checks if any of the previously queued requests match
  597. /// the message. If so, the callback is dispatched and removed.
  598. ///
  599. /// \param envelope The envelope of the message.
  600. /// \param msg The actual message data.
  601. /// \return True if the message was used for a callback, false
  602. /// otherwise.
  603. bool checkAsyncRecv(const data::ConstElementPtr& envelope,
  604. const data::ConstElementPtr& msg);
  605. /// \brief Checks if a message with this envelope matches the request
  606. bool requestMatch(const AsyncRecvRequest& request,
  607. const data::ConstElementPtr& envelope) const;
  608. bool started_;
  609. std::string module_name_;
  610. isc::cc::AbstractSession& session_;
  611. ModuleSpec module_specification_;
  612. AsyncRecvRequests async_recv_requests_;
  613. SubscribedNotifications notifications_;
  614. isc::data::ConstElementPtr handleConfigUpdate(
  615. isc::data::ConstElementPtr new_config);
  616. isc::data::ConstElementPtr checkConfigUpdateCommand(
  617. const std::string& target_module,
  618. isc::data::ConstElementPtr arg);
  619. isc::data::ConstElementPtr checkModuleCommand(
  620. const std::string& cmd_str,
  621. const std::string& target_module,
  622. isc::data::ConstElementPtr arg) const;
  623. isc::data::ConstElementPtr(*config_handler_)(
  624. isc::data::ConstElementPtr new_config);
  625. isc::data::ConstElementPtr(*command_handler_)(
  626. const std::string& command,
  627. isc::data::ConstElementPtr args);
  628. std::map<std::string, ConfigData> remote_module_configs_;
  629. std::map<std::string, RemoteHandler> remote_module_handlers_;
  630. void updateRemoteConfig(const std::string& module_name,
  631. isc::data::ConstElementPtr new_config);
  632. ModuleSpec fetchRemoteSpec(const std::string& module, bool is_filename);
  633. UnhandledCallback unhandled_callback_;
  634. };
  635. /// \brief Default handler for logging config updates
  636. ///
  637. /// When CCSession is initialized with handle_logging set to true,
  638. /// this callback will be used to update the logger when a configuration
  639. /// change comes in.
  640. ///
  641. /// This function updates the (global) loggers by initializing a
  642. /// LoggerManager and passing the settings as specified in the given
  643. /// configuration update.
  644. ///
  645. /// \param module_name The name of the module
  646. /// \param new_config The modified configuration values
  647. /// \param config_data The full config data for the (remote) logging
  648. /// module.
  649. void
  650. default_logconfig_handler(const std::string& module_name,
  651. isc::data::ConstElementPtr new_config,
  652. const ConfigData& config_data);
  653. /// \brief Returns the loggers related to this module
  654. ///
  655. /// This function does two things;
  656. /// - it drops the configuration parts for loggers for other modules.
  657. /// - it replaces the '*' in the name of the loggers by the name of
  658. /// this module, but *only* if the expanded name is not configured
  659. /// explicitly.
  660. ///
  661. /// Examples: if this is the module b10-resolver,
  662. /// For the config names ['*', 'b10-auth']
  663. /// The '*' is replaced with 'b10-resolver', and this logger is used.
  664. /// 'b10-auth' is ignored (of course, it will not be in the b10-auth
  665. /// module).
  666. ///
  667. /// For ['*', 'b10-resolver']
  668. /// The '*' is ignored, and only 'b10-resolver' is used.
  669. ///
  670. /// For ['*.reslib', 'b10-resolver']
  671. /// Or ['b10-resolver.reslib', '*']
  672. /// Both are used, where the * will be expanded to b10-resolver
  673. ///
  674. /// \note This is a public function at this time, but mostly for
  675. /// the purposes of testing. Once we can directly test what loggers
  676. /// are running, this function may be moved to the unnamed namespace
  677. ///
  678. /// \param loggers the original 'loggers' config list
  679. /// \return ListElement containing only loggers relevant for this
  680. /// module, where * is replaced by the root logger name
  681. isc::data::ConstElementPtr
  682. getRelatedLoggers(isc::data::ConstElementPtr loggers);
  683. } // namespace config
  684. } // namespace isc
  685. #endif // CCSESSION_H
  686. // Local Variables:
  687. // mode: c++
  688. // End: