#!/usr/bin/python
import struct, socket, sys, time
# Working: nbd protocol, read/write serving up files, error handling, file size detection, in theory, large file support... not really, so_reuseaddr, nonforking
def recvall(sock, length):
rv = []
while sum(map(len, rv)) < length:
rv.append(sock.recv(length-sum(map(len, rv))))
assert rv[-1], "no more data to read"
return ''.join(rv)
def serveclient():
READ, WRITE, CLOSE = 0,1,2
"Serves a single client until it exits."
afile.seek(0, 2)
asock.send('NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53' + struct.pack('>Q', afile.tell()) + '\0'*128);
while True:
header = recvall(asock, struct.calcsize('>LL8sQL'))
magic, request, handle, offset, dlen = struct.unpack('>LL8sQL', header)
assert magic == 0x25609513
if request == READ:
afile.seek(offset)
asock.send('gDf\x98\0\0\0\0'+handle)
asock.send(afile.read(dlen))
print "read\t0x%08x\t0x%08x" % (offset, dlen), time.time()
elif request == WRITE:
afile.seek(offset)
afile.write(recvall(asock, dlen))
afile.flush()
asock.send('gDf\x98\0\0\0\0'+handle)
print "write\t0x%08x\t0x%08x" % (offset, dlen), time.time()
elif request == CLOSE:
asock.close()
print "closed"
return
else:
print "ignored request", request
if __name__ == '__main__':
"Given a port and a filename, serves up the file."
afile = file(sys.argv[2], 'rb+')
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
lsock.bind(('', int(sys.argv[1])))
lsock.listen(5)
while True:
(asock, addr) = lsock.accept()
print "connection from", addr
serveclient()