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.

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")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.