NS3Wrapper server and client
[nepi.git] / src / nepi / resources / ns3 / ns3server.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2014 INRIA
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published by
7 #    the Free Software Foundation, either version 3 of the License, or
8 #    (at your option) any later version.
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 import base64
21 import cPickle
22 import errno
23 import socket
24 from optparse import OptionParser, SUPPRESS_HELP
25
26 from ns3wrapper import NS3Wrapper
27
28 class NS3WrapperMessage:
29     CREATE = "CREATE"
30     INVOKE = "INVOKE"
31     SET = "SET"
32     GET = "GET"
33     TRACE = "TRACE"
34     START = "START"
35     STOP = "STOP"
36     SHUTDOWN = "SHUTDOWN"
37
38 def handle_message(ns3_wrapper, msg, args):
39     if msg == NS3WrapperMessage.SHUTDOWN:
40         ns3_wrapper.shutdown()
41         return "BYEBYE"
42     
43     if msg == NS3WrapperMessage.STOP:
44         time = None
45         if args:
46             time = args[0]
47
48         ns3_wrapper.stop(time=time)
49         return "STOPPED"
50
51     if msg == NS3WrapperMessage.START:
52         ns3_wrapper.start()
53         return "STARTED"
54
55     if msg == NS3WrapperMessage.CREATE:
56         clazzname = args.pop(0)
57         
58         uuid = ns3_wrapper.create(clazzname, *args)
59         return uuid
60
61     if msg == NS3WrapperMessage.INVOKE:
62         uuid = args.pop(0)
63         operation = args.pop(0)
64         
65         uuid = ns3_wrapper.invoke(uuid, operation, *args)
66         return uuid
67
68     if msg == NS3WrapperMessage.GET:
69         uuid = args.pop(0)
70         name = args.pop(0)
71
72         value = ns3_wrapper.get(uuid, name)
73         return value
74
75     if msg == NS3WrapperMessage.SET:
76         uuid = args.pop(0)
77         name = args.pop(0)
78         value = args.pop(0)
79
80         value = ns3_wrapper.set(uuid, name, value)
81         return value
82  
83     if msg == NS3WrapperMessage.TRACE:
84         return "NOT IMPLEMENTED"
85
86 def create_socket(socket_name):
87     sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
88     sock.bind(socket_name)
89     return sock
90
91 def recv_msg(conn):
92     msg = []
93     chunk = ''
94
95     while '\n' not in chunk:
96         try:
97             chunk = conn.recv(1024)
98         except (OSError, socket.error), e:
99             if e[0] != errno.EINTR:
100                 raise
101             # Ignore eintr errors
102             continue
103
104         if chunk:
105             msg.append(chunk)
106         else:
107             # empty chunk = EOF
108             break
109  
110     msg = ''.join(msg).split('\n')[0]
111
112     # The message might have arguments that will be appended
113     # as a '|' separated list after the message identifier
114     def decode(arg):
115         arg = base64.b64decode(arg).rstrip()
116         return cPickle.loads(arg)
117
118     dargs = map(decode, msg.split("|"))
119
120     # decoded message
121     dmsg = dargs.pop(0)
122
123     return (dmsg, dargs)
124
125 def send_reply(conn, reply):
126     encoded = base64.b64encode(cPickle.dumps(reply))
127     conn.send("%s\n" % encoded)
128
129 def get_options():
130     usage = ("usage: %prog -S <socket-name>")
131     
132     parser = OptionParser(usage = usage)
133
134     parser.add_option("-S", "--socket-name", dest="socket_name",
135         help = "Name for the unix socket used to interact with this process", 
136         default = "tap.sock", type="str")
137
138     (options, args) = parser.parse_args()
139     
140     return options.socket_name
141
142 def run_server(socket_name): 
143     ns3_wrapper = NS3Wrapper()
144
145     # create unix socket to receive instructions
146     sock = create_socket(socket_name)
147     sock.listen(0)
148
149     # wait for messages to arrive and process them
150     stop = False
151
152     while not stop:
153         conn, addr = sock.accept()
154         conn.settimeout(5)
155
156         try:
157             (msg, args) = recv_msg(conn)
158         except socket.timeout, e:
159             # Ingore time-out
160             continue
161
162         if not msg:
163             # Ignore - connection lost
164             break
165  
166         ns3_wrapper.logger.debug("Message received %s args %s" % ( msg, str(args)))
167
168         if msg == NS3WrapperMessage.SHUTDOWN:
169            stop = True
170    
171         reply = handle_message(ns3_wrapper, msg, args)
172
173         try:
174             send_reply(conn, reply)
175         except socket.error:
176             break
177
178 if __name__ == '__main__':
179             
180     socket_name = get_options()
181
182     run_server(socket_name)
183