BIND 10 master, updated. 95218da8e5bfd78889639e7cac68b4afcd44d264 Merge #2768

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Mar 11 09:39:17 UTC 2013


The branch, master has been updated
       via  95218da8e5bfd78889639e7cac68b4afcd44d264 (commit)
       via  c32bfa79b248fb9351dafc853ecc0a18ca2e3a66 (commit)
       via  8bab20ff2358dfcc7d7f09520688b9a07bbc1ea3 (commit)
       via  e8757a6861d8328cf7f8f2bd815af3a6461cfdc9 (commit)
       via  83966d1e3ede61d6e71a26d179e2d2d30b4655df (commit)
       via  1e0c42db90fa4f02586da442501cf1669a93db04 (commit)
       via  e589380dcc531fb2c3d8bf87e0e2fed8ba09270f (commit)
       via  845ffd35d10646345dc1f534ad725cada568fa5c (commit)
       via  ce19b150c67834a91d7742f362a175904172a7d7 (commit)
       via  2fb30723fa35fa5a9ffae03b0715650a76a5f20a (commit)
      from  6067533e5c4ebded8260ef4b97f2709868bb2799 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 95218da8e5bfd78889639e7cac68b4afcd44d264
Merge: 6067533 c32bfa7
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Mon Mar 11 09:50:53 2013 +0100

    Merge #2768
    
    The rpcCall method in C++

-----------------------------------------------------------------------

Summary of changes:
 src/lib/cc/cc_messages.mes                  |    2 +-
 src/lib/cc/proto_defs.cc                    |    2 +-
 src/lib/cc/session.cc                       |    2 +-
 src/lib/config/ccsession.cc                 |   24 +++++++-
 src/lib/config/ccsession.h                  |   79 ++++++++++++++++++++++++++-
 src/lib/config/config_messages.mes          |    4 ++
 src/lib/config/tests/ccsession_unittests.cc |   52 ++++++++++++++++++
 src/lib/config/tests/fake_session.cc        |    9 ++-
 src/lib/config/tests/fake_session.h         |    3 +-
 9 files changed, 167 insertions(+), 10 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/cc/cc_messages.mes b/src/lib/cc/cc_messages.mes
index b561784..9be9c7c 100644
--- a/src/lib/cc/cc_messages.mes
+++ b/src/lib/cc/cc_messages.mes
@@ -37,7 +37,7 @@ socket listed in the output.
 This debug message indicates that the connection was successfully made, this
 should follow CC_ESTABLISH.
 
-% CC_GROUP_RECEIVE trying to receive a message
+% CC_GROUP_RECEIVE trying to receive a message with seq %1
 Debug message, noting that a message is expected to come over the command
 channel.
 
diff --git a/src/lib/cc/proto_defs.cc b/src/lib/cc/proto_defs.cc
index 5eb8575..72ca41b 100644
--- a/src/lib/cc/proto_defs.cc
+++ b/src/lib/cc/proto_defs.cc
@@ -38,8 +38,8 @@ const char* const CC_COMMAND_SEND = "send";
 const char* const CC_TO_WILDCARD = "*";
 const char* const CC_INSTANCE_WILDCARD = "*";
 // Reply codes
-const int CC_REPLY_SUCCESS = 0;
 const int CC_REPLY_NO_RECPT = -1;
+const int CC_REPLY_SUCCESS = 0;
 
 }
 }
