@@ -553,16 +553,65 @@ def fromshare(info):
553553 return socket (0 , 0 , 0 , info )
554554 __all__ .append ("fromshare" )
555555
556- if hasattr (_socket , "socketpair" ):
556+ # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
557+ # This is used if _socket doesn't natively provide socketpair. It's
558+ # always defined so that it can be patched in for testing purposes.
559+ def _fallback_socketpair (family = AF_INET , type = SOCK_STREAM , proto = 0 ):
560+ if family == AF_INET :
561+ host = _LOCALHOST
562+ elif family == AF_INET6 :
563+ host = _LOCALHOST_V6
564+ else :
565+ raise ValueError ("Only AF_INET and AF_INET6 socket address families "
566+ "are supported" )
567+ if type != SOCK_STREAM :
568+ raise ValueError ("Only SOCK_STREAM socket type is supported" )
569+ if proto != 0 :
570+ raise ValueError ("Only protocol zero is supported" )
571+
572+ # We create a connected TCP socket. Note the trick with
573+ # setblocking(False) that prevents us from having to create a thread.
574+ lsock = socket (family , type , proto )
575+ try :
576+ lsock .bind ((host , 0 ))
577+ lsock .listen ()
578+ # On IPv6, ignore flow_info and scope_id
579+ addr , port = lsock .getsockname ()[:2 ]
580+ csock = socket (family , type , proto )
581+ try :
582+ csock .setblocking (False )
583+ try :
584+ csock .connect ((addr , port ))
585+ except (BlockingIOError , InterruptedError ):
586+ pass
587+ csock .setblocking (True )
588+ ssock , _ = lsock .accept ()
589+ except :
590+ csock .close ()
591+ raise
592+ finally :
593+ lsock .close ()
557594
558- def socketpair (family = None , type = SOCK_STREAM , proto = 0 ):
559- """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
595+ # Authenticating avoids using a connection from something else
596+ # able to connect to {host}:{port} instead of us.
597+ # We expect only AF_INET and AF_INET6 families.
598+ try :
599+ if (
600+ ssock .getsockname () != csock .getpeername ()
601+ or csock .getsockname () != ssock .getpeername ()
602+ ):
603+ raise ConnectionError ("Unexpected peer connection" )
604+ except :
605+ # getsockname() and getpeername() can fail
606+ # if either socket isn't connected.
607+ ssock .close ()
608+ csock .close ()
609+ raise
560610
561- Create a pair of socket objects from the sockets returned by the platform
562- socketpair() function.
563- The arguments are the same as for socket() except the default family is
564- AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
565- """
611+ return (ssock , csock )
612+
613+ if hasattr (_socket , "socketpair" ):
614+ def socketpair (family = None , type = SOCK_STREAM , proto = 0 ):
566615 if family is None :
567616 try :
568617 family = AF_UNIX
@@ -574,61 +623,7 @@ def socketpair(family=None, type=SOCK_STREAM, proto=0):
574623 return a , b
575624
576625else :
577-
578- # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
579- def socketpair (family = AF_INET , type = SOCK_STREAM , proto = 0 ):
580- if family == AF_INET :
581- host = _LOCALHOST
582- elif family == AF_INET6 :
583- host = _LOCALHOST_V6
584- else :
585- raise ValueError ("Only AF_INET and AF_INET6 socket address families "
586- "are supported" )
587- if type != SOCK_STREAM :
588- raise ValueError ("Only SOCK_STREAM socket type is supported" )
589- if proto != 0 :
590- raise ValueError ("Only protocol zero is supported" )
591-
592- # We create a connected TCP socket. Note the trick with
593- # setblocking(False) that prevents us from having to create a thread.
594- lsock = socket (family , type , proto )
595- try :
596- lsock .bind ((host , 0 ))
597- lsock .listen ()
598- # On IPv6, ignore flow_info and scope_id
599- addr , port = lsock .getsockname ()[:2 ]
600- csock = socket (family , type , proto )
601- try :
602- csock .setblocking (False )
603- try :
604- csock .connect ((addr , port ))
605- except (BlockingIOError , InterruptedError ):
606- pass
607- csock .setblocking (True )
608- ssock , _ = lsock .accept ()
609- except :
610- csock .close ()
611- raise
612- finally :
613- lsock .close ()
614-
615- # Authenticating avoids using a connection from something else
616- # able to connect to {host}:{port} instead of us.
617- # We expect only AF_INET and AF_INET6 families.
618- try :
619- if (
620- ssock .getsockname () != csock .getpeername ()
621- or csock .getsockname () != ssock .getpeername ()
622- ):
623- raise ConnectionError ("Unexpected peer connection" )
624- except :
625- # getsockname() and getpeername() can fail
626- # if either socket isn't connected.
627- ssock .close ()
628- csock .close ()
629- raise
630-
631- return (ssock , csock )
626+ socketpair = _fallback_socketpair
632627 __all__ .append ("socketpair" )
633628
634629socketpair .__doc__ = """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
0 commit comments