Browse Source

[4267] Finished merge of trac4266 (run_one server routine)

Francis Dupont 9 years ago
parent
commit
2b06d0f707

+ 11 - 4
src/bin/dhcp4/dhcp4_messages.mes

@@ -449,10 +449,17 @@ This error message is issued when preparing an on-wire format of the packet
 has failed. The first argument identifies the client and the DHCP transaction.
 The second argument includes the error string.
 
-% DHCP4_PACKET_PROCESS_EXCEPTION exception occurred during packet processing: %1
-This error message indicates that an exception was raised during packet processing
-that was not caught by other, more specific exception handlers. This packet will
-be dropped and the server will continue operation.
+% DHCP4_PACKET_PROCESS_EXCEPTION exception occurred during packet processing
+This error message indicates that a non-standard exception was raised
+during packet processing that was not caught by other, more specific
+exception handlers. This packet will be dropped and the server will
+continue operation.
+
+% DHCP4_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1
+This error message indicates that a standard exception was raised
+during packet processing that was not caught by other, more specific
+exception handlers. This packet will be dropped and the server will
+continue operation.
 
 % DHCP4_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
 A debug message noting that the server has received the specified type of

+ 78 - 77
src/bin/dhcp4/dhcp4_srv.cc

@@ -415,88 +415,18 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
 bool
 Dhcpv4Srv::run() {
     while (!shutdown_) {
-        // client's message and server's response
-        Pkt4Ptr query;
-
-        try {
-
-        try {
-            uint32_t timeout = 1000;
-            LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT).arg(timeout);
-            query = receivePacket(timeout);
-
-            // Log if packet has arrived. We can't log the detailed information
-            // about the DHCP message because it hasn't been unpacked/parsed
-            // yet, and it can't be parsed at this point because hooks will
-            // have to process it first. The only information available at this
-            // point are: the interface, source address and destination addresses
-            // and ports.
-            if (query) {
-                LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_BUFFER_RECEIVED)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getRemotePort())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getLocalPort())
-                    .arg(query->getIface());
-
-            } else {
-                LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_INTERRUPTED)
-                    .arg(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,
-            // SIGINT, SIGHUP or SIGCHILD which are handled by the server. For
-            // signals that are not handled by the server we rely on the default
-            // behavior of the system.
-            LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL,
-                      DHCP4_BUFFER_WAIT_SIGNAL)
-                .arg(signal_set_->getNext());
-        } catch (const std::exception& e) {
-            // Log all other errors.
-            LOG_ERROR(packet4_logger, DHCP4_BUFFER_RECEIVE_FAIL).arg(e.what());
-        }
-
-        // Handle next signal received by the process. It must be called after
-        // an attempt to receive a packet to properly handle server shut down.
-        // The SIGTERM or SIGINT will be received prior to, or during execution
-        // of select() (select is invoked by receivePacket()). When that
-        // happens, select will be interrupted. The signal handler will be
-        // invoked immediately after select(). The handler will set the
-        // shutdown flag and cause the process to terminate before the next
-        // select() function is called. If the function was called before
-        // receivePacket the process could wait up to the duration of timeout
-        // of select() to terminate.
         try {
-            handleSignal();
-        } catch (const std::exception& e) {
-            // Standard exception occurred. Let's be on the safe side to
-            // catch std::exception.
-            LOG_ERROR(dhcp4_logger, DHCP4_HANDLE_SIGNAL_EXCEPTION)
-                .arg(e.what());
-        }
-
-        // Timeout may be reached or signal received, which breaks select()
-        // with no reception occurred. No need to log anything here because
-        // we have logged right after the call to receivePacket().
-        if (!query) {
-            continue;
-        }
-
-        processPacket(query);
-
+            run_one();
         } catch (const std::exception& e) {
             // General catch-all exception that are not caught by more specific
             // catches. This one is for exceptions derived from std::exception.
-            LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION)
+            LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_STD_EXCEPTION)
                 .arg(e.what());
         } catch (...) {
             // General catch-all exception that are not caught by more specific
             // catches. This one is for other exceptions, not derived from
             // std::exception.
-            LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION)
-                .arg("an unknown exception not derived from std::exception");
+	    LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION);
         }
     }
 
