keep track of what has moved to py3
[tests.git] / system / tcptest.py
1 #!/usr/bin/env python
2
3 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
4 # Copyright (C) 2010 INRIA 
5 #
6
7 # this is a small and simple standalone utility
8 # designed to run in slice-space
9 # we keep this in python2 for now until python3
10 # can be taken for granted in sliceimage
11
12 from __future__ import print_function
13
14 import sys
15 import time
16 import subprocess
17 import socket
18 import SocketServer
19 import threading
20 from optparse import OptionParser    
21
22 def myprint(message, id='client'):
23     now = time.strftime("%H:%M:%S", time.localtime())
24     print("* {now} ({id}) -- {message}".format(**locals()))
25     sys.stdout.flush()
26
27 def show_network_status(id):
28     myprint("ip address show", id=id)
29     subprocess.call(['ip', 'address', 'show'])
30     myprint("ip route show", id=id)
31     subprocess.call(['ip', 'route', 'show'])
32
33 class EchoRequestHandler(SocketServer.StreamRequestHandler):
34     def handle(self):
35         line = self.rfile.readline()
36         self.wfile.write(line)
37
38 class UppercaseRequestHandler(SocketServer.StreamRequestHandler):
39     def handle(self):
40         line = self.rfile.readline()
41         self.wfile.write(line.upper())
42
43 class Server:
44     """
45     A TCP server, running for some finite amount of time
46     """
47     def main(self):
48         parser = OptionParser()
49         parser.add_option("-p", "--port", action="store", dest="port", type="int",
50                           default=10000, help="port number")
51         parser.add_option("-a", "--address", action="store", dest="address", 
52                           default=socket.gethostname(), help="address")
53         parser.add_option("-t", "--timeout", action="store", dest="timeout", type="int",
54                           default="0")
55         (options, args) = parser.parse_args()
56
57         if len(args) != 0:
58             parser.print_help()
59             sys.exit(1)
60
61         myprint("==================== tcptest.py server", id='server')
62         show_network_status(id='server')
63         server = SocketServer.TCPServer((options.address, options.port),
64                                         UppercaseRequestHandler)
65         try:
66             if options.timeout:
67                 t = threading.Thread(target=server.serve_forever)
68                 t.setDaemon(True) # don't hang on exit
69                 t.start()
70                 time.sleep(options.timeout)
71                 sys.exit(0)
72             else:
73                 server.serve_forever()        
74         except KeyboardInterrupt as e:
75             print('Bailing out on keyboard interrupt')
76             sys.exit(1)
77             
78 class Ready:
79     """
80     A utility that does exit(0) iff network as perceived
81     from the sliver is ready. Designed to be run before Server,
82     so one can wait for the right conditions.
83     """
84     def main(self):
85         parser = OptionParser()
86         # by default use another port so we don't run into
87         # the SO_LINGER kind of trouble
88         parser.add_option("-p", "--port", action="store", dest="port", type="int",
89                           default=9999, help="port number")
90         parser.add_option("-a", "--address", action="store", dest="address", 
91                           default=socket.gethostname(), help="address")
92         (options, args) = parser.parse_args()
93
94         myprint("==================== tcptest.py ready", id='ready')
95         def can_bind ():
96             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
97             try:
98                 s.bind((options.address, options.port))
99                 return True
100             except Exception as e:
101                 print(e)
102                 return False
103
104         def eth0_has_ipv4():
105             command = "ip address show eth0 | grep -q ' inet '"
106             return subprocess.check_call(command, shell=True) == 0
107
108         sys.exit(0 if can_bind() and eth0_has_ipv4() else 1)
109         
110 class Client:
111     """
112     Runs a client against a Server instance
113     """
114     def main(self):
115         parser = OptionParser()
116         parser.add_option("-p","--port", action="store", dest="port", type="int",
117                           default=10000, help="port number")
118         parser.add_option("-a","--address", action="store", dest="address", 
119                           default=socket.gethostname(), help="address")
120         parser.add_option("-s","--sleep", action="store", dest="sleep", type="int",
121                           default=1, help="sleep seconds")
122         parser.add_option("-l","--loops", action="store", dest="loops", type="int",
123                           default=1, help="iteration loops")
124         
125         (options, args) = parser.parse_args()
126         if len(args) != 0:
127             parser.print_help()
128             sys.exit(1)
129
130         myprint("==================== tcptest.py client", id='client')
131         result=True
132         for i in range(1,options.loops+1):
133             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
134             s.connect((options.address, options.port))
135             mout=i*'ping ' + '\n'
136             min=mout.upper()
137             if s.send(mout) != len(mout):
138                 myprint("cannot send {}".format(mout.strip()))
139                 result=False
140                 break
141             line=s.recv(len(min))
142             if line is not line:
143                 myprint("unexpected reception\ngot:{}\nexpected: {}".format(line, min))
144                 result = False
145             else:
146                 myprint("OK:{}".format(mout.strip()))
147             # leave the connection open, but the last one (so 1 iter returns fast)
148             if i != options.loops:
149                 time.sleep(options.sleep)
150             myprint("disconnecting")
151             s.close()
152         myprint("Done")
153         exit_return=0
154         if not result:
155             exit_return=1
156         sys.exit(exit_return)
157
158 if __name__ == '__main__':
159     for arg in sys.argv[1:]:
160         if arg.find("client") >= 0:
161             sys.argv.remove(arg)
162             Client().main()
163         elif arg.find("server") >= 0:
164             sys.argv.remove(arg)
165             Server().main()
166         elif arg.find("ready") >= 0:
167             sys.argv.remove(arg)
168             Ready().main()
169     print('you must specify either --client or --server')
170     sys.exit(1)