ccsession.h 30.2 KB
Newer Older
JINMEI Tatuya's avatar
JINMEI Tatuya committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
16
#ifndef CCSESSION_H
#define CCSESSION_H 1
JINMEI Tatuya's avatar
JINMEI Tatuya committed
17

18
#include <config/config_data.h>
19
#include <config/module_spec.h>
20

21
22
#include <cc/session.h>
#include <cc/data.h>
23
#include <cc/proto_defs.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
24

25
26
27
28
#include <string>
#include <list>
#include <boost/function.hpp>

29
30
31
namespace isc {
namespace config {

32
33
34
35
///
/// \brief Creates a standard config/command level success answer message
///        (i.e. of the form { "result": [ 0 ] }
/// \return Standard command/config success answer message
36
isc::data::ConstElementPtr createAnswer();
37
38
39
40
41
42
43
44
45
46
47

///
/// \brief Creates a standard config/command level answer message
///        (i.e. of the form { "result": [ rcode, arg ] }
/// If rcode != 0, arg must be a StringElement
///
/// \param rcode The return code (0 for success)
/// \param arg For rcode == 0, this is an optional argument of any
///            Element type. For rcode == 1, this argument is mandatory,
///            and must be a StringElement containing an error description
/// \return Standard command/config answer message
48
49
isc::data::ConstElementPtr createAnswer(const int rcode,
                                        isc::data::ConstElementPtr arg);
50
51
52
53
54
55
56
57

///
/// \brief Creates a standard config/command level answer message
/// (i.e. of the form { "result": [ rcode, arg ] }
///
/// \param rcode The return code (0 for success)
/// \param arg A string to put into the StringElement argument
/// \return Standard command/config answer message
58
59
isc::data::ConstElementPtr createAnswer(const int rcode,
                                        const std::string& arg);
60
61
62
63
64
65
66
67
68
69

///
/// Parses a standard config/command level answer message
/// 
/// \param rcode This value will be set to the return code contained in
///              the message
/// \param msg The message to parse
/// \return The optional argument in the message, or an empty ElementPtr
///         if there was no argument. If rcode != 0, this contains a
///         StringElement with the error description.
70
71
isc::data::ConstElementPtr parseAnswer(int &rcode,
                                       isc::data::ConstElementPtr msg);
72
73
74
75
76
77
78

///
/// \brief Creates a standard config/command command message with no
/// argument (of the form { "command": [ "my_command" ] }
/// 
/// \param command The command string
/// \return The created message
79
isc::data::ConstElementPtr createCommand(const std::string& command);
80
81
82
83
84
85
86
87
88

///
/// \brief Creates a standard config/command command message with the
/// given argument (of the form { "command": [ "my_command", arg ] }
/// 
/// \param command The command string
/// \param arg The optional argument for the command. This can be of 
///        any Element type, but it should conform to the .spec file.
/// \return The created message
89
90
isc::data::ConstElementPtr createCommand(const std::string& command,
                                         isc::data::ConstElementPtr arg);
91
92
93
94
95

///
/// \brief Parses the given command into a string containing the actual
///        command and an ElementPtr containing the optional argument.
///
96
97
/// Raises a CCSessionError if this is not a well-formed command
///
98
99
100
/// Example code: (command_message is a ConstElementPtr that is
/// passed here)
/// \code
Jelte Jansen's avatar
Jelte Jansen committed
101
/// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
102
/// try {
Jelte Jansen's avatar
Jelte Jansen committed
103
104
///     ConstElementPtr args;
///     std::string command_str = parseCommand(args, command_message);
105
106
///     if (command_str == "foo") {
///         std::cout << "The command 'foo' was given" << std::endl;
Jelte Jansen's avatar
Jelte Jansen committed
107
108
///         if (args->contains("bar")) {
///             std::cout << "It had argument name 'bar' set, which has"
109
///                       << "value " 
Jelte Jansen's avatar
Jelte Jansen committed
110
///                       << args->get("bar")->intValue();
111
112
113
114
115
116
117
118
119
120
///         }
///     } else {
///         std::cout << "Unknown command '" << command_str << std::endl;
///     }
/// } catch (CCSessionError cse) {
///     std::cerr << "Bad command in CC Session: "
///     << cse.what() << std::endl;
/// }
/// \endcode
/// 
121
/// \param arg This value will be set to the ElementPtr pointing to
122
///        the argument, or to an empty Map (ElementPtr) if there was none.
123
124
/// \param command The command message containing the command (as made
///        by createCommand()
125
/// \return The command name
126
127
std::string parseCommand(isc::data::ConstElementPtr& arg,
                         isc::data::ConstElementPtr command);
128
129


Jelte Jansen's avatar
Jelte Jansen committed
130
131
132
133
134
135
136
137
138
139
140
///
/// \brief A standard cc session exception that is thrown if a function
/// is there is a problem with one of the messages
///
// todo: include types and called function in the exception
class CCSessionError : public isc::Exception {
public:
    CCSessionError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

141
142
143
144
145
146
147
148
149
///
/// \brief This exception is thrown if the constructor fails
///
class CCSessionInitError : public isc::Exception {
public:
    CCSessionInitError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

150
151
152
153
154
155
156
157
158
159
/// \brief Exception thrown when there's a problem with the remote call.
///
/// This usually means either the command couldn't be called or the remote
/// side sent an error as a response.
class RPCError: public CCSessionError {
public:
    RPCError(const char* file, size_t line, const char* what, int rcode) :
        CCSessionError(file, line, what),
        rcode_(rcode)
    {}
160

161
162
163
164
165
    /// \brief The error code for the error.
    int rcode() const {
        return (rcode_);
    }
private:
166
    const int rcode_;
167
168
169
170
171
172
173
174
175
176
177
};

/// \brief Specific version of RPCError for the case the recipient of command
///     doesn't exist.
class RPCRecipientMissing: public RPCError {
public:
    RPCRecipientMissing(const char* file, size_t line, const char* what) :
        RPCError(file, line, what, isc::cc::CC_REPLY_NO_RECPT)
    {}
};

178
///
179
/// \brief This module keeps a connection to the command channel,
180
181
182
/// holds configuration information, and handles messages from
/// the command channel
///
183
class ModuleCCSession : public ConfigData {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
184
public:
185
186
    /**
     * Initialize a config/command session
187
188
     *
     * @param spec_file_name The name of the file containing the
189
     *                        module specification.
190
191
192
193
     * @param session A Session object over which configuration and command
     * data are exchanged.
     * @param config_handler A callback function pointer to be called when
     * configuration of the local module needs to be updated.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
194
195
     * This must refer to a valid object of a concrete derived class of
     * AbstractSession without establishing the session.
Jelte Jansen's avatar
Jelte Jansen committed
196
     *
197
198
     * Note: the design decision on who is responsible for establishing the
     * session is in flux, and may change in near future.
199
     *
Jelte Jansen's avatar
Jelte Jansen committed
200
201
202
     * \exception CCSessionInitError when the initialization fails,
     *            either because the file cannot be read or there is
     *            a communication problem with the config manager.
203
     *
204
205
206
     * @param command_handler A callback function pointer to be called when
     * a control command from a remote agent needs to be performed on the
     * local module.
207
     * @param start_immediately If true (default), start listening to new commands
208
209
210
211
     * and configuration changes asynchronously at the end of the constructor;
     * if false, it will be delayed until the start() method is explicitly
     * called. (This is a short term workaround for an initialization trouble.
     * We'll need to develop a cleaner solution, and then remove this knob)
212
213
     * @param handle_logging If true, the ModuleCCSession will automatically
     * take care of logging configuration through the virtual Logging config
214
     * module. Defaults to true.
215
     */
216
    ModuleCCSession(const std::string& spec_file_name,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
217
                    isc::cc::AbstractSession& session,
218
219
220
                    isc::data::ConstElementPtr(*config_handler)(
                        isc::data::ConstElementPtr new_config) = NULL,
                    isc::data::ConstElementPtr(*command_handler)(
JINMEI Tatuya's avatar
JINMEI Tatuya committed
221
                        const std::string& command,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
222
                        isc::data::ConstElementPtr args) = NULL,
Jelte Jansen's avatar
Jelte Jansen committed
223
                    bool start_immediately = true,
224
                    bool handle_logging = true
225
                    );
226

227
228
229
    ///
    /// Destructor
    ///
Jelte Jansen's avatar
Jelte Jansen committed
230
    /// The destructor automatically calls sendStopping(), which sends
231
232
    /// a message to the ConfigManager that this module is stopping
    ///
Jelte Jansen's avatar
Jelte Jansen committed
233
    virtual ~ModuleCCSession();
234

JINMEI Tatuya's avatar
JINMEI Tatuya committed
235
    /// Start receiving new commands and configuration changes asynchronously.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
236
237
238
239
240
241
242
243
244
    ///
    /// This method must be called only once, and only when the ModuleCCSession
    /// was constructed with start_immediately being false.  Otherwise
    /// CCSessionError will be thrown.
    ///
    /// As noted in the constructor, this method should be considered a short
    /// term workaround and will be removed in future.
    void start();

Jelte Jansen's avatar
Jelte Jansen committed
245
246
247
248
249
250
251
252
    /**
     * Optional optimization for checkCommand loop; returns true
     * if there are unhandled queued messages in the cc session.
     * (if either this is true or there is data on the socket found
     * by the select() call on getSocket(), run checkCommand())
     * 
     * @return true if there are unhandled queued messages
     */
253
    bool hasQueuedMsgs() const;
Jelte Jansen's avatar
Jelte Jansen committed
254

255
256
257
258
259
260
261
    /**
     * 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.
     */
262
    int checkCommand();
263
264
265
266
267
268
269
270
271

