Files @ 164e41861584
Branch filter:

Location: Morevna/src/server.py - annotation

Laman
renamed command update->push
d0161c81635b
d0161c81635b
cd2ba192bf12
d0161c81635b
d0161c81635b
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
cd2ba192bf12
cd2ba192bf12
cd2ba192bf12
cd2ba192bf12
34f4027c1bd6
026618d6681b
026618d6681b
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
34f4027c1bd6
cd2ba192bf12
026618d6681b
34f4027c1bd6
34f4027c1bd6
b73a5d69a11b
8b0dc65400f3
026618d6681b
d0161c81635b
8b0dc65400f3
8b0dc65400f3
026618d6681b
8b0dc65400f3
026618d6681b
8b0dc65400f3
d0161c81635b
026618d6681b
34f4027c1bd6
cd2ba192bf12
cd2ba192bf12
cd2ba192bf12
cd2ba192bf12
026618d6681b
026618d6681b
026618d6681b
34f4027c1bd6
44cf81f3b6b8
026618d6681b
34f4027c1bd6
b73a5d69a11b
dad65188b1a0
cd2ba192bf12
dad65188b1a0
dad65188b1a0
dad65188b1a0
dad65188b1a0
dad65188b1a0
34f4027c1bd6
dad65188b1a0
dad65188b1a0
34f4027c1bd6
dad65188b1a0
dad65188b1a0
026618d6681b
dad65188b1a0
b73a5d69a11b
dad65188b1a0
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
dad65188b1a0
dad65188b1a0
dad65188b1a0
34f4027c1bd6
dad65188b1a0
d0161c81635b
dad65188b1a0
b73a5d69a11b
dad65188b1a0
dad65188b1a0
34f4027c1bd6
dad65188b1a0
34f4027c1bd6
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
34f4027c1bd6
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
44cf81f3b6b8
34f4027c1bd6
b73a5d69a11b
b73a5d69a11b
b73a5d69a11b
b73a5d69a11b
34f4027c1bd6
026618d6681b
026618d6681b
b73a5d69a11b
44cf81f3b6b8
44cf81f3b6b8
026618d6681b
44cf81f3b6b8
d0161c81635b
44cf81f3b6b8
34f4027c1bd6
dad65188b1a0
d0161c81635b
d0161c81635b
d0161c81635b
026618d6681b
026618d6681b
d0161c81635b
d0161c81635b
6355fe7d655f
026618d6681b
026618d6681b
d0161c81635b
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")