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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright (C) 2020 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/.

#ifndef CLIENT_HANDLER_H
#define CLIENT_HANDLER_H

#include <dhcp/pkt6.h>
#include <boost/noncopyable.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/multi_index_container.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/multi_index/hashed_index.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/multi_index/member.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/shared_ptr.hpp><--- 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 <mutex><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <thread><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp {

/// @brief Define the type of packet processing continuation.
typedef std::function<void()> Continuation;

/// @brief Define the type of shared pointers to continuations.
typedef boost::shared_ptr<Continuation> ContinuationPtr;

/// @brief Continuation factory.
///
/// @param cont Continuation rvalue.
inline ContinuationPtr makeContinuation(Continuation&& cont) {
    return (boost::make_shared<Continuation>(cont));
}

/// @brief Client race avoidance RAII handler.
class ClientHandler : public boost::noncopyable {
private:

    /// Class (aka static) types, methods and members.

    /// @brief Structure representing a client.
    struct Client {

        /// @brief Constructor.
        ///
        /// @param query The query.
        /// @param client_id The client ID.
        /// @throw if the query is null or has empty client ID.
        Client(Pkt6Ptr query, DuidPtr client_id);

        /// @brief The query being processed.
        Pkt6Ptr query_;

        /// @brief Cached binary client ID.
        std::vector<uint8_t> duid_;

        /// @brief The ID of the thread processing the query.
        std::thread::id thread_;

        /// @brief The next query.
        ///
        /// @note This field can be modified from another handler
        /// holding the mutex.
        Pkt6Ptr next_query_;

        /// @brief The continuation to process next query for the client.
        ///
        /// @note This field can be modified from another handler
        /// holding the mutex.
        ContinuationPtr cont_;
    };

    /// @brief The type of shared pointers to clients.
    typedef boost::shared_ptr<Client> ClientPtr;

    /// @brief The type of the client container.
    typedef boost::multi_index_container<

        // This container stores pointers to client objects.
        ClientPtr,

        // Start specification of indexes here.
        boost::multi_index::indexed_by<

            // First index is used to search by Duid.
            boost::multi_index::hashed_unique<

                // Client ID binary content as a member of the Client object.
                boost::multi_index::member<
                    Client, std::vector<uint8_t>, &Client::duid_
                >
            >
        >
    > ClientContainer;

    /// @brief Lookup a client.
    ///
    /// The mutex must be held by the caller.
    ///
    /// @param duid The duid of the query from the client.
    /// @return The client found in the container or null.
    static ClientPtr lookup(const DuidPtr& duid);

    /// @brief Add a client.
    ///
    /// The mutex must be held by the caller.
    ///
    /// @param client The client to insert into the client container.
    static void add(const ClientPtr& client);

    /// @brief Delete a client.
    ///
    /// The mutex must be held by the caller.
    ///
    /// @param duid The duid to delete from the client container.
    static void del(const DuidPtr& duid);

    /// @brief Mutex to protect the client container.
    ///
    /// The mutex is used only by public methods for guards.
    static std::mutex mutex_;

    /// @brief The client container.
    static ClientContainer clients_;

public:

    /// Public interface.

    /// @brief Constructor.
    ClientHandler();

    /// @brief Destructor.
    ///
    /// Releases the client if it was acquired.
    virtual ~ClientHandler();

    /// @brief Tries to acquires a client.
    ///
    /// Lookup the client:
    ///  - if not found insert the client in the clients map and return true
    ///  - if found, if has a continuation put it in the holder,
    ///    and return false
    ///
    /// @param query The query from the client.
    /// @param cont The continuation in the case the client was held.
    /// @return true if the client was acquired, false if there is already
    /// a query from the same client.
    bool tryLock(Pkt6Ptr query, ContinuationPtr cont = ContinuationPtr());

private:

    /// Instance methods and members.

    /// @brief Acquire a client.
    ///
    /// The mutex must be held by the caller.
    void lock();

    /// @brief Release a client.
    ///
    /// If the client has a continuation, push it at front of the thread
    /// packet queue.
    ///
    /// The mutex must be held by the only caller: the destructor.
    void unLock();

    /// @brief Local client.
    ClientPtr client_;

    /// @brief Client ID locked by this handler.
    DuidPtr locked_;
};

} // namespace isc
} // namespace dhcp

#endif // CLIENT_HANDLER_H