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