cql_lease_mgr.cc 71.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Copyright (C) 2015 - 2016 Deutsche Telekom AG.
//
// Author: Razvan Becheriu <razvan.becheriu@qualitance.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//           http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcpsrv/dhcpsrv_log.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
22
#include <dhcpsrv/cql_lease_mgr.h>
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <boost/static_assert.hpp>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <ctime>

using namespace isc;
using namespace isc::dhcp;
using namespace std;

namespace isc {
namespace dhcp {

37
38
static const size_t HOSTNAME_MAX_LEN = 255U;
static const size_t ADDRESS6_TEXT_MAX_LEN = 39U;
39

Tomek Mrugalski's avatar
Tomek Mrugalski committed
40
41
/// @name CqlBind auxiliary methods for binding data into Cassandra format:
/// @{
Tomek Mrugalski's avatar
Tomek Mrugalski committed
42
static CassError CqlBindNone(CassStatement* statement, size_t index, void*) {
43
44
45
    return cass_statement_bind_null(statement, index);
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
46
47
48
49
static CassError CqlBindBool(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_bool(statement, index,
        *(static_cast<cass_bool_t*>(value)));
50
51
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
52
53
54
55
static CassError CqlBindInt32(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_int32(statement, index,
        *(static_cast<cass_int32_t*>(value)));
56
57
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
58
59
60
61
static CassError CqlBindInt64(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_int64(statement, index,
        *(static_cast<cass_int64_t*>(value)));
62
63
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
64
65
66
67
static CassError CqlBindTimestamp(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_int64(statement, index,
        *(static_cast<cass_int64_t*>(value)));
68
69
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
70
71
72
73
static CassError CqlBindString(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_string(statement, index,
        (static_cast<const char*>(value)));
74
75
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
76
77
78
79
80
static CassError CqlBindBytes(CassStatement* statement, size_t index,
        void* value) {
    return cass_statement_bind_bytes(statement, index,
        static_cast<std::vector<cass_byte_t>*>(value)->data(),
        static_cast<std::vector<cass_byte_t>*>(value)->size());
81
}
Tomek Mrugalski's avatar
Tomek Mrugalski committed
82
/// @}
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
static CassError CqlGetNone(const CassValue*, void*, size_t*) {
    return CASS_OK;
}

static CassError CqlGetBool(const CassValue* value, void* data, size_t*) {
    return cass_value_get_bool(value, static_cast<cass_bool_t*>(data));
}

static CassError CqlGetInt32(const CassValue* value, void* data, size_t*) {
    return cass_value_get_int32(value, static_cast<cass_int32_t*>(data));
}

static CassError CqlGetInt64(const CassValue* value, void* data, size_t*) {
    return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
}

static CassError CqlGetTimestamp(const CassValue* value, void* data, size_t*) {
    return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
104
105
static CassError CqlGetString(const CassValue* value, void* data,
        size_t* size) {
106
107
108
109
    return cass_value_get_string(value, static_cast<const char**>(data), size);
}

static CassError CqlGetBytes(const CassValue* value, void* data, size_t* size) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
110
111
    return cass_value_get_bytes(value, static_cast<const cass_byte_t**>(data),
        size);
112
113
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
114
115
116
117
typedef CassError (*CqlBindFunction)(CassStatement* statement, size_t index,
        void* value);
typedef CassError (*CqlGetFunction)(const CassValue* value, void* data,
        size_t* size);
118
119
120
121

struct CqlFunctionData {
    CqlBindFunction sqlBindFunction_;
    CqlGetFunction sqlGetFunction_;
122
123
};

124
125
126
127
128
129
130
131
static struct CqlFunctionData CqlFunctions[] = {
    {CqlBindNone, CqlGetNone},
    {CqlBindBool, CqlGetBool},
    {CqlBindInt32, CqlGetInt32},
    {CqlBindInt64, CqlGetInt64},
    {CqlBindTimestamp, CqlGetTimestamp},
    {CqlBindString, CqlGetString},
    {CqlBindBytes, CqlGetBytes}
132
133
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
134
/// @brief Catalog of all the SQL statements currently supported. Note
135
/// that the order columns appear in statement body must match the order they
Tomek Mrugalski's avatar
Tomek Mrugalski committed
136
/// that the occur in the table. This does not apply to the where clause.
137
138
139
140
141
142

static const char* delete_lease4_params[] = {
        static_cast<const char*>("address"),
        NULL };
static const char* delete_expired_lease4_params[] = {
        static_cast<const char*>("state"),
143
        static_cast<const char*>("expire"),
144
145
146
147
148
149
        NULL };
static const char* delete_lease6_params[] = {
        static_cast<const char*>("address"),
        NULL };
static const char* delete_expired_lease6_params[] = {
        static_cast<const char*>("state"),
150
        static_cast<const char*>("expire"),
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
        NULL };
static const char* get_lease4_addr_params[] = {
        static_cast<const char*>("address"),
        NULL };
static const char* get_lease4_clientid_params[] = {
        static_cast<const char*>("client_id"),
        NULL };
static const char* get_lease4_clientid_subid_params[] = {
        static_cast<const char*>("client_id"),
        static_cast<const char*>("subnet_id"),
        NULL };
static const char* get_lease4_hwaddr_params[] = {
        static_cast<const char*>("hwaddr"),
        NULL };
static const char* get_lease4_hwaddr_subid_params[] = {
        static_cast<const char*>("hwaddr"),
        static_cast<const char*>("subnet_id"),
        NULL };
static const char* get_lease4_expired_params[] = {
        static_cast<const char*>("state"),
171
        static_cast<const char*>("expire"),
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
        static_cast<const char*>("limit"),
        NULL };
static const char* get_lease6_addr_params[] = {
        static_cast<const char*>("address"),
        static_cast<const char*>("lease_type"),
        NULL };
static const char* get_lease6_duid_iaid_params[] = {
        static_cast<const char*>("duid"),
        static_cast<const char*>("iaid"),
        static_cast<const char*>("lease_type"),
        NULL };
static const char* get_lease6_duid_iaid_subid_params[] = {
        static_cast<const char*>("duid"),
        static_cast<const char*>("iaid"),
        static_cast<const char*>("subnet_id"),
        static_cast<const char*>("lease_type"),
        NULL };
static const char* get_lease6_expired_params[] = {
        static_cast<const char*>("state"),
191
        static_cast<const char*>("expire"),
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
        static_cast<const char*>("limit"),
        NULL };
static const char* get_version_params[] = {
        NULL };
static const char* insert_lease4_params[] = {
        static_cast<const char*>("address"),
        static_cast<const char*>("hwaddr"),
        static_cast<const char*>("client_id"),
        static_cast<const char*>("valid_lifetime"),
        static_cast<const char*>("expire"),
        static_cast<const char*>("subnet_id"),
        static_cast<const char*>("fqdn_fwd"),
        static_cast<const char*>("fqdn_rev"),
        static_cast<const char*>("hostname"),
        static_cast<const char*>("state"),
        NULL };
static const char* insert_lease6_params[] = {
        static_cast<const char*>("address"),
        static_cast<const char*>("duid"),
        static_cast<const char*>("valid_lifetime"),
        static_cast<const char*>("expire"),
        static_cast<const char*>("subnet_id"),
        static_cast<const char*>("pref_lifetime"),
        static_cast<const char*>("lease_type"),
        static_cast<const char*>("iaid"),
        static_cast<const char*>("prefix_len"),
        static_cast<const char*>("fqdn_fwd"),
        static_cast<const char*>("fqdn_rev"),
        static_cast<const char*>("hostname"),
        static_cast<const char*>("hwaddr"),
        static_cast<const char*>("hwtype"),
        static_cast<const char*>("hwaddr_source"),
        static_cast<const char*>("state"),
        NULL };
static const char* update_lease4_params[] = {
        static_cast<const char*>("hwaddr"),
        static_cast<const char*>("client_id"),
        static_cast<const char*>("valid_lifetime"),
        static_cast<const char*>("expire"),
        static_cast<const char*>("subnet_id"),
        static_cast<const char*>("fqdn_fwd"),
        static_cast<const char*>("fqdn_rev"),
        static_cast<const char*>("hostname"),
        static_cast<const char*>("state"),
        static_cast<const char*>("address"),
        NULL };
static const char* update_lease6_params[] = {
        static_cast<const char*>("duid"),
        static_cast<const char*>("valid_lifetime"),
        static_cast<const char*>("expire"),
        static_cast<const char*>("subnet_id"),
        static_cast<const char*>("pref_lifetime"),
        static_cast<const char*>("lease_type"),
        static_cast<const char*>("iaid"),
        static_cast<const char*>("prefix_len"),
        static_cast<const char*>("fqdn_fwd"),
        static_cast<const char*>("fqdn_rev"),
        static_cast<const char*>("hostname"),
        static_cast<const char*>("hwaddr"),
        static_cast<const char*>("hwtype"),
        static_cast<const char*>("hwaddr_source"),
        static_cast<const char*>("state"),
        static_cast<const char*>("address"),
        NULL };

Tomek Mrugalski's avatar
Tomek Mrugalski committed
257
CqlTaggedStatement CqlLeaseMgr::tagged_statements_[] = {
258
259
260
    // DELETE_LEASE4
    { delete_lease4_params,
      "delete_lease4",
261
262
      "DELETE FROM lease4 WHERE address = ? "
      "IF EXISTS" },
263
264
265
266
267
268
269
270

    // DELETE_LEASE4_STATE_EXPIRED
    { delete_expired_lease4_params,
      "delete_lease4_expired",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
271
272
      "WHERE state = ? AND expire < ? "
      "ALLOW FILTERING" },
273
274
275
276

    // DELETE_LEASE6
    { delete_lease6_params,
      "delete_lease6",
277
278
      "DELETE FROM lease6 WHERE address = ? "
      "IF EXISTS" },
279
280
281
282
283
284
285
286
287

    // DELETE_LEASE6_STATE_EXPIRED
    { delete_expired_lease6_params,
      "delete_lease6_expired",
      "SELECT address, duid, valid_lifetime, "
        "expire, subnet_id, pref_lifetime, "
        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
        "hwaddr, hwtype, hwaddr_source, state "
      "FROM lease6 "
288
289
      "WHERE state = ? AND expire < ? "
      "ALLOW FILTERING" },
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

    // GET_LEASE4_ADDR
    { get_lease4_addr_params,
      "get_lease4_addr",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
      "WHERE address = ?" },

    // GET_LEASE4_CLIENTID
    { get_lease4_clientid_params,
      "get_lease4_clientid",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
      "WHERE client_id = ?" },

    // GET_LEASE4_CLIENTID_SUBID
    { get_lease4_clientid_subid_params,
      "get_lease4_clientid_subid",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
316
317
      "WHERE client_id = ? AND subnet_id = ? "
      "ALLOW FILTERING" },
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

    // GET_LEASE4_HWADDR
    { get_lease4_hwaddr_params,
      "get_lease4_hwaddr",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
      "WHERE hwaddr = ?" },

    // GET_LEASE4_HWADDR_SUBID
    { get_lease4_hwaddr_subid_params,
      "get_lease4_hwaddr_subid",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
335
336
      "WHERE hwaddr = ? AND subnet_id = ? "
      "ALLOW FILTERING" },
337
338
339
340
341
342
343
344

    // GET_LEASE4_EXPIRE
    { get_lease4_expired_params,
      "get_lease4_expired",
      "SELECT address, hwaddr, client_id, "
        "valid_lifetime, expire, subnet_id, "
        "fqdn_fwd, fqdn_rev, hostname, state "
      "FROM lease4 "
345
      "WHERE state = ? AND expire < ? "
346
347
      "LIMIT ? "
      "ALLOW FILTERING" },
348
349
350
351
352
353
354
355
356

    // GET_LEASE6_ADDR
    { get_lease6_addr_params,
      "get_lease6_addr",
      "SELECT address, duid, valid_lifetime, "
        "expire, subnet_id, pref_lifetime, "
        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
        "hwaddr, hwtype, hwaddr_source, state "
      "FROM lease6 "
357
358
      "WHERE address = ? AND lease_type = ? "
      "ALLOW FILTERING" },
359
360
361
362
363
364
365
366
367

    // GET_LEASE6_DUID_IAID
    { get_lease6_duid_iaid_params,
       "get_lease6_duid_iaid",
       "SELECT address, duid, valid_lifetime, "
         "expire, subnet_id, pref_lifetime, "
         "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
         "hwaddr, hwtype, hwaddr_source, state "
       "FROM lease6 "
368
369
       "WHERE duid = ? AND iaid = ? AND lease_type = ? "
       "ALLOW FILTERING" },
370
371
372
373
374
375
376
377
378

    // GET_LEASE6_DUID_IAID_SUBID
    { get_lease6_duid_iaid_subid_params,
      "get_lease6_duid_iaid_subid",
      "SELECT address, duid, valid_lifetime, "
        "expire, subnet_id, pref_lifetime, "
        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
        "hwaddr, hwtype, hwaddr_source, state "
      "FROM lease6 "
379
380
      "WHERE duid = ? AND iaid = ? AND subnet_id = ? AND lease_type = ? "
      "ALLOW FILTERING" },
381

382
    // GET_LEASE6_EXPIRE
383
384
385
386
387
388
389
    { get_lease6_expired_params,
      "get_lease6_expired",
      "SELECT address, duid, valid_lifetime, "
        "expire, subnet_id, pref_lifetime, "
        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
        "hwaddr, hwtype, hwaddr_source, state "
      "FROM lease6 "
390
      "WHERE state = ? AND expire < ? "
391
392
      "LIMIT ? "
      "ALLOW FILTERING" },
393
394
395
396
397
398
399
400
401
402

    // GET_VERSION
    { get_version_params,
      "get_version",
      "SELECT version, minor FROM schema_version" },

    // INSERT_LEASE4
    { insert_lease4_params,
      "insert_lease4",
      "INSERT INTO lease4(address, hwaddr, client_id, "
Tomek Mrugalski's avatar
Tomek Mrugalski committed
403
404
        "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
        "state) "
405
      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
406
      "IF NOT EXISTS" },
407
408
409
410
411
412

    // INSERT_LEASE6
    { insert_lease6_params,
      "insert_lease6",
      "INSERT INTO lease6(address, duid, valid_lifetime, "
        "expire, subnet_id, pref_lifetime, "
Tomek Mrugalski's avatar
Tomek Mrugalski committed
413
414
        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, "
        "hwtype, hwaddr_source, state) "
415
      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
416
      "IF NOT EXISTS" },
417
418
419
420
421
422
423
424

    // UPDATE_LEASE4
    { update_lease4_params,
      "update_lease4",
      "UPDATE lease4 SET hwaddr = ?, "
        "client_id = ?, valid_lifetime = ?, expire = ?, "
        "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, hostname = ?, state = ? "
      "WHERE address = ? "
425
      "IF EXISTS" },
426
427
428
429
430
431
432
433
434
435

    // UPDATE_LEASE6
    { update_lease6_params,
      "update_lease6",
      "UPDATE lease6 SET duid = ?, "
        "valid_lifetime = ?, expire = ?, subnet_id = ?, "
        "pref_lifetime = ?, lease_type = ?, iaid = ?, "
        "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, hostname = ?, "
        "hwaddr = ?, hwtype = ?, hwaddr_source = ?, state = ? "
      "WHERE address = ? "
436
      "IF EXISTS" },
437
438
439
440
441

    // End of list sentinel
    { NULL, NULL, NULL }
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
442
443
444
445
446
447
/// @brief Common CQL and Lease Data Methods
///
/// The CqlLease4Exchange and CqlLease6Exchange classes provide the
/// functionality to set up binding information between variables in the
/// program and data extracted from the database. This class is the common
/// base to both of them, containing some common methods.
448
449
class CqlLeaseExchange : public CqlExchange {
public:
Tomek Mrugalski's avatar
Tomek Mrugalski committed
450
451
452
    CqlLeaseExchange() : hwaddr_length_(0), expire_(0), subnet_id_(0),
                         valid_lifetime_(0), fqdn_fwd_(false), fqdn_rev_(false),
                         hostname_length_(0), state_(0) {
453
454
455
        memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
        memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
    }
456
457
458
459
460
461
462
463
464
465
466
467
protected:
    std::vector<uint8_t> hwaddr_;       ///< Hardware address
    uint8_t         hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
                                        ///< Hardware address buffer
    unsigned long   hwaddr_length_;     ///< Hardware address length
    uint64_t        expire_;            ///< Lease expiry time
    uint32_t        subnet_id_;         ///< Subnet identification
    uint64_t        valid_lifetime_;    ///< Lease time
    uint32_t        fqdn_fwd_;          ///< Has forward DNS update been
                                        ///< performed
    uint32_t        fqdn_rev_;          ///< Has reverse DNS update been
                                        ///< performed
468
    char            hostname_buffer_[HOSTNAME_MAX_LEN + 1];
469
470
471
472
473
                                        ///< Client hostname
    unsigned long   hostname_length_;   ///< Client hostname length
    uint32_t        state_;             ///< Lease state
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
474
475
476
477
478
479
480
class CqlVersionExchange : public virtual CqlExchange {
public:
    /// @brief Constructor
    ///
    /// The initialization of the variables here is only to satisfy cppcheck -
    /// all variables are initialized/set in the methods before they are used.
    CqlVersionExchange() {
481
482
483
484
485
486
487
488
489
        const size_t MAX_COLUMNS = 2U;
        // Set the column names
        size_t offset = 0U;
        BOOST_STATIC_ASSERT(2U == MAX_COLUMNS);
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("version",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("minor",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
490
491
492
    }
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
493
/// @brief Exchange CQL and Lease4 Data
494
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
495
/// On any CQL operation, arrays of CQL BIND structures must be built to
Tomek Mrugalski's avatar
Tomek Mrugalski committed
496
/// describe the parameters in the prepared statements. Where information is
497
/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
Tomek Mrugalski's avatar
Tomek Mrugalski committed
498
/// structure is identical. This class handles the creation of that array.
499
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
500
/// Owing to the CQL API, the process requires some intermediate variables
Tomek Mrugalski's avatar
Tomek Mrugalski committed
501
/// to hold things like data length etc. This object holds those variables.
502
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
503
/// @note There are no unit tests for this class. It is tested indirectly
Tomek Mrugalski's avatar
Tomek Mrugalski committed
504
/// in all CqlLeaseMgr::xxx4() calls where it is used.
505

Tomek Mrugalski's avatar
Tomek Mrugalski committed
506
class CqlLease4Exchange : public CqlLeaseExchange {
507
508
509
510
511
public:
    /// @brief Constructor
    ///
    /// The initialization of the variables here is only to satisfy cppcheck -
    /// all variables are initialized/set in the methods before they are used.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
512
    CqlLease4Exchange() : addr4_(0), client_id_length_(0),
513
                            client_id_null_(false) {
514
        const size_t MAX_COLUMNS = 12U;
515
516
        memset(client_id_buffer_, 0, sizeof(client_id_buffer_));

517
518
        // Set the column names
        size_t offset = 0U;
519
        BOOST_STATIC_ASSERT(12U == MAX_COLUMNS);
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("address",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("client_id",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("valid_lifetime",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("expire",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_TIMESTAMP)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("subnet_id",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_fwd",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_rev",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hostname",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("state",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("limit",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
542
543
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("[applied]",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
544
        BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
545
546
    }

Tomek Mrugalski's avatar
Tomek Mrugalski committed
547
    /// @brief Create CQL_BIND objects for Lease4 Pointer
548
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
549
    /// Fills in the CQL_BIND array for sending data in the Lease4 object to
550
    /// the database.
551
    void createBindForSend(const Lease4Ptr& lease, CqlDataArray& data) {
552
553
554
555
556
557
558
559
560
        if (!lease) {
            isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
        }
        // Store lease object to ensure it remains valid.
        lease_ = lease;
        // Set up the structures for the various components of the lease4
        // structure.

        try {
561
            // address: int
Tomek Mrugalski's avatar
Tomek Mrugalski committed
562
563
            // The address in the Lease structure is an IOAddress object.
            // Convert this to an integer for storage.
564
            addr4_ = static_cast<uint32_t>(lease_->addr_);
565
            data.add(&addr4_);
566

567
            // hwaddr: blob
568
569
570
571
572
573
574
575
576
577
578
579
            HWAddrPtr hwaddr = lease_->hwaddr_;
            if (hwaddr) {
                if (hwaddr->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
                    isc_throw(DbOperationError, "Hardware address length " <<
                              lease_->hwaddr_->hwaddr_.size() <<
                              " exceeds maximum allowed of " <<
                              HWAddr::MAX_HWADDR_LEN);
                }
                hwaddr_ = hwaddr->hwaddr_;
            } else {
                hwaddr_.clear();
            }
580
            hwaddr_length_ = hwaddr_.size();
581
            data.add(&hwaddr_);
582

583
            // client_id: blob
584
585
586
587
588
589
            if (lease_->client_id_) {
                client_id_ = lease_->client_id_->getClientId();
            } else {
                client_id_.clear();
            }
            client_id_length_ = client_id_.size();
590
            data.add(&client_id_);
591

592
            // valid lifetime: bigint
593
            valid_lifetime_ = lease_->valid_lft_;
594
            data.add(&valid_lifetime_);
595
596

            // expire: bigint
597
598
            // The lease structure holds the client last transmission time (cltt_)
            // For convenience for external tools, this is converted to lease
Tomek Mrugalski's avatar
Tomek Mrugalski committed
599
            // expiry time (expire). The relationship is given by:
600
601
            //
            // expire = cltt_ + valid_lft_
Tomek Mrugalski's avatar
Tomek Mrugalski committed
602
603
            CqlLeaseExchange::convertToDatabaseTime(lease_->cltt_,
                lease_->valid_lft_, expire_);
604
            data.add(&expire_);
605

606
            // subnet_id: int
607
608
            // Can use lease_->subnet_id_ directly as it is of type uint32_t.
            subnet_id_ = lease_->subnet_id_;
609
            data.add(&subnet_id_);
610
611
612

            // fqdn_fwd: boolean
            fqdn_fwd_ = lease_->fqdn_fwd_;
613
            data.add(&fqdn_fwd_);
614
615
616

            // fqdn_rev: boolean
            fqdn_rev_ = lease_->fqdn_rev_;
617
            data.add(&fqdn_rev_);
618

619
620
            // hostname: varchar
            hostname_length_ = lease_->hostname_.length();
621
            if (hostname_length_ >= sizeof(hostname_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
622
623
                isc_throw(BadValue, "hostname value is too large: " <<
                    lease_->hostname_.c_str());
624
625
            }
            if (hostname_length_) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
626
627
                memcpy(hostname_buffer_, lease_->hostname_.c_str(),
                    hostname_length_);
628
629
            }
            hostname_buffer_[hostname_length_] = '\0';
630
            data.add(hostname_buffer_);
631

632
            // state: int
633
            state_ = lease_->state_;
634
            data.add(&state_);
635
636
637
638
639
640
641
642
643
644

        } catch (const std::exception& ex) {
            isc_throw(DbOperationError,
                      "Could not create bind array from Lease4: "
                      << lease_->addr_.toText() << ", reason: " << ex.what());
        }
    }

    /// @brief Create BIND array to receive data
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
645
    /// Creates a CQL_BIND array to receive Lease4 data from the database.
646
647
    Lease4Ptr createBindForReceive(const CassRow* row) {
        try {
648
649
650
651
652
            unsigned char* hwaddr_buffer = NULL;
            const char* client_id_buffer = NULL;
            const char* hostname_buffer = NULL;
            CqlDataArray data;
            CqlDataArray size;
653

654
            // address: int
655
656
            data.add(reinterpret_cast<void*>(&addr4_));
            size.add(NULL);
657

658
            // hwaddr: blob
659
660
            data.add(reinterpret_cast<void*>(&hwaddr_buffer));
            size.add(reinterpret_cast<void*>(&hwaddr_length_));
661

662
            // client_id: blob
663
664
            data.add(reinterpret_cast<void*>(&client_id_buffer));
            size.add(reinterpret_cast<void*>(&client_id_length_));
665

666
            // valid_lifetime: bigint
667
668
            data.add(reinterpret_cast<void*>(&valid_lifetime_));
            size.add(NULL);
669

670
            // expire: bigint
671
672
            data.add(reinterpret_cast<void*>(&expire_));
            size.add(NULL);
673

674
            // subnet_id: int
675
676
            data.add(reinterpret_cast<void*>(&subnet_id_));
            size.add(NULL);
677
678

            // fqdn_fwd: boolean
679
680
            data.add(reinterpret_cast<void*>(&fqdn_fwd_));
            size.add(NULL);
681
682

            // fqdn_rev: boolean
683
684
685
            data.add(reinterpret_cast<void*>(&fqdn_rev_));
            size.add(NULL);

686
            // hostname: varchar
687
688
689
            data.add(reinterpret_cast<void*>(&hostname_buffer));
            size.add(reinterpret_cast<void*>(&hostname_length_));

690
            // state: int
691
692
693
            data.add(reinterpret_cast<void*>(&state_));
            size.add(NULL);

694
695
            for (size_t i = 0; i < data.size(); i++) {
                CqlLeaseMgr::getData(row, i, data, size, i, *this);
696
697
            }

698
            // hwaddr: blob
699
700
            hwaddr_.assign(hwaddr_buffer, hwaddr_buffer + hwaddr_length_);

701
            // client_id: blob
Tomek Mrugalski's avatar
Tomek Mrugalski committed
702
703
            client_id_.assign(client_id_buffer, client_id_buffer +
                client_id_length_);
704
            if (client_id_length_ >= sizeof(client_id_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
705
706
                isc_throw(BadValue, "client id value is too large: " <<
                    client_id_buffer);
707
708
709
710
711
            }
            if (client_id_length_) {
                memcpy(client_id_buffer_, client_id_buffer, client_id_length_);
            }
            client_id_buffer_[client_id_length_] = '\0';
712

713
            // hostname: varchar
714
            if (hostname_length_ >= sizeof(hostname_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
715
716
                isc_throw(BadValue, "hostname value is too large: " <<
                    hostname_buffer);
717
718
            }
            if (hostname_length_) {
719
                memcpy(hostname_buffer_, hostname_buffer, hostname_length_);
720
721
722
723
            }
            hostname_buffer_[hostname_length_] = '\0';

            time_t cltt = 0;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
724
725
            CqlLeaseExchange::convertFromDatabaseTime(expire_, valid_lifetime_,
                cltt);
726
727
728
729
730
731
732

            // Recreate the hardware address.
            HWAddrPtr hwaddr(new HWAddr(hwaddr_, HTYPE_ETHER));

            std::string hostname(hostname_buffer_,
                                 hostname_buffer_ + hostname_length_);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
733
734
735
736
            Lease4Ptr result(new Lease4(addr4_, hwaddr, client_id_buffer_,
                                        client_id_length_, valid_lifetime_, 0,
                                        0, cltt, subnet_id_, fqdn_fwd_,
                                        fqdn_rev_, hostname));
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758

            result->state_ = state_;

            return (result);
        } catch (const std::exception& ex) {
            isc_throw(DbOperationError,
                      "Could not convert data to Lease4, reason: "
                       << ex.what());
        }
        return (Lease4Ptr());
    }

private:
    Lease4Ptr       lease_;             ///< Pointer to lease object
    uint32_t        addr4_;             ///< IPv4 address
    std::vector<uint8_t> client_id_;    ///< Client identification
    uint8_t         client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
                                        ///< Client ID buffer
    unsigned long   client_id_length_;  ///< Client ID address length
    bool            client_id_null_;    ///< Is Client ID null?
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
759
/// @brief Exchange CQL and Lease6 Data
760
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
761
/// On any CQL operation, arrays of CQL BIND structures must be built to
Tomek Mrugalski's avatar
Tomek Mrugalski committed
762
/// describe the parameters in the prepared statements. Where information is
763
/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
Tomek Mrugalski's avatar
Tomek Mrugalski committed
764
/// structure is identical. This class handles the creation of that array.
765
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
766
/// Owing to the CQL API, the process requires some intermediate variables
Tomek Mrugalski's avatar
Tomek Mrugalski committed
767
/// to hold things like data length etc. This object holds those variables.
768
///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
769
/// @note There are no unit tests for this class. It is tested indirectly
Tomek Mrugalski's avatar
Tomek Mrugalski committed
770
/// in all CqlLeaseMgr::xxx6() calls where it is used.
771

Tomek Mrugalski's avatar
Tomek Mrugalski committed
772
class CqlLease6Exchange : public CqlLeaseExchange {
773
774
775
776
777
public:
    /// @brief Constructor
    ///
    /// The initialization of the variables here is nonly to satisfy cppcheck -
    /// all variables are initialized/set in the methods before they are used.
778
779
780
    CqlLease6Exchange() : addr6_length_(0), duid_length_(0), iaid_(0),
                          lease_type_(0), prefixlen_(0), pref_lifetime_(0),
                          hwaddr_null_(false), hwtype_(0), hwaddr_source_(0) {
781
        const size_t MAX_COLUMNS = 18U;
782
783
784
        memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
        memset(duid_buffer_, 0, sizeof(duid_buffer_));

785
786
        // Set the column names
        size_t offset = 0U;
787
        BOOST_STATIC_ASSERT(18U == MAX_COLUMNS);
788
789
790
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("address",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("duid",
791
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("valid_lifetime",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("expire",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_TIMESTAMP)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("subnet_id",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("pref_lifetime",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("lease_type",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("iaid",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("prefix_len",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_fwd",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_rev",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hostname",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwtype",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr_source",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("state",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("limit",
            offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
822
823
        parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("[applied]",
            offset++, EXCHANGE_DATA_TYPE_IO_OUT, EXCHANGE_DATA_TYPE_BOOL)));
824
        BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
825
826
    }

Tomek Mrugalski's avatar
Tomek Mrugalski committed
827
    /// @brief Create CQL_BIND objects for Lease6 Pointer
828
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
829
    /// Fills in the CQL_BIND array for sending data in the Lease6 object to
830
    /// the database.
831
    void createBindForSend(const Lease6Ptr& lease, CqlDataArray& data) {
832
833
834
835
836
        if (!lease) {
            isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
        }
        // Store lease object to ensure it remains valid.
        lease_ = lease;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
837

838
839
840
        // Set up the structures for the various components of the lease4
        // structure.
        try {
841
            // address: varchar
842
843
844
            std::string text_buffer = lease_->addr_.toText();
            addr6_length_ = text_buffer.size();
            if (addr6_length_ >= sizeof(addr6_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
845
846
                isc_throw(BadValue, "address value is too large: " <<
                    text_buffer);
847
848
849
850
851
            }
            if (addr6_length_) {
                memcpy(addr6_buffer_, text_buffer.c_str(), addr6_length_);
            }
            addr6_buffer_[addr6_length_] = '\0';
852
            data.add(addr6_buffer_);
853

854
            // duid: blob
855
            if (!lease_->duid_) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
856
                isc_throw(DbOperationError, "lease6 for address " <<
857
                    addr6_buffer_ << " is missing mandatory client-id");
858
859
860
            }
            duid_ = lease_->duid_->getDuid();
            duid_length_ = duid_.size();
861
            data.add(&duid_);
862

863
            // valid lifetime: bigint
864
            valid_lifetime_ = lease_->valid_lft_;
865
            data.add(&valid_lifetime_);
866

867
            // expire: bigint
868
869
            // The lease structure holds the client last transmission time (cltt_)
            // For convenience for external tools, this is converted to lease
Tomek Mrugalski's avatar
Tomek Mrugalski committed
870
            // expiry time (expire). The relationship is given by:
871
872
            //
            // expire = cltt_ + valid_lft_
Tomek Mrugalski's avatar
Tomek Mrugalski committed
873
874
            CqlLeaseExchange::convertToDatabaseTime(lease_->cltt_,
                lease_->valid_lft_, expire_);
875
            data.add(&expire_);
876

877
            // subnet_id: int
878
879
            // Can use lease_->subnet_id_ directly as it is of type uint32_t.
            subnet_id_ = lease_->subnet_id_;
880
            data.add(&subnet_id_);
881

882
            // pref_lifetime: bigint
883
884
            // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
            pref_lifetime_ = lease_->preferred_lft_;
885
            data.add(&pref_lifetime_);
886

887
            // lease_type: int
888
889
            // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
            lease_type_ = lease_->type_;
890
            data.add(&lease_type_);
891

892
            // iaid: int
893
894
            // Can use lease_->iaid_ directly as it is of type uint32_t.
            iaid_ = lease_->iaid_;
895
            data.add(&iaid_);
896

897
            // prefix_len: int
898
899
            // Can use lease_->prefixlen_ directly as it is uint32_t.
            prefixlen_ = lease_->prefixlen_;
900
            data.add(&prefixlen_);
901
902
903

            // fqdn_fwd: boolean
            fqdn_fwd_ = lease_->fqdn_fwd_;
904
            data.add(&fqdn_fwd_);
905
906
907

            // fqdn_rev: boolean
            fqdn_rev_ = lease_->fqdn_rev_;
908
            data.add(&fqdn_rev_);
909

910
911
            // hostname: varchar
            hostname_length_ = lease_->hostname_.length();
912
            if (hostname_length_ >= sizeof(hostname_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
913
914
                isc_throw(BadValue, "hostname value is too large: " <<
                    lease_->hostname_.c_str());
915
916
            }
            if (hostname_length_) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
917
918
                memcpy(hostname_buffer_, lease_->hostname_.c_str(),
                    hostname_length_);
919
920
            }
            hostname_buffer_[hostname_length_] = '\0';
921
            data.add(hostname_buffer_);
922

923
            // hwaddr: blob
924
925
            HWAddrPtr hwaddr = lease_->hwaddr_;
            if (hwaddr) {
926
927
928
929
930
931
                if (hwaddr->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
                    isc_throw(DbOperationError, "Hardware address length : "
                              << lease_->hwaddr_->hwaddr_.size()
                              << " exceeds maximum allowed of: "
                              << HWAddr::MAX_HWADDR_LEN);
                }
932
933
934
935
936
                hwaddr_ = hwaddr->hwaddr_;
            } else {
                hwaddr_.clear();
            }
            hwaddr_length_ = hwaddr_.size();
937
            data.add(&hwaddr_);
938

939
            // hwtype: int
940
941
942
943
944
            if (hwaddr) {
                hwtype_ = lease->hwaddr_->htype_;
            } else {
                hwtype_ = 0;
            }
945
            data.add(&hwtype_);
946

947
            // hwaddr_source: int
948
949
950
951
952
            if (hwaddr) {
                hwaddr_source_ = lease->hwaddr_->source_;
            } else {
                hwaddr_source_ = 0;
            }
953
            data.add(&hwaddr_source_);
954

955
            // state: int
956
            state_ = lease_->state_;
957
            data.add(&state_);
958
959
960
961
962
963
964
965
966
967

        } catch (const std::exception& ex) {
            isc_throw(DbOperationError,
                      "Could not create bind array from Lease6: "
                      << lease_->addr_.toText() << ", reason: " << ex.what());
        }
    }

    /// @brief Create BIND array to receive data
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
968
    /// Creates a CQL_BIND array to receive Lease6 data from the database.
969
970
    Lease6Ptr createBindForReceive(const CassRow* row) {
        try {
971
972
973
974
975
976
            unsigned char* duid_buffer = NULL;
            unsigned char* hwaddr_buffer = NULL;
            const char* address_buffer = NULL;
            const char* hostname_buffer = NULL;
            CqlDataArray data;
            CqlDataArray size;
977

978
            // address: varchar
979
980
            data.add(reinterpret_cast<void*>(&address_buffer));
            size.add(reinterpret_cast<void*>(&addr6_length_));
981

982
            // duid: blob
983
984
            data.add(reinterpret_cast<void*>(&duid_buffer));
            size.add(reinterpret_cast<void*>(&duid_length_));
985

986
            // valid_lifetime_: bigint
987
988
            data.add(reinterpret_cast<void*>(&valid_lifetime_));
            size.add(NULL);
989

990
            // expire: bigint
991
992
            data.add(reinterpret_cast<void*>(&expire_));
            size.add(NULL);
993

994
            // subnet_id: int
995
996
            data.add(reinterpret_cast<void*>(&subnet_id_));
            size.add(NULL);
997

998
            // pref_lifetime: bigint
999
1000
            data.add(reinterpret_cast<void*>(&pref_lifetime_));
            size.add(NULL);
1001

1002
            // lease_type: int
1003
1004
            data.add(reinterpret_cast<void*>(&lease_type_));
            size.add(NULL);
1005

1006
            // iaid: int
1007
1008
            data.add(reinterpret_cast<void*>(&iaid_));
            size.add(NULL);
1009

1010
            // prefix_len: int
1011
1012
            data.add(reinterpret_cast<void*>(&prefixlen_));
            size.add(NULL);
1013
1014

            // fqdn_fwd: boolean
1015
1016
            data.add(reinterpret_cast<void*>(&fqdn_fwd_));
            size.add(NULL);
1017
1018

            // fqdn_rev: boolean
1019
1020
            data.add(reinterpret_cast<void*>(&fqdn_rev_));
            size.add(NULL);
1021

1022
            // hostname: varchar
1023
1024
            data.add(reinterpret_cast<void*>(&hostname_buffer));
            size.add(reinterpret_cast<void*>(&hostname_length_));
1025

1026
            // hwaddr: blob
1027
1028
            data.add(reinterpret_cast<void*>(&hwaddr_buffer));
            size.add(reinterpret_cast<void*>(&hwaddr_length_));
1029

1030
            // hwtype: int
1031
1032
            data.add(reinterpret_cast<void*>(&hwtype_));
            size.add(NULL);
1033

1034
            // hwaddr_source: int
1035
1036
            data.add(reinterpret_cast<void*>(&hwaddr_source_));
            size.add(NULL);
1037

1038
            // state: int
1039
1040
1041
            data.add(reinterpret_cast<void*>(&state_));
            size.add(NULL);

1042
1043
            for (size_t i = 0; i < data.size(); i++) {
                CqlLeaseMgr::getData(row, i, data, size, i, *this);
1044
1045
            }

1046
            // address: varchar
1047
            if (addr6_length_ >= sizeof(addr6_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1048
1049
                isc_throw(BadValue, "address value is too large: " <<
                    address_buffer);
1050
1051
1052
1053
1054
1055
            }
            if (addr6_length_) {
                memcpy(addr6_buffer_, address_buffer, addr6_length_);
            }
            addr6_buffer_[addr6_length_] = '\0';

1056
            // duid: blob
1057
1058
            duid_.assign(duid_buffer, duid_buffer + duid_length_);

1059
            // hostname: varchar
1060
            if (hostname_length_ >= sizeof(hostname_buffer_)) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1061
1062
                isc_throw(BadValue, "hostname value is too large: " <<
                    hostname_buffer);
1063
1064
1065
1066
1067
1068
            }
            if (hostname_length_) {
                memcpy(hostname_buffer_, hostname_buffer, hostname_length_);
            }
            hostname_buffer_[hostname_length_] = '\0';

1069
            // hwaddr: blob
1070
            hwaddr_.assign(hwaddr_buffer, hwaddr_buffer + hwaddr_length_);
1071
1072
1073
1074
1075
1076

            if (lease_type_ != Lease::TYPE_NA && lease_type_ != Lease::TYPE_TA &&
                    lease_type_ != Lease::TYPE_PD) {
                isc_throw(BadValue, "invalid lease type returned (" <<
                    static_cast<int>(lease_type_) << ") for lease with "
                    << "address " << addr6_buffer_ << ". Only 0, 1, or 2 are "
1077
                    << "allowed");
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
            }

            isc::asiolink::IOAddress addr(addr6_buffer_);
            DuidPtr duid(new DUID(duid_));
            HWAddrPtr hwaddr;
            if (hwaddr_.size()) {
                hwaddr.reset(new HWAddr(hwaddr_, hwtype_));
                hwaddr->source_ = hwaddr_source_;
            }

            std::string hostname(hostname_buffer_,
                                 hostname_buffer_ + hostname_length_);

            // Create the lease and set the cltt (after converting from the
            // expire time retrieved from the database).
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1093
1094
1095
1096
1097
            Lease6Ptr result(new Lease6(static_cast<Lease::Type>(lease_type_),
                                        addr, duid, iaid_, pref_lifetime_,
                                        valid_lifetime_, 0, 0, subnet_id_,
                                        fqdn_fwd_, fqdn_rev_, hostname, hwaddr,
                                        prefixlen_));
1098
1099

            time_t cltt = 0;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1100
1101
            CqlLeaseExchange::convertFromDatabaseTime(expire_, valid_lifetime_,
                cltt);
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
            result->cltt_ = cltt;

            result->state_ = state_;

            return (result);
        } catch (const std::exception& ex) {
            isc_throw(DbOperationError,
                      "Could not convert data to Lease4, reason: "
                       << ex.what());
        }
        return (Lease6Ptr());
    }

private:
    Lease6Ptr       lease_;             ///< Pointer to lease object
    char            addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];  ///< Character
                                        ///< array form of V6 address
    unsigned long   addr6_length_;      ///< Length of the address
    std::vector<uint8_t> duid_;         ///< Client identification
    uint8_t         duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
    unsigned long   duid_length_;       ///< Length of the DUID
    uint32_t        iaid_;              ///< Identity association ID
    uint32_t        lease_type_;        ///< Lease type
    uint32_t        prefixlen_;         ///< Prefix length
    uint32_t        pref_lifetime_;     ///< Preferred lifetime
    bool            hwaddr_null_;       ///< Used when HWAddr is null
    uint32_t        hwtype_;            ///< Hardware type
    uint32_t        hwaddr_source_;     ///< Source of the hardware address
};

Tomek Mrugalski's avatar
Tomek Mrugalski committed
1132
1133
CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
    : LeaseMgr(), dbconn_(parameters), exchange4_(new CqlLease4Exchange()),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1134
    exchange6_(new CqlLease6Exchange()), versionExchange_(new CqlVersionExchange()) {
1135
    dbconn_.openDatabase();
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1136
    dbconn_.prepareStatements(CqlLeaseMgr::tagged_statements_);
1137
1138
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
1139
CqlLeaseMgr::~CqlLeaseMgr() {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1140
1141
    // There is no need to close the database in this destructor: it is
    // closed in the destructor of the dbconn_ member variable.
1142
1143
1144
}

std::string
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1145
CqlLeaseMgr::getDBVersion() {
1146
    std::stringstream tmp;
1147
1148
    tmp << "CQL backend " << CQL_SCHEMA_VERSION_MAJOR;
    tmp << "." << CQL_SCHEMA_VERSION_MINOR;
1149
1150
1151
1152
    tmp << ", library " << "cassandra_static";
    return (tmp.str());
}

1153
ExchangeDataType
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1154
CqlLeaseMgr::getDataType(const StatementIndex stindex, int pindex,
1155
        const SqlExchange& exchange) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1156
1157
    if (CqlLeaseMgr::tagged_statements_[stindex].params_ &&
            CqlLeaseMgr::tagged_statements_[stindex].params_[pindex]) {
1158
1159
1160
1161
1162
        const ExchangeColumnInfoContainerName& idx = exchange.parameters_.get<1>();
        const ExchangeColumnInfoContainerNameRange& range =
            idx.equal_range(CqlLeaseMgr::tagged_statements_[stindex].params_[pindex]);
        if (std::distance(range.first, range.second) > 0)