import files that are relative to the source as nepi.full.path
[nepi.git] / src / nepi / resources / ns3 / ns3wrapper.py
index eea32d0..a9a5e12 100644 (file)
@@ -3,9 +3,8 @@
 #    Copyright (C) 2013 INRIA
 #
 #    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
+#    it under the terms of the GNU General Public License version 2 as
+#    published by the Free Software Foundation;
 #
 #    This program is distributed in the hope that it will be useful,
 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -131,7 +130,7 @@ class NS3Wrapper(object):
         self._allowed_types = None
 
         # Object to dump instructions to reproduce and debug experiment
-        from ns3wrapper_debug import NS3WrapperDebuger
+        from nepi.resources.ns3.ns3wrapper_debug import NS3WrapperDebuger
         self._debuger = NS3WrapperDebuger(enabled = enable_dump)
 
     @property
@@ -155,7 +154,7 @@ class NS3Wrapper(object):
             tid_count = type_id.GetRegisteredN()
             base = type_id.LookupByName("ns3::Object")
 
-            for i in xrange(tid_count):
+            for i in range(tid_count):
                 tid = type_id.GetRegistered(i)
                 
                 if tid.MustHideFromDocumentation() or \
@@ -174,7 +173,16 @@ class NS3Wrapper(object):
 
     @property
     def is_running(self):
-        return self._started and not self.ns3.Simulator.IsFinished()
+        return self.is_started and not self.ns3.Simulator.IsFinished()
+
+    @property
+    def is_started(self):
+        if not self._started:
+            now = self.ns3.Simulator.Now()
+            if not now.IsZero():
+                self._started = True
+
+        return self._started
 
     @property
     def is_finished(self):
@@ -199,13 +207,13 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("FACTORY %s( %s )" % (type_name, str(kwargs)))
         
+        ### DUMP
         self.debuger.dump_factory(uuid, type_name, kwargs)
-        ########
 
         factory = self.ns3.ObjectFactory()
         factory.SetTypeId(type_name)
 
-        for name, value in kwargs.iteritems():
+        for name, value in kwargs.items():
             ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value)
             factory.Set(name, ns3_value)
 
@@ -216,7 +224,6 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("RET FACTORY ( uuid %s ) %s = %s( %s )" % (
             str(uuid), str(obj), type_name, str(kwargs)))
-        ########
  
         return uuid
 
@@ -233,8 +240,8 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("CREATE %s( %s )" % (clazzname, str(args)))
     
+        ### DUMP
         self.debuger.dump_create(uuid, clazzname, args)
-        ########
 
         clazz = getattr(self.ns3, clazzname)
  
@@ -249,7 +256,6 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), 
             str(obj), clazzname, str(args)))
-        ########
 
         return uuid
 
@@ -264,45 +270,66 @@ class NS3Wrapper(object):
 
         if operation == "isRunning":
             result = self.is_running
+
+        elif operation == "isStarted":
+            result = self.is_started
+
         elif operation == "isFinished":
             result = self.is_finished
+
         elif operation == "isAppRunning":
             result = self._is_app_running(uuid)
+
+        elif operation == "isAppStarted":
+            result = self._is_app_started(uuid)
+
+        elif operation == "recvFD":
+            ### passFD operation binds to a different random socket 
+            ### en every execution, so the socket name that could be
+            ### dumped to the debug script using dump_invoke is
+            ### not be valid accross debug executions.
+            result = self._recv_fd(uuid, *args, **kwargs)
+
+        elif operation == "addStaticRoute":
+            result = self._add_static_route(uuid, *args)
+            
+            ### DUMP - result is static, so will be dumped as plain text
+            self.debuger.dump_invoke(result, uuid, operation, args, kwargs)
+
+        elif operation == "retrieveObject":
+            result = self._retrieve_object(uuid, *args, **kwargs)
+       
+            ### DUMP - result is static, so will be dumped as plain text
+            self.debuger.dump_invoke(result, uuid, operation, args, kwargs)
+       
         else:
             newuuid = self.make_uuid()
 
-            ### DEBUG
+            ### DUMP - result is a uuid that encoded an dynamically generated 
+            ### object
             self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs)
-            ########
-
-            if operation == "addStaticRoute":
-                result = self._add_static_route(uuid, *args)
-
-            elif operation == "retrieveObject":
-                result = self._retrieve_object(uuid, *args, **kwargs)
 
+            if uuid.startswith(SINGLETON):
+                obj = self._singleton(uuid)
             else:
-                if uuid.startswith(SINGLETON):
-                    obj = self._singleton(uuid)
-                else:
-                    obj = self.get_object(uuid)
-                
-                method = getattr(obj, operation)
+                obj = self.get_object(uuid)
+            
+            method = getattr(obj, operation)
 
-                # arguments starting with 'uuid' identify ns-3 C++
-                # objects and must be replaced by the actual object
-                realargs = self.replace_args(args)
-                realkwargs = self.replace_kwargs(kwargs)
+            # arguments starting with 'uuid' identify ns-3 C++
+            # objects and must be replaced by the actual object
+            realargs = self.replace_args(args)
+            realkwargs = self.replace_kwargs(kwargs)
 
-                result = method(*realargs, **realkwargs)
+            result = method(*realargs, **realkwargs)
 