@@ -504,12 +434,86 @@ Dhcpv4Srv::run() {
 }
 
 void
+Dhcpv4Srv::run_one() {
+    // client's message and server's response
+    Pkt4Ptr query;
+    Pkt4Ptr rsp;
+
+    try {
+        uint32_t timeout = 1000;
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT).arg(timeout);
+        query = receivePacket(timeout);
+
+        // Log if packet has arrived. We can't log the detailed information
+        // about the DHCP message because it hasn't been unpacked/parsed
+        // yet, and it can't be parsed at this point because hooks will
+        // have to process it first. The only information available at this
+        // point are: the interface, source address and destination addresses
+        // and ports.
+        if (query) {
+            LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_BUFFER_RECEIVED)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getRemotePort())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getLocalPort())
+                .arg(query->getIface());
+
+        } else {
+            LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_INTERRUPTED)
+                .arg(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,
+        // SIGINT, SIGHUP or SIGCHILD which are handled by the server. For
+        // signals that are not handled by the server we rely on the default
+        // behavior of the system.
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_SIGNAL)
+            .arg(signal_set_->getNext());
+    } catch (const std::exception& e) {
+        // Log all other errors.
+        LOG_ERROR(packet4_logger, DHCP4_BUFFER_RECEIVE_FAIL).arg(e.what());
+    }
+
+    // Handle next signal received by the process. It must be called after
+    // an attempt to receive a packet to properly handle server shut down.
+    // The SIGTERM or SIGINT will be received prior to, or during execution
+    // of select() (select is invoked by receivePacket()). When that
+    // happens, select will be interrupted. The signal handler will be
+    // invoked immediately after select(). The handler will set the
+    // shutdown flag and cause the process to terminate before the next
+    // select() function is called. If the function was called before
+    // receivePacket the process could wait up to the duration of timeout
+    // of select() to terminate.
+    try {
+        handleSignal();
+    } catch (const std::exception& e) {
+        // Standard exception occurred. Let's be on the safe side to
+        // catch std::exception.
+        LOG_ERROR(dhcp4_logger, DHCP4_HANDLE_SIGNAL_EXCEPTION)
+            .arg(e.what());
+    }
+
+    // Timeout may be reached or signal received, which breaks select()
+    // with no reception occurred. No need to log anything here because
+    // we have logged right after the call to receivePacket().
+    if (!query) {
+        return;
+    }
+
+    processPacket(query);
+
+    }
+}
+
+void
 Dhcpv4Srv::processPacket(Pkt4Ptr& query) {
     Pkt4Ptr rsp;
 
     // Log reception of the packet. We need to increase it early, as any
     // failures in unpacking will cause the packet to be dropped. We
-    // will increase type specific statistoc further down the road.
+    // will increase type specific statistic further down the road.
     // See processStatsReceived().
     isc::stats::StatsMgr::instance().addValue("pkt4-received",
                                               static_cast<int64_t>(1));
@@ -712,9 +716,6 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query) {
         // Clear skip flag if it was set in previous callouts
         callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
 
-        // Also pass the corresponding query packet as argument
-        callout_handle->setArgument("query4", query);
-
         // Set our response
         callout_handle->setArgument("response4", rsp);
 

+ 9 - 4
src/bin/dhcp4/dhcp4_srv.h

@@ -208,13 +208,18 @@ public:
  
     /// @brief Main server processing loop.
     ///
-    /// Main server processing loop. Receives incoming packets, and calls
-    /// processPacket for each of them.
+    /// Main server processing loop. Call the processing one routine
+    /// until shut down.
     ///
-    /// @return true, if being shut down gracefully, fail if experienced
-    ///         critical error.
+    /// @return true, if being shut down gracefully, never fail.
     bool run();
 
+    /// @brief Main server processing one.
+    ///
+    /// Main server processing one. Receives one incoming packet, calls
+    /// the processing packet routing,
+    void run_one();
+
     /// @brief Process a single incoming DHCPv4 packet.
     ///
     /// It verifies correctness of the passed packet, call per-type processXXX

+ 11 - 4
src/bin/dhcp6/dhcp6_messages.mes

@@ -417,16 +417,23 @@ because packets of this type must be sent to multicast. The first argument
 specifies the client and transaction identification information, the
 second argument specifies packet type.
 
-% DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing: %1
-This error message indicates that an exception was raised during packet processing
-that was not caught by other, more specific exception handlers. This packet will
-be dropped and the server will continue operation.
+% DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing
+This error message indicates that a non-standard exception was raised
+during packet processing that was not caught by other, more specific
+exception handlers. This packet will be dropped and the server will
+continue operation.
 
 % DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3
 This is a general catch-all message indicating that the processing of the
 specified packet type from the indicated address failed.  The reason is given in the
 message.  The server will not send a response but will instead ignore the packet.
 
+% DHCP6_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1
+This error message indicates that a standard exception was raised
+during packet processing that was not caught by other, more specific
+exception handlers. This packet will be dropped and the server will
+continue operation.
+
 % DHCP6_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
 A debug message noting that the server has received the specified type of
 packet on the specified interface. The first argument specifies the

+ 336 - 335
src/bin/dhcp6/dhcp6_srv.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -288,420 +288,421 @@ Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) {
 
 bool Dhcpv6Srv::run() {
     while (!shutdown_) {
-        // client's message and server's response
-        Pkt6Ptr query;
-        Pkt6Ptr rsp;
-
-        try {
-
-        try {
-            uint32_t timeout = 1000;
-            LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT).arg(timeout);
-            query = receivePacket(timeout);
-
-            // Log if packet has arrived. We can't log the detailed information
-            // about the DHCP message because it hasn't been unpacked/parsed
-            // yet, and it can't be parsed at this point because hooks will
-            // have to process it first. The only information available at this
-            // point are: the interface, source address and destination addresses
-            // and ports.
-            if (query) {
-                LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_BUFFER_RECEIVED)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getRemotePort())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getLocalPort())
-                    .arg(query->getIface());
-
-                // Log reception of the packet. We need to increase it early, as
-                // any failures in unpacking will cause the packet to be dropped.
-                // we will increase type specific packets further down the road.
-                // See processStatsReceived().
-                StatsMgr::instance().addValue("pkt6-received", static_cast<int64_t>(1));
-
-            } else {
-                LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_INTERRUPTED)
-                    .arg(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,
-            // SIGINT or SIGHUP which are handled by the server. For signals
-            // that are not handled by the server we rely on the default
-            // behavior of the system.
-            LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
-                .arg(signal_set_->getNext());
-        } catch (const std::exception& e) {
-            LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
-        }
-
-        // Handle next signal received by the process. It must be called after
-        // an attempt to receive a packet to properly handle server shut down.
-        // The SIGTERM or SIGINT will be received prior to, or during execution
-        // of select() (select is invoked by receivePacket()). When that happens,
-        // select will be interrupted. The signal handler will be invoked
-        // immediately after select(). The handler will set the shutdown flag
-        // and cause the process to terminate before the next select() function
-        // is called. If the function was called before receivePacket the
-        // process could wait up to the duration of timeout of select() to
-        // terminate.
         try {
-            handleSignal();
+            run_one();
         } catch (const std::exception& e) {
-            // An (a standard or ISC) exception occurred.
-            LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
+            // General catch-all standard exceptions that are not caught by more
+            // specific catches.
+            LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_STD_EXCEPTION)
                 .arg(e.what());
+        } catch (...) {
+            // General catch-all non-standard exception that are not caught
+            // by more specific catches.
+            LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION);
         }
