@@ -588,16 +588,65 @@ def fromshare(info):
588588 return socket (0 , 0 , 0 , info )
589589 __all__ .append ("fromshare" )
590590
591- if hasattr (_socket , "socketpair" ):
591+ # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
592+ # This is used if _socket doesn't natively provide socketpair. It's
593+ # always defined so that it can be patched in for testing purposes.
594+ def _fallback_socketpair (family = AF_INET , type = SOCK_STREAM , proto = 0 ):
595+ if family == AF_INET :
596+ host = _LOCALHOST
597+ elif family == AF_INET6 :
598+ host = _LOCALHOST_V6
599+ else :
600+ raise ValueError ("Only AF_INET and AF_INET6 socket address families "
601+ "are supported" )
602+ if type != SOCK_STREAM :
603+ raise ValueError ("Only SOCK_STREAM socket type is supported" )
604+ if proto != 0 :
605+ raise ValueError ("Only protocol zero is supported" )
606+
607+ # We create a connected TCP socket. Note the trick with
608+ # setblocking(False) that prevents us from having to create a thread.
609+ lsock = socket (family , type , proto )
610+ try :
611+ lsock .bind ((host , 0 ))
612+ lsock .listen ()
613+ # On IPv6, ignore flow_info and scope_id
614+ addr , port = lsock .getsockname ()[:2 ]
615+ csock = socket (family , type , proto )
616+ try :
617+ csock .setblocking (False )
618+ try :
619+ csock .connect ((addr , port ))
620+ except (BlockingIOError , InterruptedError ):
621+ pass
622+ csock .setblocking (True )
623+ ssock , _ = lsock .accept ()
624+ except :
625+ csock .close ()
626+ raise
627+ finally :
628+ lsock .close ()
592629
593- def socketpair (family = None , type = SOCK_STREAM , proto = 0 ):
594- """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
630+ # Authenticating avoids using a connection from something else
631+ # able to connect to {host}:{port} instead of us.
632+ # We expect only AF_INET and AF_INET6 families.
633+ try :
634+ if (
635+ ssock .getsockname () != csock .getpeername ()
636+ or csock .getsockname () != ssock .getpeername ()
637+ ):
638+ raise ConnectionError ("Unexpected peer connection" )
639+ except :
640+ # getsockname() and getpeername() can fail
641+ # if either socket isn't connected.
642+ ssock .close ()
643+ csock .close ()
644+ raise
595645
596- Create a pair of socket objects from the sockets returned by the platform
597- socketpair() function.
598- The arguments are the same as for socket() except the default family is
599- AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
600- """
646+ return (ssock , csock )
647+
648+ if hasattr (_socket , "socketpair" ):
649+ def socketpair (family = None , type = SOCK_STREAM , proto = 0 ):
601650 if family is None :
602651 try :
603652 family = AF_UNIX
@@ -609,61 +658,7 @@ def socketpair(family=None, type=SOCK_STREAM, proto=0):
609658 return a , b
610659
611660else :
612-
613- # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
614- def socketpair (family = AF_INET , type = SOCK_STREAM , proto = 0 ):
615- if family == AF_INET :
616- host = _LOCALHOST
617- elif family == AF_INET6 :
618- host = _LOCALHOST_V6
619- else :
620- raise ValueError ("Only AF_INET and AF_INET6 socket address families "
621- "are supported" )
622- if type != SOCK_STREAM :
623- raise ValueError ("Only SOCK_STREAM socket type is supported" )
624- if proto != 0 :
625- raise ValueError ("Only protocol zero is supported" )
626-
627- # We create a connected TCP socket. Note the trick with
628- # setblocking(False) that prevents us from having to create a thread.
629- lsock = socket (family , type , proto )
630- try :
631- lsock .bind ((host , 0 ))
632- lsock .listen ()
633- # On IPv6, ignore flow_info and scope_id
634- addr , port = lsock .getsockname ()[:2 ]
635- csock = socket (family , type , proto )
636- try :
637- csock .setblocking (False )
638- try :
639- csock .connect ((addr , port ))
640- except (BlockingIOError , InterruptedError ):
641- pass
642- csock .setblocking (True )
643- ssock , _ = lsock .accept ()
644- except :
645- csock .close ()
646- raise
647- finally :
648- lsock .close ()
649-
650- # Authenticating avoids using a connection from something else
651- # able to connect to {host}:{port} instead of us.
652- # We expect only AF_INET and AF_INET6 families.
653- try :
654- if (
655- ssock .getsockname () != csock .getpeername ()
656- or csock .getsockname () != ssock .getpeername ()
657- ):
658- raise ConnectionError ("Unexpected peer connection" )
659- except :
660- # getsockname() and getpeername() can fail
661- # if either socket isn't connected.
662- ssock .close ()
663- csock .close ()
664- raise
665-
666- return (ssock , csock )
661+ socketpair = _fallback_socketpair
667662 __all__ .append ("socketpair" )
668663
669664socketpair .__doc__ = """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
0 commit comments