-                # If the result is an object (not a base value),
-                # then keep track of the object a return the object
-                # reference (newuuid)
-                if not (result is None or type(result) in [
-                        bool, float, long, str, int]):
-                    self._objects[newuuid] = result
-                    result = newuuid
+            # If the result is an object (not a base value),
+            # then keep track of the object a return the object
+            # reference (newuuid)
+            if not (result is None or type(result) in [
+                    bool, float, long, str, int]):
+                self._objects[newuuid] = result
+                result = newuuid
 
         ### DEBUG
         self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % (
@@ -319,8 +346,8 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
     
+        ### DUMP
         self.debuger.dump_set(uuid, name, value)
-        ########
 
         obj = self.get_object(uuid)
         type_name = obj.GetInstanceTypeId().GetName()
@@ -347,7 +374,6 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, 
             str(value)))
-        ########
 
         return value
 
@@ -358,8 +384,8 @@ class NS3Wrapper(object):
         ### DEBUG
         self.logger.debug("GET %s %s" % (uuid, name))
         
+        ### DUMP
         self.debuger.dump_get(uuid, name)
-        ########
 
         obj = self.get_object(uuid)
         type_name = obj.GetInstanceTypeId().GetName()
@@ -379,14 +405,12 @@ class NS3Wrapper(object):
 
         ### DEBUG
         self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name))
-        ########
 
         return result
 
     def start(self):
-        ### DEBUG
+        ### DUMP
         self.debuger.dump_start()
-        ########
 
         # Launch the simulator thread and Start the
         # simulator in that thread
@@ -396,16 +420,13 @@ class NS3Wrapper(object):
                 args = [self._condition])
         self._simulator_thread.setDaemon(True)
         self._simulator_thread.start()
-        self._started = True
-
+        
         ### DEBUG
         self.logger.debug("START")
-        ########
 
     def stop(self, time = None):
-        ### DEBUG
+        ### DUMP
         self.debuger.dump_stop(time=time)
-        ########
         
         if time is None:
             self.ns3.Simulator.Stop()
@@ -414,12 +435,10 @@ class NS3Wrapper(object):
 
         ### DEBUG
         self.logger.debug("STOP time=%s" % str(time))
-        ########
 
     def shutdown(self):
-        ### DEBUG
+        ### DUMP
         self.debuger.dump_shutdown()
-        ########
 
         while not self.ns3.Simulator.IsFinished():
             #self.logger.debug("Waiting for simulation to finish")
@@ -438,7 +457,6 @@ class NS3Wrapper(object):
 
         ### DEBUG
         self.logger.debug("SHUTDOWN")
-        ########
 
     def _simulator_run(self, condition):
         # Run simulation
@@ -557,19 +575,22 @@ class NS3Wrapper(object):
     def replace_kwargs(self, kwargs):
         realkwargs = dict([(k, self.get_object(v) \
                 if str(v).startswith("uuid") else v) \
-                for k,v in kwargs.iteritems()])
+                for k,v in kwargs.items()])
  
         realkwargs = dict([(k, self._singleton(v) \
                 if str(v).startswith(SINGLETON) else v )\
-                for k, v in realkwargs.iteritems()])
+                for k, v in realkwargs.items()])
 
         return realkwargs
 
-    def _is_app_running(self, uuid): 
+    def _is_app_running(self, uuid):
         now = self.ns3.Simulator.Now()
         if now.IsZero():
             return False
 
+        if self.ns3.Simulator.IsFinished():
+            return False
+
         app = self.get_object(uuid)
         stop_time_value = self.ns3.TimeValue()
         app.GetAttribute("StopTime", stop_time_value)
@@ -579,10 +600,14 @@ class NS3Wrapper(object):
         app.GetAttribute("StartTime", start_time_value)
         start_time = start_time_value.Get()
         
-        if now.Compare(start_time) >= 0 and now.Compare(stop_time) < 0:
-            return True
+        if now.Compare(start_time) >= 0:
+            if stop_time.IsZero() or now.Compare(stop_time) < 0:
+                return True
 
         return False
+    
+    def _is_app_started(self, uuid):
+        return self._is_app_running(uuid) or self.is_finished
 
     def _add_static_route(self, ipv4_uuid, network, prefix, nexthop):
         ipv4 = self.get_object(ipv4_uuid)
@@ -620,10 +645,10 @@ class NS3Wrapper(object):
         # For all the interfaces registered with the ipv4 object, find
         # the one that matches the network of the nexthop
         nifaces = ipv4.GetNInterfaces()
-        for ifidx in xrange(nifaces):
+        for ifidx in range(nifaces):
             iface = ipv4.GetInterface(ifidx)
             naddress = iface.GetNAddresses()
-            for addridx in xrange(naddress):
+            for addridx in range(naddress):
                 ifaddr = iface.GetAddress(addridx)
                 ifmask = ifaddr.GetMask()
                 
@@ -643,7 +668,7 @@ class NS3Wrapper(object):
         newuuid = None
         if search:
             # search object
-            for ouuid, oobj in self._objects.iteritems():
+            for ouuid, oobj in self._objects.items():
                 if nobj == oobj:
                     newuuid = ouuid
                     break
@@ -653,5 +678,28 @@ class NS3Wrapper(object):
 
         return newuuid
 
+    def _recv_fd(self, uuid):
+        """ Waits on a local address to receive a file descriptor
+        from a local process. The file descriptor is associated
+        to a FdNetDevice to stablish communication between the
+        simulation and what ever process writes on that file descriptor
+        """
+
+        def recvfd(sock, fdnd):
+            (fd, msg) = passfd.recvfd(sock)
+            # Store a reference to the endpoint to keep the socket alive
+            fdnd.SetFileDescriptor(fd)
+        
+        import passfd
+        import socket
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+        sock.bind("")
+        address = sock.getsockname()
+        
+        fdnd = self.get_object(uuid)
+        t = threading.Thread(target=recvfd, args=(sock,fdnd))
+        t.start()
+
+        return address