1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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 file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <functional><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <sstream><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <vector><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

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);
}

}