| @@ -0,0 +1,2 @@ | |||
| *.pyc | |||
| elmo/* | |||
| @@ -0,0 +1,11 @@ | |||
| # ELMO Online | |||
| ELMO Online is a Python library which proposes an encapsulation of the binary project ELMO. | |||
| [MOW17] **Towards Practical Tools for Side | |||
| Channel Aware Software Engineering : ’Grey Box’ Modelling for Instruction Leakages** | |||
| by _David McCann, Elisabeth Oswald et Carolyn Whitnall_. | |||
| https://www.usenix.org/conference/ | |||
| usenixsecurity17/technical-sessions/presentation/mccann. | |||
| **ELMO GitHub**: https://github.com/sca-research/ELMO | |||
| @@ -0,0 +1,192 @@ | |||
| import numpy as np | |||
| import os | |||
| def hweight(n): | |||
| c = 0 | |||
| while n>0: | |||
| c += (n & 1) | |||
| n >>= 1 | |||
| return c | |||
| def hdistance(x,y): | |||
| return hweight(x^y) | |||
| def binary_writing(n, nb_bits=32, with_hamming=False): | |||
| n = np.array(n) | |||
| w, h = np.zeros((nb_bits, len(n))), np.zeros((len(n))) | |||
| for ind in range(nb_bits): | |||
| w[ind] = (n & 1) | |||
| h += w[ind] | |||
| n >>= 1 | |||
| ind += 1 | |||
| return (w, h) if with_hamming else w | |||
| PREVIOUS = 0 | |||
| CURRENT = 1 | |||
| SUBSEQUENT = 2 | |||
| class ELMOEngine: | |||
| def __init__(self): | |||
| self.load_coefficients() | |||
| self.reset_points() | |||
| def _extract_data(self, nb): | |||
| coeffs = self.coefficients[self.pos:self.pos+nb] | |||
| self.pos += nb | |||
| return coeffs | |||
| def load_coefficients(self): | |||
| filename = os.path.dirname(os.path.abspath(__file__))+'/elmo/coeffs.txt' | |||
| self.coefficients = None | |||
| with open(filename, 'r') as _file: | |||
| self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]]) | |||
| if self.coefficients is None: | |||
| raise IOError('Problem to read the coefficients.') | |||
| self.pos = 0 | |||
| self.constant = np.squeeze(self._extract_data(1)) | |||
| self.PrvInstr = self._extract_data(4) | |||
| self.SubInstr = self._extract_data(4) | |||
| self.Operand1 = self._extract_data(32) | |||
| self.Operand2 = self._extract_data(32) | |||
| self.BitFlip1 = self._extract_data(32) | |||
| self.BitFlip2 = self._extract_data(32) | |||
| self.HWOp1PrvInstr = self._extract_data(4) | |||
| self.HWOp2PrvInstr = self._extract_data(4) | |||
| self.HDOp1PrvInstr = self._extract_data(4) | |||
| self.HDOp2PrvInstr = self._extract_data(4) | |||
| self.HWOp1SubInstr = self._extract_data(4) | |||
| self.HWOp2SubInstr = self._extract_data(4) | |||
| self.HDOp1SubInstr = self._extract_data(4) | |||
| self.HDOp2SubInstr = self._extract_data(4) | |||
| self.Operand1_bitinteractions = self._extract_data(496) | |||
| self.Operand2_bitinteractions = self._extract_data(496) | |||
| self.BitFlip1_bitinteractions = self._extract_data(496) | |||
| self.BitFlip2_bitinteractions = self._extract_data(496) | |||
| def reset_points(self): | |||
| self.points = [] | |||
| self.power = None | |||
| def add_point(self, triplet, previous_ops, current_ops): | |||
| self.points.append((triplet, previous_ops, current_ops)) | |||
| def _dot(self, a, b): | |||
| return np.sum(a * b, axis=0) | |||
| def calculate_point(self, triplet, previous_ops, current_ops, debug=False): | |||
| nb_points = triplet.shape[1] | |||
| instructiontype = triplet[CURRENT] | |||
| instructiontype = instructiontype % 5 # Type 5 = Instruction was not profiled | |||
| # Previous | |||
| previous_instruction_typedec = triplet[PREVIOUS] | |||
| previous_instruction_type = np.zeros((5, nb_points)) | |||
| for i in range(nb_points): | |||
| if previous_instruction_typedec[i] < 5: | |||
| previous_instruction_type[previous_instruction_typedec[i],i] = 1 | |||
| # Current | |||
| (current_op1_binary, hw_op1) = binary_writing(current_ops[0], with_hamming=True) | |||
| (current_op2_binary, hw_op2) = binary_writing(current_ops[1], with_hamming=True) | |||
| (current_op1_bitflip, hd_op1) = binary_writing(previous_ops[0] ^ current_ops[0], with_hamming=True) | |||
| (current_op2_bitflip, hd_op2) = binary_writing(previous_ops[1] ^ current_ops[1], with_hamming=True) | |||
| current_instruction_typedec = instructiontype | |||
| current_instruction_type = np.zeros((5, nb_points)) | |||
| for i in range(nb_points): | |||
| if triplet[CURRENT,i] < 5: | |||
| current_instruction_type[current_instruction_typedec[i],i] = 1 | |||
| # Subsequent | |||
| subsequent_instruction_typedec = triplet[SUBSEQUENT] | |||
| subsequent_instruction_type = np.zeros((5, nb_points)) | |||
| for i in range(nb_points): | |||
| if subsequent_instruction_typedec[i] < 5: | |||
| subsequent_instruction_type[subsequent_instruction_typedec[i],i] = 1 | |||
| # Component variables | |||
| PrvInstr_data = self._dot( previous_instruction_type[1:], self.PrvInstr[:,instructiontype] ) | |||
| SubInstr_data = self._dot( subsequent_instruction_type[1:], self.SubInstr[:,instructiontype] ) | |||
| Operand1_data = self._dot( current_op1_binary, self.Operand1[:,instructiontype] ) | |||
| Operand2_data = self._dot( current_op2_binary, self.Operand2[:,instructiontype] ) | |||
| BitFlip1_data = self._dot( current_op1_bitflip, self.BitFlip1[:,instructiontype] ) | |||
| BitFlip2_data = self._dot( current_op2_bitflip, self.BitFlip2[:,instructiontype] ) | |||
| HWOp1PrvInstr_data = hw_op1 * self._dot(previous_instruction_type[1:], self.HWOp1PrvInstr[:,instructiontype]) | |||
| HWOp2PrvInstr_data = hw_op2 * self._dot(previous_instruction_type[1:], self.HWOp2PrvInstr[:,instructiontype]) | |||
| HDOp1PrvInstr_data = hd_op1 * self._dot(previous_instruction_type[1:], self.HDOp1PrvInstr[:,instructiontype]) | |||
| HDOp2PrvInstr_data = hd_op2 * self._dot(previous_instruction_type[1:], self.HDOp2PrvInstr[:,instructiontype]) | |||
| HWOp1SubInstr_data = hw_op1 * self._dot(subsequent_instruction_type[1:], self.HWOp1SubInstr[:,instructiontype]) | |||
| HWOp2SubInstr_data = hw_op2 * self._dot(subsequent_instruction_type[1:], self.HWOp2SubInstr[:,instructiontype]) | |||
| HDOp1SubInstr_data = hd_op1 * self._dot(subsequent_instruction_type[1:], self.HDOp1SubInstr[:,instructiontype]) | |||
| HDOp2SubInstr_data = hd_op2 * self._dot(subsequent_instruction_type[1:], self.HDOp2SubInstr[:,instructiontype]) | |||
| Operand1_bitinteractions_data = np.zeros((nb_points)) | |||
| Operand2_bitinteractions_data = np.zeros((nb_points)) | |||
| BitFlip1_bitinteractions_data = np.zeros((nb_points)) | |||
| BitFlip2_bitinteractions_data = np.zeros((nb_points)) | |||
| count = 0 | |||
| for i in range(32): | |||
| for j in range(i+1,32): | |||
| Operand1_bitinteractions_data += self.Operand1_bitinteractions[count,instructiontype] * current_op1_binary[i] * current_op1_binary[j] | |||
| Operand2_bitinteractions_data += self.Operand2_bitinteractions[count,instructiontype] * current_op2_binary[i] * current_op2_binary[j] | |||
| BitFlip1_bitinteractions_data += self.BitFlip1_bitinteractions[count,instructiontype] * current_op1_bitflip[i] * current_op1_bitflip[j] | |||
| BitFlip2_bitinteractions_data += self.BitFlip2_bitinteractions[count,instructiontype] * current_op2_bitflip[i] * current_op2_bitflip[j] | |||
| count += 1 | |||
| power = self.constant[instructiontype] \ | |||
| + PrvInstr_data + SubInstr_data \ | |||
| + Operand1_data + Operand2_data \ | |||
| + BitFlip1_data + BitFlip2_data \ | |||
| + HWOp1PrvInstr_data + HWOp2PrvInstr_data \ | |||
| + HDOp1PrvInstr_data + HDOp2PrvInstr_data \ | |||
| + HWOp1SubInstr_data + HWOp2SubInstr_data \ | |||
| + HDOp1SubInstr_data + HDOp2SubInstr_data \ | |||
| + Operand1_bitinteractions_data + Operand2_bitinteractions_data \ | |||
| + BitFlip1_bitinteractions_data + BitFlip2_bitinteractions_data | |||
| for i in range(nb_points): | |||
| if triplet[CURRENT,i] == 5: | |||
| power[i] = self.constant[triplet[CURRENT,i]] | |||
| if debug: | |||
| print([self.constant[instructiontype], \ | |||
| PrvInstr_data, SubInstr_data, \ | |||
| Operand1_data, Operand2_data, \ | |||
| BitFlip1_data, BitFlip2_data, \ | |||
| HWOp1PrvInstr_data, HWOp2PrvInstr_data, \ | |||
| HDOp1PrvInstr_data, HDOp2PrvInstr_data, \ | |||
| HWOp1SubInstr_data, HWOp2SubInstr_data, \ | |||
| HDOp1SubInstr_data, HDOp2SubInstr_data, \ | |||
| Operand1_bitinteractions_data, Operand2_bitinteractions_data, \ | |||
| BitFlip1_bitinteractions_data, BitFlip2_bitinteractions_data]) | |||
| return power | |||
| def run(self): | |||
| nb_points = len(self.points) | |||
| triplet = np.array([p[0] for p in self.points]).T # shape = (3, nb_points) | |||
| previous_ops = np.array([p[1] for p in self.points]).T # shape = (2, nb_points) | |||
| current_ops = np.array([p[2] for p in self.points]).T # shape = (2, nb_points) | |||
| self.power = self.calculate_point(triplet, previous_ops, current_ops) | |||
| def oneshot_point(self, triplet, previous_ops, current_ops): | |||
| self.reset_points() | |||
| self.add_point(triplet, previous_ops, current_ops) | |||
| self.run() | |||
| return self.power | |||
| @@ -0,0 +1,66 @@ | |||
| from servicethread import OneShotServiceThread | |||
| import subprocess | |||
| import shutil | |||
| from project_reader import ProjectReader | |||
| global_variables = {} | |||
| class ExecutorThread(OneShotServiceThread): | |||
| def __init__(self, ip, port, clientsocket, **kwargs): | |||
| super().__init__(ip, port, clientsocket) | |||
| self.projects = kwargs['projects'] if 'projects' in kwargs else None | |||
| def execute(self): | |||
| projects = self.projects | |||
| if project is None: | |||
| reader = ProjectReader() | |||
| projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||
| print('Warning: need to research the projects.') | |||
| else: | |||
| print('Already have projects') | |||
| data = self.protocol.get_data() | |||
| self.protocol.please_assert(data) | |||
| self.protocol.please_assert('project' in data) | |||
| self.protocol.please_assert(data['project'] in projects) | |||
| self.protocol.send_ack() | |||
| # Get the project | |||
| project = projects[data['project']] | |||
| # Make the compilation | |||
| if False: | |||
| print('Compiling binary...') | |||
| # Adapt the project source | |||
| with open('binaries/Frodo/frodo-base.c', 'r') as _src_file: | |||
| content = _src_file.read() | |||
| with open('binaries/Frodo/frodo.c', 'w') as _dst_file: | |||
| _dst_file.write(content.replace('%NEED_TO_FILL%', str(n))) | |||
| # Compile the project | |||
| make_directory = 'projects/{}/{}'.format(project.get_project_directory(), project.get_make_directory()) | |||
| process = subprocess.Popen('make', shell=True, cwd=make_directory, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
| output, error = process.communicate() | |||
| if error and ('error' in error.decode('latin-1')): | |||
| print("Error to compile") | |||
| print(error) | |||
| raise Exception() | |||
| # Save last compilation data | |||
| global_variables[project_name] = { | |||
| 'last_n': n, | |||
| } | |||
| # Generate the trace by launching ELMO | |||
| command = './elmo ../projects/{}/{}'.format(project.get_project_directory(), project.get_binary()) | |||
| process = subprocess.Popen(command, shell=True, cwd='elmo_online/elmo/', executable='/bin/bash', stdout=subprocess.PIPE) | |||
| output, error = process.communicate() | |||
| # Send results | |||
| self.protocol.send_data({ | |||
| 'output': output.decode('latin-1') if output else None, | |||
| 'error': error.decode('latin-1') if error else None, | |||
| }) | |||
| self.protocol.close() | |||
| @@ -0,0 +1,6 @@ | |||
| from .project_reader import Project | |||
| reader = ProjectReader() | |||
| projects = reader.get_projects() | |||
| for key, project in projects.items(): | |||
| globals()[key] = project | |||
| @@ -0,0 +1,39 @@ | |||
| from servicethread import PermanentServiceThread | |||
| import socket | |||
| class ListeningThread(PermanentServiceThread): | |||
| def __init__(self, host, port, threadclass, **kwargs): | |||
| super().__init__() | |||
| self.hostname = host | |||
| self.port = port | |||
| self.threadclass = threadclass | |||
| self.kwargs = kwargs | |||
| def execute(self): | |||
| self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
| self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |||
| self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |||
| # self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_ATTACH_REUSEPORT_CBPF, 1) | |||
| self.tcpsock.bind((self.hostname, self.port)) | |||
| self.tcpsock.listen(5) | |||
| print('[port][%s] Listening' % self.port) | |||
| while self.is_running(): | |||
| try: | |||
| (clientsocket, (ip, port)) = self.tcpsock.accept() | |||
| print('[port][{}] Accepted: {} <=> {}'.format( | |||
| self.port, | |||
| clientsocket.getsockname(), | |||
| clientsocket.getpeername(), | |||
| )) | |||
| newthread = self.threadclass(ip, port, clientsocket, **self.kwargs) | |||
| newthread.start() | |||
| except socket.timeout: | |||
| pass | |||
| def stop(self): | |||
| super().stop() | |||
| clientsocker = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
| clientsocker.connect( (self.hostname, self.port) ) | |||
| self.tcpsock.close() | |||
| print('[port][%s] Stop listening' % self.port) | |||
| @@ -0,0 +1,214 @@ | |||
| import os, re | |||
| import socket | |||
| from protocol import SocketTool | |||
| import numpy as np | |||
| def to_hex(v, nb_bits=16): | |||
| try: | |||
| v_hex = v.hex() | |||
| except AttributeError: | |||
| v_hex = hex(v)[2:] | |||
| return '0'*(nb_bits//4-len(v_hex)) + v_hex | |||
| def split_octet(hexstr): | |||
| return [hexstr[i:i+2] for i in range(0, len(hexstr), 2)] | |||
| def to_signed_hex(v, nb_bits=16): | |||
| return split_octet(to_hex(v & (2**nb_bits-1), nb_bits=nb_bits)) | |||
| def write(_input, uintXX, nb_bits=16): | |||
| uintXX = to_signed_hex(uintXX, nb_bits=nb_bits) | |||
| for i in range(nb_bits//8): | |||
| _input.write(uintXX[i]+'\n') | |||
| def write_list(_input, uint16_list): | |||
| for uint16 in uint16_list: | |||
| write(_input, uint16) | |||
| def launch_simulation(quiet=False, **kwargs): | |||
| try: | |||
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
| s.connect(('localhost', 5000)) | |||
| SocketTool.send_data(s, kwargs) | |||
| if not SocketTool.get_ack(s): | |||
| raise RuntimeError("The request has been refused !") | |||
| else: | |||
| data = SocketTool.get_data(s) | |||
| if data['error'] and not quiet: | |||
| raise Exception("The simulation return an error") | |||
| return data['output'], data['error'] | |||
| s.close() | |||
| except IOError: | |||
| raise RuntimeError("The connection refused. Has the ELMO server been switch on ?") | |||
| class SimulationProject: | |||
| _nb_bits_for_nb_challenges = 16 | |||
| _project_directory = None | |||
| ### Define the project | |||
| @classmethod | |||
| def get_project_directory(cl): | |||
| if cl._project_directory: | |||
| return cl._project_directory | |||
| else: | |||
| raise NotImplementedError() | |||
| @classmethod | |||
| def set_project_directory(cl, project_directory): | |||
| cl._project_directory = project_directory | |||
| @classmethod | |||
| def get_project_label(cl): | |||
| return cl.get_project_directory() | |||
| @classmethod | |||
| def get_make_directory(cl): | |||
| return '' | |||
| @classmethod | |||
| def get_binary(cl): | |||
| raise NotImplementedError() | |||
| @classmethod | |||
| def get_parameters_names(cl): | |||
| return set() | |||
| @classmethod | |||
| def adapt_project(cl, parameters): | |||
| return | |||
| def get_challenge_format(self): | |||
| raise NotImplementedError() | |||
| ### Tools to realize the simulation of the project | |||
| def __init__(self, challenges=None): | |||
| self.elmo_folder = os.path.dirname(os.path.abspath(__file__))+'/elmo' | |||
| self.challenges = challenges | |||
| self.is_executed = False | |||
| def set_challenges(self, challenges): | |||
| self.challenges = challenges | |||
| def get_writable_input_file(self): | |||
| return open('{}/input.txt'.format(self.elmo_folder), 'w') | |||
| def set_input_for_each_challenge(self, input, challenge): | |||
| format = self.get_challenge_format() | |||
| def aux(sizes, data): | |||
| if len(sizes) == 0: | |||
| write(input, data) | |||
| else: | |||
| assert len(data) == sizes[0], 'Incorrect format for challenge. Get {} instead of {}'.format(len(data), sizes[0]) | |||
| for i in range(sizes[0]): | |||
| aux(sizes[1:], data[i]) | |||
| for num_part in range(len(format)): | |||
| aux(format[num_part], challenge[num_part]) | |||
| def set_input(self, input): | |||
| assert len(self.challenges) < 2**16, 'The number of challenges must be strictly lower than 65536. Currently, there are {} challenges.'.format(len(self.challenges)) | |||
| write(input, len(self.challenges), nb_bits=self._nb_bits_for_nb_challenges) | |||
| for challenge in self.challenges: | |||
| self.set_input_for_each_challenge(input, challenge) | |||
| def run(self): | |||
| with open('{}/input.txt'.format(self.elmo_folder), 'w') as _input: | |||
| self.set_input(_input) | |||
| launch_simulation(project=self.get_project_label(), quiet=False) | |||
| self.is_executed = True | |||
| def get_asmtrace_filename(self): | |||
| return '{}/output/asmoutput/asmtrace00001.txt'.format(self.elmo_folder) | |||
| def get_indexes_of(self, condition): | |||
| with open(self.get_asmtrace_filename(), 'r') as _file: | |||
| asmtrace = _file.readlines() | |||
| return [i for i, instr in enumerate(asmtrace) if condition(instr)] | |||
| def get_number_of_traces(self): | |||
| return len(self.challenges) | |||
| def get_results(self, only_filenames=False, reorganise=None, indexes=None): | |||
| assert self.is_executed | |||
| nb_traces = self.get_number_of_traces() | |||
| trace_filenames = [] | |||
| for filename in os.listdir('{}/output/traces/'.format(self.elmo_folder)): | |||
| if re.search(r'^trace\d+\.trc$', filename): | |||
| trace_filenames.append('{}/output/traces/{}'.format(self.elmo_folder, filename)) | |||
| if len(trace_filenames) >= nb_traces: | |||
| break | |||
| assert len(trace_filenames) == nb_traces | |||
| results = trace_filenames | |||
| if not only_filenames: | |||
| for i in range(len(results)): | |||
| with open(results[i], 'r') as _file: | |||
| if indexes is not None: | |||
| results[i] = list(map(float, _file.readlines()[indexes])) | |||
| else: | |||
| results[i] = list(map(float, _file.readlines())) | |||
| if reorganise is not None: | |||
| results = reorganise(results) | |||
| return results | |||
| def get_traces(self, reorganise=None, indexes=None): | |||
| results = self.get_results(only_filenames=False, reorganise=reorganise,indexes=indexes) | |||
| nb_traces = self.get_number_of_traces() | |||
| trace_length = len(results[0]) | |||
| traces = np.zeros((nb_traces, trace_length)) | |||
| for i in range(nb_traces): | |||
| traces[i,:] = results[i] | |||
| if reorganise is not None: | |||
| traces = reorganise(traces) | |||
| return traces | |||
| def get_printed_data(self): | |||
| with open('{}/output/printdata.txt'.format(self.elmo_folder), 'r') as _file: | |||
| data = list(map(lambda x: int(x, 16), _file.readlines())) | |||
| nb_traces = self.get_number_of_traces() | |||
| nb_data_per_trace = len(data) // nb_traces | |||
| return [data[nb_data_per_trace*i:nb_data_per_trace*(i+1)] for i in range(nb_traces)] | |||
| def analyse_operands(self, num_line, num_trace=1): | |||
| num_str = str(num_trace) | |||
| num_str = '0'*(5-len(num_str)) + num_str | |||
| operands_filename = self.elmo_folder + '/output/operands/operands{}.txt'.format(num_str) | |||
| trace_filename = self.elmo_folder + '/output/traces/trace0000{}.trc'.format(num_trace) | |||
| is_multiple = (type(num_line) is list) | |||
| if not is_multiple: | |||
| num_line = [num_line] | |||
| output = [{}]*len(num_line) | |||
| with open(operands_filename, 'r') as _file: | |||
| lines = _file.readlines() | |||
| for i, num in enumerate(num_line): | |||
| line = lines[num].split() | |||
| data = list(map(int, line[0:7])) | |||
| output[i]['previous'] = data[0:2] | |||
| output[i]['current'] = data[2:4] | |||
| output[i]['triplet'] = data[4:7] | |||
| output[i]['other'] = list(map(float, line[7:])) | |||
| with open(trace_filename, 'r') as _file: | |||
| lines = _file.readlines() | |||
| for i, num in enumerate(num_line): | |||
| line = lines[num] | |||
| output[i]['power'] = float(line) | |||
| return output if is_multiple else output[0] | |||
| @@ -0,0 +1,42 @@ | |||
| from project_base import SimulationProject | |||
| import os, re | |||
| import inspect | |||
| PROJECTS_REPOSITORY = 'projects' | |||
| class ProjectReader: | |||
| def __init__(self): | |||
| pass | |||
| def get_projects(self): | |||
| projects = {} | |||
| for root, repositories, files in os.walk(PROJECTS_REPOSITORY): | |||
| for filename in files: | |||
| if re.fullmatch(r'.*project.*\.py', filename): | |||
| # Encapsulation the project | |||
| complete_filename = root+'/'+filename | |||
| globals = { | |||
| #'__builtins__': {'__build_class__': __build_class__}, | |||
| 'SimulationProject': SimulationProject, | |||
| } | |||
| locals = {} | |||
| # Read the project code | |||
| with open(complete_filename, 'r') as _file: | |||
| project = '\n'.join(_file.readlines()) | |||
| exec(project, globals, locals) | |||
| # Extract the simulations | |||
| for key, obj in locals.item(): | |||
| if inspect.isclass(obj) and issubclass(obj, SimulationProject): | |||
| if key in projects: | |||
| print('Warning! Multiplie simulation with the same name. Simulation ignored: {} in {}'.format(key, complete_filename[len(PROJECTS_REPOSITORY)+1:])) | |||
| else: | |||
| obj.set_project_directory(root[len(PROJECTS_REPOSITORY)+1:]) | |||
| projects[key] = obj | |||
| return projects | |||
| def get_project_classes(self): | |||
| return self.get_projects().values() | |||
| @@ -0,0 +1,3 @@ | |||
| * | |||
| !.gitignore | |||
| !elmoasmfunctions* | |||
| @@ -0,0 +1,257 @@ | |||
| ## | |||
| ## University of Bristol – Open Access Software Licence | |||
| ## Copyright (c) 2016, The University of Bristol, a chartered | |||
| ## corporation having Royal Charter number RC000648 and a charity | |||
| ## (number X1121) and its place of administration being at Senate | |||
| ## House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||
| ## All rights reserved | |||
| ## | |||
| ## Redistribution and use in source and binary forms, with or without | |||
| ## modification, are permitted provided that the following conditions | |||
| ## are met: | |||
| ## | |||
| ## 1. Redistributions of source code must retain the above copyright | |||
| ## notice, this list of conditions and the following disclaimer. | |||
| ## | |||
| ## 2. Redistributions in binary form must reproduce the above | |||
| ## copyright notice, this list of conditions and the following | |||
| ## disclaimer in the documentation and/or other materials provided | |||
| ## with the distribution. | |||
| ## | |||
| ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
| ## FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
| ## COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
| ## INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| ## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
| ## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
| ## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
| ## OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| ## | |||
| ## Any use of the software for scientific publications or commercial | |||
| ## purposes should be reported to the University of Bristol | |||
| ## (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||
| ## for impact and usage monitoring purposes only. | |||
| ## | |||
| ## Enquiries about further applications and development opportunities | |||
| ## are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||
| ## | |||
| .syntax unified | |||
| .text | |||
| .thumb | |||
| .func starttrigger | |||
| .global starttrigger | |||
| starttrigger: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x04 | |||
| eors r4, r5 | |||
| movs r5, #1 | |||
| str r5, [r4, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func endtrigger | |||
| .global endtrigger | |||
| endtrigger: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x04 | |||
| eors r4, r5 | |||
| movs r5, #0 | |||
| str r5, [r4, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func readbyte | |||
| .global readbyte | |||
| readbyte: | |||
| push {r0-r7} | |||
| movs r4, #0xE1 | |||
| lsls r4, #24 | |||
| ldr r1, [r4, #0] | |||
| strb r1, [r0, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func LoadN | |||
| .global LoadN | |||
| LoadN: | |||
| push {r0-r7} | |||
| movs r4, #0xE1 | |||
| lsls r4, #24 | |||
| movs r5, #0x10 | |||
| eors r4, r5 | |||
| ldr r1, [r4, #0] | |||
| str r1, [r0, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func randbyte | |||
| .global randbyte | |||
| randbyte: | |||
| push {r0-r7} | |||
| movs r4, #0xE1 | |||
| lsls r4, #24 | |||
| movs r5, #0x04 | |||
| eors r4, r5 | |||
| ldr r1, [r4, #0] | |||
| strb r1, [r0, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func getstart | |||
| .global getstart | |||
| getstart: | |||
| push {r0-r7} | |||
| movs r4, #0xE1 | |||
| lsls r4, #24 | |||
| movs r5, #0x08 | |||
| eors r4, r5 | |||
| ldr r1, [r4, #0] | |||
| str r1, [r0, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func getruncount | |||
| .global getruncount | |||
| getruncount: | |||
| push {r0-r7} | |||
| movs r4, #0xE1 | |||
| lsls r4, #24 | |||
| movs r5, #0x0C | |||
| eors r4, r5 | |||
| ldr r1, [r4, #0] | |||
| str r1, [r0, #0] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func printbyte | |||
| .global printbyte | |||
| printbyte: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| ldrb r5, [r0] | |||
| str r5, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func endprogram | |||
| .global endprogram | |||
| endprogram: | |||
| push {r0-r7} | |||
| movs r4, #0xF0 | |||
| lsls r4, #24 | |||
| movs r5, #0 | |||
| str r5, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func initialisemaskflow | |||
| .global initialisemaskflow | |||
| # Takes address of key as input (r0) | |||
| initialisemaskflow: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x40 | |||
| eors r4, r5 | |||
| str r0, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func resetmaskflow | |||
| .global resetmaskflow | |||
| resetmaskflow: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x42 | |||
| eors r4, r5 | |||
| movs r5, #0 | |||
| str r5, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func setmaskflowstart | |||
| .global setmaskflowstart | |||
| # Takes r0 as start number | |||
| setmaskflowstart: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x44 | |||
| eors r4, r5 | |||
| str r0, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| .func resetdatafile | |||
| .global resetdatafile | |||
| resetdatafile: | |||
| push {r0-r7} | |||
| movs r4, #0xE0 | |||
| lsls r4, #24 | |||
| movs r5, #0x46 | |||
| eors r4, r5 | |||
| movs r5, #0 | |||
| str r5, [r4] | |||
| pop {r0-r7} | |||
| bx lr | |||
| .endfunc | |||
| @@ -0,0 +1,55 @@ | |||
| /* | |||
| * University of Bristol – Open Access Software Licence | |||
| * Copyright (c) 2016, The University of Bristol, a chartered | |||
| * corporation having Royal Charter number RC000648 and a charity | |||
| * (number X1121) and its place of administration being at Senate | |||
| * House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||
| * All rights reserved | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above | |||
| * copyright notice, this list of conditions and the following | |||
| * disclaimer in the documentation and/or other materials provided | |||
| * with the distribution. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
| * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
| * OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| * | |||
| * Any use of the software for scientific publications or commercial | |||
| * purposes should be reported to the University of Bristol | |||
| * (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||
| * for impact and usage monitoring purposes only. | |||
| * | |||
| * Enquiries about further applications and development opportunities | |||
| * are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||
| */ | |||
| extern void starttrigger(void); | |||
| extern void endtrigger(void); | |||
| extern void randbyte(unsigned char * pointer); | |||
| extern void LoadN(void* addr); | |||
| extern void readbyte(unsigned char * pointer); | |||
| extern void printbyte(unsigned char * pointer); | |||
| extern void endprogram(void); | |||
| extern void getstart(unsigned int * pointer); | |||
| extern void getruncount(unsigned int * pointer); | |||
| extern void initialisemaskflow(unsigned char * pointer); | |||
| extern void resetmaskflow(void); | |||
| extern void setmaskflowstart(unsigned int start); | |||
| extern void resetdatafile(void); | |||
| @@ -0,0 +1,134 @@ | |||
| import os | |||
| import json | |||
| class ClosureException(Exception): | |||
| pass | |||
| # https://stackoverflow.com/questions/20007319/how-to-do-a-large-text-file-transfer-in-python | |||
| class SocketTool: | |||
| @classmethod | |||
| def convert_to_bytes(cl, no): | |||
| result = bytearray() | |||
| result.append(no & 255) | |||
| for i in range(3): | |||
| no = no >> 8 | |||
| result.append(no & 255) | |||
| return result | |||
| @classmethod | |||
| def bytes_to_number(cl, b): | |||
| import sys | |||
| b = b if (sys.version_info > (3, 0)) else map(ord, b) | |||
| res = 0 | |||
| for i in range(4): | |||
| res += b[i] << (i*8) | |||
| return res | |||
| @classmethod | |||
| def send_file(cl, s, filename, mode='rb'): | |||
| length = os.path.getsize(filename) | |||
| s.send(cl.convert_to_bytes(length)) # has to be 4 bytes | |||
| with open(filename, mode) as infile: | |||
| d = infile.read(1024*64) # We send by pack of 64 ko | |||
| while d: | |||
| s.send(d) | |||
| d = infile.read(1024*64) | |||
| @classmethod | |||
| def get_file(cl, s): | |||
| size = s.recv(4) # assuming that the size won't be bigger then 1GB | |||
| size = cl.bytes_to_number(size) | |||
| current_size = 0 | |||
| buffer = b'' | |||
| while current_size < size: | |||
| data = s.recv(1024*64) | |||
| if not data: | |||
| break | |||
| if len(data) + current_size > size: | |||
| data = data[:size-current_size] # trim additional data | |||
| buffer += data | |||
| # you can stream here to disk | |||
| current_size += len(data) | |||
| # you have entire file in memory | |||
| return buffer | |||
| @classmethod | |||
| def send_data(cl, s, data): | |||
| data = json.dumps(data) | |||
| data = data.encode('utf-8') | |||
| s.send(cl.convert_to_bytes(len(data))) # has to be 4 bytes | |||
| s.send(data) | |||
| @classmethod | |||
| def get_data(cl, s): | |||
| import sys | |||
| exception_class = json.decoder.JSONDecodeError if (sys.version_info > (3, 0)) else ValueError | |||
| try: | |||
| size = s.recv(4) | |||
| if not size: | |||
| return None | |||
| size = cl.bytes_to_number(size) | |||
| data = s.recv(size) | |||
| data = data.decode('utf-8') | |||
| data = json.loads(data) | |||
| return data | |||
| except exception_class: | |||
| return None | |||
| @classmethod | |||
| def send_ack(cl, s, positive=True): | |||
| data = 'OK' if positive else 'NO' | |||
| s.send(data.encode('ascii')) | |||
| @classmethod | |||
| def get_ack(cl, s): | |||
| data = s.recv(2).decode('ascii') | |||
| return (data == 'OK') | |||
| class Protocol: | |||
| def __init__(self, clientsocket): | |||
| self.clientsocket = clientsocket | |||
| def send_file(self, filename, mode='rb'): | |||
| SocketTool.send_file(self.clientsocket, filename, mode) | |||
| def get_file(self): | |||
| return SocketTool.get_file(self.clientsocket) | |||
| def send_data(self, data): | |||
| SocketTool.send_data(self.clientsocket, data) | |||
| def get_data(self): | |||
| return SocketTool.get_data(self.clientsocket) | |||
| def send_ack(self, positive=True): | |||
| SocketTool.send_ack(self.clientsocket, positive) | |||
| def send_nack(self, positive=True): | |||
| SocketTool.send_ack(self.clientsocket, not positive) | |||
| def get_ack(self): | |||
| return SocketTool.get_ack(self.clientsocket) | |||
| def please_assert(self, condition): | |||
| if not condition: | |||
| self.send_nack() | |||
| self.clientsocket.close() | |||
| raise ClosureException | |||
| def get_object_or_nack(self, model, **kwargs): | |||
| try: | |||
| return model.objects.get(**kwargs) | |||
| except model.DoesNotExist: | |||
| self.send_nack() | |||
| self.clientsocket.close() | |||
| raise ClosureException | |||
| def close(self): | |||
| self.clientsocket.close() | |||
| @@ -0,0 +1,24 @@ | |||
| elmo_repository="elmo" | |||
| elmo_source="https://github.com/sca-research/ELMO.git" | |||
| echo "====== ELMO Online ======" | |||
| if [ -d ${elmo_repository} ]; then | |||
| echo " - ELMO tool already installed." | |||
| else | |||
| # Download the tool | |||
| git clone --depth=1 --branch=master ${elmo_source} ${elmo_repository} | |||
| rm -rf ./${elmo_repository}/.git | |||
| # Compile the tool | |||
| cd ./${elmo_repository} | |||
| make | |||
| cd .. | |||
| fi | |||
| #current_directory=${PWD##*/} | |||
| #echo " - Current directory: ${current_directory}" | |||
| echo | |||
| #cd .. | |||
| #python3 -m ${current_directory}.run_server | |||
| python3 run_server.py | |||
| @@ -0,0 +1,36 @@ | |||
| from listeningthread import ListeningThread | |||
| from executorthread import ExecutorThread | |||
| def do_main_program(projects): | |||
| global thread, stop | |||
| thread = ListeningThread('localhost', 5000, ExecutorThread, projects=projects) | |||
| thread.start() | |||
| def program_cleanup(signum, frame): | |||
| global thread, stop | |||
| thread.stop() | |||
| stop = True | |||
| thread = None | |||
| stop = False | |||
| # Information | |||
| from project_reader import ProjectReader | |||
| reader = ProjectReader() | |||
| projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||
| print('Available projects: %s' % list(projects.keys())) | |||
| print('') | |||
| # Execute | |||
| print("Executing...") | |||
| do_main_program(projects) | |||
| print("Done ! And now, listening...") | |||
| import signal | |||
| signal.signal(signal.SIGINT, program_cleanup) | |||
| signal.signal(signal.SIGTERM, program_cleanup) | |||
| # Wait | |||
| import time | |||
| while not stop: | |||
| time.sleep(1) | |||
| @@ -0,0 +1,43 @@ | |||
| import threading | |||
| from protocol import Protocol, ClosureException | |||
| class ServiceThread(threading.Thread): | |||
| def run(self): | |||
| self.execute() | |||
| def execute(self): | |||
| # Method where the service runs | |||
| pass | |||
| class OneShotServiceThread(ServiceThread): | |||
| def __init__(self, ip, port, clientsocket): | |||
| threading.Thread.__init__(self) | |||
| self.ip = ip | |||
| self.port = port | |||
| self.clientsocket = clientsocket | |||
| self.protocol = Protocol(clientsocket) | |||
| def run(self): | |||
| try: | |||
| self.execute() | |||
| except ClosureException: | |||
| return | |||
| def execute(self): | |||
| # Method where the service runs | |||
| pass | |||
| class PermanentServiceThread(ServiceThread): | |||
| def __init__(self): | |||
| threading.Thread.__init__(self) | |||
| self._is_running = True | |||
| def is_running(self): | |||
| return self._is_running | |||
| def stop(self): | |||
| self._is_running = False | |||