@@ -364,6 +364,22 @@ namespace ds {
364
364
{}
365
365
};
366
366
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
+
367
383
class Multi_source
368
384
{
369
385
@@ -398,6 +414,7 @@ namespace ds {
398
414
399
415
typedef std::multimap<Prio, DS_variant, std::greater<Prio>> DS_list;
400
416
DS_list m_ds_list;
417
+ uint32_t m_total_weight = 0 ;
401
418
402
419
public:
403
420
@@ -444,6 +461,8 @@ namespace ds {
444
461
*/
445
462
m_ds_list.emplace (Prio ({m_counter--,weight}), pair);
446
463
}
464
+
465
+ m_total_weight += weight;
447
466
}
448
467
449
468
private:
@@ -480,89 +499,7 @@ namespace ds {
480
499
bool stop_processing = false ;
481
500
std::vector<DS_variant*> same_prio;
482
501
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;
566
503
567
504
for (auto it = m_ds_list.begin (); !stop_processing;)
568
505
{
@@ -584,17 +521,14 @@ namespace ds {
584
521
{
585
522
// If weight is not specified, we need to set all weight values
586
523
// 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 );
589
525
same_prio.push_back (&(it1->second ));
590
526
}
591
527
}
592
528
593
- std::random_device generator;
594
529
std::discrete_distribution<int > distribution (
595
- weights.begin (), weights.end ());
596
-
597
-
530
+ weights.begin (), weights.end ()
531
+ );
598
532
599
533
auto el = same_prio.begin ();
600
534
@@ -642,6 +576,7 @@ namespace ds {
642
576
{
643
577
m_ds_list.clear ();
644
578
m_is_prioritized = false ;
579
+ m_total_weight = 0 ;
645
580
}
646
581
647
582
size_t size ()
@@ -652,6 +587,81 @@ namespace ds {
652
587
struct Access ;
653
588
friend Access;
654
589
};
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
+
655
665
}
656
666
657
667
0 commit comments