Browse Source

[4267] Merged (rebased) trac4108 (Reorganize DHCP server code flow)

Francis Dupont 9 years ago
parent
commit
bcb9bf7e3a
3 changed files with 286 additions and 265 deletions
  1. 1 0
      AUTHORS
  2. 274 262
      src/bin/dhcp4/dhcp4_srv.cc
  3. 11 3
      src/bin/dhcp4/dhcp4_srv.h

+ 1 - 0
AUTHORS

@@ -88,6 +88,7 @@ We have received the following contributions:
 
  - Jinmei Tatuya
    2015-10: Pkt4o6 class improvements
+   2015-11: split Dhcpv4Srv::run() int run() and processPacket()
 
  - Sebastien Couture, Ubity Inc
    2015-12: Fixes to MySQL schema creation

+ 274 - 262
src/bin/dhcp4/dhcp4_srv.cc

@@ -417,7 +417,6 @@ Dhcpv4Srv::run() {
     while (!shutdown_) {
         // client's message and server's response
         Pkt4Ptr query;
-        Pkt4Ptr rsp;
 
         try {
 
@@ -445,13 +444,14 @@ Dhcpv4Srv::run() {
                     .arg(timeout);
             }
 
-        } catch (const SignalInterruptOnSelect) {
+        } 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)
+            LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL,
+                      DHCP4_BUFFER_WAIT_SIGNAL)
                 .arg(signal_set_->getNext());
         } catch (const std::exception& e) {
             // Log all other errors.
@@ -484,319 +484,331 @@ Dhcpv4Srv::run() {
             continue;
         }
 
-        // 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().
-        isc::stats::StatsMgr::instance().addValue("pkt4-received",
-                                                  static_cast<int64_t>(1));
+        processPacket(query);
 
-        // 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(&Dhcpv4Srv::unpackOptions, this,
-                                       _1, _2, _3));
+        } 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)
+                .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");
+        }
+    }
 
-        bool skip_unpack = false;
+    return (true);
+}
 
-        // The packet has just been received so contains the uninterpreted wire
-        // data; execute callouts registered for buffer4_receive.
-        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(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 packets further down the road.
+    // See processStatsReceived().
+    isc::stats::StatsMgr::instance().addValue("pkt4-received",
+                                              static_cast<int64_t>(1));
 
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
+    // 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(&Dhcpv4Srv::unpackOptions, this,
+                                   _1, _2, _3));
 
-            // Pass incoming packet as argument
-            callout_handle->setArgument("query4", query);
+    bool skip_unpack = false;
 
-            // Call callouts
-            HooksManager::callCallouts(Hooks.hook_index_buffer4_receive_,
-                                       *callout_handle);
+    // The packet has just been received so contains the uninterpreted wire
+    // data; execute callouts registered for buffer4_receive.
+    if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            // 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_DHCP4_DETAIL, DHCP4_HOOK_BUFFER_RCVD_SKIP)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getIface());
-                skip_unpack = true;
-            }
+        // Delete previously set arguments
+        callout_handle->deleteAllArguments();
 
-            callout_handle->getArgument("query4", query);
+        // Pass incoming packet as argument
+        callout_handle->setArgument("query4", query);
 
-            /// @todo: add support for DROP status
-        }
+        // Call callouts
+        HooksManager::callCallouts(Hooks.hook_index_buffer4_receive_,
+                                   *callout_handle);
 
-        // Unpack the packet information unless the buffer4_receive callouts
-        // indicated they did it
-        if (!skip_unpack) {
-            try {
-                LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_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_packet4_logger, DBG_DHCP4_DETAIL,
-                          DHCP4_PACKET_DROP_0001)
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(query->getLocalAddr().toText())
-                    .arg(query->getIface())
-                    .arg(e.what());
-
-                // Increase the statistics of parse failues and dropped packets.
-                isc::stats::StatsMgr::instance().addValue("pkt4-parse-failed",
-                                                          static_cast<int64_t>(1));
-                isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
-                                                          static_cast<int64_t>(1));
-                continue;
-            }
+        // 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_DHCP4_DETAIL,
+                      DHCP4_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);
+        callout_handle->getArgument("query4", query);
 
-        // Assign this packet to one or more classes if needed. We need to do
-        // this before calling accept(), because getSubnet4() may need client
-        // class information.
-        classifyPacket(query);
+        /// @todo: add support for DROP status
+    }
 