    /**
     * 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)
     */
272
273
274
275
276
    void setConfigHandler(isc::data::ConstElementPtr(*config_handler)(
                              isc::data::ConstElementPtr new_config))
    {
        config_handler_ = config_handler;
    }
277
278
279
280
281
282
283
284
285
286
287

    /**
     * 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.
     */
288
289
290
291
292
293
    void setCommandHandler(isc::data::ConstElementPtr(*command_handler)(
                               const std::string& command,
                               isc::data::ConstElementPtr args))
    {
        command_handler_ = command_handler;
    }
Jelte Jansen's avatar
Jelte Jansen committed
294

295
296
297
    /**
     * Gives access to the configuration values of a different module
     * Once this function has been called with the name of the specification
298
     * file or the module you want the configuration of, you can use
299
     * \c getRemoteConfigValue() to get a specific setting.
300
301
302
     * Changes are automatically updated, and you can specify handlers
     * for those changes. This function will subscribe to the relevant module
     * channel.
303
     *
304
305
306
     * This method must be called before calling the \c start() method on the
     * ModuleCCSession (it also implies the ModuleCCSession must have been
     * constructed with start_immediately being false).
307
     *
308
309
310
311
     * \param spec_name This specifies the module to add. It is either a
     *                  filename of the spec file to use or a name of module
     *                  (in case it's a module name, the spec data is
     *                  downloaded from the configuration manager, therefore
312
     *                  the configuration manager must know it). If
313
     *                  spec_is_filename is true (the default), then a
314
     *                  filename is assumed, otherwise a module name.
315
     * \param handler The handler functor called whenever there's a change.
316
     *                Called once initially from this function. May be NULL
317
318
319
     *                if you don't want any handler to be called and you're
     *                fine with requesting the data through
     *                getRemoteConfigValue() each time.
320
     *
321
     *                The handler should not throw, or it'll fall through and
322
323
     *                the exception will get into strange places, probably
     *                aborting the application.
324
     * \param spec_is_filename Says if spec_name is filename or module name.
325
326
327
     * \return The name of the module specified in the given specification
     *         file
     */
328
329
330
    typedef boost::function<void(const std::string&,
                                 isc::data::ConstElementPtr,
                                 const ConfigData&)> RemoteHandler;
331
    std::string addRemoteConfig(const std::string& spec_name,
332
                                RemoteHandler handler = RemoteHandler(),
333
                                bool spec_is_filename = true);
334
335
336
337

