diff options
-rwxr-xr-x | tupkg/client/tupkg | 142 | ||||
-rwxr-xr-x | tupkg/server/tupkgs | 109 |
2 files changed, 240 insertions, 11 deletions
diff --git a/tupkg/client/tupkg b/tupkg/client/tupkg index ab42b437..4c0da4e3 100755 --- a/tupkg/client/tupkg +++ b/tupkg/client/tupkg @@ -8,12 +8,146 @@ # # Python Indentation: # ------------------- -# Use tabs not spaces. If you use vim, the following comment will -# configure it to use tabs. -# vim: ts=2 sw=2 noet ft=python +# For a vim: line to be effective, it must be at the end of the +# file. See the end of the file for more information. # +import sys +import socket +import os +import struct +import os.path +import cgi +import urllib +import md5 + +class ClientFile: + def __init__(self, pathname): + self.pathname = pathname + self.filename = os.path.basename(pathname) + self.fd = open(pathname, "rb") + self.fd.seek(0, 2) + self.size = self.fd.tell() + self.fd.seek(0) + self.makeMd5() + + def makeMd5(self): + md5sum = md5.new() + while self.fd.tell() != self.size: + md5sum.update(self.fd.read(1024)) + self.md5 = md5sum.hexdigest() + +class ClientSocket: + def __init__(self, files, host, port, username, password): + self.files = files + self.host = host + self.port = port + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.username = username + self.password = password + + def connect(self): + self.socket.connect((self.host, self.port)) + + def reliableRead(self, size): + totalread = "" + while len(totalread) < size: + read = self.socket.recv(size-len(totalread)) + if read == 0: + raise RuntimeError, "socket connection broken" + totalread += read + return totalread + + def sendMsg(self, msg): + if type(msg) == dict: + msg = urllib.unquote(urllib.urlencode(msg,1)) + length = struct.pack("H", socket.htons(len(msg))) + self.socket.sendall(length) + self.socket.sendall(msg) + + def readMsg(self, format=0): + initsize = self.reliableRead(2) + (length,) = struct.unpack("H", initsize) + length = socket.ntohs(length) + data = self.reliableRead(length) + if format == 1: + qs = cgi.parse_qs(data) + return qs + else: + return data + + def close(self): + self.socket.close() + + def auth(self): + msg = {'username': self.username, 'password': self.password} + self.sendMsg(msg) + reply = self.readMsg(1) + if reply['result'] == ["PASS"]: + return 1 + else: + return 0 + + def sendFileMeta(self): + msg = {'numpkgs': len(self.files)} + for i, v in enumerate(self.files): + msg['name'+str(i)] = v.filename + msg['size'+str(i)] = v.size + msg['md5sum'+str(i)] = v.md5 + self.sendMsg(msg) + reply = self.readMsg(1) + print reply + for i in reply: + if i[:4] == 'size': + self.files[int(i[4:])].cur_done = int(reply[i][0]) + + def sendFiles(self): + for i in self.files: + i.fd.seek(i.cur_done) + while i.fd.tell() < i.size: + self.socket.sendall(i.fd.read(1024)) + reply = self.readMsg(1) + print reply + self.sendMsg("ack") + +def usage(): + print "usage: tupkg <package file>" +def main(argv=None): + if argv is None: + argv = sys.argv -# TODO write the code + if len(argv) == 1: + usage() + return 1 + + try: + fil = ClientFile(argv[1]) + except IOError, err: + print "Error: " + err.strerror + ": '" + err.filename + "'" + usage() + return 1 + + cs = ClientSocket([fil], 'localhost', 1034, "bfinch@example.net", "B0b") + cs.connect() + + if not cs.auth(): + print "Error authenticating you, you bastard" + + cs.sendFileMeta() + + cs.sendFiles() + + cs.close() + + return 0 + +if __name__ == "__main__": + sys.exit(main()) + +# Python Indentation: +# ------------------- +# Use tabs not spaces. If you use vim, the following comment will +# configure it to use tabs. # +# vim:noet:ts=2 sw=2 ft=python diff --git a/tupkg/server/tupkgs b/tupkg/server/tupkgs index b4a3e867..ef010c94 100755 --- a/tupkg/server/tupkgs +++ b/tupkg/server/tupkgs @@ -18,25 +18,119 @@ import sys import socket import threading import select +import struct +import cgi +import urllib +import md5 + +CACHEDIR = '/var/cache/tupkgs/' + +class ClientFile: + def __init__(self, filename, actual_size, actual_md5): + self.pathname = CACHEDIR + filename + self.filename = filename + self.fd = open(self.pathname, "w+b") + self.actual_size = actual_size + self.actual_md5 = actual_md5 + + def getSize(self): + cur = self.fd.tell() + self.fd.seek(0,2) + self.size = self.fd.tell() + self.fd.seek(cur) + + def makeMd5(self): + md5sum = md5.new() + cur = self.fd.tell() + self.getSize() + self.fd.seek(0) + while self.fd.tell() != self.size: + md5sum.update(self.fd.read(1024)) + self.fd.seek(cur) + self.md5 = md5sum.hexdigest() class ClientSocket(threading.Thread): - def __init__(self, socket, **other): + def __init__(self, sock, **other): threading.Thread.__init__(self, *other) - self.socket = socket + self.socket = sock + self.running = 1 + self.files = [] def close(self): - pass + self.running = 0 + + def reliableRead(self, size): + totalread = "" + while len(totalread) < size: + read = self.socket.recv(size-len(totalread)) + if read == 0: + raise RuntimeError, "socket connection broken" + totalread += read + return totalread + + def sendMsg(self, msg): + if type(msg) == dict: + msg = urllib.unquote(urllib.urlencode(msg,1)) + length = struct.pack("H", socket.htons(len(msg))) + self.socket.sendall(length) + self.socket.sendall(msg) + + def readMsg(self, format=0): + initsize = self.reliableRead(2) + (length,) = struct.unpack("H", initsize) + length = socket.ntohs(length) + data = self.reliableRead(length) + if format == 1: + qs = cgi.parse_qs(data) + return qs + else: + return data + + def auth(self): + authdata = self.readMsg() + print authdata + # Do auth stuff here + self.sendMsg("result=PASS") + + def readFileMeta(self): + files = self.readMsg(1) + print files + # Actually do file checking, et al + for i in range(int(files['numpkgs'][0])): + self.files.append(ClientFile(files['name'+str(i)][0], int(files['size'+str(i)][0]), files['md5sum'+str(i)][0])) + new_files = files.copy() + for i in files: + if i[:4] == 'size': + new_files[i] = '0' + if i[:6] == 'md5sum': + del new_files[i] + self.sendMsg(new_files) + + def readFiles(self): + for i in self.files: + i.fd.write(self.reliableRead(i.actual_size)) + i.fd.flush() + reply = {'numpkgs': len(self.files)} + for i, v in enumerate(self.files): + v.makeMd5() + if v.actual_md5 == v.md5: + reply['md5sum'+str(i)] = "PASS" + else: + reply['md5sum'+str(i)] = "FAIL" + self.sendMsg(reply) + print self.readMsg() def run(self): - while len(self.socket.recv(1)) != 0: - pass + self.auth() + self.readFileMeta() + self.readFiles() class ServerSocket(threading.Thread): def __init__(self, port=1034, maxqueue=5, **other): threading.Thread.__init__(self, *other) self.running = 1 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.bind((socket.gethostname(), port)) + self.socket.bind(('', port)) self.socket.listen(maxqueue) self.clients = [] @@ -47,6 +141,7 @@ class ServerSocket(threading.Thread): def close(self): self.socket.close() + self.running = 0 def run(self): while self.running: @@ -82,7 +177,7 @@ def main(argv=None): print "Just cleaning up stuff" - servsock.running = 0 + servsock.close() servsock.join() |