summaryrefslogtreecommitdiffstats
path: root/scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py')
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py753
1 files changed, 753 insertions, 0 deletions
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py
new file mode 100644
index 00000000..cd32b5c0
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/automaton.py
@@ -0,0 +1,753 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Automata with states, transitions and actions.
+"""
+
+from __future__ import with_statement
+import types,itertools,time,os,sys,socket,functools
+from select import select
+from collections import deque
+import _thread
+from .config import conf
+from .utils import do_graph
+from .error import log_interactive
+from .plist import PacketList
+from .data import MTU
+from .supersocket import SuperSocket
+
+class ObjectPipe:
+ def __init__(self):
+ self.rd,self.wr = os.pipe()
+ self.queue = deque()
+ def fileno(self):
+ return self.rd
+ def send(self, obj):
+ self.queue.append(obj)
+ os.write(self.wr,b"X")
+ def recv(self, n=0):
+ os.read(self.rd,1)
+ return self.queue.popleft()
+
+
+class Message:
+ def __init__(self, **args):
+ self.__dict__.update(args)
+ def __repr__(self):
+ return "<Message %s>" % " ".join("%s=%r"%(k,v)
+ for (k,v) in self.__dict__.items()
+ if not k.startswith("_"))
+
+# Currently does not seem necessary
+# class _meta_instance_state(type):
+# def __init__(cls, name, bases, dct):
+# def special_gen(special_method):
+# def special_wrapper(self):
+# print("Calling %s" % special_method)
+# return getattr(getattr(self, "im_func"), special_method)
+# return special_wrapper
+
+# type.__init__(cls, name, bases, dct)
+# for i in ["__int__", "__repr__", "__str__", "__index__", "__add__", "__radd__", "__bytes__"]:
+# setattr(cls, i, property(special_gen(i)))
+
+class _instance_state():
+ def __init__(self, instance):
+ self.im_self = instance.__self__
+ self.im_func = instance.__func__
+ self.im_class = instance.__self__.__class__
+ def __getattr__(self, attr):
+ return getattr(self.im_func, attr)
+
+ def __call__(self, *args, **kargs):
+ return self.im_func(self.im_self, *args, **kargs)
+ def breaks(self):
+ return self.im_self.add_breakpoints(self.im_func)
+ def intercepts(self):
+ return self.im_self.add_interception_points(self.im_func)
+ def unbreaks(self):
+ return self.im_self.remove_breakpoints(self.im_func)
+ def unintercepts(self):
+ return self.im_self.remove_interception_points(self.im_func)
+
+
+##############
+## Automata ##
+##############
+
+class ATMT:
+ STATE = "State"
+ ACTION = "Action"
+ CONDITION = "Condition"
+ RECV = "Receive condition"
+ TIMEOUT = "Timeout condition"
+ IOEVENT = "I/O event"
+
+ class NewStateRequested(Exception):
+ def __init__(self, state_func, automaton, *args, **kargs):
+ self.func = state_func
+ self.state = state_func.atmt_state
+ self.initial = state_func.atmt_initial
+ self.error = state_func.atmt_error
+ self.final = state_func.atmt_final
+ Exception.__init__(self, "Request state [%s]" % self.state)
+ self.automaton = automaton
+ self.args = args
+ self.kargs = kargs
+ self.action_parameters() # init action parameters
+ def action_parameters(self, *args, **kargs):
+ self.action_args = args
+ self.action_kargs = kargs
+ return self
+ def run(self):
+ return self.func(self.automaton, *self.args, **self.kargs)
+ def __repr__(self):
+ return "NewStateRequested(%s)" % self.state
+
+ @staticmethod
+ def state(initial=0,final=0,error=0):
+ def deco(f,initial=initial, final=final):
+ f.atmt_type = ATMT.STATE
+ f.atmt_state = f.__name__
+ f.atmt_initial = initial
+ f.atmt_final = final
+ f.atmt_error = error
+# @functools.wraps(f) This is possible alternative to assigning __qualname__; it would save __doc__, too
+ def state_wrapper(self, *args, **kargs):
+ return ATMT.NewStateRequested(f, self, *args, **kargs)
+
+ state_wrapper.__qualname__ = "%s_wrapper" % f.__name__
+ state_wrapper.atmt_type = ATMT.STATE
+ state_wrapper.atmt_state = f.__name__
+ state_wrapper.atmt_initial = initial
+ state_wrapper.atmt_final = final
+ state_wrapper.atmt_error = error
+ state_wrapper.atmt_origfunc = f
+ return state_wrapper
+ return deco
+ @staticmethod
+ def action(cond, prio=0):
+ def deco(f,cond=cond):
+ if not hasattr(f,"atmt_type"):
+ f.atmt_cond = {}
+ f.atmt_type = ATMT.ACTION
+ f.atmt_cond[cond.atmt_condname] = prio
+ return f
+ return deco
+ @staticmethod
+ def condition(state, prio=0):
+ def deco(f, state=state):
+ f.atmt_type = ATMT.CONDITION
+ f.atmt_state = state.atmt_state
+ f.atmt_condname = f.__name__
+ f.atmt_prio = prio
+ return f
+ return deco
+ @staticmethod
+ def receive_condition(state, prio=0):
+ def deco(f, state=state):
+ f.atmt_type = ATMT.RECV
+ f.atmt_state = state.atmt_state
+ f.atmt_condname = f.__name__
+ f.atmt_prio = prio
+ return f
+ return deco
+ @staticmethod
+ def ioevent(state, name, prio=0, as_supersocket=None):
+ def deco(f, state=state):
+ f.atmt_type = ATMT.IOEVENT
+ f.atmt_state = state.atmt_state
+ f.atmt_condname = f.__name__
+ f.atmt_ioname = name
+ f.atmt_prio = prio
+ f.atmt_as_supersocket = as_supersocket
+ return f
+ return deco
+ @staticmethod
+ def timeout(state, timeout):
+ def deco(f, state=state, timeout=timeout):
+ f.atmt_type = ATMT.TIMEOUT
+ f.atmt_state = state.atmt_state
+ f.atmt_timeout = timeout
+ f.atmt_condname = f.__name__
+ return f
+ return deco
+
+class _ATMT_Command:
+ RUN = "RUN"
+ NEXT = "NEXT"
+ FREEZE = "FREEZE"
+ STOP = "STOP"
+ END = "END"
+ EXCEPTION = "EXCEPTION"
+ SINGLESTEP = "SINGLESTEP"
+ BREAKPOINT = "BREAKPOINT"
+ INTERCEPT = "INTERCEPT"
+ ACCEPT = "ACCEPT"
+ REPLACE = "REPLACE"
+ REJECT = "REJECT"
+
+class _ATMT_supersocket(SuperSocket):
+ def __init__(self, name, ioevent, automaton, proto, args, kargs):
+ self.name = name
+ self.ioevent = ioevent
+ self.proto = proto
+ self.spa,self.spb = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM)
+ kargs["external_fd"] = {ioevent:self.spb}
+ self.atmt = automaton(*args, **kargs)
+ self.atmt.runbg()
+ def fileno(self):
+ return self.spa.fileno()
+ def send(self, s):
+ if type(s) is str:
+ s = s.encode()
+ elif type(s) is not bytes:
+ s = bytes(s)
+ return self.spa.send(s)
+ def recv(self, n=MTU):
+ r = self.spa.recv(n)
+ if self.proto is not None:
+ r = self.proto(r)
+ return r
+ def close(self):
+ pass
+
+class _ATMT_to_supersocket:
+ def __init__(self, name, ioevent, automaton):
+ self.name = name
+ self.ioevent = ioevent
+ self.automaton = automaton
+ def __call__(self, proto, *args, **kargs):
+ return _ATMT_supersocket(self.name, self.ioevent, self.automaton, proto, args, kargs)
+
+class Automaton_metaclass(type):
+ def __new__(cls, name, bases, dct):
+ cls = super(Automaton_metaclass, cls).__new__(cls, name, bases, dct)
+ cls.states={}
+ cls.state = None
+ cls.recv_conditions={}
+ cls.conditions={}
+ cls.ioevents={}
+ cls.timeout={}
+ cls.actions={}
+ cls.initial_states=[]
+ cls.ionames = []
+ cls.iosupersockets = []
+
+ members = {}
+ classes = [cls]
+ while classes:
+ c = classes.pop(0) # order is important to avoid breaking method overloading
+ classes += list(c.__bases__)
+ for k,v in c.__dict__.items():
+ if k not in members:
+ members[k] = v
+
+ decorated = [v for v in members.values()
+ if type(v) is types.FunctionType and hasattr(v, "atmt_type")]
+
+ for m in decorated:
+ if m.atmt_type == ATMT.STATE:
+ s = m.atmt_state
+ cls.states[s] = m
+ cls.recv_conditions[s]=[]
+ cls.ioevents[s]=[]
+ cls.conditions[s]=[]
+ cls.timeout[s]=[]
+ if m.atmt_initial:
+ cls.initial_states.append(m)
+ elif m.atmt_type in [ATMT.CONDITION, ATMT.RECV, ATMT.TIMEOUT, ATMT.IOEVENT]:
+ cls.actions[m.atmt_condname] = []
+
+ for m in decorated:
+ if m.atmt_type == ATMT.CONDITION:
+ cls.conditions[m.atmt_state].append(m)
+ elif m.atmt_type == ATMT.RECV:
+ cls.recv_conditions[m.atmt_state].append(m)
+ elif m.atmt_type == ATMT.IOEVENT:
+ cls.ioevents[m.atmt_state].append(m)
+ cls.ionames.append(m.atmt_ioname)
+ if m.atmt_as_supersocket is not None:
+ cls.iosupersockets.append(m)
+ elif m.atmt_type == ATMT.TIMEOUT:
+ cls.timeout[m.atmt_state].append((m.atmt_timeout, m))
+ elif m.atmt_type == ATMT.ACTION:
+ for c in m.atmt_cond:
+ cls.actions[c].append(m)
+
+
+ for v in cls.timeout.values():
+ #v.sort(lambda (t1,f1),(t2,f2): cmp(t1,t2))
+ v.sort(key = lambda x: x[0])
+ v.append((None, None))
+ for v in itertools.chain(cls.conditions.values(),
+ cls.recv_conditions.values(),
+ cls.ioevents.values()):
+ v.sort(key = lambda x: x.atmt_prio)
+ for condname,actlst in cls.actions.items():
+ actlst.sort(key = lambda x: x.atmt_cond[condname])
+
+ for ioev in cls.iosupersockets:
+ setattr(cls, ioev.atmt_as_supersocket, _ATMT_to_supersocket(ioev.atmt_as_supersocket, ioev.atmt_ioname, cls))
+
+ return cls
+
+ def graph(self, **kargs):
+ s = 'digraph "%s" {\n' % self.__class__.__name__
+
+ se = "" # Keep initial nodes at the begining for better rendering
+ for st in self.states.values():
+ if st.atmt_initial:
+ se = ('\t"%s" [ style=filled, fillcolor=blue, shape=box, root=true];\n' % st.atmt_state)+se
+ elif st.atmt_final:
+ se += '\t"%s" [ style=filled, fillcolor=green, shape=octagon ];\n' % st.atmt_state
+ elif st.atmt_error:
+ se += '\t"%s" [ style=filled, fillcolor=red, shape=octagon ];\n' % st.atmt_state
+ s += se
+
+ for st in self.states.values():
+ for n in st.atmt_origfunc.__code__.co_names+st.atmt_origfunc.__code__.co_consts:
+ if n in self.states:
+ s += '\t"%s" -> "%s" [ color=green ];\n' % (st.atmt_state,n)
+
+
+ for c,k,v in ([("purple",k,v) for k,v in self.conditions.items()]+
+ [("red",k,v) for k,v in self.recv_conditions.items()]+
+ [("orange",k,v) for k,v in self.ioevents.items()]):
+ for f in v:
+ for n in f.__code__.co_names+f.__code__.co_consts:
+ if n in self.states:
+ l = f.atmt_condname
+ for x in self.actions[f.atmt_condname]:
+ l += "\\l>[%s]" % x.__name__
+ s += '\t"%s" -> "%s" [label="%s", color=%s];\n' % (k,n,l,c)
+ for k,v in self.timeout.items():
+ for t,f in v:
+ if f is None:
+ continue
+ for n in f.__code__.co_names+f.__code__.co_consts:
+ if n in self.states:
+ l = "%s/%.1fs" % (f.atmt_condname,t)
+ for x in self.actions[f.atmt_condname]:
+ l += "\\l>[%s]" % x.__name__
+ s += '\t"%s" -> "%s" [label="%s",color=blue];\n' % (k,n,l)
+ s += "}\n"
+ return do_graph(s, **kargs)
+
+
+
+class Automaton(metaclass = Automaton_metaclass):
+
+ ## Methods to overload
+ def parse_args(self, debug=0, store=1, **kargs):
+ self.debug_level=debug
+ self.socket_kargs = kargs
+ self.store_packets = store
+
+ def master_filter(self, pkt):
+ return True
+
+ def my_send(self, pkt):
+ self.send_sock.send(pkt)
+
+
+ ## Utility classes and exceptions
+ class _IO_fdwrapper:
+ def __init__(self,rd,wr):
+ if rd is not None and type(rd) is not int:
+ rd = rd.fileno()
+ if wr is not None and type(wr) is not int:
+ wr = wr.fileno()
+ self.rd = rd
+ self.wr = wr
+ def fileno(self):
+ return self.rd
+ def read(self, n=65535):
+ return os.read(self.rd, n)
+ def write(self, msg):
+ return os.write(self.wr,msg)
+ def recv(self, n=65535):
+ return self.read(n)
+ def send(self, msg):
+ return self.write(msg)
+
+ class _IO_mixer:
+ def __init__(self,rd,wr):
+ self.rd = rd
+ self.wr = wr
+ def fileno(self):
+ if type(self.rd) is int:
+ return self.rd
+ return self.rd.fileno()
+ def recv(self, n=None):
+ return self.rd.recv(n)
+ def read(self, n=None):
+ return self.rd.recv(n)
+ def send(self, msg):
+ return self.wr.send(msg)
+ def write(self, msg):
+ return self.wr.send(msg)
+
+
+ class AutomatonException(Exception):
+ def __init__(self, msg, state=None, result=None):
+ Exception.__init__(self, msg)
+ self.state = state
+ self.result = result
+
+ class AutomatonError(AutomatonException):
+ pass
+ class ErrorState(AutomatonException):
+ pass
+ class Stuck(AutomatonException):
+ pass
+ class AutomatonStopped(AutomatonException):
+ pass
+
+ class Breakpoint(AutomatonStopped):
+ pass
+ class Singlestep(AutomatonStopped):
+ pass
+ class InterceptionPoint(AutomatonStopped):
+ def __init__(self, msg, state=None, result=None, packet=None):
+ Automaton.AutomatonStopped.__init__(self, msg, state=state, result=result)
+ self.packet = packet
+
+ class CommandMessage(AutomatonException):
+ pass
+
+
+ ## Services
+ def debug(self, lvl, msg):
+ if self.debug_level >= lvl:
+ log_interactive.debug(msg)
+
+ def send(self, pkt):
+ if self.state.state in self.interception_points:
+ self.debug(3,"INTERCEPT: packet intercepted: %s" % pkt.summary())
+ self.intercepted_packet = pkt
+ cmd = Message(type = _ATMT_Command.INTERCEPT, state=self.state, pkt=pkt)
+ self.cmdout.send(cmd)
+ cmd = self.cmdin.recv()
+ self.intercepted_packet = None
+ if cmd.type == _ATMT_Command.REJECT:
+ self.debug(3,"INTERCEPT: packet rejected")
+ return
+ elif cmd.type == _ATMT_Command.REPLACE:
+ pkt = cmd.pkt
+ self.debug(3,"INTERCEPT: packet replaced by: %s" % pkt.summary())
+ elif cmd.type == _ATMT_Command.ACCEPT:
+ self.debug(3,"INTERCEPT: packet accepted")
+ else:
+ raise self.AutomatonError("INTERCEPT: unkown verdict: %r" % cmd.type)
+ self.my_send(pkt)
+ self.debug(3,"SENT : %s" % pkt.summary())
+ self.packets.append(pkt.copy())
+
+
+ ## Internals
+ def __init__(self, *args, **kargs):
+ external_fd = kargs.pop("external_fd",{})
+ self.send_sock_class = kargs.pop("ll", conf.L3socket)
+ self.started = _thread.allocate_lock()
+ self.threadid = None
+ self.breakpointed = None
+ self.breakpoints = set()
+ self.interception_points = set()
+ self.intercepted_packet = None
+ self.debug_level=0
+ self.init_args=args
+ self.init_kargs=kargs
+ self.io = type.__new__(type, "IOnamespace",(),{})
+ self.oi = type.__new__(type, "IOnamespace",(),{})
+ self.cmdin = ObjectPipe()
+ self.cmdout = ObjectPipe()
+ self.ioin = {}
+ self.ioout = {}
+ for n in self.ionames:
+ extfd = external_fd.get(n)
+ if type(extfd) is not tuple:
+ extfd = (extfd,extfd)
+ ioin,ioout = extfd
+ if ioin is None:
+ ioin = ObjectPipe()
+ #elif type(ioin) is not types.InstanceType:
+ else:
+ #print(type(ioin))
+ ioin = self._IO_fdwrapper(ioin,None)
+ if ioout is None:
+ ioout = ObjectPipe()
+ #elif type(ioout) is not types.InstanceType:
+ else:
+ #print(type(ioout))
+ ioout = self._IO_fdwrapper(None,ioout)
+
+ self.ioin[n] = ioin
+ self.ioout[n] = ioout
+ ioin.ioname = n
+ ioout.ioname = n
+ setattr(self.io, n, self._IO_mixer(ioout,ioin))
+ setattr(self.oi, n, self._IO_mixer(ioin,ioout))
+
+ for stname in self.states:
+ setattr(self, stname,
+ _instance_state(getattr(self, stname)))
+
+ self.parse_args(*args, **kargs)
+
+ self.start()
+
+ def __iter__(self):
+ return self
+
+ def __del__(self):
+ self.stop()
+
+ def _run_condition(self, cond, *args, **kargs):
+ try:
+ self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname))
+ cond(self,*args, **kargs)
+ except ATMT.NewStateRequested as state_req:
+ self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state))
+ if cond.atmt_type == ATMT.RECV:
+ self.packets.append(args[0])
+ for action in self.actions[cond.atmt_condname]:
+ self.debug(2, " + Running action [%s]" % action.__name__)
+ action(self, *state_req.action_args, **state_req.action_kargs)
+ raise
+ except Exception as e:
+ self.debug(2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e))
+ raise
+ else:
+ self.debug(2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname))
+
+ def _do_start(self, *args, **kargs):
+
+ _thread.start_new_thread(self._do_control, args, kargs)
+
+
+ def _do_control(self, *args, **kargs):
+ with self.started:
+ self.threadid = _thread.get_ident()
+
+ # Update default parameters
+ a = args+self.init_args[len(args):]
+ k = self.init_kargs.copy()
+ k.update(kargs)
+ self.parse_args(*a,**k)
+
+ # Start the automaton
+ self.state=self.initial_states[0](self)
+ self.send_sock = self.send_sock_class()
+ self.listen_sock = conf.L2listen(**self.socket_kargs)
+ self.packets = PacketList(name="session[%s]"%self.__class__.__name__)
+
+ singlestep = True
+ iterator = self._do_iter()
+ self.debug(3, "Starting control thread [tid=%i]" % self.threadid)
+ try:
+ while True:
+ c = self.cmdin.recv()
+ self.debug(5, "Received command %s" % c.type)
+ if c.type == _ATMT_Command.RUN:
+ singlestep = False
+ elif c.type == _ATMT_Command.NEXT:
+ singlestep = True
+ elif c.type == _ATMT_Command.FREEZE:
+ continue
+ elif c.type == _ATMT_Command.STOP:
+ break
+ while True:
+ state = next(iterator)
+ if isinstance(state, self.CommandMessage):
+ break
+ elif isinstance(state, self.Breakpoint):
+ c = Message(type=_ATMT_Command.BREAKPOINT,state=state)
+ self.cmdout.send(c)
+ break
+ if singlestep:
+ c = Message(type=_ATMT_Command.SINGLESTEP,state=state)
+ self.cmdout.send(c)
+ break
+ except StopIteration as e:
+ c = Message(type=_ATMT_Command.END, result=e.args[0])
+ self.cmdout.send(c)
+ except Exception as e:
+ self.debug(3, "Transfering exception [%s] from tid=%i"% (e,self.threadid))
+ m = Message(type = _ATMT_Command.EXCEPTION, exception=e, exc_info=sys.exc_info())
+ self.cmdout.send(m)
+ self.debug(3, "Stopping control thread (tid=%i)"%self.threadid)
+ self.threadid = None
+
+ def _do_iter(self):
+ while True:
+ try:
+ self.debug(1, "## state=[%s]" % self.state.state)
+
+ # Entering a new state. First, call new state function
+ if self.state.state in self.breakpoints and self.state.state != self.breakpointed:
+ self.breakpointed = self.state.state
+ yield self.Breakpoint("breakpoint triggered on state %s" % self.state.state,
+ state = self.state.state)
+ self.breakpointed = None
+ state_output = self.state.run()
+ if self.state.error:
+ raise self.ErrorState("Reached %s: [%r]" % (self.state.state, state_output),
+ result=state_output, state=self.state.state)
+ if self.state.final:
+ raise StopIteration(state_output)
+
+ if state_output is None:
+ state_output = ()
+ elif type(state_output) is not list:
+ state_output = state_output,
+
+ # Then check immediate conditions
+ for cond in self.conditions[self.state.state]:
+ self._run_condition(cond, *state_output)
+
+ # If still there and no conditions left, we are stuck!
+ if ( len(self.recv_conditions[self.state.state]) == 0 and
+ len(self.ioevents[self.state.state]) == 0 and
+ len(self.timeout[self.state.state]) == 1 ):
+ raise self.Stuck("stuck in [%s]" % self.state.state,
+ state=self.state.state, result=state_output)
+
+ # Finally listen and pay attention to timeouts
+ expirations = iter(self.timeout[self.state.state])
+ next_timeout,timeout_func = next(expirations)
+ t0 = time.time()
+
+ fds = [self.cmdin]
+ if len(self.recv_conditions[self.state.state]) > 0:
+ fds.append(self.listen_sock)
+ for ioev in self.ioevents[self.state.state]:
+ fds.append(self.ioin[ioev.atmt_ioname])
+ while 1:
+ t = time.time()-t0
+ if next_timeout is not None:
+ if next_timeout <= t:
+ self._run_condition(timeout_func, *state_output)
+ next_timeout,timeout_func = next(expirations)
+ if next_timeout is None:
+ remain = None
+ else:
+ remain = next_timeout-t
+
+ self.debug(5, "Select on %r" % fds)
+ r,_,_ = select(fds,[],[],remain)
+ self.debug(5, "Selected %r" % r)
+ for fd in r:
+ self.debug(5, "Looking at %r" % fd)
+ if fd == self.cmdin:
+ yield self.CommandMessage("Received command message")
+ elif fd == self.listen_sock:
+ pkt = self.listen_sock.recv(MTU)
+ if pkt is not None:
+ if self.master_filter(pkt):
+ self.debug(3, "RECVD: %s" % pkt.summary())
+ for rcvcond in self.recv_conditions[self.state.state]:
+ self._run_condition(rcvcond, pkt, *state_output)
+ else:
+ self.debug(4, "FILTR: %s" % pkt.summary())
+ else:
+ self.debug(3, "IOEVENT on %s" % fd.ioname)
+ for ioevt in self.ioevents[self.state.state]:
+ if ioevt.atmt_ioname == fd.ioname:
+ self._run_condition(ioevt, fd, *state_output)
+
+ except ATMT.NewStateRequested as state_req:
+ self.debug(2, "switching from [%s] to [%s]" % (self.state.state,state_req.state))
+ self.state = state_req
+ yield state_req
+
+ ## Public API
+ def add_interception_points(self, *ipts):
+ for ipt in ipts:
+ if hasattr(ipt,"atmt_state"):
+ ipt = ipt.atmt_state
+ self.interception_points.add(ipt)
+
+ def remove_interception_points(self, *ipts):
+ for ipt in ipts:
+ if hasattr(ipt,"atmt_state"):
+ ipt = ipt.atmt_state
+ self.interception_points.discard(ipt)
+
+ def add_breakpoints(self, *bps):
+ for bp in bps:
+ if hasattr(bp,"atmt_state"):
+ bp = bp.atmt_state
+ self.breakpoints.add(bp)
+
+ def remove_breakpoints(self, *bps):
+ for bp in bps:
+ if hasattr(bp,"atmt_state"):
+ bp = bp.atmt_state
+ self.breakpoints.discard(bp)
+
+ def start(self, *args, **kargs):
+ if not self.started.locked():
+ self._do_start(*args, **kargs)
+
+ def run(self, resume=None, wait=True):
+ if resume is None:
+ resume = Message(type = _ATMT_Command.RUN)
+ self.cmdin.send(resume)
+ if wait:
+ try:
+ c = self.cmdout.recv()
+ except KeyboardInterrupt:
+ self.cmdin.send(Message(type = _ATMT_Command.FREEZE))
+ return
+ if c.type == _ATMT_Command.END:
+ return c.result
+ elif c.type == _ATMT_Command.INTERCEPT:
+ raise self.InterceptionPoint("packet intercepted", state=c.state.state, packet=c.pkt)
+ elif c.type == _ATMT_Command.SINGLESTEP:
+ raise self.Singlestep("singlestep state=[%s]"%c.state.state, state=c.state.state)
+ elif c.type == _ATMT_Command.BREAKPOINT:
+ raise self.Breakpoint("breakpoint triggered on state [%s]"%c.state.state, state=c.state.state)
+ elif c.type == _ATMT_Command.EXCEPTION:
+ raise c.exc_info[0](c.exc_info[1])
+ #raise c.exc_info[0],c.exc_info[1],c.exc_info[2]
+
+ def runbg(self, resume=None, wait=False):
+ self.run(resume, wait)
+
+ def next(self):
+ return self.run(resume = Message(type=_ATMT_Command.NEXT))
+
+ def stop(self):
+ self.cmdin.send(Message(type=_ATMT_Command.STOP))
+ with self.started:
+ # Flush command pipes
+ while True:
+ r,_,_ = select([self.cmdin, self.cmdout],[],[],0)
+ if not r:
+ break
+ for fd in r:
+ fd.recv()
+
+ def restart(self, *args, **kargs):
+ self.stop()
+ self.start(*args, **kargs)
+
+ def accept_packet(self, pkt=None, wait=False):
+ rsm = Message()
+ if pkt is None:
+ rsm.type = _ATMT_Command.ACCEPT
+ else:
+ rsm.type = _ATMT_Command.REPLACE
+ rsm.pkt = pkt
+ return self.run(resume=rsm, wait=wait)
+
+ def reject_packet(self, wait=False):
+ rsm = Message(type = _ATMT_Command.REJECT)
+ return self.run(resume=rsm, wait=wait)
+
+
+