]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3357] Merged and squashed 4o6 branch of https://github.com/gnocuil/kea.git
authorMarcin Siodelski <marcin@isc.org>
Wed, 10 Sep 2014 06:44:03 +0000 (08:44 +0200)
committerMarcin Siodelski <marcin@isc.org>
Wed, 10 Sep 2014 06:44:03 +0000 (08:44 +0200)
This contains an initial implementation of the DHCPv4 over DHCPv6 protocol
(RFC7341) from Tsinghua University.

25 files changed:
src/bin/dhcp4/dhcp4.spec
src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp6/dhcp6.spec
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/json_config_parser.cc
src/lib/dhcp/Makefile.am
src/lib/dhcp/dhcp6.h
src/lib/dhcp/pkt4o6.cc [new file with mode: 0644]
src/lib/dhcp/pkt4o6.h [new file with mode: 0644]
src/lib/dhcp/tests/Makefile.am
src/lib/dhcp/tests/pkt4o6_unittest.cc [new file with mode: 0644]
src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/dhcp4o6_ipc.cc [new file with mode: 0644]
src/lib/dhcpsrv/dhcp4o6_ipc.h [new file with mode: 0644]
src/lib/dhcpsrv/tests/Makefile.am
src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc [new file with mode: 0644]
src/lib/util/Makefile.am
src/lib/util/ipc.h [new file with mode: 0644]
src/lib/util/tests/Makefile.am
src/lib/util/tests/ipc_unittest.cc [new file with mode: 0644]

index c0918bbc0dfb22103b5c61b257d707a2ae5a3c17..1486b0e4f911d36d3c1722c9f4b060b7c5d16e5d 100644 (file)
             },
         ]
       },
+      { "item_name": "4o6-enable",
+        "item_type": "boolean",
+        "item_optional": true,
+        "item_default": false,
+        "item_description": "Enable DHCPv4 over DHCPv6 function"
+      },
 
     ],
     "commands": [
index 46a43ca0ab09b96cd5ab3ce8bc2cf989a2a089bf..87fc5fa8d246725aa2b01bddd220f717a9de01f4 100644 (file)
@@ -383,3 +383,13 @@ This debug message indicates that the message type carried in DHCPv4 option
 53 is valid but the message will not be processed by the server. This includes
 messages being normally sent by the server to the client, such as Offer, ACK,
 NAK etc.
+
+% DHCP4_IPC_CONSTRUCT_ERROR failed to create DHCP4o6IPC in DHCPv4 server
+This error message indicates that the construction of a
+DHCP4o6 IPC within the DHCPv4 server has failed.
+As a result, DHCPv4 over DHCPv6 function is disabled.
+The server will continue running its regular DHCPv4 function.
+
+% DHCP4_IPC_SEND_ERROR failed to send message through DHCP4o6IPC
+This error message indicates that the DHCP4o6IPC failed to send
+a packet through unix socket.
index 78ac0a7198d6dca7af690770e77384b92ac1d241..8b51fe754d1b234044fffef4f41e32ac84467f38 100644 (file)
@@ -155,9 +155,20 @@ Dhcpv4Srv::run() {
         Pkt4Ptr query;
         Pkt4Ptr rsp;
 
-        try {
-            query = receivePacket(timeout);
+        // 4o6
+        bool dhcp4o6Request = false;
+        if (!query && ipc_ && !ipc_->empty()) {
+            query = ipc_->pop()->getPkt4();
+            dhcp4o6Request = true;
+
+            //set Pkt4's localAddr according to U flag in Pkt6's transid field
+            ipc_->currentPkt4o6()->setPkt4LocalAddr();
+        }
 
+        try {
+            if (!query) {
+                query = receivePacket(timeout);
+            }
         } catch (const SignalInterruptOnSelect) {
             // Packet reception interrupted because a signal has been received.
             // This is not an error because we might have received a SIGTERM,
@@ -424,7 +435,16 @@ Dhcpv4Srv::run() {
                       DHCP4_RESPONSE_DATA)
                 .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 
-            sendPacket(rsp);
+            if (ipc_ && dhcp4o6Request) {//4o6
+                try {
+                    Pkt4o6Ptr rsp4o6(new Pkt4o6(ipc_->currentPkt4o6(), rsp));
+                    ipc_->sendPkt4o6(rsp4o6);
+                } catch (const Exception& ex) {
+                    LOG_ERROR(dhcp4_logger, DHCP4_IPC_SEND_ERROR).arg(ex.what());
+                }
+            } else {
+                sendPacket(rsp);
+            }
         } catch (const std::exception& e) {
             LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL)
                 .arg(e.what());
@@ -1995,6 +2015,30 @@ Dhcpv4Srv::d2ClientErrorHandler(const
     CfgMgr::instance().getD2ClientMgr().suspendUpdates();
 }
 
+void
+Dhcpv4Srv::enable4o6() {
+    /// init DHCP4o6 IPC
+    try {
+        ipc_ = DHCP4o6IPCPtr(new DHCP4o6IPC("DHCPv4_over_DHCPv6_v6tov4",
+                                            "DHCPv4_over_DHCPv6_v4tov6"));
+    } catch (const Exception &e) {
+        LOG_ERROR(dhcp4_logger, DHCP4_IPC_CONSTRUCT_ERROR).arg(e.what());
+        ipc_ = DHCP4o6IPCPtr();
+    }
+    if (!ipc_)
+        return;
+    IfaceMgr::instance().addExternalSocket(ipc_->getSocket(),
+                                boost::bind(&DHCP4o6IPC::recvPkt4o6, ipc_));
+}
+
+void
+Dhcpv4Srv::disable4o6() {
+    if (!ipc_)
+        return;
+    IfaceMgr::instance().deleteExternalSocket(ipc_->getSocket());
+    ipc_ = boost::shared_ptr<DHCP4o6IPC>();
+}
+
 std::string
 Daemon::getVersion(bool extended) {
     std::stringstream tmp;
index 1ccc0ede4bb9a0981c5ecd0c35ed13b6eca1f4a7..ee35e1cb01181b5ec309c5515eaec5c3cf7de3a7 100644 (file)
@@ -26,6 +26,7 @@
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/alloc_engine.h>
 #include <hooks/callout_handle.h>
+#include <dhcpsrv/dhcp4o6_ipc.h>
 #include <dhcpsrv/daemon.h>
 
 #include <boost/noncopyable.hpp>
@@ -173,6 +174,17 @@ public:
     virtual void d2ClientErrorHandler(const dhcp_ddns::
                                       NameChangeSender::Result result,
                                       dhcp_ddns::NameChangeRequestPtr& ncr);
+                                      
+    /// @brief Enable DHCPv4 over DHCPv6 function
+    ///
+    /// Calling this method enables 4o6 function in dhcpv4 server
+    void enable4o6();
+    
+    /// @brief Disable DHCPv4 over DHCPv6 function
+    ///
+    /// Calling this method disables 4o6 function in dhcpv4 server
+    void disable4o6();
+    
 protected:
 
     /// @name Functions filtering and sanity-checking received messages.
@@ -692,6 +704,9 @@ private:
     int hook_index_pkt4_receive_;
     int hook_index_subnet4_select_;
     int hook_index_pkt4_send_;
+    
+    /// IPC used for communation with dhcp4_srv (for RFC7341).
+    DHCP4o6IPCPtr ipc_;
 };
 
 }; // namespace isc::dhcp
index 4cdde0fe6c288d59cca8fa366e555a6b792dc9ac..cbbef76be2502615165d88c111af0aba3cbd739f 100644 (file)
@@ -23,6 +23,7 @@
 #include <dhcpsrv/option_space_container.h>
 #include <util/encode/hex.h>
 #include <util/strutil.h>
+#include <dhcp4/dhcp4_srv.h>
 
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
@@ -461,7 +462,8 @@ namespace dhcp {
         parser = new DbAccessParser(config_id, *globalContext());
     } else if (config_id.compare("hooks-libraries") == 0) {
         parser = new HooksLibrariesParser(config_id);
-    } else if (config_id.compare("echo-client-id") == 0) {
+    } else if ((config_id.compare("echo-client-id") == 0) ||
+               (config_id.compare("4o6-enable") == 0)) {
         parser = new BooleanParser(config_id, globalContext()->boolean_values_);
     } else if (config_id.compare("dhcp-ddns") == 0) {
         parser = new D2ClientConfigParser(config_id);
@@ -489,7 +491,7 @@ void commitGlobalOptions() {
 }
 
 isc::data::ConstElementPtr
-configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
+configureDhcp4Server(Dhcpv4Srv& srv, isc::data::ConstElementPtr config_set) {
     if (!config_set) {
         ConstElementPtr answer = isc::config::createAnswer(1,
                                  string("Can't parse NULL config"));
@@ -571,6 +573,17 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
                 // but we need it so as the subnet6 parser can access the
                 // parsed data.
                 parser->commit();
+                if (config_pair.first == "4o6-enable") {
+                    try {
+                        if (config_pair.second->boolValue()) {
+                            srv.enable4o6();
+                        } else {
+                            srv.disable4o6();
+                        }
+                    } catch (const isc::Exception& e) {
+                        //TODO: do someting
+                    }
+                }
             }
         }
 
index 174170f850ebc77dc10e4e4369c94b5006d6a02b..b82f418891af6ba06bb9a13fc89ed4e3b3345883 100644 (file)
             },
         ]
       },