+    }
 
-        // Timeout may be reached or signal received, which breaks select()
-        // with no packet received
-        if (!query) {
-            continue;
-        }
+    return (true);
+}
 
-        // In order to parse the DHCP options, the server needs to use some
-        // configuration information such as: existing option spaces, option
-        // definitions etc. This is the kind of information which is not
-        // available in the libdhcp, so we need to supply our own implementation
-        // of the option parsing function here, which would rely on the
-        // configuration data.
-        query->setCallback(boost::bind(&Dhcpv6Srv::unpackOptions, this, _1, _2,
-                                       _3, _4, _5));
+void Dhcpv6Srv::run_one() {
+    // client's message and server's response
+    Pkt6Ptr query;
+    Pkt6Ptr rsp;
 
-        bool skip_unpack = false;
+    try {
+        uint32_t timeout = 1000;
+        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT).arg(timeout);
+        query = receivePacket(timeout);
+
+        // Log if packet has arrived. We can't log the detailed information
+        // about the DHCP message because it hasn't been unpacked/parsed
+        // yet, and it can't be parsed at this point because hooks will
+        // have to process it first. The only information available at this
+        // point are: the interface, source address and destination addresses
+        // and ports.
+        if (query) {
+            LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_BUFFER_RECEIVED)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getRemotePort())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getLocalPort())
+                .arg(query->getIface());
 
