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_));
571 static_cast<Host::IdentifierType>(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"));
std::vector< std::string > text_statements_
Raw text of statements.
boost::shared_ptr< MySqlHostWithOptionsExchange > host_exchange_
Pointer to the object representing an exchange which can be used to retrieve hosts and DHCPv4 options...
MySqlHolder mysql_
MySQL connection handle.
void addResv(const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
virtual std::string getDescription() const
Returns description of the backend.
Simple class representing an optional value.
ConstHostPtr getHost(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, StatementIndex stindex, boost::shared_ptr< MySqlHostExchange > exchange) const
Retrieves a host by subnet and client's unique identifier.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Fetch and Release MySQL Results.
boost::shared_ptr< MySqlOptionExchange > host_option_exchange_
Pointer to an object representing an exchange which can be used to insert DHCPv4 or DHCPv6 option int...
void checkError(const int status, const StatementIndex index, const char *what) const
Check Error and Throw Exception.
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
virtual void rollback()
Rollback Transactions.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
uint8_t getPrefixLen() const
Returns prefix length.
virtual bool del4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet4-id, identifier type, identifier)
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
void commit()
Commits transaction.
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
#define DHCP6_OPTION_SPACE
virtual bool del6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet6-id, identifier type, identifier)
boost::shared_ptr< Option > OptionPtr
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
Universe
defines option universe DHCPv4 or DHCPv6
void checkReadOnly() const
Throws exception if database is read only.
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
IPv6 reservation for a host.
std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
boost::shared_ptr< MySqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Exception thrown on failure to open database.
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
Multiple lease records found where one expected.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
std::string formatted_value_
Option value in textual (CSV) format.
const my_bool MLM_FALSE
MySQL false value.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
~MySqlHostDataSourceImpl()
Destructor.
MySqlConnection conn_
MySQL connection.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool persistent_
Persistence flag.
A generic exception that is thrown when an unexpected error condition occurs.
virtual void commit()
Commit Transactions.
virtual ~MySqlHostDataSource()
Virtual destructor.
boost::shared_ptr< MySqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation.
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
void addStatement(MySqlHostDataSourceImpl::StatementIndex stindex, std::vector< MYSQL_BIND > &bind)
Executes statements which inserts a row into one of the tables.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
virtual std::string getName() const
Returns backend name.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
Represents a device with IPv4 and/or IPv6 reservations.
bool configuredReadOnly() const
Convenience method checking if database should be opened with read only access.
Type
Type of the reservation.
#define DHCP4_OPTION_SPACE
virtual ConstHostPtr get6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv6 subnet.
bool isV4() const
Convenience function to check for an IPv4 address.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
OptionPtr option_
Option instance.
const int MLM_MYSQL_FETCH_SUCCESS
MySQL fetch success code.
StatementIndex
Statement Tags.
bool is_readonly_
Indicates if the database is opened in read only mode.
Defines the logger used by the top-level component of kea-dhcp-ddns.
Type getType() const
Returns reservation type.
std::string toText() const
Convert the address to a string.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
Implementation of the MySqlHostDataSource.
void getHostCollection(StatementIndex stindex, MYSQL_BIND *bind, boost::shared_ptr< MySqlHostExchange > exchange, ConstHostCollection &result, bool single) const
Creates collection of Host objects with associated information such as IPv6 reservations and/or DHCP ...
void addOptions(const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
std::vector< MYSQL_STMT * > statements_
Prepared statements.
const int MLM_MYSQL_FETCH_FAILURE
MySQL fetch failure code.
A wrapper interface for the ASIO library.
boost::shared_ptr< MySqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
RAII object representing MySQL transaction.
bool isSpecified() const
Checks if the value is specified or unspecified.
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Attempt to modify data in read-only database.
void rollback()
Rollback Transactions.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Return all hosts connected to any subnet for which reservations have been made using a specified iden...
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
void commit()
Commit Transactions.
IdentifierType
Type of the host identifier.
bool delStatement(StatementIndex stindex, MYSQL_BIND *bind)
Executes statements that delete records.
The IOAddress class represents an IP addresses (version agnostic)
void checkError(const int status, const StatementIndex &index, const char *what) const
Check Error and Throw Exception.
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
void prepareStatements(const TaggedStatement *start_statement, const TaggedStatement *end_statement)
Prepare statements.
void openDatabase()
Open Database.
uint64_t HostID
HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
virtual ConstHostPtr get4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv4 subnet.
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Returns a collection of hosts using the specified IPv4 address.
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete a host by (subnet-id, address)
Exception thrown on failure to execute a database function.
const my_bool MLM_TRUE
MySQL true value.
MySqlHostDataSource(const db::DatabaseConnection::ParameterMap ¶meters)
Constructor.
boost::array< TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS > TaggedStatementArray
Array of tagged statements.
Database duplicate entry error.
virtual void add(const HostPtr &host)
Adds a new host to the collection.
void addOption(const MySqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const OptionalValue< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Common MySQL Connector Pool.