+      { "item_name": "4o6-enable",
+        "item_type": "boolean",
+        "item_optional": true,
+        "item_default": false,
+        "item_description": "Enable DHCPv4 over DHCPv6 function"
+      },
+      
     ],
     "commands": [
         {
index b99370109d0a590562ba1512c10c7f295ff3e57c..840254a68709d000a4ecefa4a920d4824988ad1e 100644 (file)
@@ -580,3 +580,13 @@ This warning message is printed when client attempts to release an prefix
 lease, but no such lease is known by the server. See the explanation
 of the status code DHCP6_UNKNOWN_RENEW_PD for possible reasons for
 such behavior.
+
+% DHCP6_IPC_CONSTRUCT_ERROR failed to create DHCP4o6IPC in DHCPv6 server
+This error message indicates that the construction of a
+DHCP4o6 IPC within the DHCPv6 server has failed.
+As a result, DHCPv4 over DHCPv6 function is disabled.
+The server will continue running its regular DHCPv6 function.
+
+% DHCP6_IPC_SEND_ERROR failed to send message through DHCP4o6IPC
+This error message indicates that the DHCP4o6IPC failed to send
+a packet through unix socket.
index 9e960f322e825599d18f4825df987d3ce17245f1..47ccb041b56342e1c47c462c56ea0249ce05ebc3 100644 (file)
@@ -45,6 +45,7 @@
 #include <util/encode/hex.h>
 #include <util/io_utilities.h>
 #include <util/range_utilities.h>
+#include <dhcp/pkt4o6.h> //used by DHCP4o6
 
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
@@ -157,7 +158,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
             ->cfg_iface_.setFamily(CfgIface::V6);
 
         /// @todo call loadLibraries() when handling configuration changes
-
+        
     } catch (const std::exception &e) {
         LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what());
         return;
@@ -245,10 +246,18 @@ bool Dhcpv6Srv::run() {
         // client's message and server's response
         Pkt6Ptr query;
         Pkt6Ptr rsp;
+        
+        // 4o6
+        bool dhcp4o6Response = false;
+        if (!query && ipc_ && !ipc_->empty()) {
+            query = ipc_->pop()->getPkt6();
+            dhcp4o6Response = true;
+        }
 
         try {
-            query = receivePacket(timeout);
-
+            if (!query) {
+                query = receivePacket(timeout);
+            }
         } catch (const SignalInterruptOnSelect) {
             // Packet reception interrupted because a signal has been received.
             // This is not an error because we might have received a SIGTERM,
@@ -406,6 +415,13 @@ bool Dhcpv6Srv::run() {
             case DHCPV6_INFORMATION_REQUEST:
                 rsp = processInfRequest(query);
                 break;
+                
+            case DHCPV4_QUERY:
+                if (dhcp4o6Response)
+                    rsp = processDHCPv4Response(query);
+                else
+                    processDHCPv4Query(query);
+                break;
 
             default:
                 // We received a packet type that we do not recognize.
@@ -2435,6 +2451,59 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
     return reply;
 }
 
+void
+Dhcpv6Srv::processDHCPv4Query(const Pkt6Ptr& query) {
+    try {
+        Pkt4o6Ptr pkt4o6(new Pkt4o6(query));
+        ipc_->sendPkt4o6(pkt4o6);
+    } catch (const Exception& ex) {
+        LOG_ERROR(dhcp6_logger, DHCP6_IPC_SEND_ERROR).arg(ex.what());
+    }
+}
+
+Pkt6Ptr
+Dhcpv6Srv::processDHCPv4Response(const Pkt6Ptr& query) {
+    Pkt6Ptr reply = Pkt6Ptr(new Pkt6(DHCPV4_RESPONSE, query->getTransid()));
+
+    appendRequestedOptions(query, reply);//TODO: should we remove this?
+        
+    OptionPtr option(new Option(Option::V6,
+                                OPTION_DHCPV4_MSG,
+                                ipc_->currentPkt4o6()->getDHCPv4MsgOption()));
+    reply->addOption(option);
+
+    //Add relay info
+    if (!query->relay_info_.empty()) {
+        reply->copyRelayInfo(query);
+    }
+    return reply;
+}
+
+
+void
+Dhcpv6Srv::enable4o6() {
+    /// init DHCP4o6 IPC
+    try {
+        ipc_ = DHCP4o6IPCPtr(new DHCP4o6IPC("DHCPv4_over_DHCPv6_v4tov6",
+                                            "DHCPv4_over_DHCPv6_v6tov4"));
+    } catch (const Exception &e) {
+        LOG_ERROR(dhcp6_logger, DHCP6_IPC_CONSTRUCT_ERROR).arg(e.what());
+        ipc_ = DHCP4o6IPCPtr();
+    }
+    if (!ipc_)
+        return;
+    IfaceMgr::instance().addExternalSocket(ipc_->getSocket(),
+                                boost::bind(&DHCP4o6IPC::recvPkt4o6, ipc_));
+}
+
+void
+Dhcpv6Srv::disable4o6() {
+    if (!ipc_)
+        return;
+    IfaceMgr::instance().deleteExternalSocket(ipc_->getSocket());
+    ipc_ = boost::shared_ptr<DHCP4o6IPC>();
+}
+
 size_t
 Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
                          const std::string& option_space,
index af355c0d7a140628ae55ddbc9989d1d4d6093c7c..bed8e1e29060e754df319fd9b8ef9c7099504fe9 100644 (file)
@@ -27,6 +27,7 @@
 #include <dhcpsrv/d2_client_mgr.h>
 #include <dhcpsrv/subnet.h>
 #include <hooks/callout_handle.h>
+#include <dhcpsrv/dhcp4o6_ipc.h> //4o6
 #include <dhcpsrv/daemon.h>
 
 #include <iostream>
@@ -130,6 +131,16 @@ public:
                                       NameChangeSender::Result result,
                                       dhcp_ddns::NameChangeRequestPtr& ncr);
 
+    /// @brief Enable DHCPv4 over DHCPv6 function
+    ///
+    /// Calling this method enables 4o6 function in dhcpv6 server
+    void enable4o6();
+    
+    /// @brief Disable DHCPv4 over DHCPv6 function
+    ///
+    /// Calling this method disables 4o6 function in dhcpv6 server
+    void disable4o6();
+
 protected:
 
     /// @brief Compare received server id with our server id
@@ -244,7 +255,25 @@ protected:
     ///
     /// @param infRequest message received from client
     Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
+    
+    /// @brief Processing incoming DHCPv4-QUERY messages.
+    ///
+    /// Processes incoming DHCPv4-QUERY messages (DHCPv4 over DHCPv6) from clients.
+    /// Payload DHCPv4 message from clients will be sent to dhcp4_srv through ipc.
+    ///
+    /// @param query DHCPv4-QUERY message received from client
+    void processDHCPv4Query(const Pkt6Ptr& query);
 
+    /// @brief Processing DHCPv4 response from dhcpv4 server.
+    ///
+    /// Processes DHCPv4 response from dhcp4_srv (used by DHCPv4 over DHCPv6).
+    /// DHCPv4 response from dhcp4_srv will result a DHCPv4-RESPONSE packet and
+    /// send back to the client.
+    ///
+    /// @param query Raw DHCPv4 message and original DHCPv6 information
+    /// received from dhcp4_srv.
+    Pkt6Ptr processDHCPv4Response(const Pkt6Ptr& query);
+    
     /// @brief Creates status-code option.
     ///
     /// @param code status code value (see RFC3315)
@@ -669,6 +698,9 @@ private:
 
     /// UDP port number on which server listens.
     uint16_t port_;
+    
+    /// IPC used for communation with dhcp4_srv (for RFC7341).
+    DHCP4o6IPCPtr ipc_;
 
 protected:
 
index 1208e21d397207df616c06a05afa4441c6e3f517..c14cfec26a3276d8567406b9f7bc98915ae6cb0c 100644 (file)
@@ -29,6 +29,7 @@
 #include <log/logger_support.h>
 #include <util/encode/hex.h>
 #include <util/strutil.h>
+#include <dhcp6/dhcp6_srv.h>
 
 #include <boost/algorithm/string.hpp>
 #include <boost/foreach.hpp>
@@ -681,6 +682,8 @@ namespace dhcp {
         parser = new HooksLibrariesParser(config_id);
     } else if (config_id.compare("dhcp-ddns") == 0) {
         parser = new D2ClientConfigParser(config_id);
+    } else if (config_id.compare("4o6-enable") == 0) {
+        parser = new BooleanParser(config_id, globalContext()->boolean_values_);
     } else {
         isc_throw(DhcpConfigError,
                 "unsupported global configuration parameter: "
@@ -691,7 +694,7 @@ namespace dhcp {
 }
 
 isc::data::ConstElementPtr
-configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
+configureDhcp6Server(Dhcpv6Srv& srv, isc::data::ConstElementPtr config_set) {
     if (!config_set) {
         ConstElementPtr answer = isc::config::createAnswer(1,
                                  string("Can't parse NULL config"));
@@ -775,6 +778,17 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
                 // but we need it so as the subnet6 parser can access the
                 // parsed data.
                 parser->commit();
+                if (config_pair.first == "4o6-enable") {
+                    try {
+                        if (config_pair.second->boolValue()) {
+                            srv.enable4o6();
+                        } else {
+                            srv.disable4o6();
+                        }
+                    } catch (const isc::Exception& e) {
+                        //TODO: do someting
+                    }
+                }
             }
         }
 
index 14347bbc243d04fdb28cc448d1c632555fd2abcc..24f41c23d545b0fe8cbd351c28681b2cfd8d0a63 100644 (file)
@@ -50,6 +50,9 @@ libkea_dhcp___la_SOURCES += pkt_filter6.h pkt_filter6.cc
 libkea_dhcp___la_SOURCES += pkt_filter_inet.cc pkt_filter_inet.h
 libkea_dhcp___la_SOURCES += pkt_filter_inet6.cc pkt_filter_inet6.h
 
+#DHCP4o6
+libkea_dhcp___la_SOURCES += pkt4o6.cc pkt4o6.h
+
 # Utilize Linux Packet Filtering on Linux.
 if OS_LINUX
 libkea_dhcp___la_SOURCES += pkt_filter_lpf.cc pkt_filter_lpf.h
index d5201a97401e80c0b2703edbcb8c2a6a011a00c6..2aa909ceb9f23c743b7d88e22a31cbdb1fffc521 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2006-2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2006-2014  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
@@ -81,6 +81,9 @@
 #define STATUS_NotConfigured     9
 #define STATUS_NotAllowed       10
 
+/* DHCPv4 Message Option, defined in RFC 7341 */
+#define OPTION_DHCPV4_MSG         87 
+
 /*
  * DHCPv6 message types, defined in section 5.3 of RFC 3315
  */
 #define DHCPV6_LEASEQUERY          14
 #define DHCPV6_LEASEQUERY_REPLY    15
 
+/*
+ * DHCPv4-query and DHCPv4-response message types,
+ * defined in RFC 7341
+ */
+#define DHCPV4_QUERY              20
+#define DHCPV4_RESPONSE           21
+
 extern const char *dhcpv6_type_names[];
 extern const int dhcpv6_type_name_max;
 
diff --git a/src/lib/dhcp/pkt4o6.cc b/src/lib/dhcp/pkt4o6.cc
new file mode 100644 (file)
index 0000000..4e9a055
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#include <dhcp/pkt4o6.h>\r
+#include <dhcp/dhcp4.h>\r
+#include <asiolink/io_address.h>\r
+\r
+#include <boost/property_tree/ptree.hpp>\r
+#include <boost/property_tree/json_parser.hpp>\r
+#include <sstream>\r
+\r
+using namespace std;\r
+\r
+namespace isc {\r
+namespace dhcp {\r
+          \r
+Pkt4o6::Pkt4o6(const uint8_t* data4, size_t len4,\r
+               const uint8_t* data6, size_t len6)\r
+       :pkt4_(new Pkt4(data4, len4)),\r
+        pkt6_(new Pkt6(data6, len6))\r
+{\r
+    pkt6_->repack();//call repack() to generate outputBuffer\r
+    pkt4_->repack();//call repack() to generate outputBuffer\r
+}\r
+\r
+Pkt4o6::Pkt4o6(const Pkt6Ptr& pkt6) {\r
+    if (pkt6->getType() != DHCPV4_QUERY && \r
+        pkt6->getType() != DHCPV4_RESPONSE) {\r
+        isc_throw(Pkt4o6ConstructError,\r
+                  "The DHCPv6 packet is not DHCPV4_QUERY or DHCPV4_RESPONSE");\r
+    }\r
+    OptionPtr opt = pkt6->getOption(OPTION_DHCPV4_MSG);\r
+    if (opt) {\r
+        const OptionBuffer& data = opt->getData();\r
+        pkt4_ = Pkt4Ptr(new Pkt4(data.data(), data.size()));\r
+    } else {\r
+        isc_throw(Pkt4o6ConstructError,\r
+                 "The DHCPv6 message doesn't contain a DHCPv4 Message Option");\r
+    }\r
+    \r
+    pkt6_ = pkt6;\r
+    pkt6_->repack();//call repack() to generate outputBuffer\r
+    pkt4_->repack();//call repack() to generate outputBuffer\r
+}\r
+\r
+Pkt4o6::Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4) {\r
+    pkt4_ = pkt4;\r
+    pkt6_ = pkt4o6->getPkt6();\r
+}\r
+\r
+void\r
+Pkt4o6::setPkt4LocalAddr() {\r
+    if (pkt4_ && pkt6_) {\r
+        pkt6_->unpack();\r
+        if (pkt6_->getTransid() & 0x800000) {//U flag is 1, pkt4 sent unicast\r
+            pkt4_->setLocalAddr(isc::asiolink::IOAddress("8.8.8.8"));\r
+        } else {//u flag is 0, pkt4 sent to broadcast\r
+            pkt4_->setLocalAddr(isc::asiolink::IOAddress("255.255.255.255"));\r
+        }\r
+    }\r
+}\r
+\r
+std::string\r
+Pkt4o6::getJsonAttribute() {\r
+    using boost::property_tree::ptree;\r
+    ptree pt;\r
+    pt.put("RemoteAddr", pkt6_->getRemoteAddr().toText());\r
+    pt.put("LocalAddr", pkt6_->getLocalAddr().toText());\r
+    pt.put("RemotePort", pkt6_->getRemotePort());\r
+    pt.put("LocalPort", pkt6_->getLocalPort());\r
+    pt.put("Index", pkt6_->getIndex());\r
+    pt.put("Iface", pkt6_->getIface());\r
+    std::stringstream sout;\r
+    write_json(sout, pt);\r
+    return (sout.str());\r
+}\r
+\r
+void\r
+Pkt4o6::setJsonAttribute(std::string json) {\r
+    using boost::property_tree::ptree;\r
+    std::istringstream sin(json);\r
+    ptree pt;\r
+    read_json(sin, pt);\r
+    try {\r
+        pkt6_->setRemoteAddr(isc::asiolink::IOAddress(pt.get<std::string>("RemoteAddr")));\r
+        pkt6_->setLocalAddr(isc::asiolink::IOAddress(pt.get<std::string>("LocalAddr")));\r
+        pkt6_->setRemotePort(pt.get<uint16_t>("RemotePort"));\r
+        pkt6_->setLocalPort(pt.get<uint16_t>("LocalPort"));\r
+        pkt6_->setIndex(pt.get<uint32_t>("Index"));\r
+        pkt6_->setIface(pt.get<std::string>("Iface"));\r
+        \r
+        pkt4_->setIface(pkt6_->getIface());\r
+    } catch (const std::exception& ex) {\r
+        //TODO: logging\r
+    }\r
+}\r
+\r
+OptionBuffer\r
+Pkt4o6::getDHCPv4MsgOption() {\r
+    const isc::util::OutputBuffer &buf(pkt4_->getBuffer());\r
+    uint8_t* head = (uint8_t*)buf.getData();\r
+    OptionBuffer ret(head, head + buf.getLength());\r
+    return ret;\r
+}\r
+\r
+}\r
+}\r
diff --git a/src/lib/dhcp/pkt4o6.h b/src/lib/dhcp/pkt4o6.h
new file mode 100644 (file)
index 0000000..53bb7dc
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#ifndef PKT4o6_H\r
+#define PKT4o6_H\r
+\r
+#include <dhcp/pkt6.h>\r
+#include <dhcp/pkt4.h>\r
+#include <dhcp/option.h>\r
+#include <dhcp/dhcp6.h>\r
+\r
+namespace isc {\r
+\r
+namespace dhcp {\r
+\r
+/// @brief Pkt4o6 exception thrown when construction fails.\r
+class Pkt4o6ConstructError : public Exception {\r
+public:\r
+    Pkt4o6ConstructError(const char* file, size_t line, const char* what) :\r
+        isc::Exception(file, line, what) { };\r
+};\r
+\r
+/// Forward declaration for Pkt4o6\r
+class Pkt4o6;\r
+\r
+/// Pointer of Pkt4o6\r
+typedef boost::shared_ptr<Pkt4o6> Pkt4o6Ptr;\r
+\r
+/// @brief DHCPv4 over DHCPv6 packet (RFC 7341)\r
+///\r
+/// It represents DHCPv4o6 packet by including a Pkt4ptr and a Pkt6ptr \r
+/// member variables. Generally the Pkt4ptr points to its DHCPv4 message\r
+/// content, and Pkt6ptr gives DHCPv6 information.\r
+class Pkt4o6{\r
+public:\r
+    /// @brief Constructor, used in DHCP4o6IPC to construct Pkt4o6 from\r
+    /// raw data.\r
+    ///\r
+    /// It is used when a DHCP4o6IPC receives raw data from the other server.\r
+    /// It constructs internal Pkt4 and Pkt6 seperately using the given raw data.\r
+    ///\r
+    /// @param data4 raw data of Pkt4\r
+    /// @param len4 raw data length of Pkt4\r
+    /// @param data6 raw data of Pkt6\r
+    /// @param len6 raw data length of Pkt6\r
+    Pkt4o6(const uint8_t* data4, size_t len4,\r
+           const uint8_t* data6, size_t len6);\r
+           \r
+    /// @brief Constructor, used in DHCPv6 server to construct Pkt4o6 from Pkt6.\r
+    ///\r
+    /// It is used when a DHCPv6 server receives a DHCPv4-query message, and \r
+    /// converts it into a DHCP4o6 message.\r
+    /// It constructs internal Pkt4 using the pkt6's DHCPv4 Message Option\r
+    /// \r
+    /// @throw Pkt4o6ConstructError if given mssage is not DHCPV4_QUERY or \r
+    /// DHCPV4_RESPONSE, or if OPTION_DHCPV4_MSG not found\r
+    ///\r
+    /// @param pkt6 A DHCPv6 DHCPV4_QUERY message.\r
+    Pkt4o6(const Pkt6Ptr& pkt6);               \r
+\r
+    /// @brief Constructor, used in DHCPv4 server to construct Pkt4o6 from\r
+    /// Pkt4 response and Pkt4o6 query.\r
+    ///\r
+    /// It is used when a DHCPv4 server successfully produces a DHCPv4 reply\r
+    /// for a DHCP4o6 query. It converts the DHCPv4 reply into a DHCP4o6 message.\r
+    ///\r
+    /// @param pkt4o6 a DHCPv4 over DHCPv6 message\r
+    /// @param pkt4 a DHCPv4 response message\r
+    Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4);\r
+\r
+    /// @brief Get Pkt6 format of this DHCPv4 over DHCPv6 packet\r
+    ///\r
+    /// @return A pointer to the Pkt6 object.\r
+    Pkt6Ptr getPkt6() const { return (pkt6_); }\r
+    \r
+    /// @brief Get Pkt4 content of this DHCPv4 over DHCPv6 packet\r
+    /// @return A pointer to the Pkt4 object.\r
+    Pkt4Ptr getPkt4() const { return (pkt4_); }\r
+    \r
+    /// @brief Json format of nessary information\r
+    ///\r
+    /// There are some nessary information that needs to be passed between\r
+    /// DHCPv4 and DHCPv6 servers, such as IPv6 addresses, ports, iface, etc.\r
+    /// The raw data of the DHCPv6 packet does not contain these information,\r
+    /// so we transmit them using json format string\r
+    ///\r
+    /// @return A json format string containing all necessary information\r
+    std::string getJsonAttribute();\r
+    \r
+    /// @brief Set Packet attributes according to a json format string\r
+    void setJsonAttribute(std::string json);\r
+    \r
+    /// @brief Get a DHCPv4MsgOption that contains pkt4_\r
+    ///\r
+    /// @return A DHCPv4MsgOption\r
+    OptionBuffer getDHCPv4MsgOption();\r
+    \r
+    /// @brief Set local address in pkt4_ according to U flag in pkt6_\r
+    void setPkt4LocalAddr();\r
+    \r
+protected:\r
+    /// @brief A poiner to a DHCPv4 packet\r
+    Pkt4Ptr pkt4_;\r
+    \r
+    /// @brief A pointer to a DHCPv6 packet\r
+    Pkt6Ptr pkt6_;    \r
+};// pkt4o6 class\r
+\r
+} // isc::dhcp namespace\r
+\r
+} // isc namespace      \r
+    \r
+#endif\r
+   \r
+    \r
+     \r
+       \r
+             \r
+             \r
+      \r
index 8489ede1238f79a96e273c2bb81c8c5a5d949aee..f2c042c85c92fde58d2bd5a83668f268ed4dc152 100644 (file)
@@ -78,6 +78,9 @@ libdhcp___unittests_SOURCES += pkt_filter6_test_stub.cc pkt_filter_test_stub.h
 libdhcp___unittests_SOURCES += pkt_filter_test_utils.h pkt_filter_test_utils.cc
 libdhcp___unittests_SOURCES += pkt_filter6_test_utils.h pkt_filter6_test_utils.cc
 
+#4o6
+libdhcp___unittests_SOURCES += pkt4o6_unittest.cc
+
 # Utilize Linux Packet Filtering on Linux.
 if OS_LINUX
 libdhcp___unittests_SOURCES += pkt_filter_lpf_unittest.cc
diff --git a/src/lib/dhcp/tests/pkt4o6_unittest.cc b/src/lib/dhcp/tests/pkt4o6_unittest.cc
new file mode 100644 (file)
index 0000000..9ab0077
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright (C) 2011-2014  Internet Systems Consortium, Inc. ("ISC")\r
+//\r
+// Permission to use, copy, modify, and/or distribute this software for any\r
+// purpose with or without fee is hereby granted, provided that the above\r
+// copyright notice and this permission notice appear in all copies.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH\r
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\r
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\r
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
+// PERFORMANCE OF THIS SOFTWARE.\r
+\r
+#include <config.h>\r
+\r
+#include <asiolink/io_address.h>\r
+#include <dhcp/dhcp4.h>\r
+#include <dhcp/dhcp6.h>\r
+#include <dhcp/libdhcp++.h>\r
+#include <dhcp/docsis3_option_defs.h>\r
+#include <dhcp/option_string.h>\r
+#include <dhcp/pkt4.h>\r
+#include <dhcp/pkt6.h>\r
+#include <dhcp/option.h>\r
+#include <exceptions/exceptions.h>\r
+#include <util/buffer.h>\r
+#include <dhcp/pkt4o6.h>\r
+#include <boost/shared_array.hpp>\r
+#include <boost/shared_ptr.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <gtest/gtest.h>\r
+\r
+#include <iostream>\r
+#include <sstream>\r
+\r
+#include <arpa/inet.h>\r
+\r
+using namespace std;\r
+using namespace isc;\r
+using namespace isc::asiolink;\r
+using namespace isc::dhcp;\r
+using namespace isc::util;\r
+\r
+namespace {\r
+\r
+//Test buffer length\r
+const int LENGTH = 250;\r
+\r
+/// @brief A test fixture class for Pkt4o6.\r
+class Pkt4o6Test : public ::testing::Test {\r
+public:\r
+    \r
+    /// @brief Constructor.\r
+    Pkt4o6Test() {\r
+        for (int i = 0; i < LENGTH; i++) {\r
+            testData[i] = i;\r
+        }\r
+    }\r
+    \r
+    /// @brief Generate a 4o6 packet for testing.\r
+    ///\r
+    /// It first generates a Pkt6, and then generates a Pkt4o6 from the Pkt6.\r
+    ///\r
+    /// @return A pointer to allocated Pkt4o6 object\r
+    Pkt4o6Ptr generatePkt4o6(){\r
+           //First generate a Pkt6\r
+        Pkt6Ptr pkt6(new Pkt6(testData, LENGTH));\r
+        pkt6->setType(DHCPV4_QUERY);\r
+        pkt6->setRemotePort(546);\r
+        pkt6->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));\r
+        pkt6->setLocalPort(0);\r
+        pkt6->setLocalAddr(IOAddress("ff02::1:2"));\r
+        pkt6->setIndex(2);\r
+        pkt6->setIface("eth0");\r
+        \r
+        //Then generate a Pkt4, and put it into a OPTION_DHCPV4_MSG of the pkt6\r
+        Pkt4Ptr pkt4(new Pkt4(testData, LENGTH));\r
+        pkt4->repack();\r
+        isc::util::OutputBuffer tmp = pkt4->getBuffer();\r
+        OptionBuffer p((uint8_t*)tmp.getData(),\r
+                       (uint8_t*)tmp.getData() + tmp.getLength());\r
+        OptionPtr opt = OptionPtr(new Option(Option::V6, OPTION_DHCPV4_MSG, p));\r
+        pkt6->addOption(opt);\r
+        \r
+           //Finally generate a Pkt4o6\r
+        Pkt4o6Ptr pkt4o6(new Pkt4o6(pkt6));\r
+        return pkt4o6;\r
+    }\r
+\r
+    /// @brief Generate a 4o6 packet for testing.\r
+    ///\r
+    /// It generates a Pkt4o6 directly from raw data.\r
+    ///\r
+    /// @return A pointer to allocated Pkt4o6 object\r
+    Pkt4o6Ptr generatePkt4o6_2(){\r
+        Pkt4o6Ptr pkt4o6(new Pkt4o6(testData, LENGTH, testData, LENGTH));\r
+        return pkt4o6;\r
+    }\r
+\r
+protected:    \r
+    ///Buffer for test data\r
+    uint8_t testData[LENGTH];\r
+};\r
+\r
+\r
+//Test Pkt4o6 class constructor\r
+TEST_F(Pkt4o6Test, constructor) {\r
+    Pkt4o6Ptr pkt4o6;\r
+    uint8_t* data;\r
+    Pkt6Ptr pkt6;\r
+    Pkt4Ptr pkt4;\r
+\r
+    //Case 1:test Pkt4o6::Pkt4o6(const Pkt6Ptr& pkt6)\r
+    pkt6 = Pkt6Ptr(new Pkt6(testData, LENGTH));\r
+    pkt4 = Pkt4Ptr(new Pkt4(testData, LENGTH));\r
+    pkt4->repack();\r
+    isc::util::OutputBuffer tmp = pkt4->getBuffer();\r
+    OptionBuffer buf((uint8_t*)tmp.getData(),\r
+                     (uint8_t*)tmp.getData() + tmp.getLength());\r
+    OptionPtr opt(new Option(Option::V6, OPTION_DHCPV4_MSG, buf));\r
+    \r
+    EXPECT_THROW(\r
+        pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6)),\r
+        Pkt4o6ConstructError\r
+    );\r
+    pkt6->setType(DHCPV4_QUERY);\r
+    EXPECT_THROW(\r
+        pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6)),\r
+        Pkt4o6ConstructError\r
+    );\r
+    pkt6->addOption(opt);\r
+    EXPECT_NO_THROW(\r
+        pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt6))\r
+    );\r
+    pkt4 = pkt4o6->getPkt4();\r
+    ASSERT_EQ(LENGTH, pkt4->getBuffer().getLength());\r
+    data = (uint8_t*)pkt4->getBuffer().getData();\r
+    for(int i = 0;i < LENGTH;i++)\r
+           EXPECT_EQ(i, data[i]);\r
+\r
+       //Case 2: test Pkt4o6::Pkt4o6(const uint8_t* data4, size_t len4, \r
+       //                            const uint8_t* data6, size_t len6)\r
+    \r
+    pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, testData, LENGTH));\r
+    pkt4 = pkt4o6->getPkt4();\r
+    pkt6 = pkt4o6->getPkt6();\r
+    \r
+    ASSERT_EQ(LENGTH, pkt4->getBuffer().getLength());\r
+    ASSERT_EQ(LENGTH, pkt6->getBuffer().getLength());\r
+    data = (uint8_t*)pkt4->getBuffer().getData();\r
+    for(int i = 0;i < LENGTH;i++)\r
+           EXPECT_EQ(i, data[i]);\r
+    data = (uint8_t*)pkt6->getBuffer().getData();\r
+    for(int i = 0;i < LENGTH;i++){\r
+           EXPECT_EQ(i,data[i]);\r
+    }\r
+\r
+    //Case 3:test Pkt4o6::Pkt4o6(const Pkt4o6Ptr& pkt4o6, const Pkt4Ptr& pkt4)\r
+    const int LEN2 = 240;\r
+    uint8_t newData[LEN2];\r
+    for(int i = 0 ;i < LEN2;i++)\r
+           newData[i] = i + 2;\r
+\r
+    pkt4 = Pkt4Ptr(new Pkt4(newData, LEN2));\r
+       \r
+       //Create testing PKt4o6 now \r
+    pkt4o6 = Pkt4o6Ptr(new Pkt4o6(pkt4o6, pkt4));\r
+    pkt4 = pkt4o6->getPkt4();\r
+    pkt6 = pkt4o6->getPkt6();\r
+    pkt4->repack();\r
+    //pkt6->repack();\r
+    ASSERT_EQ(LEN2, pkt4->getBuffer().getLength());\r
+    ASSERT_EQ(LENGTH, pkt6->getBuffer().getLength());\r
+    data = (uint8_t*)pkt4->getBuffer().getData();\r
+    for(int i = 0;i < LEN2;i++)\r
+           EXPECT_EQ(i + 2, data[i]);\r
+    data = (uint8_t*)pkt6->getBuffer().getData();\r
+    for(int i = 0;i < LENGTH;i++){\r
+           EXPECT_EQ(i,data[i]);\r
+    }\r
+\r
+}\r
+\r
+//Test setJsonAttribute and getJsonAttribute\r
+TEST_F(Pkt4o6Test, jsonAttribute) {\r
+\r
+    Pkt4o6Ptr pkt4o6 = generatePkt4o6();\r
+       \r
+       //store pkt4o6 josn info.\r
+    std::string json = pkt4o6->getJsonAttribute();\r
+    Pkt4o6Ptr pkt4o6_ = generatePkt4o6_2();\r
+    pkt4o6_->setJsonAttribute(json);\r
+    int RemotePort = 546; \r
+    std::string RemoteAddr("fe80::21e:8cff:fe9b:7349");\r
+    int LocalPort = 0;\r
+    std::string LocalAddr("ff02::1:2");\r
+    int Index = 2;\r
+    std::string Iface("eth0");\r
+       \r
+       // test current pkt4o6 json info.\r
+    Pkt6Ptr v6(pkt4o6_->getPkt6());\r
+    EXPECT_EQ(RemotePort,v6->getRemotePort());\r
+    EXPECT_EQ(RemoteAddr,v6->getRemoteAddr().toText());\r
+    EXPECT_EQ(LocalPort,v6->getLocalPort());\r
+    EXPECT_EQ(LocalAddr,v6->getLocalAddr().toText());\r
+    EXPECT_EQ(Index,v6->getIndex());\r
+    EXPECT_EQ(Iface,v6->getIface());\r
+}\r
+\r
+//Test DHCPv4MsgOption\r
+TEST_F(Pkt4o6Test, generateDHCPv4MsgOption) {\r
+    Pkt4o6Ptr pkt4o6 = generatePkt4o6();\r
+       \r
+       //get DHCPv4MsgOption from Pkt4o6\r
+    OptionBuffer buf(pkt4o6->getDHCPv4MsgOption());\r
+    for(int i = 0;i < LENGTH;i++)\r
+           EXPECT_EQ(i,buf[i]);\r
+\r
+}\r
+\r
+//Test unicast/broadcast flag\r
+TEST_F(Pkt4o6Test, unicastFlag) {\r
+    //create and test a broadcast packet\r
+    uint8_t buf0[] = {DHCPV4_QUERY, 0, 0, 0};//U=0\r
+    Pkt4o6Ptr pkt4o6;\r
+    pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, buf0, sizeof(buf0)));\r
+    pkt4o6->setPkt4LocalAddr();\r
+    EXPECT_EQ("255.255.255.255", pkt4o6->getPkt4()->getLocalAddr().toText());\r
+    \r
+    //create and test a unicast packet\r
+    uint8_t buf1[] = {DHCPV4_QUERY, 0x80, 0, 0};//U=1\r
+    pkt4o6 = Pkt4o6Ptr(new Pkt4o6(testData, LENGTH, buf1, sizeof(buf0)));\r
+    pkt4o6->setPkt4LocalAddr();\r
+    EXPECT_NE("255.255.255.255", pkt4o6->getPkt4()->getLocalAddr().toText());\r
+}\r
+\r
+} // end of anonymous namespace\r
index 5f06f3a4542826710ad0457100653accfef6b631..5a6728c41d7fea4c78c991ca8aba13bbd31a3068 100644 (file)
@@ -76,6 +76,9 @@ libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h
 libkea_dhcpsrv_la_SOURCES += triplet.h
 libkea_dhcpsrv_la_SOURCES += utils.h
 
