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