@@ -508,19 +508,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
508508 def __init__ (self , methodName = 'runTest' ):
509509 unittest .TestCase .__init__ (self , methodName = methodName )
510510 ThreadableTest .__init__ (self )
511+ self .cli = None
512+ self .serv = None
513+
514+ def socketpair (self ):
515+ # To be overridden by some child classes.
516+ return socket .socketpair ()
511517
512518 def setUp (self ):
513- self .serv , self .cli = socket .socketpair ()
519+ self .serv , self .cli = self .socketpair ()
514520
515521 def tearDown (self ):
516- self .serv .close ()
522+ if self .serv :
523+ self .serv .close ()
517524 self .serv = None
518525
519526 def clientSetUp (self ):
520527 pass
521528
522529 def clientTearDown (self ):
523- self .cli .close ()
530+ if self .cli :
531+ self .cli .close ()
524532 self .cli = None
525533 ThreadableTest .clientTearDown (self )
526534
@@ -4307,6 +4315,120 @@ def _testSend(self):
43074315 self .assertEqual (msg , MSG )
43084316
43094317
4318+ class PurePythonSocketPairTest (SocketPairTest ):
4319+
4320+ # Explicitly use socketpair AF_INET or AF_INET6 to ensure that is the
4321+ # code path we're using regardless platform is the pure python one where
4322+ # `_socket.socketpair` does not exist. (AF_INET does not work with
4323+ # _socket.socketpair on many platforms).
4324+ def socketpair (self ):
4325+ # called by super().setUp().
4326+ try :
4327+ return socket .socketpair (socket .AF_INET6 )
4328+ except OSError :
4329+ return socket .socketpair (socket .AF_INET )
4330+
4331+ # Local imports in this class make for easy security fix backporting.
4332+
4333+ def setUp (self ):
4334+ import _socket
4335+ self ._orig_sp = getattr (_socket , 'socketpair' , None )
4336+ if self ._orig_sp is not None :
4337+ # This forces the version using the non-OS provided socketpair
4338+ # emulation via an AF_INET socket in Lib/socket.py.
4339+ del _socket .socketpair
4340+ import importlib
4341+ global socket
4342+ socket = importlib .reload (socket )
4343+ else :
4344+ pass # This platform already uses the non-OS provided version.
4345+ super ().setUp ()
4346+
4347+ def tearDown (self ):
4348+ super ().tearDown ()
4349+ import _socket
4350+ if self ._orig_sp is not None :
4351+ # Restore the default socket.socketpair definition.
4352+ _socket .socketpair = self ._orig_sp
4353+ import importlib
4354+ global socket
4355+ socket = importlib .reload (socket )
4356+
4357+ def test_recv (self ):
4358+ msg = self .serv .recv (1024 )
4359+ self .assertEqual (msg , MSG )
4360+
4361+ def _test_recv (self ):
4362+ self .cli .send (MSG )
4363+
4364+ def test_send (self ):
4365+ self .serv .send (MSG )
4366+
4367+ def _test_send (self ):
4368+ msg = self .cli .recv (1024 )
4369+ self .assertEqual (msg , MSG )
4370+
4371+ def test_ipv4 (self ):
4372+ cli , srv = socket .socketpair (socket .AF_INET )
4373+ cli .close ()
4374+ srv .close ()
4375+
4376+ def _test_ipv4 (self ):
4377+ pass
4378+
4379+ @unittest .skipIf (not hasattr (_socket , 'IPPROTO_IPV6' ) or
4380+ not hasattr (_socket , 'IPV6_V6ONLY' ),
4381+ "IPV6_V6ONLY option not supported" )
4382+ @unittest .skipUnless (support .IPV6_ENABLED , 'IPv6 required for this test' )
4383+ def test_ipv6 (self ):
4384+ cli , srv = socket .socketpair (socket .AF_INET6 )
4385+ cli .close ()
4386+ srv .close ()
4387+
4388+ def _test_ipv6 (self ):
4389+ pass
4390+
4391+ def test_injected_authentication_failure (self ):
4392+ orig_getsockname = socket .socket .getsockname
4393+ inject_sock = None
4394+
4395+ def inject_getsocketname (self ):
4396+ nonlocal inject_sock
4397+ sockname = orig_getsockname (self )
4398+ # Connect to the listening socket ahead of the
4399+ # client socket.
4400+ if inject_sock is None :
4401+ inject_sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
4402+ inject_sock .setblocking (False )
4403+ try :
4404+ inject_sock .connect (sockname [:2 ])
4405+ except (BlockingIOError , InterruptedError ):
4406+ pass
4407+ inject_sock .setblocking (True )
4408+ return sockname
4409+
4410+ sock1 = sock2 = None
4411+ try :
4412+ socket .socket .getsockname = inject_getsocketname
4413+ with self .assertRaises (OSError ):
4414+ sock1 , sock2 = socket .socketpair ()
4415+ finally :
4416+ socket .socket .getsockname = orig_getsockname
4417+ if inject_sock :
4418+ inject_sock .close ()
4419+ if sock1 : # This cleanup isn't needed on a successful test.
4420+ sock1 .close ()
4421+ if sock2 :
4422+ sock2 .close ()
4423+
4424+ def _test_injected_authentication_failure (self ):
4425+ # No-op. Exists for base class threading infrastructure to call.
4426+ # We could refactor this test into its own lesser class along with the
4427+ # setUp and tearDown code to construct an ideal; it is simpler to keep
4428+ # it here and live with extra overhead one this _one_ failure test.
4429+ pass
4430+
4431+
43104432class NonBlockingTCPTests (ThreadedTCPSocketTest ):
43114433
43124434 def __init__ (self , methodName = 'runTest' ):
0 commit comments