1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
#include <drizzled/gettext.h>
22
#include <drizzled/error.h>
23
#include <drizzled/query_id.h>
24
#include <drizzled/error/sql_state.h>
25
#include <drizzled/session.h>
26
#include "drizzled/internal/m_string.h"
28
#include <boost/program_options.hpp>
29
#include <drizzled/module/option_map.h>
30
#include "drizzled/util/tokenize.h"
32
#include "mysql_protocol.h"
33
#include "mysql_password.h"
36
#include "drizzled/identifier.h"
38
#define PROTOCOL_VERSION 10
40
namespace po= boost::program_options;
42
using namespace drizzled;
44
namespace drizzle_plugin
47
std::vector<std::string> ClientMySQLProtocol::mysql_admin_ip_addresses;
48
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
50
static port_constraint port;
51
static timeout_constraint connect_timeout;
52
static timeout_constraint read_timeout;
53
static timeout_constraint write_timeout;
54
static retry_constraint retry_count;
55
static buffer_constraint buffer_length;
57
static uint32_t random_seed1;
58
static uint32_t random_seed2;
59
static const uint32_t random_max= 0x3FFFFFFF;
60
static const double random_max_double= (double)0x3FFFFFFF;
63
ProtocolCounters *ListenMySQLProtocol::mysql_counters= new ProtocolCounters();
65
ListenMySQLProtocol::~ListenMySQLProtocol()
68
void ListenMySQLProtocol::addCountersToTable()
70
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters()->connectionCount));
71
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters()->connected));
72
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters()->failedConnections));
75
const std::string ListenMySQLProtocol::getHost(void) const
80
in_port_t ListenMySQLProtocol::getPort(void) const
85
plugin::Client *ListenMySQLProtocol::getClient(int fd)
88
new_fd= acceptTcp(fd);
92
return new ClientMySQLProtocol(new_fd, _using_mysql41_protocol, getCounters());
95
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
96
is_admin_connection(false),
97
_using_mysql41_protocol(using_mysql41_protocol),
98
counters(set_counters)
106
if (drizzleclient_net_init_sock(&net, fd, buffer_length.get()))
109
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
110
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
111
net.retry_count=retry_count.get();
114
ClientMySQLProtocol::~ClientMySQLProtocol()
120
int ClientMySQLProtocol::getFileDescriptor(void)
122
return drizzleclient_net_get_sd(&net);
125
bool ClientMySQLProtocol::isConnected()
130
bool ClientMySQLProtocol::isReading(void)
132
return net.reading_or_writing == 1;
135
bool ClientMySQLProtocol::isWriting(void)
137
return net.reading_or_writing == 2;
140
bool ClientMySQLProtocol::flush()
144
bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
150
void ClientMySQLProtocol::close(void)
154
drizzleclient_net_close(&net);
155
drizzleclient_net_end(&net);
156
if (is_admin_connection)
157
counters->adminConnected.decrement();
159
counters->connected.decrement();
163
bool ClientMySQLProtocol::authenticate()
165
bool connection_is_valid;
166
if (is_admin_connection)
168
counters->adminConnectionCount.increment();
169
counters->adminConnected.increment();
173
counters->connectionCount.increment();
174
counters->connected.increment();
177
/* Use "connect_timeout" value during connection phase */
178
drizzleclient_net_set_read_timeout(&net, connect_timeout.get());
179
drizzleclient_net_set_write_timeout(&net, connect_timeout.get());
181
connection_is_valid= checkConnection();
183
if (connection_is_valid)
185
if (not is_admin_connection and (counters->connected > counters->max_connections))
187
std::string errmsg(ER(ER_CON_COUNT_ERROR));
188
sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
189
counters->failedConnections.increment();
198
sendError(session->main_da.sql_errno(), session->main_da.message());
199
counters->failedConnections.increment();
203
/* Connect completed, set read/write timeouts back to default */
204
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
205
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
209
bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t *packet_length)
212
This thread will do a blocking read from the client which
213
will be interrupted when the next command is received from
214
the client, the connection is closed or "net_wait_timeout"
215
number of seconds has passed
218
/* We can do this much more efficiently with poll timeouts or watcher thread,
219
disabling for now, which means net_wait_timeout == read_timeout. */
220
drizzleclient_net_set_read_timeout(&net,
221
session->variables.net_wait_timeout);
226
*packet_length= drizzleclient_net_read(&net);
227
if (*packet_length == packet_error)
229
/* Check if we can continue without closing the connection */
231
if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
232
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
233
if (session->main_da.status() == Diagnostics_area::DA_ERROR)
234
sendError(session->main_da.sql_errno(), session->main_da.message());
239
return false; // We have to close it.
244
*l_packet= (char*) net.read_pos;
247
'packet_length' contains length of data, as it was stored in packet
248
header. In case of malformed header, drizzleclient_net_read returns zero.
249
If packet_length is not zero, drizzleclient_net_read ensures that the returned
250
number of bytes was actually read from network.
251
There is also an extra safety measure in drizzleclient_net_read:
252
it sets packet[packet_length]= 0, but only for non-zero packets.
255
if (*packet_length == 0) /* safety */
257
/* Initialize with COM_SLEEP packet */
258
(*l_packet)[0]= (unsigned char) COM_SLEEP;
261
else if (_using_mysql41_protocol)
263
/* Map from MySQL commands to Drizzle commands. */
264
switch ((int)(*l_packet)[0])
268
case 2: /* INIT_DB */
272
case 8: /* SHUTDOWN */
273
(*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
277
(*l_packet)[0]= (unsigned char) COM_PING;
282
/* Respond with unknown command for MySQL commands we don't support. */
283
(*l_packet)[0]= (unsigned char) COM_END;
289
/* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
290
(*l_packet)[*packet_length]= '\0'; /* safety */
293
/* See comment above. */
294
/* Restore read timeout value */
295
drizzleclient_net_set_read_timeout(&net,
296
session->variables.net_read_timeout);
303
Return ok to the client.
305
The ok packet has the following structure:
307
- 0 : Marker (1 byte)
308
- affected_rows : Stored in 1-9 bytes
309
- id : Stored in 1-9 bytes
310
- server_status : Copy of session->server_status; Can be used by client
311
to check if we are inside an transaction.
313
- warning_count : Stored in 2 bytes; New in 4.1 client
314
- message : Stored as packed length (1-9 bytes) + message.
315
Is not stored if no message.
317
@param session Thread handler
318
@param affected_rows Number of rows changed by statement
319
@param id Auto_increment id for first row (if used)
320
@param message Message to send to the client (Used by mysql_status)
323
void ClientMySQLProtocol::sendOK()
325
unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
326
const char *message= NULL;
329
if (!net.vio) // hack for re-parsing queries
334
buff[0]=0; // No fields
335
if (session->main_da.status() == Diagnostics_area::DA_OK)
337
if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
338
pos=storeLength(buff+1,session->main_da.found_rows());
340
pos=storeLength(buff+1,session->main_da.affected_rows());
341
pos=storeLength(pos, session->main_da.last_insert_id());
342
int2store(pos, session->main_da.server_status());
344
tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
345
message= session->main_da.message();
349
pos=storeLength(buff+1,0);
350
pos=storeLength(pos, 0);
351
int2store(pos, session->server_status);
353
tmp= min(session->total_warn_count, (uint32_t)65535);
356
/* We can only return up to 65535 warnings in two bytes */
360
session->main_da.can_overwrite_status= true;
362
if (message && message[0])
364
size_t length= strlen(message);
365
pos=storeLength(pos,length);
366
memcpy(pos,(unsigned char*) message,length);
369
drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
370
drizzleclient_net_flush(&net);
372
session->main_da.can_overwrite_status= false;
376
Send eof (= end of result set) to the client.
378
The eof packet has the following structure:
380
- 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
381
- warning_count : Stored in 2 bytes; New in 4.1 client
382
- status_flag : Stored in 2 bytes;
383
For flags like SERVER_MORE_RESULTS_EXISTS.
385
Note that the warning count will not be sent if 'no_flush' is set as
386
we don't want to report the warning count until all data is sent to the
390
void ClientMySQLProtocol::sendEOF()
392
/* Set to true if no active vio, to work well in case of --init-file */
395
session->main_da.can_overwrite_status= true;
396
writeEOFPacket(session->main_da.server_status(),
397
session->main_da.total_warn_count());
398
drizzleclient_net_flush(&net);
399
session->main_da.can_overwrite_status= false;
401
packet.shrink(buffer_length.get());
405
void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
409
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
411
unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
413
assert(sql_errno != EE_OK);
414
assert(err && err[0]);
417
It's one case when we can push an error even though there
418
is an OK or EOF already.
420
session->main_da.can_overwrite_status= true;
422
/* Abort multi-result sets */
423
session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
426
Send a error string to client.
428
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
429
critical that every error that can be intercepted is issued in one
430
place only, my_message_sql.
438
int2store(buff, static_cast<uint16_t>(sql_errno));
441
/* The first # is to make the client backward compatible */
443
pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
444
pos+= strlen(error::convert_to_sqlstate(sql_errno));
446
char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
447
tmp+= strlen((char*)pos);
449
length= (uint32_t)(tmp-(char*)buff);
452
drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
454
drizzleclient_net_flush(&net);
456
session->main_da.can_overwrite_status= false;
460
Send name and type of result to client.
462
Sum fields has table name empty and field_name.
464
@param Session Thread data object
465
@param list List of items to send to client
466
@param flag Bit mask with the following functions:
467
- 1 send number of rows
468
- 2 send default values
469
- 4 don't write eof packet
474
1 Error (Note that in this case the error is not sent to the
477
bool ClientMySQLProtocol::sendFields(List<Item> *list)
479
List_iterator_fast<Item> it(*list);
481
unsigned char buff[80];
482
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
484
unsigned char *row_pos= storeLength(buff, list->elements);
485
(void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
491
item->make_field(&field);
495
if (store(STRING_WITH_LEN("def")) ||
496
store(field.db_name) ||
497
store(field.table_name) ||
498
store(field.org_table_name) ||
499
store(field.col_name) ||
500
store(field.org_col_name) ||
501
packet.realloc(packet.length()+12))
504
/* Store fixed length fields */
505
pos= (char*) packet.ptr()+packet.length();
506
*pos++= 12; // Length of packed fields
508
int2store(pos, field.charsetnr);
509
int4store(pos+2, field.length);
511
if (_using_mysql41_protocol)
513
/* Switch to MySQL field numbering. */
516
case DRIZZLE_TYPE_LONG:
520
case DRIZZLE_TYPE_DOUBLE:
524
case DRIZZLE_TYPE_NULL:
528
case DRIZZLE_TYPE_TIMESTAMP:
532
case DRIZZLE_TYPE_LONGLONG:
536
case DRIZZLE_TYPE_DATETIME:
540
case DRIZZLE_TYPE_TIME:
544
case DRIZZLE_TYPE_DATE:
548
case DRIZZLE_TYPE_VARCHAR:
552
case DRIZZLE_TYPE_MICROTIME:
556
case DRIZZLE_TYPE_UUID:
560
case DRIZZLE_TYPE_BOOLEAN:
564
case DRIZZLE_TYPE_DECIMAL:
568
case DRIZZLE_TYPE_ENUM:
572
case DRIZZLE_TYPE_BLOB:
579
/* Add one to compensate for tinyint removal from enum. */
580
pos[6]= field.type + 1;
583
int2store(pos+7,field.flags);
584
pos[9]= (char) field.decimals;
585
pos[10]= 0; // For the future
586
pos[11]= 0; // For the future
589
packet.length((uint32_t) (pos - packet.ptr()));
595
Mark the end of meta-data result set, and store session->server_status,
596
to show that there is no cursor.
597
Send no warning information, as it will be sent at statement end.
599
writeEOFPacket(session->server_status, session->total_warn_count);
603
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
608
bool ClientMySQLProtocol::store(Field *from)
612
char buff[MAX_FIELD_WIDTH];
613
String str(buff,sizeof(buff), &my_charset_bin);
615
from->val_str_internal(&str);
617
return netStoreData((const unsigned char *)str.ptr(), str.length());
620
bool ClientMySQLProtocol::store(void)
624
return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
627
bool ClientMySQLProtocol::store(int32_t from)
630
return netStoreData((unsigned char*) buff,
631
(size_t) (internal::int10_to_str(from, buff, -10) - buff));
634
bool ClientMySQLProtocol::store(uint32_t from)
637
return netStoreData((unsigned char*) buff,
638
(size_t) (internal::int10_to_str(from, buff, 10) - buff));
641
bool ClientMySQLProtocol::store(int64_t from)
644
return netStoreData((unsigned char*) buff,
645
(size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
648
bool ClientMySQLProtocol::store(uint64_t from)
651
return netStoreData((unsigned char*) buff,
652
(size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
655
bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
657
buffer->set_real(from, decimals, session->charset());
658
return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
661
bool ClientMySQLProtocol::store(const char *from, size_t length)
663
return netStoreData((const unsigned char *)from, length);
666
bool ClientMySQLProtocol::wasAborted(void)
668
return net.error && net.vio != 0;
671
bool ClientMySQLProtocol::haveMoreData(void)
673
return drizzleclient_net_more_data(&net);
676
bool ClientMySQLProtocol::haveError(void)
678
return net.error || net.vio == 0;
681
bool ClientMySQLProtocol::checkConnection(void)
685
char scramble[SCRAMBLE_LENGTH];
686
identifier::User::shared_ptr user_identifier= identifier::User::make_shared();
688
makeScramble(scramble);
695
if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
697
my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
701
user_identifier->setAddress(ip);
703
drizzleclient_net_keepalive(&net, true);
705
uint32_t server_capabilites;
707
/* buff[] needs to big enough to hold the server_version variable */
708
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
710
server_capabilites= CLIENT_BASIC_FLAGS;
712
if (_using_mysql41_protocol)
713
server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
716
server_capabilites|= CLIENT_COMPRESS;
717
#endif /* HAVE_COMPRESS */
719
end= buff + strlen(PANDORA_RELEASE_VERSION);
720
if ((end - buff) >= SERVER_VERSION_LENGTH)
721
end= buff + (SERVER_VERSION_LENGTH - 1);
722
memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
726
int4store((unsigned char*) end, session->variables.pseudo_thread_id);
729
/* We don't use scramble anymore. */
730
memcpy(end, scramble, SCRAMBLE_LENGTH_323);
731
end+= SCRAMBLE_LENGTH_323;
732
*end++= 0; /* an empty byte for some reason */
734
int2store(end, server_capabilites);
735
/* write server characteristics: up to 16 bytes allowed */
736
end[2]=(char) default_charset_info->number;
737
int2store(end+3, session->server_status);
738
memset(end+5, 0, 13);
741
/* Write scramble tail. */
742
memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
743
end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
744
*end++= 0; /* an empty byte for some reason */
746
/* At this point we write connection message and read reply */
747
if (drizzleclient_net_write_command(&net
748
, (unsigned char) PROTOCOL_VERSION
749
, (unsigned char*) ""
751
, (unsigned char*) buff
752
, (size_t) (end-buff))
753
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
754
|| pkt_len < MIN_HANDSHAKE_SIZE)
756
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
760
if (packet.alloc(buffer_length.get()))
761
return false; /* The error is set by alloc(). */
763
client_capabilities= uint2korr(net.read_pos);
764
if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
766
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
770
client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
771
session->max_client_packet_length= uint4korr(net.read_pos + 4);
772
end= (char*) net.read_pos + 32;
775
Disable those bits which are not supported by the server.
776
This is a precautionary measure, if the client lies. See Bug#27944.
778
client_capabilities&= server_capabilites;
780
if (end >= (char*) net.read_pos + pkt_len + 2)
782
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
786
net.return_status= &session->server_status;
789
char *passwd= strchr(user, '\0')+1;
790
uint32_t user_len= passwd - user - 1;
794
Only support new password format.
796
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
797
*passwd > 127 and become 2**32-127+ after casting to uint.
800
if (client_capabilities & CLIENT_SECURE_CONNECTION &&
801
passwd < (char *) net.read_pos + pkt_len)
803
passwd_len= (unsigned char)(*passwd++);
806
user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
807
user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
815
if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
816
passwd < (char *) net.read_pos + pkt_len)
818
l_db= l_db + passwd_len + 1;
825
/* strlen() can't be easily deleted without changing client */
826
uint32_t db_len= l_db ? strlen(l_db) : 0;
828
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
830
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
834
/* If username starts and ends in "'", chop them off */
835
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
842
if (client_capabilities & CLIENT_ADMIN)
844
if ((strncmp(user, "root", 4) == 0) and isAdminAllowed())
846
is_admin_connection= true;
850
my_error(ER_ADMIN_ACCESS, MYF(0));
855
user_identifier->setUser(user);
856
session->setUser(user_identifier);
858
return session->checkUser(string(passwd, passwd_len),
859
string(l_db ? l_db : ""));
863
bool ClientMySQLProtocol::isAdminAllowed(void)
865
if (std::find(mysql_admin_ip_addresses.begin(), mysql_admin_ip_addresses.end(), session->user()->address()) != mysql_admin_ip_addresses.end())
871
bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
873
size_t packet_length= packet.length();
875
The +9 comes from that strings of length longer than 16M require
876
9 bytes to be stored (see storeLength).
878
if (packet_length+9+length > packet.alloced_length() &&
879
packet.realloc(packet_length+9+length))
881
unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
882
memcpy(to,from,length);
883
packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
888
Format EOF packet according to the current client and
889
write it to the network output buffer.
892
void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status,
893
uint32_t total_warn_count)
895
unsigned char buff[5];
897
Don't send warn count during SP execution, as the warn_list
898
is cleared between substatements, and mysqltest gets confused
900
uint32_t tmp= min(total_warn_count, (uint32_t)65535);
901
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
902
int2store(buff+1, tmp);
904
The following test should never be true, but it's better to do it
905
because if 'is_fatal_error' is set the server is not going to execute
906
other queries (see the if test in dispatch_command / COM_QUERY)
908
if (session->is_fatal_error)
909
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
910
int2store(buff + 3, server_status);
911
drizzleclient_net_write(&net, buff, 5);
915
Store an integer with simple packing into a output package
917
buffer Store the packed integer here
918
length integers to store
920
This is mostly used to store lengths of strings. We have to cast
921
the result for the LL() becasue of a bug in Forte CC compiler.
924
Position in 'buffer' after the packed length
927
unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
929
if (length < (uint64_t) 251LL)
931
*buffer=(unsigned char) length;
934
/* 251 is reserved for NULL */
935
if (length < (uint64_t) 65536LL)
938
int2store(buffer,(uint32_t) length);
941
if (length < (uint64_t) 16777216LL)
944
int3store(buffer,(uint32_t) length);
948
int8store(buffer,length);
952
void ClientMySQLProtocol::makeScramble(char *scramble)
954
/* This is the MySQL algorithm with minimal changes. */
955
random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
956
random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
957
uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
960
uint32_t pointer_seed;
961
memcpy(&pointer_seed, &pointer, 4);
962
uint32_t random1= (seed + pointer_seed) % random_max;
963
uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
965
for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
967
random1= (random1 * 3 + random2) % random_max;
968
random2= (random1 + random2 + 33) % random_max;
969
*scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
973
void ClientMySQLProtocol::mysql_compose_ip_addresses(vector<string> options)
975
for (vector<string>::iterator it= options.begin();
979
tokenize(*it, mysql_admin_ip_addresses, ",", true);
983
static ListenMySQLProtocol *listen_obj= NULL;
984
plugin::Create_function<MySQLPassword> *mysql_password= NULL;
986
static int init(drizzled::module::Context &context)
988
/* Initialize random seeds for the MySQL algorithm with minimal changes. */
989
time_t seed_time= time(NULL);
990
random_seed1= seed_time % random_max;
991
random_seed2= (seed_time / 2) % random_max;
993
const module::option_map &vm= context.getOptions();
995
mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
996
context.add(mysql_password);
998
listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
999
listen_obj->addCountersToTable();
1000
context.add(listen_obj);
1001
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
1002
context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
1003
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
1004
context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
1005
context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
1006
context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
1007
context.registerVariable(new sys_var_const_string_val("bind_address",
1008
vm["bind-address"].as<std::string>()));
1010
context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters->max_connections));
1015
static void init_options(drizzled::module::option_context &context)
1018
po::value<port_constraint>(&port)->default_value(3306),
1019
_("Port number to use for connection or 0 for default to with MySQL "
1021
context("connect-timeout",
1022
po::value<timeout_constraint>(&connect_timeout)->default_value(10),
1023
_("Connect Timeout."));
1024
context("read-timeout",
1025
po::value<timeout_constraint>(&read_timeout)->default_value(30),
1026
_("Read Timeout."));
1027
context("write-timeout",
1028
po::value<timeout_constraint>(&write_timeout)->default_value(60),
1029
_("Write Timeout."));
1030
context("retry-count",
1031
po::value<retry_constraint>(&retry_count)->default_value(10),
1033
context("buffer-length",
1034
po::value<buffer_constraint>(&buffer_length)->default_value(16384),
1035
_("Buffer length."));
1036
context("bind-address",
1037
po::value<string>()->default_value(""),
1038
_("Address to bind to."));
1039
context("max-connections",
1040
po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
1041
_("Maximum simultaneous connections."));
1042
context("admin-ip-addresses",
1043
po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
1044
_("A restrictive IP address list for incoming admin connections."));
1047
} /* namespace drizzle_plugin */
1049
DRIZZLE_DECLARE_PLUGIN
1055
"MySQL Protocol Module",
1057
drizzle_plugin::init, /* Plugin Init */
1059
drizzle_plugin::init_options /* config options */
1061
DRIZZLE_DECLARE_PLUGIN_END;