Changeset: 2c61c25c8af9 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=2c61c25c8af9 Modified Files: python/monetdb/mapi2.py python/monetdb/mapi3.py python/test/runtests.py Branch: default Log Message:
complete rewrite of mapi3 diffs (truncated from 380 to 300 lines): diff -r ee57ff972e9c -r 2c61c25c8af9 python/monetdb/mapi2.py --- a/python/monetdb/mapi2.py Fri May 28 09:18:02 2010 +0200 +++ b/python/monetdb/mapi2.py Fri May 28 15:42:03 2010 +0200 @@ -28,6 +28,8 @@ import crypt import platform +from cStringIO import StringIO + from monetdb.monetdb_exceptions import * # windows doesn't support MSG_WAITALL flag for recv @@ -215,36 +217,33 @@ def __getblock(self): """ read one mapi encoded block """ - result = [] + result = StringIO() last = 0 while not last: flag = self.__getbytes(2) - - # unpack (little endian short) - unpacked = struct.unpack('<H', flag)[0] + unpacked = struct.unpack('<H', flag)[0] # unpack little endian short length = unpacked >> 1 last = unpacked & 1 logger.debug("II: reading %i bytes, last: %s" % (length, bool(last))) - if length > 0: - result.append(self.__getbytes(length)) - - result_str = "".join(result) - logger.debug("RX: %s" % result_str) - return result_str + result.write(self.__getbytes(length)) + logger.debug("RX: %s" % result.getvalue()) + return result.getvalue() def __getbytes(self, bytes): """Read an amount of bytes from the socket""" + result = StringIO() count = bytes - result = "" while count > 0: try: recv = self.socket.recv(bytes, flags) + logging.debug("II: package size: %i payload: %s" % (len(recv), recv)) except socket.error, error: raise OperationalError(error[1]) count -= len(recv) - result += recv - return result + result.write(recv) + return result.getvalue() + def __putblock(self, block): """ wrap the line in mapi format and put it into the socket """ @@ -256,9 +255,9 @@ if length < MAX_PACKAGE_LENGTH: last = 1 flag = struct.pack( '<H', ( length << 1 ) + last ) + logger.debug("II: sending %i bytes, last: %s" % (length, bool(last))) + logger.debug("TX: %s" % data) try: - logger.debug("II: sending %i bytes, last: %s" % (length, bool(last))) - logger.debug("TX: %s" % data) self.socket.send(flag) self.socket.send(data) except socket.error, error: diff -r ee57ff972e9c -r 2c61c25c8af9 python/monetdb/mapi3.py --- a/python/monetdb/mapi3.py Fri May 28 09:18:02 2010 +0200 +++ b/python/monetdb/mapi3.py Fri May 28 15:42:03 2010 +0200 @@ -18,27 +18,24 @@ """ This is the python 3 version of the mapi API. -Main differences are: - * different try except syntax - * Changed IO handling - * strict seperation between bytes and strings - -If you use python 2.* you should use the normal mapi.py +If you use python 2.* you should use mapi2.py """ import socket import logging import struct +import hashlib +import crypt +import platform + from io import BytesIO -import platform from monetdb.monetdb_exceptions import * # windows doesn't support MSG_WAITALL flag for recv flags = None if platform.system() != 'Windows': - flags = socket.MSG_WAITALL - + flags = socket.MSG_WAITALL logger = logging.getLogger("monetdb") @@ -63,16 +60,12 @@ class Server: - """ A connection to a MonetDB database server. This is a native driver - implementation that uses only python code """ - def __init__(self): self.state = STATE_INIT self._result = None - self.timeout = 5 def connect(self, hostname, port, username, password, database, language): - """ connect to a MonetDB database""" + """ connect to a MonetDB database using the mapi protocol""" self.hostname = hostname self.port = port @@ -87,9 +80,6 @@ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 0) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - - self.settimeout(self.timeout) - try: self.socket.connect((hostname, port)) except socket.error as error: @@ -107,7 +97,6 @@ response = self.__challenge_response(challenge) self.__putblock(response) prompt = self.__getblock().strip() - logger.debug(prompt) if len(prompt) == 0: # Empty response, server is happy @@ -122,23 +111,22 @@ elif prompt.startswith(MSG_REDIRECT): # a redirect can contain multiple redirects, for now we only use # the first - response = prompt.split()[0][1:].split(':') - - if response[1] == "merovingian": + redirect = prompt.split()[0][1:].split(':') + if redirect[1] == "merovingian": logger.debug("II: merovingian proxy, restarting " + - "authenticatiton") + "authenticatiton") if iteration <= 10: self.__login(iteration=iteration+1) else: raise OperationalError("maximal number of redirects " + - "reached (10)") + "reached (10)") - elif response[1] == "monetdb": - self.hostname = response[2][2:] - self.port, self.database = response[3].split('/') + elif redirect[1] == "monetdb": + self.hostname = redirect[2][2:] + self.port, self.database = redirect[3].split('/') self.port = int(self.port) - logger.info("II: merovingian redirect to monetdb://%s:%s/%s" - % (self.hostname, self.port, self.database)) + logger.info("II: merovingian redirect to monetdb://%s:%s/%s" % + (self.hostname, self.port, self.database)) self.socket.close() self.connect(self.hostname, self.port, self.username, self.password, self.database, self.language) @@ -166,12 +154,12 @@ logger.debug("II: executing command %s" % operation) if self.state != STATE_READY: - raise ProgrammingError("Not connected") + raise ProgrammingError self.__putblock(operation) response = self.__getblock() if not len(response): - return "" + return if response[0] in [MSG_Q, MSG_HEADER, MSG_TUPLE]: return response elif response[0] == MSG_ERROR: @@ -180,7 +168,6 @@ raise ProgrammingError("unknown state: %s" % response) - def __challenge_response(self, challenge): """ generate a response to a mapi login challenge """ challenges = challenge.split(':') @@ -190,7 +177,6 @@ if protocol == '9': algo = challenges[5] - import hashlib if algo == 'SHA512': password = hashlib.sha512(password.encode()).hexdigest() elif algo == 'SHA384': @@ -211,19 +197,16 @@ h = hashes.split(",") if "SHA1" in h: - import hashlib s = hashlib.sha1() s.update(password.encode()) s.update(salt.encode()) pwhash = "{SHA1}" + s.hexdigest() elif "MD5" in h: - import hashlib m = hashlib.md5() m.update(password.encode()) m.update(salt.encode()) pwhash = "{MD5}" + m.hexdigest() elif "crypt" in h: - import crypt pwhash = "{crypt}" + crypt.crypt((password+salt)[:8], salt[-2:]) else: pwhash = "{plain}" + password + salt @@ -234,59 +217,51 @@ def __getblock(self): """ read one mapi encoded block """ - result_bytes = BytesIO() + result = BytesIO() last = 0 while not last: flag = self.__getbytes(2) - if len(flag) != 2: - raise OperationalError("server returned %s bytes, I need 2" % - len(flag)) - - # unpack (little endian short) - unpacked = struct.unpack('<H', flag)[0] + unpacked = struct.unpack('<H', flag)[0] # unpack little endian short length = unpacked >> 1 last = unpacked & 1 - logger.debug("II: reading %i bytes" % length) - if length > 0: - count = length - while count > 0: - recv = self.__getbytes(length) - result_bytes.write(recv) - count -= len(recv) - - result = result_bytes.getvalue() - logger.debug("RX: %s" % result) - return result.decode() + logger.debug("II: reading %i bytes, last: %s" % (length, bool(last))) + result.write(self.__getbytes(length)) + result_str = result.getvalue() + logger.debug("RX: length: %i payload: %s" % (len(result_str), result_str)) + return result_str.decode() def __getbytes(self, bytes): """Read an amount of bytes from the socket""" - try: - return self.socket.recv(bytes, flags) - except socket.error as error_str: - raise OperationalError(error_str) + result = BytesIO() + count = bytes + while count > 0: + try: + recv = self.socket.recv(bytes, flags) + logging.debug("II: package size: %i payload: %s" % (len(recv), recv)) + except socket.error as error: + raise OperationalError(error[1]) + count -= len(recv) + result.write(recv) + return result.getvalue() def __putblock(self, block): """ wrap the line in mapi format and put it into the socket """ pos = 0 last = 0 - logger.debug("TX: %s" % block) while not last: data = block[pos:pos+MAX_PACKAGE_LENGTH].encode() - if len(data) < MAX_PACKAGE_LENGTH: + length = len(data) + if length < MAX_PACKAGE_LENGTH: last = 1 - flag = struct.pack( '<H', ( len(data) << 1 ) + last ) + flag = struct.pack( '<H', ( length << 1 ) + last ) + logger.debug("II: sending %i bytes, last: %s" % (length, bool(last))) + logger.debug("TX: %s" % data) try: self.socket.send(flag) _______________________________________________ Checkin-list mailing list Checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list