-        // The packet has just been received so contains the uninterpreted wire
-        // data; execute callouts registered for buffer6_receive.
-        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+            // Log reception of the packet. We need to increase it early, as
+            // any failures in unpacking will cause the packet to be dropped.
+            // we will increase type specific packets further down the road.
+            // See processStatsReceived().
+            StatsMgr::instance().addValue("pkt6-received", static_cast<int64_t>(1));
 
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
+        } else {
+            LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_INTERRUPTED)
+                .arg(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,
+        // SIGINT or SIGHUP which are handled by the server. For signals
+        // that are not handled by the server we rely on the default
+        // behavior of the system.
+        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
+            .arg(signal_set_->getNext());
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
+    }
+
+    // Handle next signal received by the process. It must be called after
+    // an attempt to receive a packet to properly handle server shut down.
+    // The SIGTERM or SIGINT will be received prior to, or during execution
+    // of select() (select is invoked by receivePacket()). When that happens,
+    // select will be interrupted. The signal handler will be invoked
+    // immediately after select(). The handler will set the shutdown flag
+    // and cause the process to terminate before the next select() function
+    // is called. If the function was called before receivePacket the
+    // process could wait up to the duration of timeout of select() to
+    // terminate.
+    try {
+        handleSignal();
+    } catch (const std::exception& e) {
+        // An (a standard or ISC) exception occurred.
+        LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
+            .arg(e.what());
+    }
 
-            // Pass incoming packet as argument
-            callout_handle->setArgument("query6", query);
+    // Timeout may be reached or signal received, which breaks select()
+    // with no packet received
+    if (!query) {
+        return;
+    }
 
-            // Call callouts
-            HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
+    // In order to parse the DHCP options, the server needs to use some
+    // configuration information such as: existing option spaces, option
+    // definitions etc. This is the kind of information which is not
+    // available in the libdhcp, so we need to supply our own implementation
+    // of the option parsing function here, which would rely on the
+    // configuration data.
+    query->setCallback(boost::bind(&Dhcpv6Srv::unpackOptions, this, _1, _2,
+                                   _3, _4, _5));
 
-            // Callouts decided to skip the next processing step. The next
-            // processing step would to parse the packet, so skip at this
-            // stage means that callouts did the parsing already, so server
-            // should skip parsing.
-            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
-                LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_SKIP)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getIface());
-                skip_unpack = true;
-            }
+    bool skip_unpack = false;
 
-            /// @todo: Add support for DROP status.
+    // The packet has just been received so contains the uninterpreted wire
+    // data; execute callouts registered for buffer6_receive.
+    if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            callout_handle->getArgument("query6", query);
-        }
+        // Delete previously set arguments
+        callout_handle->deleteAllArguments();
 
-        // Unpack the packet information unless the buffer6_receive callouts
-        // indicated they did it
-        if (!skip_unpack) {
-            try {
-                LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_UNPACK)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getIface());
-                query->unpack();
-            } catch (const std::exception &e) {
-                // Failed to parse the packet.
-                LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL,
-                          DHCP6_PACKET_DROP_PARSE_FAIL)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getIface())
-                    .arg(e.what());
+        // Pass incoming packet as argument
+        callout_handle->setArgument("query6", query);
 
