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