Sounds like something that should have gone to the Candidate (Nov2009) branch?
Gijs Molenaar wrote: > Update of /cvsroot/monetdb/clients/src/python/monetdb > In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv12494 > > Modified Files: > mapi.py > Added Files: > mapi2.py > Log Message: > > Both python2 and python3 can do import monetdb.mapi now. Change is backwards > compatible. > > Previously you needed to do import monetdb.mapi3 in python3. > > > > --- NEW FILE: mapi2.py --- > # The contents of this file are subject to the MonetDB Public License > # Version 1.1 (the "License"); you may not use this file except in > # compliance with the License. You may obtain a copy of the License at > # http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html > # > # Software distributed under the License is distributed on an "AS IS" > # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the > # License for the specific language governing rights and limitations > # under the License. > # > # The Original Code is the MonetDB Database System. > # > # The Initial Developer of the Original Code is CWI. > # Portions created by CWI are Copyright (C) 1997-July 2008 CWI. > # Copyright August 2008-2009 MonetDB B.V. > # All Rights Reserved. > > """ > this is the python 2.* implementation of the mapi API. > > If you use python 3.* you should use mapi3.py > """ > > import socket > import logging > import struct > > from monetdb.monetdb_exceptions import * > > > logger = logging.getLogger("monetdb") > > MAX_PACKAGE_LENGTH = (1024*8)-2 > > MSG_PROMPT = "" > MSG_INFO = "#" > MSG_ERROR = "!" > MSG_Q = "&" > MSG_QTABLE = "&1" > MSG_QUPDATE = "&2" > MSG_QSCHEMA = "&3" > MSG_QTRANS = "&4" > MSG_QPREPARE = "&5" > MSG_QBLOCK = "&6" > MSG_HEADER = "%" > MSG_TUPLE = "[" > MSG_REDIRECT = "^" > > STATE_INIT = 0 > STATE_READY = 1 > > > class Server: > def __init__(self): > self.state = STATE_INIT > self._result = None > > def connect(self, hostname, port, username, password, database, language): > """ connect to a MonetDB database using the mapi protocol""" > > self.hostname = hostname > self.port = port > self.username = username > self.password = password > self.database = database > self.language = language > > self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > > try: > self.socket.connect((hostname, port)) > except socket.error, error: > (error_code, error_str) = error > raise OperationalError(error_str) > > self.__login() > > > def __login(self, iteration=0): > """ Reads challenge from line, generate response and check if > everything is okay """ > > challenge = self.__getblock() > response = self.__challenge_response(challenge) > self.__putblock(response) > prompt = self.__getblock().strip() > > if len(prompt) == 0: > # Empty response, server is happy > pass > elif prompt.startswith(MSG_INFO): > logger.info("II %s" % prompt[1:]) > > elif prompt.startswith(MSG_ERROR): > logger.error(prompt[1:]) > raise DatabaseError(prompt[1:]) > > 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": > logger.debug("II: merovingian proxy, restarting " + > "authenticatiton") > if iteration <= 10: > self.__login(iteration=iteration+1) > else: > raise OperationalError("maximal number of redirects " + > "reached (10)") > > elif response[1] == "monetdb": > self.hostname = response[2][2:] > self.port, self.database = response[3].split('/') > self.port = int(self.port) > 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) > > else: > logger.error('!' + prompt[0]) > raise ProgrammingError("unknown redirect: %s" % prompt) > > else: > logger.error('!' + prompt[0]) > raise ProgrammingError("unknown state: %s" % prompt) > > self.state = STATE_READY > return True > > > def disconnect(self): > """ disconnect from the monetdb server """ > self.state = STATE_INIT > self.socket.close() > > > def cmd(self, operation): > """ put a mapi command on the line""" > logger.debug("II: executing command %s" % operation) > > if self.state != STATE_READY: > raise(ProgrammingError, "Not connected") > > self.__putblock(operation) > response = self.__getblock() > if not len(response): > return > if response[0] in [MSG_Q, MSG_HEADER, MSG_TUPLE]: > return response > elif response[0] == MSG_ERROR: > raise OperationalError(response[1:]) > else: > raise ProgrammingError("unknown state: %s" % response) > > > def __challenge_response(self, challenge): > """ generate a response to a mapi login challenge """ > challenges = challenge.split(':') > salt, identity, protocol, hashes, endian = challenges[:5] > > password = self.password > > if protocol == '9': > algo = challenges[5] > if algo == 'SHA512': > import hashlib > password = hashlib.sha512(password).hexdigest() > elif algo == 'SHA384': > import hashlib > password = hashlib.sha384(password).hexdigest() > elif algo == 'SHA256': > import hashlib > password = hashlib.sha256(password).hexdigest() > elif algo == 'SHA224': > import hashlib > password = hashlib.sha224(password).hexdigest() > elif algo == 'SHA1': > import hashlib > password = hashlib.sha1(password).hexdigest() > elif algo == 'MD5': > import hashlib > password = hashlib.md5(password).hexdigest() > else: > raise NotSupportedError("The %s hash algorithm is not " + > "supported" % algo) > elif protocol != "8": > raise NotSupportedError("We only speak protocol v8 and v9") > > 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 > > return ":".join(["BIG", self.username, pwhash, self.language, > self.database]) + ":" > > > def __getblock(self): > """ read one mapi encoded block """ > result = [] > 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] > length = unpacked >> 1 > last = unpacked & 1 > logger.debug("II: reading %i bytes" % length) > if length > 0: > result.append(self.__getbytes(length)) > > result_str = "".join(result) > logger.debug("RX: %s" % result_str) > return result_str > > > def __getbytes(self, bytes): > """Read an amount of bytes from the socket""" > try: > return self.socket.recv(bytes) > except socket.error, error: > raise OperationalError(error[1]) > > > def __putblock(self, block): > """ wrap the line in mapi format and put it into the socket """ > pos = 0 > last = 0 > while not last: > data = block[pos:pos+MAX_PACKAGE_LENGTH] > length = len(data) > if length < MAX_PACKAGE_LENGTH: > last = 1 > flag = struct.pack( '<H', ( length << 1 ) + last ) > try: > logger.debug("II: sending %i bytes, last: %s" % (length, > last)) > logger.debug("TX: %s" % data) > self.socket.send(flag) > self.socket.send(data) > except socket.error, error: > raise OperationalError(error[1]) > pos += length > > > Index: mapi.py > =================================================================== > RCS file: /cvsroot/monetdb/clients/src/python/monetdb/mapi.py,v > retrieving revision 1.17 > retrieving revision 1.18 > diff -u -d -r1.17 -r1.18 > --- mapi.py 7 Jul 2009 11:15:45 -0000 1.17 > +++ mapi.py 22 Oct 2009 10:25:35 -0000 1.18 > @@ -1,263 +1,10 @@ > -# The contents of this file are subject to the MonetDB Public License > -# Version 1.1 (the "License"); you may not use this file except in > -# compliance with the License. You may obtain a copy of the License at > -# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html > -# > -# Software distributed under the License is distributed on an "AS IS" > -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the > -# License for the specific language governing rights and limitations > -# under the License. > -# > -# The Original Code is the MonetDB Database System. > -# > -# The Initial Developer of the Original Code is CWI. > -# Portions created by CWI are Copyright (C) 1997-July 2008 CWI. > -# Copyright August 2008-2009 MonetDB B.V. > -# All Rights Reserved. > - > -""" > -this is the python 2.* implementation of the mapi API. > - > -If you use python 3.* you should use mapi3.py > -""" > - > -import socket > -import logging > -import struct > - > -from monetdb.monetdb_exceptions import * > - > - > -logger = logging.getLogger("monetdb") > - > -MAX_PACKAGE_LENGTH = (1024*8)-2 > - > -MSG_PROMPT = "" > -MSG_INFO = "#" > -MSG_ERROR = "!" > -MSG_Q = "&" > -MSG_QTABLE = "&1" > -MSG_QUPDATE = "&2" > -MSG_QSCHEMA = "&3" > -MSG_QTRANS = "&4" > -MSG_QPREPARE = "&5" > -MSG_QBLOCK = "&6" > -MSG_HEADER = "%" > -MSG_TUPLE = "[" > -MSG_REDIRECT = "^" > - > -STATE_INIT = 0 > -STATE_READY = 1 > - > - > -class Server: > - def __init__(self): > - self.state = STATE_INIT > - self._result = None > - > - def connect(self, hostname, port, username, password, database, > language): > - """ connect to a MonetDB database using the mapi protocol""" > - > - self.hostname = hostname > - self.port = port > - self.username = username > - self.password = password > - self.database = database > - self.language = language > - > - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > - > - try: > - self.socket.connect((hostname, port)) > - except socket.error, error: > - (error_code, error_str) = error > - raise OperationalError(error_str) > - > - self.__login() > - > - > - def __login(self, iteration=0): > - """ Reads challenge from line, generate response and check if > - everything is okay """ > - > - challenge = self.__getblock() > - response = self.__challenge_response(challenge) > - self.__putblock(response) > - prompt = self.__getblock().strip() > - > - if len(prompt) == 0: > - # Empty response, server is happy > - pass > - elif prompt.startswith(MSG_INFO): > - logger.info("II %s" % prompt[1:]) > - > - elif prompt.startswith(MSG_ERROR): > - logger.error(prompt[1:]) > - raise DatabaseError(prompt[1:]) > - > - 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": > - logger.debug("II: merovingian proxy, restarting " + > - "authenticatiton") > - if iteration <= 10: > - self.__login(iteration=iteration+1) > - else: > - raise OperationalError("maximal number of redirects " + > - "reached (10)") > - > - elif response[1] == "monetdb": > - self.hostname = response[2][2:] > - self.port, self.database = response[3].split('/') > - self.port = int(self.port) > - 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) > - > - else: > - logger.error('!' + prompt[0]) > - raise ProgrammingError("unknown redirect: %s" % prompt) > - > - else: > - logger.error('!' + prompt[0]) > - raise ProgrammingError("unknown state: %s" % prompt) > - > - self.state = STATE_READY > - return True > - > - > - def disconnect(self): > - """ disconnect from the monetdb server """ > - self.state = STATE_INIT > - self.socket.close() > - > - > - def cmd(self, operation): > - """ put a mapi command on the line""" > - logger.debug("II: executing command %s" % operation) > - > - if self.state != STATE_READY: > - raise(ProgrammingError, "Not connected") > - > - self.__putblock(operation) > - response = self.__getblock() > - if not len(response): > - return > - if response[0] in [MSG_Q, MSG_HEADER, MSG_TUPLE]: > - return response > - elif response[0] == MSG_ERROR: > - raise OperationalError(response[1:]) > - else: > - raise ProgrammingError("unknown state: %s" % response) > - > - > - def __challenge_response(self, challenge): > - """ generate a response to a mapi login challenge """ > - challenges = challenge.split(':') > - salt, identity, protocol, hashes, endian = challenges[:5] > - > - password = self.password > - > - if protocol == '9': > - algo = challenges[5] > - if algo == 'SHA512': > - import hashlib > - password = hashlib.sha512(password).hexdigest() > - elif algo == 'SHA384': > - import hashlib > - password = hashlib.sha384(password).hexdigest() > - elif algo == 'SHA256': > - import hashlib > - password = hashlib.sha256(password).hexdigest() > - elif algo == 'SHA224': > - import hashlib > - password = hashlib.sha224(password).hexdigest() > - elif algo == 'SHA1': > - import hashlib > - password = hashlib.sha1(password).hexdigest() > - elif algo == 'MD5': > - import hashlib > - password = hashlib.md5(password).hexdigest() > - else: > - raise NotSupportedError("The %s hash algorithm is not " + > - "supported" % algo) > - elif protocol != "8": > - raise NotSupportedError("We only speak protocol v8 and v9") > - > - 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 > - > - return ":".join(["BIG", self.username, pwhash, self.language, > - self.database]) + ":" > - > - > - def __getblock(self): > - """ read one mapi encoded block """ > - result = [] > - 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] > - length = unpacked >> 1 > - last = unpacked & 1 > - logger.debug("II: reading %i bytes" % length) > - if length > 0: > - result.append(self.__getbytes(length)) > - > - result_str = "".join(result) > - logger.debug("RX: %s" % result_str) > - return result_str > - > - > - def __getbytes(self, bytes): > - """Read an amount of bytes from the socket""" > - try: > - return self.socket.recv(bytes) > - except socket.error, error: > - raise OperationalError(error[1]) > > +import sys > > - def __putblock(self, block): > - """ wrap the line in mapi format and put it into the socket """ > - pos = 0 > - last = 0 > - while not last: > - data = block[pos:pos+MAX_PACKAGE_LENGTH] > - length = len(data) > - if length < MAX_PACKAGE_LENGTH: > - last = 1 > - flag = struct.pack( '<H', ( length << 1 ) + last ) > - try: > - logger.debug("II: sending %i bytes, last: %s" % (length, > last)) > - logger.debug("TX: %s" % data) > - self.socket.send(flag) > - self.socket.send(data) > - except socket.error, error: > - raise OperationalError(error[1]) > - pos += length > +# a ugly hack to support python 2 and 3 at the same time > +(major, minor, micro, level, serial) = sys.version_info > +if (major == 3): > + from monetdb.mapi3 import * > +else: > + from monetdb.mapi2 import * > > > > ------------------------------------------------------------------------------ > Come build with us! The BlackBerry(R) Developer Conference in SF, CA > is the only developer event you need to attend this year. Jumpstart your > developing skills, take BlackBerry mobile applications to market and stay > ahead of the curve. Join us from November 9 - 12, 2009. Register now! > http://p.sf.net/sfu/devconference > _______________________________________________ > Monetdb-checkins mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/monetdb-checkins -- Sjoerd Mullender
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------------------ Come build with us! The BlackBerry(R) Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9 - 12, 2009. Register now! http://p.sf.net/sfu/devconference
_______________________________________________ Monetdb-developers mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/monetdb-developers
