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
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/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"
35
#include "table_function.h"
37
#define PROTOCOL_VERSION 10
39
namespace po= boost::program_options;
41
using namespace drizzled;
43
namespace drizzle_plugin
46
std::vector<std::string> ClientMySQLProtocol::mysql_admin_ip_addresses;
47
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
49
static port_constraint port;
50
static timeout_constraint connect_timeout;
51
static timeout_constraint read_timeout;
52
static timeout_constraint write_timeout;
53
static retry_constraint retry_count;
54
static buffer_constraint buffer_length;
56
static uint32_t random_seed1;
57
static uint32_t random_seed2;
58
static const uint32_t random_max= 0x3FFFFFFF;
59
static const double random_max_double= (double)0x3FFFFFFF;
62
ProtocolCounters *ListenMySQLProtocol::mysql_counters= new ProtocolCounters();
64
ListenMySQLProtocol::~ListenMySQLProtocol()
67
const std::string ListenMySQLProtocol::getHost(void) const
72
in_port_t ListenMySQLProtocol::getPort(void) const
77
plugin::Client *ListenMySQLProtocol::getClient(int fd)
80
new_fd= acceptTcp(fd);
84
return new ClientMySQLProtocol(new_fd, _using_mysql41_protocol, getCounters());
87
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
88
is_admin_connection(false),
89
_using_mysql41_protocol(using_mysql41_protocol),
90
counters(set_counters)
98
if (drizzleclient_net_init_sock(&net, fd, buffer_length.get()))
101
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
102
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
103
net.retry_count=retry_count.get();
106
ClientMySQLProtocol::~ClientMySQLProtocol()
112
int ClientMySQLProtocol::getFileDescriptor(void)
114
return drizzleclient_net_get_sd(&net);
117
bool ClientMySQLProtocol::isConnected()
122
bool ClientMySQLProtocol::isReading(void)
124
return net.reading_or_writing == 1;
127
bool ClientMySQLProtocol::isWriting(void)
129
return net.reading_or_writing == 2;
132
bool ClientMySQLProtocol::flush()
136
bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
142
void ClientMySQLProtocol::close(void)
146
drizzleclient_net_close(&net);
147
drizzleclient_net_end(&net);
148
if (is_admin_connection)
149
counters->adminConnected.decrement();
151
counters->connected.decrement();
155
bool ClientMySQLProtocol::authenticate()
157
bool connection_is_valid;
158
if (is_admin_connection)
160
counters->adminConnectionCount.increment();
161
counters->adminConnected.increment();
165
counters->connectionCount.increment();
166
counters->connected.increment();
169
/* Use "connect_timeout" value during connection phase */
170
drizzleclient_net_set_read_timeout(&net, connect_timeout.get());
171
drizzleclient_net_set_write_timeout(&net, connect_timeout.get());
173
connection_is_valid= checkConnection();
175
if (connection_is_valid)
177
if (not is_admin_connection and (counters->connected > counters->max_connections))
179
std::string errmsg(ER(ER_CON_COUNT_ERROR));
180
sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
181
counters->failedConnections.increment();
190
sendError(session->main_da.sql_errno(), session->main_da.message());
191
counters->failedConnections.increment();
195
/* Connect completed, set read/write timeouts back to default */
196
drizzleclient_net_set_read_timeout(&net, read_timeout.get());
197
drizzleclient_net_set_write_timeout(&net, write_timeout.get());
201
bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t *packet_length)
204
This thread will do a blocking read from the client which
205
will be interrupted when the next command is received from
206
the client, the connection is closed or "net_wait_timeout"
207
number of seconds has passed
210
/* We can do this much more efficiently with poll timeouts or watcher thread,
211
disabling for now, which means net_wait_timeout == read_timeout. */
212
drizzleclient_net_set_read_timeout(&net,
213
session->variables.net_wait_timeout);
218
*packet_length= drizzleclient_net_read(&net);
219
if (*packet_length == packet_error)
221
/* Check if we can continue without closing the connection */
223
if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
224
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
225
if (session->main_da.status() == Diagnostics_area::DA_ERROR)
226
sendError(session->main_da.sql_errno(), session->main_da.message());
231
return false; // We have to close it.
236
*l_packet= (char*) net.read_pos;
239
'packet_length' contains length of data, as it was stored in packet
240
header. In case of malformed header, drizzleclient_net_read returns zero.
241
If packet_length is not zero, drizzleclient_net_read ensures that the returned
242
number of bytes was actually read from network.
243
There is also an extra safety measure in drizzleclient_net_read:
244
it sets packet[packet_length]= 0, but only for non-zero packets.
247
if (*packet_length == 0) /* safety */
249
/* Initialize with COM_SLEEP packet */
250
(*l_packet)[0]= (unsigned char) COM_SLEEP;
253
else if (_using_mysql41_protocol)
255
/* Map from MySQL commands to Drizzle commands. */
256
switch ((int)(*l_packet)[0])
260
case 2: /* INIT_DB */
264
case 8: /* SHUTDOWN */
265
(*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
269
(*l_packet)[0]= (unsigned char) COM_PING;
274
/* Respond with unknown command for MySQL commands we don't support. */
275
(*l_packet)[0]= (unsigned char) COM_END;
281
/* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
282
(*l_packet)[*packet_length]= '\0'; /* safety */
285
/* See comment above. */
286
/* Restore read timeout value */
287
drizzleclient_net_set_read_timeout(&net,
288
session->variables.net_read_timeout);
295
Return ok to the client.
297
The ok packet has the following structure:
299
- 0 : Marker (1 byte)
300
- affected_rows : Stored in 1-9 bytes
301
- id : Stored in 1-9 bytes
302
- server_status : Copy of session->server_status; Can be used by client
303
to check if we are inside an transaction.
305
- warning_count : Stored in 2 bytes; New in 4.1 client
306
- message : Stored as packed length (1-9 bytes) + message.
307
Is not stored if no message.
309
@param session Thread handler
310
@param affected_rows Number of rows changed by statement
311
@param id Auto_increment id for first row (if used)
312
@param message Message to send to the client (Used by mysql_status)
315
void ClientMySQLProtocol::sendOK()
317
unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
318
const char *message= NULL;
321
if (!net.vio) // hack for re-parsing queries
326
buff[0]=0; // No fields
327
if (session->main_da.status() == Diagnostics_area::DA_OK)
329
if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
330
pos=storeLength(buff+1,session->main_da.found_rows());
332
pos=storeLength(buff+1,session->main_da.affected_rows());
333
pos=storeLength(pos, session->main_da.last_insert_id());
334
int2store(pos, session->main_da.server_status());
336
tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
337
message= session->main_da.message();
341
pos=storeLength(buff+1,0);
342
pos=storeLength(pos, 0);
343
int2store(pos, session->server_status);
345
tmp= min(session->total_warn_count, (uint32_t)65535);
348
/* We can only return up to 65535 warnings in two bytes */
352
session->main_da.can_overwrite_status= true;
354
if (message && message[0])
356
size_t length= strlen(message);
357
pos=storeLength(pos,length);
358
memcpy(pos,(unsigned char*) message,length);
361
drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
362
drizzleclient_net_flush(&net);
364
session->main_da.can_overwrite_status= false;
368
Send eof (= end of result set) to the client.
370
The eof packet has the following structure:
372
- 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
373
- warning_count : Stored in 2 bytes; New in 4.1 client
374
- status_flag : Stored in 2 bytes;
375
For flags like SERVER_MORE_RESULTS_EXISTS.
377
Note that the warning count will not be sent if 'no_flush' is set as
378
we don't want to report the warning count until all data is sent to the
382
void ClientMySQLProtocol::sendEOF()
384
/* Set to true if no active vio, to work well in case of --init-file */
387
session->main_da.can_overwrite_status= true;
388
writeEOFPacket(session->main_da.server_status(),
389
session->main_da.total_warn_count());
390
drizzleclient_net_flush(&net);
391
session->main_da.can_overwrite_status= false;
393
packet.shrink(buffer_length.get());
397
void ClientMySQLProtocol::sendError(uint32_t sql_errno, const char *err)
401
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
403
unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
406
assert(err && err[0]);
409
It's one case when we can push an error even though there
410
is an OK or EOF already.
412
session->main_da.can_overwrite_status= true;
414
/* Abort multi-result sets */
415
session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
418
Send a error string to client.
420
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
421
critical that every error that can be intercepted is issued in one
422
place only, my_message_sql.
430
int2store(buff,sql_errno);
433
/* The first # is to make the client backward compatible */
435
pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
436
pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
438
char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
439
tmp+= strlen((char*)pos);
441
length= (uint32_t)(tmp-(char*)buff);
444
drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
446
drizzleclient_net_flush(&net);
448
session->main_da.can_overwrite_status= false;
452
Send name and type of result to client.
454
Sum fields has table name empty and field_name.
456
@param Session Thread data object
457
@param list List of items to send to client
458
@param flag Bit mask with the following functions:
459
- 1 send number of rows
460
- 2 send default values
461
- 4 don't write eof packet
466
1 Error (Note that in this case the error is not sent to the
469
bool ClientMySQLProtocol::sendFields(List<Item> *list)
471
List_iterator_fast<Item> it(*list);
473
unsigned char buff[80];
474
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
476
unsigned char *row_pos= storeLength(buff, list->elements);
477
(void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
483
item->make_field(&field);
487
if (store(STRING_WITH_LEN("def")) ||
488
store(field.db_name) ||
489
store(field.table_name) ||
490
store(field.org_table_name) ||
491
store(field.col_name) ||
492
store(field.org_col_name) ||
493
packet.realloc(packet.length()+12))
496
/* Store fixed length fields */
497
pos= (char*) packet.ptr()+packet.length();
498
*pos++= 12; // Length of packed fields
500
int2store(pos, field.charsetnr);
501
int4store(pos+2, field.length);
503
if (_using_mysql41_protocol)
505
/* Switch to MySQL field numbering. */
508
case DRIZZLE_TYPE_LONG:
512
case DRIZZLE_TYPE_DOUBLE:
516
case DRIZZLE_TYPE_NULL:
520
case DRIZZLE_TYPE_TIMESTAMP:
524
case DRIZZLE_TYPE_LONGLONG:
528
case DRIZZLE_TYPE_DATETIME:
532
case DRIZZLE_TYPE_DATE:
536
case DRIZZLE_TYPE_VARCHAR:
540
case DRIZZLE_TYPE_UUID:
544
case DRIZZLE_TYPE_DECIMAL:
548
case DRIZZLE_TYPE_ENUM:
552
case DRIZZLE_TYPE_BLOB:
559
/* Add one to compensate for tinyint removal from enum. */
560
pos[6]= field.type + 1;
563
int2store(pos+7,field.flags);
564
pos[9]= (char) field.decimals;
565
pos[10]= 0; // For the future
566
pos[11]= 0; // For the future
569
packet.length((uint32_t) (pos - packet.ptr()));
575
Mark the end of meta-data result set, and store session->server_status,
576
to show that there is no cursor.
577
Send no warning information, as it will be sent at statement end.
579
writeEOFPacket(session->server_status, session->total_warn_count);
583
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
588
bool ClientMySQLProtocol::store(Field *from)
592
char buff[MAX_FIELD_WIDTH];
593
String str(buff,sizeof(buff), &my_charset_bin);
595
from->val_str_internal(&str);
597
return netStoreData((const unsigned char *)str.ptr(), str.length());
600
bool ClientMySQLProtocol::store(void)
604
return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
607
bool ClientMySQLProtocol::store(int32_t from)
610
return netStoreData((unsigned char*) buff,
611
(size_t) (internal::int10_to_str(from, buff, -10) - buff));
614
bool ClientMySQLProtocol::store(uint32_t from)
617
return netStoreData((unsigned char*) buff,
618
(size_t) (internal::int10_to_str(from, buff, 10) - buff));
621
bool ClientMySQLProtocol::store(int64_t from)
624
return netStoreData((unsigned char*) buff,
625
(size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
628
bool ClientMySQLProtocol::store(uint64_t from)
631
return netStoreData((unsigned char*) buff,
632
(size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
635
bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
637
buffer->set_real(from, decimals, session->charset());
638
return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
641
bool ClientMySQLProtocol::store(const char *from, size_t length)
643
return netStoreData((const unsigned char *)from, length);
646
bool ClientMySQLProtocol::wasAborted(void)
648
return net.error && net.vio != 0;
651
bool ClientMySQLProtocol::haveMoreData(void)
653
return drizzleclient_net_more_data(&net);
656
bool ClientMySQLProtocol::haveError(void)
658
return net.error || net.vio == 0;
661
bool ClientMySQLProtocol::checkConnection(void)
665
char scramble[SCRAMBLE_LENGTH];
667
makeScramble(scramble);
674
if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
676
my_error(ER_BAD_HOST_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
680
session->getSecurityContext().setIp(ip);
682
drizzleclient_net_keepalive(&net, true);
684
uint32_t server_capabilites;
686
/* buff[] needs to big enough to hold the server_version variable */
687
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
689
server_capabilites= CLIENT_BASIC_FLAGS;
691
if (_using_mysql41_protocol)
692
server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
695
server_capabilites|= CLIENT_COMPRESS;
696
#endif /* HAVE_COMPRESS */
698
end= buff + strlen(PANDORA_RELEASE_VERSION);
699
if ((end - buff) >= SERVER_VERSION_LENGTH)
700
end= buff + (SERVER_VERSION_LENGTH - 1);
701
memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
705
int4store((unsigned char*) end, session->variables.pseudo_thread_id);
708
/* We don't use scramble anymore. */
709
memcpy(end, scramble, SCRAMBLE_LENGTH_323);
710
end+= SCRAMBLE_LENGTH_323;
711
*end++= 0; /* an empty byte for some reason */
713
int2store(end, server_capabilites);
714
/* write server characteristics: up to 16 bytes allowed */
715
end[2]=(char) default_charset_info->number;
716
int2store(end+3, session->server_status);
717
memset(end+5, 0, 13);
720
/* Write scramble tail. */
721
memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
722
end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
723
*end++= 0; /* an empty byte for some reason */
725
/* At this point we write connection message and read reply */
726
if (drizzleclient_net_write_command(&net
727
, (unsigned char) PROTOCOL_VERSION
728
, (unsigned char*) ""
730
, (unsigned char*) buff
731
, (size_t) (end-buff))
732
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
733
|| pkt_len < MIN_HANDSHAKE_SIZE)
735
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
739
if (packet.alloc(buffer_length.get()))
740
return false; /* The error is set by alloc(). */
742
client_capabilities= uint2korr(net.read_pos);
743
if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
745
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
749
client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
750
session->max_client_packet_length= uint4korr(net.read_pos + 4);
751
end= (char*) net.read_pos + 32;
754
Disable those bits which are not supported by the server.
755
This is a precautionary measure, if the client lies. See Bug#27944.
757
client_capabilities&= server_capabilites;
759
if (end >= (char*) net.read_pos + pkt_len + 2)
761
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
765
net.return_status= &session->server_status;
768
char *passwd= strchr(user, '\0')+1;
769
uint32_t user_len= passwd - user - 1;
773
Only support new password format.
775
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
776
*passwd > 127 and become 2**32-127+ after casting to uint.
779
if (client_capabilities & CLIENT_SECURE_CONNECTION &&
780
passwd < (char *) net.read_pos + pkt_len)
782
passwd_len= (unsigned char)(*passwd++);
785
session->getSecurityContext().setPasswordType(SecurityContext::MYSQL_HASH);
786
session->getSecurityContext().setPasswordContext(scramble, SCRAMBLE_LENGTH);
792
if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
793
passwd < (char *) net.read_pos + pkt_len)
795
l_db= l_db + passwd_len + 1;
800
/* strlen() can't be easily deleted without changing client */
801
uint32_t db_len= l_db ? strlen(l_db) : 0;
803
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
805
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
809
/* If username starts and ends in "'", chop them off */
810
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
817
if (client_capabilities & CLIENT_ADMIN)
819
if ((strncmp(user, "root", 4) == 0) and isAdminAllowed())
821
is_admin_connection= true;
825
my_error(ER_ADMIN_ACCESS, MYF(0));
830
session->getSecurityContext().setUser(user);
832
return session->checkUser(string(passwd, passwd_len),
833
string(l_db ? l_db : ""));
837
bool ClientMySQLProtocol::isAdminAllowed(void)
839
if (std::find(mysql_admin_ip_addresses.begin(), mysql_admin_ip_addresses.end(), session->getSecurityContext().getIp()) != mysql_admin_ip_addresses.end())
845
bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
847
size_t packet_length= packet.length();
849
The +9 comes from that strings of length longer than 16M require
850
9 bytes to be stored (see storeLength).
852
if (packet_length+9+length > packet.alloced_length() &&
853
packet.realloc(packet_length+9+length))
855
unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
856
memcpy(to,from,length);
857
packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
862
Format EOF packet according to the current client and
863
write it to the network output buffer.
866
void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status,
867
uint32_t total_warn_count)
869
unsigned char buff[5];
871
Don't send warn count during SP execution, as the warn_list
872
is cleared between substatements, and mysqltest gets confused
874
uint32_t tmp= min(total_warn_count, (uint32_t)65535);
875
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
876
int2store(buff+1, tmp);
878
The following test should never be true, but it's better to do it
879
because if 'is_fatal_error' is set the server is not going to execute
880
other queries (see the if test in dispatch_command / COM_QUERY)
882
if (session->is_fatal_error)
883
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
884
int2store(buff + 3, server_status);
885
drizzleclient_net_write(&net, buff, 5);
889
Store an integer with simple packing into a output package
891
buffer Store the packed integer here
892
length integers to store
894
This is mostly used to store lengths of strings. We have to cast
895
the result for the LL() becasue of a bug in Forte CC compiler.
898
Position in 'buffer' after the packed length
901
unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
903
if (length < (uint64_t) 251LL)
905
*buffer=(unsigned char) length;
908
/* 251 is reserved for NULL */
909
if (length < (uint64_t) 65536LL)
912
int2store(buffer,(uint32_t) length);
915
if (length < (uint64_t) 16777216LL)
918
int3store(buffer,(uint32_t) length);
922
int8store(buffer,length);
926
void ClientMySQLProtocol::makeScramble(char *scramble)
928
/* This is the MySQL algorithm with minimal changes. */
929
random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
930
random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
931
uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
934
uint32_t pointer_seed;
935
memcpy(&pointer_seed, &pointer, 4);
936
uint32_t random1= (seed + pointer_seed) % random_max;
937
uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
939
for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
941
random1= (random1 * 3 + random2) % random_max;
942
random2= (random1 + random2 + 33) % random_max;
943
*scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
947
void ClientMySQLProtocol::mysql_compose_ip_addresses(vector<string> options)
949
for (vector<string>::iterator it= options.begin();
953
tokenize(*it, mysql_admin_ip_addresses, ",", true);
957
static ListenMySQLProtocol *listen_obj= NULL;
958
plugin::Create_function<MySQLPassword> *mysql_password= NULL;
960
static int init(drizzled::module::Context &context)
962
context.add(new MysqlProtocolStatus);
964
/* Initialize random seeds for the MySQL algorithm with minimal changes. */
965
time_t seed_time= time(NULL);
966
random_seed1= seed_time % random_max;
967
random_seed2= (seed_time / 2) % random_max;
969
const module::option_map &vm= context.getOptions();
971
mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
972
context.add(mysql_password);
974
listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
975
context.add(listen_obj);
976
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
977
context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
978
context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
979
context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
980
context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
981
context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
982
context.registerVariable(new sys_var_const_string_val("bind_address",
983
vm["bind-address"].as<std::string>()));
985
context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters->max_connections));
990
static void init_options(drizzled::module::option_context &context)
993
po::value<port_constraint>(&port)->default_value(3306),
994
N_("Port number to use for connection or 0 for default to with MySQL "
996
context("connect-timeout",
997
po::value<timeout_constraint>(&connect_timeout)->default_value(10),
998
N_("Connect Timeout."));
999
context("read-timeout",
1000
po::value<timeout_constraint>(&read_timeout)->default_value(30),
1001
N_("Read Timeout."));
1002
context("write-timeout",
1003
po::value<timeout_constraint>(&write_timeout)->default_value(60),
1004
N_("Write Timeout."));
1005
context("retry-count",
1006
po::value<retry_constraint>(&retry_count)->default_value(10),
1007
N_("Retry Count."));
1008
context("buffer-length",
1009
po::value<buffer_constraint>(&buffer_length)->default_value(16384),
1010
N_("Buffer length."));
1011
context("bind-address",
1012
po::value<string>()->default_value(""),
1013
N_("Address to bind to."));
1014
context("max-connections",
1015
po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
1016
N_("Maximum simultaneous connections."));
1017
context("admin-ip-addresses",
1018
po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
1019
N_("A restrictive IP address list for incoming admin connections."));
1022
static int mysql_protocol_connection_count_func(drizzle_show_var *var, char *buff)
1024
var->type= SHOW_LONGLONG;
1026
*((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->connectionCount;
1030
static int mysql_protocol_connected_count_func(drizzle_show_var *var, char *buff)
1032
var->type= SHOW_LONGLONG;
1034
*((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->connected;
1038
static int mysql_protocol_failed_count_func(drizzle_show_var *var, char *buff)
1040
var->type= SHOW_LONGLONG;
1042
*((uint64_t *)buff)= ListenMySQLProtocol::mysql_counters->failedConnections;
1046
static st_show_var_func_container mysql_protocol_connection_count=
1047
{ &mysql_protocol_connection_count_func };
1049
static st_show_var_func_container mysql_protocol_connected_count=
1050
{ &mysql_protocol_connected_count_func };
1052
static st_show_var_func_container mysql_protocol_failed_count=
1053
{ &mysql_protocol_failed_count_func };
1055
static drizzle_show_var mysql_protocol_status_variables[]= {
1057
(char*) &mysql_protocol_connection_count, SHOW_FUNC},
1059
(char*) &mysql_protocol_connected_count, SHOW_FUNC},
1060
{"Failed_connections",
1061
(char*) &mysql_protocol_failed_count, SHOW_FUNC},
1062
{NULL, NULL, SHOW_LONGLONG}
1065
MysqlProtocolStatus::Generator::Generator(drizzled::Field **fields) :
1066
plugin::TableFunction::Generator(fields)
1068
status_var_ptr= mysql_protocol_status_variables;
1071
bool MysqlProtocolStatus::Generator::populate()
1073
MY_ALIGNED_BYTE_ARRAY(buff_data, SHOW_VAR_FUNC_BUFF_SIZE, int64_t);
1074
char * const buff= (char *) &buff_data;
1075
drizzle_show_var tmp;
1077
if (status_var_ptr->name)
1079
std::ostringstream oss;
1080
string return_value;
1084
push(status_var_ptr->name);
1086
if (status_var_ptr->type == SHOW_FUNC)
1088
((drizzle_show_var_func)((st_show_var_func_container *)status_var_ptr->value)->func)(&tmp, buff);
1094
value= status_var_ptr->value;
1095
type= status_var_ptr->type;
1101
oss << *(uint64_t*) value;
1102
return_value= oss.str();
1107
if (return_value.length())
1119
} /* namespace drizzle_plugin */
1121
DRIZZLE_DECLARE_PLUGIN
1127
"MySQL Protocol Module",
1129
drizzle_plugin::init, /* Plugin Init */
1130
NULL, /* system variables */
1131
drizzle_plugin::init_options /* config options */
1133
DRIZZLE_DECLARE_PLUGIN_END;