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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
31
#include "mysql_protocol.h"
32
#include "mysql_password.h"
34
#include "table_function.h"
36
namespace po= boost::program_options;
38
using namespace drizzled;
40
#define PROTOCOL_VERSION 10
42
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
44
static uint32_t connect_timeout;
45
static uint32_t read_timeout;
46
static uint32_t write_timeout;
47
static uint32_t retry_count;
48
static uint32_t buffer_length;
49
static char* bind_address;
50
static uint32_t random_seed1;
51
static uint32_t random_seed2;
52
static const uint32_t random_max= 0x3FFFFFFF;
53
static const double random_max_double= (double)0x3FFFFFFF;
55
static plugin::TableFunction* mysql_status_table_function_ptr= NULL;
57
ListenMySQLProtocol::~ListenMySQLProtocol()
59
/* This is strdup'd from the options */
63
const char* ListenMySQLProtocol::getHost(void) const
68
in_port_t ListenMySQLProtocol::getPort(void) const
70
return (in_port_t) port;
73
plugin::Client *ListenMySQLProtocol::getClient(int fd)
76
new_fd= acceptTcp(fd);
80
return new (nothrow) ClientMySQLProtocol(new_fd, using_mysql41_protocol);
83
drizzled::atomic<uint64_t> ClientMySQLProtocol::connectionCount;
84
drizzled::atomic<uint64_t> ClientMySQLProtocol::failedConnections;
85
drizzled::atomic<uint64_t> ClientMySQLProtocol::connected;
87
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol_arg):
88
using_mysql41_protocol(using_mysql41_protocol_arg)
95
if (drizzleclient_net_init_sock(&net, fd, buffer_length))
98
drizzleclient_net_set_read_timeout(&net, read_timeout);
99
drizzleclient_net_set_write_timeout(&net, write_timeout);
100
net.retry_count=retry_count;
103
ClientMySQLProtocol::~ClientMySQLProtocol()
109
int ClientMySQLProtocol::getFileDescriptor(void)
111
return drizzleclient_net_get_sd(&net);
114
bool ClientMySQLProtocol::isConnected()
119
bool ClientMySQLProtocol::isReading(void)
121
return net.reading_or_writing == 1;
124
bool ClientMySQLProtocol::isWriting(void)
126
return net.reading_or_writing == 2;
129
bool ClientMySQLProtocol::flush()
133
bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
139
void ClientMySQLProtocol::close(void)
143
drizzleclient_net_close(&net);
144
drizzleclient_net_end(&net);
145
connected.decrement();
149
bool ClientMySQLProtocol::authenticate()
151
bool connection_is_valid;
153
connectionCount.increment();
154
connected.increment();
156
/* Use "connect_timeout" value during connection phase */
157
drizzleclient_net_set_read_timeout(&net, connect_timeout);
158
drizzleclient_net_set_write_timeout(&net, connect_timeout);
160
connection_is_valid= checkConnection();
162
if (connection_is_valid)
166
sendError(session->main_da.sql_errno(), session->main_da.message());
167
failedConnections.increment();
170
/* Connect completed, set read/write timeouts back to default */
171
drizzleclient_net_set_read_timeout(&net, read_timeout);
172
drizzleclient_net_set_write_timeout(&net, write_timeout);
176
bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t *packet_length)
179
This thread will do a blocking read from the client which
180
will be interrupted when the next command is received from
181
the client, the connection is closed or "net_wait_timeout"
182
number of seconds has passed
185
/* We can do this much more efficiently with poll timeouts or watcher thread,
186
disabling for now, which means net_wait_timeout == read_timeout. */
187
drizzleclient_net_set_read_timeout(&net,
188
session->variables.net_wait_timeout);
193
*packet_length= drizzleclient_net_read(&net);
194
if (*packet_length == packet_error)
196
/* Check if we can continue without closing the connection */
198
if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
199
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
200
if (session->main_da.status() == Diagnostics_area::DA_ERROR)
201
sendError(session->main_da.sql_errno(), session->main_da.message());
206
return false; // We have to close it.
213
*l_packet= (char*) net.read_pos;
216
'packet_length' contains length of data, as it was stored in packet
217
header. In case of malformed header, drizzleclient_net_read returns zero.
218
If packet_length is not zero, drizzleclient_net_read ensures that the returned
219
number of bytes was actually read from network.
220
There is also an extra safety measure in drizzleclient_net_read:
221
it sets packet[packet_length]= 0, but only for non-zero packets.
224
if (*packet_length == 0) /* safety */
226
/* Initialize with COM_SLEEP packet */
227
(*l_packet)[0]= (unsigned char) COM_SLEEP;
230
else if (using_mysql41_protocol)
232
/* Map from MySQL commands to Drizzle commands. */
233
switch ((int)(*l_packet)[0])
237
case 2: /* INIT_DB */
241
case 8: /* SHUTDOWN */
242
(*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
246
(*l_packet)[0]= (unsigned char) COM_PING;
251
/* Respond with unknown command for MySQL commands we don't support. */
252
(*l_packet)[0]= (unsigned char) COM_END;
258
/* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
259
(*l_packet)[*packet_length]= '\0'; /* safety */
262
/* See comment above. */
263
/* Restore read timeout value */
264
drizzleclient_net_set_read_timeout(&net,
265
session->variables.net_read_timeout);
272
Return ok to the client.
274
The ok packet has the following structure:
276
- 0 : Marker (1 byte)
277
- affected_rows : Stored in 1-9 bytes
278
- id : Stored in 1-9 bytes
279
- server_status : Copy of session->server_status; Can be used by client
280
to check if we are inside an transaction.
282
- warning_count : Stored in 2 bytes; New in 4.1 client
283
- message : Stored as packed length (1-9 bytes) + message.
284
Is not stored if no message.
286
@param session Thread handler
287
@param affected_rows Number of rows changed by statement
288
@param id Auto_increment id for first row (if used)
289
@param message Message to send to the client (Used by mysql_status)
292
void ClientMySQLProtocol::sendOK()
294
unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
295
const char *message= NULL;
298
if (!net.vio) // hack for re-parsing queries
303
buff[0]=0; // No fields
304
if (session->main_da.status() == Diagnostics_area::DA_OK)
306
if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
307
pos=storeLength(buff+1,session->main_da.found_rows());
309
pos=storeLength(buff+1,session->main_da.affected_rows());
310
pos=storeLength(pos, session->main_da.last_insert_id());
311
int2store(pos, session->main_da.server_status());
313
tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
314
message= session->main_da.message();
318
pos=storeLength(buff+1,0);
319
pos=storeLength(pos, 0);
320
int2store(pos, session->server_status);
322
tmp= min(session->total_warn_count, (uint32_t)65535);
325
/* We can only return up to 65535 warnings in two bytes */
329
session->main_da.can_overwrite_status= true;
331
if (message && message[0])
333
size_t length= strlen(message);
334
pos=storeLength(pos,length);
335
memcpy(pos,(unsigned char*) message,length);
338
drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
339
drizzleclient_net_flush(&net);
341
session->main_da.can_overwrite_status= false;
345
Send eof (= end of result set) to the client.
347
The eof packet has the following structure:
349
- 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
350
- warning_count : Stored in 2 bytes; New in 4.1 client
351
- status_flag : Stored in 2 bytes;
352
For flags like SERVER_MORE_RESULTS_EXISTS.
354
Note that the warning count will not be sent if 'no_flush' is set as
355
we don't want to report the warning count until all data is sent to the
359
void ClientMySQLProtocol::sendEOF()
361
/* Set to true if no active vio, to work well in case of --init-file */
364
session->main_da.can_overwrite_status= true;
365
writeEOFPacket(session->main_da.server_status(),
366
session->main_da.total_warn_count());
367
drizzleclient_net_flush(&net);
368
session->main_da.can_overwrite_status= false;
370
packet.shrink(buffer_length);
374
void ClientMySQLProtocol::sendError(uint32_t sql_errno, const char *err)
378
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
380
unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
383
assert(err && err[0]);
386
It's one case when we can push an error even though there
387
is an OK or EOF already.
389
session->main_da.can_overwrite_status= true;
391
/* Abort multi-result sets */
392
session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
395
Send a error string to client.
397
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
398
critical that every error that can be intercepted is issued in one
399
place only, my_message_sql.
407
int2store(buff,sql_errno);
410
/* The first # is to make the client backward compatible */
412
pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
413
pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
415
char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
416
tmp+= strlen((char*)pos);
418
length= (uint32_t)(tmp-(char*)buff);
421
drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
423
session->main_da.can_overwrite_status= false;
427
Send name and type of result to client.
429
Sum fields has table name empty and field_name.
431
@param Session Thread data object
432
@param list List of items to send to client
433
@param flag Bit mask with the following functions:
434
- 1 send number of rows
435
- 2 send default values
436
- 4 don't write eof packet
441
1 Error (Note that in this case the error is not sent to the
444
bool ClientMySQLProtocol::sendFields(List<Item> *list)
446
List_iterator_fast<Item> it(*list);
448
unsigned char buff[80];
449
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
451
unsigned char *row_pos= storeLength(buff, list->elements);
452
(void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
458
item->make_field(&field);
462
if (store(STRING_WITH_LEN("def")) ||
463
store(field.db_name) ||
464
store(field.table_name) ||
465
store(field.org_table_name) ||
466
store(field.col_name) ||
467
store(field.org_col_name) ||
468
packet.realloc(packet.length()+12))
471
/* Store fixed length fields */
472
pos= (char*) packet.ptr()+packet.length();
473
*pos++= 12; // Length of packed fields
475
int2store(pos, field.charsetnr);
476
int4store(pos+2, field.length);
478
if (using_mysql41_protocol)
480
/* Switch to MySQL field numbering. */
483
case DRIZZLE_TYPE_LONG:
487
case DRIZZLE_TYPE_DOUBLE:
491
case DRIZZLE_TYPE_NULL:
495
case DRIZZLE_TYPE_TIMESTAMP:
499
case DRIZZLE_TYPE_LONGLONG:
503
case DRIZZLE_TYPE_DATETIME:
507
case DRIZZLE_TYPE_DATE:
511
case DRIZZLE_TYPE_VARCHAR:
515
case DRIZZLE_TYPE_DECIMAL:
519
case DRIZZLE_TYPE_ENUM:
523
case DRIZZLE_TYPE_BLOB:
530
/* Add one to compensate for tinyint removal from enum. */
531
pos[6]= field.type + 1;
534
int2store(pos+7,field.flags);
535
pos[9]= (char) field.decimals;
536
pos[10]= 0; // For the future
537
pos[11]= 0; // For the future
540
packet.length((uint32_t) (pos - packet.ptr()));
546
Mark the end of meta-data result set, and store session->server_status,
547
to show that there is no cursor.
548
Send no warning information, as it will be sent at statement end.
550
writeEOFPacket(session->server_status, session->total_warn_count);
554
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
559
bool ClientMySQLProtocol::store(Field *from)
563
char buff[MAX_FIELD_WIDTH];
564
String str(buff,sizeof(buff), &my_charset_bin);
568
return netStoreData((const unsigned char *)str.ptr(), str.length());
571
bool ClientMySQLProtocol::store(void)
575
return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
578
bool ClientMySQLProtocol::store(int32_t from)
581
return netStoreData((unsigned char*) buff,
582
(size_t) (internal::int10_to_str(from, buff, -10) - buff));
585
bool ClientMySQLProtocol::store(uint32_t from)
588
return netStoreData((unsigned char*) buff,
589
(size_t) (internal::int10_to_str(from, buff, 10) - buff));
592
bool ClientMySQLProtocol::store(int64_t from)
595
return netStoreData((unsigned char*) buff,
596
(size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
599
bool ClientMySQLProtocol::store(uint64_t from)
602
return netStoreData((unsigned char*) buff,
603
(size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
606
bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
608
buffer->set_real(from, decimals, session->charset());
609
return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
612
bool ClientMySQLProtocol::store(const char *from, size_t length)
614
return netStoreData((const unsigned char *)from, length);
617
bool ClientMySQLProtocol::wasAborted(void)
619
return net.error && net.vio != 0;
622
bool ClientMySQLProtocol::haveMoreData(void)
624
return drizzleclient_net_more_data(&net);
627
bool ClientMySQLProtocol::haveError(void)
629
return net.error || net.vio == 0;
632
bool ClientMySQLProtocol::checkConnection(void)
636
char scramble[SCRAMBLE_LENGTH];
638
makeScramble(scramble);
645
if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
647
my_error(ER_BAD_HOST_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
651
session->getSecurityContext().setIp(ip);
653
drizzleclient_net_keepalive(&net, true);
655
uint32_t server_capabilites;
657
/* buff[] needs to big enough to hold the server_version variable */
658
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
660
server_capabilites= CLIENT_BASIC_FLAGS;
662
if (using_mysql41_protocol)
663
server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
666
server_capabilites|= CLIENT_COMPRESS;
667
#endif /* HAVE_COMPRESS */
669
end= buff + strlen(PANDORA_RELEASE_VERSION);
670
if ((end - buff) >= SERVER_VERSION_LENGTH)
671
end= buff + (SERVER_VERSION_LENGTH - 1);
672
memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
676
int4store((unsigned char*) end, session->variables.pseudo_thread_id);
679
/* We don't use scramble anymore. */
680
memcpy(end, scramble, SCRAMBLE_LENGTH_323);
681
end+= SCRAMBLE_LENGTH_323;
682
*end++= 0; /* an empty byte for some reason */
684
int2store(end, server_capabilites);
685
/* write server characteristics: up to 16 bytes allowed */
686
end[2]=(char) default_charset_info->number;
687
int2store(end+3, session->server_status);
688
memset(end+5, 0, 13);
691
/* Write scramble tail. */
692
memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
693
end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
694
*end++= 0; /* an empty byte for some reason */
696
/* At this point we write connection message and read reply */
697
if (drizzleclient_net_write_command(&net
698
, (unsigned char) PROTOCOL_VERSION
699
, (unsigned char*) ""
701
, (unsigned char*) buff
702
, (size_t) (end-buff))
703
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
704
|| pkt_len < MIN_HANDSHAKE_SIZE)
706
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
710
if (packet.alloc(buffer_length))
711
return false; /* The error is set by alloc(). */
713
client_capabilities= uint2korr(net.read_pos);
714
if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
716
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
720
client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
721
session->max_client_packet_length= uint4korr(net.read_pos + 4);
722
end= (char*) net.read_pos + 32;
725
Disable those bits which are not supported by the server.
726
This is a precautionary measure, if the client lies. See Bug#27944.
728
client_capabilities&= server_capabilites;
730
if (end >= (char*) net.read_pos + pkt_len + 2)
732
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
736
net.return_status= &session->server_status;
739
char *passwd= strchr(user, '\0')+1;
740
uint32_t user_len= passwd - user - 1;
744
Only support new password format.
746
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
747
*passwd > 127 and become 2**32-127+ after casting to uint.
750
if (client_capabilities & CLIENT_SECURE_CONNECTION &&
751
passwd < (char *) net.read_pos + pkt_len)
753
passwd_len= (unsigned char)(*passwd++);
756
session->getSecurityContext().setPasswordType(SecurityContext::MYSQL_HASH);
757
session->getSecurityContext().setPasswordContext(scramble, SCRAMBLE_LENGTH);
763
if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
764
passwd < (char *) net.read_pos + pkt_len)
766
l_db= l_db + passwd_len + 1;
771
/* strlen() can't be easily deleted without changing client */
772
uint32_t db_len= l_db ? strlen(l_db) : 0;
774
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
776
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
780
/* If username starts and ends in "'", chop them off */
781
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
788
session->getSecurityContext().setUser(user);
790
return session->checkUser(passwd, passwd_len, l_db);
793
bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
795
size_t packet_length= packet.length();
797
The +9 comes from that strings of length longer than 16M require
798
9 bytes to be stored (see storeLength).
800
if (packet_length+9+length > packet.alloced_length() &&
801
packet.realloc(packet_length+9+length))
803
unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
804
memcpy(to,from,length);
805
packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
810
Format EOF packet according to the current client and
811
write it to the network output buffer.
814
void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status,
815
uint32_t total_warn_count)
817
unsigned char buff[5];
819
Don't send warn count during SP execution, as the warn_list
820
is cleared between substatements, and mysqltest gets confused
822
uint32_t tmp= min(total_warn_count, (uint32_t)65535);
823
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
824
int2store(buff+1, tmp);
826
The following test should never be true, but it's better to do it
827
because if 'is_fatal_error' is set the server is not going to execute
828
other queries (see the if test in dispatch_command / COM_QUERY)
830
if (session->is_fatal_error)
831
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
832
int2store(buff + 3, server_status);
833
drizzleclient_net_write(&net, buff, 5);
837
Store an integer with simple packing into a output package
839
buffer Store the packed integer here
840
length integers to store
842
This is mostly used to store lengths of strings. We have to cast
843
the result for the LL() becasue of a bug in Forte CC compiler.
846
Position in 'buffer' after the packed length
849
unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
851
if (length < (uint64_t) 251LL)
853
*buffer=(unsigned char) length;
856
/* 251 is reserved for NULL */
857
if (length < (uint64_t) 65536LL)
860
int2store(buffer,(uint32_t) length);
863
if (length < (uint64_t) 16777216LL)
866
int3store(buffer,(uint32_t) length);
870
int8store(buffer,length);
874
void ClientMySQLProtocol::makeScramble(char *scramble)
876
/* This is the MySQL algorithm with minimal changes. */
877
random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
878
random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
879
uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
882
uint32_t pointer_seed;
883
memcpy(&pointer_seed, &pointer, 4);
884
uint32_t random1= (seed + pointer_seed) % random_max;
885
uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->sd) % random_max;
887
for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
889
random1= (random1 * 3 + random2) % random_max;
890
random2= (random1 + random2 + 33) % random_max;
891
*scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
895
static ListenMySQLProtocol *listen_obj= NULL;
896
plugin::Create_function<MySQLPassword> *mysql_password= NULL;
898
static int init(drizzled::module::Context &context)
900
mysql_status_table_function_ptr= new MysqlProtocolStatus;
902
context.add(mysql_status_table_function_ptr);
903
/* Initialize random seeds for the MySQL algorithm with minimal changes. */
904
time_t seed_time= time(NULL);
905
random_seed1= seed_time % random_max;
906
random_seed2= (seed_time / 2) % random_max;
908
const module::option_map &vm= context.getOptions();
909
if (vm.count("port"))
913
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of port\n"));
918
if (vm.count("connect-timeout"))
920
if (connect_timeout < 1 || connect_timeout > 300)
922
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for connect_timeout\n"));
927
if (vm.count("read-timeout"))
929
if (read_timeout < 1 || read_timeout > 300)
931
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for read_timeout\n"));
936
if (vm.count("write-timeout"))
938
if (write_timeout < 1 || write_timeout > 300)
940
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for write_timeout\n"));
945
if (vm.count("retry-count"))
947
if (retry_count < 1 || retry_count > 100)
949
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for retry_count"));
954
if (vm.count("buffer-length"))
956
if (buffer_length < 1024 || buffer_length > 1024*1024)
958
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for buffer_length\n"));
963
if (vm.count("bind-address"))
965
bind_address= strdup(vm["bind-address"].as<string>().c_str());
973
mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
974
context.add(mysql_password);
976
listen_obj= new ListenMySQLProtocol("mysql_protocol", true);
977
context.add(listen_obj);
982
static DRIZZLE_SYSVAR_UINT(port, port, PLUGIN_VAR_RQCMDARG,
983
N_("Port number to use for connection or 0 for default to with MySQL "
985
NULL, NULL, 3306, 0, 65535, 0);
986
static DRIZZLE_SYSVAR_UINT(connect_timeout, connect_timeout,
987
PLUGIN_VAR_RQCMDARG, N_("Connect Timeout."),
988
NULL, NULL, 10, 1, 300, 0);
989
static DRIZZLE_SYSVAR_UINT(read_timeout, read_timeout, PLUGIN_VAR_RQCMDARG,
990
N_("Read Timeout."), NULL, NULL, 30, 1, 300, 0);
991
static DRIZZLE_SYSVAR_UINT(write_timeout, write_timeout, PLUGIN_VAR_RQCMDARG,
992
N_("Write Timeout."), NULL, NULL, 60, 1, 300, 0);
993
static DRIZZLE_SYSVAR_UINT(retry_count, retry_count, PLUGIN_VAR_RQCMDARG,
994
N_("Retry Count."), NULL, NULL, 10, 1, 100, 0);
995
static DRIZZLE_SYSVAR_UINT(buffer_length, buffer_length, PLUGIN_VAR_RQCMDARG,
996
N_("Buffer length."), NULL, NULL, 16384, 1024,
998
static DRIZZLE_SYSVAR_STR(bind_address, bind_address, PLUGIN_VAR_READONLY,
999
N_("Address to bind to."), NULL, NULL, NULL);
1001
static void init_options(drizzled::module::option_context &context)
1004
po::value<uint32_t>(&port)->default_value(3306),
1005
N_("Port number to use for connection or 0 for default to with MySQL "
1007
context("connect-timeout",
1008
po::value<uint32_t>(&connect_timeout)->default_value(10),
1009
N_("Connect Timeout."));
1010
context("read-timeout",
1011
po::value<uint32_t>(&read_timeout)->default_value(30),
1012
N_("Read Timeout."));
1013
context("write-timeout",
1014
po::value<uint32_t>(&write_timeout)->default_value(60),
1015
N_("Write Timeout."));
1016
context("retry-count",
1017
po::value<uint32_t>(&retry_count)->default_value(10),
1018
N_("Retry Count."));
1019
context("buffer-length",
1020
po::value<uint32_t>(&buffer_length)->default_value(16384),
1021
N_("Buffer length."));
1022
context("bind-address",
1023
po::value<string>(),
1024
N_("Address to bind to."));
1027
static drizzle_sys_var* sys_variables[]= {
1028
DRIZZLE_SYSVAR(port),
1029
DRIZZLE_SYSVAR(connect_timeout),
1030
DRIZZLE_SYSVAR(read_timeout),
1031
DRIZZLE_SYSVAR(write_timeout),
1032
DRIZZLE_SYSVAR(retry_count),
1033
DRIZZLE_SYSVAR(buffer_length),
1034
DRIZZLE_SYSVAR(bind_address),
1038
static int mysql_protocol_connection_count_func(drizzle_show_var *var, char *buff)
1040
var->type= SHOW_LONGLONG;
1042
*((uint64_t *)buff)= ClientMySQLProtocol::connectionCount;
1046
static int mysql_protocol_connected_count_func(drizzle_show_var *var, char *buff)
1048
var->type= SHOW_LONGLONG;
1050
*((uint64_t *)buff)= ClientMySQLProtocol::connected;
1054
static int mysql_protocol_failed_count_func(drizzle_show_var *var, char *buff)
1056
var->type= SHOW_LONGLONG;
1058
*((uint64_t *)buff)= ClientMySQLProtocol::failedConnections;
1062
static st_show_var_func_container mysql_protocol_connection_count=
1063
{ &mysql_protocol_connection_count_func };
1065
static st_show_var_func_container mysql_protocol_connected_count=
1066
{ &mysql_protocol_connected_count_func };
1068
static st_show_var_func_container mysql_protocol_failed_count=
1069
{ &mysql_protocol_failed_count_func };
1071
static drizzle_show_var mysql_protocol_status_variables[]= {
1073
(char*) &mysql_protocol_connection_count, SHOW_FUNC},
1075
(char*) &mysql_protocol_connected_count, SHOW_FUNC},
1076
{"Failed_connections",
1077
(char*) &mysql_protocol_failed_count, SHOW_FUNC},
1078
{NULL, NULL, SHOW_LONGLONG}
1081
MysqlProtocolStatus::Generator::Generator(drizzled::Field **fields) :
1082
plugin::TableFunction::Generator(fields)
1084
status_var_ptr= mysql_protocol_status_variables;
1087
bool MysqlProtocolStatus::Generator::populate()
1089
MY_ALIGNED_BYTE_ARRAY(buff_data, SHOW_VAR_FUNC_BUFF_SIZE, int64_t);
1090
char * const buff= (char *) &buff_data;
1091
drizzle_show_var tmp;
1093
if (status_var_ptr->name)
1095
std::ostringstream oss;
1096
string return_value;
1100
push(status_var_ptr->name);
1102
if (status_var_ptr->type == SHOW_FUNC)
1104
((mysql_show_var_func)((st_show_var_func_container *)status_var_ptr->value)->func)(&tmp, buff);
1110
value= status_var_ptr->value;
1111
type= status_var_ptr->type;
1117
oss << *(uint64_t*) value;
1118
return_value= oss.str();
1123
if (return_value.length())
1135
DRIZZLE_DECLARE_PLUGIN
1141
"MySQL Protocol Module",
1143
init, /* Plugin Init */
1144
sys_variables, /* system variables */
1145
init_options /* config options */
1147
DRIZZLE_DECLARE_PLUGIN_END;