-        // Check whether the message should be further processed or discarded.
-        // There is no need to log anything here. This function logs by itself.
-        if (!accept(query)) {
-            // Increase the statistic of dropped packets.
+    // Unpack the packet information unless the buffer4_receive callouts
+    // indicated they did it
+    if (!skip_unpack) {
+        try {
+            LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_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_packet4_logger, DBG_DHCP4_DETAIL,
+                      DHCP4_PACKET_DROP_0001)
+                .arg(query->getRemoteAddr().toText())
+                .arg(query->getLocalAddr().toText())
+                .arg(query->getIface())
+                .arg(e.what());
+
+            // Increase the statistics of parse failues and dropped packets.
+            isc::stats::StatsMgr::instance().addValue("pkt4-parse-failed",
+                                                      static_cast<int64_t>(1));
             isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
                                                       static_cast<int64_t>(1));
-            continue;
+            return;
         }
+    }
 
-        // We have sanity checked (in accept() that the Message Type option
-        // exists, so we can safely get it here.
-        int type = query->getType();
-        LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_PACKET_RECEIVED)
-            .arg(query->getLabel())
-            .arg(query->getName())
-            .arg(type)
-            .arg(query->getRemoteAddr())
-            .arg(query->getLocalAddr())
-            .arg(query->getIface());
-        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
-            .arg(query->getLabel())
-            .arg(query->toText());
+    // Update statistics accordingly for received packet.
+    processStatsReceived(query);
 
-        // Let's execute all callouts registered for pkt4_receive
-        if (HooksManager::calloutsPresent(hook_index_pkt4_receive_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+    // Assign this packet to one or more classes if needed. We need to do
+    // this before calling accept(), because getSubnet4() may need client
+    // class information.
+    classifyPacket(query);
 
-            // Delete previously set arguments
-            callout_handle->deleteAllArguments();
+    // Check whether the message should be further processed or discarded.
+    // There is no need to log anything here. This function logs by itself.
+    if (!accept(query)) {
+        // Increase the statistic of dropped packets.
+        isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+                                                  static_cast<int64_t>(1));
+        return;
+    }
 
-            // Pass incoming packet as argument
-            callout_handle->setArgument("query4", query);
+    // We have sanity checked (in accept() that the Message Type option
+    // exists, so we can safely get it here.
+    int type = query->getType();
+    LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_PACKET_RECEIVED)
+        .arg(query->getLabel())
+        .arg(query->getName())
+        .arg(type)
+        .arg(query->getRemoteAddr())
+        .arg(query->getLocalAddr())
+        .arg(query->getIface());
+    LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
+        .arg(query->getLabel())
+        .arg(query->toText());
+
+    // Let's execute all callouts registered for pkt4_receive
+    if (HooksManager::calloutsPresent(hook_index_pkt4_receive_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            // Call callouts
-            HooksManager::callCallouts(hook_index_pkt4_receive_,
-                                       *callout_handle);
+        // Delete previously set arguments
+        callout_handle->deleteAllArguments();
 
-            // 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_DHCP4_HOOKS, DHCP4_HOOK_PACKET_RCVD_SKIP)
-                    .arg(query->getLabel());
-                continue;
-            }
+        // Pass incoming packet as argument
+        callout_handle->setArgument("query4", query);
 
-            /// @todo: Add support for DROP status
+        // Call callouts
+        HooksManager::callCallouts(hook_index_pkt4_receive_,
+                                   *callout_handle);
 
-            callout_handle->getArgument("query4", 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_DHCP4_HOOKS,
+                      DHCP4_HOOK_PACKET_RCVD_SKIP)
+                .arg(query->getLabel());
+            return;
         }
 
