@@ -555,19 +555,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
555
555
def __init__ (self , methodName = 'runTest' ):
556
556
unittest .TestCase .__init__ (self , methodName = methodName )
557
557
ThreadableTest .__init__ (self )
558
+ self .cli = None
559
+ self .serv = None
560
+
561
+ def socketpair (self ):
562
+ # To be overridden by some child classes.
563
+ return socket .socketpair ()
558
564
559
565
def setUp (self ):
560
- self .serv , self .cli = socket .socketpair ()
566
+ self .serv , self .cli = self .socketpair ()
561
567
562
568
def tearDown (self ):
563
- self .serv .close ()
569
+ if self .serv :
570
+ self .serv .close ()
564
571
self .serv = None
565
572
566
573
def clientSetUp (self ):
567
574
pass
568
575
569
576
def clientTearDown (self ):
570
- self .cli .close ()
577
+ if self .cli :
578
+ self .cli .close ()
571
579
self .cli = None
572
580
ThreadableTest .clientTearDown (self )
573
581
@@ -4613,6 +4621,120 @@ def _testSend(self):
4613
4621
self .assertEqual (msg , MSG )
4614
4622
4615
4623
4624
+ class PurePythonSocketPairTest (SocketPairTest ):
4625
+
4626
+ # Explicitly use socketpair AF_INET or AF_INET6 to ensure that is the
4627
+ # code path we're using regardless platform is the pure python one where
4628
+ # `_socket.socketpair` does not exist. (AF_INET does not work with
4629
+ # _socket.socketpair on many platforms).
4630
+ def socketpair (self ):
4631
+ # called by super().setUp().
4632
+ try :
4633
+ return socket .socketpair (socket .AF_INET6 )
4634
+ except OSError :
4635
+ return socket .socketpair (socket .AF_INET )
4636
+
4637
+ # Local imports in this class make for easy security fix backporting.
4638
+
4639
+ def setUp (self ):
4640
+ import _socket
4641
+ self ._orig_sp = getattr (_socket , 'socketpair' , None )
4642
+ if self ._orig_sp is not None :
4643
+ # This forces the version using the non-OS provided socketpair
4644
+ # emulation via an AF_INET socket in Lib/socket.py.
4645
+ del _socket .socketpair
4646
+ import importlib
4647
+ global socket
4648
+ socket = importlib .reload (socket )
4649
+ else :
4650
+ pass # This platform already uses the non-OS provided version.
4651
+ super ().setUp ()
4652
+
4653
+ def tearDown (self ):
4654
+ super ().tearDown ()
4655
+ import _socket
4656
+ if self ._orig_sp is not None :
4657
+ # Restore the default socket.socketpair definition.
4658
+ _socket .socketpair = self ._orig_sp
4659
+ import importlib
4660
+ global socket
4661
+ socket = importlib .reload (socket )
4662
+
4663
+ def test_recv (self ):
4664
+ msg = self .serv .recv (1024 )
4665
+ self .assertEqual (msg , MSG )
4666
+
4667
+ def _test_recv (self ):
4668
+ self .cli .send (MSG )
4669
+
4670
+ def test_send (self ):
4671
+ self .serv .send (MSG )
4672
+
4673
+ def _test_send (self ):
4674
+ msg = self .cli .recv (1024 )
4675
+ self .assertEqual (msg , MSG )
4676
+
4677
+ def test_ipv4 (self ):
4678
+ cli , srv = socket .socketpair (socket .AF_INET )
4679
+ cli .close ()
4680
+ srv .close ()
4681
+
4682
+ def _test_ipv4 (self ):
4683
+ pass
4684
+
4685
+ @unittest .skipIf (not hasattr (_socket , 'IPPROTO_IPV6' ) or
4686
+ not hasattr (_socket , 'IPV6_V6ONLY' ),
4687
+ "IPV6_V6ONLY option not supported" )
4688
+ @unittest .skipUnless (socket_helper .IPV6_ENABLED , 'IPv6 required for this test' )
4689
+ def test_ipv6 (self ):
4690
+ cli , srv = socket .socketpair (socket .AF_INET6 )
4691
+ cli .close ()
4692
+ srv .close ()
4693
+
4694
+ def _test_ipv6 (self ):
4695
+ pass
4696
+
4697
+ def test_injected_authentication_failure (self ):
4698
+ orig_getsockname = socket .socket .getsockname
4699
+ inject_sock = None
4700
+
4701
+ def inject_getsocketname (self ):
4702
+ nonlocal inject_sock
4703
+ sockname = orig_getsockname (self )
4704
+ # Connect to the listening socket ahead of the
4705
+ # client socket.
4706
+ if inject_sock is None :
4707
+ inject_sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
4708
+ inject_sock .setblocking (False )
4709
+ try :
4710
+ inject_sock .connect (sockname [:2 ])
4711
+ except (BlockingIOError , InterruptedError ):
4712
+ pass
4713
+ inject_sock .setblocking (True )
4714
+ return sockname
4715
+
4716
+ sock1 = sock2 = None
4717
+ try :
4718
+ socket .socket .getsockname = inject_getsocketname
4719
+ with self .assertRaises (OSError ):
4720
+ sock1 , sock2 = socket .socketpair ()
4721
+ finally :
4722
+ socket .socket .getsockname = orig_getsockname
4723
+ if inject_sock :
4724
+ inject_sock .close ()
4725
+ if sock1 : # This cleanup isn't needed on a successful test.
4726
+ sock1 .close ()
4727
+ if sock2 :
4728
+ sock2 .close ()
4729
+
4730
+ def _test_injected_authentication_failure (self ):
4731
+ # No-op. Exists for base class threading infrastructure to call.
4732
+ # We could refactor this test into its own lesser class along with the
4733
+ # setUp and tearDown code to construct an ideal; it is simpler to keep
4734
+ # it here and live with extra overhead one this _one_ failure test.
4735
+ pass
4736
+
4737
+
4616
4738
class NonBlockingTCPTests (ThreadedTCPSocketTest ):
4617
4739
4618
4740
def __init__ (self , methodName = 'runTest' ):
0 commit comments