xref: /aosp_15_r20/kernel/tests/net/test/tcp_repair_test.py (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
1*2f2c4c7aSAndroid Build Coastguard Worker#!/usr/bin/python3
2*2f2c4c7aSAndroid Build Coastguard Worker#
3*2f2c4c7aSAndroid Build Coastguard Worker# Copyright 2019 The Android Open Source Project
4*2f2c4c7aSAndroid Build Coastguard Worker#
5*2f2c4c7aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*2f2c4c7aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*2f2c4c7aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*2f2c4c7aSAndroid Build Coastguard Worker#
9*2f2c4c7aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0
10*2f2c4c7aSAndroid Build Coastguard Worker#
11*2f2c4c7aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*2f2c4c7aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*2f2c4c7aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*2f2c4c7aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*2f2c4c7aSAndroid Build Coastguard Worker# limitations under the License.
16*2f2c4c7aSAndroid Build Coastguard Worker
17*2f2c4c7aSAndroid Build Coastguard Workerimport unittest
18*2f2c4c7aSAndroid Build Coastguard Worker
19*2f2c4c7aSAndroid Build Coastguard Workerfrom errno import *  # pylint: disable=wildcard-import
20*2f2c4c7aSAndroid Build Coastguard Workerfrom socket import *  # pylint: disable=wildcard-import
21*2f2c4c7aSAndroid Build Coastguard Workerimport ctypes
22*2f2c4c7aSAndroid Build Coastguard Workerimport fcntl
23*2f2c4c7aSAndroid Build Coastguard Workerimport os
24*2f2c4c7aSAndroid Build Coastguard Workerimport random
25*2f2c4c7aSAndroid Build Coastguard Workerimport select
26*2f2c4c7aSAndroid Build Coastguard Workerimport termios
27*2f2c4c7aSAndroid Build Coastguard Workerimport threading
28*2f2c4c7aSAndroid Build Coastguard Workerimport time
29*2f2c4c7aSAndroid Build Coastguard Workerfrom scapy import all as scapy
30*2f2c4c7aSAndroid Build Coastguard Worker
31*2f2c4c7aSAndroid Build Coastguard Workerimport multinetwork_base
32*2f2c4c7aSAndroid Build Coastguard Workerimport net_test
33*2f2c4c7aSAndroid Build Coastguard Workerimport packets
34*2f2c4c7aSAndroid Build Coastguard Worker
35*2f2c4c7aSAndroid Build Coastguard WorkerSOL_TCP = net_test.SOL_TCP
36*2f2c4c7aSAndroid Build Coastguard WorkerSHUT_RD = net_test.SHUT_RD
37*2f2c4c7aSAndroid Build Coastguard WorkerSHUT_WR = net_test.SHUT_WR
38*2f2c4c7aSAndroid Build Coastguard WorkerSHUT_RDWR = net_test.SHUT_RDWR
39*2f2c4c7aSAndroid Build Coastguard WorkerSIOCINQ = termios.FIONREAD
40*2f2c4c7aSAndroid Build Coastguard WorkerSIOCOUTQ = termios.TIOCOUTQ
41*2f2c4c7aSAndroid Build Coastguard Worker
42*2f2c4c7aSAndroid Build Coastguard WorkerTEST_PORT = 5555
43*2f2c4c7aSAndroid Build Coastguard Worker
44*2f2c4c7aSAndroid Build Coastguard Worker# Following constants are SOL_TCP level options and arguments.
45*2f2c4c7aSAndroid Build Coastguard Worker# They are defined in linux-kernel: include/uapi/linux/tcp.h
46*2f2c4c7aSAndroid Build Coastguard Worker
47*2f2c4c7aSAndroid Build Coastguard Worker# SOL_TCP level options.
48*2f2c4c7aSAndroid Build Coastguard WorkerTCP_REPAIR = 19
49*2f2c4c7aSAndroid Build Coastguard WorkerTCP_REPAIR_QUEUE = 20
50*2f2c4c7aSAndroid Build Coastguard WorkerTCP_QUEUE_SEQ = 21
51*2f2c4c7aSAndroid Build Coastguard Worker
52*2f2c4c7aSAndroid Build Coastguard Worker# TCP_REPAIR_{OFF, ON} is an argument to TCP_REPAIR.
53*2f2c4c7aSAndroid Build Coastguard WorkerTCP_REPAIR_OFF = 0
54*2f2c4c7aSAndroid Build Coastguard WorkerTCP_REPAIR_ON = 1
55*2f2c4c7aSAndroid Build Coastguard Worker
56*2f2c4c7aSAndroid Build Coastguard Worker# TCP_{NO, RECV, SEND}_QUEUE is an argument to TCP_REPAIR_QUEUE.
57*2f2c4c7aSAndroid Build Coastguard WorkerTCP_NO_QUEUE = 0
58*2f2c4c7aSAndroid Build Coastguard WorkerTCP_RECV_QUEUE = 1
59*2f2c4c7aSAndroid Build Coastguard WorkerTCP_SEND_QUEUE = 2
60*2f2c4c7aSAndroid Build Coastguard Worker
61*2f2c4c7aSAndroid Build Coastguard Worker# This test is aiming to ensure tcp keep alive offload works correctly
62*2f2c4c7aSAndroid Build Coastguard Worker# when it fetches tcp information from kernel via tcp repair mode.
63*2f2c4c7aSAndroid Build Coastguard Workerclass TcpRepairTest(multinetwork_base.MultiNetworkBaseTest):
64*2f2c4c7aSAndroid Build Coastguard Worker
65*2f2c4c7aSAndroid Build Coastguard Worker  def assertSocketNotConnected(self, sock):
66*2f2c4c7aSAndroid Build Coastguard Worker    self.assertRaisesErrno(ENOTCONN, sock.getpeername)
67*2f2c4c7aSAndroid Build Coastguard Worker
68*2f2c4c7aSAndroid Build Coastguard Worker  def assertSocketConnected(self, sock):
69*2f2c4c7aSAndroid Build Coastguard Worker    sock.getpeername()  # No errors? Socket is alive and connected.
70*2f2c4c7aSAndroid Build Coastguard Worker
71*2f2c4c7aSAndroid Build Coastguard Worker  def createConnectedSocket(self, version, netid):
72*2f2c4c7aSAndroid Build Coastguard Worker    s = net_test.TCPSocket(net_test.GetAddressFamily(version))
73*2f2c4c7aSAndroid Build Coastguard Worker    net_test.DisableFinWait(s)
74*2f2c4c7aSAndroid Build Coastguard Worker    self.SelectInterface(s, netid, "mark")
75*2f2c4c7aSAndroid Build Coastguard Worker
76*2f2c4c7aSAndroid Build Coastguard Worker    remotesockaddr = self.GetRemoteSocketAddress(version)
77*2f2c4c7aSAndroid Build Coastguard Worker    remoteaddr = self.GetRemoteAddress(version)
78*2f2c4c7aSAndroid Build Coastguard Worker    self.assertRaisesErrno(EINPROGRESS, s.connect, (remotesockaddr, TEST_PORT))
79*2f2c4c7aSAndroid Build Coastguard Worker    self.assertSocketNotConnected(s)
80*2f2c4c7aSAndroid Build Coastguard Worker
81*2f2c4c7aSAndroid Build Coastguard Worker    myaddr = self.MyAddress(version, netid)
82*2f2c4c7aSAndroid Build Coastguard Worker    port = s.getsockname()[1]
83*2f2c4c7aSAndroid Build Coastguard Worker    self.assertNotEqual(0, port)
84*2f2c4c7aSAndroid Build Coastguard Worker
85*2f2c4c7aSAndroid Build Coastguard Worker    desc, expect_syn = packets.SYN(TEST_PORT, version, myaddr, remoteaddr, port, seq=None)
86*2f2c4c7aSAndroid Build Coastguard Worker    msg = "socket connect: expected %s" % desc
87*2f2c4c7aSAndroid Build Coastguard Worker    syn = self.ExpectPacketOn(netid, msg, expect_syn)
88*2f2c4c7aSAndroid Build Coastguard Worker    synack_desc, synack = packets.SYNACK(version, remoteaddr, myaddr, syn)
89*2f2c4c7aSAndroid Build Coastguard Worker    synack.getlayer("TCP").seq = random.getrandbits(32)
90*2f2c4c7aSAndroid Build Coastguard Worker    synack.getlayer("TCP").window = 14400
91*2f2c4c7aSAndroid Build Coastguard Worker    self.ReceivePacketOn(netid, synack)
92*2f2c4c7aSAndroid Build Coastguard Worker    desc, ack = packets.ACK(version, myaddr, remoteaddr, synack)
93*2f2c4c7aSAndroid Build Coastguard Worker    msg = "socket connect: got SYN+ACK, expected %s" % desc
94*2f2c4c7aSAndroid Build Coastguard Worker    ack = self.ExpectPacketOn(netid, msg, ack)
95*2f2c4c7aSAndroid Build Coastguard Worker    self.last_sent = ack
96*2f2c4c7aSAndroid Build Coastguard Worker    self.last_received = synack
97*2f2c4c7aSAndroid Build Coastguard Worker    return s
98*2f2c4c7aSAndroid Build Coastguard Worker
99*2f2c4c7aSAndroid Build Coastguard Worker  def receiveFin(self, netid, version, sock):
100*2f2c4c7aSAndroid Build Coastguard Worker    self.assertSocketConnected(sock)
101*2f2c4c7aSAndroid Build Coastguard Worker    remoteaddr = self.GetRemoteAddress(version)
102*2f2c4c7aSAndroid Build Coastguard Worker    myaddr = self.MyAddress(version, netid)
103*2f2c4c7aSAndroid Build Coastguard Worker    desc, fin = packets.FIN(version, remoteaddr, myaddr, self.last_sent)
104*2f2c4c7aSAndroid Build Coastguard Worker    self.ReceivePacketOn(netid, fin)
105*2f2c4c7aSAndroid Build Coastguard Worker    self.last_received = fin
106*2f2c4c7aSAndroid Build Coastguard Worker
107*2f2c4c7aSAndroid Build Coastguard Worker  def sendData(self, netid, version, sock, payload):
108*2f2c4c7aSAndroid Build Coastguard Worker    sock.send(payload)
109*2f2c4c7aSAndroid Build Coastguard Worker
110*2f2c4c7aSAndroid Build Coastguard Worker    remoteaddr = self.GetRemoteAddress(version)
111*2f2c4c7aSAndroid Build Coastguard Worker    myaddr = self.MyAddress(version, netid)
112*2f2c4c7aSAndroid Build Coastguard Worker    desc, send = packets.ACK(version, myaddr, remoteaddr,
113*2f2c4c7aSAndroid Build Coastguard Worker                             self.last_received, payload)
114*2f2c4c7aSAndroid Build Coastguard Worker    self.last_sent = send
115*2f2c4c7aSAndroid Build Coastguard Worker
116*2f2c4c7aSAndroid Build Coastguard Worker  def receiveData(self, netid, version, payload):
117*2f2c4c7aSAndroid Build Coastguard Worker    remoteaddr = self.GetRemoteAddress(version)
118*2f2c4c7aSAndroid Build Coastguard Worker    myaddr = self.MyAddress(version, netid)
119*2f2c4c7aSAndroid Build Coastguard Worker
120*2f2c4c7aSAndroid Build Coastguard Worker    desc, received = packets.ACK(version, remoteaddr, myaddr,
121*2f2c4c7aSAndroid Build Coastguard Worker                                 self.last_sent, payload)
122*2f2c4c7aSAndroid Build Coastguard Worker    ack_desc, ack = packets.ACK(version, myaddr, remoteaddr, received)
123*2f2c4c7aSAndroid Build Coastguard Worker    self.ReceivePacketOn(netid, received)
124*2f2c4c7aSAndroid Build Coastguard Worker    time.sleep(0.1)
125*2f2c4c7aSAndroid Build Coastguard Worker    self.ExpectPacketOn(netid, "expecting %s" % ack_desc, ack)
126*2f2c4c7aSAndroid Build Coastguard Worker    self.last_sent = ack
127*2f2c4c7aSAndroid Build Coastguard Worker    self.last_received = received
128*2f2c4c7aSAndroid Build Coastguard Worker
129*2f2c4c7aSAndroid Build Coastguard Worker  # Test the behavior of NO_QUEUE. Expect incoming data will be stored into
130*2f2c4c7aSAndroid Build Coastguard Worker  # the queue, but socket cannot be read/written in NO_QUEUE.
131*2f2c4c7aSAndroid Build Coastguard Worker  def testTcpRepairInNoQueue(self):
132*2f2c4c7aSAndroid Build Coastguard Worker    for version in [4, 5, 6]:
133*2f2c4c7aSAndroid Build Coastguard Worker      self.tcpRepairInNoQueueTest(version)
134*2f2c4c7aSAndroid Build Coastguard Worker
135*2f2c4c7aSAndroid Build Coastguard Worker  def tcpRepairInNoQueueTest(self, version):
136*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
137*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
138*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
139*2f2c4c7aSAndroid Build Coastguard Worker
140*2f2c4c7aSAndroid Build Coastguard Worker    # In repair mode with NO_QUEUE, writes fail...
141*2f2c4c7aSAndroid Build Coastguard Worker    self.assertRaisesErrno(EINVAL, sock.send, b"write test")
142*2f2c4c7aSAndroid Build Coastguard Worker
143*2f2c4c7aSAndroid Build Coastguard Worker    # remote data is coming.
144*2f2c4c7aSAndroid Build Coastguard Worker    TEST_RECEIVED = net_test.UDP_PAYLOAD
145*2f2c4c7aSAndroid Build Coastguard Worker    self.receiveData(netid, version, TEST_RECEIVED)
146*2f2c4c7aSAndroid Build Coastguard Worker
147*2f2c4c7aSAndroid Build Coastguard Worker    # In repair mode with NO_QUEUE, read fail...
148*2f2c4c7aSAndroid Build Coastguard Worker    self.assertRaisesErrno(EPERM, sock.recv, 4096)
149*2f2c4c7aSAndroid Build Coastguard Worker
150*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_OFF)
151*2f2c4c7aSAndroid Build Coastguard Worker    readData = sock.recv(4096)
152*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(readData, TEST_RECEIVED)
153*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
154*2f2c4c7aSAndroid Build Coastguard Worker
155*2f2c4c7aSAndroid Build Coastguard Worker  # Test whether tcp read/write sequence number can be fetched correctly
156*2f2c4c7aSAndroid Build Coastguard Worker  # by TCP_QUEUE_SEQ.
157*2f2c4c7aSAndroid Build Coastguard Worker  def testGetSequenceNumber(self):
158*2f2c4c7aSAndroid Build Coastguard Worker    for version in [4, 5, 6]:
159*2f2c4c7aSAndroid Build Coastguard Worker      self.GetSequenceNumberTest(version)
160*2f2c4c7aSAndroid Build Coastguard Worker
161*2f2c4c7aSAndroid Build Coastguard Worker  def GetSequenceNumberTest(self, version):
162*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
163*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
164*2f2c4c7aSAndroid Build Coastguard Worker    # test write queue sequence number
165*2f2c4c7aSAndroid Build Coastguard Worker    sequence_before = self.GetWriteSequenceNumber(version, sock)
166*2f2c4c7aSAndroid Build Coastguard Worker    expect_sequence = self.last_sent.getlayer("TCP").seq
167*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(sequence_before & 0xffffffff, expect_sequence)
168*2f2c4c7aSAndroid Build Coastguard Worker    TEST_SEND = net_test.UDP_PAYLOAD
169*2f2c4c7aSAndroid Build Coastguard Worker    self.sendData(netid, version, sock, TEST_SEND)
170*2f2c4c7aSAndroid Build Coastguard Worker    sequence_after = self.GetWriteSequenceNumber(version, sock)
171*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(sequence_before + len(TEST_SEND), sequence_after)
172*2f2c4c7aSAndroid Build Coastguard Worker
173*2f2c4c7aSAndroid Build Coastguard Worker    # test read queue sequence number
174*2f2c4c7aSAndroid Build Coastguard Worker    sequence_before = self.GetReadSequenceNumber(version, sock)
175*2f2c4c7aSAndroid Build Coastguard Worker    expect_sequence = self.last_received.getlayer("TCP").seq + 1
176*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(sequence_before & 0xffffffff, expect_sequence)
177*2f2c4c7aSAndroid Build Coastguard Worker    TEST_READ = net_test.UDP_PAYLOAD
178*2f2c4c7aSAndroid Build Coastguard Worker    self.receiveData(netid, version, TEST_READ)
179*2f2c4c7aSAndroid Build Coastguard Worker    sequence_after = self.GetReadSequenceNumber(version, sock)
180*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(sequence_before + len(TEST_READ), sequence_after)
181*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
182*2f2c4c7aSAndroid Build Coastguard Worker
183*2f2c4c7aSAndroid Build Coastguard Worker  def GetWriteSequenceNumber(self, version, sock):
184*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
185*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE)
186*2f2c4c7aSAndroid Build Coastguard Worker    sequence = sock.getsockopt(SOL_TCP, TCP_QUEUE_SEQ)
187*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE)
188*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_OFF)
189*2f2c4c7aSAndroid Build Coastguard Worker    return sequence
190*2f2c4c7aSAndroid Build Coastguard Worker
191*2f2c4c7aSAndroid Build Coastguard Worker  def GetReadSequenceNumber(self, version, sock):
192*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
193*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE)
194*2f2c4c7aSAndroid Build Coastguard Worker    sequence = sock.getsockopt(SOL_TCP, TCP_QUEUE_SEQ)
195*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE)
196*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_OFF)
197*2f2c4c7aSAndroid Build Coastguard Worker    return sequence
198*2f2c4c7aSAndroid Build Coastguard Worker
199*2f2c4c7aSAndroid Build Coastguard Worker  # Test whether tcp repair socket can be poll()'ed correctly
200*2f2c4c7aSAndroid Build Coastguard Worker  # in mutiple threads at the same time.
201*2f2c4c7aSAndroid Build Coastguard Worker  def testMultiThreadedPoll(self):
202*2f2c4c7aSAndroid Build Coastguard Worker    for version in [4, 5, 6]:
203*2f2c4c7aSAndroid Build Coastguard Worker      self.PollWhenShutdownTest(version)
204*2f2c4c7aSAndroid Build Coastguard Worker      self.PollWhenReceiveFinTest(version)
205*2f2c4c7aSAndroid Build Coastguard Worker
206*2f2c4c7aSAndroid Build Coastguard Worker  def PollRepairSocketInMultipleThreads(self, netid, version, expected):
207*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
208*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
209*2f2c4c7aSAndroid Build Coastguard Worker
210*2f2c4c7aSAndroid Build Coastguard Worker    multiThreads = []
211*2f2c4c7aSAndroid Build Coastguard Worker    for i in [0, 1]:
212*2f2c4c7aSAndroid Build Coastguard Worker      thread = SocketExceptionThread(sock, lambda sk: self.fdSelect(sock, expected))
213*2f2c4c7aSAndroid Build Coastguard Worker      thread.start()
214*2f2c4c7aSAndroid Build Coastguard Worker      self.assertTrue(thread.is_alive())
215*2f2c4c7aSAndroid Build Coastguard Worker      multiThreads.append(thread)
216*2f2c4c7aSAndroid Build Coastguard Worker
217*2f2c4c7aSAndroid Build Coastguard Worker    return sock, multiThreads
218*2f2c4c7aSAndroid Build Coastguard Worker
219*2f2c4c7aSAndroid Build Coastguard Worker  def assertThreadsStopped(self, multiThreads, msg) :
220*2f2c4c7aSAndroid Build Coastguard Worker    for thread in multiThreads:
221*2f2c4c7aSAndroid Build Coastguard Worker      if (thread.is_alive()):
222*2f2c4c7aSAndroid Build Coastguard Worker        thread.join(1)
223*2f2c4c7aSAndroid Build Coastguard Worker      if (thread.is_alive()):
224*2f2c4c7aSAndroid Build Coastguard Worker        thread.stop()
225*2f2c4c7aSAndroid Build Coastguard Worker        raise AssertionError(msg)
226*2f2c4c7aSAndroid Build Coastguard Worker
227*2f2c4c7aSAndroid Build Coastguard Worker  def PollWhenShutdownTest(self, version):
228*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
229*2f2c4c7aSAndroid Build Coastguard Worker    expected = select.POLLIN
230*2f2c4c7aSAndroid Build Coastguard Worker    sock, multiThreads = self.PollRepairSocketInMultipleThreads(netid, version, expected)
231*2f2c4c7aSAndroid Build Coastguard Worker    # Test shutdown RD.
232*2f2c4c7aSAndroid Build Coastguard Worker    sock.shutdown(SHUT_RD)
233*2f2c4c7aSAndroid Build Coastguard Worker    self.assertThreadsStopped(multiThreads, "poll fail during SHUT_RD")
234*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
235*2f2c4c7aSAndroid Build Coastguard Worker
236*2f2c4c7aSAndroid Build Coastguard Worker    expected = None
237*2f2c4c7aSAndroid Build Coastguard Worker    sock, multiThreads = self.PollRepairSocketInMultipleThreads(netid, version, expected)
238*2f2c4c7aSAndroid Build Coastguard Worker    # Test shutdown WR.
239*2f2c4c7aSAndroid Build Coastguard Worker    sock.shutdown(SHUT_WR)
240*2f2c4c7aSAndroid Build Coastguard Worker    self.assertThreadsStopped(multiThreads, "poll fail during SHUT_WR")
241*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
242*2f2c4c7aSAndroid Build Coastguard Worker
243*2f2c4c7aSAndroid Build Coastguard Worker    expected = select.POLLIN | select.POLLHUP
244*2f2c4c7aSAndroid Build Coastguard Worker    sock, multiThreads = self.PollRepairSocketInMultipleThreads(netid, version, expected)
245*2f2c4c7aSAndroid Build Coastguard Worker    # Test shutdown RDWR.
246*2f2c4c7aSAndroid Build Coastguard Worker    sock.shutdown(SHUT_RDWR)
247*2f2c4c7aSAndroid Build Coastguard Worker    self.assertThreadsStopped(multiThreads, "poll fail during SHUT_RDWR")
248*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
249*2f2c4c7aSAndroid Build Coastguard Worker
250*2f2c4c7aSAndroid Build Coastguard Worker  def PollWhenReceiveFinTest(self, version):
251*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
252*2f2c4c7aSAndroid Build Coastguard Worker    expected = select.POLLIN
253*2f2c4c7aSAndroid Build Coastguard Worker    sock, multiThreads = self.PollRepairSocketInMultipleThreads(netid, version, expected)
254*2f2c4c7aSAndroid Build Coastguard Worker    self.receiveFin(netid, version, sock)
255*2f2c4c7aSAndroid Build Coastguard Worker    self.assertThreadsStopped(multiThreads, "poll fail during FIN")
256*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
257*2f2c4c7aSAndroid Build Coastguard Worker
258*2f2c4c7aSAndroid Build Coastguard Worker  # Test whether socket idle can be detected by SIOCINQ and SIOCOUTQ.
259*2f2c4c7aSAndroid Build Coastguard Worker  def testSocketIdle(self):
260*2f2c4c7aSAndroid Build Coastguard Worker    for version in [4, 5, 6]:
261*2f2c4c7aSAndroid Build Coastguard Worker      self.readQueueIdleTest(version)
262*2f2c4c7aSAndroid Build Coastguard Worker      self.writeQueueIdleTest(version)
263*2f2c4c7aSAndroid Build Coastguard Worker
264*2f2c4c7aSAndroid Build Coastguard Worker  def readQueueIdleTest(self, version):
265*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
266*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
267*2f2c4c7aSAndroid Build Coastguard Worker
268*2f2c4c7aSAndroid Build Coastguard Worker    buf = ctypes.c_int()
269*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCINQ, buf)
270*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, 0)
271*2f2c4c7aSAndroid Build Coastguard Worker
272*2f2c4c7aSAndroid Build Coastguard Worker    TEST_RECV_PAYLOAD = net_test.UDP_PAYLOAD
273*2f2c4c7aSAndroid Build Coastguard Worker    self.receiveData(netid, version, TEST_RECV_PAYLOAD)
274*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCINQ, buf)
275*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, len(TEST_RECV_PAYLOAD))
276*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
277*2f2c4c7aSAndroid Build Coastguard Worker
278*2f2c4c7aSAndroid Build Coastguard Worker  def writeQueueIdleTest(self, version):
279*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
280*2f2c4c7aSAndroid Build Coastguard Worker    # Setup a connected socket, write queue is empty.
281*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
282*2f2c4c7aSAndroid Build Coastguard Worker    buf = ctypes.c_int()
283*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCOUTQ, buf)
284*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, 0)
285*2f2c4c7aSAndroid Build Coastguard Worker    # Change to repair mode with SEND_QUEUE, writing some data to the queue.
286*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR, TCP_REPAIR_ON)
287*2f2c4c7aSAndroid Build Coastguard Worker    TEST_SEND_PAYLOAD = net_test.UDP_PAYLOAD
288*2f2c4c7aSAndroid Build Coastguard Worker    sock.setsockopt(SOL_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE)
289*2f2c4c7aSAndroid Build Coastguard Worker    self.sendData(netid, version, sock, TEST_SEND_PAYLOAD)
290*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCOUTQ, buf)
291*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, len(TEST_SEND_PAYLOAD))
292*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
293*2f2c4c7aSAndroid Build Coastguard Worker
294*2f2c4c7aSAndroid Build Coastguard Worker    # Setup a connected socket again.
295*2f2c4c7aSAndroid Build Coastguard Worker    netid = self.RandomNetid()
296*2f2c4c7aSAndroid Build Coastguard Worker    sock = self.createConnectedSocket(version, netid)
297*2f2c4c7aSAndroid Build Coastguard Worker    # Send out some data and don't receive ACK yet.
298*2f2c4c7aSAndroid Build Coastguard Worker    self.sendData(netid, version, sock, TEST_SEND_PAYLOAD)
299*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCOUTQ, buf)
300*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, len(TEST_SEND_PAYLOAD))
301*2f2c4c7aSAndroid Build Coastguard Worker    # Receive response ACK.
302*2f2c4c7aSAndroid Build Coastguard Worker    remoteaddr = self.GetRemoteAddress(version)
303*2f2c4c7aSAndroid Build Coastguard Worker    myaddr = self.MyAddress(version, netid)
304*2f2c4c7aSAndroid Build Coastguard Worker    desc_ack, ack = packets.ACK(version, remoteaddr, myaddr, self.last_sent)
305*2f2c4c7aSAndroid Build Coastguard Worker    self.ReceivePacketOn(netid, ack)
306*2f2c4c7aSAndroid Build Coastguard Worker    fcntl.ioctl(sock, SIOCOUTQ, buf)
307*2f2c4c7aSAndroid Build Coastguard Worker    self.assertEqual(buf.value, 0)
308*2f2c4c7aSAndroid Build Coastguard Worker    sock.close()
309*2f2c4c7aSAndroid Build Coastguard Worker
310*2f2c4c7aSAndroid Build Coastguard Worker
311*2f2c4c7aSAndroid Build Coastguard Worker  def fdSelect(self, sock, expected):
312*2f2c4c7aSAndroid Build Coastguard Worker    READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR | select.POLLNVAL
313*2f2c4c7aSAndroid Build Coastguard Worker    p = select.poll()
314*2f2c4c7aSAndroid Build Coastguard Worker    p.register(sock, READ_ONLY)
315*2f2c4c7aSAndroid Build Coastguard Worker    events = p.poll(500)
316*2f2c4c7aSAndroid Build Coastguard Worker    for fd,event in events:
317*2f2c4c7aSAndroid Build Coastguard Worker      if fd == sock.fileno():
318*2f2c4c7aSAndroid Build Coastguard Worker        self.assertEqual(event, expected)
319*2f2c4c7aSAndroid Build Coastguard Worker      else:
320*2f2c4c7aSAndroid Build Coastguard Worker        raise AssertionError("unexpected poll fd")
321*2f2c4c7aSAndroid Build Coastguard Worker
322*2f2c4c7aSAndroid Build Coastguard Workerclass SocketExceptionThread(threading.Thread):
323*2f2c4c7aSAndroid Build Coastguard Worker
324*2f2c4c7aSAndroid Build Coastguard Worker  def __init__(self, sock, operation):
325*2f2c4c7aSAndroid Build Coastguard Worker    self.exception = None
326*2f2c4c7aSAndroid Build Coastguard Worker    super(SocketExceptionThread, self).__init__()
327*2f2c4c7aSAndroid Build Coastguard Worker    self.daemon = True
328*2f2c4c7aSAndroid Build Coastguard Worker    self.sock = sock
329*2f2c4c7aSAndroid Build Coastguard Worker    self.operation = operation
330*2f2c4c7aSAndroid Build Coastguard Worker
331*2f2c4c7aSAndroid Build Coastguard Worker  def stop(self):
332*2f2c4c7aSAndroid Build Coastguard Worker    self._Thread__stop()
333*2f2c4c7aSAndroid Build Coastguard Worker
334*2f2c4c7aSAndroid Build Coastguard Worker  def run(self):
335*2f2c4c7aSAndroid Build Coastguard Worker    try:
336*2f2c4c7aSAndroid Build Coastguard Worker      self.operation(self.sock)
337*2f2c4c7aSAndroid Build Coastguard Worker    except (IOError, AssertionError) as e:
338*2f2c4c7aSAndroid Build Coastguard Worker      self.exception = e
339*2f2c4c7aSAndroid Build Coastguard Worker
340*2f2c4c7aSAndroid Build Coastguard Workerif __name__ == '__main__':
341*2f2c4c7aSAndroid Build Coastguard Worker  unittest.main()
342