    /**
     * Removes the module with the given name from the remote config
     * settings. If the module was not added with \c addRemoteConfig(),
338
339
     * nothing happens. If there was a handler for this config, it is
     * removed as well.
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
     */
    void removeRemoteConfig(const std::string& module_name);

    /**
     * Returns the current configuration value for the given module
     * name at the given identifier. See \c ConfigData::getValue() for
     * more details.
     * Raises a ModuleCCSessionError if the module name is unknown
     * Raises a DataNotFoundError if the identifier does not exist
     * in the specification.
     *
     * \param module_name The name of the module to get a config value for
     * \param identifier The identifier of the config value
     * \return The configuration setting at the given identifier
     */
355
356
357
    isc::data::ConstElementPtr getRemoteConfigValue(
        const std::string& module_name,
        const std::string& identifier) const;
358
359
360
361
362
363
364
365
366

    /**
     * Send a message to the underlying CC session.
     * This has the same interface as isc::cc::Session::group_sendmsg()
     *
     * \param msg see isc::cc::Session::group_sendmsg()
     * \param group see isc::cc::Session::group_sendmsg()
     * \param instance see isc::cc::Session::group_sendmsg()
     * \param to see isc::cc::Session::group_sendmsg()
367
     * \param want_answer see isc::cc::Session::group_sendmsg()
368
369
370
371
     * \return see isc::cc::Session::group_sendmsg()
     */
    int groupSendMsg(isc::data::ConstElementPtr msg,
                     std::string group,
372
373
                     std::string instance = isc::cc::CC_INSTANCE_WILDCARD,
                     std::string to = isc::cc::CC_TO_WILDCARD,
374
375
                     bool want_answer = false) {
        return (session_.group_sendmsg(msg, group, instance, to, want_answer));
376
377
    };

378
379
380
381
382
383
384
385
386
387
388
    /// \brief Receive a message from the underlying CC session.
    /// This has the same interface as isc::cc::Session::group_recvmsg()
    ///
    /// NOTE: until #2804 is resolved this method wouldn't work except in
    /// very limited cases; don't try to use it until then.
    ///
    /// \param envelope see isc::cc::Session::group_recvmsg()
    /// \param msg see isc::cc::Session::group_recvmsg()
    /// \param nonblock see isc::cc::Session::group_recvmsg()
    /// \param seq see isc::cc::Session::group_recvmsg()
    /// \return see isc::cc::Session::group_recvmsg()
389
390
391
392
    bool groupRecvMsg(isc::data::ConstElementPtr& envelope,
                      isc::data::ConstElementPtr& msg,
                      bool nonblock = true,
                      int seq = -1) {
393
        return (session_.group_recvmsg(envelope, msg, nonblock, seq));
394
    }
395

396
397
    /// \brief Send a command message and wait for the answer.
    ///
398
399
400
    /// NOTE: until #2804 is resolved this method wouldn't work except in
    /// very limited cases; don't try to use it until then.
    ///
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
    /// This is mostly a convenience wrapper around groupSendMsg
    /// and groupRecvMsg, with some error handling.
    ///
    /// \param command Name of the command to call.
    /// \param group Name of the remote module to call the command on.
    /// \param instance Instance part of recipient address.
    /// \param to The lname to send it to. Can be used to override the
    ///     addressing and use a direct recipient.
    /// \param params Parameters for the command. Can be left NULL if
    ///     no parameters are needed.
    /// \return Return value of the successfull remote call. It can be
    ///     NULL if the remote command is void function (returns nothing).
    /// \throw RPCError if the call fails (for example when the other
    ///     side responds with error code).
    /// \throw RPCRecipientMissing if the recipient doesn't exist.
    /// \throw CCSessionError if some lower-level error happens (eg.
    ///     the response was malformed).
    isc::data::ConstElementPtr rpcCall(const std::string& command,
                                       const std::string& group,
                                       const std::string& instance =
                                           isc::cc::CC_INSTANCE_WILDCARD,
                                       const std::string& to =
                                           isc::cc::CC_TO_WILDCARD,
                                       const isc::data::ConstElementPtr&
                                           params =
                                           isc::data::ConstElementPtr());

428
    /// \brief Send a notification to subscribed users
429
    ///
430
    /// Send a notification message to all users subscribed to the given
431
432
    /// notification group.
    ///
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
433
434
435
436
437
438
    /// This method does not not block.
    ///
    /// See docs/design/ipc-high.txt for details about notifications and
    /// the format of messages sent.
    ///
    /// \throw CCSessionError for low-level communication errors.
439
    /// \param notification_group This parameter (indirectly) signifies what
440
    ///     users should receive the notification. Only the users that
441
442
    ///     subscribed to notifications on the same group receive it.
    /// \param name The name of the event to notify about (for example
443
    ///     `new_group_member`).
444
    /// \param params Other parameters that describe the event. This might
445
446
447
    ///     be, for example, the ID of the new member and the name of the
    ///     group. This can be any data element, but it is common for it to be
    ///     map.
448
449
450
451
452
    void notify(const std::string& notification_group,
                const std::string& name,
                const isc::data::ConstElementPtr& params =
                    isc::data::ConstElementPtr());

453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
    /// \brief Convenience version of rpcCall
    ///
    /// This is exactly the same as the previous version of rpcCall, except
    /// that the instance and to parameters are at their default. This
    /// allows to sending a command with parameters to a named module
    /// without long typing of the parameters.
    isc::data::ConstElementPtr rpcCall(const std::string& command,
                                       const std::string& group,
                                       const isc::data::ConstElementPtr&
                                           params)
    {
        return rpcCall(command, group, isc::cc::CC_INSTANCE_WILDCARD,
                       isc::cc::CC_TO_WILDCARD, params);
    }

468
469
470
471
472
    /// \brief Forward declaration of internal data structure.
    ///
    /// This holds information about one asynchronous request to receive
    /// a message. It is declared as public to allow declaring other derived
    /// types, but without showing the internal representation.
473
    class AsyncRecvRequest;
474
475

