diff --git a/.gitignore b/.gitignore index 343e2f9..264daca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -OUT -BUILD *__pycache__ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/RTL/toplevel.vhd b/RTL/toplevel.vhd deleted file mode 100644 index 1bb9ea5..0000000 --- a/RTL/toplevel.vhd +++ /dev/null @@ -1,23 +0,0 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.all; -use IEEE.NUMERIC_STD.all; -entity toplevel is - port ( - ACLK : in std_logic; - LED : out std_logic_vector(7 downto 0); - SW : in std_logic_vector(3 downto 0) - ); -end toplevel; -architecture structural of toplevel is - signal ARESETN : std_logic; -begin - ARESETN <= SW(3); - process(ACLK, ARESETN) - begin - if ARESETN='0' then - LED <= "11111111"; - elsif rising_edge(ACLK) then - LED <= SW & SW; - end if; - end process; -end architecture; \ No newline at end of file diff --git a/project.cfg b/project.cfg deleted file mode 100644 index 981c783..0000000 --- a/project.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[project] -name = testproject -version = 0.1 -out_dir = OUT -build_dir = BUILD - -[target:default] -family = spartan6 -device = xc6slx9 -package = tqg144 -speedgrade = -2 -toolchain = ISE - -[sources:default] -target = default -toplevel = toplevel -src_vhdl = RTL/toplevel.vhd -src_verilog = -src_sysverilog = \ No newline at end of file diff --git a/rbuild.py b/rbuild.py deleted file mode 100755 index fdf1d6d..0000000 --- a/rbuild.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -import remotesyn -import remotesyn.ISE as ISE - -import configparser -import signal -import time - -threads = [] - -def sighandler(sig, frame): - print("\nCRTL-C: stopping threads") - - for t in threads: - t.stop(); - - exit(0); - -if __name__=="__main__": - signal.signal(signal.SIGINT, sighandler) - - config = configparser.ConfigParser() - config.read("project.cfg") - - # Test local build - copy = remotesyn.copy_local(config) - synth = ISE.synth(config, copy, 'default') - threads.append(synth) - - needed_files = synth.needed_files() - print(needed_files) - - synth.start() - - looping = True - while looping: - time.sleep(1) - looping = False - for t in threads: - if t.running: - looping = True \ No newline at end of file diff --git a/remotesyn.egg-info/PKG-INFO b/remotesyn.egg-info/PKG-INFO new file mode 100644 index 0000000..fffd59d --- /dev/null +++ b/remotesyn.egg-info/PKG-INFO @@ -0,0 +1,13 @@ +Metadata-Version: 2.1 +Name: remotesyn +Version: 0.2 +Summary: Remote FPGA synthesis abstraction tool +Home-page: https://git.joppeb.nl/joppe/remotesyn +Download-URL: +Author: Joppe Blondel +Author-email: joppe@blondel.nl +License: BSD Licence +Keywords: FPGA,Synthesis,Xilinx,ISE,Vivado +Classifier: Development Status :: 3 - Alpha +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python :: 3 diff --git a/remotesyn.egg-info/SOURCES.txt b/remotesyn.egg-info/SOURCES.txt new file mode 100644 index 0000000..dfa20ec --- /dev/null +++ b/remotesyn.egg-info/SOURCES.txt @@ -0,0 +1,19 @@ +.gitignore +README.md +setup.py +remotesyn/__init__.py +remotesyn.egg-info/PKG-INFO +remotesyn.egg-info/SOURCES.txt +remotesyn.egg-info/dependency_links.txt +remotesyn.egg-info/requires.txt +remotesyn.egg-info/top_level.txt +remotesyn/ISE/__init__.py +scripts/rbuild +scripts/rmbuild +scripts/rmserver +server/authorized_hosts +server/id_rsa +server/id_rsa.pub +test/.gitignore +test/project.cfg +test/RTL/toplevel.vhd \ No newline at end of file diff --git a/remotesyn.egg-info/dependency_links.txt b/remotesyn.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/remotesyn.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/remotesyn.egg-info/requires.txt b/remotesyn.egg-info/requires.txt new file mode 100644 index 0000000..8608c1b --- /dev/null +++ b/remotesyn.egg-info/requires.txt @@ -0,0 +1 @@ +paramiko diff --git a/remotesyn.egg-info/top_level.txt b/remotesyn.egg-info/top_level.txt new file mode 100644 index 0000000..7689873 --- /dev/null +++ b/remotesyn.egg-info/top_level.txt @@ -0,0 +1 @@ +remotesyn diff --git a/remotesyn/ISE/__init__.py b/remotesyn/ISE/__init__.py index 145f565..e69de29 100644 --- a/remotesyn/ISE/__init__.py +++ b/remotesyn/ISE/__init__.py @@ -1 +0,0 @@ -from .synth import synth \ No newline at end of file diff --git a/remotesyn/ISE/runner.py b/remotesyn/ISE/runner.py deleted file mode 100644 index 249ee17..0000000 --- a/remotesyn/ISE/runner.py +++ /dev/null @@ -1,14 +0,0 @@ -import threading -import shutil -import os -import time -import subprocess - -def runner(threads, process, name): - print(f" - executing {name}: ", end='', flush=True) - p = subprocess.Popen(process, shell=True, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - threads.append(p) - while p.poll() is None: - print('.', end='', flush=True) - time.sleep(2) - res = p.returncode \ No newline at end of file diff --git a/remotesyn/ISE/syn.py b/remotesyn/ISE/syn.py new file mode 100644 index 0000000..9e53852 --- /dev/null +++ b/remotesyn/ISE/syn.py @@ -0,0 +1,79 @@ +import threading +import shutil +import os +import time +import subprocess +import signal +import random + +def needed_files(config, target) -> list: + if not config.has_section(f'build:{target}'): + print("ERROR: config file has no build section for target") + return None + needed_files = [] + for s in config.get(f'build:{target}', 'src_vhdl', fallback="").split(): + needed_files.append(s) + for s in config.get(f'build:{target}', 'src_verilog', fallback="").split(): + needed_files.append(s) + for s in config.get(f'build:{target}', 'src_sysverilog', fallback="").split(): + needed_files.append(s) + return needed_files + +def generated_files(config, target) -> list: + outdir = f"{config.get('project', 'out_dir', fallback='out')}" + return [ + f'{outdir}/{target}/synth.log', + f'{outdir}/{target}/synth.ngc', + ] + +def do(config, target, log, subprocesses, prefix='.') -> int: + log("Synthesize:") + + if not config.has_section(f'build:{target}'): + log("ERROR: config file has no build section for target") + return 1 + + devtarget = f'target:{config.get(f"build:{target}", "target", fallback="")}' + if not config.has_section(devtarget): + log("ERROR: config file has no section for device target") + return 1 + + device = f"{config.get(devtarget, 'device', fallback='')}{config.get(devtarget, 'speedgrade', fallback='')}-{config.get(devtarget, 'package', fallback='')}" + builddir = f"{prefix}/{config.get('project', 'build_dir', fallback='.build')}" + outdir = f"{prefix}/{config.get('project', 'out_dir', fallback='out')}" + + os.makedirs(builddir, exist_ok=True) + curdir = f"{os.getcwd()}/{prefix}" + + log(" - writing project file") + with open(f'{builddir}/syn.prj', 'w') as f: + for s in config.get(f'build:{target}', 'src_vhdl', fallback="").split(): + f.write(f"vhdl work {curdir}/{s}\n") + for s in config.get(f'build:{target}', 'src_verilog', fallback="").split(): + f.write(f"verilog work {curdir}/{s}\n") + for s in config.get(f'build:{target}', 'src_sysverilog', fallback="").split(): + f.write(f"verilog work {curdir}/{s}\n") + + log(" - writing project generation file") + with open(f'{builddir}/prj.scr', 'w') as f: + f.write(f'run\n-ifn syn.prj\n-ofn syn.ngc\n-ifmt mixed\n') + f.write(f'-top {config.get(f"sources:{target}", "toplevel", fallback="toplevel")}\n') + f.write(f'-p {device}\n-glob_opt max_delay -opt_mode speed') + + p = subprocess.Popen("xst -intstyle xflow -ifn prj.scr", shell=True, cwd=builddir, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocesses.append(p) + while p.poll() is None: + time.sleep(1) + res = p.returncode + if res: + log(" - ERROR: return code is", res) + log(" - copy log") + os.makedirs(f'{outdir}/{target}', exist_ok=True) + shutil.copy(f'{builddir}/prj.srp', f'{outdir}/{target}/synth.log') + return res + + log(" - copy output files") + os.makedirs(f'{outdir}/{target}', exist_ok=True) + shutil.copy(f'{builddir}/syn.ngc', f'{outdir}/{target}/synth.ngc') + shutil.copy(f'{builddir}/prj.srp', f'{outdir}/{target}/synth.log') + return 0 \ No newline at end of file diff --git a/remotesyn/ISE/synth.py b/remotesyn/ISE/synth.py deleted file mode 100644 index d4b4768..0000000 --- a/remotesyn/ISE/synth.py +++ /dev/null @@ -1,107 +0,0 @@ -import threading -import shutil -import os -import time -import subprocess -import signal -import random - -from .runner import runner - -class synth(threading.Thread): - def __init__(self, config, copy, target): - threading.Thread.__init__(self) - self.config = config - self.copy = copy - self.target = target - - self.threads = [] - self.running = True - self.name = config.get('project', 'name', fallback=f'{random.random():.4f}') - self.version = config.get('project', 'version', fallback=f'{random.random():.4f}') - self.builddir = f"{config.get('project', 'build_dir', fallback='.build')}/synth_{target}_{self.name}_{self.version}" - self.outdir = config.get('project', 'out_dir', fallback='out') - - # Returns the list of needed files to execute operation. Caller need - # to check for existance of the files and if in remote execution these - # files must be synched - def needed_files(self): - if not self.config.has_section(f'sources:{self.target}'): - print("ERROR: config file has no sources section for target") - return None - needed_files = [] - for s in self.config.get(f'sources:{self.target}', 'src_vhdl', fallback="").split(): - needed_files.append(s) - for s in self.config.get(f'sources:{self.target}', 'src_verilog', fallback="").split(): - needed_files.append(s) - for s in self.config.get(f'sources:{self.target}', 'src_sysverilog', fallback="").split(): - needed_files.append(s) - return needed_files - - def stop(self): - print("Stopping synth...") - for t in self.threads: - print(" <> kill", t) - t.send_signal(signal.SIGINT) - ti = 0 - while t.poll() is None: - time.sleep(1) - ti += 1 - if ti>2: - print(" <> force kill", t) - t.send_signal(signal.SIGKILL) - self.running = False - - def run(self): - print("Synthesize:") - if not self.config.has_section(f'sources:{self.target}'): - print("ERROR: config file has no sources section for target") - self.running = False - return None - - devtarget = f'target:{self.config.get(f"sources:{self.target}", "target", fallback="")}' - if not self.config.has_section(devtarget): - print("ERROR: config file has no section for device target") - self.running = False - return None - - device = f"{self.config.get(devtarget, 'device', fallback='')}{self.config.get(devtarget, 'speedgrade', fallback='')}-{self.config.get(devtarget, 'package', fallback='')}" - - os.makedirs(self.builddir, exist_ok=True) - curdir = os.getcwd() - os.chdir(self.builddir) - - try: - - print(" - writing project file") - with open('syn.prj', 'w') as f: - for s in self.config.get(f'sources:{self.target}', 'src_vhdl', fallback="").split(): - f.write(f"vhdl work {curdir}/{s}\n") - for s in self.config.get(f'sources:{self.target}', 'src_verilog', fallback="").split(): - f.write(f"verilog work {curdir}/{s}\n") - for s in self.config.get(f'sources:{self.target}', 'src_sysverilog', fallback="").split(): - f.write(f"verilog work {curdir}/{s}\n") - - print(" - writing project generation file") - with open('prj.scr', 'w') as f: - f.write(f'run\n-ifn syn.prj\n-ofn syn.ngc\n-ifmt mixed\n') - f.write(f'-top {self.config.get(f"sources:{self.target}", "toplevel", fallback="toplevel")}\n') - f.write(f'-p {device}\n-glob_opt max_delay -opt_mode speed') - - runner(self.threads, "xst -intstyle xflow -ifn prj.scr", "xst") - if not self.running: - os.chdir(curdir) - return - print('DONE') - - print(" - copy output files") - os.makedirs(f'{curdir}/{self.outdir}/{self.target}', exist_ok=True) - self.copy.copy_to_dir('syn.ngc', f'{curdir}/{self.outdir}/{self.target}/synth.ngc') - self.copy.copy_to_dir('prj.srp', f'{curdir}/{self.outdir}/{self.target}/synth.log') - - except Exception as e: - print(e) - - finally: - os.chdir(curdir) - self.running = False \ No newline at end of file diff --git a/remotesyn/__init__.py b/remotesyn/__init__.py index 6479edc..e69de29 100644 --- a/remotesyn/__init__.py +++ b/remotesyn/__init__.py @@ -1 +0,0 @@ -from .copy import copy_local, copy_remote \ No newline at end of file diff --git a/remotesyn/copy.py b/remotesyn/copy.py deleted file mode 100644 index 5bd6f9c..0000000 --- a/remotesyn/copy.py +++ /dev/null @@ -1,22 +0,0 @@ -import shutil - -class copy_local: - def __init__(self, config): - self.config = config - - def copy_from_dir(self, src, dst): - pass - # Nothing to do here since we are working in local build - - def copy_to_dir(self, src, dst): - shutil.copy(src, dst) - -class copy_remote: - def __init__(self, config): - self.config = config - - def copy_from_dir(self, src, dst): - print("ERROR: Not yet implemented") - - def copy_to_dir(self, src, dst): - print("ERROR: Not yet implemented") \ No newline at end of file diff --git a/scripts/rbuild b/scripts/rbuild new file mode 100755 index 0000000..c3b7fcd --- /dev/null +++ b/scripts/rbuild @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +import configparser +import sys + +def print_help(): + print("Unified FPGA synthesizer frontend\r\n(c) Joppe Blondel - 2022\r\n") + print(f"Usage: {sys.argv[0]} [ OPTIONS ] action [ target ] ...") + print("") + print("Options:") + print(" -h Show this help message") + print(" -c Configuration file, defaults to project.cfg") + print("") + print("Actions:") + print("ip Generate IP files from vendor provided libraries") + print("syn Synthesize design for target") + print("impl Route and place design for target") + print("bit Generate output files and run analysis for target") + print("all Generate IP, synthesize, route and place design for target") + print("floorplan Run floorplan editor, currently only for local execution") + print("sim Run simulation target") + +if __name__=="__main__": + # Parse arguments + i = 1 + nextarg = None + configpath = 'project.cfg' + actions = [] + while iI', len(s)) + s.encode('utf-8') + +def rstr(channel): + l = struct.unpack('>I', channel.recv(4))[0] + return bytes.decode(channel.recv(l), 'utf-8') + +def send_file(channel, file, othername=None): + print(f"> {file}") + if not os.path.exists(file): + print(f"Error: {file} does not exists") + with open(file, 'rb') as f: + stat = os.fstat(f.fileno()) + print(' -> fsize', stat.st_size) + if othername is None: + othername = file + fsize = struct.pack('>q', stat.st_size) + cmd(b'sf'+sstr(othername)+fsize, channel) + status = channel.recv(3) + if status!=b'OK\n': + print('Something went wrong...') + exit(1) + i = stat.st_size + while i>0: + fdata = f.read(1024) + i -= 1024 + channel.sendall(fdata) + +def recv_file(channel, file): + print(f"< {file}") + if os.path.dirname(file) != '': + os.makedirs(os.path.dirname(file), exist_ok=True) + with open(file, 'wb') as f: + cmd(b'rf'+sstr(file), channel) + while True: + status = channel.recv(2) + if status != b'\x00\x00': + break + if status!=b'OK': + msg = channel.recv(1024) + print("Error:", bytes.decode(msg, 'ascii')) + exit(1) + fsize = channel.recv(8) + fsize = struct.unpack('>q', fsize)[0] + print(' -> fsize', fsize) + while fsize>0: + f.write(channel.recv(1024)) + fsize -= 1024 + +def print_help(): + print("Unified FPGA synthesizer frontend - remote execution\r\n(c) Joppe Blondel - 2022\r\n") + print(f"Usage: {sys.argv[0]} [ OPTIONS ] action [ target ] ...") + print("") + print("Options:") + print(" -h Show this help message") + print(" -c Configuration file, defaults to project.cfg") + print("") + print("Actions:") + print("ip Generate IP files from vendor provided libraries") + print("syn Synthesize design for target") + print("impl Route and place design for target") + print("bit Generate output files and run analysis for target") + print("all Generate IP, synthesize, route and place design for target") + print("floorplan Run floorplan editor, currently only for local execution") + print("sim Run simulation target") + +if __name__=="__main__": + # Parse arguments + i = 1 + nextarg = None + configpath = 'project.cfg' + actions = [] + while iq', hash(host_key.get_base64())), channel) + # Send config + cmd(b'cf' + sstr(json.dumps({s:dict(config.items(s)) for s in config.sections()})), channel) + + subprocesses = [] + + try: + for action in actions: + target = action[1] + action = action[0] + + if not config.has_section(f'build:{target}'): + print("ERROR: config file has no build section for target") + exit(1) + devtarget = f'target:{config.get(f"build:{target}", "target", fallback="")}' + if not config.has_section(devtarget): + print("ERROR: config file has no section for device target") + exit(1) + toolchain = config.get(devtarget, 'toolchain', fallback="NONE") + if toolchain=="NONE": + print("ERROR: no toolchain specified for device target") + exit(1) + + try: + exec(f"from remotesyn.{toolchain}.{action} import do, needed_files, generated_files") + except ImportError: + print(f"ERROR: Unknown action '{action}' for toolchain '{toolchain}'") + exit(1) + + # Send needed files + for f in needed_files(config, target): + send_file(channel, f) + + # ret = do(config, target, print, subprocesses) + cmd(b'do'+sstr(f"{action} {target}"), channel) + ret = 0 + + # Get generated files + for f in generated_files(config, target): + recv_file(channel, f) + + if ret!=0: + exit(ret) + + except paramiko.ssh_exception.SSHException as e: + print("ERROR: Connection error...") + for p in subprocesses: + p.kill() + exit(0) + + except KeyboardInterrupt: + print("\rStopping rmbuild") + for p in subprocesses: + p.kill() + exit(0) \ No newline at end of file diff --git a/scripts/rmserver b/scripts/rmserver new file mode 100644 index 0000000..1d9ecc3 --- /dev/null +++ b/scripts/rmserver @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 + +import configparser +import signal +import sys +import time +import subprocess +from types import NoneType +import paramiko +import base64 +import struct +import os +import json +import threading +import socket +import shutil + +# List of running threads +threads = [] +running = False + +def sighandler(sig, frame): + global threads + global running + + print("\rStopping server") + running = False + for t in threads: + t.stop(); + +class FileTransferSF(threading.Thread): + def __init__(self, channel, fname, identifier, fsize): + threading.Thread.__init__(self) + self.channel = channel + self.fname = fname + self.identifier = identifier + self.fsize = fsize + self.running = True + def stop(self): + self.running = False + def run(self): + with open(f"{self.identifier}/{self.fname}", 'wb') as f: + fsize = self.fsize + while fsize>0 and self.running: + fdata = self.channel.recv(1024) + f.write(fdata) + fsize -= 1024 + +class FileTransferRF(threading.Thread): + def __init__(self, channel, fname, identifier): + threading.Thread.__init__(self) + self.channel = channel + self.fname = fname + self.identifier = identifier + self.running = True + def stop(self): + self.running = False + def run(self): + with open(f"{self.identifier}/{self.fname}", 'rb') as f: + stat = os.fstat(f.fileno()) + print(' -> fsize', stat.st_size) + fsize = struct.pack('>q', stat.st_size) + i = stat.st_size + self.channel.sendall(b'OK'+fsize) + while i>0 and self.running: + fdata = f.read(1024) + self.channel.sendall(fdata) + i -= 1024 + +class SSHServer(paramiko.ServerInterface): + def __init__(self, authorized): + self.event = threading.Event() + self.authorized = authorized + self.identifier = '' + self.subprocesses = [] + self.threads = [] + + def stop(self): + self.event.set() + for s in self.subprocesses: + s.kill() + for t in self.threads: + if type(t) is not NoneType: + t.stop() + t.join() + + def check_channel_request(self, kind, chanid): + if kind == 'session': + return paramiko.OPEN_SUCCEEDED + + def check_auth_publickey(self, username, key): + keyascii = key.get_base64() + for auth in self.authorized: + authascii = auth.split(' ')[1] + if authascii==keyascii: + return paramiko.AUTH_SUCCESSFUL + return paramiko.AUTH_FAILED + + def get_allowed_auths(self, username): + return 'publickey' + + def rstr(self, b): + l = struct.unpack('>I', b[:4])[0] + return (bytes.decode(b[4:4+l], 'utf-8'), b[4+l:]) + + def sstr(self, s): + return struct.pack('>I', len(s)) + s.encode('utf-8') + + def check_channel_exec_request(self, channel, command): + try: + command = base64.decodebytes(command) + cmd = command[:2] + data = command[2:] + + # Identifier + if cmd==b'id': + identifier = struct.unpack('>q', data[:8])[0] + self.identifier = str(identifier) + print('>', identifier) + # Create directory + if os.path.exists(str(identifier)): + shutil.rmtree(str(identifier)) + os.mkdir(str(identifier)) + + # Exit + elif cmd==b'ex': + print('<', self.identifier) + self.event.set() + + # Config + elif cmd==b'cf': + cnf, data = self.rstr(data) + self.config = configparser.ConfigParser() + self.config.read_dict(json.loads(cnf)) + + # List files + elif cmd==b'ls': + dr, data = self.rstr(data) + print('ls', dr) + if not os.path.exists(f"{self.identifier}/{dr}"): + channel.sendall(b'ERFile not found') + es = [] + for f in os.listdir(f'{self.identifier}/{dr}'): + if os.path.isfile(f'{self.identifier}/{dr}/{f}'): + df = 'f' + else: + df = 'd' + es.append(f'{df}{f}') + channel.sendall(b'OK' + self.sstr('\n'.join(es))) + + # Send file + elif cmd==b'sf': + fname, data = self.rstr(data) + fsize = struct.unpack('>q', data)[0] + print('>>', fname, fsize) + os.makedirs(os.path.dirname(f"{self.identifier}/{fname}"), exist_ok=True) + channel.sendall(b'OK\n') + t = FileTransferSF(channel, fname, self.identifier, fsize) + self.threads.append(t) + t.start() + + # Receive file + elif cmd==b'rf': + fname, data = self.rstr(data) + print('<<', fname, self.identifier) + if not os.path.exists(f"{self.identifier}/{fname}"): + channel.sendall(b'ERFile not found') + else: + t = FileTransferRF(channel, fname, self.identifier) + self.threads.append(t) + t.start() + + # Execute rbuild + elif cmd==b'do': + args, data = self.rstr(data) + print('[]', args) + with open(f"{self.identifier}/project.cfg", "w") as f: + self.config.write(f) + p = subprocess.Popen(f"rbuild -c project.cfg {args}", shell=True, cwd=f'{self.identifier}', stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + self.subprocesses.append(p) + res = p.wait() + channel.sendall(struct.pack('>I', res)) + + return True + + except Exception: + global running + if running: + print("ERROR: Unknown error") + return False + +class Connection(threading.Thread): + def __init__(self, sock, addr, host_key, authorized): + threading.Thread.__init__(self) + self.sock = sock + self.addr = addr + self.host_key = host_key + self.authorized = authorized + self.running = False + print("Connection from", addr) + + def stop(self): + self.server.event.set() + self.server.stop() + + def clean(self): + pass + + def run(self): + transport = paramiko.Transport(self.sock) + transport.set_gss_host(socket.getfqdn("")) + transport.load_server_moduli() + transport.add_server_key(self.host_key) + server = SSHServer(self.authorized) + transport.start_server(server=server) + self.server = server + while not server.event.is_set(): + if not transport.is_alive(): + print("Connection", self.addr, "is broken from other end") + server.stop() + break + time.sleep(0.2) + else: + print("Connection", self.addr, "closed") + if server.identifier!='': + pass + shutil.rmtree(server.identifier, True) + transport.close() + +def print_help(): + print("Unified FPGA synthesizer frontend - remote execution server\r\n(c) Joppe Blondel - 2022\r\n") + print(f"Usage: {sys.argv[0]} [ OPTIONS ] host port privkey pubkey authorized_hosts") + print("") + print("Options:") + print(" -h Show this help message") + +if __name__=="__main__": + # Parse arguments + i = 1 + host = '' + port = '' + pubkey = '' + privkey = '' + authorized_f = '' + while i