Commits

Mike Steder committed 844f3ea

Connects to db and allows me to issue commands.
Next step is to figure out the appropriate interface and make tmysqlc into workable client.
Then I should be able to worry about supporting actual features like queries and the like.
Need to figure out how the adbapi works and maybe copy some of it's features.

  • Participants
  • Parent commits 64ebbf0

Comments (0)

Files changed (5)

 d.addBoth(shutdown)
 
 
+
 reactor.connectTCP(settings.HOSTNAME, settings.PORT, factory)
 reactor.run()
 

txmysql/packet.py

 
 def unpackHandshakeInitialization(bytes):
     index = bytes.find("\x00")
-    print "bytes:", bytes
-    #import pdb; pdb.set_trace()
     values = struct.unpack(handshakeInitializationFormat % (index-1,), bytes)
     return values
 

txmysql/protocol.py

 CLIENT_MULTI_STATEMENTS   = 65536    # /* Enable/disable multi-stmt support */
 CLIENT_MULTI_RESULTS      = 131072   # /* Enable/disable multi-results */
 
+# SERVER_STATUS
+SERVER_STATUS_IN_TRANS = 1
+SERVER_STATUS_AUTOCOMMIT = 2
+SERVER_MORE_RESULTS_EXISTS = 8
+SERVER_QUERY_NO_GOOD_INDEX_USED = 16
+SERVER_QUERY_NO_INDEX_USED = 32
+SERVER_STATUS_CURSOR_EXISTS = 64
+SERVER_STATUS_LAST_ROW_SENT = 128
+SERVER_STATUS_DB_DROPPED = 256
+SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512
+SERVER_STATUS_METADATA_CHANGED = 1024
+
+# COMMAND CODES:
+COM_SLEEP = 0x00
+COM_QUIT = 0x01
+
+
 # PROTOCOLS:
-protocolStates = enum.Enum("AWAITING_HANDSHAKE", "AUTHENTICATING")
+protocolStates = enum.Enum("AWAITING_HANDSHAKE", "AUTHENTICATING", "CONNECTED")
+
+def is_ascii(data):
+    if data.isalnum():
+        return data
+    return '.'
+
+
+def dump_packet(data):    
+    print "packet length %d" % len(data)
+    print "method call[1]: %s" % sys._getframe(1).f_code.co_name
+    print "method call[2]: %s" % sys._getframe(2).f_code.co_name
+    print "method call[3]: %s" % sys._getframe(3).f_code.co_name
+    print "method call[4]: %s" % sys._getframe(4).f_code.co_name
+    print "method call[5]: %s" % sys._getframe(5).f_code.co_name
+    print "-" * 88
+    dump_data = [data[i:i+16] for i in xrange(len(data)) if i%16 == 0]
+    for d in dump_data:
+        print ' '.join(map(lambda x:"%02X" % ord(x), d)) + \
+                '   ' * (16 - len(d)) + ' ' * 2 + ' '.join(map(lambda x:"%s" % is_ascii(x), d))
+    print "-" * 88
+    print ""
+
 
 class MysqlProtocol(protocol.Protocol):
     def __init__(self):
 
     def dataReceived(self, data):
         self.buffer += data
-        self.msg(data)
 
         if self.state == protocolStates.AWAITING_HANDSHAKE:
-            packet = self.getHandshakeInitialization(self.buffer)
-            if packet is not None:
+            pac = self.getHandshakeInitialization(self.buffer)
+            if pac is not None:
                 self.state = protocolStates.AUTHENTICATING
-                self.sendAuthentication(packet)
+                self.sendAuthentication(pac)
         elif self.state == protocolStates.AUTHENTICATING:
