@@ -542,19 +542,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
542
542
def __init__ (self , methodName = 'runTest' ):
543
543
unittest .TestCase .__init__ (self , methodName = methodName )
544
544
ThreadableTest .__init__ (self )
545
+ self .cli = None
546
+ self .serv = None
547
+
548
+ def socketpair (self ):
549
+ # To be overridden by some child classes.
550
+ return socket .socketpair ()
545
551
546
552
def setUp (self ):
547
- self .serv , self .cli = socket .socketpair ()
553
+ self .serv , self .cli = self .socketpair ()
548
554
549
555
def tearDown (self ):
550
- self .serv .close ()
556
+ if self .serv :
557
+ self .serv .close ()
551
558
self .serv = None
552
559
553
560
def clientSetUp (self ):
554
561
pass
555
562
556
563
def clientTearDown (self ):
557
- self .cli .close ()
564
+ if self .cli :
565
+ self .cli .close ()
558
566
self .cli = None
559
567
ThreadableTest .clientTearDown (self )
560
568
@@ -4667,6 +4675,120 @@ def _testSend(self):
4667
4675
self .assertEqual (msg , MSG )
4668
4676
4669
4677
4678
+ class PurePythonSocketPairTest (SocketPairTest ):
4679
+
4680
+ # Explicitly use socketpair AF_INET or AF_INET6 to ensure that is the
4681
+ # code path we're using regardless platform is the pure python one where
4682
+ # `_socket.socketpair` does not exist. (AF_INET does not work with
4683
+ # _socket.socketpair on many platforms).
4684
+ def socketpair (self ):
4685
+ # called by super().setUp().
4686
+ try :
4687
+ return socket .socketpair (socket .AF_INET6 )
4688
+ except OSError :
4689
+ return socket .socketpair (socket .AF_INET )
4690
+
4691
+ # Local imports in this class make for easy security fix backporting.
4692
+
4693
+ def setUp (self ):
4694
+ import _socket
4695
+ self ._orig_sp = getattr (_socket , 'socketpair' , None )
4696
+ if self ._orig_sp is not None :
4697
+ # This forces the version using the non-OS provided socketpair
4698
+ # emulation via an AF_INET socket in Lib/socket.py.
4699
+ del _socket .socketpair
4700
+ import importlib
4701
+ global socket
4702
+ socket = importlib .reload (socket )
4703
+ else :
4704
+ pass # This platform already uses the non-OS provided version.
4705
+ super ().setUp ()
4706
+
4707
+ def tearDown (self ):
4708
+ super ().tearDown ()
4709
+ import _socket
4710
+ if self ._orig_sp is not None :
4711
+ # Restore the default socket.socketpair definition.
4712
+ _socket .socketpair = self ._orig_sp
4713
+ import importlib
4714
+ global socket
4715
+ socket = importlib .reload (socket )
4716
+
4717
+ def test_recv (self ):
4718
+ msg = self .serv .recv (1024 )
4719
+ self .assertEqual (msg , MSG )
4720
+
4721
+ def _test_recv (self ):
4722
+ self .cli .send (MSG )
4723
+
4724
+ def test_send (self ):
4725
+ self .serv .send (MSG )
4726
+
4727
+ def _test_send (self ):
4728
+ msg = self .cli .recv (1024 )
4729
+ self .assertEqual (msg , MSG )
4730
+
4731
+ def test_ipv4 (self ):
4732
+ cli , srv = socket .socketpair (socket .AF_INET )
4733
+ cli .close ()
4734
+ srv .close ()
4735
+
4736
+ def _test_ipv4 (self ):
4737
+ pass
4738
+
4739
+ @unittest .skipIf (not hasattr (_socket , 'IPPROTO_IPV6' ) or
4740
+ not hasattr (_socket , 'IPV6_V6ONLY' ),
4741
+ "IPV6_V6ONLY option not supported" )
4742
+ @unittest .skipUnless (socket_helper .IPV6_ENABLED , 'IPv6 required for this test' )
4743
+ def test_ipv6 (self ):
4744
+ cli , srv = socket .socketpair (socket .AF_INET6 )
4745
+ cli .close ()
4746
+ srv .close ()
4747
+
4748
+ def _test_ipv6 (self ):
4749
+ pass
4750
+
4751
+ def test_injected_authentication_failure (self ):
4752
+ orig_getsockname = socket .socket .getsockname
4753
+ inject_sock = None
4754
+
4755
+ def inject_getsocketname (self ):
4756
+ nonlocal inject_sock
4757
+ sockname = orig_getsockname (self )
4758
+ # Connect to the listening socket ahead of the
4759
+ # client socket.
4760
+ if inject_sock is None :
4761
+ inject_sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
4762
+ inject_sock .setblocking (False )
4763
+ try :
4764
+ inject_sock .connect (sockname [:2 ])
4765
+ except (BlockingIOError , InterruptedError ):
4766
+ pass
4767
+ inject_sock .setblocking (True )
4768
+ return sockname
4769
+
4770
+ sock1 = sock2 = None
4771
+ try :
4772
+ socket .socket .getsockname = inject_getsocketname
4773
+ with self .assertRaises (OSError ):
4774
+ sock1 , sock2 = socket .socketpair ()
4775
+ finally :
4776
+ socket .socket .getsockname = orig_getsockname
4777
+ if inject_sock :
4778
+ inject_sock .close ()
4779
+ if sock1 : # This cleanup isn't needed on a successful test.
4780
+ sock1 .close ()
4781
+ if sock2 :
4782
+ sock2 .close ()
4783
+
4784
+ def _test_injected_authentication_failure (self ):
4785
+ # No-op. Exists for base class threading infrastructure to call.
4786
+ # We could refactor this test into its own lesser class along with the
4787
+ # setUp and tearDown code to construct an ideal; it is simpler to keep
4788
+ # it here and live with extra overhead one this _one_ failure test.
4789
+ pass
4790
+
4791
+
4670
4792
class NonBlockingTCPTests (ThreadedTCPSocketTest ):
4671
4793
4672
4794
def __init__ (self , methodName = 'runTest' ):
0 commit comments