Drizzled Public API Documentation

handshake.py
1 #!/usr/bin/env python
2 #
3 # Drizzle Client & Protocol Library
4 #
5 # Copyright (C) 2008 Eric Day (eday@oddments.org)
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions are
10 # met:
11 #
12 # * Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 #
15 # * Redistributions in binary form must reproduce the above
16 # copyright notice, this list of conditions and the following disclaimer
17 # in the documentation and/or other materials provided with the
18 # distribution.
19 #
20 # * The names of its contributors may not be used to endorse or
21 # promote products derived from this software without specific prior
22 # written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #
36 
37 '''
38 MySQL Protocol Handshake Objects
39 '''
40 
41 import struct
42 import unittest
43 import bitfield
44 
46  _fields = [
47  'LONG_PASSWORD',
48  'FOUND_ROWS',
49  'LONG_FLAG',
50  'CONNECT_WITH_DB',
51  'NO_SCHEMA',
52  'COMPRESS',
53  'ODBC',
54  'LOCAL_FILES',
55  'IGNORE_SPACE',
56  'PROTOCOL_41',
57  'INTERACTIVE',
58  'SSL',
59  'IGNORE_SIGPIPE',
60  'TRANSACTIONS',
61  'RESERVED',
62  'SECURE_CONNECTION',
63  'MULTI_STATEMENTS',
64  'MULTI_RESULTS',
65  None,
66  None,
67  None,
68  None,
69  None,
70  None,
71  None,
72  None,
73  None,
74  None,
75  None,
76  None,
77  'SSL_VERIFY_SERVER_CERT',
78  'REMEMBER_OPTIONS'
79  ]
80 
82  _fields = [
83  'IN_TRANS',
84  'AUTOCOMMIT',
85  'MORE_RESULTS_EXISTS',
86  'QUERY_NO_GOOD_INDEX_USED',
87  'QUERY_NO_INDEX_USED',
88  'CURSOR_EXISTS',
89  'LAST_ROW_SENT',
90  'DB_DROPPED',
91  'NO_BACKSLASH_ESCAPES',
92  'QUERY_WAS_SLOW'
93  ]
94 
95 class ServerHandshake(object):
96  '''This class represents the initial handshake sent from server to client.'''
97 
98  def __init__(self, packed=None, protocol_version=10, server_version='',
99  thread_id=0, scramble=tuple([0] * 20), null1=0, capabilities=0,
100  charset=0, status=0, unused=tuple([0] * 13), null2=0):
101  if packed is None:
102  self.protocol_version = protocol_version
103  self.server_version = server_version
104  self.thread_id = thread_id
105  self.scramble = scramble
106  self.null1 = null1
107  self.capabilities = Capabilities(capabilities)
108  self.charset = charset
109  self.status = Status(status)
110  self.unused = unused
111  self.null2 = null2
112  else:
113  self.protocol_version = struct.unpack('B', packed[:1])[0]
114  server_version_length = packed[1:].index('\x00')
115  self.server_version = packed[1:1+server_version_length]
116  data = struct.unpack('<I8BB2BB2B13B12BB', packed[2+server_version_length:])
117  self.thread_id = data[0]
118  self.scramble = data[1:9] + data[28:40]
119  self.null1 = data[9]
120  self.capabilities = Capabilities(data[10] | (data[11] << 8))
121  self.charset = data[12]
122  self.status = Status(data[13] | (data[14] << 8))
123  self.unused = data[15:28]
124  self.null2 = data[40]
125 
126  def pack(self):
127  data = struct.pack('B', self.protocol_version)
128  data += self.server_version + '\x00'
129  data += struct.pack('<I', self.thread_id)
130  data += ''.join(map(chr, self.scramble[:8]))
131  data += struct.pack('B2BB2B',
132  self.null1,
133  self.capabilities.value() & 0xFF,
134  (self.capabilities.value() >> 8) & 0xFF,
135  self.charset,
136  self.status.value() & 0xFF,
137  (self.status.value() >> 8) & 0xFF)
138  data += ''.join(map(chr, self.unused))
139  data += ''.join(map(chr, self.scramble[8:]))
140  data += struct.pack('B', self.null2)
141  return data
142 
143  def __str__(self):
144  return '''ServerHandshake
145  protocol_version = %s
146  server_version = %s
147  thread_id = %s
148  scramble = %s
149  null1 = %s
150  capabilities = %s
151  charset = %s
152  status = %s
153  unused = %s
154  null2 = %s
155 ''' % (self.protocol_version, self.server_version, self.thread_id,
156  self.scramble, self.null1, self.capabilities, self.charset,
157  self.status, self.unused, self.null2)
158 
159 class TestServerHandshake(unittest.TestCase):
160 
161  def testDefaultInit(self):
162  handshake = ServerHandshake()
163  self.verifyDefault(handshake)
164  handshake.__str__()
165 
166  def testKeywordInit(self):
167  handshake = ServerHandshake(protocol_version=11,
168  server_version='test',
169  thread_id=1234,
170  scramble=tuple([5] * 20),
171  null1=1,
172  capabilities=65279,
173  charset=253,
174  status=64508,
175  unused=tuple([6] * 13),
176  null2=2)
177  self.verifyCustom(handshake)
178  handshake.__str__()
179 
180  def testUnpackInit(self):
181  data = struct.pack('B', 11)
182  data += 'test\x00'
183  data += struct.pack('<I', 1234)
184  data += ''.join([chr(5)] * 8)
185  data += struct.pack('B2BB2B', 1, 255, 254, 253, 252, 251)
186  data += ''.join([chr(6)] * 13)
187  data += ''.join([chr(5)] * 12)
188  data += struct.pack('B', 2)
189 
190  handshake = ServerHandshake(data)
191  self.verifyCustom(handshake)
192 
193  def testPack(self):
194  handshake = ServerHandshake(ServerHandshake().pack())
195  self.verifyDefault(handshake)
196 
197  def verifyDefault(self, handshake):
198  self.assertEqual(handshake.protocol_version, 10)
199  self.assertEqual(handshake.server_version, '')
200  self.assertEqual(handshake.thread_id, 0)
201  self.assertEqual(handshake.scramble, tuple([0] * 20))
202  self.assertEqual(handshake.null1, 0)
203  self.assertEqual(handshake.capabilities.value(), 0)
204  self.assertEqual(handshake.charset, 0)
205  self.assertEqual(handshake.status.value(), 0)
206  self.assertEqual(handshake.unused, tuple([0] * 13))
207  self.assertEqual(handshake.null2, 0)
208 
209  def verifyCustom(self, handshake):
210  self.assertEqual(handshake.protocol_version, 11)
211  self.assertEqual(handshake.server_version, 'test')
212  self.assertEqual(handshake.thread_id, 1234)
213  self.assertEqual(handshake.scramble, tuple([5] * 20))
214  self.assertEqual(handshake.null1, 1)
215  self.assertEqual(handshake.capabilities.value(), 65279)
216  self.assertEqual(handshake.charset, 253)
217  self.assertEqual(handshake.status.value(), 64508)
218  self.assertEqual(handshake.unused, tuple([6] * 13))
219  self.assertEqual(handshake.null2, 2)
220 
221 class ClientHandshake(object):
222  '''This class represents the client handshake sent back to the server.'''
223 
224  def __init__(self, packed=None, capabilities=0, max_packet_size=0, charset=0,
225  unused=tuple([0] * 23), user='', scramble_size=0,
226  scramble=None, db=''):
227  if packed is None:
228  self.capabilities = Capabilities(capabilities)
229  self.max_packet_size = max_packet_size
230  self.charset = charset
231  self.unused = unused
232  self.user = user
233  self.scramble_size = scramble_size
234  self.scramble = scramble
235  self.db = db
236  else:
237  data = struct.unpack('<IIB23B', packed[:32])
238  self.capabilities = Capabilities(data[0])
239  self.max_packet_size = data[1]
240  self.charset = data[2]
241  self.unused = data[3:]
242  packed = packed[32:]
243  user_length = packed.index('\x00')
244  self.user = packed[:user_length]
245  packed = packed[1+user_length:]
246  self.scramble_size = ord(packed[0])
247  if self.scramble_size == 0:
248  self.scramble = None
249  else:
250  self.scramble = tuple(map(ord, packed[1:21]))
251  if packed[-1:] == '\x00':
252  self.db = packed[21:-1]
253  else:
254  self.db = packed[21:]
255 
256  def pack(self):
257  data = struct.pack('<IIB',
258  self.capabilities.value(),
259  self.max_packet_size,
260  self.charset)
261  data += ''.join(map(chr, self.unused))
262  data += self.user + '\x00'
263  data += chr(self.scramble_size)
264  if self.scramble_size != 0:
265  data += ''.join(map(chr, self.scramble))
266  data += self.db + '\x00'
267  return data
268 
269  def __str__(self):
270  return '''ClientHandshake
271  capabilities = %s
272  max_packet_size = %s
273  charset = %s
274  unused = %s
275  user = %s
276  scramble_size = %s
277  scramble = %s
278  db = %s
279 ''' % (self.capabilities, self.max_packet_size, self.charset, self.unused,
280  self.user, self.scramble_size, self.scramble, self.db)
281 
282 class TestClientHandshake(unittest.TestCase):
283 
284  def testDefaultInit(self):
285  handshake = ClientHandshake()
286  self.verifyDefault(handshake)
287  handshake.__str__()
288 
289  def testKeywordInit(self):
290  handshake = ClientHandshake(capabilities=65279,
291  max_packet_size=64508,
292  charset=253,
293  unused=tuple([6] * 23),
294  user='user',
295  scramble_size=20,
296  scramble=tuple([5] * 20),
297  db='db')
298  self.verifyCustom(handshake)
299  handshake.__str__()
300 
301  def testUnpackInit(self):
302  data = struct.pack('<IIB', 65279, 64508, 253)
303  data += ''.join([chr(6)] * 23)
304  data += 'user\x00'
305  data += chr(20)
306  data += ''.join([chr(5)] * 20)
307  data += 'db\x00'
308 
309  handshake = ClientHandshake(data)
310  self.verifyCustom(handshake)
311 
312  def testPack(self):
313  handshake = ClientHandshake(ClientHandshake().pack())
314  self.verifyDefault(handshake)
315 
316  def verifyDefault(self, handshake):
317  self.assertEqual(handshake.capabilities.value(), 0)
318  self.assertEqual(handshake.max_packet_size, 0)
319  self.assertEqual(handshake.charset, 0)
320  self.assertEqual(handshake.unused, tuple([0] * 23))
321  self.assertEqual(handshake.user, '')
322  self.assertEqual(handshake.scramble_size, 0)
323  self.assertEqual(handshake.scramble, None)
324  self.assertEqual(handshake.db, '')
325 
326  def verifyCustom(self, handshake):
327  self.assertEqual(handshake.capabilities.value(), 65279)
328  self.assertEqual(handshake.max_packet_size, 64508)
329  self.assertEqual(handshake.charset, 253)
330  self.assertEqual(handshake.unused, tuple([6] * 23))
331  self.assertEqual(handshake.user, 'user')
332  self.assertEqual(handshake.scramble_size, 20)
333  self.assertEqual(handshake.scramble, tuple([5] * 20))
334  self.assertEqual(handshake.db, 'db')
335 
336 if __name__ == '__main__':
337  unittest.main()