@@ -508,19 +508,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
508
508
def __init__ (self , methodName = 'runTest' ):
509
509
unittest .TestCase .__init__ (self , methodName = methodName )
510
510
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 ()
511
517
512
518
def setUp (self ):
513
- self .serv , self .cli = socket .socketpair ()
519
+ self .serv , self .cli = self .socketpair ()
514
520
515
521
def tearDown (self ):
516
- self .serv .close ()
522
+ if self .serv :
523
+ self .serv .close ()
517
524
self .serv = None
518
525
519
526
def clientSetUp (self ):
520
527
pass
521
528
522
529
def clientTearDown (self ):
523
- self .cli .close ()
530
+ if self .cli :
531
+ self .cli .close ()
524
532
self .cli = None
525
533
ThreadableTest .clientTearDown (self )
526
534
@@ -4307,6 +4315,120 @@ def _testSend(self):
4307
4315
self .assertEqual (msg , MSG )
4308
4316
4309
4317
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
+
4310
4432
class NonBlockingTCPTests (ThreadedTCPSocketTest ):
4311
4433
4312
4434
def __init__ (self , methodName = 'runTest' ):
0 commit comments