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
154
155
156
157
158
159
160
161
162
// Copyright (C) 2023-2024 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/.

#include <config.h>

#include <exceptions/exceptions.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/tracking_lease_mgr.h>
#include <util/multi_threading_mgr.h>
#include <boost/foreach.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/tuple/tuple.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

using namespace isc::asiolink;
using namespace isc::util;

namespace isc {
namespace dhcp {

TrackingLeaseMgr::TrackingLeaseMgr()
    : LeaseMgr(), callbacks_(new TrackingLeaseMgr::CallbackContainer()) {
}

bool
TrackingLeaseMgr::tryLock(const LeasePtr& lease) {
    // Try inserting a lease. If such a lease already exists in the set, return false.
    auto result = locked_leases_.insert(lease->addr_);
    return (result.second);
}

void
TrackingLeaseMgr::unlock(const LeasePtr& lease) {
    // Remove the locked lease from the set.
    locked_leases_.erase(lease->addr_);
}

bool
TrackingLeaseMgr::isLocked(const LeasePtr& lease) {
    return (locked_leases_.find(lease->addr_) != locked_leases_.end());
}

void
TrackingLeaseMgr::trackAddLease(const LeasePtr& lease) {
    runCallbacks(TRACK_ADD_LEASE, lease);
}

void
TrackingLeaseMgr::trackUpdateLease(const LeasePtr& lease) {
    runCallbacks(TRACK_UPDATE_LEASE, lease);
}

void
TrackingLeaseMgr::trackDeleteLease(const LeasePtr& lease) {
    runCallbacks(TRACK_DELETE_LEASE, lease);
}

void
TrackingLeaseMgr::registerCallback(TrackingLeaseMgr::CallbackType type,
                                   std::string owner,
                                   SubnetID subnet_id,
                                   Lease::Type lease_type,
                                   TrackingLeaseMgr::CallbackFn callback_fn) {
    // The first index filters the callbacks by type and subnet_id.
    auto& idx = callbacks_->get<0>();
    auto range = idx.equal_range(boost::make_tuple(type, subnet_id, lease_type));
    if (range.first != range.second) {
        // Make sure that the callback for this owner does not exist.
        if (std::find_if(range.first, range.second,
                         [&owner] (const Callback& cb) -> bool {
                             return (cb.owner == owner);
                         }) != range.second) {
            isc_throw(InvalidOperation, "the callback owned by the " << owner
                      << ", for subnet ID " << subnet_id
                      << ", and lease type " << Lease::typeToText(lease_type)
                      << " has already been registered in the lease manager");
        }
    }
    TrackingLeaseMgr::Callback callback{type, owner, subnet_id, lease_type, callback_fn};
    callbacks_->insert(callback);
}

void
TrackingLeaseMgr::registerCallback(TrackingLeaseMgr::CallbackType type,
                                   std::string owner,<--- Function parameter 'owner' should be passed by const reference.
                                   Lease::Type lease_type,
                                   TrackingLeaseMgr::CallbackFn callback_fn) {
    registerCallback(type, owner, SUBNET_ID_GLOBAL, lease_type, callback_fn);
}

void
TrackingLeaseMgr::unregisterCallbacks(SubnetID subnet_id, Lease::Type lease_type) {
    // The second index filters the callbacks by the subnet identifier and
    // the lease type.
    auto& idx = callbacks_->get<1>();
    auto range = idx.equal_range(boost::make_tuple(subnet_id, lease_type));
    if (range.first != range.second) {
        idx.erase(range.first, range.second);
    }
}

void
TrackingLeaseMgr::unregisterAllCallbacks() {
    callbacks_->clear();
}

bool
TrackingLeaseMgr::hasCallbacks() const {
    return (!callbacks_->empty());
}

std::string
TrackingLeaseMgr::callbackTypeToString(CallbackType type) {
    switch (type) {
    case TrackingLeaseMgr::TRACK_ADD_LEASE:
        return ("add_lease");
    case TrackingLeaseMgr::TRACK_UPDATE_LEASE:
        return ("update_lease");
    case TrackingLeaseMgr::TRACK_DELETE_LEASE:
        return ("delete_lease");
    default:
        return ("unknown");
    }
}

void
TrackingLeaseMgr::runCallbacks(TrackingLeaseMgr::CallbackType type,
                               const LeasePtr& lease) {
    runCallbacksForSubnetID(type, SUBNET_ID_GLOBAL, lease);
    runCallbacksForSubnetID(type, lease->subnet_id_, lease);
}

void
TrackingLeaseMgr::runCallbacksForSubnetID(CallbackType type, SubnetID subnet_id,
                                          const LeasePtr& lease) {
    // The first index filters by callback type and subnet_id.
    auto& idx = callbacks_->get<0>();
    auto cbs = idx.equal_range(boost::make_tuple(type, subnet_id, lease->getType()));
    if (cbs.first == cbs.second) {
        return;
    }
    BOOST_FOREACH(auto const& cb, cbs) {
        try {
            cb.fn(lease);
        } catch (const std::exception& ex) {
            LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION)
                .arg(callbackTypeToString(type))
                .arg(subnet_id)
                .arg(lease->addr_.toText())
                .arg(ex.what());
        } catch (...) {
            LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION)
                .arg(callbackTypeToString(type))
                .arg(subnet_id)
                .arg(lease->addr_.toText());
        }
    }
}

} // end of namespace isc::dhcp
} // end of namespace isc