+#DHCP4o6
+libkea_dhcpsrv_la_SOURCES += dhcp4o6_ipc.h dhcp4o6_ipc.cc
+
 nodist_libkea_dhcpsrv_la_SOURCES = dhcpsrv_messages.h dhcpsrv_messages.cc
 
 libkea_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/dhcpsrv/dhcp4o6_ipc.cc b/src/lib/dhcpsrv/dhcp4o6_ipc.cc
new file mode 100644 (file)
index 0000000..42510cb
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (C) 2014 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.
+
+#include <dhcpsrv/dhcp4o6_ipc.h>
+#include <dhcp/iface_mgr.h>
+
+namespace isc {
+namespace dhcp {
+
+DHCP4o6IPC::DHCP4o6IPC(const std::string& local_filename, const std::string& remote_filename) :
+    BaseIPC(local_filename, remote_filename) {
+    open();
+}
+
+void
+DHCP4o6IPC::sendPkt4o6(const Pkt4o6Ptr& pkt4o6) {
+    if (!pkt4o6) {
+        isc_throw(DHCP4o6IPCSendError, "NULL 4o6 Packet");
+    }
+    isc::util::OutputBuffer buf(0);
+    const isc::util::OutputBuffer &buf4(pkt4o6->getPkt4()->getBuffer());
+    size_t len = buf4.getLength();
+    buf.writeData(&len, sizeof(size_t));
+    buf.writeData(buf4.getData(), len);
+    const isc::util::OutputBuffer &buf6(pkt4o6->getPkt6()->getBuffer());
+    len = buf6.getLength();
+    buf.writeData(&len, sizeof(size_t));
+    buf.writeData(buf6.getData(), len);
+    std::string att = pkt4o6->getJsonAttribute();
+    len = att.size();
+    buf.writeData(&len, sizeof(size_t));
+    buf.writeData(att.c_str(), len);
+    
+    BaseIPC::send(buf);
+}
+
+void
+DHCP4o6IPC::recvPkt4o6() {
+    isc::util::InputBuffer buf = recv();
+    size_t len4, len6, len_json;
+    uint8_t buf4[RCVBUFSIZE];
+    uint8_t buf6[RCVBUFSIZE];
+    char buf_json[RCVBUFSIZE] = {0};
+    buf.readData(&len4, sizeof(size_t));
+    buf.readData(buf4, len4);
+    buf.readData(&len6, sizeof(size_t));
+    buf.readData(buf6, len6);
+    buf.readData(&len_json, sizeof(size_t));
+    buf.readData(buf_json, len_json);
+    
+    Pkt4o6Ptr p(new Pkt4o6(buf4, len4, buf6, len6));
+    p->setJsonAttribute(buf_json);
+    queue_.push(p);
+}
+
+Pkt4o6Ptr
+DHCP4o6IPC::pop() {
+    if (queue_.empty())
+        return Pkt4o6Ptr();
+    current_ = queue_.front();
+    queue_.pop();
+    return current_;
+}
+
+} // isc::dhcp namespace
+} // isc namespace
diff --git a/src/lib/dhcpsrv/dhcp4o6_ipc.h b/src/lib/dhcpsrv/dhcp4o6_ipc.h
new file mode 100644 (file)
index 0000000..3b0fe19
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright (C) 2014 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.
+
+#ifndef DHCP4O6_IPC_H
+#define DHCP4O6_IPC_H
+
+#include <dhcp/pkt4o6.h>
+#include <util/ipc.h>
+
+#include <queue>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown when DHCP4o6IPC::send() failed.
+class DHCP4o6IPCSendError : public isc::util::IPCSendError {
+public:
+    DHCP4o6IPCSendError(const char* file, size_t line, const char* what) :
+        isc::util::IPCSendError(file, line, what) { };
+};
+
+/// @brief IPC class to pass Pkt4o6 between DHCPv4 and DHCPv6 servers
+class DHCP4o6IPC : public isc::util::BaseIPC {
+public:
+    /// @brief Default constructor.
+    ///
+    /// This function calls BaseIPC::open() to initiate socket directly
+    /// Method will throw if BaseIPC::open() method failed
+    ///
+    /// @param local_filename Filename for receiving socket
+    /// @param remote_filename Filename for sending socket
+    DHCP4o6IPC(const std::string& local_filename, const std::string& remote_filename);
+    
+    /// @brief Send a DHCPv4 ove DHCPv6 packet
+    ///
+    /// This function converts Pkt4o6 into binary data and sends it
+    /// through BaseIPC::send().
+    /// Method will throw if BaseIPC::send() failed
+    ///
+    /// @param pkt4o6 Pointer to the packet to be sent
+    void sendPkt4o6(const Pkt4o6Ptr& pkt4o6);
+    
+    /// @brief Receive a DHCPv4 ove DHCPv6 packet
+    ///
+    /// This function calls BaseIPC::recv() to receive binary data
+    /// and converts it into Pkt4o6
+    /// It pushes received Pkt4o6 into a queue and does not return immediately.
+    /// Method will throw if BaseIPC::recv() failed or Pkt4o6
+    /// construction failed
+    void recvPkt4o6();
+    
+    /// @brief Test if Pkt4o6 receiving queue is empty.
+    /// 
+    /// @return true if the Pkt4o6 receiving queue is empty.
+    bool empty() const { return queue_.empty(); }
+    
+    /// @brief Retrive a Pkt4o6 in the receiving queue and remove it.
+    ///
+    /// If the receiving queue is not empty, return the one 
+    /// in front of the queue and remove it from the queue.
+    ///
+    /// @return A pointer to the retrived Pkt4o6, or a null pointer if the
+    /// queue is empty.
+    Pkt4o6Ptr pop();
+    
+    /// @brief Get the instance of current processing Pkt4o6
+    Pkt4o6Ptr currentPkt4o6() { return current_; }
+
+protected:
+    
+    /// @brief A queue of received DHCPv4 over DHCPv6 packets that has
+    /// not been processed
+    std::queue<Pkt4o6Ptr> queue_;
+      
+    /// @brief The current processing DHCPv4 over DHCPv6 packet
+    Pkt4o6Ptr current_;
+};//DHCP4o6IPC class
+
+typedef boost::shared_ptr<DHCP4o6IPC> DHCP4o6IPCPtr;
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif //DHCP4O6_IPC_H
index 108ccd0b83e8f9de75f0808c525410a65dc29e15..5b2586ad1574b19c544894d6a2bec56ca4d2d8a0 100644 (file)
@@ -86,6 +86,9 @@ libdhcpsrv_unittests_SOURCES += test_get_callout_handle.cc test_get_callout_hand
 libdhcpsrv_unittests_SOURCES += triplet_unittest.cc
 libdhcpsrv_unittests_SOURCES += test_utils.cc test_utils.h
 
