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
#include <libdrizzle/constants.h>
40
#define PROTOCOL_VERSION 10
42
namespace po= boost::program_options;
44
using namespace drizzled;
46
namespace drizzle_plugin
49
std::vector<std::string> ClientMySQLProtocol::mysql_admin_ip_addresses;
50
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
52
static port_constraint port;
53
static timeout_constraint connect_timeout;
54
static timeout_constraint read_timeout;
55
static timeout_constraint write_timeout;
56
static retry_constraint retry_count;
57
static buffer_constraint buffer_length;
59
static uint32_t random_seed1;
60
static uint32_t random_seed2;
61
static const uint32_t random_max= 0x3FFFFFFF;
62
static const double random_max_double= (double)0x3FFFFFFF;
65
ProtocolCounters *ListenMySQLProtocol::mysql_counters= new ProtocolCounters();
67
ListenMySQLProtocol::~ListenMySQLProtocol()
70
void ListenMySQLProtocol::addCountersToTable()
72
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters()->connectionCount));
73
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters()->connected));
74
counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters()->failedConnections));
77
const std::string ListenMySQLProtocol::getHost(void) const
82
in_port_t ListenMySQLProtocol::getPort(void) const
87
plugin::Client *ListenMySQLProtocol::getClient(int fd)
90
new_fd= acceptTcp(fd);
94
return new ClientMySQLProtocol(new_fd, _using_mysql41_protocol, getCounters());
97
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
98
is_admin_connection(false),
99
_using_mysql41_protocol(using_mysql41_protocol),
100
counters(set_counters)
108
if (drizzleclient_net_init_sock(&net, fd, buffer_length.get()))
111
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
112
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
113
net.retry_count=retry_count.get();
116
ClientMySQLProtocol::~ClientMySQLProtocol()
122
int ClientMySQLProtocol::getFileDescriptor(void)
124
return drizzleclient_net_get_sd(&net);
127
bool ClientMySQLProtocol::isConnected()
132
bool ClientMySQLProtocol::isReading(void)
134
return net.reading_or_writing == 1;
137
bool ClientMySQLProtocol::isWriting(void)
139
return net.reading_or_writing == 2;
142
bool ClientMySQLProtocol::flush()
146
bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
152
void ClientMySQLProtocol::close(void)
156
drizzleclient_net_close(&net);
157
drizzleclient_net_end(&net);
158
if (is_admin_connection)
159
counters->adminConnected.decrement();
161
counters->connected.decrement();
165
bool ClientMySQLProtocol::authenticate()
167
bool connection_is_valid;
168
if (is_admin_connection)
170
counters->adminConnectionCount.increment();
171
counters->adminConnected.increment();
175
counters->connectionCount.increment();
176
counters->connected.increment();
179
/* Use "connect_timeout" value during connection phase */
180
drizzleclient_net_set_read_timeout(&net, connect_timeout.get());
181
drizzleclient_net_set_write_timeout(&net, connect_timeout.get());
183
connection_is_valid= checkConnection();
185
if (connection_is_valid)
187
if (not is_admin_connection and (counters->connected > counters->max_connections))
189
std::string errmsg(ER(ER_CON_COUNT_ERROR));
190
sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
191
counters->failedConnections.increment();
200
sendError(session->main_da.sql_errno(), session->main_da.message());
201
counters->failedConnections.increment();
205
/* Connect completed, set read/write timeouts back to default */
206
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
207
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
211
bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t *packet_length)
214
This thread will do a blocking read from the client which
215
will be interrupted when the next command is received from
216
the client, the connection is closed or "net_wait_timeout"
217
number of seconds has passed
220
/* We can do this much more efficiently with poll timeouts or watcher thread,
221
disabling for now, which means net_wait_timeout == read_timeout. */
222
drizzleclient_net_set_read_timeout(&net,
223
session->variables.net_wait_timeout);
228
*packet_length= drizzleclient_net_read(&net);
229
if (*packet_length == packet_error)
231
/* Check if we can continue without closing the connection */
233
if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
234
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
235
if (session->main_da.status() == Diagnostics_area::DA_ERROR)
236
sendError(session->main_da.sql_errno(), session->main_da.message());
241
return false; // We have to close it.
246
*l_packet= (char*) net.read_pos;
249
'packet_length' contains length of data, as it was stored in packet
250
header. In case of malformed header, drizzleclient_net_read returns zero.
251
If packet_length is not zero, drizzleclient_net_read ensures that the returned
252
number of bytes was actually read from network.
253
There is also an extra safety measure in drizzleclient_net_read:
254
it sets packet[packet_length]= 0, but only for non-zero packets.
257
if (*packet_length == 0) /* safety */
259
/* Initialize with COM_SLEEP packet */
260
(*l_packet)[0]= (unsigned char) COM_SLEEP;
263
else if (_using_mysql41_protocol)
265
/* Map from MySQL commands to Drizzle commands. */
266
switch ((int)(*l_packet)[0])
270
case 2: /* INIT_DB */
274
case 8: /* SHUTDOWN */
275
(*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
279
(*l_packet)[0]= (unsigned char) COM_PING;
284
/* Respond with unknown command for MySQL commands we don't support. */
285
(*l_packet)[0]= (unsigned char) COM_END;
291
/* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
292
(*l_packet)[*packet_length]= '\0'; /* safety */
295
/* See comment above. */
296
/* Restore read timeout value */
297
drizzleclient_net_set_read_timeout(&net,
298
session->variables.net_read_timeout);
305
Return ok to the client.
307
The ok packet has the following structure:
309
- 0 : Marker (1 byte)
310
- affected_rows : Stored in 1-9 bytes
311
- id : Stored in 1-9 bytes
312
- server_status : Copy of session->server_status; Can be used by client
313
to check if we are inside an transaction.
315
- warning_count : Stored in 2 bytes; New in 4.1 client
316
- message : Stored as packed length (1-9 bytes) + message.
317
Is not stored if no message.
319
@param session Thread handler
320
@param affected_rows Number of rows changed by statement
321
@param id Auto_increment id for first row (if used)
322
@param message Message to send to the client (Used by mysql_status)
325
void ClientMySQLProtocol::sendOK()
327
unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
328
const char *message= NULL;
331
if (!net.vio) // hack for re-parsing queries
336
buff[0]=0; // No fields
337
if (session->main_da.status() == Diagnostics_area::DA_OK)
339
if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
340
pos=storeLength(buff+1,session->main_da.found_rows());
342
pos=storeLength(buff+1,session->main_da.affected_rows());
343
pos=storeLength(pos, session->main_da.last_insert_id());
344
int2store(pos, session->main_da.server_status());
346
tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
347
message= session->main_da.message();
351
pos=storeLength(buff+1,0);
352
pos=storeLength(pos, 0);
353
int2store(pos, session->server_status);
355
tmp= min(session->total_warn_count, (uint32_t)65535);
358
/* We can only return up to 65535 warnings in two bytes */
362
session->main_da.can_overwrite_status= true;
364
if (message && message[0])
366
size_t length= strlen(message);
367
pos=storeLength(pos,length);
368
memcpy(pos,(unsigned char*) message,length);
371
drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
372
drizzleclient_net_flush(&net);
374
session->main_da.can_overwrite_status= false;
378
Send eof (= end of result set) to the client.
380
The eof packet has the following structure:
382
- 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
383
- warning_count : Stored in 2 bytes; New in 4.1 client
384
- status_flag : Stored in 2 bytes;
385
For flags like SERVER_MORE_RESULTS_EXISTS.
387
Note that the warning count will not be sent if 'no_flush' is set as
388
we don't want to report the warning count until all data is sent to the
392
void ClientMySQLProtocol::sendEOF()
394
/* Set to true if no active vio, to work well in case of --init-file */
397
session->main_da.can_overwrite_status= true;
398
writeEOFPacket(session->main_da.server_status(),
399
session->main_da.total_warn_count());
400
drizzleclient_net_flush(&net);
401
session->main_da.can_overwrite_status= false;
403
packet.shrink(buffer_length.get());
407
void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
411
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
413
unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
415
assert(sql_errno != EE_OK);
416
assert(err && err[0]);
419
It's one case when we can push an error even though there
420
is an OK or EOF already.
422
session->main_da.can_overwrite_status= true;
424
/* Abort multi-result sets */
425
session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
428
Send a error string to client.
430
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
431
critical that every error that can be intercepted is issued in one
432
place only, my_message_sql.
440
int2store(buff, static_cast<uint16_t>(sql_errno));
443
/* The first # is to make the client backward compatible */
445
pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
446
pos+= strlen(error::convert_to_sqlstate(sql_errno));
448
char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
449
tmp+= strlen((char*)pos);
451
length= (uint32_t)(tmp-(char*)buff);
454
drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
456
drizzleclient_net_flush(&net);
458
session->main_da.can_overwrite_status= false;
462
Send name and type of result to client.
464
Sum fields has table name empty and field_name.
466
@param Session Thread data object
467
@param list List of items to send to client
468
@param flag Bit mask with the following functions:
469
- 1 send number of rows
470
- 2 send default values
471
- 4 don't write eof packet
476
1 Error (Note that in this case the error is not sent to the
479
bool ClientMySQLProtocol::sendFields(List<Item> *list)
481
List<Item>::iterator it(list->begin());
483
unsigned char buff[80];
484
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
486
unsigned char *row_pos= storeLength(buff, list->elements);
487
(void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
493
item->make_field(&field);
497
if (store(STRING_WITH_LEN("def")) ||
498
store(field.db_name) ||
499
store(field.table_name) ||
500
store(field.org_table_name) ||
501
store(field.col_name) ||
502
store(field.org_col_name) ||
503
packet.realloc(packet.length()+12))
506
/* Store fixed length fields */
507
pos= (char*) packet.ptr()+packet.length();
508
*pos++= 12; // Length of packed fields
510
int2store(pos, field.charsetnr);
511
int4store(pos+2, field.length);
513
if (_using_mysql41_protocol)
515
/* Switch to MySQL field numbering. */
518
case DRIZZLE_TYPE_LONG:
522
case DRIZZLE_TYPE_DOUBLE:
526
case DRIZZLE_TYPE_NULL:
530
case DRIZZLE_TYPE_TIMESTAMP:
534
case DRIZZLE_TYPE_LONGLONG:
538
case DRIZZLE_TYPE_DATETIME:
542
case DRIZZLE_TYPE_TIME:
546
case DRIZZLE_TYPE_DATE:
550
case DRIZZLE_TYPE_VARCHAR:
554
case DRIZZLE_TYPE_MICROTIME:
558
case DRIZZLE_TYPE_UUID:
562
case DRIZZLE_TYPE_BOOLEAN:
563
pos[6]= DRIZZLE_COLUMN_TYPE_TINY;
566
case DRIZZLE_TYPE_DECIMAL:
570
case DRIZZLE_TYPE_ENUM:
574
case DRIZZLE_TYPE_BLOB:
581
/* Add one to compensate for tinyint removal from enum. */
582
pos[6]= field.type + 1;
585
int2store(pos+7,field.flags);
586
pos[9]= (char) field.decimals;
587
pos[10]= 0; // For the future
588
pos[11]= 0; // For the future
591
packet.length((uint32_t) (pos - packet.ptr()));
597
Mark the end of meta-data result set, and store session->server_status,
598
to show that there is no cursor.
599
Send no warning information, as it will be sent at statement end.
601
writeEOFPacket(session->server_status, session->total_warn_count);
605
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
610
bool ClientMySQLProtocol::store(Field *from)
614
if (from->type() == DRIZZLE_TYPE_BOOLEAN)
616
return store(from->val_int());
619
char buff[MAX_FIELD_WIDTH];
620
String str(buff,sizeof(buff), &my_charset_bin);
622
from->val_str_internal(&str);
624
return netStoreData((const unsigned char *)str.ptr(), str.length());
627
bool ClientMySQLProtocol::store(void)
631
return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
634
bool ClientMySQLProtocol::store(int32_t from)
637
return netStoreData((unsigned char*) buff,
638
(size_t) (internal::int10_to_str(from, buff, -10) - buff));
641
bool ClientMySQLProtocol::store(uint32_t from)
644
return netStoreData((unsigned char*) buff,
645
(size_t) (internal::int10_to_str(from, buff, 10) - buff));
648
bool ClientMySQLProtocol::store(int64_t from)
651
return netStoreData((unsigned char*) buff,
652
(size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
655
bool ClientMySQLProtocol::store(uint64_t from)
658
return netStoreData((unsigned char*) buff,
659
(size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
662
bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
664
buffer->set_real(from, decimals, session->charset());
665
return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
668
bool ClientMySQLProtocol::store(const char *from, size_t length)
670
return netStoreData((const unsigned char *)from, length);
673
bool ClientMySQLProtocol::wasAborted(void)
675
return net.error && net.vio != 0;
678
bool ClientMySQLProtocol::haveMoreData(void)
680
return drizzleclient_net_more_data(&net);
683
bool ClientMySQLProtocol::haveError(void)
685
return net.error || net.vio == 0;
688
bool ClientMySQLProtocol::checkConnection(void)
692
char scramble[SCRAMBLE_LENGTH];
693
identifier::User::shared_ptr user_identifier= identifier::User::make_shared();
695
makeScramble(scramble);
702
if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
704
my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
708
user_identifier->setAddress(ip);
710
drizzleclient_net_keepalive(&net, true);
712
uint32_t server_capabilites;
714
/* buff[] needs to big enough to hold the server_version variable */
715
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
717
server_capabilites= CLIENT_BASIC_FLAGS;
719
if (_using_mysql41_protocol)
720
server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
723
server_capabilites|= CLIENT_COMPRESS;
724
#endif /* HAVE_COMPRESS */
726
end= buff + strlen(PANDORA_RELEASE_VERSION);
727
if ((end - buff) >= SERVER_VERSION_LENGTH)
728
end= buff + (SERVER_VERSION_LENGTH - 1);
729
memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
733
int4store((unsigned char*) end, session->variables.pseudo_thread_id);
736
/* We don't use scramble anymore. */
737
memcpy(end, scramble, SCRAMBLE_LENGTH_323);
738
end+= SCRAMBLE_LENGTH_323;
739
*end++= 0; /* an empty byte for some reason */
741
int2store(end, server_capabilites);
742
/* write server characteristics: up to 16 bytes allowed */
743
end[2]=(char) default_charset_info->number;
744
int2store(end+3, session->server_status);
745
memset(end+5, 0, 13);
748
/* Write scramble tail. */
749
memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
750
end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
751
*end++= 0; /* an empty byte for some reason */
753
/* At this point we write connection message and read reply */
754
if (drizzleclient_net_write_command(&net
755
, (unsigned char) PROTOCOL_VERSION
756
, (unsigned char*) ""
758
, (unsigned char*) buff
759
, (size_t) (end-buff))
760
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
761
|| pkt_len < MIN_HANDSHAKE_SIZE)
763
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
767
if (packet.alloc(buffer_length.get()))
768
return false; /* The error is set by alloc(). */
770
client_capabilities= uint2korr(net.read_pos);
771
if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
773
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
777
client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
778
session->max_client_packet_length= uint4korr(net.read_pos + 4);
779
end= (char*) net.read_pos + 32;
782
Disable those bits which are not supported by the server.
783
This is a precautionary measure, if the client lies. See Bug#27944.
785
client_capabilities&= server_capabilites;
787
if (end >= (char*) net.read_pos + pkt_len + 2)
789
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
793
net.return_status= &session->server_status;
796
char *passwd= strchr(user, '\0')+1;
797
uint32_t user_len= passwd - user - 1;
801
Only support new password format.
803
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
804
*passwd > 127 and become 2**32-127+ after casting to uint.
807
if (client_capabilities & CLIENT_SECURE_CONNECTION &&
808
passwd < (char *) net.read_pos + pkt_len)
810
passwd_len= (unsigned char)(*passwd++);
813
user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
814
user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
822
if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
823
passwd < (char *) net.read_pos + pkt_len)
825
l_db= l_db + passwd_len + 1;
832
/* strlen() can't be easily deleted without changing client */
833
uint32_t db_len= l_db ? strlen(l_db) : 0;
835
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
837
my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
841
/* If username starts and ends in "'", chop them off */
842
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
849
if (client_capabilities & CLIENT_ADMIN)
851
if ((strncmp(user, "root", 4) == 0) and isAdminAllowed())
853
is_admin_connection= true;
857
my_error(ER_ADMIN_ACCESS, MYF(0));
862
user_identifier->setUser(user);
863
session->setUser(user_identifier);
865
return session->checkUser(string(passwd, passwd_len),
866
string(l_db ? l_db : ""));
870
bool ClientMySQLProtocol::isAdminAllowed(void)
872
if (std::find(mysql_admin_ip_addresses.begin(), mysql_admin_ip_addresses.end(), session->user()->address()) != mysql_admin_ip_addresses.end())
878
bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
880
size_t packet_length= packet.length();
882
The +9 comes from that strings of length longer than 16M require
883
9 bytes to be stored (see storeLength).
885
if (packet_length+9+length > packet.alloced_length() &&
886
packet.realloc(packet_length+9+length))
888
unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
889
memcpy(to,from,length);
890
packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
895
Format EOF packet according to the current client and
896
write it to the network output buffer.
899
void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status,
900
uint32_t total_warn_count)
902
unsigned char buff[5];
904
Don't send warn count during SP execution, as the warn_list
905
is cleared between substatements, and mysqltest gets confused
907
uint32_t tmp= min(total_warn_count, (uint32_t)65535);
908
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
909
int2store(buff+1, tmp);
911
The following test should never be true, but it's better to do it
912
because if 'is_fatal_error' is set the server is not going to execute
913
other queries (see the if test in dispatch_command / COM_QUERY)
915
if (session->is_fatal_error)
916
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
917
int2store(buff + 3, server_status);
918
drizzleclient_net_write(&net, buff, 5);
922
Store an integer with simple packing into a output package
924
buffer Store the packed integer here
925
length integers to store
927
This is mostly used to store lengths of strings. We have to cast
928
the result for the LL() becasue of a bug in Forte CC compiler.
931
Position in 'buffer' after the packed length
934
unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
936
if (length < (uint64_t) 251LL)
938
*buffer=(unsigned char) length;
941
/* 251 is reserved for NULL */
942
if (length < (uint64_t) 65536LL)
945
int2store(buffer,(uint32_t) length);
948
if (length < (uint64_t) 16777216LL)
951
int3store(buffer,(uint32_t) length);
955
int8store(buffer,length);
959
void ClientMySQLProtocol::makeScramble(char *scramble)
961
/* This is the MySQL algorithm with minimal changes. */
962
random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
963
random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
964
uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
967
uint32_t pointer_seed;
968
memcpy(&pointer_seed, &pointer, 4);
969
uint32_t random1= (seed + pointer_seed) % random_max;
970
uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
972
for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
974
random1= (random1 * 3 + random2) % random_max;
975
random2= (random1 + random2 + 33) % random_max;
976
*scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
980
void ClientMySQLProtocol::mysql_compose_ip_addresses(vector<string> options)
982
for (vector<string>::iterator it= options.begin();
986
tokenize(*it, mysql_admin_ip_addresses, ",", true);
990
static ListenMySQLProtocol *listen_obj= NULL;
991
plugin::Create_function<MySQLPassword> *mysql_password= NULL;
993
static int init(drizzled::module::Context &context)
995
/* Initialize random seeds for the MySQL algorithm with minimal changes. */
996
time_t seed_time= time(NULL);
997
random_seed1= seed_time % random_max;
998
random_seed2= (seed_time / 2) % random_max;
1000
const module::option_map &vm= context.getOptions();
1002
mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
1003
context.add(mysql_password);
1005
listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
1006
listen_obj->addCountersToTable();
1007
context.add(listen_obj);
1008
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
1009
context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
1010
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
1011
context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
1012
context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
1013
context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
1014
context.registerVariable(new sys_var_const_string_val("bind_address",
1015
vm["bind-address"].as<std::string>()));
1017
context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters->max_connections));
1022
static void init_options(drizzled::module::option_context &context)
1025
po::value<port_constraint>(&port)->default_value(3306),
1026
_("Port number to use for connection or 0 for default to with MySQL "
1028
context("connect-timeout",
1029
po::value<timeout_constraint>(&connect_timeout)->default_value(10),
1030
_("Connect Timeout."));
1031
context("read-timeout",
1032
po::value<timeout_constraint>(&read_timeout)->default_value(30),
1033
_("Read Timeout."));
1034
context("write-timeout",
1035
po::value<timeout_constraint>(&write_timeout)->default_value(60),
1036
_("Write Timeout."));
1037
context("retry-count",
1038
po::value<retry_constraint>(&retry_count)->default_value(10),
1040
context("buffer-length",
1041
po::value<buffer_constraint>(&buffer_length)->default_value(16384),
1042
_("Buffer length."));
1043
context("bind-address",
1044
po::value<string>()->default_value(""),
1045
_("Address to bind to."));
1046
context("max-connections",
1047
po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
1048
_("Maximum simultaneous connections."));
1049
context("admin-ip-addresses",
1050
po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
1051
_("A restrictive IP address list for incoming admin connections."));
1054
} /* namespace drizzle_plugin */
1056
DRIZZLE_DECLARE_PLUGIN
1062
"MySQL Protocol Module",
1064
drizzle_plugin::init, /* Plugin Init */
1066
drizzle_plugin::init_options /* config options */
1068
DRIZZLE_DECLARE_PLUGIN_END;