Drizzled Public API Documentation

mysql_protocol.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; version 2 of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <boost/program_options.hpp>
00023 
00024 #include <algorithm>
00025 #include <climits>
00026 
00027 #include <drizzled/gettext.h>
00028 #include <drizzled/error.h>
00029 #include <drizzled/error/sql_state.h>
00030 #include <drizzled/session.h>
00031 #include <drizzled/internal/m_string.h>
00032 #include <drizzled/module/option_map.h>
00033 #include <drizzled/util/tokenize.h>
00034 #include <plugin/mysql_protocol/errmsg.h>
00035 #include <plugin/mysql_protocol/mysql_protocol.h>
00036 #include <plugin/mysql_protocol/mysql_password.h>
00037 #include <plugin/mysql_protocol/options.h>
00038 #include <drizzled/identifier.h>
00039 #include <drizzled/plugin/function.h>
00040 #include <drizzled/diagnostics_area.h>
00041 #include <drizzled/system_variables.h>
00042 #include <libdrizzle-2.0/constants.h>
00043 
00044 #define MIN_HANDSHAKE_SIZE 6
00045 #define PROTOCOL_VERSION 10
00046 
00047 namespace po= boost::program_options;
00048 using namespace std;
00049 using namespace drizzled;
00050 
00051 namespace drizzle_plugin {
00052 
00053 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
00054 
00055 static port_constraint port;
00056 static timeout_constraint connect_timeout;
00057 static timeout_constraint read_timeout;
00058 static timeout_constraint write_timeout;
00059 static retry_constraint retry_count;
00060 static buffer_constraint buffer_length;
00061 
00062 static uint32_t random_seed1;
00063 static uint32_t random_seed2;
00064 static const uint32_t random_max= 0x3FFFFFFF;
00065 static const double random_max_double= (double)0x3FFFFFFF;
00066 
00067 ProtocolCounters ListenMySQLProtocol::mysql_counters;
00068 
00069 void ListenMySQLProtocol::addCountersToTable()
00070 {
00071   counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters().connectionCount));
00072   counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters().connected));
00073   counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters().failedConnections));
00074 }
00075 
00076 const std::string ListenMySQLProtocol::getHost() const
00077 {
00078   return _hostname;
00079 }
00080 
00081 in_port_t ListenMySQLProtocol::getPort() const
00082 {
00083   return port.get();
00084 }
00085 
00086 plugin::Client *ListenMySQLProtocol::getClient(int fd)
00087 {
00088   int new_fd= acceptTcp(fd);
00089   return new_fd == -1 ? NULL : new ClientMySQLProtocol(new_fd, getCounters());
00090 }
00091 
00092 ClientMySQLProtocol::ClientMySQLProtocol(int fd, ProtocolCounters& set_counters) :
00093   _is_interactive(false),
00094   counters(set_counters)
00095 {
00096   net.vio= 0;
00097 
00098   if (fd == -1)
00099     return;
00100 
00101   net.init(fd, buffer_length.get());
00102   net.set_read_timeout(read_timeout.get());
00103   net.set_write_timeout(write_timeout.get());
00104   net.retry_count=retry_count.get();
00105 }
00106 
00107 ClientMySQLProtocol::~ClientMySQLProtocol()
00108 {
00109   if (net.vio)
00110     net.vio->close();
00111 }
00112 
00113 int ClientMySQLProtocol::getFileDescriptor()
00114 {
00115   return net.get_sd();
00116 }
00117 
00118 bool ClientMySQLProtocol::isConnected()
00119 {
00120   return net.vio != 0;
00121 }
00122 
00123 bool ClientMySQLProtocol::flush()
00124 {
00125   if (net.vio == NULL)
00126     return false;
00127   bool ret= net.write(packet.ptr(), packet.length());
00128   packet.length(0);
00129   return ret;
00130 }
00131 
00132 void ClientMySQLProtocol::close()
00133 {
00134   if (net.vio)
00135   { 
00136     net.close();
00137     net.end();
00138     counters.connected.decrement();
00139   }
00140 }
00141 
00142 bool ClientMySQLProtocol::authenticate()
00143 {
00144   counters.connectionCount.increment();
00145   counters.connected.increment();
00146 
00147   /* Use "connect_timeout" value during connection phase */
00148   net.set_read_timeout(connect_timeout.get());
00149   net.set_write_timeout(connect_timeout.get());
00150 
00151   if (checkConnection())
00152   {
00153     if (counters.connected > counters.max_connections)
00154     {
00155       std::string errmsg(ER(ER_CON_COUNT_ERROR));
00156       sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
00157       counters.failedConnections.increment();
00158     }
00159     else
00160     {
00161       sendOK();
00162     }
00163   }
00164   else
00165   {
00166     sendError(session->main_da().sql_errno(), session->main_da().message());
00167     counters.failedConnections.increment();
00168     return false;
00169   }
00170 
00171   /* Connect completed, set read/write timeouts back to default */
00172   net.set_read_timeout(read_timeout.get());
00173   net.set_write_timeout(write_timeout.get());
00174   return true;
00175 }
00176 
00177 bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t& packet_length)
00178 {
00179   /*
00180     This thread will do a blocking read from the client which
00181     will be interrupted when the next command is received from
00182     the client, the connection is closed or "net_wait_timeout"
00183     number of seconds has passed
00184   */
00185 #ifdef NEVER
00186   /* We can do this much more efficiently with poll timeouts or watcher thread,
00187      disabling for now, which means net_wait_timeout == read_timeout. */
00188   drizzleclient_net_set_read_timeout(&net,
00189                                      session->variables.net_wait_timeout);
00190 #endif
00191 
00192   net.pkt_nr=0;
00193   packet_length= net.read();
00194   if (packet_length == packet_error)
00195   {
00196     /* Check if we can continue without closing the connection */
00197 
00198     if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
00199       my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
00200     if (session->main_da().status() == Diagnostics_area::DA_ERROR)
00201       sendError(session->main_da().sql_errno(), session->main_da().message());
00202     else
00203       sendOK();
00204 
00205     if (net.error_ != 3)
00206       return false;                       // We have to close it.
00207 
00208     net.error_= 0;
00209   }
00210 
00211   *l_packet= (char*) net.read_pos;
00212 
00213   /*
00214     'packet_length' contains length of data, as it was stored in packet
00215     header. In case of malformed header, drizzleclient_net_read returns zero.
00216     If packet_length is not zero, drizzleclient_net_read ensures that the returned
00217     number of bytes was actually read from network.
00218     There is also an extra safety measure in drizzleclient_net_read:
00219     it sets packet[packet_length]= 0, but only for non-zero packets.
00220   */
00221 
00222   if (packet_length == 0)                       /* safety */
00223   {
00224     /* Initialize with COM_SLEEP packet */
00225     (*l_packet)[0]= COM_SLEEP;
00226     packet_length= 1;
00227   }
00228   else
00229   {
00230     /* Map from MySQL commands to Drizzle commands. */
00231     switch ((*l_packet)[0])
00232     {
00233     case 0: /* SLEEP */
00234     case 1: /* QUIT */
00235     case 2: /* INIT_DB */
00236     case 3: /* QUERY */
00237       break;
00238 
00239     case 8: /* SHUTDOWN */
00240       (*l_packet)[0]= COM_SHUTDOWN;
00241       break;
00242 
00243     case 12: /* KILL */
00244       (*l_packet)[0]= COM_KILL;
00245       break;
00246 
00247     case 14: /* PING */
00248       (*l_packet)[0]= COM_PING;
00249       break;
00250 
00251     default:
00252       /* Respond with unknown command for MySQL commands we don't support. */
00253       (*l_packet)[0]= COM_END;
00254       packet_length= 1;
00255     }
00256   }
00257 
00258   /* Do not rely on drizzleclient_net_read, extra safety against programming errors. */
00259   (*l_packet)[packet_length]= '\0';                  /* safety */
00260 
00261 #ifdef NEVER
00262   /* See comment above. */
00263   /* Restore read timeout value */
00264   drizzleclient_net_set_read_timeout(&net, session->variables.net_read_timeout);
00265 #endif
00266 
00267   return true;
00268 }
00269 
00291 void ClientMySQLProtocol::sendOK()
00292 {
00293   unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
00294   const char *message= NULL;
00295   uint32_t tmp;
00296 
00297   if (!net.vio)    // hack for re-parsing queries
00298   {
00299     return;
00300   }
00301 
00302   buff[0]=0;                    // No fields
00303   if (session->main_da().status() == Diagnostics_area::DA_OK)
00304   {
00305     if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da().found_rows())
00306       pos=storeLength(buff+1,session->main_da().found_rows());
00307     else
00308       pos=storeLength(buff+1,session->main_da().affected_rows());
00309     pos=storeLength(pos, session->main_da().last_insert_id());
00310     int2store(pos, session->main_da().server_status());
00311     pos+=2;
00312     tmp= min(session->main_da().total_warn_count(), (uint32_t)65535);
00313     message= session->main_da().message();
00314   }
00315   else
00316   {
00317     pos=storeLength(buff+1,0);
00318     pos=storeLength(pos, 0);
00319     int2store(pos, session->server_status);
00320     pos+=2;
00321     tmp= min(session->total_warn_count, (uint32_t)65535);
00322   }
00323 
00324   /* We can only return up to 65535 warnings in two bytes */
00325   int2store(pos, tmp);
00326   pos+= 2;
00327 
00328   session->main_da().can_overwrite_status= true;
00329 
00330   if (message && message[0])
00331   {
00332     size_t length= strlen(message);
00333     pos=storeLength(pos,length);
00334     memcpy(pos,(unsigned char*) message,length);
00335     pos+=length;
00336   }
00337   net.write(buff, pos - buff);
00338   net.flush();
00339 
00340   session->main_da().can_overwrite_status= false;
00341 }
00342 
00358 void ClientMySQLProtocol::sendEOF()
00359 {
00360   /* Set to true if no active vio, to work well in case of --init-file */
00361   if (net.vio)
00362   {
00363     session->main_da().can_overwrite_status= true;
00364     writeEOFPacket(session->main_da().server_status(), session->main_da().total_warn_count());
00365     net.flush();
00366     session->main_da().can_overwrite_status= false;
00367   }
00368   packet.shrink(buffer_length.get());
00369 }
00370 
00371 
00372 void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
00373 {
00374   // buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + DRIZZLE_ERRMSG_SIZE:512
00375   unsigned char buff[2 + 1 + SQLSTATE_LENGTH + DRIZZLE_ERRMSG_SIZE];
00376 
00377   assert(sql_errno != EE_OK);
00378   assert(err && err[0]);
00379 
00380   /*
00381     It's one case when we can push an error even though there
00382     is an OK or EOF already.
00383   */
00384   session->main_da().can_overwrite_status= true;
00385 
00386   /* Abort multi-result sets */
00387   session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
00388 
00397   if (net.vio == 0)
00398   {
00399     return;
00400   }
00401 
00402   int2store(buff, static_cast<uint16_t>(sql_errno));
00403 
00404   /* The first # is to make the client backward compatible */
00405   buff[2]= '#';
00406   unsigned char* pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
00407   pos+= strlen(error::convert_to_sqlstate(sql_errno));
00408 
00409   char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
00410   tmp+= strlen((char*)pos);
00411   tmp[0]= '\0';
00412   net.write_command(255, data_ref(), data_ref(buff, tmp));
00413   net.flush();
00414   session->main_da().can_overwrite_status= false;
00415 }
00416 
00435 void ClientMySQLProtocol::sendFields(List<Item>& list)
00436 {
00437   List<Item>::iterator it(list.begin());
00438   unsigned char buff[80];
00439   String tmp((char*) buff,sizeof(buff),&my_charset_bin);
00440 
00441   unsigned char *row_pos= storeLength(buff, list.size());
00442   (void) net.write(buff, row_pos - buff);
00443 
00444   while (Item* item=it++)
00445   {
00446     SendField field;
00447     item->make_field(&field);
00448 
00449     packet.length(0);
00450 
00451     store(STRING_WITH_LEN("def"));
00452     store(field.db_name);
00453     store(field.table_name);
00454     store(field.org_table_name);
00455     store(field.col_name);
00456     store(field.org_col_name);
00457     packet.realloc(packet.length()+12);
00458 
00459     /* Store fixed length fields */
00460     char* pos= (char*) packet.ptr()+packet.length();
00461     *pos++= 12;                // Length of packed fields
00462     /* No conversion */
00463     int2store(pos, field.charsetnr);
00464     int4store(pos+2, field.length);
00465 
00466     if (true) // _using_mysql41_protocol)
00467     {
00468       /* Switch to MySQL field numbering. */
00469       switch (field.type)
00470       {
00471       case DRIZZLE_TYPE_LONG:
00472         pos[6]= DRIZZLE_COLUMN_TYPE_LONG;
00473         break;
00474 
00475       case DRIZZLE_TYPE_DOUBLE:
00476         pos[6]= DRIZZLE_COLUMN_TYPE_DOUBLE;
00477         break;
00478 
00479       case DRIZZLE_TYPE_NULL:
00480         pos[6]= DRIZZLE_COLUMN_TYPE_NULL;
00481         break;
00482 
00483       case DRIZZLE_TYPE_TIMESTAMP:
00484         pos[6]= DRIZZLE_COLUMN_TYPE_TIMESTAMP;
00485         break;
00486 
00487       case DRIZZLE_TYPE_LONGLONG:
00488         pos[6]= DRIZZLE_COLUMN_TYPE_LONGLONG;
00489         break;
00490 
00491       case DRIZZLE_TYPE_DATETIME:
00492         pos[6]= DRIZZLE_COLUMN_TYPE_DATETIME;
00493         break;
00494 
00495       case DRIZZLE_TYPE_TIME:
00496         pos[6]= DRIZZLE_COLUMN_TYPE_TIME;
00497         break;
00498 
00499       case DRIZZLE_TYPE_DATE:
00500         pos[6]= DRIZZLE_COLUMN_TYPE_DATE;
00501         break;
00502 
00503       case DRIZZLE_TYPE_VARCHAR:
00504         pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00505         break;
00506 
00507       case DRIZZLE_TYPE_MICROTIME:
00508         pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00509         break;
00510 
00511       case DRIZZLE_TYPE_UUID:
00512         pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00513         break;
00514 
00515       case DRIZZLE_TYPE_IPV6:
00516         pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00517         break;
00518 
00519       case DRIZZLE_TYPE_BOOLEAN:
00520         pos[6]= DRIZZLE_COLUMN_TYPE_TINY;
00521         break;
00522 
00523       case DRIZZLE_TYPE_DECIMAL:
00524         pos[6]= (char)DRIZZLE_COLUMN_TYPE_NEWDECIMAL;
00525         break;
00526 
00527       case DRIZZLE_TYPE_ENUM:
00528         pos[6]= (char)DRIZZLE_COLUMN_TYPE_ENUM;
00529         break;
00530 
00531       case DRIZZLE_TYPE_BLOB:
00532         pos[6]= (char)DRIZZLE_COLUMN_TYPE_BLOB;
00533         break;
00534       }
00535     }
00536     else
00537     {
00538       /* Add one to compensate for tinyint removal from enum. */
00539       pos[6]= field.type + 1;
00540     }
00541 
00542     int2store(pos+7,field.flags);
00543     pos[9]= (char) field.decimals;
00544     pos[10]= 0;                // For the future
00545     pos[11]= 0;                // For the future
00546     pos+= 12;
00547 
00548     packet.length((uint32_t) (pos - packet.ptr()));
00549     if (flush())
00550       break;
00551   }
00552 
00553   /*
00554     Mark the end of meta-data result set, and store session->server_status,
00555     to show that there is no cursor.
00556     Send no warning information, as it will be sent at statement end.
00557   */
00558   writeEOFPacket(session->server_status, session->total_warn_count);
00559 }
00560 
00561 void ClientMySQLProtocol::store(Field *from)
00562 {
00563   if (from->is_null())
00564     return store();
00565   if (from->type() == DRIZZLE_TYPE_BOOLEAN)
00566   {
00567     return store(from->val_int());
00568   }
00569 
00570   char buff[MAX_FIELD_WIDTH];
00571   String str(buff,sizeof(buff), &my_charset_bin);
00572 
00573   from->val_str_internal(&str);
00574 
00575   netStoreData(str.ptr(), str.length());
00576 }
00577 
00578 void ClientMySQLProtocol::store()
00579 {
00580   char buff[1];
00581   buff[0]= (char)251;
00582   packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
00583 }
00584 
00585 void ClientMySQLProtocol::store(int32_t from)
00586 {
00587   char buff[12];
00588   netStoreData(buff, internal::int10_to_str(from, buff, -10) - buff);
00589 }
00590 
00591 void ClientMySQLProtocol::store(uint32_t from)
00592 {
00593   char buff[11];
00594   netStoreData(buff, internal::int10_to_str(from, buff, 10) - buff);
00595 }
00596 
00597 void ClientMySQLProtocol::store(int64_t from)
00598 {
00599   char buff[22];
00600   netStoreData(buff, internal::int64_t10_to_str(from, buff, -10) - buff);
00601 }
00602 
00603 void ClientMySQLProtocol::store(uint64_t from)
00604 {
00605   char buff[21];
00606   netStoreData(buff, internal::int64_t10_to_str(from, buff, 10) - buff);
00607 }
00608 
00609 void ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
00610 {
00611   buffer->set_real(from, decimals, session->charset());
00612   netStoreData(buffer->ptr(), buffer->length());
00613 }
00614 
00615 void ClientMySQLProtocol::store(const char *from, size_t length)
00616 {
00617   netStoreData(from, length);
00618 }
00619 
00620 bool ClientMySQLProtocol::wasAborted()
00621 {
00622   return net.error_ && net.vio != 0;
00623 }
00624 
00625 bool ClientMySQLProtocol::haveError()
00626 {
00627   return net.error_ || net.vio == 0;
00628 }
00629 
00630 bool ClientMySQLProtocol::checkConnection()
00631 {
00632   char scramble[SCRAMBLE_LENGTH];
00633   identifier::user::mptr user_identifier= identifier::User::make_shared();
00634 
00635   makeScramble(scramble);
00636 
00637   // TCP/IP connection
00638   {
00639     char ip[NI_MAXHOST];
00640     uint16_t peer_port;
00641 
00642     if (net.peer_addr(ip, NI_MAXHOST, peer_port))
00643     {
00644       my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
00645       return false;
00646     }
00647 
00648     user_identifier->setAddress(ip);
00649   }
00650   net.keepalive(true);
00651 
00652   char* end;
00653   uint32_t pkt_len= 0;
00654   uint32_t server_capabilites;
00655   {
00656     /* buff[] needs to big enough to hold the server_version variable */
00657     char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
00658 
00659     server_capabilites= CLIENT_BASIC_FLAGS | CLIENT_PROTOCOL_MYSQL41;
00660 
00661 #ifdef HAVE_COMPRESS
00662     server_capabilites|= CLIENT_COMPRESS;
00663 #endif /* HAVE_COMPRESS */
00664 
00665     end= buff + strlen(PANDORA_RELEASE_VERSION);
00666     if ((end - buff) >= SERVER_VERSION_LENGTH)
00667       end= buff + (SERVER_VERSION_LENGTH - 1);
00668     memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
00669     *end= 0;
00670     end++;
00671 
00672     int4store((unsigned char*) end, session->variables.pseudo_thread_id);
00673     end+= 4;
00674 
00675     /* We don't use scramble anymore. */
00676     memcpy(end, scramble, SCRAMBLE_LENGTH_323);
00677     end+= SCRAMBLE_LENGTH_323;
00678     *end++= 0; /* an empty byte for some reason */
00679 
00680     int2store(end, server_capabilites);
00681     /* write server characteristics: up to 16 bytes allowed */
00682     end[2]=(char) default_charset_info->number;
00683     int2store(end+3, session->server_status);
00684     memset(end+5, 0, 13);
00685     end+= 18;
00686 
00687     /* Write scramble tail. */
00688     memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
00689     end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
00690     *end++= 0; /* an empty byte for some reason */
00691 
00692     /* At this point we write connection message and read reply */
00693     if (net.write_command(PROTOCOL_VERSION, data_ref(), data_ref(buff, end)) 
00694         || (pkt_len= net.read()) == packet_error 
00695         || pkt_len < MIN_HANDSHAKE_SIZE)
00696     {
00697       my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00698       return false;
00699     }
00700   }
00701   packet.alloc(buffer_length.get());
00702 
00703   client_capabilities= uint2korr(net.read_pos);
00704   if (not (client_capabilities & CLIENT_PROTOCOL_MYSQL41))
00705   {
00706     my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00707     return false;
00708   }
00709 
00710   client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
00711   // session->max_client_packet_length= uint4korr(net.read_pos + 4);
00712   end= (char*) net.read_pos + 32;
00713 
00714   /*
00715     Disable those bits which are not supported by the server.
00716     This is a precautionary measure, if the client lies. See Bug#27944.
00717   */
00718   client_capabilities&= server_capabilites;
00719 
00720   if (end >= (char*) net.read_pos + pkt_len + 2)
00721   {
00722     my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00723     return false;
00724   }
00725 
00726   char *user= end;
00727   char *passwd= strchr(user, '\0')+1;
00728   uint32_t user_len= passwd - user - 1;
00729   char *l_db= passwd;
00730 
00731   /*
00732     Only support new password format.
00733 
00734     Cast *passwd to an unsigned char, so that it doesn't extend the sign for
00735     *passwd > 127 and become 2**32-127+ after casting to uint.
00736   */
00737   uint32_t passwd_len;
00738   if (client_capabilities & CLIENT_SECURE_CONNECTION &&
00739       passwd < (char *) net.read_pos + pkt_len)
00740   {
00741     passwd_len= (unsigned char)(*passwd++);
00742     if (passwd_len > 0 and client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
00743     {
00744       user_identifier->setPasswordType(identifier::User::PLAIN_TEXT);
00745     }
00746     else if (passwd_len > 0)
00747     {
00748       user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
00749       user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
00750     }
00751   }
00752   else
00753   {
00754     passwd_len= 0;
00755   }
00756 
00757   if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
00758       passwd < (char *) net.read_pos + pkt_len)
00759   {
00760     l_db= l_db + passwd_len + 1;
00761   }
00762   else
00763   {
00764     l_db= NULL;
00765   }
00766 
00767   /* strlen() can't be easily deleted without changing client */
00768   uint32_t db_len= l_db ? strlen(l_db) : 0;
00769 
00770   if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
00771   {
00772     my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00773     return false;
00774   }
00775 
00776   /* If username starts and ends in "'", chop them off */
00777   if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
00778   {
00779     user[user_len-1]= 0;
00780     user++;
00781     user_len-= 2;
00782   }
00783 
00784   if (client_capabilities & CLIENT_INTERACTIVE)
00785   {
00786     _is_interactive= true;
00787   }
00788 
00789   if (client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
00790   {
00791     passwd_len= strlen(passwd);
00792   }
00793 
00794   user_identifier->setUser(user);
00795   session->setUser(user_identifier);
00796 
00797   return session->checkUser(string(passwd, passwd_len), string(l_db ? l_db : ""));
00798 
00799 }
00800 
00801 void ClientMySQLProtocol::netStoreData(const void* from, size_t length)
00802 {
00803   size_t packet_length= packet.length();
00804   /*
00805      The +9 comes from that strings of length longer than 16M require
00806      9 bytes to be stored (see storeLength).
00807   */
00808   if (packet_length+9+length > packet.alloced_length())
00809       packet.realloc(packet_length+9+length);
00810   unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
00811   memcpy(to,from,length);
00812   packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
00813 }
00814 
00820 void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status, uint32_t total_warn_count)
00821 {
00822   unsigned char buff[5];
00823   /*
00824     Don't send warn count during SP execution, as the warn_list
00825     is cleared between substatements, and mysqltest gets confused
00826   */
00827   uint32_t tmp= min(total_warn_count, (uint32_t)65535);
00828   buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
00829   int2store(buff+1, tmp);
00830   /*
00831     The following test should never be true, but it's better to do it
00832     because if 'is_fatal_error' is set the server is not going to execute
00833     other queries (see the if test in dispatch_command / COM_QUERY)
00834   */
00835   if (session->is_fatal_error)
00836     server_status&= ~SERVER_MORE_RESULTS_EXISTS;
00837   int2store(buff + 3, server_status);
00838   net.write(buff, 5);
00839 }
00840 
00841 /*
00842   Store an integer with simple packing into a output package
00843 
00844   buffer      Store the packed integer here
00845   length    integers to store
00846 
00847   This is mostly used to store lengths of strings.  We have to cast
00848   the result for the LL() becasue of a bug in Forte CC compiler.
00849 
00850   RETURN
00851   Position in 'buffer' after the packed length
00852 */
00853 
00854 unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
00855 {
00856   if (length < 251)
00857   {
00858     *buffer= (unsigned char) length;
00859     return buffer+1;
00860   }
00861   /* 251 is reserved for NULL */
00862   if (length < 65536)
00863   {
00864     *buffer++= 252;
00865     int2store(buffer, (uint32_t) length);
00866     return buffer+2;
00867   }
00868   if (length < 16777216)
00869   {
00870     *buffer++=253;
00871     int3store(buffer, (uint32_t) length);
00872     return buffer+3;
00873   }
00874   *buffer++=254;
00875   int8store(buffer, length);
00876   return buffer+8;
00877 }
00878 
00879 void ClientMySQLProtocol::makeScramble(char *scramble)
00880 {
00881   /* This is the MySQL algorithm with minimal changes. */
00882   random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
00883   random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
00884   uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
00885 
00886   void *pointer= this;
00887   uint32_t pointer_seed;
00888   memcpy(&pointer_seed, &pointer, 4);
00889   uint32_t random1= (seed + pointer_seed) % random_max;
00890   uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
00891 
00892   for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
00893   {
00894     random1= (random1 * 3 + random2) % random_max;
00895     random2= (random1 + random2 + 33) % random_max;
00896     *scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
00897   }
00898 }
00899 
00900 static int init(drizzled::module::Context &context)
00901 {  
00902   /* Initialize random seeds for the MySQL algorithm with minimal changes. */
00903   time_t seed_time= time(NULL);
00904   random_seed1= seed_time % random_max;
00905   random_seed2= (seed_time / 2) % random_max;
00906 
00907   const module::option_map &vm= context.getOptions();
00908 
00909   context.add(new plugin::Create_function<MySQLPassword>(MySQLPasswordName));
00910 
00911   ListenMySQLProtocol* listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>());
00912   listen_obj->addCountersToTable();
00913   context.add(listen_obj); 
00914   context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
00915   context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
00916   context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
00917   context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
00918   context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
00919   context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
00920   context.registerVariable(new sys_var_const_string_val("bind_address", vm["bind-address"].as<std::string>()));
00921   context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters.max_connections));
00922 
00923   return 0;
00924 }
00925 
00926 static void init_options(drizzled::module::option_context &context)
00927 {
00928   context("port",
00929           po::value<port_constraint>(&port)->default_value(3306),
00930           _("Port number to use for connection or 0 for default to with MySQL "
00931                               "protocol."));
00932   context("connect-timeout",
00933           po::value<timeout_constraint>(&connect_timeout)->default_value(10),
00934           _("Connect Timeout."));
00935   context("read-timeout",
00936           po::value<timeout_constraint>(&read_timeout)->default_value(30),
00937           _("Read Timeout."));
00938   context("write-timeout",
00939           po::value<timeout_constraint>(&write_timeout)->default_value(60),
00940           _("Write Timeout."));
00941   context("retry-count",
00942           po::value<retry_constraint>(&retry_count)->default_value(10),
00943           _("Retry Count."));
00944   context("buffer-length",
00945           po::value<buffer_constraint>(&buffer_length)->default_value(16384),
00946           _("Buffer length."));
00947   context("bind-address",
00948           po::value<string>()->default_value("localhost"),
00949           _("Address to bind to."));
00950   context("max-connections",
00951           po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters.max_connections)->default_value(1000),
00952           _("Maximum simultaneous connections."));
00953 }
00954 
00955 } /* namespace drizzle_plugin */
00956 
00957 DRIZZLE_DECLARE_PLUGIN
00958 {
00959   DRIZZLE_VERSION_ID,
00960   "mysql-protocol",
00961   "0.1",
00962   "Eric Day",
00963   "MySQL Protocol Module",
00964   PLUGIN_LICENSE_GPL,
00965   drizzle_plugin::init,             /* Plugin Init */
00966   NULL, /* depends */
00967   drizzle_plugin::init_options    /* config options */
00968 }
00969 DRIZZLE_DECLARE_PLUGIN_END;