+#4o6
+libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
+
 libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
 if HAVE_MYSQL
 libdhcpsrv_unittests_CPPFLAGS += $(MYSQL_CPPFLAGS)
diff --git a/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc b/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc
new file mode 100644 (file)
index 0000000..cb645d4
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright (C) 2014  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.
+
+
+#include <config.h>
+#include <asiolink/io_address.h>
+#include <dhcpsrv/dhcp4o6_ipc.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/docsis3_option_defs.h>
+#include <dhcp/option_string.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/option.h>
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+#include <dhcp/pkt4o6.h>
+#include <dhcp/iface_mgr.h>
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+
+#include <gtest/gtest.h>
+
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+namespace {
+
+//Test buffer length
+const int LENGTH = 250;
+
+/// @brief A test fixture class for DHCP4o6IPC.
+class DHCP4o6IPCTest : public ::testing::Test {
+public:
+
+    /// @brief Constructor.
+    DHCP4o6IPCTest() {
+        for (int i = 0; i < LENGTH; ++i)
+            testData[i] = i;
+    }
+        
+    /// @brief Generate a 4o6 packet for testing.
+    ///
+    /// @return A pointer to allocated Pkt4o6 object
+    Pkt4o6Ptr generatePkt4o6(){
+        Pkt4Ptr pkt4(new Pkt4(testData,LENGTH));
+        Pkt6Ptr pkt6(new Pkt6(testData,LENGTH));
+        pkt6->setType(DHCPV4_QUERY);
+        pkt6->setRemotePort(546);
+        pkt6->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
+        pkt6->setLocalPort(0);
+        pkt6->setLocalAddr(IOAddress("ff02::1:2"));
+        pkt6->setIndex(2);
+        pkt6->setIface("eth0");
+        pkt4->repack();
+        isc::util::OutputBuffer tmp = pkt4->getBuffer();
+        OptionBuffer p((uint8_t*)tmp.getData(),
+                       (uint8_t*)tmp.getData()+tmp.getLength());
+        OptionPtr opt = OptionPtr(new Option(Option::V6, OPTION_DHCPV4_MSG, p));
+        pkt6->addOption(opt);
+        Pkt4o6Ptr pkt4o6(new Pkt4o6(pkt6));
+        return pkt4o6;
+    }
+    
+protected:    
+    ///Buffer for test data
+    uint8_t testData[LENGTH];
+};
+
+// This test verifies sending and receiving between v4/v6 IPCs
+TEST_F(DHCP4o6IPCTest, send_receive) {
+    //create Pkt4o6
+       Pkt4o6Ptr pkt4o6 = generatePkt4o6();
+
+    std::string json = pkt4o6->getJsonAttribute();
+
+    DHCP4o6IPC ipc4("DHCP4o6IPCTest_6to4", "DHCP4o6IPCTest_4to6");
+    DHCP4o6IPC ipc6("DHCP4o6IPCTest_4to6", "DHCP4o6IPCTest_6to4");
+
+    EXPECT_NO_THROW(
+       ipc4.sendPkt4o6(pkt4o6); 
+    );
+    EXPECT_NO_THROW(
+       ipc6.sendPkt4o6(pkt4o6); 
+    );    
+    EXPECT_NO_THROW(
+       ipc6.recvPkt4o6();
+    );   
+    EXPECT_NO_THROW(
+       ipc4.recvPkt4o6();
+    );   
+    Pkt4o6Ptr recvmsg1 = ipc6.pop();
+    Pkt4o6Ptr recvmsg2 = ipc4.pop();
+
+    ASSERT_EQ(json, recvmsg1->getJsonAttribute());//json must be equal
+    const OutputBuffer &buf4_1(recvmsg1->getPkt4()->getBuffer());
+    size_t len = buf4_1.getLength();
+    ASSERT_EQ(LENGTH,len);//length of data in pkt4 must be equal
+    const OutputBuffer &buf6_1(recvmsg1->getPkt6()->getBuffer());
+    len = buf6_1.getLength();
+    ASSERT_EQ(LENGTH,len);//length of data in pkt6 must be equal
+    
+    uint8_t *pkt4data1 = (uint8_t*)buf4_1.getData();
+    for(int i = 0;i < LENGTH ;i++){//test data in pkt4
+           EXPECT_EQ(pkt4data1[i],testData[i]);
+    }
+    uint8_t *pkt6data1 = (uint8_t*)buf6_1.getData();
+    for(int i = 0;i < LENGTH ;i++){//test data in pkt6
+           EXPECT_EQ(pkt6data1[i],testData[i]);
+    }
+    
+    ASSERT_EQ(json, recvmsg2->getJsonAttribute());//json must be equal
+    const OutputBuffer &buf4_2(recvmsg2->getPkt4()->getBuffer());
+    len = buf4_2.getLength();
+    ASSERT_EQ(LENGTH,len);//length of data in pkt4 must be equal
+    const OutputBuffer &buf6_2(recvmsg2->getPkt6()->getBuffer());
+    len = buf6_2.getLength();
+    ASSERT_EQ(LENGTH,len);//length of data in pkt6 must be equal
+    
+    uint8_t *pkt4data2 = (uint8_t*)buf4_2.getData();
+    for(int i = 0;i < LENGTH ;i++){//test data in pkt4
+           EXPECT_EQ(pkt4data2[i],testData[i]);
+    }
+    uint8_t *pkt6data2 = (uint8_t*)buf6_2.getData();
+    for(int i = 0;i < LENGTH ;i++){//test data in pkt6
+           EXPECT_EQ(pkt6data2[i],testData[i]);
+    }
+}
+
+// Test send exception
+TEST_F(DHCP4o6IPCTest, exception) {
+    DHCP4o6IPC ipc4("DHCP4o6IPCTest_6to4", "DHCP4o6IPCTest_4to6");
+
+    EXPECT_THROW(
+        ipc4.sendPkt4o6(Pkt4o6Ptr()),
+        DHCP4o6IPCSendError
+    );
+}
+
+
+}
+
+
+
index 09f28662b4f26b85e2545e0b0aa3e4c07fe9073c..aa6b5776c7c14cd6790c71aaa2c21385c7af752d 100644 (file)
@@ -41,6 +41,9 @@ libkea_util_la_SOURCES += encode/binary_from_base16.h
 libkea_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
 libkea_util_la_SOURCES += random/random_number_generator.h
 