-                // Increase the statistics of parse failures and dropped packets.
-                StatsMgr::instance().addValue("pkt6-parse-failed",
-                                              static_cast<int64_t>(1));
-                StatsMgr::instance().addValue("pkt6-receive-drop",
-                                              static_cast<int64_t>(1));
-                continue;
-            }
+        // Call callouts
+        HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
+
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to parse the packet, so skip at this
+        // stage means that callouts did the parsing already, so server
+        // should skip parsing.
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_SKIP)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getIface());
+            skip_unpack = true;
         }
 
-        // Update statistics accordingly for received packet.
-        processStatsReceived(query);
+        /// @todo: Add support for DROP status.
 
-        // Check if received query carries server identifier matching
-        // server identifier being used by the server.
-        if (!testServerID(query)) {
+        callout_handle->getArgument("query6", query);
+    }
 
-            // Increase the statistic of dropped packets.
-            StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
-            continue;
+    // Unpack the packet information unless the buffer6_receive callouts
+    // indicated they did it
+    if (!skip_unpack) {
+        try {
+            LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_UNPACK)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getIface());
+            query->unpack();
+        } catch (const std::exception &e) {
+            // Failed to parse the packet.
+            LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL,
+                      DHCP6_PACKET_DROP_PARSE_FAIL)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getIface())
+                .arg(e.what());
+
+            // Increase the statistics of parse failures and dropped packets.
+            StatsMgr::instance().addValue("pkt6-parse-failed",
+                                          static_cast<int64_t>(1));
+            StatsMgr::instance().addValue("pkt6-receive-drop",
+                                          static_cast<int64_t>(1));
+            return;
         }
+    }
 
-        // Check if the received query has been sent to unicast or multicast.
-        // The Solicit, Confirm, Rebind and Information Request will be
-        // discarded if sent to unicast address.
-        if (!testUnicast(query)) {
+    // Update statistics accordingly for received packet.
+    processStatsReceived(query);
 
-            // Increase the statistic of dropped packets.
-            StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
-            continue;
-        }
+    // Check if received query carries server identifier matching
+    // server identifier being used by the server.
+    if (!testServerID(query)) {
 
-        LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
-            .arg(query->getLabel())
-            .arg(query->getName())
-            .arg(static_cast<int>(query->getType()))
-            .arg(query->getRemoteAddr())
-            .arg(query->getLocalAddr())
-            .arg(query->getIface());
-        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
-            .arg(query->getLabel())
-            .arg(query->toText());
+        // Increase the statistic of dropped packets.
+        StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+        return;
+    }
 
-        // At this point the information in the packet has been unpacked into
-        // the various packet fields and option objects has been created.
-        // Execute callouts registered for packet6_receive.
-        if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+    // Check if the received query has been sent to unicast or multicast.
+    // The Solicit, Confirm, Rebind and Information Request will be
+    // discarded if sent to unicast address.
+    if (!testUnicast(query)) {
 
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
+        // Increase the statistic of dropped packets.
+        StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+        return;
+    }
 
-            // Pass incoming packet as argument
-            callout_handle->setArgument("query6", query);
+    LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
+        .arg(query->getLabel())
+        .arg(query->getName())
+        .arg(static_cast<int>(query->getType()))
+        .arg(query->getRemoteAddr())
+        .arg(query->getLocalAddr())
+        .arg(query->getIface());
+    LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
+        .arg(query->getLabel())
+        .arg(query->toText());
 
-            // Call callouts
-            HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
+    // At this point the information in the packet has been unpacked into
+    // the various packet fields and option objects has been created.
+    // Execute callouts registered for packet6_receive.
+    if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            // Callouts decided to skip the next processing step. The next
-            // processing step would to process the packet, so skip at this
-            // stage means drop.
-            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
-                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
-                    .arg(query->getLabel());
-                continue;
-            }
+        // Delete previously set arguments
+        callout_handle->deleteAllArguments();
 
-            /// @todo: Add support for DROP status.
+        // Pass incoming packet as argument
+        callout_handle->setArgument("query6", query);
+
+        // Call callouts
+        HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
 
