Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1 #pragma diag_remark 177
segundo 0:ac1725ba162c 2 /*
segundo 0:ac1725ba162c 3 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
segundo 0:ac1725ba162c 4
segundo 0:ac1725ba162c 5 Permission is hereby granted, free of charge, to any person obtaining a copy
segundo 0:ac1725ba162c 6 of this software and associated documentation files (the "Software"), to deal
segundo 0:ac1725ba162c 7 in the Software without restriction, including without limitation the rights
segundo 0:ac1725ba162c 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
segundo 0:ac1725ba162c 9 copies of the Software, and to permit persons to whom the Software is
segundo 0:ac1725ba162c 10 furnished to do so, subject to the following conditions:
segundo 0:ac1725ba162c 11
segundo 0:ac1725ba162c 12 The above copyright notice and this permission notice shall be included in
segundo 0:ac1725ba162c 13 all copies or substantial portions of the Software.
segundo 0:ac1725ba162c 14
segundo 0:ac1725ba162c 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
segundo 0:ac1725ba162c 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
segundo 0:ac1725ba162c 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
segundo 0:ac1725ba162c 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
segundo 0:ac1725ba162c 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
segundo 0:ac1725ba162c 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
segundo 0:ac1725ba162c 21 THE SOFTWARE.
segundo 0:ac1725ba162c 22 */
segundo 0:ac1725ba162c 23
segundo 0:ac1725ba162c 24 #include "MySQLClient.h"
segundo 0:ac1725ba162c 25 #include "sha1.h" //For 4.1+ passwords
segundo 0:ac1725ba162c 26 #include "mycrypt.h" //For 4.0- passwords
segundo 0:ac1725ba162c 27
segundo 0:ac1725ba162c 28 //#define __DEBUG
segundo 0:ac1725ba162c 29 #include "dbg/dbg.h"
segundo 0:ac1725ba162c 30
segundo 0:ac1725ba162c 31 #define MYSQL_TIMEOUT_MS 45000
segundo 0:ac1725ba162c 32 #define MYSQL_PORT 3306
segundo 0:ac1725ba162c 33
segundo 0:ac1725ba162c 34 #define BUF_SIZE 256
segundo 0:ac1725ba162c 35
segundo 0:ac1725ba162c 36 #define CLIENT_LONG_PASSWORD 1
segundo 0:ac1725ba162c 37 #define CLIENT_CONNECT_WITH_DB 8
segundo 0:ac1725ba162c 38 #define CLIENT_PROTOCOL_41 512
segundo 0:ac1725ba162c 39 #define CLIENT_INTERACTIVE 1024
segundo 0:ac1725ba162c 40 #define CLIENT_SECURE_CONNECTION 32768
segundo 0:ac1725ba162c 41
segundo 0:ac1725ba162c 42 #define MIN(a,b) ((a)<(b)?(a):(b))
segundo 0:ac1725ba162c 43 #define ABS(a) (((a)>0)?(a):0)
segundo 0:ac1725ba162c 44
segundo 0:ac1725ba162c 45 //MySQL commands
segundo 0:ac1725ba162c 46 #define COM_QUIT 0x01 //Exit
segundo 0:ac1725ba162c 47 #define COM_QUERY 0x03 //Execute an SQL query
segundo 0:ac1725ba162c 48
segundo 0:ac1725ba162c 49 //#define htons( x ) ( (( x << 8 ) & 0xFF00) | (( x >> 8 ) & 0x00FF) )
segundo 0:ac1725ba162c 50 #define ntohs( x ) (htons(x))
segundo 0:ac1725ba162c 51
segundo 0:ac1725ba162c 52 /*#define htonl( x ) ( (( x << 24 ) & 0xFF000000) \
segundo 0:ac1725ba162c 53 | (( x << 8 ) & 0x00FF0000) \
segundo 0:ac1725ba162c 54 | (( x >> 8 ) & 0x0000FF00) \
segundo 0:ac1725ba162c 55 | (( x >> 24 ) & 0x000000FF) )*/
segundo 0:ac1725ba162c 56 #define htonl( x ) (x)
segundo 0:ac1725ba162c 57 #define ntohl( x ) (htonl(x))
segundo 0:ac1725ba162c 58
segundo 0:ac1725ba162c 59 MySQLClient::MySQLClient() : NetService(false) /*Not owned by the pool*/, m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
segundo 0:ac1725ba162c 60 m_pTCPSocket(NULL), m_watchdog(), m_timeout(MYSQL_TIMEOUT_MS*1000), m_pDnsReq(NULL), m_closed(true),
segundo 0:ac1725ba162c 61 m_host(), m_user(), m_password(), m_db(), m_state(MYSQL_CLOSED)
segundo 0:ac1725ba162c 62 {
segundo 0:ac1725ba162c 63 m_buf = new byte[BUF_SIZE];
segundo 0:ac1725ba162c 64 m_pPos = m_buf;
segundo 0:ac1725ba162c 65 m_len = 0;
segundo 0:ac1725ba162c 66 m_size = BUF_SIZE;
segundo 0:ac1725ba162c 67 }
segundo 0:ac1725ba162c 68
segundo 0:ac1725ba162c 69 MySQLClient::~MySQLClient()
segundo 0:ac1725ba162c 70 {
segundo 0:ac1725ba162c 71 close();
segundo 0:ac1725ba162c 72 delete[] m_buf;
segundo 0:ac1725ba162c 73 }
segundo 0:ac1725ba162c 74
segundo 0:ac1725ba162c 75 //High Level setup functions
segundo 0:ac1725ba162c 76 MySQLResult MySQLClient::open(Host& host, const string& user, const string& password, const string& db, void (*pMethod)(MySQLResult)) //Non blocking
segundo 0:ac1725ba162c 77 {
segundo 0:ac1725ba162c 78 setOnResult(pMethod);
segundo 0:ac1725ba162c 79 setup(host, user, password, db);
segundo 0:ac1725ba162c 80 return MYSQL_PROCESSING;
segundo 0:ac1725ba162c 81 }
segundo 0:ac1725ba162c 82
segundo 0:ac1725ba162c 83 #if 0 //Ref only
segundo 0:ac1725ba162c 84 template<class T>
segundo 0:ac1725ba162c 85 MySQLResult MySQLClient::open(Host& host, const string& user, const string& password, const string& db, T* pItem, void (T::*pMethod)(MySQLResult)) //Non blocking
segundo 0:ac1725ba162c 86 {
segundo 0:ac1725ba162c 87 setOnResult(pItem, pMethod);
segundo 0:ac1725ba162c 88 setup(host, user, password, db);
segundo 0:ac1725ba162c 89 return MYSQL_PROCESSING;
segundo 0:ac1725ba162c 90 }
segundo 0:ac1725ba162c 91 #endif
segundo 0:ac1725ba162c 92
segundo 0:ac1725ba162c 93 MySQLResult MySQLClient::sql(string& sqlCommand)
segundo 0:ac1725ba162c 94 {
segundo 0:ac1725ba162c 95 if(m_state!=MYSQL_COMMANDS)
segundo 0:ac1725ba162c 96 return MYSQL_SETUP;
segundo 0:ac1725ba162c 97 sendCommand(COM_QUERY, (byte*)sqlCommand.data(), sqlCommand.length());
segundo 0:ac1725ba162c 98 return MYSQL_PROCESSING;
segundo 0:ac1725ba162c 99 }
segundo 0:ac1725ba162c 100
segundo 0:ac1725ba162c 101 MySQLResult MySQLClient::exit()
segundo 0:ac1725ba162c 102 {
segundo 0:ac1725ba162c 103 sendCommand(COM_QUIT, NULL, 0);
segundo 0:ac1725ba162c 104 close();
segundo 0:ac1725ba162c 105 return MYSQL_OK;
segundo 0:ac1725ba162c 106 }
segundo 0:ac1725ba162c 107
segundo 0:ac1725ba162c 108 void MySQLClient::setOnResult( void (*pMethod)(MySQLResult) )
segundo 0:ac1725ba162c 109 {
segundo 0:ac1725ba162c 110 m_pCb = pMethod;
segundo 0:ac1725ba162c 111 m_pCbItem = NULL;
segundo 0:ac1725ba162c 112 m_pCbMeth = NULL;
segundo 0:ac1725ba162c 113 }
segundo 0:ac1725ba162c 114
segundo 0:ac1725ba162c 115 #if 0 //Ref only
segundo 0:ac1725ba162c 116 template<class T>
segundo 0:ac1725ba162c 117 void MySQLClient::setOnResult( T* pItem, void (T::*pMethod)(MySQLResult) )
segundo 0:ac1725ba162c 118 {
segundo 0:ac1725ba162c 119 m_pCb = NULL;
segundo 0:ac1725ba162c 120 m_pCbItem = (CDummy*) pItem;
segundo 0:ac1725ba162c 121 m_pCbMeth = (void (CDummy::*)(MySQLResult)) pMethod;
segundo 0:ac1725ba162c 122 }
segundo 0:ac1725ba162c 123 #endif
segundo 0:ac1725ba162c 124
segundo 0:ac1725ba162c 125 void MySQLClient::setTimeout(int ms)
segundo 0:ac1725ba162c 126 {
segundo 0:ac1725ba162c 127 m_timeout = 1000*ms;
segundo 0:ac1725ba162c 128 }
segundo 0:ac1725ba162c 129
segundo 0:ac1725ba162c 130 void MySQLClient::poll() //Called by NetServices
segundo 0:ac1725ba162c 131 {
segundo 0:ac1725ba162c 132 if(m_closed)
segundo 0:ac1725ba162c 133 {
segundo 0:ac1725ba162c 134 return;
segundo 0:ac1725ba162c 135 }
segundo 0:ac1725ba162c 136 if(m_watchdog.read_us()>m_timeout)
segundo 0:ac1725ba162c 137 {
segundo 0:ac1725ba162c 138 onTimeout();
segundo 0:ac1725ba162c 139 }
segundo 0:ac1725ba162c 140 }
segundo 0:ac1725ba162c 141
segundo 0:ac1725ba162c 142 void MySQLClient::resetTimeout()
segundo 0:ac1725ba162c 143 {
segundo 0:ac1725ba162c 144 m_watchdog.reset();
segundo 0:ac1725ba162c 145 m_watchdog.start();
segundo 0:ac1725ba162c 146 }
segundo 0:ac1725ba162c 147
segundo 0:ac1725ba162c 148 void MySQLClient::init()
segundo 0:ac1725ba162c 149 {
segundo 0:ac1725ba162c 150 close(); //Remove previous elements
segundo 0:ac1725ba162c 151 if(!m_closed) //Already opened
segundo 0:ac1725ba162c 152 return;
segundo 0:ac1725ba162c 153 m_state = MYSQL_HANDSHAKE;
segundo 0:ac1725ba162c 154 m_pTCPSocket = new TCPSocket;
segundo 0:ac1725ba162c 155 m_pTCPSocket->setOnEvent(this, &MySQLClient::onTCPSocketEvent);
segundo 0:ac1725ba162c 156 m_closed = false;
segundo 0:ac1725ba162c 157 }
segundo 0:ac1725ba162c 158
segundo 0:ac1725ba162c 159 void MySQLClient::close()
segundo 0:ac1725ba162c 160 {
segundo 0:ac1725ba162c 161 if(m_closed)
segundo 0:ac1725ba162c 162 return;
segundo 0:ac1725ba162c 163 m_state = MYSQL_CLOSED;
segundo 0:ac1725ba162c 164 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
segundo 0:ac1725ba162c 165 m_watchdog.stop(); //Stop timeout
segundo 0:ac1725ba162c 166 m_watchdog.reset();
segundo 0:ac1725ba162c 167 m_pTCPSocket->resetOnEvent();
segundo 0:ac1725ba162c 168 m_pTCPSocket->close();
segundo 0:ac1725ba162c 169 delete m_pTCPSocket;
segundo 0:ac1725ba162c 170 m_pTCPSocket = NULL;
segundo 0:ac1725ba162c 171 if( m_pDnsReq )
segundo 0:ac1725ba162c 172 {
segundo 0:ac1725ba162c 173 m_pDnsReq->close();
segundo 0:ac1725ba162c 174 delete m_pDnsReq;
segundo 0:ac1725ba162c 175 m_pDnsReq = NULL;
segundo 0:ac1725ba162c 176 }
segundo 0:ac1725ba162c 177 }
segundo 0:ac1725ba162c 178
segundo 0:ac1725ba162c 179 void MySQLClient::setup(Host& host, const string& user, const string& password, const string& db) //Setup connection, make DNS Req if necessary
segundo 0:ac1725ba162c 180 {
segundo 0:ac1725ba162c 181 init(); //Initialize client in known state, create socket
segundo 0:ac1725ba162c 182 resetTimeout();
segundo 0:ac1725ba162c 183 m_host = host;
segundo 0:ac1725ba162c 184 if(!host.getPort())
segundo 0:ac1725ba162c 185 host.setPort( MYSQL_PORT ); //Default port
segundo 0:ac1725ba162c 186
segundo 0:ac1725ba162c 187 m_user = user;
segundo 0:ac1725ba162c 188 m_password = password;
segundo 0:ac1725ba162c 189
segundo 0:ac1725ba162c 190 m_db = db;
segundo 0:ac1725ba162c 191
segundo 0:ac1725ba162c 192 if( !host.getIp().isNull() )
segundo 0:ac1725ba162c 193 {
segundo 0:ac1725ba162c 194 connect();
segundo 0:ac1725ba162c 195 }
segundo 0:ac1725ba162c 196 else //Need to do a DNS Query...
segundo 0:ac1725ba162c 197 {
segundo 0:ac1725ba162c 198 DBG("DNS Query...\n");
segundo 0:ac1725ba162c 199 m_pDnsReq = new DNSRequest();
segundo 0:ac1725ba162c 200 m_pDnsReq->setOnReply(this, &MySQLClient::onDNSReply);
segundo 0:ac1725ba162c 201 m_pDnsReq->resolve(&m_host);
segundo 0:ac1725ba162c 202 DBG("MySQLClient : DNSRequest %p\n", m_pDnsReq);
segundo 0:ac1725ba162c 203 }
segundo 0:ac1725ba162c 204 }
segundo 0:ac1725ba162c 205
segundo 0:ac1725ba162c 206 void MySQLClient::connect() //Start Connection
segundo 0:ac1725ba162c 207 {
segundo 0:ac1725ba162c 208 resetTimeout();
segundo 0:ac1725ba162c 209 DBG("Connecting...\n");
segundo 0:ac1725ba162c 210 m_pTCPSocket->connect(m_host);
segundo 0:ac1725ba162c 211 m_packetId = 0;
segundo 0:ac1725ba162c 212 }
segundo 0:ac1725ba162c 213
segundo 0:ac1725ba162c 214 void MySQLClient::handleHandshake()
segundo 0:ac1725ba162c 215 {
segundo 0:ac1725ba162c 216 readData();
segundo 0:ac1725ba162c 217 if( ! (( m_len > 1 ) && ( memchr( m_buf + 1, 0, m_len ) != NULL )) )
segundo 0:ac1725ba162c 218 {
segundo 0:ac1725ba162c 219 DBG("Connected but could not find pcsz...\n");
segundo 0:ac1725ba162c 220 onResult(MYSQL_PRTCL);
segundo 0:ac1725ba162c 221 return;
segundo 0:ac1725ba162c 222 }
segundo 0:ac1725ba162c 223
segundo 0:ac1725ba162c 224 DBG("Connected to server: %d bytes read ; Protocol version %d, mysql-%s.\n", m_len, m_buf[0], &m_buf[1]);
segundo 0:ac1725ba162c 225
segundo 0:ac1725ba162c 226 m_pPos = (byte*) memchr( (char*)(m_buf + 1), 0, m_len ) + 1;
segundo 0:ac1725ba162c 227
segundo 0:ac1725ba162c 228 sendAuth();
segundo 0:ac1725ba162c 229 }
segundo 0:ac1725ba162c 230
segundo 0:ac1725ba162c 231 void MySQLClient::sendAuth()
segundo 0:ac1725ba162c 232 {
segundo 0:ac1725ba162c 233 if( m_len - (m_pPos - m_buf) != 44)
segundo 0:ac1725ba162c 234 {
segundo 0:ac1725ba162c 235 //We only support protocol >= mysql-4.1
segundo 0:ac1725ba162c 236 DBG("Message after pcsz has wrong len (%d != 44)...\n", m_len - (m_pPos - m_buf));
segundo 0:ac1725ba162c 237 onResult(MYSQL_PRTCL);
segundo 0:ac1725ba162c 238 return;
segundo 0:ac1725ba162c 239 }
segundo 0:ac1725ba162c 240
segundo 0:ac1725ba162c 241 uint16_t serverFlags = *((uint16_t*)&m_pPos[13]);
segundo 0:ac1725ba162c 242 DBG("Server capabilities are %04X.\n", serverFlags);
segundo 0:ac1725ba162c 243
segundo 0:ac1725ba162c 244 uint32_t clientFlags = CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | CLIENT_INTERACTIVE;;
segundo 0:ac1725ba162c 245
segundo 0:ac1725ba162c 246 //if(serverFlags & CLIENT_LONG_PASSWORD)
segundo 0:ac1725ba162c 247
segundo 0:ac1725ba162c 248 DBG("Using auth 4.1+\n");
segundo 0:ac1725ba162c 249 //Encrypt pw using scramble
segundo 0:ac1725ba162c 250 byte scramble[20+20]={0};
segundo 0:ac1725ba162c 251 memcpy(scramble, m_pPos+4, 8);
segundo 0:ac1725ba162c 252 memcpy(scramble+8, m_pPos+31, 12); // *(m_pPos+43) == 0 (zero-terminated char*)
segundo 0:ac1725ba162c 253
segundo 0:ac1725ba162c 254 byte stage1_hash[20] = {0};
segundo 0:ac1725ba162c 255 sha1( (byte*)m_password.data(), m_password.length(), stage1_hash );
segundo 0:ac1725ba162c 256
segundo 0:ac1725ba162c 257 sha1( stage1_hash, 20, ((byte*)scramble + 20) );
segundo 0:ac1725ba162c 258
segundo 0:ac1725ba162c 259 byte token[20] = {0};
segundo 0:ac1725ba162c 260 sha1( scramble, 40, token );
segundo 0:ac1725ba162c 261
segundo 0:ac1725ba162c 262 for(int i=0;i<20;i++)
segundo 0:ac1725ba162c 263 token[i] = token[i] ^ stage1_hash[i];
segundo 0:ac1725ba162c 264
segundo 0:ac1725ba162c 265 clientFlags |= CLIENT_LONG_PASSWORD;
segundo 0:ac1725ba162c 266
segundo 0:ac1725ba162c 267 DBG("Building response\n");
segundo 0:ac1725ba162c 268 //Build response
segundo 0:ac1725ba162c 269
segundo 0:ac1725ba162c 270 //BE
segundo 0:ac1725ba162c 271 *((uint32_t*)&m_buf[0]) = htonl(clientFlags);
segundo 0:ac1725ba162c 272 *((uint32_t*)&m_buf[4]) = BUF_SIZE; //Max packets size
segundo 0:ac1725ba162c 273 m_buf[8] = 8; //latin1 charset
segundo 0:ac1725ba162c 274 memset((char*)(m_buf+9),0,23);
segundo 0:ac1725ba162c 275 strcpy((char*)(m_buf+32),m_user.c_str());
segundo 0:ac1725ba162c 276 m_pPos = m_buf + 32 + m_user.length() + 1;
segundo 0:ac1725ba162c 277 m_pPos[0] = 20;
segundo 0:ac1725ba162c 278 memcpy((char*)&m_pPos[1],token,20);
segundo 0:ac1725ba162c 279 strcpy((char*)(m_pPos+21),m_db.c_str());
segundo 0:ac1725ba162c 280 m_len = 32 + m_user.length() + 1 + 21 + m_db.length() + 1;
segundo 0:ac1725ba162c 281
segundo 0:ac1725ba162c 282 //Save first part of scramble in case we need it again
segundo 0:ac1725ba162c 283 memcpy(&m_buf[BUF_SIZE-8], scramble, 8);
segundo 0:ac1725ba162c 284
segundo 0:ac1725ba162c 285 m_state = MYSQL_AUTH;
segundo 0:ac1725ba162c 286
segundo 0:ac1725ba162c 287 DBG("Writing data\n");
segundo 0:ac1725ba162c 288 writeData();
segundo 0:ac1725ba162c 289 }
segundo 0:ac1725ba162c 290
segundo 0:ac1725ba162c 291 void MySQLClient::handleAuthResult()
segundo 0:ac1725ba162c 292 {
segundo 0:ac1725ba162c 293 readData();
segundo 0:ac1725ba162c 294 if(m_len==1 && *m_buf==0xfe)
segundo 0:ac1725ba162c 295 {
segundo 0:ac1725ba162c 296 //Re-send auth using 4.0- auth
segundo 0:ac1725ba162c 297 sendAuth323();
segundo 0:ac1725ba162c 298 return;
segundo 0:ac1725ba162c 299 }
segundo 0:ac1725ba162c 300 m_watchdog.stop(); //Stop timeout
segundo 0:ac1725ba162c 301 m_watchdog.reset();
segundo 0:ac1725ba162c 302 if(m_len<2)
segundo 0:ac1725ba162c 303 {
segundo 0:ac1725ba162c 304 DBG("Response too short..\n");
segundo 0:ac1725ba162c 305 onResult(MYSQL_PRTCL);
segundo 0:ac1725ba162c 306 return;
segundo 0:ac1725ba162c 307 }
segundo 0:ac1725ba162c 308 DBG("RC=%d ",m_buf[0]);
segundo 0:ac1725ba162c 309 if(m_buf[0]==0)
segundo 0:ac1725ba162c 310 {
segundo 0:ac1725ba162c 311 m_buf[m_len] = 0;
segundo 0:ac1725ba162c 312 m_pPos = m_buf + 1;
segundo 0:ac1725ba162c 313 m_pPos += m_buf[1] +1;
segundo 0:ac1725ba162c 314 m_pPos += m_pPos[0];
segundo 0:ac1725ba162c 315 m_pPos += 1;
segundo 0:ac1725ba162c 316 DBG("(OK) : Server status %d, Message : %s\n", *((uint16_t*)&m_pPos[0]), m_pPos+4);
segundo 0:ac1725ba162c 317 onResult(MYSQL_OK);
segundo 0:ac1725ba162c 318 }
segundo 0:ac1725ba162c 319 else
segundo 0:ac1725ba162c 320 {
segundo 0:ac1725ba162c 321 m_buf[m_len] = 0;
segundo 0:ac1725ba162c 322 DBG("(Error %d) : %s\n", *((uint16_t*)&m_buf[1]), &m_buf[9]); //LE
segundo 0:ac1725ba162c 323 onResult(MYSQL_AUTHFAILED);
segundo 0:ac1725ba162c 324 return;
segundo 0:ac1725ba162c 325 }
segundo 0:ac1725ba162c 326 m_state = MYSQL_COMMANDS;
segundo 0:ac1725ba162c 327 }
segundo 0:ac1725ba162c 328
segundo 0:ac1725ba162c 329 void MySQLClient::sendAuth323()
segundo 0:ac1725ba162c 330 {
segundo 0:ac1725ba162c 331 DBG("Using auth 4.0-\n");
segundo 0:ac1725ba162c 332 byte scramble[8]={0};
segundo 0:ac1725ba162c 333
segundo 0:ac1725ba162c 334 memcpy(scramble, &m_buf[BUF_SIZE-8], 8); //Recover scramble
segundo 0:ac1725ba162c 335
segundo 0:ac1725ba162c 336 //memcpy(scramble+8, m_pPos+31, 12); // *(m_pPos+43) == 0 (zero-terminated char*)
segundo 0:ac1725ba162c 337
segundo 0:ac1725ba162c 338 byte token[9]={0};
segundo 0:ac1725ba162c 339
segundo 0:ac1725ba162c 340 scramble_323((char*)token, (const char*)scramble, m_password.c_str());
segundo 0:ac1725ba162c 341
segundo 0:ac1725ba162c 342 DBG("Building response\n");
segundo 0:ac1725ba162c 343 //Build response
segundo 0:ac1725ba162c 344
segundo 0:ac1725ba162c 345 memcpy((char*)m_buf,token,9);
segundo 0:ac1725ba162c 346 m_len = 9;
segundo 0:ac1725ba162c 347
segundo 0:ac1725ba162c 348 #if 0
segundo 0:ac1725ba162c 349 *((uint32_t*)&m_buf[0]) = htonl(clientFlags);
segundo 0:ac1725ba162c 350 *((uint32_t*)&m_buf[4]) = BUF_SIZE; //Max packets size
segundo 0:ac1725ba162c 351 m_buf[8] = 8; //latin1 charset
segundo 0:ac1725ba162c 352 memset((char*)(m_buf+9),0,23);
segundo 0:ac1725ba162c 353 strcpy((char*)(m_buf+32),m_user.c_str());
segundo 0:ac1725ba162c 354 m_pPos = m_buf + 32 + m_user.length() + 1;
segundo 0:ac1725ba162c 355 m_pPos[0] = 8;
segundo 0:ac1725ba162c 356 memcpy((char*)&m_pPos[1],token+1,8);
segundo 0:ac1725ba162c 357 strcpy((char*)(m_pPos+9),m_db.c_str());
segundo 0:ac1725ba162c 358 m_len = 32 + m_user.length() + 1 + 9 + m_db.length() + 1;
segundo 0:ac1725ba162c 359 #endif
segundo 0:ac1725ba162c 360
segundo 0:ac1725ba162c 361 DBG("Writing data\n");
segundo 0:ac1725ba162c 362 writeData();
segundo 0:ac1725ba162c 363 }
segundo 0:ac1725ba162c 364
segundo 0:ac1725ba162c 365 void MySQLClient::sendCommand(byte command, byte* arg, int len)
segundo 0:ac1725ba162c 366 {
segundo 0:ac1725ba162c 367 DBG("Sending command %d, payload of len %d\n", command, len);
segundo 0:ac1725ba162c 368 m_packetId=0;//Reset packet ID (New sequence)
segundo 0:ac1725ba162c 369 m_buf[0] = command;
segundo 0:ac1725ba162c 370 memcpy(&m_buf[1], arg, len);
segundo 0:ac1725ba162c 371 m_len = 1 + len;
segundo 0:ac1725ba162c 372 writeData();
segundo 0:ac1725ba162c 373 m_watchdog.start();
segundo 0:ac1725ba162c 374 }
segundo 0:ac1725ba162c 375
segundo 0:ac1725ba162c 376 void MySQLClient::handleCommandResult()
segundo 0:ac1725ba162c 377 {
segundo 0:ac1725ba162c 378 readData();
segundo 0:ac1725ba162c 379 m_watchdog.stop(); //Stop timeout
segundo 0:ac1725ba162c 380 m_watchdog.reset();
segundo 0:ac1725ba162c 381 if(m_len<2)
segundo 0:ac1725ba162c 382 {
segundo 0:ac1725ba162c 383 DBG("Response too short..\n");
segundo 0:ac1725ba162c 384 onResult(MYSQL_PRTCL);
segundo 0:ac1725ba162c 385 return;
segundo 0:ac1725ba162c 386 }
segundo 0:ac1725ba162c 387 DBG("RC=%d ",m_buf[0]);
segundo 0:ac1725ba162c 388 if(m_buf[0]==0)
segundo 0:ac1725ba162c 389 {
segundo 0:ac1725ba162c 390 DBG("(OK)\n");
segundo 0:ac1725ba162c 391 onResult(MYSQL_OK);
segundo 0:ac1725ba162c 392 }
segundo 0:ac1725ba162c 393 else
segundo 0:ac1725ba162c 394 {
segundo 0:ac1725ba162c 395 m_buf[m_len] = 0;
segundo 0:ac1725ba162c 396 DBG("(SQL Error %d) : %s\n", *((uint16_t*)&m_buf[1]), &m_buf[9]); //LE
segundo 0:ac1725ba162c 397 onResult(MYSQL_SQL);
segundo 0:ac1725ba162c 398 return;
segundo 0:ac1725ba162c 399 }
segundo 0:ac1725ba162c 400 }
segundo 0:ac1725ba162c 401
segundo 0:ac1725ba162c 402 void MySQLClient::readData() //Copy to buf
segundo 0:ac1725ba162c 403 {
segundo 0:ac1725ba162c 404 byte head[4];
segundo 0:ac1725ba162c 405 int ret = m_pTCPSocket->recv((char*)head, 4); //Packet header
segundo 0:ac1725ba162c 406 m_len = *((uint16_t*)&head[0]);
segundo 0:ac1725ba162c 407 m_packetId = head[3];
segundo 0:ac1725ba162c 408 DBG("Packet Id %d of length %d\n", head[3], m_len);
segundo 0:ac1725ba162c 409 m_packetId++;
segundo 0:ac1725ba162c 410 if(ret>0)
segundo 0:ac1725ba162c 411 ret = m_pTCPSocket->recv((char*)m_buf, m_len);
segundo 0:ac1725ba162c 412 if(ret < 0)//Error
segundo 0:ac1725ba162c 413 {
segundo 0:ac1725ba162c 414 onResult(MYSQL_CONN);
segundo 0:ac1725ba162c 415 return;
segundo 0:ac1725ba162c 416 }
segundo 0:ac1725ba162c 417 if(ret < m_len)
segundo 0:ac1725ba162c 418 {
segundo 0:ac1725ba162c 419 DBG("WARN: Incomplete packet\n");
segundo 0:ac1725ba162c 420 }
segundo 0:ac1725ba162c 421 m_len = ret;
segundo 0:ac1725ba162c 422 }
segundo 0:ac1725ba162c 423
segundo 0:ac1725ba162c 424 void MySQLClient::writeData() //Copy from buf
segundo 0:ac1725ba162c 425 {
segundo 0:ac1725ba162c 426 byte head[4] = { 0 };
segundo 0:ac1725ba162c 427 *((uint16_t*)&head[0]) = m_len;
segundo 0:ac1725ba162c 428 head[3] = m_packetId;
segundo 0:ac1725ba162c 429 DBG("Packet Id %d\n", head[3]);
segundo 0:ac1725ba162c 430 m_packetId++;
segundo 0:ac1725ba162c 431 int ret = m_pTCPSocket->send((char*)head, 4); //Packet header
segundo 0:ac1725ba162c 432 if(ret>0)
segundo 0:ac1725ba162c 433 ret = m_pTCPSocket->send((char*)m_buf, m_len);
segundo 0:ac1725ba162c 434 if(ret < 0)//Error
segundo 0:ac1725ba162c 435 {
segundo 0:ac1725ba162c 436 onResult(MYSQL_CONN);
segundo 0:ac1725ba162c 437 return;
segundo 0:ac1725ba162c 438 }
segundo 0:ac1725ba162c 439 m_len = 0;//FIXME... incomplete packets handling
segundo 0:ac1725ba162c 440 }
segundo 0:ac1725ba162c 441
segundo 0:ac1725ba162c 442 void MySQLClient::onTCPSocketEvent(TCPSocketEvent e)
segundo 0:ac1725ba162c 443 {
segundo 0:ac1725ba162c 444 DBG("Event %d in MySQLClient::onTCPSocketEvent()\n", e);
segundo 0:ac1725ba162c 445
segundo 0:ac1725ba162c 446 if(m_closed)
segundo 0:ac1725ba162c 447 {
segundo 0:ac1725ba162c 448 DBG("WARN: Discarded\n");
segundo 0:ac1725ba162c 449 return;
segundo 0:ac1725ba162c 450 }
segundo 0:ac1725ba162c 451
segundo 0:ac1725ba162c 452 switch(e)
segundo 0:ac1725ba162c 453 {
segundo 0:ac1725ba162c 454 case TCPSOCKET_READABLE: //Incoming data
segundo 0:ac1725ba162c 455 resetTimeout();
segundo 0:ac1725ba162c 456 if(m_state == MYSQL_HANDSHAKE)
segundo 0:ac1725ba162c 457 handleHandshake();
segundo 0:ac1725ba162c 458 else if(m_state == MYSQL_AUTH)
segundo 0:ac1725ba162c 459 handleAuthResult();
segundo 0:ac1725ba162c 460 else if(m_state == MYSQL_COMMANDS)
segundo 0:ac1725ba162c 461 handleCommandResult();
segundo 0:ac1725ba162c 462 break;
segundo 0:ac1725ba162c 463 case TCPSOCKET_WRITEABLE: //We can send data
segundo 0:ac1725ba162c 464 resetTimeout();
segundo 0:ac1725ba162c 465 break;
segundo 0:ac1725ba162c 466 case TCPSOCKET_CONNECTED: //Connected, wait for handshake packet
segundo 0:ac1725ba162c 467 resetTimeout();
segundo 0:ac1725ba162c 468 break;
segundo 0:ac1725ba162c 469 case TCPSOCKET_CONTIMEOUT:
segundo 0:ac1725ba162c 470 case TCPSOCKET_CONRST:
segundo 0:ac1725ba162c 471 case TCPSOCKET_CONABRT:
segundo 0:ac1725ba162c 472 case TCPSOCKET_ERROR:
segundo 0:ac1725ba162c 473 DBG("Connection error.\n");
segundo 0:ac1725ba162c 474 onResult(MYSQL_CONN);
segundo 0:ac1725ba162c 475 case TCPSOCKET_DISCONNECTED:
segundo 0:ac1725ba162c 476 //There might still be some data available for reading
segundo 0:ac1725ba162c 477 //So if we are in a reading state, do not close the socket yet
segundo 0:ac1725ba162c 478 if(m_state != MYSQL_CLOSED)
segundo 0:ac1725ba162c 479 {
segundo 0:ac1725ba162c 480 onResult(MYSQL_CONN);
segundo 0:ac1725ba162c 481 }
segundo 0:ac1725ba162c 482 DBG("Connection closed by remote host.\n");
segundo 0:ac1725ba162c 483 break;
segundo 0:ac1725ba162c 484 }
segundo 0:ac1725ba162c 485 }
segundo 0:ac1725ba162c 486
segundo 0:ac1725ba162c 487 void MySQLClient::onDNSReply(DNSReply r)
segundo 0:ac1725ba162c 488 {
segundo 0:ac1725ba162c 489 if(m_closed)
segundo 0:ac1725ba162c 490 {
segundo 0:ac1725ba162c 491 DBG("WARN: Discarded\n");
segundo 0:ac1725ba162c 492 return;
segundo 0:ac1725ba162c 493 }
segundo 0:ac1725ba162c 494
segundo 0:ac1725ba162c 495 if( r != DNS_FOUND )
segundo 0:ac1725ba162c 496 {
segundo 0:ac1725ba162c 497 DBG("Could not resolve hostname.\n");
segundo 0:ac1725ba162c 498 onResult(MYSQL_DNS);
segundo 0:ac1725ba162c 499 return;
segundo 0:ac1725ba162c 500 }
segundo 0:ac1725ba162c 501
segundo 0:ac1725ba162c 502 DBG("DNS Resolved to %d.%d.%d.%d.\n",m_host.getIp()[0],m_host.getIp()[1],m_host.getIp()[2],m_host.getIp()[3]);
segundo 0:ac1725ba162c 503 //If no error, m_host has been updated by m_pDnsReq so we're set to go !
segundo 0:ac1725ba162c 504 m_pDnsReq->close();
segundo 0:ac1725ba162c 505 delete m_pDnsReq;
segundo 0:ac1725ba162c 506 m_pDnsReq = NULL;
segundo 0:ac1725ba162c 507 connect();
segundo 0:ac1725ba162c 508 }
segundo 0:ac1725ba162c 509
segundo 0:ac1725ba162c 510 void MySQLClient::onResult(MySQLResult r) //Called when exchange completed or on failure
segundo 0:ac1725ba162c 511 {
segundo 0:ac1725ba162c 512 if(m_pCbItem && m_pCbMeth)
segundo 0:ac1725ba162c 513 (m_pCbItem->*m_pCbMeth)(r);
segundo 0:ac1725ba162c 514 else if(m_pCb)
segundo 0:ac1725ba162c 515 m_pCb(r);
segundo 0:ac1725ba162c 516
segundo 0:ac1725ba162c 517 if( (r==MYSQL_DNS) || (r==MYSQL_PRTCL) || (r==MYSQL_AUTHFAILED) || (r==MYSQL_TIMEOUT) || (r==MYSQL_CONN) ) //Fatal error, close connection
segundo 0:ac1725ba162c 518 close();
segundo 0:ac1725ba162c 519 }
segundo 0:ac1725ba162c 520
segundo 0:ac1725ba162c 521 void MySQLClient::onTimeout() //Connection has timed out
segundo 0:ac1725ba162c 522 {
segundo 0:ac1725ba162c 523 DBG("Timed out.\n");
segundo 0:ac1725ba162c 524 onResult(MYSQL_TIMEOUT);
segundo 0:ac1725ba162c 525 close();
segundo 0:ac1725ba162c 526 }