From bfae396ab3b373b7d081a75a1b139907f4ea0a4b Mon Sep 17 00:00:00 2001
From: Phil <phil@secdev.org>
Date: Thu, 30 Apr 2009 16:14:28 +0200
Subject: [PATCH] Added ability to provide external file descriptors for
 IOevents in automata

---
 scapy/automaton.py  | 44 ++++++++++++++++++++++++++++++++++++++------
 test/regression.uts | 29 ++++++++++++++++++++++++++++-
 2 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/scapy/automaton.py b/scapy/automaton.py
index b5b1cb01..3c500131 100644
--- a/scapy/automaton.py
+++ b/scapy/automaton.py
@@ -276,7 +276,26 @@ class Automaton:
 
 
     ## Utility classes and exceptions
-    class _IO_wrapper:
+    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):
+            return os.read(self.rd, n)
+        def write(self, msg):
+            return os.write(self.wr,msg)
+        def recv(self, n):
+            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
@@ -316,7 +335,7 @@ class Automaton:
             
 
     ## Internals
-    def __init__(self, *args, **kargs):
+    def __init__(self, external_fd={}, *args, **kargs):
         self.running = thread.allocate_lock()
         self.threadid = None
         self.breakpointed = None
@@ -332,12 +351,25 @@ class Automaton:
         self.ioin = {}
         self.ioout = {}
         for n in self.ionames:
-            self.ioin[n] = ioin = ObjectPipe()
-            self.ioout[n] = ioout = ObjectPipe()
+            extfd = external_fd.get(n)
+            if type(extfd) is not tuple:
+                extfd = (extfd,None)
+            ioin,ioout = extfd                
+            if ioin is None:
+                ioin = ObjectPipe()
+            elif type(ioin) is int:
+                ioin = self._IO_fdwrapper(ioin,None)
+            if ioout is None:
+                ioout = ObjectPipe()
+            elif type(ioout) is int:
+                ioin = 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_wrapper(ioout,ioin))
-            setattr(self.oi, n, self._IO_wrapper(ioin,ioout))
+            setattr(self.io, n, self._IO_mixer(ioout,ioin))
+            setattr(self.oi, n, self._IO_mixer(ioin,ioout))
         
         self.parse_args(*args, **kargs)
 
diff --git a/test/regression.uts b/test/regression.uts
index 3d36ca81..8c69930a 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -929,7 +929,34 @@ assert( _ == "Saturn" )
 
 = Automaton test io event from external fd
 ~ automaton
-pass
+class ATMT8(Automaton):
+    @ATMT.state(initial=1)
+    def BEGIN(self):
+        self.res = "U"
+    @ATMT.ioevent(BEGIN, name="extfd")
+    def tr1(self, fd):
+        self.res += fd.read(2)
+        raise self.NEXT_STATE()
+    @ATMT.state()
+    def NEXT_STATE(self):
+        pass
+    @ATMT.ioevent(NEXT_STATE, name="extfd")
+    def tr2(self, fd):
+        self.res += fd.read(2)
+        raise self.END()
+    @ATMT.state(final=1)
+    def END(self):
+        self.res += "s"
+        return self.res
+
+r,w = os.pipe()
+
+a=ATMT8(external_fd={"extfd":r})
+a.run(wait=False)
+os.write(w,"ra")
+os.write(w,"nu")
+a.run()
+assert( _ == "Uranus" )
  
 
 + Test IP options
-- 
GitLab