-        try {
-            switch (query->getType()) {
-            case DHCPDISCOVER:
-                rsp = processDiscover(query);
-                break;
-
-            case DHCPREQUEST:
-                // Note that REQUEST is used for many things in DHCPv4: for
-                // requesting new leases, renewing existing ones and even
-                // for rebinding.
-                rsp = processRequest(query);
-                break;
-
-            case DHCPRELEASE:
-                processRelease(query);
-                break;
-
-            case DHCPDECLINE:
-                processDecline(query);
-                break;
-
-            case DHCPINFORM:
-                rsp = processInform(query);
-                break;
-
-            default:
-                // Only action is to output a message if debug is enabled,
-                // and that is covered by the debug statement before the
-                // "switch" statement.
-                ;
-            }
-        } catch (const std::exception& e) {
+        /// @todo: Add support for DROP status
 
-            // Catch-all exception (we used to call only isc::Exception, but
-            // std::exception could potentially be raised and if we don't catch
-            // it here, it would be caught in main() and the process would
-            // terminate).  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_packet4_logger, DBG_DHCP4_BASIC,
-                      DHCP4_PACKET_DROP_0007)
-                .arg(query->getLabel())
-                .arg(e.what());
+        callout_handle->getArgument("query4", query);
+    }
 
-            // Increase the statistic of dropped packets.
-            isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
-                                                      static_cast<int64_t>(1));
-        }
+    try {
+        switch (query->getType()) {
+        case DHCPDISCOVER:
+            rsp = processDiscover(query);
+            break;
 
-        if (!rsp) {
-            continue;
-        }
+        case DHCPREQUEST:
+            // Note that REQUEST is used for many things in DHCPv4: for
+            // requesting new leases, renewing existing ones and even
+            // for rebinding.
+            rsp = processRequest(query);
+            break;
 
+        case DHCPRELEASE:
+            processRelease(query);
+            break;
 
-        // Specifies if server should do the packing
-        bool skip_pack = false;
+        case DHCPDECLINE:
+            processDecline(query);
+            break;
 
-        // Execute all callouts registered for pkt4_send
-        if (HooksManager::calloutsPresent(hook_index_pkt4_send_)) {
-            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+        case DHCPINFORM:
+            rsp = processInform(query);
+            break;
 
-            // Delete all previous arguments
-            callout_handle->deleteAllArguments();
+        default:
+            // Only action is to output a message if debug is enabled,
+            // and that is covered by the debug statement before the
+            // "switch" statement.
+            ;
+        }
+    } catch (const std::exception& e) {
+
+        // Catch-all exception (we used to call only isc::Exception, but
+        // std::exception could potentially be raised and if we don't catch
+        // it here, it would be caught in main() and the process would
+        // terminate).  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_packet4_logger, DBG_DHCP4_BASIC,
+                  DHCP4_PACKET_DROP_0007)
+            .arg(query->getLabel())
+            .arg(e.what());
 
-            // Clear skip flag if it was set in previous callouts
-            callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+        // Increase the statistic of dropped packets.
+        isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+                                                  static_cast<int64_t>(1));
+    }
 
-            // Set our response
-            callout_handle->setArgument("response4", rsp);
+    if (!rsp) {
+        return;
+    }
 
-            // Also pass the corresponding query packet as argument
-            callout_handle->setArgument("query4", query);
+    // Specifies if server should do the packing
+    bool skip_pack = false;
 
-            // Call all installed callouts
-            HooksManager::callCallouts(hook_index_pkt4_send_,
-                                       *callout_handle);
+    // Execute all callouts registered for pkt4_send
+    if (HooksManager::calloutsPresent(hook_index_pkt4_send_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-            // Callouts decided to skip the next processing step. The next
-            // processing step would to send the packet, so skip at this
-            // stage means "drop response".
-            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
-                LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS, DHCP4_HOOK_PACKET_SEND_SKIP)
-                    .arg(query->getLabel());
-                skip_pack = true;
-            }
+        // Delete all previous arguments
+        callout_handle->deleteAllArguments();
 
-            /// @todo: Add support for DROP status
-        }
+        // Clear skip flag if it was set in previous callouts
+        callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
 
-        if (!skip_pack) {
-            try {
-                LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_PACK)
-                    .arg(rsp->getLabel());
-                rsp->pack();
-            } catch (const std::exception& e) {
-                LOG_ERROR(options4_logger, DHCP4_PACKET_PACK_FAIL)
-                    .arg(rsp->getLabel())
-                    .arg(e.what());
-            }
-        }
+        // Also pass the corresponding query packet as argument
+        callout_handle->setArgument("query4", query);
 