    /// \brief List of all requests for asynchronous reads.
476
    typedef std::list<AsyncRecvRequest> AsyncRecvRequests;
477
478

    /// \brief Identifier of single request for asynchronous read.
479
    typedef AsyncRecvRequests::iterator AsyncRecvRequestID;
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496

    /// \brief Callback which is called when an asynchronous receive finishes.
    ///
    /// This is the callback used by groupRecvMsgAsync() function. It is called
    /// when a matching message arrives. It receives following parameters when
    /// called:
    /// - The envelope of the message
    /// - The message itself
    /// - The ID of the request, as returned by corresponding groupRecvMsgAsync
    ///   call.
    ///
    /// It is possible to throw exceptions from the callback, but they will not
    /// be caught and they will get propagated out through the checkCommand()
    /// call. This, if not handled on higher level, will likely terminate the
    /// application. However, the ModuleCCSession internals will be in
    /// well-defined state after the call (both the callback and the message
    /// will be removed from the queues as already called).
497
498
499
500
    typedef boost::function3<void, const isc::data::ConstElementPtr&,
                             const isc::data::ConstElementPtr&,
                             const AsyncRecvRequestID&>
        AsyncRecvCallback;
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

    /// \brief Receive a message from the CC session asynchronously.
    ///
    /// This registers a callback which is called when a matching message
    /// is received. This message returns immediately.
    ///
    /// Once a matching message arrives, the callback is called with the
    /// envelope of the message, the message itself and the result of this
    /// function call (which might be useful for identifying which of many
    /// events the recipient is waiting for this is). This makes the callback
    /// used and is not called again even if a message that would match
    /// arrives later (this is a single-shot callback).
    ///
    /// The callback is never called from within this function. Even if there
    /// are queued messages, the callback would be called once checkCommand()
    /// is invoked (possibly from start() or the constructor).
    ///
Jelte Jansen's avatar
Jelte Jansen committed
518
    /// The matching is as follows. If is_reply is true, only replies are
519
520
    /// considered. In that case, if seq is -1, any reply is accepted. If
    /// it is something else than -1, only the reply with matching seq is
Jelte Jansen's avatar
Jelte Jansen committed
521
    /// taken. This may be used to receive replies to commands
522
523
524
525
526
    /// asynchronously.
    ///
    /// In case the is_reply is false, the function looks for command messages.
    /// The seq parameter is ignored, but the recipient one is considered. If
    /// it is an empty string, any command is taken. If it is non-empty, only
527
    /// commands addressed to the recipient channel (eg. group - instance is
Jelte Jansen's avatar
Jelte Jansen committed
528
    /// ignored for now) are taken. This can be used to receive foreign commands
529
530
531
    /// or notifications. In such case, it might be desirable to call the
    /// groupRecvMsgAsync again from within the callback, to receive any future
    /// commands or events of the same type.
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
    ///
    /// The interaction with other receiving functions is slightly complicated.
    /// The groupRecvMsg call takes precedence. If the message matches its
    /// parameters, it steals the message and no callback matching it as well
    /// is called. Then, all the queued asynchronous receives are considered,
    /// with the oldest active ones taking precedence (they work as FIFO).
    /// If none of them matches, generic command and config handling takes
    /// place. If it is not handled by that, the message is dropped. However,
    /// it is better if there's just one place that wants to receive each given
    /// message.
    ///
    /// \exception std::bad_alloc if there isn't enough memory to store the
    ///     callback.
    /// \param callback is the function to be called when a matching message
    ///     arrives.
    /// \param is_reply specifies if the desired message should be a reply or
    ///     a command.
    /// \param seq specifies the reply sequence number in case a reply is
    ///     desired. The default -1 means any reply is OK.
    /// \param recipient is the CC channel to which the command should be
    ///     addressed to match (in case is_reply is false). Empty means any
    ///     command is good one.
    /// \return An identifier of the request. This will be passed to the
    ///     callback or can be used to cancel the request by cancelAsyncRecv.
556
    /// \todo Decide what to do with instance and what was it meant for anyway.
557
    AsyncRecvRequestID groupRecvMsgAsync(const AsyncRecvCallback& callback,
558
                                         bool is_reply, int seq = -1,
559
560
561
                                         const std::string& recipient =
                                         std::string());

562
563
564
565
566
567
568
569
570
571
572
573
574
575
    /// \brief Removes yet unused request for asynchronous receive.
    ///
    /// This function cancels a request previously queued by
    /// groupRecvMsgAsync(). You may use it only before the callback was
    /// already triggered. If you call it with an ID of callback that
    /// already happened or was already canceled, the behaviour is undefined
    /// (but something like a crash is very likely, as the function removes
    /// an item from a list and this would be removing it from a list that
    /// does not contain the item).
    ///
    /// It is important to cancel requests that are no longer going to happen
    /// for some reason, as the request would occupy memory forever.
    ///
    /// \param id The id of request as returned by groupRecvMsgAsync.
576
577
    void cancelAsyncRecv(const AsyncRecvRequestID& id);

578
579
580
581
582
583
584
585
586
587
588
589
590
591
    /// \brief Subscribe to a group
    ///
    /// Wrapper around the CCSession::subscribe.
    void subscribe(const std::string& group) {
        session_.subscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
    }