-            self.msg("GOT RESPONSE AFTER AUTH:", str(len(data)), data)
-            field_count = struct.unpack("B", data[0])
-            if field_count == 0:
-                self.msg("OK:")
-            else:
-                field_count, errno, marker, sqlstate = struct.unpack("BHB5s", data[:10])
-                self.msg("ERROR:", field_count, errno, marker, sqlstate, data[11:])
+            p = self.getPacket(self.buffer)
+            if p:
+                field_count = struct.unpack("B", p.bytes[0])[0]
+                print "FIELD_COUNT:", field_count
+                if field_count == 0:
+                    print "OK!"
+                    self.state = protocolStates.CONNECTED
+                else:
+                    print "ERROR!"
+
+    def quit(self):
+        quit_packet = struct.pack("B4s", COM_QUIT, "quit")
+        self.write(quit_packet)
 
     def sendAuthentication(self, greetingPacket):
         salt = (greetingPacket.scrambleBuffer +
         if greetingPacket.serverVersion.startswith('5'):
             self.factory.clientFlags |= CLIENT_MULTI_RESULTS
         data = (struct.pack('=i', self.factory.clientFlags) +
-                "\x00\x00\x00\x01" +  '\x08' + '\x00'*23 + 
+                "\x00\x00\x00\x01" +  '\x21' + '\x00'*23 + 
                 self.factory.username + "\x00" +
                 self._scramble(self.factory.password, salt))
-        self.msg("authData:", "\"", data, "\"", str(len(data)))
         if self.factory.database:
             data += self.factory.database + "\x00"
-        self.msg("authData:", "\"", data, "\"", str(len(data)))
         data = packet.pack_uint24(len(data)) + "\x01" + data
-        self.msg("authData:", "\"", data, "\"", str(len(data)))
-        self.transport.write(data)
+        self.write(data)
+
+    def write(self, p):
+        dump_packet(p)
+        self.transport.write(p)
 
     def _scramble(self, password, message):
         if password == None or len(password) == 0:
             result += struct.pack('B', x)
         return result
 
+    def getPacket(self, buff):
+        p = None
+        if len(buff) >= packet.packetHeaderLength:
+            length, order = packet.unpackHeader(buff[0:4])
+            if (len(buff) >= length+packet.packetHeaderLength):
+                # create the packet
+                dump_packet(buff)
+                p = packet.Packet.fromBytes(buff[0:(length+packet.packetHeaderLength)])
+                # remove packet bytes from buffer
+                self.buffer = buff[(length+packet.packetHeaderLength):]
+        return p
+
     def getHandshakeInitialization(self, buff):
-        p = None
-        if len(buff) > packet.packetHeaderLength:
-            length, order = packet.unpackHeader(buff[:4])
-            if len(buff[4:]) >= length:
-                # create the packet
-                p = imysql.IHandshakeInitializationPacket(
-                    packet.Packet.fromBytes(buff[:length+4]))
-
-                # remove packet bytes from buffer
-                self.buffer = buff[length+4:]
+        p = self.getPacket(buff)
+        if p:
+            p = imysql.IHandshakeInitializationPacket(p)
         return p
 
     def connectionMade(self):

txmysql/test/test_packet.py

         bytes += handshakeMessage
         p = imysql.IHandshakeInitializationPacket(packet.Packet.fromBytes(bytes))
         self.assertEqual(p.serverVersion, "5.1b1")
-        self.assertEqual(p.scrambleBuffer, "")
-        self.assertEqual(p.restOfScrambleBuffer, "")
+        self.assertEqual(p.scrambleBuffer, "abcdefgh")
+        self.assertEqual(p.restOfScrambleBuffer, "abcdefghijklm")
         

txmysql/test/test_protocol.py

 
     def test_sendAuthenticationPacket(self):
         self._receiveHandshakeInitializationPacket()
-        self.assertEqual(self.buff.getvalue(), ".\x00\x00\x00")
+        self.assertEqual(self.buff.getvalue(), ":\x00\x00\x01\x05\xa2\x02\x00\x00\x00\x00\x01\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00test\x00\x14G\xf0{9\xf6\xcb\xdf\x00RD\xda\xf9\x84\xca\xa6\\\xccJ\xb8\x8c")