-            callout_handle->getArgument("query6", query);
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to process the packet, so skip at this
+        // stage means drop.
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
+                .arg(query->getLabel());
+            return;
         }
 
-        // Assign this packet to a class, if possible
-        classifyPacket(query);
+        /// @todo: Add support for DROP status.
 
-        try {
-            NameChangeRequestPtr ncr;
+        callout_handle->getArgument("query6", query);
+    }
 
-            switch (query->getType()) {
-            case DHCPV6_SOLICIT:
-                rsp = processSolicit(query);
-                    break;
+    // Assign this packet to a class, if possible
+    classifyPacket(query);
 
-            case DHCPV6_REQUEST:
-                rsp = processRequest(query);
-                break;
+    try {
+        NameChangeRequestPtr ncr;
 
-            case DHCPV6_RENEW:
-                rsp = processRenew(query);
-                break;
+        switch (query->getType()) {
+        case DHCPV6_SOLICIT:
+            rsp = processSolicit(query);
+            break;
 
-            case DHCPV6_REBIND:
-                rsp = processRebind(query);
-                break;
+        case DHCPV6_REQUEST:
+            rsp = processRequest(query);
+            break;
 
-            case DHCPV6_CONFIRM:
-                rsp = processConfirm(query);
-                break;
+        case DHCPV6_RENEW:
+            rsp = processRenew(query);
+            break;
 
-            case DHCPV6_RELEASE:
-                rsp = processRelease(query);
-                break;
+        case DHCPV6_REBIND:
+            rsp = processRebind(query);
+            break;
 
-            case DHCPV6_DECLINE:
-                rsp = processDecline(query);
-                break;
+        case DHCPV6_CONFIRM:
+            rsp = processConfirm(query);
+            break;
 
-            case DHCPV6_INFORMATION_REQUEST:
-                rsp = processInfRequest(query);
-                break;
+        case DHCPV6_RELEASE:
+            rsp = processRelease(query);
+            break;
 
-            default:
-                // We received a packet type that we do not recognize.
-                LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_UNKNOWN_MSG_RECEIVED)
-                    .arg(static_cast<int>(query->getType()))
-                    .arg(query->getIface());
-                // Only action is to output a message if debug is enabled,
-                // and that will be covered by the debug statement before
-                // the "switch" statement.
-                ;
-            }
+        case DHCPV6_DECLINE:
+            rsp = processDecline(query);
+            break;
 
-        } catch (const RFCViolation& e) {
-            LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
-                .arg(query->getName())
-                .arg(query->getRemoteAddr().toText())
-                .arg(e.what());
+        case DHCPV6_INFORMATION_REQUEST:
+            rsp = processInfRequest(query);
+            break;
 
-            // Increase the statistic of dropped packets.
-            StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+        default:
+            // We received a packet type that we do not recognize.
+            LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_UNKNOWN_MSG_RECEIVED)
+                .arg(static_cast<int>(query->getType()))
+                .arg(query->getIface());
+            // Only action is to output a message if debug is enabled,
+            // and that will be covered by the debug statement before
+            // the "switch" statement.
+            ;
+        }
 
-        } catch (const std::exception& e) {
+    } catch (const RFCViolation& e) {
+        LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
+            .arg(query->getName())
+            .arg(query->getRemoteAddr().toText())
+            .arg(e.what());
+
+        // Increase the statistic of dropped packets.
+        StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+
+    } catch (const std::exception& e) {
+
+        // Catch-all exception (at least for ones based on the isc Exception
+        // class, which covers more or less all that are explicitly raised
+        // in the Kea code), but also the standard one, which may possibly be
+        // thrown from boost code.  Just log the problem and ignore the packet.
+        // (The problem is logged as a debug message because debug is
+        // disabled by default - it prevents a DDOS attack based on the
+        // sending of problem packets.)
+        LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
+            .arg(query->getName())
+            .arg(query->getRemoteAddr().toText())
+            .arg(e.what());
 
-            // Catch-all exception (at least for ones based on the isc Exception
-            // class, which covers more or less all that are explicitly raised
-            // in the Kea code), but also the standard one, which may possibly be
-            // thrown from boost code.  Just log the problem and ignore the packet.
-            // (The problem is logged as a debug message because debug is
-            // disabled by default - it prevents a DDOS attack based on the
-            // sending of problem packets.)
-            LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
-                .arg(query->getName())
-                .arg(query->getRemoteAddr().toText())
-                .arg(e.what());
+        // Increase the statistic of dropped packets.
+        StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+    }
 
