91
return new ClientDrizzleProtocol(new_fd, getCounters());
94
static int init(drizzled::module::Context &context)
96
const module::option_map &vm= context.getOptions();
98
ListenDrizzleProtocol *protocol=new ListenDrizzleProtocol("drizzle_protocol", vm["bind-address"].as<std::string>(), true);
99
protocol->addCountersToTable();
100
context.add(protocol);
101
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
102
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("connect_timeout", connect_timeout));
103
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_timeout", read_timeout));
104
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_timeout", write_timeout));
105
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("retry_count", retry_count));
106
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("buffer_length", buffer_length));
107
context.registerVariable(new sys_var_const_string_val("bind_address",
108
vm["bind-address"].as<std::string>()));
110
context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenDrizzleProtocol::drizzle_counters->max_connections));
116
static void init_options(drizzled::module::option_context &context)
119
po::value<port_constraint>(&port)->default_value(DRIZZLE_TCP_PORT),
120
N_("Port number to use for connection or 0 for default to with Drizzle/MySQL protocol."));
121
context("connect-timeout",
122
po::value<timeout_constraint>(&connect_timeout)->default_value(10),
123
N_("Connect Timeout."));
124
context("read-timeout",
125
po::value<timeout_constraint>(&read_timeout)->default_value(30),
126
N_("Read Timeout."));
127
context("write-timeout",
128
po::value<timeout_constraint>(&write_timeout)->default_value(60),
129
N_("Write Timeout."));
130
context("retry-count",
131
po::value<retry_constraint>(&retry_count)->default_value(10),
133
context("buffer-length",
134
po::value<buffer_constraint>(&buffer_length)->default_value(16384),
135
N_("Buffer length."));
136
context("bind-address",
137
po::value<std::string>()->default_value(""),
138
N_("Address to bind to."));
139
context("max-connections",
140
po::value<uint32_t>(&ListenDrizzleProtocol::drizzle_counters->max_connections)->default_value(1000),
141
N_("Maximum simultaneous connections."));
142
context("admin-ip-addresses",
143
po::value<vector<string> >()->composing()->notifier(&ClientDrizzleProtocol::drizzle_compose_ip_addresses),
144
N_("A restrictive IP address list for incoming admin connections."));
88
return new (nothrow) ClientDrizzleProtocol(new_fd, using_mysql41_protocol);
91
ClientDrizzleProtocol::ClientDrizzleProtocol(int fd, bool using_mysql41_protocol_arg):
92
using_mysql41_protocol(using_mysql41_protocol_arg)
99
if (drizzleclient_net_init_sock(&net, fd, 0, buffer_length))
102
drizzleclient_net_set_read_timeout(&net, read_timeout);
103
drizzleclient_net_set_write_timeout(&net, write_timeout);
104
net.retry_count=retry_count;
107
ClientDrizzleProtocol::~ClientDrizzleProtocol()
110
drizzleclient_vio_close(net.vio);
113
int ClientDrizzleProtocol::getFileDescriptor(void)
115
return drizzleclient_net_get_sd(&net);
118
bool ClientDrizzleProtocol::isConnected()
123
bool ClientDrizzleProtocol::isReading(void)
125
return net.reading_or_writing == 1;
128
bool ClientDrizzleProtocol::isWriting(void)
130
return net.reading_or_writing == 2;
133
bool ClientDrizzleProtocol::flush()
137
bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
143
void ClientDrizzleProtocol::close(void)
147
drizzleclient_net_close(&net);
148
drizzleclient_net_end(&net);
152
bool ClientDrizzleProtocol::authenticate()
154
bool connection_is_valid;
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());
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 ClientDrizzleProtocol::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== CR_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_SHUTDOWN;
251
/* Just drop connection for MySQL commands we don't support. */
252
(*l_packet)[0]= (unsigned char) COM_QUIT;
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 ClientDrizzleProtocol::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=drizzleclient_net_store_length(buff+1,session->main_da.found_rows());
309
pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
310
pos=drizzleclient_net_store_length(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=drizzleclient_net_store_length(buff+1,0);
319
pos=drizzleclient_net_store_length(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=drizzleclient_net_store_length(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 ClientDrizzleProtocol::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 ClientDrizzleProtocol::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 ClientDrizzleProtocol::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= drizzleclient_net_store_length(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 ClientDrizzleProtocol::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 ClientDrizzleProtocol::store(void)
575
return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
578
bool ClientDrizzleProtocol::store(int32_t from)
581
return netStoreData((unsigned char*) buff,
582
(size_t) (internal::int10_to_str(from, buff, -10) - buff));
585
bool ClientDrizzleProtocol::store(uint32_t from)
588
return netStoreData((unsigned char*) buff,
589
(size_t) (internal::int10_to_str(from, buff, 10) - buff));
592
bool ClientDrizzleProtocol::store(int64_t from)
595
return netStoreData((unsigned char*) buff,
596
(size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
599
bool ClientDrizzleProtocol::store(uint64_t from)
602
return netStoreData((unsigned char*) buff,
603
(size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
606
bool ClientDrizzleProtocol::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 ClientDrizzleProtocol::store(const char *from, size_t length)
614
return netStoreData((const unsigned char *)from, length);
617
bool ClientDrizzleProtocol::wasAborted(void)
619
return net.error && net.vio != 0;
622
bool ClientDrizzleProtocol::haveMoreData(void)
624
return drizzleclient_net_more_data(&net);
627
bool ClientDrizzleProtocol::haveError(void)
629
return net.error || net.vio == 0;
632
bool ClientDrizzleProtocol::checkConnection(void)
642
if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
644
my_error(ER_BAD_HOST_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
648
session->getSecurityContext().setIp(ip);
650
drizzleclient_net_keepalive(&net, true);
652
uint32_t server_capabilites;
654
/* buff[] needs to big enough to hold the server_version variable */
655
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
657
server_capabilites= CLIENT_BASIC_FLAGS;
659
if (using_mysql41_protocol)
660
server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
663
server_capabilites|= CLIENT_COMPRESS;
664
#endif /* HAVE_COMPRESS */
666
end= buff + strlen(PANDORA_RELEASE_VERSION);
667
if ((end - buff) >= SERVER_VERSION_LENGTH)
668
end= buff + (SERVER_VERSION_LENGTH - 1);
669
memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
673
int4store((unsigned char*) end, global_thread_id);
676
/* We don't use scramble anymore. */
677
memset(end, 'X', SCRAMBLE_LENGTH_323);
678
end+= SCRAMBLE_LENGTH_323;
679
*end++= 0; /* an empty byte for some reason */
681
int2store(end, server_capabilites);
682
/* write server characteristics: up to 16 bytes allowed */
683
end[2]=(char) default_charset_info->number;
684
int2store(end+3, session->server_status);
685
memset(end+5, 0, 13);
688
/* Write scramble tail. */
689
memset(end, 'X', SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
690
end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
691
*end++= 0; /* an empty byte for some reason */
693
/* At this point we write connection message and read reply */
694
if (drizzleclient_net_write_command(&net
695
, (unsigned char) PROTOCOL_VERSION
696
, (unsigned char*) ""
698
, (unsigned char*) buff
699
, (size_t) (end-buff))
700
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
701
|| pkt_len < MIN_HANDSHAKE_SIZE)
703
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
707
if (packet.alloc(buffer_length))
708
return false; /* The error is set by alloc(). */
710
client_capabilities= uint2korr(net.read_pos);
713
client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
714
session->max_client_packet_length= uint4korr(net.read_pos + 4);
715
end= (char*) net.read_pos + 32;
718
Disable those bits which are not supported by the server.
719
This is a precautionary measure, if the client lies. See Bug#27944.
721
client_capabilities&= server_capabilites;
723
if (end >= (char*) net.read_pos + pkt_len + 2)
725
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
729
net.return_status= &session->server_status;
732
char *passwd= strchr(user, '\0')+1;
733
uint32_t user_len= passwd - user - 1;
737
Old clients send null-terminated string as password; new clients send
738
the size (1 byte) + string (not null-terminated). Hence in case of empty
739
password both send '\0'.
741
This strlen() can't be easily deleted without changing client.
743
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
744
*passwd > 127 and become 2**32-127+ after casting to uint.
746
uint32_t passwd_len= client_capabilities & CLIENT_SECURE_CONNECTION ?
747
(unsigned char)(*passwd++) : strlen(passwd);
748
l_db= client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
750
/* strlen() can't be easily deleted without changing client */
751
uint32_t db_len= l_db ? strlen(l_db) : 0;
753
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
755
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->getSecurityContext().getIp().c_str());
759
/* If username starts and ends in "'", chop them off */
760
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
767
session->getSecurityContext().setUser(user);
769
return session->checkUser(passwd, passwd_len, l_db);
772
bool ClientDrizzleProtocol::netStoreData(const unsigned char *from, size_t length)
774
size_t packet_length= packet.length();
776
The +9 comes from that strings of length longer than 16M require
777
9 bytes to be stored (see drizzleclient_net_store_length).
779
if (packet_length+9+length > packet.alloced_length() &&
780
packet.realloc(packet_length+9+length))
782
unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet.ptr()+packet_length, length);
783
memcpy(to,from,length);
784
packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
789
Format EOF packet according to the current client and
790
write it to the network output buffer.
793
void ClientDrizzleProtocol::writeEOFPacket(uint32_t server_status,
794
uint32_t total_warn_count)
796
unsigned char buff[5];
798
Don't send warn count during SP execution, as the warn_list
799
is cleared between substatements, and mysqltest gets confused
801
uint32_t tmp= min(total_warn_count, (uint32_t)65535);
802
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
803
int2store(buff+1, tmp);
805
The following test should never be true, but it's better to do it
806
because if 'is_fatal_error' is set the server is not going to execute
807
other queries (see the if test in dispatch_command / COM_QUERY)
809
if (session->is_fatal_error)
810
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
811
int2store(buff + 3, server_status);
812
drizzleclient_net_write(&net, buff, 5);
815
static ListenDrizzleProtocol *listen_obj= NULL;
817
static int init(module::Context &context)
819
listen_obj= new ListenDrizzleProtocol("drizzle_protocol", false);
820
context.add(listen_obj);
824
static DRIZZLE_SYSVAR_UINT(port, port, PLUGIN_VAR_RQCMDARG,
825
N_("Port number to use for connection or 0 for "
826
"default to, in order of "
827
"preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
828
"built-in default (4427)."),
829
NULL, NULL, 0, 0, 65535, 0);
830
static DRIZZLE_SYSVAR_UINT(connect_timeout, connect_timeout,
831
PLUGIN_VAR_RQCMDARG, N_("Connect Timeout."),
832
NULL, NULL, 10, 1, 300, 0);
833
static DRIZZLE_SYSVAR_UINT(read_timeout, read_timeout, PLUGIN_VAR_RQCMDARG,
834
N_("Read Timeout."), NULL, NULL, 30, 1, 300, 0);
835
static DRIZZLE_SYSVAR_UINT(write_timeout, write_timeout, PLUGIN_VAR_RQCMDARG,
836
N_("Write Timeout."), NULL, NULL, 60, 1, 300, 0);
837
static DRIZZLE_SYSVAR_UINT(retry_count, retry_count, PLUGIN_VAR_RQCMDARG,
838
N_("Retry Count."), NULL, NULL, 10, 1, 100, 0);
839
static DRIZZLE_SYSVAR_UINT(buffer_length, buffer_length, PLUGIN_VAR_RQCMDARG,
840
N_("Buffer length."), NULL, NULL, 16384, 1024,
842
static DRIZZLE_SYSVAR_STR(bind_address, bind_address, PLUGIN_VAR_READONLY,
843
N_("Address to bind to."), NULL, NULL, NULL);
845
static drizzle_sys_var* sys_variables[]= {
846
DRIZZLE_SYSVAR(port),
847
DRIZZLE_SYSVAR(connect_timeout),
848
DRIZZLE_SYSVAR(read_timeout),
849
DRIZZLE_SYSVAR(write_timeout),
850
DRIZZLE_SYSVAR(retry_count),
851
DRIZZLE_SYSVAR(buffer_length),
852
DRIZZLE_SYSVAR(bind_address),
147
856
} /* namespace drizzle_protocol */
148
} /* namespace drizzle_plugin */
150
DRIZZLE_PLUGIN(drizzle_plugin::drizzle_protocol::init, NULL, drizzle_plugin::drizzle_protocol::init_options);
858
DRIZZLE_PLUGIN(drizzle_protocol::init, drizzle_protocol::sys_variables);