    /// \brief Unsubscribe from a group.
    ///
    /// Wrapper around the CCSession::unsubscribe.
    void unsubscribe(const std::string& group) {
        session_.unsubscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
    }

JINMEI Tatuya's avatar
JINMEI Tatuya committed
592
private:
593
    ModuleSpec readModuleSpecification(const std::string& filename);
594
    void startCheck();
595
    void sendStopping();
596
597
598
599
600
601
602
603
604
605
606
607
608
609
    /// \brief Check if the message is wanted by asynchronous read
    ///
    /// It checks if any of the previously queued requests match
    /// the message. If so, the callback is dispatched and removed.
    ///
    /// \param envelope The envelope of the message.
    /// \param msg The actual message data.
    /// \return True if the message was used for a callback, false
    ///     otherwise.
    bool checkAsyncRecv(const data::ConstElementPtr& envelope,
                        const data::ConstElementPtr& msg);
    /// \brief Checks if a message with this envelope matches the request
    bool requestMatch(const AsyncRecvRequest& request,
                      const data::ConstElementPtr& envelope) const;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
610
611

    bool started_;
612
    std::string module_name_;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
613
    isc::cc::AbstractSession& session_;
614
    ModuleSpec module_specification_;
615
    AsyncRecvRequests async_recv_requests_;
616
617
    isc::data::ConstElementPtr handleConfigUpdate(
        isc::data::ConstElementPtr new_config);
618

Jelte Jansen's avatar
Jelte Jansen committed
619
620
621
    isc::data::ConstElementPtr checkConfigUpdateCommand(
        const std::string& target_module,
        isc::data::ConstElementPtr arg);
622

Jelte Jansen's avatar
Jelte Jansen committed
623
624
625
    isc::data::ConstElementPtr checkModuleCommand(
        const std::string& cmd_str,
        const std::string& target_module,
626
        isc::data::ConstElementPtr arg) const;
Jelte Jansen's avatar
Jelte Jansen committed
627

628
629
630
631
632
    isc::data::ConstElementPtr(*config_handler_)(
        isc::data::ConstElementPtr new_config);
    isc::data::ConstElementPtr(*command_handler_)(
        const std::string& command,
        isc::data::ConstElementPtr args);
633
634