+#4o6
+libkea_util_la_SOURCES += ipc.h
+
 libkea_util_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
 CLEANFILES = *.gcno *.gcda
 
diff --git a/src/lib/util/ipc.h b/src/lib/util/ipc.h
new file mode 100644 (file)
index 0000000..eb617c8
--- /dev/null
@@ -0,0 +1,209 @@
+// Copyright (C) 2014 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.
+
+#ifndef IPC_H
+#define IPC_H
+
+#include <util/buffer.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
+
+namespace isc {
+namespace util {
+
+/// @brief Exception thrown when BaseIPC::open() failed.
+class IPCOpenError : public Exception {
+public:
+    IPCOpenError(const char* file, size_t line, const char* what) :
+    isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when BaseIPC::recv() failed.
+class IPCRecvError : public Exception {
+public:
+    IPCRecvError(const char* file, size_t line, const char* what) :
+    isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when BaseIPC::send() failed.
+class IPCSendError : public Exception {
+public:
+    IPCSendError(const char* file, size_t line, const char* what) :
+    isc::Exception(file, line, what) { };
+};
+
+/// @brief An Inter Process Communication(IPC) tool based on UNIX domain socket.
+///
+/// It is used by 2 processes for data communication. It provides methods for
+/// bi-directional binary data transfer.
+///
+/// There should be 2 instances (a sender and a receiver) using this tool
+/// at the same time. The filename for the sockets must match (i.e. 
+/// the remote filename of the sender = the local filename of the receiver).
+///
+/// It should be used as a base class and not directly used for future classes
+/// implementing inter process communication.
+class BaseIPC {
+public:
+
+    /// @brief Packet reception buffer size
+    ///
+    /// Receive buffer size of UNIX socket
+    static const uint32_t RCVBUFSIZE = 4096;
+
+    /// @brief BaseIPC constructor.
+    ///
+    /// Creates BaseIPC object for UNIX socket communication using the given
+    /// filenames. It doesn't create the socket immediately.
+    ///
+    /// @param local_filename Filename for receiving socket
+    /// @param remote_filename Filename for sending socket
+    BaseIPC(const std::string& local_filename, const std::string& remote_filename) :
+        socketfd_(-1),
+        remote_addr_len_(0),
+        local_filename_(local_filename),
+        remote_filename_(remote_filename)
+    {
+    }
+
+    /// @brief BaseIPC destructor.
+    ///
+    /// It closes the socket explicitly.
+    virtual ~BaseIPC() { closeIPC(); }
+    
+    
+    /// @brief Open UNIX socket
+    ///
+    /// Method will throw if socket creation fails.
+    ///
+    /// @return A int value of the socket descriptor.
+    int open() {
+        //create socket
+        int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+        if (fd < 0) {
+            isc_throw(IPCOpenError, "Failed to create a socket");
+       }
+       socketfd_ = fd;
+       
+        bindSocket();
+        setRemoteFilename();
+       
+       return socketfd_;
+    }
+
+    /// @brief Close opened socket.
+    void closeIPC() {
+        if(socketfd_ >= 0)
+            close(socketfd_);
+        socketfd_ = -1;
+    }
+
+    /// @brief Send data.
+    /// 
+    /// @param buf The data to be sent.
+    ///
+    /// Method will throw if open() has not been called or sendto() failed. 
+    /// open() MUST be called before calling this function.
+    ///
+    /// @return The number of bytes sent.
+    int send(const isc::util::OutputBuffer &buf) { 
+        if (remote_addr_len_ == 0) {
+            isc_throw(IPCSendError, "Remote address unset");
+        }
+        int count = sendto(socketfd_, buf.getData(), buf.getLength(), 0,
+                           (struct sockaddr*)&remote_addr_, remote_addr_len_);
+        if (count < 0) {
+            isc_throw(IPCSendError, "BaseIPC failed on sendto: "
+                                    << strerror(errno));
+        }
+        return count;
+    }
+
+    /// @brief Receive data.
+    ///
+    /// Method will throw if socket recvfrom() failed.
+    /// open() MUST be called before calling this function.
+    ///
+    /// @return The number of bytes received.
+    isc::util::InputBuffer recv() {
+        uint8_t buf[RCVBUFSIZE];
+        int len = recvfrom(socketfd_, buf, RCVBUFSIZE, 0, NULL, NULL);
+        if (len < 0) {
+            isc_throw(IPCRecvError, "BaseIPC failed on recvfrom: "
+                                    << strerror(errno));
+       } 
+        isc::util::InputBuffer ibuf(buf, len);
+        return ibuf;
+    }
+
+    /// @brief Get socket fd.
+    /// 
+    /// @return The socket fd of the unix socket.
+    int getSocket() { return socketfd_; }
+
+protected:
+
+    /// @brief Set remote filename
+    ///
+    /// The remote filename is used for sending data. The filename is given
+    /// in the constructor.
+    void setRemoteFilename() {
+        memset(&remote_addr_, 0, sizeof(struct sockaddr_un));
+        remote_addr_.sun_family = AF_UNIX;
+        strcpy(&remote_addr_.sun_path[1], remote_filename_.c_str());
+        remote_addr_len_ = sizeof(sa_family_t) + remote_filename_.size() + 1;
+    }
+    
+    /// @brief Bind the UNIX socket to the given filename
+    ///
+    /// The filename is given in the constructor.
+    ///
+    /// Method will throw if socket binding fails.
+    void bindSocket() {
+        struct sockaddr_un local_addr_;
+        int local_addr_len_;
+            
+        //init address
+        memset(&local_addr_, 0, sizeof(struct sockaddr_un));
+        local_addr_.sun_family = AF_UNIX;
+        strcpy(&local_addr_.sun_path[1], local_filename_.c_str());
+        local_addr_len_ = sizeof(sa_family_t) + local_filename_.size() + 1;
+
+        //bind to local_address
+        if (bind(socketfd_, (struct sockaddr *)&local_addr_, local_addr_len_) < 0) {
+            isc_throw(IPCOpenError, "failed to bind to local address: " + local_filename_);
+       }
+    }
+    
+    /// UNIX socket value.
+    int socketfd_;
+    
+    /// Remote UNIX socket address 
+    struct sockaddr_un remote_addr_;
+    
+    /// Length of remote_addr_
+    int remote_addr_len_;
+
+    /// Filename for receiving and sending socket
+    std::string local_filename_, remote_filename_;
+
+}; // BaseIPC class
+
+} // namespace util
+} // namespace isc
+#endif  // IPC_H
+
index 2a9aaead3067eddc25d813a9d34427bd6efadca5..1504aef919bc6565ea49e508189ae10fff2c6d03 100644 (file)
@@ -51,6 +51,8 @@ run_unittests_SOURCES += signal_set_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
+#4o6
+run_unittests_SOURCES += ipc_unittest.cc
 run_unittests_LDADD = $(top_builddir)/src/lib/util/libkea-util.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
diff --git a/src/lib/util/tests/ipc_unittest.cc b/src/lib/util/tests/ipc_unittest.cc
new file mode 100644 (file)
index 0000000..6ba0cf6
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright (C) 2014  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.
+
+
+#include <util/ipc.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+
+
+namespace {
+
+/// @brief A test fixture class for BaseIPC.
+class IPCTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    ///
+    /// It initializes 2 BaseIPC objects.
+    IPCTest() :
+        ipc1("test_ipc_2to1", "test_ipc_1to2"),
+        ipc2("test_ipc_1to2", "test_ipc_2to1")
+    {
+    }
+protected:
+    /// BaseIPC objects for testing.
+    BaseIPC ipc1, ipc2;
+};
+
+// Test BaseIPC constructor
+TEST_F(IPCTest, constructor) {
+       EXPECT_EQ(-1, ipc1.getSocket());
+}
+
+
+// Test openSocket function
+TEST_F(IPCTest, openSocket) {
+       int fd;
+       EXPECT_NO_THROW(
+       fd = ipc1.open();
+    );
+       
+       EXPECT_EQ(fd, ipc1.getSocket());
+}
+
+// Test BaseIPC bidirectional data sending and receiving
+TEST_F(IPCTest, bidirectionalTransmission) {
+       const int LEN1 = 100;
+       const int LEN2 = 200;
+       uint8_t data1[LEN2];
+       uint8_t data2[LEN2];
+       uint8_t data3[LEN2];
+       uint8_t data4[LEN2];
+       for (int i = 0; i < LEN2; ++i) {
+           data1[i] = i;
+           data2[i] = -i;
+       }
+       EXPECT_NO_THROW(
+       ipc1.open();
+    );
+       EXPECT_NO_THROW(
+       ipc2.open();
+    );
+      
+       OutputBuffer sendbuf1(LEN1), sendbuf2(LEN2);
+       sendbuf1.writeData((void*)data1, LEN1);
+       sendbuf2.writeData((void*)data2, LEN2);
+       EXPECT_NO_THROW(
+           ipc1.send(sendbuf1);
+       );
+       EXPECT_NO_THROW(
+       ipc2.send(sendbuf2);
+    );
+       
+       InputBuffer recvbuf1(0, 0), recvbuf2(0, 0);
+       EXPECT_NO_THROW(
+        recvbuf1 = ipc1.recv();
+    );
+    EXPECT_NO_THROW(
+        recvbuf2 = ipc2.recv();
+    );
+    
+    size_t len1 = recvbuf1.getLength();
+    size_t len2 = recvbuf2.getLength();
+    recvbuf1.readData((void*)data3, len1);
+    recvbuf2.readData((void*)data4, len2);
+       
+       //check out length.
+       ASSERT_EQ(LEN2, len1);
+       ASSERT_EQ(LEN1, len2);
+       
+       for (int i = 0; i < len1; i++) {
+               EXPECT_EQ(data2[i], data3[i]);
+       }
+       for (int i = 0; i < len2; i++) {
+               EXPECT_EQ(data1[i], data4[i]);
+       }
+}
+
+// Test exceptions
+TEST_F(IPCTest, exceptions) {
+    EXPECT_THROW(
+        ipc1.recv(),
+        IPCRecvError
+    );
+    EXPECT_THROW(
+        ipc1.send(OutputBuffer(10)),
+        IPCSendError
+    );
+    EXPECT_NO_THROW(
+        ipc1.open();
+        ipc2.open();
+    );
+    EXPECT_NO_THROW(
+        ipc1.send(OutputBuffer(10))
+    );
+}
+
+}
+