aurweb/tupkg/server/tupkgs

194 lines
4.5 KiB
Python
Executable file

#!/usr/bin/python -O
#
# Description:
# ------------
# This is the server-side portion of the Trusted User package
# manager. This program will receive uploads from its client-side
# couterpart, tupkg. Once a package is received and verified, it
# is placed in a specified temporary incoming directory where
# a separate script will handle migrating it to the AUR. For
# more information, see the ../README.txt file.
#
# Python Indentation:
# -------------------
# 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 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, sock, **other):
threading.Thread.__init__(self, *other)
self.socket = sock
self.running = 1
self.files = []
def close(self):
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):
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(('', port))
self.socket.listen(maxqueue)
self.clients = []
def _clean(self, client):
if not client.isAlive():
return 0
return 1
def close(self):
self.socket.close()
self.running = 0
def run(self):
while self.running:
sread, swrite, serror = select.select([self.socket],[self.socket],[self.socket],5)
if sread:
(clientsocket, address) = self.socket.accept()
ct = ClientSocket(clientsocket)
ct.start()
self.clients.append(ct)
print len(self.clients)
self.clients = filter(self._clean, self.clients)
print len(self.clients)
self.socket.close()
[x.close() for x in self.clients]
[x.join() for x in self.clients]
def main(argv=None):
if argv is None:
argv = sys.argv
running = 1
servsock = ServerSocket()
servsock.start()
try:
while running:
# Maybe do stuff here?
pass
except KeyboardInterrupt:
running = 0
print "Just cleaning up stuff"
servsock.close()
servsock.join()
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