20 #include <boost/algorithm/string/split.hpp>
21 #include <boost/algorithm/string/classification.hpp>
22 #include <boost/array.hpp>
23 #include <boost/pointer_cast.hpp>
24 #include <boost/static_assert.hpp>
27 #include <mysqld_error.h>
46 const size_t ADDRESS6_TEXT_MAX_LEN = 39;
50 const size_t CLIENT_CLASSES_MAX_LEN = 255;
56 const size_t HOSTNAME_MAX_LEN = 255;
59 const size_t OPTION_VALUE_MAX_LEN = 4096;
62 const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192;
65 const size_t OPTION_SPACE_MAX_LEN = 128;
68 const size_t USER_CONTEXT_MAX_LEN = 8192;
71 const size_t SERVER_HOSTNAME_MAX_LEN = 64;
74 const size_t BOOT_FILE_NAME_MAX_LEN = 128;
77 const size_t KEY_LEN = 16;
83 const uint8_t MAX_IDENTIFIER_TYPE =
static_cast<uint8_t
>(Host::LAST_IDENTIFIER_TYPE);
113 class MySqlHostExchange {
117 static const size_t HOST_COLUMNS = 14;
127 MySqlHostExchange(
const size_t additional_columns_num = 0)
128 : columns_num_(HOST_COLUMNS + additional_columns_num),
129 bind_(columns_num_), columns_(columns_num_),
130 error_(columns_num_,
MLM_FALSE), host_id_(0),
131 dhcp_identifier_length_(0), dhcp_identifier_type_(0),
132 dhcp4_subnet_id_(SUBNET_ID_UNUSED),
133 dhcp6_subnet_id_(SUBNET_ID_UNUSED), ipv4_address_(0),
134 hostname_length_(0), dhcp4_client_classes_length_(0),
135 dhcp6_client_classes_length_(0),
136 user_context_length_(0),
137 dhcp4_next_server_(0),
138 dhcp4_server_hostname_length_(0),
139 dhcp4_boot_file_name_length_(0),
152 memset(dhcp_identifier_buffer_, 0,
sizeof(dhcp_identifier_buffer_));
153 memset(hostname_, 0,
sizeof(hostname_));
154 memset(dhcp4_client_classes_, 0,
sizeof(dhcp4_client_classes_));
155 memset(dhcp6_client_classes_, 0,
sizeof(dhcp6_client_classes_));
156 memset(user_context_, 0,
sizeof(user_context_));
157 memset(dhcp4_server_hostname_, 0,
sizeof(dhcp4_server_hostname_));
158 memset(dhcp4_boot_file_name_, 0,
sizeof(dhcp4_boot_file_name_));
163 columns_[0] =
"host_id";
164 columns_[1] =
"dhcp_identifier";
165 columns_[2] =
"dhcp_identifier_type";
166 columns_[3] =
"dhcp4_subnet_id";
167 columns_[4] =
"dhcp6_subnet_id";
168 columns_[5] =
"ipv4_address";
169 columns_[6] =
"hostname";
170 columns_[7] =
"dhcp4_client_classes";
171 columns_[8] =
"dhcp6_client_classes";
172 columns_[9] =
"user_context";
173 columns_[10] =
"dhcp4_next_server";
174 columns_[11] =
"dhcp4_server_hostname";
175 columns_[12] =
"dhcp4_boot_file_name";
176 columns_[13] =
"auth_key";
178 BOOST_STATIC_ASSERT(13 < HOST_COLUMNS);
182 virtual ~MySqlHostExchange() {
199 size_t findAvailColumn()
const {
200 std::vector<std::string>::const_iterator empty_column =
201 std::find(columns_.begin(), columns_.end(), std::string());
202 return (std::distance(columns_.begin(), empty_column));
208 uint64_t getHostId()
const {
222 static void setErrorIndicators(std::vector<MYSQL_BIND>& bind,
223 std::vector<my_bool>& error) {
224 for (
size_t i = 0; i < error.size(); ++i) {
226 bind[i].error =
reinterpret_cast<char*
>(&error[i]);
243 static std::string getColumnsInError(std::vector<my_bool>& error,
244 const std::vector<std::string>& names) {
245 std::string result =
"";
248 for (
size_t i = 0; i < names.size(); ++i) {
250 if (!result.empty()) {
257 if (result.empty()) {
274 std::vector<MYSQL_BIND> createBindForSend(
const HostPtr& host) {
282 memset(&bind_[0], 0,
sizeof(MYSQL_BIND) * bind_.size());
291 bind_[0].buffer_type = MYSQL_TYPE_LONG;
292 bind_[0].buffer =
reinterpret_cast<char*
>(&host_id_);
296 dhcp_identifier_length_ = host->getIdentifier().size();
297 memcpy(
static_cast<void*
>(dhcp_identifier_buffer_),
298 &(host->getIdentifier())[0],
299 host->getIdentifier().size());
301 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
302 bind_[1].buffer = dhcp_identifier_buffer_;
303 bind_[1].buffer_length = dhcp_identifier_length_;
304 bind_[1].length = &dhcp_identifier_length_;
307 dhcp_identifier_type_ =
static_cast<uint8_t
>(host->getIdentifierType());
308 bind_[2].buffer_type = MYSQL_TYPE_TINY;
309 bind_[2].buffer =
reinterpret_cast<char*
>(&dhcp_identifier_type_);
315 dhcp4_subnet_id_ = host->getIPv4SubnetID();
316 dhcp4_subnet_id_null_ = host->getIPv4SubnetID() == SUBNET_ID_UNUSED ?
MLM_TRUE :
MLM_FALSE;
317 bind_[3].buffer_type = MYSQL_TYPE_LONG;
318 bind_[3].buffer =
reinterpret_cast<char*
>(&dhcp4_subnet_id_);
320 bind_[3].is_null = &dhcp4_subnet_id_null_;
325 dhcp6_subnet_id_ = host->getIPv6SubnetID();
326 dhcp6_subnet_id_null_ = host->getIPv6SubnetID() == SUBNET_ID_UNUSED ?
MLM_TRUE :
MLM_FALSE;
327 bind_[4].buffer_type = MYSQL_TYPE_LONG;
328 bind_[4].buffer =
reinterpret_cast<char*
>(&dhcp6_subnet_id_);
330 bind_[4].is_null = &dhcp6_subnet_id_null_;
335 ipv4_address_ = host->getIPv4Reservation().toUint32();
337 bind_[5].buffer_type = MYSQL_TYPE_LONG;
338 bind_[5].buffer =
reinterpret_cast<char*
>(&ipv4_address_);
340 bind_[5].is_null = &ipv4_address_null_;
343 strncpy(hostname_, host->getHostname().c_str(), HOSTNAME_MAX_LEN - 1);
344 hostname_length_ = host->getHostname().length();
345 bind_[6].buffer_type = MYSQL_TYPE_STRING;
346 bind_[6].buffer =
reinterpret_cast<char*
>(hostname_);
347 bind_[6].buffer_length = hostname_length_;
350 bind_[7].buffer_type = MYSQL_TYPE_STRING;
352 string classes4_txt = host->getClientClasses4().toText(
",");
353 strncpy(dhcp4_client_classes_, classes4_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
354 bind_[7].buffer = dhcp4_client_classes_;
355 bind_[7].buffer_length = classes4_txt.length();
358 bind_[8].buffer_type = MYSQL_TYPE_STRING;
360 string classes6_txt = host->getClientClasses6().toText(
",");
361 strncpy(dhcp6_client_classes_, classes6_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
362 bind_[8].buffer = dhcp6_client_classes_;
363 bind_[8].buffer_length = classes6_txt.length();
368 bind_[9].buffer_type = MYSQL_TYPE_STRING;
369 string ctx_txt = ctx->str();
370 strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
371 bind_[9].buffer = user_context_;
372 bind_[9].buffer_length = ctx_txt.length();
374 bind_[9].buffer_type = MYSQL_TYPE_NULL;
380 dhcp4_next_server_ = host->getNextServer().toUint32();
381 bind_[10].buffer_type = MYSQL_TYPE_LONG;
382 bind_[10].buffer =
reinterpret_cast<char*
>(&dhcp4_next_server_);
388 bind_[11].buffer_type = MYSQL_TYPE_STRING;
389 std::string server_hostname = host->getServerHostname();
390 strncpy(dhcp4_server_hostname_, server_hostname.c_str(),
391 SERVER_HOSTNAME_MAX_LEN - 1);
392 bind_[11].buffer = dhcp4_server_hostname_;
393 bind_[11].buffer_length = server_hostname.length();
396 bind_[12].buffer_type = MYSQL_TYPE_STRING;
397 std::string boot_file_name = host->getBootFileName();
398 strncpy(dhcp4_boot_file_name_, boot_file_name.c_str(),
399 BOOT_FILE_NAME_MAX_LEN - 1);
400 bind_[12].buffer = dhcp4_boot_file_name_;
401 bind_[12].buffer_length = boot_file_name.length();
404 bind_[13].buffer_type = MYSQL_TYPE_STRING;
405 std::string auth_key = host->getKey().ToText();
406 std::strncpy(auth_key_, auth_key.c_str(), KEY_LEN);
408 bind_[13].buffer = auth_key_;
409 bind_[13].buffer_length = auth_key.length();
411 }
catch (
const std::exception& ex) {
413 "Could not create bind array from Host: "
414 << host->getHostname() <<
", reason: " << ex.
what());
419 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[columns_num_]));
429 virtual std::vector<MYSQL_BIND> createBindForReceive() {
436 memset(&bind_[0], 0,
sizeof(MYSQL_BIND) * bind_.size());
439 bind_[0].buffer_type = MYSQL_TYPE_LONG;
440 bind_[0].buffer =
reinterpret_cast<char*
>(&host_id_);
444 dhcp_identifier_length_ =
sizeof(dhcp_identifier_buffer_);
445 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
446 bind_[1].buffer =
reinterpret_cast<char*
>(dhcp_identifier_buffer_);
447 bind_[1].buffer_length = dhcp_identifier_length_;
448 bind_[1].length = &dhcp_identifier_length_;
451 bind_[2].buffer_type = MYSQL_TYPE_TINY;
452 bind_[2].buffer =
reinterpret_cast<char*
>(&dhcp_identifier_type_);
457 bind_[3].buffer_type = MYSQL_TYPE_LONG;
458 bind_[3].buffer =
reinterpret_cast<char*
>(&dhcp4_subnet_id_);
460 bind_[3].is_null = &dhcp4_subnet_id_null_;
464 bind_[4].buffer_type = MYSQL_TYPE_LONG;
465 bind_[4].buffer =
reinterpret_cast<char*
>(&dhcp6_subnet_id_);
467 bind_[4].is_null = &dhcp6_subnet_id_null_;
471 bind_[5].buffer_type = MYSQL_TYPE_LONG;
472 bind_[5].buffer =
reinterpret_cast<char*
>(&ipv4_address_);
474 bind_[5].is_null = &ipv4_address_null_;
478 hostname_length_ =
sizeof(hostname_);
479 bind_[6].buffer_type = MYSQL_TYPE_STRING;
480 bind_[6].buffer =
reinterpret_cast<char*
>(hostname_);
481 bind_[6].buffer_length = hostname_length_;
482 bind_[6].length = &hostname_length_;
483 bind_[6].is_null = &hostname_null_;
487 dhcp4_client_classes_length_ =
sizeof(dhcp4_client_classes_);
488 bind_[7].buffer_type = MYSQL_TYPE_STRING;
489 bind_[7].buffer =
reinterpret_cast<char*
>(dhcp4_client_classes_);
490 bind_[7].buffer_length = dhcp4_client_classes_length_;
491 bind_[7].length = &dhcp4_client_classes_length_;
492 bind_[7].is_null = &dhcp4_client_classes_null_;
496 dhcp6_client_classes_length_ =
sizeof(dhcp6_client_classes_);
497 bind_[8].buffer_type = MYSQL_TYPE_STRING;
498 bind_[8].buffer =
reinterpret_cast<char*
>(dhcp6_client_classes_);
499 bind_[8].buffer_length = dhcp6_client_classes_length_;
500 bind_[8].length = &dhcp6_client_classes_length_;
501 bind_[8].is_null = &dhcp6_client_classes_null_;
505 user_context_length_ =
sizeof(user_context_);
506 bind_[9].buffer_type = MYSQL_TYPE_STRING;
507 bind_[9].buffer =
reinterpret_cast<char*
>(user_context_);
508 bind_[9].buffer_length = user_context_length_;
509 bind_[9].length = &user_context_length_;
510 bind_[9].is_null = &user_context_null_;
514 bind_[10].buffer_type = MYSQL_TYPE_LONG;
515 bind_[10].buffer =
reinterpret_cast<char*
>(&dhcp4_next_server_);
517 bind_[10].is_null = &dhcp4_next_server_null_;
521 dhcp4_server_hostname_length_ =
sizeof(dhcp4_server_hostname_);
522 bind_[11].buffer_type = MYSQL_TYPE_STRING;
523 bind_[11].buffer =
reinterpret_cast<char*
>(dhcp4_server_hostname_);
524 bind_[11].buffer_length = dhcp4_server_hostname_length_;
525 bind_[11].length = &dhcp4_server_hostname_length_;
526 bind_[11].is_null = &dhcp4_server_hostname_null_;
530 dhcp4_boot_file_name_length_ =
sizeof(dhcp4_boot_file_name_);
531 bind_[12].buffer_type = MYSQL_TYPE_STRING;
532 bind_[12].buffer =
reinterpret_cast<char*
>(dhcp4_boot_file_name_);
533 bind_[12].buffer_length = dhcp4_boot_file_name_length_;
534 bind_[12].length = &dhcp4_boot_file_name_length_;
535 bind_[12].is_null = &dhcp4_boot_file_name_null_;
539 auth_key_length_ =
sizeof(auth_key_);
540 bind_[13].buffer_type = MYSQL_TYPE_STRING;
541 bind_[13].buffer =
reinterpret_cast<char*
>(auth_key_);
542 bind_[13].buffer_length = auth_key_length_;
543 bind_[13].length = &auth_key_length_;
544 bind_[13].is_null = &auth_key_null_;
547 setErrorIndicators(bind_, error_);
564 if (dhcp_identifier_type_ > MAX_IDENTIFIER_TYPE) {
566 <<
static_cast<int>(dhcp_identifier_type_));
575 SubnetID ipv4_subnet_id(SUBNET_ID_UNUSED);
576 if (dhcp4_subnet_id_null_ ==
MLM_FALSE) {
577 ipv4_subnet_id =
static_cast<SubnetID>(dhcp4_subnet_id_);
582 SubnetID ipv6_subnet_id(SUBNET_ID_UNUSED);
583 if (dhcp6_subnet_id_null_ ==
MLM_FALSE) {
584 ipv6_subnet_id =
static_cast<SubnetID>(dhcp6_subnet_id_);
591 ipv4_reservation = asiolink::IOAddress(ipv4_address_);
596 std::string hostname;
598 hostname = std::string(hostname_, hostname_length_);
602 std::string dhcp4_client_classes;
603 if (dhcp4_client_classes_null_ ==
MLM_FALSE) {
604 dhcp4_client_classes = std::string(dhcp4_client_classes_,
605 dhcp4_client_classes_length_);
609 std::string dhcp6_client_classes;
610 if (dhcp6_client_classes_null_ ==
MLM_FALSE) {
611 dhcp6_client_classes = std::string(dhcp6_client_classes_,
612 dhcp6_client_classes_length_);
616 std::string user_context;
618 user_context_[user_context_length_] =
'\0';
619 user_context.assign(user_context_);
624 if (dhcp4_next_server_null_ ==
MLM_FALSE) {
625 next_server = asiolink::IOAddress(dhcp4_next_server_);
629 std::string dhcp4_server_hostname;
630 if (dhcp4_server_hostname_null_ ==
MLM_FALSE) {
631 dhcp4_server_hostname = std::string(dhcp4_server_hostname_,
632 dhcp4_server_hostname_length_);
636 std::string dhcp4_boot_file_name;
637 if (dhcp4_boot_file_name_null_ ==
MLM_FALSE) {
638 dhcp4_boot_file_name = std::string(dhcp4_boot_file_name_,
639 dhcp4_boot_file_name_length_);
643 std::string auth_key;
645 auth_key = std::string(auth_key_, auth_key_length_);
649 HostPtr h(
new Host(dhcp_identifier_buffer_, dhcp_identifier_length_,
650 type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation,
651 hostname, dhcp4_client_classes, dhcp6_client_classes,
652 next_server, dhcp4_server_hostname,
653 dhcp4_boot_file_name,
AuthKey(auth_key)));
654 h->setHostId(host_id_);
657 if (!user_context.empty()) {
660 if (!ctx || (ctx->getType() != Element::map)) {
662 <<
"' is not a JSON map");
667 <<
"' is invalid JSON: " << ex.
what());
692 if (hosts.empty() || (hosts.back()->getHostId() != getHostId())) {
695 host = retrieveHost();
696 hosts.push_back(host);
710 std::string getErrorColumns() {
711 return (getColumnsInError(error_, columns_));
720 std::vector<MYSQL_BIND> bind_;
723 std::vector<std::string> columns_;
726 std::vector<my_bool> error_;
739 uint8_t dhcp_identifier_buffer_[DUID::MAX_DUID_LEN];
742 unsigned long dhcp_identifier_length_;
746 uint8_t dhcp_identifier_type_;
749 uint32_t dhcp4_subnet_id_;
752 uint32_t dhcp6_subnet_id_;
755 uint32_t ipv4_address_;
758 char hostname_[HOSTNAME_MAX_LEN];
761 unsigned long hostname_length_;
764 char dhcp4_client_classes_[CLIENT_CLASSES_MAX_LEN];
768 unsigned long dhcp4_client_classes_length_;
771 char dhcp6_client_classes_[CLIENT_CLASSES_MAX_LEN];
775 unsigned long dhcp6_client_classes_length_;
778 char user_context_[USER_CONTEXT_MAX_LEN];
781 unsigned long user_context_length_;
784 uint32_t dhcp4_next_server_;
787 char dhcp4_server_hostname_[SERVER_HOSTNAME_MAX_LEN];
790 unsigned long dhcp4_server_hostname_length_;
793 char dhcp4_boot_file_name_[BOOT_FILE_NAME_MAX_LEN];
796 unsigned long dhcp4_boot_file_name_length_;
799 char auth_key_[KEY_LEN];
802 unsigned long auth_key_length_;
807 my_bool dhcp4_subnet_id_null_;
811 my_bool dhcp6_subnet_id_null_;
814 my_bool ipv4_address_null_;
817 my_bool hostname_null_;
821 my_bool dhcp4_client_classes_null_;
825 my_bool dhcp6_client_classes_null_;
828 my_bool user_context_null_;
831 my_bool dhcp4_next_server_null_;
834 my_bool dhcp4_server_hostname_null_;
837 my_bool dhcp4_boot_file_name_null_;
840 my_bool auth_key_null_;
854 class MySqlHostWithOptionsExchange :
public MySqlHostExchange {
858 static const size_t OPTION_COLUMNS = 7;
874 class OptionProcessor {
884 const size_t start_column)
885 : universe_(universe), start_column_(start_column), option_id_(0),
886 code_(0), value_length_(0), formatted_value_length_(0),
887 space_length_(0), persistent_(false), user_context_length_(0),
891 option_id_index_(start_column), code_index_(start_column_ + 1),
892 value_index_(start_column_ + 2),
893 formatted_value_index_(start_column_ + 3),
894 space_index_(start_column_ + 4),
895 persistent_index_(start_column_ + 5),
896 user_context_index_(start_column_ + 6),
897 most_recent_option_id_(0) {
899 memset(value_, 0,
sizeof(value_));
900 memset(formatted_value_, 0,
sizeof(formatted_value_));
901 memset(space_, 0,
sizeof(space_));
902 memset(user_context_, 0,
sizeof(user_context_));
906 uint64_t getOptionId()
const {
931 if ((option_id_null_ ==
MLM_TRUE) ||
932 (most_recent_option_id_ >= option_id_)) {
938 most_recent_option_id_ = option_id_;
945 space_[space_length_] =
'\0';
946 space.assign(space_);
951 space = (universe_ == Option::V4 ?
"dhcp4" :
"dhcp6");
955 std::string formatted_value;
956 if (formatted_value_null_ ==
MLM_FALSE) {
957 formatted_value_[formatted_value_length_] =
'\0';
958 formatted_value.assign(formatted_value_);
962 std::string user_context;
964 user_context_[user_context_length_] =
'\0';
965 user_context.assign(user_context_);
981 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
983 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
code_);
990 def = LibDHCP::getRuntimeOptionDef(space,
code_);
998 option.reset(
new Option(universe_,
code_, buf.begin(),
1005 if (formatted_value.empty()) {
1007 option = def->optionFactory(universe_,
code_, buf.begin(),
1012 std::vector<std::string> split_vec;
1013 boost::split(split_vec, formatted_value, boost::is_any_of(
","));
1014 option = def->optionFactory(universe_,
code_, split_vec);
1021 if (!user_context.empty()) {
1024 if (!ctx || (ctx->getType() != Element::map)) {
1026 <<
"' is no a JSON map");
1028 desc.setContext(ctx);
1031 <<
"' is invalid JSON: " << ex.
what());
1035 cfg->add(desc, space);
1042 void setColumnNames(std::vector<std::string>& columns) {
1043 columns[option_id_index_] =
"option_id";
1044 columns[code_index_] =
"code";
1045 columns[value_index_] =
"value";
1046 columns[formatted_value_index_] =
"formatted_value";
1047 columns[space_index_] =
"space";
1048 columns[persistent_index_] =
"persistent";
1049 columns[user_context_index_] =
"user_context";
1057 void setBindFields(std::vector<MYSQL_BIND>& bind) {
1061 most_recent_option_id_ = 0;
1064 bind[option_id_index_].buffer_type = MYSQL_TYPE_LONG;
1065 bind[option_id_index_].buffer =
reinterpret_cast<char*
>(&option_id_);
1066 bind[option_id_index_].is_unsigned =
MLM_TRUE;
1069 bind[code_index_].buffer_type = MYSQL_TYPE_SHORT;
1070 bind[code_index_].buffer =
reinterpret_cast<char*
>(&
code_);
1071 bind[code_index_].is_unsigned =
MLM_TRUE;
1072 bind[code_index_].is_null = &code_null_;
1075 value_length_ =
sizeof(value_);
1076 bind[value_index_].buffer_type = MYSQL_TYPE_BLOB;
1077 bind[value_index_].buffer =
reinterpret_cast<char*
>(value_);
1078 bind[value_index_].buffer_length = value_length_;
1079 bind[value_index_].length = &value_length_;
1080 bind[value_index_].is_null = &value_null_;
1083 formatted_value_length_ =
sizeof(formatted_value_);
1084 bind[formatted_value_index_].buffer_type = MYSQL_TYPE_STRING;
1085 bind[formatted_value_index_].buffer =
reinterpret_cast<char*
>(formatted_value_);
1086 bind[formatted_value_index_].buffer_length = formatted_value_length_;
1087 bind[formatted_value_index_].length = &formatted_value_length_;
1088 bind[formatted_value_index_].is_null = &formatted_value_null_;
1091 space_length_ =
sizeof(space_);
1092 bind[space_index_].buffer_type = MYSQL_TYPE_STRING;
1093 bind[space_index_].buffer =
reinterpret_cast<char*
>(space_);
1094 bind[space_index_].buffer_length = space_length_;
1095 bind[space_index_].length = &space_length_;
1096 bind[space_index_].is_null = &space_null_;
1099 bind[persistent_index_].buffer_type = MYSQL_TYPE_TINY;
1100 bind[persistent_index_].buffer =
reinterpret_cast<char*
>(&persistent_);
1101 bind[persistent_index_].is_unsigned =
MLM_TRUE;
1104 user_context_length_ =
sizeof(user_context_);
1105 bind[user_context_index_].buffer_type = MYSQL_TYPE_STRING;
1106 bind[user_context_index_].buffer =
reinterpret_cast<char*
>(user_context_);
1107 bind[user_context_index_].buffer_length = user_context_length_;
1108 bind[user_context_index_].length = &user_context_length_;
1109 bind[user_context_index_].is_null = &user_context_null_;
1118 size_t start_column_;
1121 uint32_t option_id_;
1127 uint8_t value_[OPTION_VALUE_MAX_LEN];
1130 unsigned long value_length_;
1133 char formatted_value_[OPTION_FORMATTED_VALUE_MAX_LEN];
1136 unsigned long formatted_value_length_;
1139 char space_[OPTION_SPACE_MAX_LEN];
1142 unsigned long space_length_;
1149 char user_context_[USER_CONTEXT_MAX_LEN];
1152 unsigned long user_context_length_;
1157 my_bool option_id_null_;
1164 my_bool value_null_;
1168 my_bool formatted_value_null_;
1171 my_bool space_null_;
1174 my_bool user_context_null_;
1179 size_t option_id_index_;
1186 size_t value_index_;
1189 size_t formatted_value_index_;
1192 size_t space_index_;
1195 size_t persistent_index_;
1199 size_t user_context_index_;
1202 uint32_t most_recent_option_id_;
1206 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
1216 enum FetchedOptions {
1230 MySqlHostWithOptionsExchange(
const FetchedOptions& fetched_options,
1231 const size_t additional_columns_num = 0)
1232 : MySqlHostExchange(getRequiredColumnsNum(fetched_options)
1233 + additional_columns_num),
1234 opt_proc4_(), opt_proc6_() {
1237 if ((fetched_options == DHCP4_ONLY) ||
1238 (fetched_options == DHCP4_AND_DHCP6)) {
1239 opt_proc4_.reset(
new OptionProcessor(Option::V4,
1240 findAvailColumn()));
1241 opt_proc4_->setColumnNames(columns_);
1245 if ((fetched_options == DHCP6_ONLY) ||
1246 (fetched_options == DHCP4_AND_DHCP6)) {
1247 opt_proc6_.reset(
new OptionProcessor(Option::V6,
1248 findAvailColumn()));
1249 opt_proc6_->setColumnNames(columns_);
1264 if (!hosts.empty()) {
1273 most_recent_host = boost::const_pointer_cast<Host>(hosts.back());
1279 if (!most_recent_host || (most_recent_host->getHostId() < getHostId())) {
1280 HostPtr host = retrieveHost();
1281 hosts.push_back(host);
1282 most_recent_host = host;
1288 opt_proc4_->retrieveOption(cfg);
1294 opt_proc6_->retrieveOption(cfg);
1301 virtual std::vector<MYSQL_BIND> createBindForReceive() {
1303 static_cast<void>(MySqlHostExchange::createBindForReceive());
1307 opt_proc4_->setBindFields(bind_);
1312 opt_proc6_->setBindFields(bind_);
1316 setErrorIndicators(bind_, error_);
1334 static size_t getRequiredColumnsNum(
const FetchedOptions& fetched_options) {
1335 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
1342 OptionProcessorPtr opt_proc4_;
1347 OptionProcessorPtr opt_proc6_;
1362 class MySqlHostIPv6Exchange :
public MySqlHostWithOptionsExchange {
1366 static const size_t RESERVATION_COLUMNS = 5;
1374 MySqlHostIPv6Exchange(
const FetchedOptions& fetched_options)
1375 : MySqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
1377 reserv_type_(0), reserv_type_null_(
MLM_FALSE),
1378 ipv6_address_buffer_len_(0), prefix_len_(0), iaid_(0),
1379 reservation_id_index_(findAvailColumn()),
1380 address_index_(reservation_id_index_ + 1),
1381 prefix_len_index_(reservation_id_index_ + 2),
1382 type_index_(reservation_id_index_ + 3),
1383 iaid_index_(reservation_id_index_ + 4),
1384 most_recent_reservation_id_(0) {
1386 memset(ipv6_address_buffer_, 0,
sizeof(ipv6_address_buffer_));
1389 columns_[reservation_id_index_] =
"reservation_id";
1390 columns_[address_index_] =
"address";
1391 columns_[prefix_len_index_] =
"prefix_len";
1392 columns_[type_index_] =
"type";
1393 columns_[iaid_index_] =
"dhcp6_iaid";
1399 uint32_t getReservationId()
const {
1401 return (reservation_id_);
1416 switch (reserv_type_) {
1418 type = IPv6Resrv::TYPE_NA;
1422 type = IPv6Resrv::TYPE_PD;
1427 "invalid IPv6 reservation type returned: "
1428 <<
static_cast<int>(reserv_type_)
1429 <<
". Only 0 or 2 are allowed.");
1432 ipv6_address_buffer_[ipv6_address_buffer_len_] =
'\0';
1433 std::string address = ipv6_address_buffer_;
1460 MySqlHostWithOptionsExchange::processFetchedData(hosts);
1462 if (getReservationId() == 0) {
1466 if (hosts.empty()) {
1468 " IPv6 reservation");
1470 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1474 if (getReservationId() > most_recent_reservation_id_) {
1475 most_recent_reservation_id_ = getReservationId();
1477 if (most_recent_reservation_id_ > 0) {
1478 host->addReservation(retrieveReservation());
1491 virtual std::vector<MYSQL_BIND> createBindForReceive() {
1494 most_recent_reservation_id_ = 0;
1497 static_cast<void>(MySqlHostWithOptionsExchange::createBindForReceive());
1500 bind_[reservation_id_index_].buffer_type = MYSQL_TYPE_LONG;
1501 bind_[reservation_id_index_].buffer =
reinterpret_cast<char*
>(&reservation_id_);
1502 bind_[reservation_id_index_].is_unsigned =
MLM_TRUE;
1505 ipv6_address_buffer_len_ =
sizeof(ipv6_address_buffer_) - 1;
1506 bind_[address_index_].buffer_type = MYSQL_TYPE_STRING;
1507 bind_[address_index_].buffer = ipv6_address_buffer_;
1508 bind_[address_index_].buffer_length = ipv6_address_buffer_len_;
1509 bind_[address_index_].length = &ipv6_address_buffer_len_;
1512 bind_[prefix_len_index_].buffer_type = MYSQL_TYPE_TINY;
1513 bind_[prefix_len_index_].buffer =
reinterpret_cast<char*
>(&prefix_len_);
1514 bind_[prefix_len_index_].is_unsigned =
MLM_TRUE;
1518 bind_[type_index_].buffer_type = MYSQL_TYPE_TINY;
1519 bind_[type_index_].buffer =
reinterpret_cast<char*
>(&reserv_type_);
1520 bind_[type_index_].is_unsigned =
MLM_TRUE;
1521 bind_[type_index_].is_null = &reserv_type_null_;
1524 bind_[iaid_index_].buffer_type = MYSQL_TYPE_LONG;
1525 bind_[iaid_index_].buffer =
reinterpret_cast<char*
>(&iaid_);
1526 bind_[iaid_index_].is_unsigned =
MLM_TRUE;
1529 setErrorIndicators(bind_, error_);
1537 uint32_t reservation_id_;
1540 uint8_t reserv_type_;
1546 my_bool reserv_type_null_;
1549 char ipv6_address_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];
1552 unsigned long ipv6_address_buffer_len_;
1555 uint8_t prefix_len_;
1562 size_t reservation_id_index_;
1566 size_t address_index_;
1569 size_t prefix_len_index_;
1580 uint32_t most_recent_reservation_id_;
1593 class MySqlIPv6ReservationExchange {
1597 static const size_t RESRV_COLUMNS = 6;
1604 MySqlIPv6ReservationExchange()
1605 : host_id_(0), address_(
"::"), address_len_(0), prefix_len_(0), type_(0),
1609 std::fill(&error_[0], &error_[RESRV_COLUMNS],
MLM_FALSE);
1612 columns_[0] =
"host_id";
1613 columns_[1] =
"address";
1614 columns_[2] =
"prefix_len";
1615 columns_[3] =
"type";
1616 columns_[4] =
"dhcp6_iaid";
1617 BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS);
1632 std::vector<MYSQL_BIND> createBindForSend(
const IPv6Resrv& resv,
1644 memset(bind_, 0,
sizeof(bind_));
1651 address_len_ = address_.length();
1652 bind_[0].buffer_type = MYSQL_TYPE_BLOB;
1653 bind_[0].buffer =
reinterpret_cast<char*
>
1654 (
const_cast<char*
>(address_.c_str()));
1655 bind_[0].buffer_length = address_len_;
1656 bind_[0].length = &address_len_;
1660 bind_[1].buffer_type = MYSQL_TYPE_TINY;
1661 bind_[1].buffer =
reinterpret_cast<char*
>(&prefix_len_);
1666 type_ = resv.
getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1667 bind_[2].buffer_type = MYSQL_TYPE_TINY;
1668 bind_[2].buffer =
reinterpret_cast<char*
>(&type_);
1674 bind_[3].buffer_type = MYSQL_TYPE_LONG;
1675 bind_[3].buffer =
reinterpret_cast<char*
>(&iaid_);
1679 bind_[4].buffer_type = MYSQL_TYPE_LONG;
1680 bind_[4].buffer =
reinterpret_cast<char*
>(&host_id_);
1683 }
catch (
const std::exception& ex) {
1685 "Could not create bind array from IPv6 Reservation: "
1686 << resv_.toText() <<
", reason: " << ex.
what());
1692 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[RESRV_COLUMNS-1]));
1701 std::string address_;
1704 unsigned long address_len_;
1707 uint8_t prefix_len_;
1719 MYSQL_BIND bind_[RESRV_COLUMNS];
1722 std::string columns_[RESRV_COLUMNS];
1726 my_bool error_[RESRV_COLUMNS];
1732 class MySqlOptionExchange {
1736 static const size_t OPTION_COLUMNS = 10;
1741 MySqlOptionExchange()
1743 : type_(0), value_len_(0), formatted_value_len_(0), space_(),
1744 space_len_(0), persistent_(false), user_context_(),
1745 user_context_len_(0), client_class_(), client_class_len_(0),
1746 subnet_id_(SUBNET_ID_UNUSED), host_id_(0), option_() {
1748 BOOST_STATIC_ASSERT(9 < OPTION_COLUMNS);
1754 std::vector<MYSQL_BIND>
1756 const std::string& opt_space,
1764 memset(bind_, 0,
sizeof(bind_));
1770 bind_[0].buffer_type = MYSQL_TYPE_NULL;
1773 type_ = option_->getType();
1774 bind_[1].buffer_type = MYSQL_TYPE_SHORT;
1775 bind_[1].buffer =
reinterpret_cast<char*
>(&type_);
1786 const char* buf_ptr =
static_cast<const char*
>(buf.getData());
1787 value_.assign(buf_ptr + opt_desc.
option_->getHeaderLen(),
1788 buf_ptr + buf.getLength());
1789 value_len_ = value_.size();
1790 bind_[2].buffer_type = MYSQL_TYPE_BLOB;
1791 bind_[2].buffer = &value_[0];
1792 bind_[2].buffer_length = value_len_;
1793 bind_[2].length = &value_len_;
1799 bind_[2].buffer_type = MYSQL_TYPE_NULL;
1805 bind_[3].buffer_type = MYSQL_TYPE_STRING;
1807 bind_[3].buffer_length = formatted_value_len_;
1808 bind_[3].length = &formatted_value_len_;
1811 bind_[3].buffer_type = MYSQL_TYPE_NULL;
1816 space_len_ = space_.size();
1817 bind_[4].buffer_type = MYSQL_TYPE_STRING;
1818 bind_[4].buffer =
const_cast<char*
>(space_.c_str());
1819 bind_[4].buffer_length = space_len_;
1820 bind_[4].length = &space_len_;
1824 bind_[5].buffer_type = MYSQL_TYPE_TINY;
1825 bind_[5].buffer =
reinterpret_cast<char*
>(&persistent_);
1831 user_context_ = ctx->str();
1832 user_context_len_ = user_context_.size();
1833 bind_[6].buffer_type = MYSQL_TYPE_STRING;
1834 bind_[6].buffer =
const_cast<char*
>(user_context_.c_str());
1835 bind_[6].buffer_length = user_context_len_;
1836 bind_[6].length = &user_context_len_;
1838 bind_[6].buffer_type = MYSQL_TYPE_NULL;
1842 client_class_len_ = client_class_.size();
1843 bind_[7].buffer_type = MYSQL_TYPE_STRING;
1844 bind_[7].buffer =
const_cast<char*
>(client_class_.c_str());
1845 bind_[7].buffer_length = client_class_len_;
1846 bind_[7].length = &client_class_len_;
1850 subnet_id_ = subnet_id;
1851 bind_[8].buffer_type = MYSQL_TYPE_LONG;
1852 bind_[8].buffer =
reinterpret_cast<char*
>(subnet_id_);
1856 bind_[8].buffer_type = MYSQL_TYPE_NULL;
1861 bind_[9].buffer_type = MYSQL_TYPE_LONG;
1862 bind_[9].buffer =
reinterpret_cast<char*
>(&host_id_);
1865 }
catch (
const std::exception& ex) {
1867 "Could not create bind array for inserting DHCP "
1868 "option: " << option_->toText() <<
", reason: "
1872 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[OPTION_COLUMNS]));
1881 std::vector<uint8_t> value_;
1884 unsigned long value_len_;
1887 unsigned long formatted_value_len_;
1893 unsigned long space_len_;
1900 std::string user_context_;
1903 unsigned long user_context_len_;
1906 std::string client_class_;
1909 unsigned long client_class_len_;
1912 uint32_t subnet_id_;
1921 MYSQL_BIND bind_[OPTION_COLUMNS];
1986 std::pair<uint32_t, uint32_t> getVersion()
const;
1996 std::vector<MYSQL_BIND>& bind);
2023 const std::string& opt_space,
2034 const uint64_t host_id);
2047 const char* what)
const;
2067 boost::shared_ptr<MySqlHostExchange> exchange,
2088 const uint8_t* identifier_begin,
2089 const size_t identifier_len,
2091 boost::shared_ptr<MySqlHostExchange> exchange)
const;
2100 void checkReadOnly()
const;
2132 typedef boost::array<TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS>
2142 {MySqlHostDataSourceImpl::GET_HOST_DHCPID,
2143 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2144 "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
2145 "h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
2147 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2148 "h.dhcp4_boot_file_name, h.auth_key, "
2149 "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
2150 "o4.persistent, o4.user_context, "
2151 "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
2152 "o6.persistent, o6.user_context, "
2153 "r.reservation_id, r.address, r.prefix_len, r.type, "
2156 "LEFT JOIN dhcp4_options AS o4 "
2157 "ON h.host_id = o4.host_id "
2158 "LEFT JOIN dhcp6_options AS o6 "
2159 "ON h.host_id = o6.host_id "
2160 "LEFT JOIN ipv6_reservations AS r "
2161 "ON h.host_id = r.host_id "
2162 "WHERE dhcp_identifier = ? AND dhcp_identifier_type = ? "
2163 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"},
2168 {MySqlHostDataSourceImpl::GET_HOST_ADDR,
2169 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2170 "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2171 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2172 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2173 "h.dhcp4_boot_file_name, h.auth_key, "
2174 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2175 "o.persistent, o.user_context "
2177 "LEFT JOIN dhcp4_options AS o "
2178 "ON h.host_id = o.host_id "
2179 "WHERE ipv4_address = ? "
2180 "ORDER BY h.host_id, o.option_id"},
2185 {MySqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
2186 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2187 "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2188 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2189 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2190 "h.dhcp4_boot_file_name, h.auth_key, "
2192 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2193 "o.persistent, o.user_context "
2195 "LEFT JOIN dhcp4_options AS o "
2196 "ON h.host_id = o.host_id "
2197 "WHERE h.dhcp4_subnet_id = ? AND h.dhcp_identifier_type = ? "
2198 " AND h.dhcp_identifier = ? "
2199 "ORDER BY h.host_id, o.option_id"},
2204 {MySqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID,
2205 "SELECT h.host_id, h.dhcp_identifier, "
2206 "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2207 "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2208 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2209 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2210 "h.dhcp4_boot_file_name, h.auth_key, "
2211 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2212 "o.persistent, o.user_context, "
2213 "r.reservation_id, r.address, r.prefix_len, r.type, "
2216 "LEFT JOIN dhcp6_options AS o "
2217 "ON h.host_id = o.host_id "
2218 "LEFT JOIN ipv6_reservations AS r "
2219 "ON h.host_id = r.host_id "
2220 "WHERE h.dhcp6_subnet_id = ? AND h.dhcp_identifier_type = ? "
2221 "AND h.dhcp_identifier = ? "
2222 "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2228 {MySqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
2229 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2230 "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2231 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2232 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2233 "h.dhcp4_boot_file_name, h.auth_key, "
2234 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2235 "o.persistent, o.user_context "
2237 "LEFT JOIN dhcp4_options AS o "
2238 "ON h.host_id = o.host_id "
2239 "WHERE h.dhcp4_subnet_id = ? AND h.ipv4_address = ? "
2240 "ORDER BY h.host_id, o.option_id"},
2248 {MySqlHostDataSourceImpl::GET_HOST_PREFIX,
2249 "SELECT h.host_id, h.dhcp_identifier, "
2250 "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2251 "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2252 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2253 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2254 "h.dhcp4_boot_file_name, h.auth_key, "
2255 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2256 "o.persistent, o.user_context,"
2257 "r.reservation_id, r.address, r.prefix_len, r.type, "
2260 "LEFT JOIN dhcp6_options AS o "
2261 "ON h.host_id = o.host_id "
2262 "LEFT JOIN ipv6_reservations AS r "
2263 "ON h.host_id = r.host_id "
2264 "WHERE h.host_id = "
2265 "(SELECT host_id FROM ipv6_reservations "
2266 "WHERE address = ? AND prefix_len = ?) "
2267 "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2275 {MySqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
2276 "SELECT h.host_id, h.dhcp_identifier, "
2277 "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2278 "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2279 "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2281 "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2282 "h.dhcp4_boot_file_name, h.auth_key, "
2283 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2284 "o.persistent, o.user_context, "
2285 "r.reservation_id, r.address, r.prefix_len, r.type, "
2288 "LEFT JOIN dhcp6_options AS o "
2289 "ON h.host_id = o.host_id "
2290 "LEFT JOIN ipv6_reservations AS r "
2291 "ON h.host_id = r.host_id "
2292 "WHERE h.dhcp6_subnet_id = ? AND r.address = ? "
2293 "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2296 {MySqlHostDataSourceImpl::INSERT_HOST,
2297 "INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
2298 "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2299 "dhcp4_client_classes, dhcp6_client_classes, "
2300 "user_context, dhcp4_next_server, "
2301 "dhcp4_server_hostname, dhcp4_boot_file_name, auth_key) "
2302 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
2305 {MySqlHostDataSourceImpl::INSERT_V6_RESRV,
2306 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2307 "dhcp6_iaid, host_id) "
2308 "VALUES (?,?,?,?,?)"},
2312 {MySqlHostDataSourceImpl::INSERT_V4_OPTION,
2313 "INSERT INTO dhcp4_options(option_id, code, value, formatted_value, space, "
2314 "persistent, user_context, dhcp_client_class, dhcp4_subnet_id, host_id, scope_id) "
2315 " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
2319 {MySqlHostDataSourceImpl::INSERT_V6_OPTION,
2320 "INSERT INTO dhcp6_options(option_id, code, value, formatted_value, space, "
2321 "persistent, user_context, dhcp_client_class, dhcp6_subnet_id, host_id, scope_id) "
2322 " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
2324 {MySqlHostDataSourceImpl::DEL_HOST_ADDR4,
2325 "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"},
2327 {MySqlHostDataSourceImpl::DEL_HOST_SUBID4_ID,
2328 "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND dhcp_identifier_type=? "
2329 "AND dhcp_identifier = ?"},
2331 {MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
2332 "DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type=? "
2333 "AND dhcp_identifier = ?"}
2338 MySqlHostDataSourceImpl::
2339 MySqlHostDataSourceImpl(
const MySqlConnection::ParameterMap& parameters)
2340 : host_exchange_(new MySqlHostWithOptionsExchange(MySqlHostWithOptionsExchange::DHCP4_ONLY)),
2341 host_ipv6_exchange_(new MySqlHostIPv6Exchange(MySqlHostWithOptionsExchange::DHCP6_ONLY)),
2342 host_ipv46_exchange_(new MySqlHostIPv6Exchange(MySqlHostWithOptionsExchange::
2344 host_ipv6_reservation_exchange_(new MySqlIPv6ReservationExchange()),
2345 host_option_exchange_(new MySqlOptionExchange()),
2347 is_readonly_(false) {
2355 std::pair<uint32_t, uint32_t> db_version =
getVersion();
2356 if (code_version != db_version) {
2358 << code_version.first <<
"." << code_version.second
2359 <<
" found version: " << db_version.first <<
"."
2360 << db_version.second);
2370 my_bool result = mysql_autocommit(
conn_.
mysql_, 1);
2411 std::pair<uint32_t, uint32_t>
2414 DHCPSRV_MYSQL_HOST_DB_GET_VERSION);
2420 "statement structure, reason: " << mysql_error(
conn_.
mysql_));
2424 const char* version_sql =
"SELECT version, minor FROM schema_version";
2425 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
2428 << version_sql <<
">, reason: " << mysql_errno(
conn_.
mysql_));
2432 if (mysql_stmt_execute(stmt) != 0) {
2434 << version_sql <<
">, reason: " << mysql_errno(
conn_.
mysql_));
2439 memset(bind, 0,
sizeof(bind));
2442 bind[0].buffer_type = MYSQL_TYPE_LONG;
2443 bind[0].is_unsigned = 1;
2444 bind[0].buffer = &major;
2445 bind[0].buffer_length =
sizeof(major);
2448 bind[1].buffer_type = MYSQL_TYPE_LONG;
2449 bind[1].is_unsigned = 1;
2450 bind[1].buffer = &minor;
2451 bind[1].buffer_length =
sizeof(minor);
2453 if (mysql_stmt_bind_result(stmt, bind)) {
2455 << version_sql <<
">, reason: " << mysql_errno(
conn_.
mysql_));
2459 if (mysql_stmt_fetch(stmt)) {
2460 mysql_stmt_close(stmt);
2462 << version_sql <<
">, reason: " << mysql_errno(
conn_.
mysql_));
2466 mysql_stmt_close(stmt);
2468 return (std::make_pair(major, minor));
2474 std::vector<MYSQL_BIND>& bind) {
2478 checkError(status, stindex,
"unable to bind parameters");
2488 checkError(status, stindex,
"unable to execute");
2497 checkError(status, stindex,
"unable to bind parameters");
2503 checkError(status, stindex,
"unable to execute");
2507 my_ulonglong numrows = mysql_stmt_affected_rows(
conn_.
statements_[stindex]);
2508 return (numrows != 0);
2514 std::vector<MYSQL_BIND> bind =
2523 const std::string& opt_space,
2526 std::vector<MYSQL_BIND> bind =
2536 const uint64_t host_id) {
2539 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2540 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2541 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2542 vendor_spaces.end());
2546 for (std::list<std::string>::const_iterator space = option_spaces.begin();
2547 space != option_spaces.end(); ++space) {
2549 if (options && !options->empty()) {
2550 for (OptionContainer::const_iterator opt = options->begin();
2551 opt != options->end(); ++opt) {
2562 const char* what)
const {
2569 boost::shared_ptr<MySqlHostExchange> exchange,
2574 checkError(status, stindex,
"unable to bind WHERE clause parameter");
2578 std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
2580 checkError(status, stindex,
"unable to bind SELECT clause parameters");
2584 checkError(status, stindex,
"unable to execute");
2589 checkError(status, stindex,
"unable to set up for storing all results");
2599 exchange->processFetchedData(result);
2607 if (single && (result.size() > 1)) {
2609 "database where only one was expected for query "
2618 checkError(status, stindex,
"unable to fetch results");
2620 }
else if (status == MYSQL_DATA_TRUNCATED) {
2623 <<
" returned truncated data: columns affected are "
2624 << exchange->getErrorColumns());
2632 const uint8_t* identifier_begin,
2633 const size_t identifier_len,
2635 boost::shared_ptr<MySqlHostExchange> exchange)
const {
2638 MYSQL_BIND inbind[3];
2639 memset(inbind, 0,
sizeof(inbind));
2641 uint32_t subnet_buffer =
static_cast<uint32_t
>(subnet_id);
2642 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2643 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet_buffer);
2647 std::vector<char> identifier_vec(identifier_begin,
2648 identifier_begin + identifier_len);
2649 unsigned long length = identifier_vec.size();
2650 inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2651 inbind[2].buffer = &identifier_vec[0];
2652 inbind[2].buffer_length = length;
2653 inbind[2].length = &length;
2656 char identifier_type_copy =
static_cast<char>(identifier_type);
2657 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2658 inbind[1].buffer =
reinterpret_cast<char*
>(&identifier_type_copy);
2666 if (!collection.empty())
2667 result = *collection.begin();
2676 " operate in read only mode");
2701 std::vector<MYSQL_BIND> bind = impl_->
host_exchange_->createBindForSend(host);
2707 uint64_t host_id = mysql_insert_id(impl_->
conn_.
mysql_);
2713 cfg_option4, host_id);
2720 cfg_option6, host_id);
2725 if (std::distance(v6resv.first, v6resv.second) > 0) {
2728 impl_->
addResv(resv->second, host_id);
2743 MYSQL_BIND inbind[2];
2745 uint32_t subnet = subnet_id;
2746 memset(inbind, 0,
sizeof(inbind));
2747 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2748 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet);
2752 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2753 inbind[1].buffer =
reinterpret_cast<char*
>(&addr4);
2767 return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
2768 host->getIdentifier().size());
2774 const uint8_t* identifier_begin,
const size_t identifier_len) {
2779 MYSQL_BIND inbind[3];
2782 memset(inbind, 0,
sizeof(inbind));
2783 uint32_t subnet =
static_cast<uint32_t
>(subnet_id);
2784 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2785 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet);
2789 char identifier_type_copy =
static_cast<char>(identifier_type);
2790 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2791 inbind[1].buffer =
reinterpret_cast<char*
>(&identifier_type_copy);
2795 std::vector<char> identifier_vec(identifier_begin,
2796 identifier_begin + identifier_len);
2797 unsigned long length = identifier_vec.size();
2798 inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2799 inbind[2].buffer = &identifier_vec[0];
2800 inbind[2].buffer_length = length;
2801 inbind[2].length = &length;
2810 const uint8_t* identifier_begin,
const size_t identifier_len) {
2815 MYSQL_BIND inbind[3];
2818 memset(inbind, 0,
sizeof(inbind));
2819 uint32_t subnet =
static_cast<uint32_t
>(subnet_id);
2820 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2821 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet);
2825 char identifier_type_copy =
static_cast<char>(identifier_type);
2826 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2827 inbind[1].buffer =
reinterpret_cast<char*
>(&identifier_type_copy);
2831 std::vector<char> identifier_vec(identifier_begin,
2832 identifier_begin + identifier_len);
2833 unsigned long length = identifier_vec.size();
2834 inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2835 inbind[2].buffer = &identifier_vec[0];
2836 inbind[2].buffer_length = length;
2837 inbind[2].length = &length;
2845 const uint8_t* identifier_begin,
2846 const size_t identifier_len)
const {
2848 MYSQL_BIND inbind[2];
2849 memset(inbind, 0,
sizeof(inbind));
2852 char identifier_type_copy =
static_cast<char>(identifier_type);
2853 inbind[1].buffer = &identifier_type_copy;
2854 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2858 std::vector<char> identifier_vec(identifier_begin,
2859 identifier_begin + identifier_len);
2860 unsigned long int length = identifier_vec.size();
2861 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2862 inbind[0].buffer = &identifier_vec[0];
2863 inbind[0].buffer_length = length;
2864 inbind[0].length = &length;
2877 MYSQL_BIND inbind[1];
2878 memset(inbind, 0,
sizeof(inbind));
2880 uint32_t addr4 = address.
toUint32();
2881 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2882 inbind[0].buffer =
reinterpret_cast<char*
>(&addr4);
2895 const uint8_t* identifier_begin,
2896 const size_t identifier_len)
const {
2898 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2907 if (!address.
isV4()) {
2909 "address supplied is not an IPv4 address");
2913 MYSQL_BIND inbind[2];
2914 uint32_t subnet = subnet_id;
2915 memset(inbind, 0,
sizeof(inbind));
2916 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2917 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet);
2920 uint32_t addr4 = address.
toUint32();
2921 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2922 inbind[1].buffer =
reinterpret_cast<char*
>(&addr4);
2931 if (!collection.empty())
2932 result = *collection.begin();
2940 const uint8_t* identifier_begin,
2941 const size_t identifier_len)
const {
2943 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2950 const uint8_t prefix_len)
const {
2954 MYSQL_BIND inbind[2];
2955 memset(inbind, 0,
sizeof(inbind));
2957 std::string addr6 = prefix.
toText();
2958 unsigned long addr6_length = addr6.size();
2960 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2961 inbind[0].buffer =
reinterpret_cast<char*
>
2962 (
const_cast<char*
>(addr6.c_str()));
2963 inbind[0].length = &addr6_length;
2964 inbind[0].buffer_length = addr6_length;
2966 uint8_t tmp = prefix_len;
2967 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2968 inbind[1].buffer =
reinterpret_cast<char*
>(&tmp);
2978 if (!collection.empty()) {
2979 result = *collection.begin();
2989 MYSQL_BIND inbind[2];
2990 memset(inbind, 0,
sizeof(inbind));
2992 uint32_t subnet_buffer =
static_cast<uint32_t
>(subnet_id);
2993 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2994 inbind[0].buffer =
reinterpret_cast<char*
>(&subnet_buffer);
2997 std::string addr6 = address.
toText();
2998 unsigned long addr6_length = addr6.size();
3000 inbind[1].buffer_type = MYSQL_TYPE_BLOB;
3001 inbind[1].buffer =
reinterpret_cast<char*
>
3002 (
const_cast<char*
>(addr6.c_str()));
3003 inbind[1].length = &addr6_length;
3004 inbind[1].buffer_length = addr6_length;
3013 if (!collection.empty()) {
3014 result = *collection.begin();
3023 std::string name =
"";
3033 return (std::string(
"Host data source that stores host information"
3034 "in MySQL database"));