diff --git a/src/lib/cc/session.cc b/src/lib/cc/session.cc
index c2f39ed..f5edcf7 100644
--- a/src/lib/cc/session.cc
+++ b/src/lib/cc/session.cc
@@ -498,7 +498,7 @@ bool
 Session::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
                        bool nonblock, int seq)
 {
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_RECEIVE);
+    LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_RECEIVE).arg(seq);
     bool result(recvmsg(envelope, msg, nonblock, seq));
     if (result) {
         LOG_DEBUG(logger, DBG_TRACE_DETAILED, CC_GROUP_RECEIVED).
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 378f2b4..78432ab 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -32,7 +32,7 @@
 #include <boost/foreach.hpp>
 
 #include <cc/data.h>
-#include <module_spec.h>
+#include <config/module_spec.h>
 #include <cc/session.h>
 #include <exceptions/exceptions.h>
 
@@ -857,5 +857,27 @@ ModuleCCSession::cancelAsyncRecv(const AsyncRecvRequestID& id) {
     async_recv_requests_.erase(id);
 }
 
+ConstElementPtr
+ModuleCCSession::rpcCall(const std::string &command, const std::string &group,
+                         const std::string &instance, const std::string &to,
+                         const ConstElementPtr &params)
+{
+    ConstElementPtr command_el(createCommand(command, params));
+    const int seq = groupSendMsg(command_el, group, instance, to, true);
+    ConstElementPtr env, answer;
+    LOG_DEBUG(config_logger, DBGLVL_TRACE_DETAIL, CONFIG_RPC_SEQ).arg(command).
+        arg(group).arg(seq);
+    groupRecvMsg(env, answer, true, seq);
+    int rcode;
+    const ConstElementPtr result(parseAnswer(rcode, answer));
+    if (rcode == isc::cc::CC_REPLY_NO_RECPT) {
+        isc_throw(RPCRecipientMissing, result);
+    } else if (rcode != isc::cc::CC_REPLY_SUCCESS) {
+        isc_throw_1(RPCError, result, rcode);
+    } else {
+        return (result);
+    }
+}
+
 }
 }
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index b4a44d0..2f8dd78 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -20,6 +20,7 @@
 
 #include <cc/session.h>
 #include <cc/data.h>
+#include <cc/proto_defs.h>
 
 #include <string>
 #include <list>
@@ -146,6 +147,34 @@ public:
         isc::Exception(file, line, what) {}
 };
 
+/// \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)
+    {}
+
+    /// \brief The error code for the error.
+    int rcode() const {
+        return (rcode_);
+    }
+private:
+    const int rcode_;
+};
+
+/// \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)
+    {}
+};
+
 ///
 /// \brief This module keeps a connection to the command channel,
 /// holds configuration information, and handles messages from
@@ -335,13 +364,15 @@ public:
      * \param group see isc::cc::Session::group_sendmsg()
      * \param instance see isc::cc::Session::group_sendmsg()
      * \param to see isc::cc::Session::group_sendmsg()