-        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 buffer4_send
-            if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
-                CalloutHandlePtr callout_handle = getCalloutHandle(query);
-
-                // Delete previously set arguments
-                callout_handle->deleteAllArguments();
-
-                // Pass incoming packet as argument
-                callout_handle->setArgument("response4", rsp);
-
-                // Call callouts
-                HooksManager::callCallouts(Hooks.hook_index_buffer4_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_DHCP4_HOOKS,
-                              DHCP4_HOOK_BUFFER_SEND_SKIP)
-                        .arg(rsp->getLabel());
-                    continue;
-                }
+        // Set our response
+        callout_handle->setArgument("response4", rsp);
 
-                /// @todo: Add support for DROP status.
+        // Also pass the corresponding query packet as argument
+        callout_handle->setArgument("query4", query);
 
-                callout_handle->getArgument("response4", rsp);
-            }
+        // Call all installed callouts
+        HooksManager::callCallouts(hook_index_pkt4_send_,
+                                   *callout_handle);
 
-            LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
-                .arg(rsp->getLabel())
-                .arg(rsp->getName())
-                .arg(static_cast<int>(rsp->getType()))
-                .arg(rsp->getLocalAddr())
-                .arg(rsp->getLocalPort())
-                .arg(rsp->getRemoteAddr())
-                .arg(rsp->getRemotePort())
-                .arg(rsp->getIface());
-
-            LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
-                      DHCP4_RESPONSE_DATA)
-                .arg(rsp->getLabel())
-                .arg(rsp->getName())
-                .arg(static_cast<int>(rsp->getType()))
-                .arg(rsp->toText());
-            sendPacket(rsp);
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to send the packet, so skip at this
+        // stage means "drop response".
+        if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
+            LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
+                      DHCP4_HOOK_PACKET_SEND_SKIP)
+                .arg(query->getLabel());
+            skip_pack = true;
+        }
 
-            // Update statistics accordingly for sent packet.
-            processStatsSent(rsp);
+        /// @todo: Add support for DROP status
+    }
 
+    if (!skip_pack) {
+        try {
+            LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_PACK)
+                .arg(rsp->getLabel());
+            rsp->pack();
         } catch (const std::exception& e) {
-            LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
+            LOG_ERROR(options4_logger, DHCP4_PACKET_PACK_FAIL)
                 .arg(rsp->getLabel())
                 .arg(e.what());
         }
+    }
 
-        } 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)
-                .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");
+    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 buffer4_send
+        if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
+            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+            // Delete previously set arguments
+            callout_handle->deleteAllArguments();
+
+            // Pass incoming packet as argument
+            callout_handle->setArgument("response4", rsp);
+
+            // Call callouts
+            HooksManager::callCallouts(Hooks.hook_index_buffer4_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_DHCP4_HOOKS,
+                          DHCP4_HOOK_BUFFER_SEND_SKIP)
+                    .arg(rsp->getLabel());
+                return;
+            }
+
+            /// @todo: Add support for DROP status.
+
+            callout_handle->getArgument("response4", rsp);
         }
-    }
 
-    return (true);
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
+            .arg(rsp->getLabel())
+            .arg(rsp->getName())
+            .arg(static_cast<int>(rsp->getType()))
+            .arg(rsp->getLocalAddr())
+            .arg(rsp->getLocalPort())
+            .arg(rsp->getRemoteAddr())
+            .arg(rsp->getRemotePort())
+            .arg(rsp->getIface());
+
+        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
+                  DHCP4_RESPONSE_DATA)
+            .arg(rsp->getLabel())
+            .arg(rsp->getName())
+            .arg(static_cast<int>(rsp->getType()))
+            .arg(rsp->toText());
+        sendPacket(rsp);
+
+        // Update statistics accordingly for sent packet.
+        processStatsSent(rsp);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
+            .arg(rsp->getLabel())
+            .arg(e.what());
+    }
 }
 
 string

+ 11 - 3
src/bin/dhcp4/dhcp4_srv.h

@@ -208,14 +208,22 @@ 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. Receives incoming packets, and calls
+    /// processPakcet for each of them.
     ///
     /// @return true, if being shut down gracefully, fail if experienced
     ///         critical error.
     bool run();
 
+    /// @brief Process a single incoming DHCPv4 packet.
+    ///
+    /// It verifies correctness of the passed packet, call per-type processXXX
+    /// methods, generates appropriate answer (if needed) and (if necessary)
+    /// transmits a response.
+    ///
+    /// @param query A pointer to the packet to be processed.
+    void processPacket(Pkt4Ptr& query);
+
     /// @brief Instructs the server to shut down.
     void shutdown();