Files
@ 08a31c3a463d
Branch filter:
Location: Morevna/src/server.py
08a31c3a463d
3.6 KiB
text/x-python
certs in a separate dir
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import hashlib
import socket
import ssl
import logging as log
from hashtree import HashTree
from networkers import NetworkReader,NetworkWriter
import config as conf
class Connection:
def __init__(self,serverSocket,sslContext):
sock, address = serverSocket.accept()
self._socket=sslContext.wrap_socket(sock,server_side=True)
log.info('Connected by {0}'.format(address))
fr=self._socket.makefile(mode="rb")
fw=self._socket.makefile(mode="wb")
self.incoming=NetworkReader(fr)
self.outcoming=NetworkWriter(fw)
def __enter__(self):
return self.incoming,self.outcoming
def __exit__(self, exc_type, exc_val, exc_tb):
self._socket.shutdown(socket.SHUT_RDWR)
self._socket.close()
class Server:
def __init__(self,filename,treeFile=""):
self._filename=filename
self._treeFile=treeFile
if treeFile:
self._tree=HashTree.load(treeFile)
else:
self._tree=HashTree.fromFile(filename)
self._newLeaves=dict()
self.BLOCK_SIZE=self._tree.BLOCK_SIZE
self._ssl=ssl.create_default_context(ssl.Purpose.CLIENT_AUTH,cafile=conf.peers)
self._ssl.verify_mode=ssl.CERT_REQUIRED
self._ssl.load_cert_chain(conf.certfile,conf.keyfile)
self._ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._ss.bind(("", conf.port))
self._ss.listen(1)
self._lastIndex=-1
self._dataFile=None
def serve(self):
while True:
with Connection(self._ss,self._ssl) as (incoming, outcoming):
try:
while True:
if not self._serveOne(incoming,outcoming): return
except AssertionError:
continue
def _serveOne(self,incoming,outcoming):
jsonData,binData=incoming.readMsg()
if jsonData["command"]=="init":
assert jsonData["blockSize"]==self.BLOCK_SIZE
assert jsonData["blockCount"]==self._tree.leafCount
outcoming.writeMsg({"command": "ack"})
elif jsonData["command"]=="req":
if jsonData["dataType"]=="data":
outcoming.writeMsg(*self._requestData(jsonData["index"]))
else:
outcoming.writeMsg(*self._requestHash(jsonData["index"]))
elif jsonData["command"]=="send" and jsonData["dataType"]=="data":
outcoming.writeMsg(*self._receiveData(jsonData,binData))
elif jsonData["command"]=="end":
self._finalize()
return False
else:
assert False, jsonData["command"]
return True
def _requestHash(self,index):
log.info("received request for node #{0}".format(index))
assert index<len(self._tree.store)
nodeHash=self._tree.store[index]
jsonResponse={"command":"send", "index":index, "dataType":"hash"}
binResponse=nodeHash
return (jsonResponse,binResponse)
def _requestData(self,index):
log.info("received request for data block #{0}".format(index))
jsonResponse={"command":"send", "index":index, "dataType":"data"}
if self._lastIndex+1!=index:
self._dataFile.seek(index*self.BLOCK_SIZE)
binResponse=self._dataFile.read(self.BLOCK_SIZE)
return (jsonResponse,binResponse)
def _receiveData(self,jsonData,binData):
log.info("received data block #{0}: {1}...{2}".format(jsonData["index"],binData[:5],binData[-5:]))
if not self._dataFile:
self._dataFile=open(self._filename, mode="rb+")
i=jsonData["index"]
if self._lastIndex+1!=i:
self._dataFile.seek(i*self.BLOCK_SIZE)
self._dataFile.write(binData)
self._lastIndex=i
if self._treeFile:
self._newLeaves[i+self._tree.leafStart]=hashlib.sha256(binData).digest()[HashTree.HASH_LEN:]
return ({"command": "ack", "index": i},)
def _finalize(self):
log.info("closing session...")
if self._dataFile:
self._dataFile.close()
if self._treeFile:
log.info("updating hash tree...")
for (k,v) in self._newLeaves.items():
self._tree.updateLeaf(k, v)
self._tree.save(self._treeFile)
log.info("done")
|