2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2014 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
27 from optparse import OptionParser, SUPPRESS_HELP
29 from .ns3wrapper import NS3Wrapper
31 class NS3WrapperMessage:
42 def handle_message(ns3_wrapper, msg_type, args, kwargs):
43 if msg_type == NS3WrapperMessage.SHUTDOWN:
44 ns3_wrapper.shutdown()
48 if msg_type == NS3WrapperMessage.STOP:
49 time = kwargs.get("time")
51 ns3_wrapper.stop(time=time)
55 if msg_type == NS3WrapperMessage.START:
60 if msg_type == NS3WrapperMessage.CREATE:
61 clazzname = args.pop(0)
63 return ns3_wrapper.create(clazzname, *args)
65 if msg_type == NS3WrapperMessage.FACTORY:
66 type_name = args.pop(0)
68 return ns3_wrapper.factory(type_name, **kwargs)
70 if msg_type == NS3WrapperMessage.INVOKE:
72 operation = args.pop(0)
74 return ns3_wrapper.invoke(uuid, operation, *args, **kwargs)
76 if msg_type == NS3WrapperMessage.GET:
80 return ns3_wrapper.get(uuid, name)
82 if msg_type == NS3WrapperMessage.SET:
87 return ns3_wrapper.set(uuid, name, value)
89 if msg_type == NS3WrapperMessage.FLUSH:
90 # Forces flushing output and error streams.
91 # NS-3 output will stay unflushed until the program exits or
92 # explicit invocation flush is done
96 ns3_wrapper.logger.debug("FLUSHED")
100 def open_socket(socket_name):
101 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
102 sock.bind(socket_name)
105 def close_socket(sock):
115 while '\n' not in chunk:
117 chunk = conn.recv(1024)
118 except (OSError, socket.error) as e:
119 if e[0] != errno.EINTR:
121 # Ignore eintr errors
130 msg = ''.join(msg).strip()
132 # The message is formatted as follows:
133 # MESSAGE_TYPE|args|kwargs
135 # where MESSAGE_TYPE, args and kwargs are pickld and enoded in base64
138 item = base64.b64decode(item).rstrip()
139 return pickle.loads(item)
141 decoded = list(map(decode, msg.split("|")))
144 dmsg_type = decoded.pop(0)
145 dargs = list(decoded.pop(0)) # transforming touple into list
146 dkwargs = decoded.pop(0)
148 return (dmsg_type, dargs, dkwargs)
150 def send_reply(conn, reply):
151 encoded = base64.b64encode(pickle.dumps(reply))
152 conn.send("%s\n" % encoded)
155 usage = ("usage: %prog -S <socket-name> -L <ns-log> -D <enable-dump> -v ")
157 parser = OptionParser(usage = usage)
159 parser.add_option("-S", "--socket-name", dest="socket_name",
160 help = "Name for the unix socket used to interact with this process",
161 default = "tap.sock", type="str")
163 parser.add_option("-L", "--ns-log", dest="ns_log",
164 help = "NS_LOG environmental variable to be set",
165 default = "", type="str")
167 parser.add_option("-D", "--enable-dump", dest="enable_dump",
168 help = "Enable dumping the remote executed ns-3 commands to a script "
169 "in order to later reproduce and debug the experiment",
170 action = "store_true",
173 parser.add_option("-v", "--verbose",
174 help="Print debug output",
176 dest="verbose", default=False)
178 (options, args) = parser.parse_args()
180 return (options.socket_name, options.verbose, options.ns_log,
183 def run_server(socket_name, level = logging.INFO, ns_log = None,
184 enable_dump = False):
186 # Sets NS_LOG environmental variable for NS debugging
188 os.environ["NS_LOG"] = ns_log
190 ###### ns-3 wrapper instantiation
192 ns3_wrapper = NS3Wrapper(loglevel=level, enable_dump = enable_dump)
194 ns3_wrapper.logger.info("STARTING...")
196 # create unix socket to receive instructions
197 sock = open_socket(socket_name)
200 # wait for messages to arrive and process them
204 conn, addr = sock.accept()
208 (msg_type, args, kwargs) = recv_msg(conn)
209 except socket.timeout as e:
215 # Ignore - connection lost
219 if msg_type == NS3WrapperMessage.SHUTDOWN:
223 reply = handle_message(ns3_wrapper, msg_type, args, kwargs)
226 err = traceback.format_exc()
227 ns3_wrapper.logger.error(err)
232 send_reply(conn, reply)
235 err = traceback.format_exc()
236 ns3_wrapper.logger.error(err)
244 ns3_wrapper.logger.info("EXITING...")
246 if __name__ == '__main__':
248 (socket_name, verbose, ns_log, enable_dump) = get_options()
251 FORMAT = "%(asctime)s %(name)s %(levelname)-4s %(message)s"
252 level = logging.DEBUG if verbose else logging.INFO
254 logging.basicConfig(format = FORMAT, level = level)
257 run_server(socket_name, level, ns_log, enable_dump)