+     * \param want_answer see isc::cc::Session::group_sendmsg()
      * \return see isc::cc::Session::group_sendmsg()
      */
     int groupSendMsg(isc::data::ConstElementPtr msg,
                      std::string group,
                      std::string instance = "*",
-                     std::string to = "*") {
-        return (session_.group_sendmsg(msg, group, instance, to));
+                     std::string to = "*",
+                     bool want_answer = false) {
+        return (session_.group_sendmsg(msg, group, instance, to, want_answer));
     };
 
     /**
@@ -361,6 +392,50 @@ public:
         return (session_.group_recvmsg(envelope, msg, nonblock, seq));
     };
 
+    /// \brief Send a command message and wait for the answer.
+    ///
+    /// 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());
+
+    /// \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);
+    }
+
     /// \brief Forward declaration of internal data structure.
     ///
     /// This holds information about one asynchronous request to receive
diff --git a/src/lib/config/config_messages.mes b/src/lib/config/config_messages.mes
index 552256c..6735b16 100644
--- a/src/lib/config/config_messages.mes
+++ b/src/lib/config/config_messages.mes
@@ -94,3 +94,7 @@ manager.
 % CONFIG_OPEN_FAIL error opening %1: %2
 There was an error opening the given file. The reason for the failure
 is included in the message.
+
+% CONFIG_RPC_SEQ RPC call %1 to %2 with seq %3
+Debug message, saying there's a RPC call of given command to given module. It
+has internal sequence number as listed in the message.
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 93307ca..c11cd24 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -58,6 +58,28 @@ protected:
         // ok answer.
         session.getMessages()->add(createAnswer());
     }
+    ConstElementPtr rpcCheck(const std::string& reply) {
+        ModuleCCSession mccs(ccspecfile("spec1.spec"), session, NULL, NULL,
+                             false, false);
+        // Prepare the answer beforehand, it'll block until it gets one
+        const ConstElementPtr reply_el(el(reply));
+        session.getMessages()->add(reply_el);
+        const ConstElementPtr
+            result(mccs.rpcCall("test", "Spec2",
+                                el("{\"param1\": \"Param 1\","
+                                   "\"param2\": \"Param 2\"}")));
+        const ConstElementPtr
+            request(el("[\"Spec2\", \"*\", {"
+                       "  \"command\": [\"test\", {"
+                       "    \"param1\": \"Param 1\","
+                       "    \"param2\": \"Param 2\""
+                       "}]}, -1, true]"));
+        // The 0th one is from the initialization, to ConfigManager.
+        // our is the 1st.
+        EXPECT_TRUE(request->equals(*session.getMsgQueue()->get(1))) <<
+            session.getMsgQueue()->get(1)->toWire();
+        return (result);
+    }
     ~CCSessionTest() {
         isc::log::setRootLoggerName(root_name);
     }
@@ -65,6 +87,36 @@ protected:
     const std::string root_name;
 };
 
+// Test we can send an RPC (command) and get an answer. The answer is success
+// in this case.
+TEST_F(CCSessionTest, rpcCallSuccess) {
+    const ConstElementPtr result =
+        rpcCheck("{\"result\": [0, {\"Hello\": \"a\"}]}");
+    EXPECT_TRUE(el("{\"Hello\": \"a\"}")->equals(*result));
+}
+
+// Test success of RPC, but the answer is empty (eg. a void function on the
+// remote side).
+TEST_F(CCSessionTest, rpcCallSuccessNone) {
+    EXPECT_FALSE(rpcCheck("{\"result\": [0]}"));
+}
+
+// Test it successfully raises CCSessionError if the answer is malformed.
+TEST_F(CCSessionTest, rpcCallMalformedAnswer) {
+    EXPECT_THROW(rpcCheck("[\"Nonsense\"]"), CCSessionError);
+}
+
+// Test it raises exception when the remote side reports an error
+TEST_F(CCSessionTest, rpcCallError) {
+    EXPECT_THROW(rpcCheck("{\"result\": [1, \"Error\"]}"), RPCError);
+}
+
+// Test it raises exception when the remote side doesn't exist
+TEST_F(CCSessionTest, rpcNoRecpt) {
+    EXPECT_THROW(rpcCheck("{\"result\": [-1, \"Error\"]}"),
+                 RPCRecipientMissing);
+}
+
 TEST_F(CCSessionTest, createAnswer) {
     ConstElementPtr answer;
     answer = createAnswer();
diff --git a/src/lib/config/tests/fake_session.cc b/src/lib/config/tests/fake_session.cc
index 4c19963..e6d569e 100644
--- a/src/lib/config/tests/fake_session.cc
+++ b/src/lib/config/tests/fake_session.cc
@@ -183,12 +183,12 @@ FakeSession::unsubscribe(std::string group, std::string instance) {
 
 int
 FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
-                           std::string to, std::string, bool)
+                           std::string to, std::string, bool want_answer)
 {
     if (throw_on_send_) {
         isc_throw(Exception, "Throw on send is set in FakeSession");
     }
-    addMessage(msg, group, to);
+    addMessage(msg, group, to, -1, want_answer);
     return (1);
 }
 
@@ -231,13 +231,16 @@ FakeSession::getFirstMessage(std::string& group, std::string& to) const {
 
 void
 FakeSession::addMessage(ConstElementPtr msg, const std::string& group,
-                        const std::string& to, int seq)
+                        const std::string& to, int seq, bool want_answer)
 {
     ElementPtr m_el = Element::createList();
     m_el->add(Element::create(group));
     m_el->add(Element::create(to));
     m_el->add(msg);
     m_el->add(Element::create(seq));
+    if (want_answer) {
+        m_el->add(Element::create(want_answer));
+    }
     if (!msg_queue_) {
         msg_queue_ = Element::createList();
     }
diff --git a/src/lib/config/tests/fake_session.h b/src/lib/config/tests/fake_session.h
index 0dbaadb..8a564a8 100644
--- a/src/lib/config/tests/fake_session.h
+++ b/src/lib/config/tests/fake_session.h
@@ -75,7 +75,8 @@ public:
     isc::data::ConstElementPtr getFirstMessage(std::string& group,
                                                std::string& to) const;
     void addMessage(isc::data::ConstElementPtr, const std::string& group,
-                    const std::string& to, int seq = -1);
+                    const std::string& to, int seq = -1,
+                    bool want_answer = false);
     bool haveSubscription(const std::string& group,
                           const std::string& instance);
     bool haveSubscription(const isc::data::ConstElementPtr group,



More information about the bind10-changes mailing list