]>
Commit | Line | Data |
---|---|---|
1573e7b8 RG |
1 | #!/usr/bin/env python |
2 | import threading | |
3 | import clientsubnetoption | |
4 | import dns | |
5 | import requests | |
6 | import socket | |
7 | import struct | |
8 | from dnsdisttests import DNSDistTest | |
9 | ||
10 | class TestBrokenTCPFastOpen(DNSDistTest): | |
11 | ||
12 | # this test suite uses a different responder port | |
13 | # because, contrary to the other ones, its | |
14 | # TCP responder will accept a connection, read the | |
15 | # query then just close the connection right away | |
16 | _testServerPort = 5410 | |
17 | _testServerRetries = 5 | |
18 | _webTimeout = 2.0 | |
19 | _webServerPort = 8083 | |
20 | _webServerBasicAuthPassword = 'secret' | |
21 | _webServerAPIKey = 'apisecret' | |
22 | _config_params = ['_testServerPort', '_testServerRetries', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey'] | |
23 | _config_template = """ | |
24 | newServer{address="127.0.0.1:%s", useClientSubnet=true, tcpFastOpen=true, retries=%d } | |
25 | webserver("127.0.0.1:%s", "%s", "%s") | |
26 | """ | |
27 | ||
28 | @classmethod | |
29 | def BrokenTCPResponder(cls, port): | |
30 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
31 | sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) | |
32 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |
33 | try: | |
34 | sock.bind(("127.0.0.1", port)) | |
35 | except socket.error as e: | |
36 | print("Error binding in the TCP responder: %s" % str(e)) | |
37 | sys.exit(1) | |
38 | ||
39 | sock.listen(100) | |
40 | while True: | |
41 | (conn, _) = sock.accept() | |
42 | conn.settimeout(5.0) | |
43 | data = conn.recv(2) | |
44 | if not data: | |
45 | conn.close() | |
46 | continue | |
47 | ||
48 | (datalen,) = struct.unpack("!H", data) | |
49 | data = conn.recv(datalen) | |
50 | conn.close() | |
51 | continue | |
52 | ||
53 | sock.close() | |
54 | ||
55 | @classmethod | |
56 | def startResponders(cls): | |
57 | print("Launching responders..") | |
58 | ||
59 | # Normal responder | |
60 | cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue]) | |
61 | cls._UDPResponder.setDaemon(True) | |
62 | cls._UDPResponder.start() | |
63 | ||
64 | # Close the connection right after reading the query | |
65 | cls._TCPResponder = threading.Thread(name='Broken TCP Responder', target=cls.BrokenTCPResponder, args=[cls._testServerPort]) | |
66 | cls._TCPResponder.setDaemon(True) | |
67 | cls._TCPResponder.start() | |
68 | ||
69 | def testTCOFastOpenOnCloseAfterRead(self): | |
70 | """ | |
71 | TCP Fast Open: Close after read | |
72 | """ | |
73 | name = 'close-after-read.tfo.tests.powerdns.com.' | |
74 | query = dns.message.make_query(name, 'A', 'IN') | |
75 | ||
76 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
77 | self.assertFalse(receivedQuery) | |
78 | self.assertFalse(receivedResponse) | |
79 | ||
80 | headers = {'x-api-key': self._webServerAPIKey} | |
81 | url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost' | |
82 | r = requests.get(url, headers=headers, timeout=self._webTimeout) | |
83 | self.assertTrue(r) | |
84 | self.assertEquals(r.status_code, 200) | |
85 | self.assertTrue(r.json()) | |
86 | content = r.json() | |
87 | self.assertTrue(len(content['servers']), 1) | |
88 | server = content['servers'][0] | |
89 | self.assertIn('tcpDiedReadingResponse', server) | |
90 | self.assertEquals(server['tcpDiedReadingResponse'], self._testServerRetries) |