1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Brian Aker
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; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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
23
#include <drizzled/gettext.h>
23
Low level functions for storing data to be send to the MySQL client.
24
The actual communction is handled by the net_xxx functions in net_serv.cc
27
#include <drizzled/server_includes.h>
24
28
#include <drizzled/error.h>
25
#include <drizzled/query_id.h>
26
29
#include <drizzled/sql_state.h>
30
#include <drizzled/protocol.h>
27
31
#include <drizzled/session.h>
28
#include "drizzled/internal/my_sys.h"
29
#include "drizzled/internal/m_string.h"
32
#include <boost/program_options.hpp>
33
#include <drizzled/module/option_map.h>
34
#include "drizzled/util/tokenize.h"
35
#include "drizzle_protocol.h"
36
#include "plugin/drizzle_protocol/status_table.h"
38
namespace po= boost::program_options;
39
using namespace drizzled;
42
namespace drizzle_plugin
44
namespace drizzle_protocol
47
std::vector<std::string> ClientDrizzleProtocol::drizzle_admin_ip_addresses;
48
static port_constraint port;
49
static timeout_constraint connect_timeout;
50
static timeout_constraint read_timeout;
51
static timeout_constraint write_timeout;
52
static retry_constraint retry_count;
53
static buffer_constraint buffer_length;
55
static const uint32_t DRIZZLE_TCP_PORT= 4427;
57
ProtocolCounters *ListenDrizzleProtocol::drizzle_counters= new ProtocolCounters();
59
ListenDrizzleProtocol::~ListenDrizzleProtocol()
63
in_port_t ListenDrizzleProtocol::getPort(void) const
68
void ClientDrizzleProtocol::drizzle_compose_ip_addresses(vector<string> options)
70
for (vector<string>::iterator it= options.begin();
74
tokenize(*it, drizzle_admin_ip_addresses, ",", true);
78
bool ClientDrizzleProtocol::isAdminAllowed(void)
80
if (std::find(drizzle_admin_ip_addresses.begin(), drizzle_admin_ip_addresses.end(), session->getSecurityContext().getIp()) != drizzle_admin_ip_addresses.end())
86
plugin::Client *ListenDrizzleProtocol::getClient(int fd)
89
new_fd= acceptTcp(fd);
93
return new ClientDrizzleProtocol(new_fd, getCounters());
96
static int init(drizzled::module::Context &context)
98
const module::option_map &vm= context.getOptions();
100
context.add(new StatusTable);
101
context.add(new ListenDrizzleProtocol("drizzle_protocol", vm["bind-address"].as<std::string>(), true));
102
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
103
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("connect_timeout", connect_timeout));
104
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_timeout", read_timeout));
105
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_timeout", write_timeout));
106
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("retry_count", retry_count));
107
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("buffer_length", buffer_length));
108
context.registerVariable(new sys_var_const_string_val("bind_address",
109
vm["bind-address"].as<std::string>()));
111
context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenDrizzleProtocol::drizzle_counters->max_connections));
117
static void init_options(drizzled::module::option_context &context)
120
po::value<port_constraint>(&port)->default_value(DRIZZLE_TCP_PORT),
121
N_("Port number to use for connection or 0 for default to with Drizzle/MySQL protocol."));
122
context("connect-timeout",
123
po::value<timeout_constraint>(&connect_timeout)->default_value(10),
124
N_("Connect Timeout."));
125
context("read-timeout",
126
po::value<timeout_constraint>(&read_timeout)->default_value(30),
127
N_("Read Timeout."));
128
context("write-timeout",
129
po::value<timeout_constraint>(&write_timeout)->default_value(60),
130
N_("Write Timeout."));
131
context("retry-count",
132
po::value<retry_constraint>(&retry_count)->default_value(10),
134
context("buffer-length",
135
po::value<buffer_constraint>(&buffer_length)->default_value(16384),
136
N_("Buffer length."));
137
context("bind-address",
138
po::value<std::string>()->default_value(""),
139
N_("Address to bind to."));
140
context("max-connections",
141
po::value<uint32_t>(&ListenDrizzleProtocol::drizzle_counters->max_connections)->default_value(1000),
142
N_("Maximum simultaneous connections."));
143
context("admin-ip-addresses",
144
po::value<vector<string> >()->composing()->notifier(&ClientDrizzleProtocol::drizzle_compose_ip_addresses),
145
N_("A restrictive IP address list for incoming admin connections."));
148
} /* namespace drizzle_protocol */
149
} /* namespace drizzle_plugin */
151
DRIZZLE_PLUGIN(drizzle_plugin::drizzle_protocol::init, NULL, drizzle_plugin::drizzle_protocol::init_options);
32
#include <drizzled/data_home.h>
35
#include "oldlibdrizzle.h"
38
Function called by drizzleclient_net_init() to set some check variables
41
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
43
static void write_eof_packet(Session *session, NET *net,
44
uint32_t server_status, uint32_t total_warn_count);
46
bool ProtocolOldLibdrizzle::isConnected()
51
void ProtocolOldLibdrizzle::setReadTimeout(uint32_t timeout)
53
drizzleclient_net_set_read_timeout(&net, timeout);
56
void ProtocolOldLibdrizzle::setWriteTimeout(uint32_t timeout)
58
drizzleclient_net_set_write_timeout(&net, timeout);
61
void ProtocolOldLibdrizzle::setRetryCount(uint32_t count)
63
net.retry_count=count;
66
void ProtocolOldLibdrizzle::setError(char error)
71
bool ProtocolOldLibdrizzle::haveError(void)
73
return net.error || net.vio == 0;
76
bool ProtocolOldLibdrizzle::wasAborted(void)
78
return net.error && net.vio != 0;
81
bool ProtocolOldLibdrizzle::haveMoreData(void)
83
return drizzleclient_net_more_data(&net);
86
void ProtocolOldLibdrizzle::enableCompression(void)
91
bool ProtocolOldLibdrizzle::isReading(void)
93
return net.reading_or_writing == 1;
96
bool ProtocolOldLibdrizzle::isWriting(void)
98
return net.reading_or_writing == 2;
101
bool ProtocolOldLibdrizzle::netStoreData(const unsigned char *from, size_t length)
103
size_t packet_length= packet->length();
105
The +9 comes from that strings of length longer than 16M require
106
9 bytes to be stored (see drizzleclient_net_store_length).
108
if (packet_length+9+length > packet->alloced_length() &&
109
packet->realloc(packet_length+9+length))
111
unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet->ptr()+packet_length, length);
112
memcpy(to,from,length);
113
packet->length((size_t) (to+length-(unsigned char*) packet->ptr()));
119
netStoreData() - extended version with character set conversion.
121
It is optimized for short strings whose length after
122
conversion is garanteed to be less than 251, which accupies
123
exactly one byte to store length. It allows not to use
124
the "convert" member as a temporary buffer, conversion
125
is done directly to the "packet" member.
126
The limit 251 is good enough to optimize send_fields()
127
because column, table, database names fit into this limit.
130
bool ProtocolOldLibdrizzle::netStoreData(const unsigned char *from, size_t length,
131
const CHARSET_INFO * const from_cs,
132
const CHARSET_INFO * const to_cs)
134
uint32_t dummy_errors;
135
/* Calculate maxumum possible result length */
136
uint32_t conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
137
if (conv_length > 250)
140
For strings with conv_length greater than 250 bytes
141
we don't know how many bytes we will need to store length: one or two,
142
because we don't know result length until conversion is done.
143
For example, when converting from utf8 (mbmaxlen=3) to latin1,
144
conv_length=300 means that the result length can vary between 100 to 300.
145
length=100 needs one byte, length=300 needs to bytes.
147
Thus conversion directly to "packet" is not worthy.
148
Let's use "convert" as a temporary buffer.
150
return (convert->copy((const char*) from, length, from_cs,
151
to_cs, &dummy_errors) ||
152
netStoreData((const unsigned char*) convert->ptr(), convert->length()));
155
size_t packet_length= packet->length();
156
size_t new_length= packet_length + conv_length + 1;
158
if (new_length > packet->alloced_length() && packet->realloc(new_length))
161
char *length_pos= (char*) packet->ptr() + packet_length;
162
char *to= length_pos + 1;
164
to+= copy_and_convert(to, conv_length, to_cs,
165
(const char*) from, length, from_cs, &dummy_errors);
167
drizzleclient_net_store_length((unsigned char*) length_pos, to - length_pos - 1);
168
packet->length((uint32_t) (to - packet->ptr()));
174
Return ok to the client.
176
The ok packet has the following structure:
178
- 0 : Marker (1 byte)
179
- affected_rows : Stored in 1-9 bytes
180
- id : Stored in 1-9 bytes
181
- server_status : Copy of session->server_status; Can be used by client
182
to check if we are inside an transaction.
184
- warning_count : Stored in 2 bytes; New in 4.1 protocol
185
- message : Stored as packed length (1-9 bytes) + message.
186
Is not stored if no message.
188
@param session Thread handler
189
@param affected_rows Number of rows changed by statement
190
@param id Auto_increment id for first row (if used)
191
@param message Message to send to the client (Used by mysql_status)
194
void ProtocolOldLibdrizzle::sendOK()
196
unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
197
const char *message= NULL;
200
if (!net.vio) // hack for re-parsing queries
205
buff[0]=0; // No fields
206
if (session->main_da.status() == Diagnostics_area::DA_OK)
208
pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
209
pos=drizzleclient_net_store_length(pos, session->main_da.last_insert_id());
210
int2store(pos, session->main_da.server_status());
212
tmp= cmin(session->main_da.total_warn_count(), (uint32_t)65535);
213
message= session->main_da.message();
217
pos=drizzleclient_net_store_length(buff+1,0);
218
pos=drizzleclient_net_store_length(pos, 0);
219
int2store(pos, session->server_status);
221
tmp= cmin(session->total_warn_count, (uint32_t)65535);
224
/* We can only return up to 65535 warnings in two bytes */
228
session->main_da.can_overwrite_status= true;
230
if (message && message[0])
232
size_t length= strlen(message);
233
pos=drizzleclient_net_store_length(pos,length);
234
memcpy(pos,(unsigned char*) message,length);
237
drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
238
drizzleclient_net_flush(&net);
240
session->main_da.can_overwrite_status= false;
244
Send eof (= end of result set) to the client.
246
The eof packet has the following structure:
248
- 254 (DRIZZLE_PROTOCOL_NO_MORE_DATA) : Marker (1 byte)
249
- warning_count : Stored in 2 bytes; New in 4.1 protocol
250
- status_flag : Stored in 2 bytes;
251
For flags like SERVER_MORE_RESULTS_EXISTS.
253
Note that the warning count will not be sent if 'no_flush' is set as
254
we don't want to report the warning count until all data is sent to the
258
void ProtocolOldLibdrizzle::sendEOF()
260
/* Set to true if no active vio, to work well in case of --init-file */
263
session->main_da.can_overwrite_status= true;
264
write_eof_packet(session, &net, session->main_da.server_status(),
265
session->main_da.total_warn_count());
266
drizzleclient_net_flush(&net);
267
session->main_da.can_overwrite_status= false;
273
Format EOF packet according to the current protocol and
274
write it to the network output buffer.
277
static void write_eof_packet(Session *session, NET *net,
278
uint32_t server_status,
279
uint32_t total_warn_count)
281
unsigned char buff[5];
283
Don't send warn count during SP execution, as the warn_list
284
is cleared between substatements, and mysqltest gets confused
286
uint32_t tmp= cmin(total_warn_count, (uint32_t)65535);
287
buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
288
int2store(buff+1, tmp);
290
The following test should never be true, but it's better to do it
291
because if 'is_fatal_error' is set the server is not going to execute
292
other queries (see the if test in dispatch_command / COM_QUERY)
294
if (session->is_fatal_error)
295
server_status&= ~SERVER_MORE_RESULTS_EXISTS;
296
int2store(buff + 3, server_status);
297
drizzleclient_net_write(net, buff, 5);
300
void ProtocolOldLibdrizzle::sendError(uint32_t sql_errno, const char *err)
304
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
306
unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
309
assert(err && err[0]);
312
It's one case when we can push an error even though there
313
is an OK or EOF already.
315
session->main_da.can_overwrite_status= true;
317
/* Abort multi-result sets */
318
session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
321
Send a error string to client.
323
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
324
critical that every error that can be intercepted is issued in one
325
place only, my_message_sql.
333
int2store(buff,sql_errno);
336
/* The first # is to make the protocol backward compatible */
338
pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
339
pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
341
char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
342
tmp+= strlen((char*)pos);
344
length= (uint32_t)(tmp-(char*)buff);
347
drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
349
session->main_da.can_overwrite_status= false;
353
ProtocolOldLibdrizzle::ProtocolOldLibdrizzle()
359
void ProtocolOldLibdrizzle::setSession(Session *session_arg)
361
session= session_arg;
362
packet= &session->packet;
363
convert= &session->convert_buffer;
368
Send name and type of result to client.
370
Sum fields has table name empty and field_name.
372
@param Session Thread data object
373
@param list List of items to send to client
374
@param flag Bit mask with the following functions:
375
- 1 send number of rows
376
- 2 send default values
377
- 4 don't write eof packet
382
1 Error (Note that in this case the error is not sent to the
385
bool ProtocolOldLibdrizzle::sendFields(List<Item> *list, uint32_t flags)
387
List_iterator_fast<Item> it(*list);
389
unsigned char buff[80];
390
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
392
if (flags & SEND_NUM_ROWS)
393
{ // Packet with number of elements
394
unsigned char *pos= drizzleclient_net_store_length(buff, list->elements);
395
(void) drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
401
const CHARSET_INFO * const cs= system_charset_info;
403
item->make_field(&field);
407
if (store(STRING_WITH_LEN("def"), cs) ||
408
store(field.db_name, cs) ||
409
store(field.table_name, cs) ||
410
store(field.org_table_name, cs) ||
411
store(field.col_name, cs) ||
412
store(field.org_col_name, cs) ||
413
packet->realloc(packet->length()+12))
416
/* Store fixed length fields */
417
pos= (char*) packet->ptr()+packet->length();
418
*pos++= 12; // Length of packed fields
419
if (item->collation.collation == &my_charset_bin)
422
int2store(pos, field.charsetnr);
423
int4store(pos+2, field.length);
427
/* With conversion */
428
uint32_t max_char_len;
429
int2store(pos, cs->number);
431
For TEXT/BLOB columns, field_length describes the maximum data
432
length in bytes. There is no limit to the number of characters
433
that a TEXT column can store, as long as the data fits into
434
the designated space.
435
For the rest of textual columns, field_length is evaluated as
436
char_count * mbmaxlen, where character count is taken from the
437
definition of the column. In other words, the maximum number
438
of characters here is limited by the column definition.
440
max_char_len= field.length / item->collation.collation->mbmaxlen;
441
int4store(pos+2, max_char_len * cs->mbmaxlen);
444
int2store(pos+7,field.flags);
445
pos[9]= (char) field.decimals;
446
pos[10]= 0; // For the future
447
pos[11]= 0; // For the future
450
packet->length((uint32_t) (pos - packet->ptr()));
451
if (flags & SEND_DEFAULTS)
452
item->send(this, &tmp); // Send default value
454
break; /* purecov: inspected */
457
if (flags & SEND_EOF)
460
Mark the end of meta-data result set, and store session->server_status,
461
to show that there is no cursor.
462
Send no warning information, as it will be sent at statement end.
464
write_eof_packet(session, &net, session->server_status, session->total_warn_count);
467
field_count= list->elements;
471
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
472
MYF(0)); /* purecov: inspected */
473
return 1; /* purecov: inspected */
477
bool ProtocolOldLibdrizzle::write()
479
return(drizzleclient_net_write(&net, (unsigned char*) packet->ptr(),
483
void ProtocolOldLibdrizzle::free()
489
void ProtocolOldLibdrizzle::setRandom(uint64_t seed1, uint64_t seed2)
491
drizzleclient_randominit(&rand, seed1, seed2);
494
bool ProtocolOldLibdrizzle::setFileDescriptor(int fd)
496
if (drizzleclient_net_init_sock(&net, fd, 0))
501
int ProtocolOldLibdrizzle::fileDescriptor(void)
503
return drizzleclient_net_get_sd(&net);
506
bool ProtocolOldLibdrizzle::authenticate()
508
bool connection_is_valid;
510
/* Use "connect_timeout" value during connection phase */
511
drizzleclient_net_set_read_timeout(&net, connect_timeout);
512
drizzleclient_net_set_write_timeout(&net, connect_timeout);
514
connection_is_valid= checkConnection();
516
if (connection_is_valid)
520
sendError(session->main_da.sql_errno(), session->main_da.message());
524
/* Connect completed, set read/write timeouts back to default */
525
drizzleclient_net_set_read_timeout(&net,
526
session->variables.net_read_timeout);
527
drizzleclient_net_set_write_timeout(&net,
528
session->variables.net_write_timeout);
532
bool ProtocolOldLibdrizzle::readCommand(char **l_packet, uint32_t *packet_length)
535
This thread will do a blocking read from the client which
536
will be interrupted when the next command is received from
537
the client, the connection is closed or "net_wait_timeout"
538
number of seconds has passed
541
/* We can do this much more efficiently with poll timeouts or watcher thread,
542
disabling for now, which means net_wait_timeout == read_timeout. */
543
drizzleclient_net_set_read_timeout(&net,
544
session->variables.net_wait_timeout);
547
session->clear_error();
548
session->main_da.reset_diagnostics_area();
552
*packet_length= drizzleclient_net_read(&net);
553
if (*packet_length == packet_error)
555
/* Check if we can continue without closing the connection */
557
if(net.last_errno== CR_NET_PACKET_TOO_LARGE)
558
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
559
if (session->main_da.status() == Diagnostics_area::DA_ERROR)
560
sendError(session->main_da.sql_errno(), session->main_da.message());
562
session->protocol->sendOK();
565
return false; // We have to close it.
572
*l_packet= (char*) net.read_pos;
575
'packet_length' contains length of data, as it was stored in packet
576
header. In case of malformed header, drizzleclient_net_read returns zero.
577
If packet_length is not zero, drizzleclient_net_read ensures that the returned
578
number of bytes was actually read from network.
579
There is also an extra safety measure in drizzleclient_net_read:
580
it sets packet[packet_length]= 0, but only for non-zero packets.
583
if (*packet_length == 0) /* safety */
585
/* Initialize with COM_SLEEP packet */
586
(*l_packet)[0]= (unsigned char) COM_SLEEP;
589
/* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
590
(*l_packet)[*packet_length]= '\0'; /* safety */
593
/* See comment above. */
594
/* Restore read timeout value */
595
drizzleclient_net_set_read_timeout(&net,
596
session->variables.net_read_timeout);
602
void ProtocolOldLibdrizzle::close(void)
606
drizzleclient_net_close(&net);
607
drizzleclient_net_end(&net);
611
void ProtocolOldLibdrizzle::forceClose(void)
614
drizzleclient_vio_close(net.vio);
617
void ProtocolOldLibdrizzle::prepareForResend()
622
bool ProtocolOldLibdrizzle::store(void)
626
return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
631
Auxilary function to convert string to the given character set
632
and store in network buffer.
635
bool ProtocolOldLibdrizzle::storeString(const char *from, size_t length,
636
const CHARSET_INFO * const fromcs,
637
const CHARSET_INFO * const tocs)
639
/* 'tocs' is set 0 when client issues SET character_set_results=NULL */
640
if (tocs && !my_charset_same(fromcs, tocs) &&
641
fromcs != &my_charset_bin &&
642
tocs != &my_charset_bin)
644
/* Store with conversion */
645
return netStoreData((unsigned char*) from, length, fromcs, tocs);
647
/* Store without conversion */
648
return netStoreData((unsigned char*) from, length);
652
bool ProtocolOldLibdrizzle::store(const char *from, size_t length,
653
const CHARSET_INFO * const fromcs)
655
const CHARSET_INFO * const tocs= default_charset_info;
656
return storeString(from, length, fromcs, tocs);
660
bool ProtocolOldLibdrizzle::store(int32_t from)
663
return netStoreData((unsigned char*) buff,
664
(size_t) (int10_to_str(from, buff, -10) - buff));
667
bool ProtocolOldLibdrizzle::store(uint32_t from)
670
return netStoreData((unsigned char*) buff,
671
(size_t) (int10_to_str(from, buff, 10) - buff));
674
bool ProtocolOldLibdrizzle::store(int64_t from)
677
return netStoreData((unsigned char*) buff,
678
(size_t) (int64_t10_to_str(from, buff, -10) - buff));
681
bool ProtocolOldLibdrizzle::store(uint64_t from)
684
return netStoreData((unsigned char*) buff,
685
(size_t) (int64_t10_to_str(from, buff, 10) - buff));
689
bool ProtocolOldLibdrizzle::store(double from, uint32_t decimals, String *buffer)
691
buffer->set_real(from, decimals, session->charset());
692
return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
696
bool ProtocolOldLibdrizzle::store(Field *from)
700
char buff[MAX_FIELD_WIDTH];
701
String str(buff,sizeof(buff), &my_charset_bin);
702
const CHARSET_INFO * const tocs= default_charset_info;
706
return storeString(str.ptr(), str.length(), str.charset(), tocs);
712
Second_part format ("%06") needs to change when
713
we support 0-6 decimals for time.
716
bool ProtocolOldLibdrizzle::store(const DRIZZLE_TIME *tm)
722
switch (tm->time_type)
724
case DRIZZLE_TIMESTAMP_DATETIME:
725
length= sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
733
length+= sprintf(buff+length, ".%06d", (int)tm->second_part);
736
case DRIZZLE_TIMESTAMP_DATE:
737
length= sprintf(buff, "%04d-%02d-%02d",
743
case DRIZZLE_TIMESTAMP_TIME:
744
day= (tm->year || tm->month) ? 0 : tm->day;
745
length= sprintf(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "",
746
(long) day*24L+(long) tm->hour, (int) tm->minute,
749
length+= sprintf(buff+length, ".%06d", (int)tm->second_part);
752
case DRIZZLE_TIMESTAMP_NONE:
753
case DRIZZLE_TIMESTAMP_ERROR:
759
return netStoreData((unsigned char*) buff, length);
762
bool ProtocolOldLibdrizzle::checkConnection(void)
771
if (drizzleclient_net_peer_addr(&net, ip, &session->peer_port, NI_MAXHOST))
773
my_error(ER_BAD_HOST_ERROR, MYF(0), session->security_ctx.ip.c_str());
777
session->security_ctx.ip.assign(ip);
779
drizzleclient_net_keepalive(&net, true);
781
uint32_t server_capabilites;
783
/* buff[] needs to big enough to hold the server_version variable */
784
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
786
server_capabilites= CLIENT_BASIC_FLAGS;
789
server_capabilites|= CLIENT_COMPRESS;
790
#endif /* HAVE_COMPRESS */
792
end= buff + strlen(server_version);
793
if ((end - buff) >= SERVER_VERSION_LENGTH)
794
end= buff + (SERVER_VERSION_LENGTH - 1);
795
memcpy(buff, server_version, end - buff);
799
int4store((unsigned char*) end, thread_id);
802
So as _checkConnection is the only entry point to authorization
803
procedure, scramble is set here. This gives us new scramble for
806
drizzleclient_create_random_string(scramble, SCRAMBLE_LENGTH, &rand);
808
Old clients does not understand long scrambles, but can ignore packet
809
tail: that's why first part of the scramble is placed here, and second
810
part at the end of packet.
812
end= strncpy(end, scramble, SCRAMBLE_LENGTH_323);
813
end+= SCRAMBLE_LENGTH_323;
815
*end++= 0; /* an empty byte for some reason */
817
int2store(end, server_capabilites);
818
/* write server characteristics: up to 16 bytes allowed */
819
end[2]=(char) default_charset_info->number;
820
int2store(end+3, session->server_status);
821
memset(end+5, 0, 13);
823
/* write scramble tail */
824
size_t scramble_len= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
825
end= strncpy(end, scramble + SCRAMBLE_LENGTH_323, scramble_len);
828
*end++= 0; /* an empty byte for some reason */
830
/* At this point we write connection message and read reply */
831
if (drizzleclient_net_write_command(&net
832
, (unsigned char) protocol_version
833
, (unsigned char*) ""
835
, (unsigned char*) buff
836
, (size_t) (end-buff))
837
|| (pkt_len= drizzleclient_net_read(&net)) == packet_error
838
|| pkt_len < MIN_HANDSHAKE_SIZE)
840
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
844
if (session->packet.alloc(session->variables.net_buffer_length))
845
return false; /* The error is set by alloc(). */
847
session->client_capabilities= uint2korr(net.read_pos);
850
session->client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
851
session->max_client_packet_length= uint4korr(net.read_pos + 4);
852
session->update_charset();
853
end= (char*) net.read_pos + 32;
856
Disable those bits which are not supported by the server.
857
This is a precautionary measure, if the client lies. See Bug#27944.
859
session->client_capabilities&= server_capabilites;
861
if (end >= (char*) net.read_pos + pkt_len + 2)
863
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
867
net.return_status= &session->server_status;
870
char *passwd= strchr(user, '\0')+1;
871
uint32_t user_len= passwd - user - 1;
873
char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
874
char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
875
uint32_t dummy_errors;
878
Old clients send null-terminated string as password; new clients send
879
the size (1 byte) + string (not null-terminated). Hence in case of empty
880
password both send '\0'.
882
This strlen() can't be easily deleted without changing protocol.
884
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
885
*passwd > 127 and become 2**32-127+ after casting to uint.
887
uint32_t passwd_len= session->client_capabilities & CLIENT_SECURE_CONNECTION ?
888
(unsigned char)(*passwd++) : strlen(passwd);
889
l_db= session->client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
891
/* strlen() can't be easily deleted without changing protocol */
892
uint32_t db_len= l_db ? strlen(l_db) : 0;
894
if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
896
my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
900
/* Since 4.1 all database names are stored in utf8 */
903
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
906
session->charset(), &dummy_errors)]= 0;
910
user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
911
system_charset_info, user, user_len,
912
session->charset(), &dummy_errors)]= '\0';
915
/* If username starts and ends in "'", chop them off */
916
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
923
session->security_ctx.user.assign(user);
925
return session->checkUser(passwd, passwd_len, l_db);
928
static ProtocolFactoryOldLibdrizzle *factory= NULL;
930
static int init(PluginRegistry ®istry)
932
factory= new ProtocolFactoryOldLibdrizzle;
933
registry.add(factory);
937
static int deinit(PluginRegistry ®istry)
941
registry.remove(factory);
947
drizzle_declare_plugin(oldlibdrizzle)
952
"Old libdrizzle Protocol",
954
init, /* Plugin Init */
955
deinit, /* Plugin Deinit */
956
NULL, /* status variables */
957
NULL, /* system variables */
958
NULL /* config options */
960
drizzle_declare_plugin_end;