From 0e779a8d824a1c5f99f0e44d6b15b417a6d3f288 Mon Sep 17 00:00:00 2001
From: gpotter2 <gabriel@potter.fr>
Date: Fri, 23 Jun 2017 15:33:59 +0200
Subject: [PATCH] Add Doc to SelectableObjects

---
 scapy/automaton.py | 56 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 3 deletions(-)

diff --git a/scapy/automaton.py b/scapy/automaton.py
index 0ece6e61..86285804 100644
--- a/scapy/automaton.py
+++ b/scapy/automaton.py
@@ -19,14 +19,55 @@ from scapy.data import MTU
 from scapy.supersocket import SuperSocket
 from scapy.consts import WINDOWS
 
+# In Windows, select.select is not available for custom objects. Here's the implementation of scapy to re-create this functionnality
+# Passive way: using no-ressources locks
+"""
+               +---------+             +---------------+      +-------------------------+
+               |  Start  +------------->Select_objects +----->+Linux: call select.select|
+               +---------+             |(select.select)|      +-------------------------+
+                                       +-------+-------+
+                                               |
+                                          +----v----+               +--------+
+                                          | Windows |               |Time Out+----------------------------------+
+                                          +----+----+               +----+---+                                  |
+                                               |                         ^                                      |
+      Event                                    |                         |                                      |
+        +                                      |                         |                                      |
+        |                              +-------v-------+                 |                                      |
+        |                       +------+Selectable Sel.+-----+-----------------+-----------+                    |
+        |                       |      +-------+-------+     |           |     |           v              +-----v-----+
++-------v----------+            |              |             |           |     |        Passive lock<-----+release_all<------+
+|Data added to list|       +----v-----+  +-----v-----+  +----v-----+     v     v            +             +-----------+      |
++--------+---------+       |Selectable|  |Selectable |  |Selectable|   ............         |                                |
+         |                 +----+-----+  +-----------+  +----------+                        |                                |
+         |                      v                                                           |                                |
+         v                 +----+------+   +------------------+               +-------------v-------------------+            |
+   +-----+------+          |wait_return+-->+  check_recv:     |               |                                 |            |
+   |call_release|          +----+------+   |If data is in list|               |  END state: selectable returned |        +---+--------+
+   +-----+--------              v          +-------+----------+               |                                 |        | exit door  |
+         |                    else                 |                          +---------------------------------+        +---+--------+
+         |                      +                  |                                                                         |
+         |                 +----v-------+          |                                                                         |
+         +--------->free -->Passive lock|          |                                                                         |
+                           +----+-------+          |                                                                         |
+                                |                  |                                                                         |
+                                |                  v                                                                         |
+                                +------------------Selectable-Selector-is-advertised-that-the-selectable-is-readable---------+
+"""
+
 class SelectableObject:
+    """DEV: to implement one of those, you need to add 2 things to your object:
+    - add "check_recv" function
+    - call "self.call_release" once you are ready to be read"""
     trigger = threading.Lock()
     was_ended = False
     def check_recv(self):
         """DEV: will be called only once (at beggining) to check if the object is ready."""
-        return False
+        raise OSError("This function must be overwriten.")
 
     def _wait_non_ressources(self, callback):
+        # This get started as a thread, and waits for the data lock to be freed
+        # Then advertise itself to the SelectableSelector using the callback
         self.call_release()
         self.trigger.acquire()
         self.trigger.acquire()
@@ -34,12 +75,14 @@ class SelectableObject:
             callback(self)
 
     def wait_return(self, callback):
+        # Entry point of SelectableObject: register the callback
         if self.check_recv():
             return callback(self)
         threading.Thread(target=self._wait_non_ressources, args=(callback,)).start()
         
     def call_release(self, arborted=False):
-        """DEV: Must be call when the object is ready to read."""
+        """DEV: Must be call when the object becomes ready to read."""
+        # Relesases the lock of _wait_non_ressources
         self.was_ended = arborted
         try:
             self.trigger.release()
@@ -59,17 +102,21 @@ class SelectableSelector(object):
     available_lock = None
     _ended = False
     def _release_all(self):
+        # Releases all locks to kill all threads
         for i in self.inputs:
             i.call_release(True)
         self.available_lock.release()
 
     def _timeout_thread(self, remain):
+        # Timeout before releasing every thing, if nothing was returned
         time.sleep(remain)
         if not self._ended:
             self._ended = True
             self._release_all()
 
     def _exit_door(self,_input):
+        # This function is passed to each SelectableObject as a callback
+        # The SelectableObjects have to call it once there are ready
         self.results.append(_input)
         if self._ended:
             return
@@ -85,6 +132,7 @@ class SelectableSelector(object):
         self._ended = False
 
     def process(self):
+        # Entry point of SelectableSelector
         if WINDOWS:
             if not self.remain:
                 for i in self.inputs:
@@ -111,7 +159,9 @@ class SelectableSelector(object):
 
 def select_objects(inputs, remain):
     """
-    Select SelectableObject objects.
+    Select SelectableObject objects. Same than:
+        select.select([inputs], [], [], remain)
+    But also works on Windows, only on SelectableObject.
     
     inputs: objects to process
     remain: timeout. If 0, return [].
-- 
GitLab