    std::map<std::string, ConfigData> remote_module_configs_;
635
636
    std::map<std::string, RemoteHandler> remote_module_handlers_;

637
    void updateRemoteConfig(const std::string& module_name,
638
                            isc::data::ConstElementPtr new_config);
639

640
    ModuleSpec fetchRemoteSpec(const std::string& module, bool is_filename);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
641
642
};

643
644
645
646
647
648
649
650
651
652
/// \brief Default handler for logging config updates
///
/// When CCSession is initialized with handle_logging set to true,
/// this callback will be used to update the logger when a configuration
/// change comes in.
///
/// This function updates the (global) loggers by initializing a
/// LoggerManager and passing the settings as specified in the given
/// configuration update.
///
653
/// \param module_name The name of the module
654
655
656
657
/// \param new_config The modified configuration values
/// \param config_data The full config data for the (remote) logging
///                    module.
void
658
default_logconfig_handler(const std::string& module_name,
659
660
661
                          isc::data::ConstElementPtr new_config,
                          const ConfigData& config_data);

662
663
664
665

/// \brief Returns the loggers related to this module
///
/// This function does two things;
666
/// - it drops the configuration parts for loggers for other modules.
667
668
/// - it replaces the '*' in the name of the loggers by the name of
///   this module, but *only* if the expanded name is not configured
669
///   explicitly.
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
///
/// Examples: if this is the module b10-resolver,
/// For the config names ['*', 'b10-auth']
/// The '*' is replaced with 'b10-resolver', and this logger is used.
/// 'b10-auth' is ignored (of course, it will not be in the b10-auth
/// module).
///
/// For ['*', 'b10-resolver']
/// The '*' is ignored, and only 'b10-resolver' is used.
///
/// For ['*.reslib', 'b10-resolver']
/// Or ['b10-resolver.reslib', '*']
/// Both are used, where the * will be expanded to b10-resolver
///
/// \note This is a public function at this time, but mostly for
/// the purposes of testing. Once we can directly test what loggers
/// are running, this function may be moved to the unnamed namespace
///
/// \param loggers the original 'loggers' config list
Jelte Jansen's avatar
Jelte Jansen committed
689
690
/// \return ListElement containing only loggers relevant for this
///         module, where * is replaced by the root logger name
691
692
693
694
695
696
isc::data::ConstElementPtr
getRelatedLoggers(isc::data::ConstElementPtr loggers);

} // namespace config

} // namespace isc
697
#endif // CCSESSION_H
JINMEI Tatuya's avatar
JINMEI Tatuya committed
698
699
700
701

// Local Variables:
// mode: c++
// End: