diff options
author | Razvan Becheriu <razvan@isc.org> | 2023-05-03 09:27:19 +0200 |
---|---|---|
committer | Razvan Becheriu <razvan@isc.org> | 2023-05-03 09:30:15 +0200 |
commit | de4d529088d7648f46aeef8f9f55e2c4683bf39a (patch) | |
tree | 865a09bd84b133f5200c793ea3d2ebf6dc804025 /src/lib/hooks | |
parent | [#2798] fixed compilation warnings (diff) | |
download | kea-de4d529088d7648f46aeef8f9f55e2c4683bf39a.tar.xz kea-de4d529088d7648f46aeef8f9f55e2c4683bf39a.zip |
[#2805] ignore exceptions on callouts but set DROP flag
Diffstat (limited to 'src/lib/hooks')
-rw-r--r-- | src/lib/hooks/callout_manager.cc | 27 | ||||
-rw-r--r-- | src/lib/hooks/tests/callout_manager_unittest.cc | 119 |
2 files changed, 108 insertions, 38 deletions
diff --git a/src/lib/hooks/callout_manager.cc b/src/lib/hooks/callout_manager.cc index 5505567465..481da0e8ad 100644 --- a/src/lib/hooks/callout_manager.cc +++ b/src/lib/hooks/callout_manager.cc @@ -40,7 +40,6 @@ CalloutManager::CalloutManager(int num_libraries) // (n is the number of libraries), 0 (pre-user library callouts), or INT_MAX // (post-user library callouts). It can also be -1 to indicate an invalid // value. - void CalloutManager::checkLibraryIndex(int library_index) const { if (((library_index >= -1) && (library_index <= num_libraries_)) || @@ -54,7 +53,6 @@ CalloutManager::checkLibraryIndex(int library_index) const { } // Register a callout for the current library. - void CalloutManager::registerCallout(const std::string& name, CalloutPtr callout, @@ -94,7 +92,6 @@ CalloutManager::registerCallout(const std::string& name, } // Check if callouts are present for a given hook index. - bool CalloutManager::calloutsPresent(int hook_index) const { // Validate the hook index. @@ -127,9 +124,7 @@ CalloutManager::commandHandlersPresent(const std::string& command_name) const { return (false); } - // Call all the callouts for a given hook. - void CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) { // Clear the "skip" flag so we don't carry state from a previous call. @@ -185,15 +180,27 @@ CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) { // If an exception occurred, the stopwatch.stop() hasn't been // called, so we have to call it here. stopwatch.stop(); - // Any exception, not just ones based on isc::Exception + // Any exception, just ones based on isc::Exception LOG_ERROR(callouts_logger, HOOKS_CALLOUT_EXCEPTION) .arg(server_hooks_.getName(callout_handle.getCurrentHook())) .arg(callout_handle.getCurrentLibrary()) .arg(PointerConverter(i->second).dlsymPtr()) .arg(e.what()) .arg(stopwatch.logFormatLastDuration()); + callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP); + } catch (...) { + // If an exception occurred, the stopwatch.stop() hasn't been + // called, so we have to call it here. + stopwatch.stop(); + // Any exception, not just ones based on isc::Exception + LOG_ERROR(callouts_logger, HOOKS_CALLOUT_EXCEPTION) + .arg(server_hooks_.getName(callout_handle.getCurrentHook())) + .arg(callout_handle.getCurrentLibrary()) + .arg(PointerConverter(i->second).dlsymPtr()) + .arg("Unspecified exception") + .arg(stopwatch.logFormatLastDuration()); + callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP); } - } // Mark end of callout execution. Include the total execution @@ -216,15 +223,12 @@ CalloutManager::callCommandHandlers(const std::string& command_name, // This will throw an exception if the hook point doesn't exist. // The caller should check if the hook point exists by calling // commandHandlersPresent. - int index = ServerHooks::getServerHooks().getIndex( - ServerHooks::commandToHookName(command_name)); + int index = ServerHooks::getServerHooks().getIndex(ServerHooks::commandToHookName(command_name)); // Call the handlers for this command. callCallouts(index, callout_handle); } - // Deregister a callout registered by the current library on a particular hook. - bool CalloutManager::deregisterCallout(const std::string& name, CalloutPtr callout, int library_index) { @@ -278,7 +282,6 @@ CalloutManager::deregisterCallout(const std::string& name, CalloutPtr callout, } // Deregister all callouts on a given hook. - bool CalloutManager::deregisterAllCallouts(const std::string& name, int library_index) { diff --git a/src/lib/hooks/tests/callout_manager_unittest.cc b/src/lib/hooks/tests/callout_manager_unittest.cc index b487a3655c..9d757f870f 100644 --- a/src/lib/hooks/tests/callout_manager_unittest.cc +++ b/src/lib/hooks/tests/callout_manager_unittest.cc @@ -139,7 +139,6 @@ int callout_seven(CalloutHandle&) { } // The next functions are duplicates of some of the above, but return an error. - int callout_one_error(CalloutHandle& handle) { (void) callout_one(handle); return (1); @@ -160,14 +159,38 @@ int callout_four_error(CalloutHandle& handle) { return (1); } -}; // extern "C" +// The next functions are duplicates of some of the above, but throw exceptions. +int callout_one_exception(CalloutHandle& handle) { + (void) callout_one(handle); + throw 0; + return (1); +} + +int callout_two_exception(CalloutHandle& handle) { + (void) callout_two(handle); + throw 0; + return (1); +} + +int callout_three_exception(CalloutHandle& handle) { + (void) callout_three(handle); + throw 0; + return (1); +} + +int callout_four_exception(CalloutHandle& handle) { + (void) callout_four(handle); + throw 0; + return (1); +} + +} // extern "C" // *** Callout Tests *** // // The next set of tests check that callouts can be called. // Constructor - check that we trap bad parameters. - TEST_F(CalloutManagerTest, BadConstructorParameters) { boost::scoped_ptr<CalloutManager> cm; @@ -176,7 +199,6 @@ TEST_F(CalloutManagerTest, BadConstructorParameters) { } // Check the number of libraries is reported successfully. - TEST_F(CalloutManagerTest, NumberOfLibraries) { boost::scoped_ptr<CalloutManager> cm; @@ -196,7 +218,6 @@ TEST_F(CalloutManagerTest, NumberOfLibraries) { } // Check that we can only set the current library index to the correct values. - TEST_F(CalloutManagerTest, CheckLibraryIndex) { // Check valid indexes. As the callout manager is sized for 10 libraries, // we expect: @@ -220,16 +241,13 @@ TEST_F(CalloutManagerTest, CheckLibraryIndex) { } // Check that we can only register callouts on valid hook names. - TEST_F(CalloutManagerTest, ValidHookNames) { EXPECT_NO_THROW(getCalloutManager()->registerCallout("alpha", callout_one, 0)); EXPECT_THROW(getCalloutManager()->registerCallout("unknown", callout_one, 0), NoSuchHook); } - // Check we can register callouts appropriately. - TEST_F(CalloutManagerTest, RegisterCallout) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -288,7 +306,6 @@ TEST_F(CalloutManagerTest, RegisterCallout) { } // Check the "calloutsPresent()" method. - TEST_F(CalloutManagerTest, CalloutsPresent) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -319,7 +336,6 @@ TEST_F(CalloutManagerTest, CalloutsPresent) { } // Test that calling a hook with no callouts on it returns success. - TEST_F(CalloutManagerTest, CallNoCallouts) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -336,7 +352,6 @@ TEST_F(CalloutManagerTest, CallNoCallouts) { // Test that the callouts are called in the correct order (i.e. the callouts // from the first library in the order they were registered, then the callouts // from the second library in the order they were registered etc.) - TEST_F(CalloutManagerTest, CallCalloutsSuccess) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -369,11 +384,10 @@ TEST_F(CalloutManagerTest, CallCalloutsSuccess) { } // Test that the callouts are called in order, but that callouts occurring -// after a callout that returns an error are not called. +// after a callout that returns an error are called. // // (Note: in this test, the callouts that return an error set the value of // callout_value_ before they return the error code.) - TEST_F(CalloutManagerTest, CallCalloutsError) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -430,8 +444,72 @@ TEST_F(CalloutManagerTest, CallCalloutsError) { EXPECT_EQ(11223344, callout_value_); } -// Now test that we can deregister a single callout on a hook. +// Test that the callouts are called in order, but that callouts occurring +// after a callout that throws exception are called. +// +// (Note: in this test, the callouts that return an error set the value of +// callout_value_ before they throw exception.) +TEST_F(CalloutManagerTest, CallCalloutsException) { + // Ensure that no callouts are attached to any of the hooks. + EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); + EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_)); + EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_)); + EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_)); + // Each library contributing one callout on hook "alpha". The first callout + // returns an error (after adding its value to the result). + callout_value_ = 0; + getCalloutManager()->registerCallout("alpha", callout_one_exception, 0); + getCalloutManager()->registerCallout("alpha", callout_two, 1); + getCalloutManager()->registerCallout("alpha", callout_three, 2); + getCalloutManager()->registerCallout("alpha", callout_four, 3); + getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle()); + EXPECT_EQ(1234, callout_value_); + EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP); + + // Each library contributing multiple callouts on hook "beta". The last + // callout on the first library returns an error. + callout_value_ = 0; + getCalloutManager()->registerCallout("beta", callout_one, 0); + getCalloutManager()->registerCallout("beta", callout_one_exception, 0); + getCalloutManager()->registerCallout("beta", callout_two, 1); + getCalloutManager()->registerCallout("beta", callout_two, 1); + getCalloutManager()->registerCallout("beta", callout_three, 1); + getCalloutManager()->registerCallout("beta", callout_three, 1); + getCalloutManager()->registerCallout("beta", callout_four, 3); + getCalloutManager()->registerCallout("beta", callout_four, 3); + getCalloutManager()->callCallouts(beta_index_, getCalloutHandle()); + EXPECT_EQ(11223344, callout_value_); + EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP); + + // A callout in a random position in the callout list returns an error. + callout_value_ = 0; + getCalloutManager()->registerCallout("gamma", callout_one, 0); + getCalloutManager()->registerCallout("gamma", callout_one, 0); + getCalloutManager()->registerCallout("gamma", callout_two, 1); + getCalloutManager()->registerCallout("gamma", callout_two, 1); + getCalloutManager()->registerCallout("gamma", callout_four_exception, 3); + getCalloutManager()->registerCallout("gamma", callout_four, 3); + getCalloutManager()->callCallouts(gamma_index_, getCalloutHandle()); + EXPECT_EQ(112244, callout_value_); + EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP); + + // The last callout on a hook returns an error. + callout_value_ = 0; + getCalloutManager()->registerCallout("delta", callout_one, 0); + getCalloutManager()->registerCallout("delta", callout_one, 0); + getCalloutManager()->registerCallout("delta", callout_two, 1); + getCalloutManager()->registerCallout("delta", callout_two, 1); + getCalloutManager()->registerCallout("delta", callout_three, 2); + getCalloutManager()->registerCallout("delta", callout_three, 2); + getCalloutManager()->registerCallout("delta", callout_four, 3); + getCalloutManager()->registerCallout("delta", callout_four_exception, 3); + getCalloutManager()->callCallouts(delta_index_, getCalloutHandle()); + EXPECT_EQ(11223344, callout_value_); + EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP); +} + +// Now test that we can deregister a single callout on a hook. TEST_F(CalloutManagerTest, DeregisterSingleCallout) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -455,7 +533,6 @@ TEST_F(CalloutManagerTest, DeregisterSingleCallout) { // Now test that we can deregister a single callout on a hook that has multiple // callouts from the same library. - TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -484,11 +561,9 @@ TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) { callout_value_ = 0; getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle()); EXPECT_EQ(134, callout_value_); - } // Check we can deregister multiple callouts from the same library. - TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -539,7 +614,6 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { } // Check we can deregister multiple callouts from multiple libraries. - TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsMultipleLibraries) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -567,7 +641,6 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsMultipleLibraries) { } // Check we can deregister all callouts from a single library. - TEST_F(CalloutManagerTest, DeregisterAllCallouts) { // Ensure that no callouts are attached to hook one. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -599,7 +672,6 @@ TEST_F(CalloutManagerTest, DeregisterAllCallouts) { // Check that we can register/deregister callouts on different libraries // and different hooks, and that the callout instances are regarded as // unique and do not affect one another. - TEST_F(CalloutManagerTest, MultipleCalloutsLibrariesHooks) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -653,7 +725,6 @@ TEST_F(CalloutManagerTest, MultipleCalloutsLibrariesHooks) { // only register and deregister callouts within its library) require that // the CalloutHandle object pass the appropriate LibraryHandle to the // callout. These tests are done in the handles_unittest tests. - TEST_F(CalloutManagerTest, LibraryHandleRegistration) { // Ensure that no callouts are attached to any of the hooks. EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -747,7 +818,6 @@ TEST_F(CalloutManagerTest, LibraryHandleAlternateConstructor) { // Check that the pre- and post- user callout library handles work // appropriately with no user libraries. - TEST_F(CalloutManagerTest, LibraryHandlePrePostNoLibraries) { // Create a local callout manager and callout handle to reflect no libraries // being loaded. @@ -779,7 +849,6 @@ TEST_F(CalloutManagerTest, LibraryHandlePrePostNoLibraries) { } // Repeat the tests with one user library. - TEST_F(CalloutManagerTest, LibraryHandlePrePostUserLibrary) { // Setup the pre-, library and post callouts. @@ -805,7 +874,6 @@ TEST_F(CalloutManagerTest, LibraryHandlePrePostUserLibrary) { } // Test that control command handlers can be installed as callouts. - TEST_F(CalloutManagerTest, LibraryHandleRegisterCommandHandler) { CalloutHandle handle(getCalloutManager()); @@ -869,9 +937,8 @@ TEST_F(CalloutManagerTest, VectorSize) { EXPECT_EQ(s + 1, getCalloutManager()->getHookLibsVectorSize()); } - // The setting of the hook index is checked in the handles_unittest // set of tests, as access restrictions mean it is not easily tested // on its own. -} // Anonymous namespace +} // namespace |