38
38
#include < stdio.h>
39
39
#include < map>
40
40
#include < vector>
41
+ #include < algorithm>
41
42
#include < random>
42
43
#ifdef HAVE_STDINT_H
43
44
#include < stdint.h>
@@ -95,6 +96,8 @@ namespace sql
95
96
namespace mysql
96
97
{
97
98
99
+ using Host_data = MySQL_Uri::Host_data;
100
+
98
101
/* {{{ MySQL_Savepoint::MySQL_Savepoint() -I- */
99
102
MySQL_Savepoint::MySQL_Savepoint (const sql::SQLString &savepoint):
100
103
name (savepoint)
@@ -376,20 +379,15 @@ struct Prio
376
379
}
377
380
};
378
381
379
- struct Srv_host_detail
380
- {
381
- std::string name;
382
- uint16_t port;
383
- };
384
382
385
383
#ifdef _WIN32
386
- std::multimap<Prio,Srv_host_detail > srv_list (const std::string &hostname,
384
+ std::multimap<Prio,Host_data > srv_list (const std::string &hostname,
387
385
uint16_t &total_weight)
388
386
{
389
387
DNS_STATUS status; // Return value of DnsQuery_A() function.
390
388
PDNS_RECORD pDnsRecord =nullptr ; // Pointer to DNS_RECORD structure.
391
389
392
- std::multimap<Prio,Srv_host_detail > srv;
390
+ std::multimap<Prio,Host_data > srv;
393
391
394
392
status = DnsQuery (hostname.c_str (), DNS_TYPE_SRV, DNS_QUERY_STANDARD, nullptr , &pDnsRecord, nullptr );
395
393
if (!status)
@@ -401,13 +399,12 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
401
399
{
402
400
srv.insert (std::make_pair (
403
401
Prio ({pRecord->Data .Srv .wPriority ,
404
- pRecord->Data .Srv .wWeight }
405
- ),
406
- Srv_host_detail
407
- {
408
- pRecord->Data .Srv .pNameTarget ,
409
- pRecord->Data .Srv .wPort
410
- }));
402
+ pRecord->Data .Srv .wWeight }),
403
+ Host_data
404
+ (pRecord->Data .Srv .pNameTarget ,
405
+ pRecord->Data .Srv .wPort )
406
+ ));
407
+
411
408
total_weight+=pRecord->Data .Srv .wWeight ;
412
409
}
413
410
pRecord = pRecord->pNext ;
@@ -419,13 +416,14 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
419
416
}
420
417
#else
421
418
422
- std::multimap<Prio,Srv_host_detail> srv_list (const std::string &hostname,
419
+ // QUery and interprete SRV data from DNS server
420
+ std::multimap<Prio,Host_data> srv_list (const std::string &hostname,
423
421
uint16_t &total_weight)
424
422
{
425
423
struct __res_state state {};
426
424
res_ninit (&state);
427
425
428
- std::multimap<Prio,Srv_host_detail > srv;
426
+ std::multimap<Prio,Host_data > srv;
429
427
430
428
unsigned char query_buffer[NS_PACKETSZ];
431
429
@@ -444,20 +442,18 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
444
442
auto process = [&msg, &name_buffer, &total_weight, &srv](const ns_rr &rr) -> void
445
443
{
446
444
const unsigned char * srv_data = ns_rr_rdata (rr);
447
- Srv_host_detail host_data;
448
- uint16_t prio, weight;
445
+ uint16_t port, prio, weight;
449
446
450
447
// Each NS_GET16 call moves srv_data to next value
451
448
NS_GET16 (prio, srv_data);
452
449
NS_GET16 (weight, srv_data);
453
- NS_GET16 (host_data. port, srv_data);
450
+ NS_GET16 (port, srv_data);
454
451
455
452
dn_expand (ns_msg_base (msg), ns_msg_end (msg),
456
453
srv_data, name_buffer, sizeof (name_buffer));
457
454
458
- host_data.name = name_buffer;
459
-
460
- srv.insert (std::make_pair (Prio ({prio, weight}), std::move (host_data)));
455
+ srv.insert (std::make_pair (Prio ({prio, weight}),
456
+ Host_data (name_buffer, port)));
461
457
462
458
total_weight+=weight;
463
459
};
@@ -957,7 +953,7 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
957
953
}
958
954
#endif
959
955
960
- proxy-> use_protocol (uri. Protocol ());
956
+
961
957
962
958
#if MYCPPCONN_STATIC_MYSQL_VERSION_ID < 80000
963
959
try {
@@ -993,11 +989,21 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
993
989
PROCESS_CONN_OPTION (int , intOptions);
994
990
}
995
991
996
- CPP_INFO_FMT (" hostName=%s" , uri.Host ().c_str ());
997
- CPP_INFO_FMT (" user=%s" , userName.c_str ());
998
- CPP_INFO_FMT (" port=%d" , uri.Port ());
999
- CPP_INFO_FMT (" schema=%s" , uri.Schema ().c_str ());
1000
- CPP_INFO_FMT (" socket/pipe=%s" , uri.SocketOrPipe ().c_str ());
992
+ bool opt_multi_host = false ;
993
+ it = properties.find (" OPT_MULTI_HOST" );
994
+ try {
995
+ if (it != properties.end ())
996
+ opt_multi_host = it->second .get <bool >();
997
+ } catch (sql::InvalidArgumentException&) {
998
+ throw sql::InvalidArgumentException (" Wrong type passed for OPT_MULTI_HOST, expected bool" );
999
+ }
1000
+
1001
+ if (!opt_multi_host && uri.size () > 1 )
1002
+ throw sql::InvalidArgumentException (" Missing option OPT_MULTI_HOST = true" );
1003
+
1004
+ if (opt_dns_srv && uri.size () > 1 )
1005
+ throw sql::InvalidArgumentException (" Specifying multiple hostnames with DNS SRV look up is not allowed." );
1006
+
1001
1007
CPP_INFO_FMT (" OPT_DNS_SRV=%d" , opt_dns_srv);
1002
1008
1003
1009
auto connect = [this ,flags,client_exp_pwd](
@@ -1008,6 +1014,11 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1008
1014
uint16_t port,
1009
1015
const std::string &socketOrPipe)
1010
1016
{
1017
+ CPP_INFO_FMT (" hostName=%s" , host.c_str ());
1018
+ CPP_INFO_FMT (" user=%s" , user.c_str ());
1019
+ CPP_INFO_FMT (" port=%d" , port);
1020
+ CPP_INFO_FMT (" schema=%s" , schema.c_str ());
1021
+ CPP_INFO_FMT (" socket/pipe=%s" , socketOrPipe.c_str ());
1011
1022
1012
1023
if (!proxy->connect (host,
1013
1024
user,
@@ -1046,6 +1057,11 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1046
1057
}
1047
1058
};
1048
1059
1060
+
1061
+ std::multimap<Prio,Host_data> host_list;
1062
+
1063
+ uint16_t total_weight = 0 ;
1064
+
1049
1065
if (opt_dns_srv)
1050
1066
{
1051
1067
if (uri.Protocol () != NativeAPI::PROTOCOL_TCP)
@@ -1058,24 +1074,34 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1058
1074
throw sql::InvalidArgumentException (" Specifying a port number with DNS SRV lookup is not allowed." );
1059
1075
}
1060
1076
1077
+ host_list = srv_list (uri.Host (),total_weight);
1061
1078
1062
- uint16_t total_weight = 0 ;
1063
-
1064
- auto list = srv_list (uri.Host (),total_weight);
1065
-
1066
- if (list.empty ())
1079
+ if (host_list.empty ())
1067
1080
{
1068
1081
std::stringstream err;
1069
1082
err << " Unable to locate any hosts for " << uri.Host ();
1070
1083
throw sql::InvalidArgumentException (err.str ());
1071
1084
}
1072
1085
1086
+
1087
+
1088
+ }
1089
+ else
1090
+ {
1091
+ for (auto host : uri)
1092
+ {
1093
+ host_list.insert (std::make_pair (Prio ({0 , 0 }), host));
1094
+ }
1095
+ }
1096
+
1097
+ // Connect loop
1098
+ {
1073
1099
bool connected = false ;
1074
1100
1075
- while (!list .empty () && !connected)
1101
+ while (!host_list .empty () && !connected)
1076
1102
{
1077
- auto same_range = list .equal_range (list .begin ()->first );
1078
- std::vector<Srv_host_detail *> same_prio;
1103
+ auto same_range = host_list .equal_range (host_list .begin ()->first );
1104
+ std::vector<Host_data *> same_prio;
1079
1105
std::vector<uint16_t > weights;
1080
1106
1081
1107
@@ -1104,6 +1130,8 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1104
1130
std::advance (weight_el, pos);
1105
1131
}
1106
1132
1133
+ proxy->use_protocol (uri.Protocol ());
1134
+
1107
1135
try {
1108
1136
connect ((*el)->name , userName,
1109
1137
password,
@@ -1120,35 +1148,28 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
1120
1148
weights.erase (weight_el);
1121
1149
}
1122
1150
1123
- list .erase (same_range.first , same_range.second );
1151
+ host_list .erase (same_range.first , same_range.second );
1124
1152
1125
1153
};
1126
1154
1127
1155
if (!connected)
1128
1156
{
1129
1157
std::stringstream err;
1130
- err << " Unable to connect to any of the hosts of " << uri.Host () << " SRV" ;
1158
+ if (opt_dns_srv)
1159
+ err << " Unable to connect to any of the hosts of " << uri.Host () << " SRV" ;
1160
+ else if (uri.size () >1 ) {
1161
+ err << " Unable to connect to any of the hosts" ;
1162
+ }
1163
+ else {
1164
+ err << " Unable to connect to " << uri.Host () << " :" << uri.Port ();
1165
+ }
1131
1166
proxy.reset ();
1132
1167
throw sql::InvalidArgumentException (err.str ());
1133
1168
}
1134
-
1135
- }
1136
- else
1137
- {
1138
- try {
1139
- connect (uri.Host (),
1140
- userName,
1141
- password,
1142
- uri.Schema () /* schema */ ,
1143
- uri.Port (),
1144
- uri.SocketOrPipe () /* socket or named pipe */ );
1145
- } catch (sql::SQLException&)
1146
- {
1147
- proxy.reset ();
1148
- throw ;
1149
- }
1150
1169
}
1151
1170
1171
+
1172
+
1152
1173
if (opt_reconnect) {
1153
1174
try {
1154
1175
proxy->options (MYSQL_OPT_RECONNECT, (const char *) &intern->reconnect );
0 commit comments