-            // Increase the statistic of dropped packets.
-            StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
+    if (rsp) {
+
+        // Process relay-supplied options. It is important to call this very
+        // late in the process, because we now have all the options the
+        // server wanted to send already set. This is important, because
+        // RFC6422, section 6 states:
+        //
+        //   The server SHOULD discard any options that appear in the RSOO
+        //   for which it already has one or more candidates.
+        //
+        // So we ignore any RSOO options if there's an option with the same
+        // code already present.
+        processRSOO(query, rsp);
+
+        rsp->setRemoteAddr(query->getRemoteAddr());
+        rsp->setLocalAddr(query->getLocalAddr());
+
+        if (rsp->relay_info_.empty()) {
+            // Direct traffic, send back to the client directly
+            rsp->setRemotePort(DHCP6_CLIENT_PORT);
+        } else {
+            // Relayed traffic, send back to the relay agent
+            rsp->setRemotePort(DHCP6_SERVER_PORT);
         }
 
-        if (rsp) {
+        rsp->setLocalPort(DHCP6_SERVER_PORT);
+        rsp->setIndex(query->getIndex());
+        rsp->setIface(query->getIface());
 
-            // Process relay-supplied options. It is important to call this very
-            // late in the process, because we now have all the options the
-            // server wanted to send already set. This is important, because
-            // RFC6422, section 6 states:
-            //
-            //   The server SHOULD discard any options that appear in the RSOO
-            //   for which it already has one or more candidates.
-            //
-            // So we ignore any RSOO options if there's an option with the same
-            // code already present.
-            processRSOO(query, rsp);
+        // Specifies if server should do the packing
+        bool skip_pack = false;
 
-            rsp->setRemoteAddr(query->getRemoteAddr());
-            rsp->setLocalAddr(query->getLocalAddr());
+        // Server's reply packet now has all options and fields set.
+        // Options are represented by individual objects, but the
+        // output wire data has not been prepared yet.
+        // Execute all callouts registered for packet6_send
+        if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
+            CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            if (rsp->relay_info_.empty()) {
-                // Direct traffic, send back to the client directly
-                rsp->setRemotePort(DHCP6_CLIENT_PORT);
-            } else {
-                // Relayed traffic, send back to the relay agent
-                rsp->setRemotePort(DHCP6_SERVER_PORT);
+            // Delete all previous arguments
+            callout_handle->deleteAllArguments();
+
+            // Set our response
+            callout_handle->setArgument("response6", rsp);
+
+            // Call all installed callouts
+            HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
+
+            // Callouts decided to skip the next processing step. The next
+            // processing step would to pack the packet (create wire data).
+            // That step will be skipped if any callout sets skip flag.
+            // It essentially means that the callout already did packing,
+            // so the server does not have to do it again.
+            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP)
+                    .arg(rsp->getLabel());
+                skip_pack = true;
+            }
+
+            /// @todo: Add support for DROP status
+        }
+
+        if (!skip_pack) {
+            try {
+                rsp->pack();
+            } catch (const std::exception& e) {
+                LOG_ERROR(options6_logger, DHCP6_PACK_FAIL)
+                    .arg(e.what());
+                return;
             }
 
-            rsp->setLocalPort(DHCP6_SERVER_PORT);
-            rsp->setIndex(query->getIndex());
-            rsp->setIface(query->getIface());
+        }
 
