153e354dd0edd0d111fb7512f366c4764ffc2e681Phil#! /usr/bin/env python 253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 353e354dd0edd0d111fb7512f366c4764ffc2e681Phil## This file is part of Scapy 453e354dd0edd0d111fb7512f366c4764ffc2e681Phil## See http://www.secdev.org/projects/scapy for more informations 553e354dd0edd0d111fb7512f366c4764ffc2e681Phil## Copyright (C) Philippe Biondi <phil@secdev.org> 653e354dd0edd0d111fb7512f366c4764ffc2e681Phil## This program is published under a GPLv2 license 753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 8b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotterfrom __future__ import print_function 959a7b9f69b5b745e58c01288cb4f85fb535250b0gpotterimport os 1053e354dd0edd0d111fb7512f366c4764ffc2e681Philimport subprocess 1153e354dd0edd0d111fb7512f366c4764ffc2e681Philimport itertools 1253e354dd0edd0d111fb7512f366c4764ffc2e681Philimport collections 1353e354dd0edd0d111fb7512f366c4764ffc2e681Philimport time 1422a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotterimport scapy.modules.six as six 1559a7b9f69b5b745e58c01288cb4f85fb535250b0gpotterfrom threading import Lock, Thread 1622a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotterimport scapy.utils 176057906368d55634d11e1d19a5cca1f127595b11Robin Jarry 180bfed5c5783d9e883abd6055079c833340052616gpotterfrom scapy.automaton import Message, select_objects, SelectableObject 19c8aedce97942cf1963c137902d50d14cd5c28bf0gpotterfrom scapy.consts import WINDOWS 202a54fe68cadcb2b75c9c31244499c2b21f385eb4gpotterfrom scapy.error import log_interactive, warning 216057906368d55634d11e1d19a5cca1f127595b11Robin Jarryfrom scapy.config import conf 22c8aedce97942cf1963c137902d50d14cd5c28bf0gpotterfrom scapy.utils import get_temp_file, do_graph 23c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter 24c8aedce97942cf1963c137902d50d14cd5c28bf0gpotterimport scapy.arch 2553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 260bfed5c5783d9e883abd6055079c833340052616gpotterclass PipeEngine(SelectableObject): 2753e354dd0edd0d111fb7512f366c4764ffc2e681Phil pipes = {} 2853e354dd0edd0d111fb7512f366c4764ffc2e681Phil @classmethod 2953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def list_pipes(cls): 3053e354dd0edd0d111fb7512f366c4764ffc2e681Phil for pn,pc in sorted(cls.pipes.items()): 3153e354dd0edd0d111fb7512f366c4764ffc2e681Phil doc = pc.__doc__ or "" 3253e354dd0edd0d111fb7512f366c4764ffc2e681Phil if doc: 3353e354dd0edd0d111fb7512f366c4764ffc2e681Phil doc = doc.splitlines()[0] 34b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print("%20s: %s" % (pn, doc)) 3553e354dd0edd0d111fb7512f366c4764ffc2e681Phil @classmethod 3653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def list_pipes_detailed(cls): 3753e354dd0edd0d111fb7512f366c4764ffc2e681Phil for pn,pc in sorted(cls.pipes.items()): 3853e354dd0edd0d111fb7512f366c4764ffc2e681Phil if pc.__doc__: 39b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print("###### %s\n %s" % (pn ,pc.__doc__)) 4053e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 41b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print("###### %s" % pn) 4253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 4353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, *pipes): 4453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_pipes = set() 4553e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_sources = set() 4653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_drains = set() 4753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_sinks = set() 4853e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._add_pipes(*pipes) 4959a7b9f69b5b745e58c01288cb4f85fb535250b0gpotter self.thread_lock = Lock() 5059a7b9f69b5b745e58c01288cb4f85fb535250b0gpotter self.command_lock = Lock() 510bfed5c5783d9e883abd6055079c833340052616gpotter self.__fd_queue = collections.deque() 5253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.__fdr,self.__fdw = os.pipe() 530bfed5c5783d9e883abd6055079c833340052616gpotter self.thread = None 5453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __getattr__(self, attr): 5553e354dd0edd0d111fb7512f366c4764ffc2e681Phil if attr.startswith("spawn_"): 5653e354dd0edd0d111fb7512f366c4764ffc2e681Phil dname = attr[6:] 5753e354dd0edd0d111fb7512f366c4764ffc2e681Phil if dname in self.pipes: 5853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def f(*args, **kargs): 5953e354dd0edd0d111fb7512f366c4764ffc2e681Phil k = self.pipes[dname] 6053e354dd0edd0d111fb7512f366c4764ffc2e681Phil p = k(*args, **kargs) 6153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.add(p) 6253e354dd0edd0d111fb7512f366c4764ffc2e681Phil return p 6353e354dd0edd0d111fb7512f366c4764ffc2e681Phil return f 6453e354dd0edd0d111fb7512f366c4764ffc2e681Phil raise AttributeError(attr) 6553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 660bfed5c5783d9e883abd6055079c833340052616gpotter def check_recv(self): 67c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter """As select.select is not available, we check if there 68c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter is some data to read by using a list that stores pointers.""" 69c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter return len(self.__fd_queue) > 0 70c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter 71c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter def fileno(self): 72c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter return self.__fdr 73c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter 74c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter def _read_cmd(self): 750bfed5c5783d9e883abd6055079c833340052616gpotter os.read(self.__fdr,1) 760bfed5c5783d9e883abd6055079c833340052616gpotter return self.__fd_queue.popleft() 77c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter 78c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter def _write_cmd(self, _cmd): 790bfed5c5783d9e883abd6055079c833340052616gpotter self.__fd_queue.append(_cmd) 801fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter os.write(self.__fdw, b"X") 810bfed5c5783d9e883abd6055079c833340052616gpotter self.call_release() 82c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter 8353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def add_one_pipe(self, pipe): 8453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_pipes.add(pipe) 8553e354dd0edd0d111fb7512f366c4764ffc2e681Phil if isinstance(pipe, Source): 8653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_sources.add(pipe) 8753e354dd0edd0d111fb7512f366c4764ffc2e681Phil if isinstance(pipe, Drain): 8853e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_drains.add(pipe) 8953e354dd0edd0d111fb7512f366c4764ffc2e681Phil if isinstance(pipe, Sink): 9053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.active_sinks.add(pipe) 9153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 9253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def get_pipe_list(self, pipe): 9353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def flatten(p, l): 9453e354dd0edd0d111fb7512f366c4764ffc2e681Phil l.add(p) 9553e354dd0edd0d111fb7512f366c4764ffc2e681Phil for q in p.sources|p.sinks|p.high_sources|p.high_sinks: 9653e354dd0edd0d111fb7512f366c4764ffc2e681Phil if q not in l: 9753e354dd0edd0d111fb7512f366c4764ffc2e681Phil flatten(q, l) 98c277f8948afe9d19703168fca385d2fa6df67657Phil pl = set() 9953e354dd0edd0d111fb7512f366c4764ffc2e681Phil flatten(pipe, pl) 10053e354dd0edd0d111fb7512f366c4764ffc2e681Phil return pl 10153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 10253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _add_pipes(self, *pipes): 103c277f8948afe9d19703168fca385d2fa6df67657Phil pl = set() 10453e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in pipes: 105c277f8948afe9d19703168fca385d2fa6df67657Phil pl |= self.get_pipe_list(p) 106c277f8948afe9d19703168fca385d2fa6df67657Phil pl -= self.active_pipes 107c277f8948afe9d19703168fca385d2fa6df67657Phil for q in pl: 108c277f8948afe9d19703168fca385d2fa6df67657Phil self.add_one_pipe(q) 109c277f8948afe9d19703168fca385d2fa6df67657Phil return pl 11053e354dd0edd0d111fb7512f366c4764ffc2e681Phil 11153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 11253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def run(self): 11353e354dd0edd0d111fb7512f366c4764ffc2e681Phil log_interactive.info("Pipe engine thread started.") 11453e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 11553e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in self.active_pipes: 11653e354dd0edd0d111fb7512f366c4764ffc2e681Phil p.start() 11753e354dd0edd0d111fb7512f366c4764ffc2e681Phil sources = self.active_sources 118c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter sources.add(self) 11953e354dd0edd0d111fb7512f366c4764ffc2e681Phil exhausted = set([]) 12053e354dd0edd0d111fb7512f366c4764ffc2e681Phil RUN=True 12153e354dd0edd0d111fb7512f366c4764ffc2e681Phil STOP_IF_EXHAUSTED = False 12253e354dd0edd0d111fb7512f366c4764ffc2e681Phil while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): 1230bfed5c5783d9e883abd6055079c833340052616gpotter fds = select_objects(sources, 2) 12453e354dd0edd0d111fb7512f366c4764ffc2e681Phil for fd in fds: 125c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter if fd is self: 126c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter cmd = self._read_cmd() 12753e354dd0edd0d111fb7512f366c4764ffc2e681Phil if cmd == "X": 12853e354dd0edd0d111fb7512f366c4764ffc2e681Phil RUN=False 12953e354dd0edd0d111fb7512f366c4764ffc2e681Phil break 13053e354dd0edd0d111fb7512f366c4764ffc2e681Phil elif cmd == "B": 13153e354dd0edd0d111fb7512f366c4764ffc2e681Phil STOP_IF_EXHAUSTED = True 13253e354dd0edd0d111fb7512f366c4764ffc2e681Phil elif cmd == "A": 13353e354dd0edd0d111fb7512f366c4764ffc2e681Phil sources = self.active_sources-exhausted 13437b8c8237ab0fcca93c09a9c8094501cf0591f8egpotter sources.add(self) 13553e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 13653e354dd0edd0d111fb7512f366c4764ffc2e681Phil warning("Unknown internal pipe engine command: %r. Ignoring." % cmd) 13753e354dd0edd0d111fb7512f366c4764ffc2e681Phil elif fd in sources: 13853e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 13953e354dd0edd0d111fb7512f366c4764ffc2e681Phil fd.deliver() 140d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter except Exception as e: 14153e354dd0edd0d111fb7512f366c4764ffc2e681Phil log_interactive.exception("piping from %s failed: %s" % (fd.name, e)) 14253e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 14353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if fd.exhausted(): 14453e354dd0edd0d111fb7512f366c4764ffc2e681Phil exhausted.add(fd) 14553e354dd0edd0d111fb7512f366c4764ffc2e681Phil sources.remove(fd) 14653e354dd0edd0d111fb7512f366c4764ffc2e681Phil except KeyboardInterrupt: 14753e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 14853e354dd0edd0d111fb7512f366c4764ffc2e681Phil finally: 14953e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 15053e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in self.active_pipes: 15153e354dd0edd0d111fb7512f366c4764ffc2e681Phil p.stop() 15253e354dd0edd0d111fb7512f366c4764ffc2e681Phil finally: 15353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.thread_lock.release() 15453e354dd0edd0d111fb7512f366c4764ffc2e681Phil log_interactive.info("Pipe engine thread stopped.") 15553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 15653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def start(self): 15753e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.thread_lock.acquire(0): 15859a7b9f69b5b745e58c01288cb4f85fb535250b0gpotter _t = Thread(target=self.run) 1596e173e9f6e570d6c3c8c76040b44e270c47308dbgpotter _t.setDaemon(True) 16059a7b9f69b5b745e58c01288cb4f85fb535250b0gpotter _t.start() 1610bfed5c5783d9e883abd6055079c833340052616gpotter self.thread = _t 16253e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 16353e354dd0edd0d111fb7512f366c4764ffc2e681Phil warning("Pipe engine already running") 16453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def wait_and_stop(self): 16553e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.stop(_cmd="B") 16653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def stop(self, _cmd="X"): 16753e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 16853e354dd0edd0d111fb7512f366c4764ffc2e681Phil with self.command_lock: 1690bfed5c5783d9e883abd6055079c833340052616gpotter if self.thread is not None: 170c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter self._write_cmd(_cmd) 1710bfed5c5783d9e883abd6055079c833340052616gpotter self.thread.join() 1720bfed5c5783d9e883abd6055079c833340052616gpotter try: 1730bfed5c5783d9e883abd6055079c833340052616gpotter self.thread_lock.release() 1740bfed5c5783d9e883abd6055079c833340052616gpotter except: 1750bfed5c5783d9e883abd6055079c833340052616gpotter pass 17653e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 17753e354dd0edd0d111fb7512f366c4764ffc2e681Phil warning("Pipe engine thread not running") 17853e354dd0edd0d111fb7512f366c4764ffc2e681Phil except KeyboardInterrupt: 179b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print("Interrupted by user.") 18053e354dd0edd0d111fb7512f366c4764ffc2e681Phil 18153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def add(self, *pipes): 182c277f8948afe9d19703168fca385d2fa6df67657Phil pipes = self._add_pipes(*pipes) 18353e354dd0edd0d111fb7512f366c4764ffc2e681Phil with self.command_lock: 1840bfed5c5783d9e883abd6055079c833340052616gpotter if self.thread is not None: 18553e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in pipes: 18653e354dd0edd0d111fb7512f366c4764ffc2e681Phil p.start() 187c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter self._write_cmd("A") 18853e354dd0edd0d111fb7512f366c4764ffc2e681Phil 18953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def graph(self,**kargs): 19053e354dd0edd0d111fb7512f366c4764ffc2e681Phil g=['digraph "pipe" {',"\tnode [shape=rectangle];",] 19153e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in self.active_pipes: 19253e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append('\t"%i" [label="%s"];' % (id(p), p.name)) 19353e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append("") 19453e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append("\tedge [color=blue, arrowhead=vee];") 19553e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in self.active_pipes: 19653e354dd0edd0d111fb7512f366c4764ffc2e681Phil for q in p.sinks: 19753e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append('\t"%i" -> "%i";' % (id(p), id(q))) 19853e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append("") 199dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil g.append("\tedge [color=purple, arrowhead=veevee];") 20053e354dd0edd0d111fb7512f366c4764ffc2e681Phil for p in self.active_pipes: 20153e354dd0edd0d111fb7512f366c4764ffc2e681Phil for q in p.high_sinks: 202dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil g.append('\t"%i" -> "%i";' % (id(p), id(q))) 203dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil g.append("") 204dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil g.append("\tedge [color=red, arrowhead=diamond];") 205dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil for p in self.active_pipes: 206dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil for q in p.trigger_sinks: 207dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil g.append('\t"%i" -> "%i";' % (id(p), id(q))) 20853e354dd0edd0d111fb7512f366c4764ffc2e681Phil g.append('}') 20953e354dd0edd0d111fb7512f366c4764ffc2e681Phil graph = "\n".join(g) 210c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter do_graph(graph, **kargs) 21153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 21253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 21353e354dd0edd0d111fb7512f366c4764ffc2e681Philclass _ConnectorLogic(object): 21453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self): 21553e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.sources = set() 21653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.sinks = set() 21753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.high_sources = set() 21853e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.high_sinks = set() 219dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil self.trigger_sources = set() 220dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil self.trigger_sinks = set() 22153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 22253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __lt__(self, other): 22353e354dd0edd0d111fb7512f366c4764ffc2e681Phil other.sinks.add(self) 22453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.sources.add(other) 22553e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 22653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __gt__(self, other): 22753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.sinks.add(other) 22853e354dd0edd0d111fb7512f366c4764ffc2e681Phil other.sources.add(self) 22953e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 23053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __eq__(self, other): 23153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self > other 23253e354dd0edd0d111fb7512f366c4764ffc2e681Phil other > self 23353e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 23453e354dd0edd0d111fb7512f366c4764ffc2e681Phil 23553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __lshift__(self, other): 23653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.high_sources.add(other) 23753e354dd0edd0d111fb7512f366c4764ffc2e681Phil other.high_sinks.add(self) 23853e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 23953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __rshift__(self, other): 24053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.high_sinks.add(other) 24153e354dd0edd0d111fb7512f366c4764ffc2e681Phil other.high_sources.add(self) 24253e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 24353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __floordiv__(self, other): 24453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self >> other 24553e354dd0edd0d111fb7512f366c4764ffc2e681Phil other >> self 24653e354dd0edd0d111fb7512f366c4764ffc2e681Phil return other 24753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 248dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil def __xor__(self, other): 249dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil self.trigger_sinks.add(other) 250dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil other.trigger_sources.add(self) 251dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil return other 25253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 2531fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter def __hash__(self): 2541fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter return object.__hash__(self) 2551fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter 2561fd5116590e760b8cd43ce41b8aaedec25251bcbgpotterclass _PipeMeta(type): 2571fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter def __new__(cls, name, bases, dct): 2581fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter c = type.__new__(cls, name, bases, dct) 2591fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter PipeEngine.pipes[name] = c 2601fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter return c 2611fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter 2621fd5116590e760b8cd43ce41b8aaedec25251bcbgpotterclass Pipe(six.with_metaclass(_PipeMeta, _ConnectorLogic)): 26353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None): 26453e354dd0edd0d111fb7512f366c4764ffc2e681Phil _ConnectorLogic.__init__(self) 26553e354dd0edd0d111fb7512f366c4764ffc2e681Phil if name is None: 26653e354dd0edd0d111fb7512f366c4764ffc2e681Phil name = "%s" % (self.__class__.__name__) 26753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.name = name 26853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _send(self, msg): 26953e354dd0edd0d111fb7512f366c4764ffc2e681Phil for s in self.sinks: 27053e354dd0edd0d111fb7512f366c4764ffc2e681Phil s.push(msg) 27153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _high_send(self, msg): 27253e354dd0edd0d111fb7512f366c4764ffc2e681Phil for s in self.high_sinks: 27353e354dd0edd0d111fb7512f366c4764ffc2e681Phil s.high_push(msg) 274f1288d41516059cab24e840f0d8cd2d1bf7735e0phil def _trigger(self, msg=None): 275dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil for s in self.trigger_sinks: 276dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s.on_trigger(msg) 27753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 27853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __repr__(self): 27953e354dd0edd0d111fb7512f366c4764ffc2e681Phil ct = conf.color_theme 28053e354dd0edd0d111fb7512f366c4764ffc2e681Phil s = "%s%s" % (ct.punct("<"), ct.layer_name(self.name)) 28153e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.sources or self.sinks: 28253e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+= " %s" % ct.punct("[") 28353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.sources: 28453e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+="%s%s" % (ct.punct(",").join(ct.field_name(s.name) for s in self.sources), 28553e354dd0edd0d111fb7512f366c4764ffc2e681Phil ct.field_value(">")) 28653e354dd0edd0d111fb7512f366c4764ffc2e681Phil s += ct.layer_name("#") 28753e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.sinks: 28853e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+="%s%s" % (ct.field_value(">"), 28953e354dd0edd0d111fb7512f366c4764ffc2e681Phil ct.punct(",").join(ct.field_name(s.name) for s in self.sinks)) 29053e354dd0edd0d111fb7512f366c4764ffc2e681Phil s += ct.punct("]") 29153e354dd0edd0d111fb7512f366c4764ffc2e681Phil 29253e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.high_sources or self.high_sinks: 29353e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+= " %s" % ct.punct("[") 29453e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.high_sources: 29553e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+="%s%s" % (ct.punct(",").join(ct.field_name(s.name) for s in self.high_sources), 29653e354dd0edd0d111fb7512f366c4764ffc2e681Phil ct.field_value(">>")) 29753e354dd0edd0d111fb7512f366c4764ffc2e681Phil s += ct.layer_name("#") 29853e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.high_sinks: 29953e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+="%s%s" % (ct.field_value(">>"), 30053e354dd0edd0d111fb7512f366c4764ffc2e681Phil ct.punct(",").join(ct.field_name(s.name) for s in self.high_sinks)) 30153e354dd0edd0d111fb7512f366c4764ffc2e681Phil s += ct.punct("]") 30253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 303dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil if self.trigger_sources or self.trigger_sinks: 304dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s+= " %s" % ct.punct("[") 305dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil if self.trigger_sources: 306dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s+="%s%s" % (ct.punct(",").join(ct.field_name(s.name) for s in self.trigger_sources), 307dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil ct.field_value("^")) 308dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s += ct.layer_name("#") 309dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil if self.trigger_sinks: 310dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s+="%s%s" % (ct.field_value("^"), 311dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil ct.punct(",").join(ct.field_name(s.name) for s in self.trigger_sinks)) 312dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil s += ct.punct("]") 313dbabf910cf2ddd7e420190267dd0c2a7abc2dfb1phil 31453e354dd0edd0d111fb7512f366c4764ffc2e681Phil 31553e354dd0edd0d111fb7512f366c4764ffc2e681Phil s += ct.punct(">") 31653e354dd0edd0d111fb7512f366c4764ffc2e681Phil return s 31753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 3180bfed5c5783d9e883abd6055079c833340052616gpotterclass Source(Pipe, SelectableObject): 31953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None): 32053e354dd0edd0d111fb7512f366c4764ffc2e681Phil Pipe.__init__(self, name=name) 32153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.is_exhausted = False 32253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _read_message(self): 32353e354dd0edd0d111fb7512f366c4764ffc2e681Phil return Message() 32453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def deliver(self): 32553e354dd0edd0d111fb7512f366c4764ffc2e681Phil msg = self._read_message 32653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._send(msg) 32753e354dd0edd0d111fb7512f366c4764ffc2e681Phil def fileno(self): 32853e354dd0edd0d111fb7512f366c4764ffc2e681Phil return None 3290bfed5c5783d9e883abd6055079c833340052616gpotter def check_recv(self): 3306178b488430ef900b56f3d5c1c9e5d92c0235c4fgpotter return False 33153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def exhausted(self): 33253e354dd0edd0d111fb7512f366c4764ffc2e681Phil return self.is_exhausted 33353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def start(self): 33453e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 33553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def stop(self): 33653e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 33753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 33853e354dd0edd0d111fb7512f366c4764ffc2e681Philclass Drain(Pipe): 33953e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Repeat messages from low/high entries to (resp.) low/high exits 34053e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 34153e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|-------|->> 34253e354dd0edd0d111fb7512f366c4764ffc2e681Phil | | 34353e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|-------|-> 34453e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 34553e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 34653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 34753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._send(msg) 34853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 34953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._high_send(msg) 35053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def start(self): 35153e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 35253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def stop(self): 35353e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 35453e354dd0edd0d111fb7512f366c4764ffc2e681Phil 35553e354dd0edd0d111fb7512f366c4764ffc2e681Philclass Sink(Pipe): 35653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 35753e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 35853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 35953e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 36053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def start(self): 36153e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 36253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def stop(self): 36353e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 36453e354dd0edd0d111fb7512f366c4764ffc2e681Phil 36553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 3660bfed5c5783d9e883abd6055079c833340052616gpotterclass AutoSource(Source, SelectableObject): 36753e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None): 36853e354dd0edd0d111fb7512f366c4764ffc2e681Phil Source.__init__(self, name=name) 36953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.__fdr,self.__fdw = os.pipe() 37053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._queue = collections.deque() 37153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def fileno(self): 37253e354dd0edd0d111fb7512f366c4764ffc2e681Phil return self.__fdr 3730bfed5c5783d9e883abd6055079c833340052616gpotter def check_recv(self): 374c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter return len(self._queue) > 0 37553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _gen_data(self, msg): 37653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._queue.append((msg,False)) 37753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._wake_up() 37853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _gen_high_data(self, msg): 37953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._queue.append((msg,True)) 38053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._wake_up() 38153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _wake_up(self): 3821fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter os.write(self.__fdw, b"X") 3836e173e9f6e570d6c3c8c76040b44e270c47308dbgpotter self.call_release() 38453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def deliver(self): 38553e354dd0edd0d111fb7512f366c4764ffc2e681Phil os.read(self.__fdr,1) 38653e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 38753e354dd0edd0d111fb7512f366c4764ffc2e681Phil msg,high = self._queue.popleft() 38853e354dd0edd0d111fb7512f366c4764ffc2e681Phil except IndexError: #empty queue. Exhausted source 38953e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 39053e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 39153e354dd0edd0d111fb7512f366c4764ffc2e681Phil if high: 39253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._high_send(msg) 39353e354dd0edd0d111fb7512f366c4764ffc2e681Phil else: 39453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._send(msg) 39553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 39653e354dd0edd0d111fb7512f366c4764ffc2e681Philclass ThreadGenSource(AutoSource): 39753e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None): 39853e354dd0edd0d111fb7512f366c4764ffc2e681Phil AutoSource.__init__(self, name=name) 39953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.RUN = False 40053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def generate(self): 40153e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 40253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def start(self): 40353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.RUN = True 40459a7b9f69b5b745e58c01288cb4f85fb535250b0gpotter Thread(target=self.generate).start() 40553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def stop(self): 40653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.RUN = False 40753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 40853e354dd0edd0d111fb7512f366c4764ffc2e681Phil 40953e354dd0edd0d111fb7512f366c4764ffc2e681Phil 41053e354dd0edd0d111fb7512f366c4764ffc2e681Philclass ConsoleSink(Sink): 41153e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Print messages on low and high entries 41253e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 41353e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--. |->> 41453e354dd0edd0d111fb7512f366c4764ffc2e681Phil | print | 41553e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--' |-> 41653e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 41753e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 41853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 419b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print(">%r" % msg) 42053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 421b72a0b59db7b6fa0726ffa22da3b88679bffe69cgpotter print(">>%r" % msg) 42253e354dd0edd0d111fb7512f366c4764ffc2e681Phil 42353e354dd0edd0d111fb7512f366c4764ffc2e681Philclass RawConsoleSink(Sink): 42453e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Print messages on low and high entries 42553e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 42653e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--. |->> 42753e354dd0edd0d111fb7512f366c4764ffc2e681Phil | write | 42853e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--' |-> 42953e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 43053e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 43153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None, newlines=True): 43253e354dd0edd0d111fb7512f366c4764ffc2e681Phil Sink.__init__(self, name=name) 43353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.newlines = newlines 4346178b488430ef900b56f3d5c1c9e5d92c0235c4fgpotter self._write_pipe = 1 43553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 43653e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.newlines: 43753e354dd0edd0d111fb7512f366c4764ffc2e681Phil msg += "\n" 4385e8857410015a93f6371459b2f870432ded39b9fgpotter os.write(self._write_pipe, msg.encode("utf8")) 43953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 44053e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.newlines: 44153e354dd0edd0d111fb7512f366c4764ffc2e681Phil msg += "\n" 4425e8857410015a93f6371459b2f870432ded39b9fgpotter os.write(self._write_pipe, msg.encode("utf8")) 44353e354dd0edd0d111fb7512f366c4764ffc2e681Phil 44453e354dd0edd0d111fb7512f366c4764ffc2e681Philclass CLIFeeder(AutoSource): 44553e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Send messages from python command line 44653e354dd0edd0d111fb7512f366c4764ffc2e681Phil +--------+ 44753e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-| |->> 44853e354dd0edd0d111fb7512f366c4764ffc2e681Phil | send() | 44953e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-| `----|-> 45053e354dd0edd0d111fb7512f366c4764ffc2e681Phil +--------+ 45153e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 45253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def send(self, msg): 45353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._gen_data(msg) 45453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def close(self): 45553e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.is_exhausted = True 45653e354dd0edd0d111fb7512f366c4764ffc2e681Phil 45753e354dd0edd0d111fb7512f366c4764ffc2e681Philclass CLIHighFeeder(CLIFeeder): 45853e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Send messages from python command line to high output 45953e354dd0edd0d111fb7512f366c4764ffc2e681Phil +--------+ 46053e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-| .----|->> 46153e354dd0edd0d111fb7512f366c4764ffc2e681Phil | send() | 46253e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-| |-> 46353e354dd0edd0d111fb7512f366c4764ffc2e681Phil +--------+ 46453e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 46553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def send(self, msg): 46653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._gen_high_data(msg) 46753e354dd0edd0d111fb7512f366c4764ffc2e681Phil 46853e354dd0edd0d111fb7512f366c4764ffc2e681Phil 46953e354dd0edd0d111fb7512f366c4764ffc2e681Philclass PeriodicSource(ThreadGenSource): 47053e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Generage messages periodically on low exit 47153e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 47253e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-| |->> 47353e354dd0edd0d111fb7512f366c4764ffc2e681Phil | msg,T | 47453e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-| `----|-> 47553e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 47653e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 47753e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, msg, period, period2=0, name=None): 47853e354dd0edd0d111fb7512f366c4764ffc2e681Phil ThreadGenSource.__init__(self,name=name) 4791fd5116590e760b8cd43ce41b8aaedec25251bcbgpotter if not isinstance(msg, (list, set, tuple)): 48053e354dd0edd0d111fb7512f366c4764ffc2e681Phil msg=[msg] 48153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.msg = msg 48253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.period = period 48353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.period2 = period2 48453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def generate(self): 48553e354dd0edd0d111fb7512f366c4764ffc2e681Phil while self.RUN: 48653e354dd0edd0d111fb7512f366c4764ffc2e681Phil empty_gen = True 48753e354dd0edd0d111fb7512f366c4764ffc2e681Phil for m in self.msg: 48853e354dd0edd0d111fb7512f366c4764ffc2e681Phil empty_gen = False 48953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._gen_data(m) 49053e354dd0edd0d111fb7512f366c4764ffc2e681Phil time.sleep(self.period) 49153e354dd0edd0d111fb7512f366c4764ffc2e681Phil if empty_gen: 49253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.is_exhausted = True 49353e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._wake_up() 49453e354dd0edd0d111fb7512f366c4764ffc2e681Phil time.sleep(self.period2) 49553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 49653e354dd0edd0d111fb7512f366c4764ffc2e681Philclass TermSink(Sink): 49753e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Print messages on low and high entries on a separate terminal 49853e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 49953e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--. |->> 50053e354dd0edd0d111fb7512f366c4764ffc2e681Phil | print | 50153e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--' |-> 50253e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 50353e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 50453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None, keepterm=True, newlines=True, openearly=True): 50553e354dd0edd0d111fb7512f366c4764ffc2e681Phil Sink.__init__(self, name=name) 50653e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.keepterm = keepterm 50753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.newlines = newlines 50853e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.openearly = openearly 50953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.opened = False 51053e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.openearly: 51153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.start() 512c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def _start_windows(self): 51353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if not self.opened: 51453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.opened = True 515c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter self.__f = get_temp_file() 5160bfed5c5783d9e883abd6055079c833340052616gpotter open(self.__f, "a").close() 517c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter self.name = "Scapy" if self.name is None else self.name 518c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter # Start a powershell in a new window and print the PID 519c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter cmd = "$app = Start-Process PowerShell -ArgumentList '-command &{$host.ui.RawUI.WindowTitle=\\\"%s\\\";Get-Content \\\"%s\\\" -wait}' -passthru; echo $app.Id" % (self.name, self.__f.replace("\\", "\\\\")) 520beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET proc = subprocess.Popen([conf.prog.powershell, cmd], stdout=subprocess.PIPE) 521beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET output, _ = proc.communicate() 522c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter # This is the process PID 523beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET self.pid = int(output) 524beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET print("PID: %d" % self.pid) 525c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def _start_unix(self): 52653e354dd0edd0d111fb7512f366c4764ffc2e681Phil if not self.opened: 52753e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.opened = True 528beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET rdesc, self.wdesc = os.pipe() 52953e354dd0edd0d111fb7512f366c4764ffc2e681Phil cmd = ["xterm"] 53053e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.name is not None: 53153e354dd0edd0d111fb7512f366c4764ffc2e681Phil cmd.extend(["-title",self.name]) 53253e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.keepterm: 53353e354dd0edd0d111fb7512f366c4764ffc2e681Phil cmd.append("-hold") 534beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET cmd.extend(["-e", "cat <&%d" % rdesc]) 535beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET self.proc = subprocess.Popen(cmd, close_fds=False) 536beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET os.close(rdesc) 537c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def start(self): 538c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter if WINDOWS: 539c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter return self._start_windows() 540c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter else: 541c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter return self._start_unix() 542c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def _stop_windows(self): 54353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if not self.keepterm: 54453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.opened = False 545c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter # Recipe to kill process with PID 546c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter # http://code.activestate.com/recipes/347462-terminating-a-subprocess-on-windows/ 547c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter import ctypes 548c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter PROCESS_TERMINATE = 1 549beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.pid) 550c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter ctypes.windll.kernel32.TerminateProcess(handle, -1) 551c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter ctypes.windll.kernel32.CloseHandle(handle) 552c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def _stop_unix(self): 55353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if not self.keepterm: 55453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.opened = False 555beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET self.proc.kill() 556beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET self.proc.wait() 557c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter def stop(self): 558c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter if WINDOWS: 559c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter return self._stop_windows() 560c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter else: 561c41c2867ee5d7d64bb58d159ab97e638f3cb96c3gpotter return self._stop_unix() 56253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def _print(self, s): 56353e354dd0edd0d111fb7512f366c4764ffc2e681Phil if self.newlines: 56453e354dd0edd0d111fb7512f366c4764ffc2e681Phil s+="\n" 565c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter if WINDOWS: 566beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET wdesc = open(self.__f, "a") 567beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET wdesc.write(s) 568beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET wdesc.close() 569c8aedce97942cf1963c137902d50d14cd5c28bf0gpotter else: 570beb5bd8ebcac8c800ffdcd379804740ab448b0ecPierre LALET os.write(self.wdesc, s.encode()) 57153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 57253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._print(str(msg)) 57353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 57453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._print(str(msg)) 57553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 57653e354dd0edd0d111fb7512f366c4764ffc2e681Phil 57753e354dd0edd0d111fb7512f366c4764ffc2e681Philclass QueueSink(Sink): 57853e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Collect messages from high and low entries and queue them. Messages are unqueued with the .recv() method. 57953e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 58053e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--. |->> 58153e354dd0edd0d111fb7512f366c4764ffc2e681Phil | queue | 58253e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--' |-> 58353e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 58453e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 58553e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, name=None): 58653e354dd0edd0d111fb7512f366c4764ffc2e681Phil Sink.__init__(self, name=name) 58722a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter self.q = six.moves.queue.Queue() 58853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 58953e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.q.put(msg) 59053e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 59153e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.q.put(msg) 59253e354dd0edd0d111fb7512f366c4764ffc2e681Phil def recv(self): 59353e354dd0edd0d111fb7512f366c4764ffc2e681Phil while True: 59453e354dd0edd0d111fb7512f366c4764ffc2e681Phil try: 59553e354dd0edd0d111fb7512f366c4764ffc2e681Phil return self.q.get(True, timeout=0.1) 59622a55b62eb35e8611fe03b99e4ff4f257a97b5d1gpotter except six.moves.queue.Empty: 59753e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 59853e354dd0edd0d111fb7512f366c4764ffc2e681Phil 59953e354dd0edd0d111fb7512f366c4764ffc2e681Phil 60053e354dd0edd0d111fb7512f366c4764ffc2e681Philclass TransformDrain(Drain): 60153e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Apply a function to messages on low and high entry 60253e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 60353e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--[f]--|->> 60453e354dd0edd0d111fb7512f366c4764ffc2e681Phil | | 60553e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--[f]--|-> 60653e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 60753e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 60853e354dd0edd0d111fb7512f366c4764ffc2e681Phil def __init__(self, f, name=None): 60953e354dd0edd0d111fb7512f366c4764ffc2e681Phil Drain.__init__(self, name=name) 61053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self.f = f 61153e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 61253e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._send(self.f(msg)) 61353e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 61453e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._high_send(self.f(msg)) 61553e354dd0edd0d111fb7512f366c4764ffc2e681Phil 61653e354dd0edd0d111fb7512f366c4764ffc2e681Philclass UpDrain(Drain): 61753e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Repeat messages from low entry to high exit 61853e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 61953e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-| ,--|->> 62053e354dd0edd0d111fb7512f366c4764ffc2e681Phil | / | 62153e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-|--' |-> 62253e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 62353e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 62453e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 62553e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._high_send(msg) 62653e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 62753e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 62853e354dd0edd0d111fb7512f366c4764ffc2e681Phil 62953e354dd0edd0d111fb7512f366c4764ffc2e681Philclass DownDrain(Drain): 63053e354dd0edd0d111fb7512f366c4764ffc2e681Phil """Repeat messages from high entry to low exit 63153e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 63253e354dd0edd0d111fb7512f366c4764ffc2e681Phil >>-|--. |->> 63353e354dd0edd0d111fb7512f366c4764ffc2e681Phil | \ | 63453e354dd0edd0d111fb7512f366c4764ffc2e681Phil >-| `--|-> 63553e354dd0edd0d111fb7512f366c4764ffc2e681Phil +-------+ 63653e354dd0edd0d111fb7512f366c4764ffc2e681Phil""" 63753e354dd0edd0d111fb7512f366c4764ffc2e681Phil def push(self, msg): 63853e354dd0edd0d111fb7512f366c4764ffc2e681Phil pass 63953e354dd0edd0d111fb7512f366c4764ffc2e681Phil def high_push(self, msg): 64053e354dd0edd0d111fb7512f366c4764ffc2e681Phil self._send(msg) 641