Hi, I assume that hanging is not the proper behavior for freenetlib.py when it encounters a non-existant key. It has been doing that for the last week or so - I have only been testing sporadically in that time. I believe that it didn't do it before - though I think I only test few successfully.
Most of my testing has been simulating freenet as a black box - just write-once dictionary. Hopefully, this still should "theoretically." I set the host to a remote host and changed the test string to gibberish and the module just hangs on receive message from the sock. I have tried a couple of servers and it does it with all of them. I am attaching my modified version of freenetlib.py - all the mods have "jsolbrig" in the comment -------------- next part -------------- #!/usr/bin/env python # A Freenet client module. May rapidly change during the development of # the Freenet protocal. # # freenetlib.py 0.03 # # Copyright (C) 2000 Travis Bemann, Itamar Shtull-Trauring # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # more information on Freenet is availiable at http://freenet.sourceforge.net/ import re import socket import string import os import whrandom import sha import struct import sys # Default values for Freenet init parameters #FREENET_DEFAULT_HOST = 'localhost' jsolbrig FREENET_DEFAULT_HOST = socket.gethostbyaddr('63.248.222.29')[0] FREENET_DEFAULT_PORT = 19114 FREENET_DEFAULT_SEARCH_DEPTH = 10 FREENET_VERSION = '1.2' FREENET_DEFAULT_MIN_DEPTH = 5 FREENET_DEFAULT_MAX_DEPTH = 30 FREENET_DEFAULT_KEEP_ALIVE = 1 FREENET_DEFAULT_AUTO_CONNECT = 1 DEBUG = 0 error_reply = 'freenetlib.error_reply' error_uniqueid = 'freenetlib.error_uniqueid' error_version = 'freenetlib.error_version' error_nodata = 'freenetlib.error_nodata' error_keyexists = 'freenetlib.error_keyexists' # Note - This is a slightly modified version of a bit of Python # code sent to me by Bill Trost <trost at cloud.rain.com>. # This is fast as in it is fast to use in a program, not that the # implementation used is necessarily fast. def quick_sha1(s): return "%X%X%X%X%X" % struct.unpack("!lllll", sha.new(s).digest()) class Freenet: # Initialize an instance # - host: host of FreeNet server # - port: port of FreeNet server # - search_depth: maximum key search depth # - min_depth: minimum starting message depth # - max_depth: maximum starting message depth # - keep_alive: whether to keep the connection open # - auto_connect: whether to handshake automatically def __init__(self, host = FREENET_DEFAULT_HOST, port = FREENET_DEFAULT_PORT, search_depth = FREENET_DEFAULT_SEARCH_DEPTH, min_depth = FREENET_DEFAULT_MIN_DEPTH, max_depth = FREENET_DEFAULT_MAX_DEPTH, keep_alive = FREENET_DEFAULT_KEEP_ALIVE, auto_connect = FREENET_DEFAULT_AUTO_CONNECT): self.host = host self.port = port if search_depth < 1: raise ValueError, \ 'search_depth must be larger than zero' self.search_depth = search_depth if min_depth < 1: raise ValueError, 'min_depth must be larger than zero' if max_depth < 1: raise ValueError, 'max_depth must be larger than zero' if min_depth > max_depth: raise ValueError, \ 'min_depth may not be larger than max_depth' self.min_depth = min_depth self.max_depth = max_depth self.keep_alive = keep_alive self.response_closed = 1 if auto_connect: self.connect() def sendmesg(self, type, items, datafile=None, datalength=0): """ Construct message from dictionary, with optional file for data """ if DEBUG: print "Sent:", type, items f = self.file f.write(type + '\n') for key, value in items.items(): f.write("%s=%s\n" % (key, value)) if datafile: if datalength: f.write("DataLength=%s\n" % datalength) f.write("Data\n") line = datafile.readline() while line: f.write(line) line = datafile.readline() else: datafile.seek(0, 2) datalength = datafile.tell() datafile.seek(0, 0) f.write('DataLength=%s\n' % datalength) f.write('Data\n') line = datafile.readline() while line: f.write(line) line = datafile.readline() else: f.write("EndMessage\n") f.flush() def recvmesg(self, savefile=None): """ Read a message, writing it to a given file if need be """ f = self.file dict = {} messagetype = string.rstrip(f.readline()) line = string.rstrip(f.readline()) while line and (line not in ['Data', 'EndMessage']): key, value = string.split(line, '=') dict[key] = value line = string.rstrip(f.readline()) if line == 'Data': #if not dict.has_key('DataLength'): # raise error_nodatalength, "Message has Data but no DataLength." line = f.readline() readlength = 0 while line: savefile.write(line) readlength = readlength + len(line) line = f.readline() #if readlength != int(dict['DataLength']): # raise error_nodata, """DataLength supposed to be %s, but # actual Data length is %s.""" % (dict['DataLength'], readlength) if DEBUG: print "Received:", messagetype, dict return messagetype, dict def getranduniqueid(self): """ Generate 64 bit hex id number """ max = pow(2, 16) - 1 result = "" for i in range(0, 4): result = result + ("%04x" % whrandom.randint(0, max)) # the server strip leading 0 from uniqueids, so we do the same while result[0] == '0': result = result[1:] return result def getranddepth(self): """ Returns a random number between self.min_depth and self.max_depth. """ return whrandom.randint(self.min_depth, self.max_depth) def connect(self): """ Connect to server """ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(self.host, self.port) self.response_closed = 0 self.file = self.sock.makefile('rb+') self._handshake() def close(self): """ close from server """ self.response_closed = 1 self.sock.close() def _handshake(self): """ Handshake with server. """ uid = self.getranduniqueid() if self.keep_alive: keep_alive = 'true' else: keep_alive = 'false' self.sendmesg('HandshakeRequest', {'UniqueID': uid, 'Depth': 1, 'HopsToLive': self.search_depth, 'KeepAlive': keep_alive}) type, items = self.recvmesg() if type == 'HandshakeRequest': try: self.sendmesg('HandshakeReply', {'UniqueID': items['UniqueID'], 'Depth': items['Depth'], 'HopsToLive': items['HopsToLive'], 'KeepAlive': keep_alive, 'Version': FREENET_VERSION}) except KeyError: self.close() raise error_reply, \ 'Necessary request fields are missing' elif type == 'HandshakeReply': try: if items['Version'] != FREENET_VERSION: self.close() raise error_version, \ 'Incompatible FreeNet version' if items['UniqueID'] != uid: self.close() raise error_uniqueid, \ 'Incorrect unique ID' except KeyError: raise error_version, \ 'Necessary reply fields are missing' else: self.close() raise error_reply, 'Unexpected message type' def insert(self, key, datafile, datalength = None): """ Insert file under key key: key to insert file under (unencrypted) data: file data """ if not self.keep_alive and self.response_closed: self.connect() uid = self.getranduniqueid() if self.keep_alive: keep_alive = 'true' else: keep_alive = 'false' self.sendmesg('InsertRequest', {'UniqueID': uid, 'Depth': self.getranddepth(), 'HopsToLive': self.search_depth, 'KeepAlive': keep_alive, 'Source': 'tcp/127.0.0.1:19114', 'SearchKey': quick_sha1(key)}) type, items = self.recvmesg() if type == 'RequestFailed': if not self.keep_alive: self.close() raise error_reply, 'Request failed' elif type == 'DataReply': if not self.keep_alive: self.close() raise error_keyexists, 'Key already exists' elif type == 'TimedOut': if not self.keep_alive: self.close() raise error_nodata, \ 'Key already exists but no data was found' elif type == 'InsertReply': if items['UniqueID'] != uid: if not self.keep_alive: self.close() raise error_uniqueid, \ 'Unique ID mismatch' self.sendmesg('DataInsert', {'UniqueID': uid, 'Depth': self.getranddepth(), 'HopsToLive': self.search_depth, 'KeepAlive': keep_alive, 'Source': 'tcp/127.0.0.1:19114', 'DataSource': 'tcp/127.0.0.1:19114'}, datafile, datalength) else: if not self.keep_alive: self.close() raise error_reply, 'Unexpected message type' if not self.keep_alive: self.close() def request(self, key, savefile=sys.stdout): """ Request file under key key: key to request file from (unencrypted) returns: file data """ if not self.keep_alive and self.response_closed: self.connect() uid = self.getranduniqueid() if self.keep_alive: keep_alive = 'true' else: keep_alive = 'false' self.sendmesg('DataRequest', {'UniqueID': uid, 'Depth': self.getranddepth(), 'HopsToLive': self.search_depth, 'KeepAlive': keep_alive, 'Source': 'tcp/127.0.0.1:19114', 'SearchKey': quick_sha1(key)}) type, items = self.recvmesg(savefile) if type == 'RequestFailed': if not self.keep_alive: self.close() raise error_reply, 'Request failed' elif type == 'TimedOut': if not self.keep_alive: self.close() raise error_keyexists, \ 'Key exists but no data was found' elif type == 'DataReply': if items['UniqueID'] != uid: if not self.keep_alive: self.close() raise error_uniqueid, \ 'Unique ID mismatch' return None else: if not self.keep_alive: self.close() raise error_reply, 'Unexpected message type' return None # shouldn't happen(?) if __name__ == '__main__': fn = Freenet() #fn.request("keyindex.pl") jsolbrig fn.request("asdfsadf")
