diff options
Diffstat (limited to 'src/lib/hooks/tests/async_callout_library.cc')
-rw-r--r-- | src/lib/hooks/tests/async_callout_library.cc | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/lib/hooks/tests/async_callout_library.cc b/src/lib/hooks/tests/async_callout_library.cc new file mode 100644 index 0000000..5f40e52 --- /dev/null +++ b/src/lib/hooks/tests/async_callout_library.cc @@ -0,0 +1,153 @@ +// Copyright (C) 2018 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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// @file +/// @brief Async callout library +/// +/// This is source of a test library for testing a "parking" feature, i.e. +/// the callouts can schedule asynchronous operation and indicate that the +/// packet should be parked until the asynchronous operation completes and +/// the hooks library indicates that packet processing should be resumed. + +#include <config.h> +#include <hooks/hooks.h> +#include <hooks/parking_lots.h> +#include <log/logger.h> +#include <log/macros.h> +#include <log/message_initializer.h> +#include <algorithm> +#include <functional> +#include <sstream> +#include <string> +#include <vector> + +using namespace isc::hooks; +using namespace isc::log; +using namespace std; + +namespace { + +/// @brief Logger used by the library. +isc::log::Logger logger("acl"); + +/// @brief Log messages. +const char* log_messages[] = { + "ACL_LOAD_START", "async callout load %1", + "ACL_LOAD_END", "async callout load end", + "ACL_LOAD_END", "duplicate of async callout load end", + NULL +}; + +/// @brief Initializer for log messages. +const MessageInitializer message_initializer(log_messages); + +/// @brief Simple callback which unparks parked object. +/// +/// @param parking_lot parking lot where the object is parked. +/// @param parked_object parked object. +void unpark(ParkingLotHandlePtr parking_lot, const std::string& parked_object) { + parking_lot->unpark(parked_object); +} + +} // end of anonymous namespace + +extern "C" { + +/// @brief Callout scheduling object parking and providing function to unpark +/// it. +/// +/// This callout is crafted to test the following scenario. The callout returns +/// status "park" to indicate that the packet should be parked. The callout +/// performs asynchronous operation and indicates that the packet should be +/// unparked when this operation completes. Unparking the packet triggers a +/// function associated with the parked packet, e.g. a function which continues +/// processing of this packet. +/// +/// This test callout "parks" a string object instead of a packet. It assumes +/// that there might be multiple callouts installed on this hook point, which +/// all trigger asynchronous operation. The object must be unparked when the +/// last asynchronous operation completes. Therefore, it calls the @c reference +/// function on the parking lot object to increase the reference count. The +/// object remains parked as long as the reference counter is greater than +/// 0. +/// +/// The callout returns 1 or more pointers to the functions which should be +/// called by the unit tests to simulate completion of the asynchronous tasks. +/// When the test calls those functions, @c unpark function is called, which +/// decreases reference count on the parked object, or actually unparks the +/// object when the reference count reaches 0. +/// +/// @param handle Reference to callout handle used to set/get arguments. +int +hookpt_one(CalloutHandle& handle) { + // Using a string as "parked" object. + std::string parked_object; + handle.getArgument("parked_object", parked_object); + + // Retrieve the parking lot handle for this hook point. It allows for + // increasing a reference count on the parked object and also for + // scheduling packet unparking. + ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr(); + + // Increase the reference count to indicate that this callout needs the + // object to remain parked until the asynchronous operation completes. + // Otherwise, other callouts could potentially call unpark and cause the + // packet processing to continue before the asynchronous operation + // completes. + parking_lot->reference(parked_object); + + // Create pointer to the function that the test should call to simulate + // completion of the asynchronous operation scheduled by this callout. + std::function<void()> unpark_trigger_func = + std::bind(unpark, parking_lot, parked_object); + + // Every callout (if multiple callouts installed on this hook point) should + // return the function pointer under unique name. The base name is + // "unpark_trigger" and the callouts append consecutive numbers to this + // base name, e.g. "unpark_trigger1", "unpark_trigger2" etc. + + std::string fun_name; + std::vector<std::string> args = handle.getArgumentNames(); + unsigned i = 1; + do { + std::ostringstream candidate_name; + candidate_name << "unpark_trigger" << i; + if (std::find(args.begin(), args.end(), candidate_name.str()) == + args.end()) { + fun_name = candidate_name.str(); + + } else { + ++i; + } + } while (fun_name.empty()); + + handle.setArgument(fun_name, unpark_trigger_func); + + handle.setStatus(CalloutHandle::NEXT_STEP_PARK); + + return (0); +} + +// Framework functions. + +int +version() { + return (KEA_HOOKS_VERSION); +} + +// load() initializes the user library if the main image was statically linked. +int +load(isc::hooks::LibraryHandle&) { +#ifdef USE_STATIC_LINK + hooksStaticLinkInit(); +#endif + LOG_INFO(logger, "ACL_LOAD_START").arg("argument"); + LOG_INFO(logger, "ACL_LOAD_END"); + return (0); +} + +} + |