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