-            // Specifies if server should do the packing
-            bool skip_pack = false;
+        try {
 
-            // Server's reply packet now has all options and fields set.
-            // Options are represented by individual objects, but the
-            // output wire data has not been prepared yet.
-            // Execute all callouts registered for packet6_send
-            if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
+            // Now all fields and options are constructed into output wire buffer.
+            // Option objects modification does not make sense anymore. Hooks
+            // can only manipulate wire buffer at this stage.
+            // Let's execute all callouts registered for buffer6_send
+            if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
                 CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-                // Delete all previous arguments
+                // Delete previously set arguments
                 callout_handle->deleteAllArguments();
 
-                // Set our response
+                // Pass incoming packet as argument
                 callout_handle->setArgument("response6", rsp);
 
-                // Call all installed callouts
-                HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
+                // Call callouts
+                HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
 
                 // Callouts decided to skip the next processing step. The next
-                // processing step would to pack the packet (create wire data).
-                // That step will be skipped if any callout sets skip flag.
-                // It essentially means that the callout already did packing,
-                // so the server does not have to do it again.
+                // processing step would to parse the packet, so skip at this
+                // stage means drop.
                 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
-                    LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP)
+                    LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
                         .arg(rsp->getLabel());
-                    skip_pack = true;
+                    return;
                 }
 
                 /// @todo: Add support for DROP status
-            }
-
-            if (!skip_pack) {
-                try {
-                    rsp->pack();
-                } catch (const std::exception& e) {
-                    LOG_ERROR(options6_logger, DHCP6_PACK_FAIL)
-                        .arg(e.what());
-                    continue;
-                }
 
+                callout_handle->getArgument("response6", rsp);
             }
 
-            try {
-
-                // Now all fields and options are constructed into output wire buffer.
-                // Option objects modification does not make sense anymore. Hooks
-                // can only manipulate wire buffer at this stage.
-                // Let's execute all callouts registered for buffer6_send
-                if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
-                    CalloutHandlePtr callout_handle = getCalloutHandle(query);
-
-                    // Delete previously set arguments
-                    callout_handle->deleteAllArguments();
-
-                    // Pass incoming packet as argument
-                    callout_handle->setArgument("response6", rsp);
-
-                    // Call callouts
-                    HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
-
-                    // Callouts decided to skip the next processing step. The next
-                    // processing step would to parse the packet, so skip at this
-                    // stage means drop.
-                    if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
-                        LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
-                            .arg(rsp->getLabel());
-                        continue;
-                    }
-
-                    /// @todo: Add support for DROP status
-
-                    callout_handle->getArgument("response6", rsp);
-                }
-
-                LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA,
-                          DHCP6_RESPONSE_DATA)
-                    .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
+            LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA,
+                      DHCP6_RESPONSE_DATA)
+                .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 
-                sendPacket(rsp);
+            sendPacket(rsp);
 
-                // Update statistics accordingly for sent packet.
-                processStatsSent(rsp);
-
-            } catch (const std::exception& e) {
-                LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL)
-                    .arg(e.what());
-            }
-        }
+            // Update statistics accordingly for sent packet.
+            processStatsSent(rsp);
 
         } catch (const std::exception& e) {
-            // General catch-all standard exceptions that are not caught by more
-            // specific catches.
-            LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION)
+            LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL)
                 .arg(e.what());
-        } catch (...) {
-            // General catch-all non-standard exception that are not caught
-            // by more specific catches.
-            LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION)
-                .arg("an unknown exception not derived from std::exception");
         }
     }
-
-    return (true);
 }
 
 std::string

+ 11 - 6
src/bin/dhcp6/dhcp6_srv.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -89,14 +89,19 @@ public:
 
     /// @brief Main server processing loop.
     ///
-    /// Main server processing loop. Receives incoming packets, verifies
-    /// their correctness, generates appropriate answer (if needed) and
-    /// transmits responses.
+    /// Main server processing loop. Call the processing one routine
+    /// until shut down.
     ///
-    /// @return true, if being shut down gracefully, fail if experienced
-    ///         critical error.
+    /// @return true, if being shut down gracefully, never fail.
     bool run();
 
+    /// @brief Main server processing one.
+    ///
+    /// Main server processing one. Receives one incoming packet, verifies
+    /// its correctness, generates appropriate answer (if needed) and
+    /// transmits response.
+    void run_one();
+
     /// @brief Instructs the server to shut down.
     void shutdown();