Skip to content

Commit c89926d

Browse files
committed
DNS+SRV ipmplementation using new ds::DNS_SRV_source class
1 parent 07ae00c commit c89926d

File tree

3 files changed

+135
-134
lines changed

3 files changed

+135
-134
lines changed

cdk/include/mysql/cdk/data_source.h

Lines changed: 99 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,22 @@ namespace ds {
364364
{}
365365
};
366366

367+
368+
/*
369+
A data source which encapsulates several other data sources (all of which
370+
are assumed to hold the same data).
371+
372+
When adding data sources to a multi source, a priority and a weight can
373+
be specified. When a visitor is visiting the multi source, the data sources
374+
are presented to the visitor in decreasing priority order. If several data
375+
sources have the same priority, they are presented in random order, taking
376+
into account specified weights. If no priorities were specified, then data
377+
sources are presented in the order in which they were added.
378+
379+
If priorities are specified, they must be specified for all data sources
380+
that are added to the multi source.
381+
*/
382+
367383
class Multi_source
368384
{
369385

@@ -398,6 +414,7 @@ namespace ds {
398414

399415
typedef std::multimap<Prio, DS_variant, std::greater<Prio>> DS_list;
400416
DS_list m_ds_list;
417+
uint32_t m_total_weight = 0;
401418

402419
public:
403420

@@ -444,6 +461,8 @@ namespace ds {
444461
*/
445462
m_ds_list.emplace(Prio({m_counter--,weight}), pair);
446463
}
464+
465+
m_total_weight += weight;
447466
}
448467

449468
private:
@@ -480,89 +499,7 @@ namespace ds {
480499
bool stop_processing = false;
481500
std::vector<DS_variant*> same_prio;
482501
std::vector<uint16_t> weights;
483-
484-
485-
struct DNS_SRV_visitor
486-
{
487-
Visitor &visitor;
488-
cdk::ds::Multi_source src;
489-
uint16_t total_weight = 0;
490-
bool has_srv = false;
491-
492-
DNS_SRV_visitor(Visitor &_visitor)
493-
: visitor(_visitor)
494-
{}
495-
496-
bool operator() (const ds::TCPIP &ds, const ds::TCPIP::Options &opts)
497-
{
498-
has_srv = opts.get_dns_srv();
499-
500-
if(has_srv)
501-
{
502-
ds::TCPIP::Options new_opts(opts);
503-
new_opts.set_dns_srv(false);
504-
505-
auto list = cdk::foundation::connection::srv_list(ds.host());
506-
507-
508-
if (list.empty())
509-
{
510-
std::string err = "Unable to locate any hosts for ";
511-
err+= ds.host();
512-
throw_error(err.c_str());
513-
}
514-
515-
auto &tls= const_cast<ds::TCPIP::Options::TLS_options&>(opts.get_tls());
516-
517-
for (auto &el : list)
518-
{
519-
TCPIP::Options::TLS_options tls (new_opts.get_tls());
520-
tls.set_host_name(el.name);
521-
new_opts.set_tls(tls);
522-
//Prio is negative because for URI prio, less is better, but for
523-
//SRV record, more is better
524-
src.add(ds::TCPIP(el.name, el.port),new_opts,-el.prio,el.weight);
525-
526-
total_weight+=el.weight;
527-
}
528-
529-
src.visit(visitor);
530-
531-
}
532-
533-
return has_srv;
534-
}
535-
536-
537-
538-
#ifndef WIN32
539-
bool operator() (const ds::Unix_socket&ds, const ds::Unix_socket::Options &options)
540-
{
541-
return false;
542-
}
543-
#endif
544-
bool operator() (const ds::TCPIP_old &ds, const ds::TCPIP_old::Options &options)
545-
{
546-
return false;
547-
}
548-
549-
};
550-
551-
DNS_SRV_visitor dns_srv_visitor {visitor};
552-
553-
//SRV only possible with 1 host
554-
if(m_ds_list.size() == 1)
555-
{
556-
// Give values to the visitor
557-
Variant_visitor<DNS_SRV_visitor> variant_visitor;
558-
variant_visitor.vis = &dns_srv_visitor;
559-
560-
m_ds_list.begin()->second.visit(variant_visitor);
561-
562-
if(variant_visitor.stop_processing)
563-
return;
564-
}
565-
502+
std::random_device generator;
566503

567504
for (auto it = m_ds_list.begin(); !stop_processing;)
568505
{
@@ -584,17 +521,14 @@ namespace ds {
584521
{
585522
//If weight is not specified, we need to set all weight values
586523
//with same, os that discrete_distribution works as expected
587-
weights.push_back(
588-
dns_srv_visitor.total_weight == 0 ? 1 : it1->first.weight);
524+
weights.push_back(it1->first.weight);
589525
same_prio.push_back(&(it1->second));
590526
}
591527
}
592528

593-
std::random_device generator;
594529
std::discrete_distribution<int> distribution(
595-
weights.begin(), weights.end());
596-
597-
530+
weights.begin(), weights.end()
531+
);
598532

599533
auto el = same_prio.begin();
600534

@@ -642,6 +576,7 @@ namespace ds {
642576
{
643577
m_ds_list.clear();
644578
m_is_prioritized = false;
579+
m_total_weight = 0;
645580
}
646581

647582
size_t size()
@@ -652,6 +587,81 @@ namespace ds {
652587
struct Access;
653588
friend Access;
654589
};
590+
591+
592+
/*
593+
A data source which takes data from one of the hosts obtained from
594+
a DNS+SRV query.
595+
596+
Method get() issues a DNS+SRV query and returns its result as
597+
a Multi_source which contains a list of TCPIP data sources for the
598+
hosts returned from the query. Also the weights and priorites
599+
obtained from the DNS+SRV query are used.
600+
601+
Example usage:
602+
603+
DNS_SRV_source dns_srv(name, opts);
604+
Multi_source src = dns_srv.get();
605+
606+
Note: Each call to get() issues new DNS query and can result in
607+
different list of sources.
608+
*/
609+
610+
class DNS_SRV_source
611+
{
612+
public:
613+
614+
using Options = TCPIP::Options;
615+
616+
/*
617+
Create DNS+SRV data source for the given DNS name and session options.
618+
619+
The DNS name is used to query DNS server when getting list of hosts.
620+
Given session options are used for each host obtained from the DNS+SRV
621+
query.
622+
*/
623+
624+
DNS_SRV_source(const std::string& host, const Options &opts)
625+
: m_host(host), m_opts(opts)
626+
{}
627+
628+
/*
629+
Query DNS and return results as a Multi_source.
630+
*/
631+
632+
Multi_source get()
633+
{
634+
Multi_source src;
635+
636+
auto list = cdk::foundation::connection::srv_list(m_host);
637+
638+
if (list.empty())
639+
{
640+
std::string err = "Unable to locate any hosts for " + m_host;
641+
throw_error(err.c_str());
642+
}
643+
644+
for (auto& el : list)
645+
{
646+
Options opt1(m_opts);
647+
Options::TLS_options tls(m_opts.get_tls());
648+
tls.set_host_name(el.name);
649+
opt1.set_tls(tls);
650+
//Prio is negative because for URI prio, less is better, but for
651+
//SRV record, more is better
652+
src.add(ds::TCPIP(el.name, el.port), opt1, -el.prio, el.weight);
653+
}
654+
655+
return src;
656+
}
657+
658+
protected:
659+
660+
std::string m_host;
661+
Options m_opts;
662+
663+
};
664+
655665
}
656666

657667

common/session.cc

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,35 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
368368

369369
src.clear();
370370

371+
if (has_option(Session_option_impl::DNS_SRV))
372+
{
373+
/*
374+
Use DNS+SRV data source.
375+
376+
Note: option consistency checks are done by Setter
377+
*/
378+
379+
assert(1 == m_data.m_host_cnt);
380+
381+
cdk::ds::DNS_SRV_source dns_srv_src(
382+
get(Session_option_impl::HOST).get_string(), opts
383+
);
384+
385+
/*
386+
Note: this assignment performs DNS lookup to populate the server list
387+
in src. If no hosts are returned, method get() throws error.
388+
*/
389+
390+
src = dns_srv_src.get();
391+
392+
assert(src.size() > 0);
393+
return;
394+
}
395+
396+
/*
397+
If DNS+SRV is not used, get list of hosts from the settings.
398+
*/
399+
371400
// if priorities were not set explicitly, assign decreasing starting from 100
372401
int prio = m_data.m_user_priorities ? -1 : 100;
373402

@@ -412,10 +441,6 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
412441
if (Session_option_impl::PORT == it->first)
413442
{
414443
assert(0 == m_data.m_host_cnt);
415-
if (opts.get_dns_srv())
416-
{
417-
throw_error("Specifying a port number with DNS SRV lookup is not allowed.");
418-
}
419444
}
420445
else
421446
{
@@ -428,10 +453,6 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
428453

429454
if (it != end() && Session_option_impl::PORT == it->first)
430455
{
431-
if (opts.get_dns_srv())
432-
{
433-
throw_error("Specifying a port number with DNS SRV lookup is not allowed.");
434-
}
435456
port = (unsigned short)it->second.get_uint();
436457
++it;
437458
}
@@ -483,20 +504,6 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
483504
};
484505
#endif
485506

486-
auto add_connect_attr = [this](iterator &it) {
487-
switch (it->second.get_type())
488-
{
489-
case Value::Type::BOOL:
490-
if (!it->second.get_bool())
491-
this->m_data.m_connection_attr.clear();
492-
else
493-
this->m_data.init_connection_attr();
494-
break;
495-
default:
496-
break;
497-
}
498-
};
499-
500507
/*
501508
Go through options and look for ones which define connections.
502509
*/
@@ -509,12 +516,6 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
509516
add_host(it, prio--); break;
510517

511518
case Session_option_impl::SOCKET:
512-
if(opts.get_dns_srv())
513-
{
514-
throw_error(
515-
"Using Unix domain sockets with DNS SRV lookup is not allowed."
516-
);
517-
}
518519
add_socket(it, prio--); break;
519520

520521
/*
@@ -530,17 +531,12 @@ void Settings_impl::get_data_source(cdk::ds::Multi_source &src)
530531
++it;
531532
}
532533
}
534+
533535
if (0 == src.size())
534536
{
535537
throw_error("No sources to connect");
536538
}
537539

538-
if(opts.get_dns_srv() && src.size() > 1)
539-
{
540-
throw_error(
541-
"Specifying multiple hostnames with DNS SRV look up is not allowed."
542-
);
543-
}
544540
}
545541

546542

0 commit comments

Comments
 (0)