@@ -700,75 +700,109 @@ def _create_connection_transport(self, sock, protocol_factory, ssl,
700
700
@coroutine
701
701
def create_datagram_endpoint (self , protocol_factory ,
702
702
local_addr = None , remote_addr = None , * ,
703
- family = 0 , proto = 0 , flags = 0 ):
703
+ family = 0 , proto = 0 , flags = 0 ,
704
+ reuse_address = None , reuse_port = None ,
705
+ allow_broadcast = None , sock = None ):
704
706
"""Create datagram connection."""
705
- if not (local_addr or remote_addr ):
706
- if family == 0 :
707
- raise ValueError ('unexpected address family' )
708
- addr_pairs_info = (((family , proto ), (None , None )),)
709
- else :
710
- # join address by (family, protocol)
711
- addr_infos = collections .OrderedDict ()
712
- for idx , addr in ((0 , local_addr ), (1 , remote_addr )):
713
- if addr is not None :
714
- assert isinstance (addr , tuple ) and len (addr ) == 2 , (
715
- '2-tuple is expected' )
716
-
717
- infos = yield from self .getaddrinfo (
718
- * addr , family = family , type = socket .SOCK_DGRAM ,
719
- proto = proto , flags = flags )
720
- if not infos :
721
- raise OSError ('getaddrinfo() returned empty list' )
722
-
723
- for fam , _ , pro , _ , address in infos :
724
- key = (fam , pro )
725
- if key not in addr_infos :
726
- addr_infos [key ] = [None , None ]
727
- addr_infos [key ][idx ] = address
728
-
729
- # each addr has to have info for each (family, proto) pair
730
- addr_pairs_info = [
731
- (key , addr_pair ) for key , addr_pair in addr_infos .items ()
732
- if not ((local_addr and addr_pair [0 ] is None ) or
733
- (remote_addr and addr_pair [1 ] is None ))]
734
-
735
- if not addr_pairs_info :
736
- raise ValueError ('can not get address information' )
737
-
738
- exceptions = []
739
-
740
- for ((family , proto ),
741
- (local_address , remote_address )) in addr_pairs_info :
742
- sock = None
707
+ if sock is not None :
708
+ if (local_addr or remote_addr or
709
+ family or proto or flags or
710
+ reuse_address or reuse_port or allow_broadcast ):
711
+ # show the problematic kwargs in exception msg
712
+ opts = dict (local_addr = local_addr , remote_addr = remote_addr ,
713
+ family = family , proto = proto , flags = flags ,
714
+ reuse_address = reuse_address , reuse_port = reuse_port ,
715
+ allow_broadcast = allow_broadcast )
716
+ problems = ', ' .join (
717
+ '{}={}' .format (k , v ) for k , v in opts .items () if v )
718
+ raise ValueError (
719
+ 'socket modifier keyword arguments can not be used '
720
+ 'when sock is specified. ({})' .format (problems ))
721
+ sock .setblocking (False )
743
722
r_addr = None
744
- try :
745
- sock = socket .socket (
746
- family = family , type = socket .SOCK_DGRAM , proto = proto )
747
- sock .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
748
- sock .setblocking (False )
749
-
750
- if local_addr :
751
- sock .bind (local_address )
752
- if remote_addr :
753
- yield from self .sock_connect (sock , remote_address )
754
- r_addr = remote_address
755
- except OSError as exc :
756
- if sock is not None :
757
- sock .close ()
758
- exceptions .append (exc )
759
- except :
760
- if sock is not None :
761
- sock .close ()
762
- raise
763
- else :
764
- break
765
723
else :
766
- raise exceptions [0 ]
724
+ if not (local_addr or remote_addr ):
725
+ if family == 0 :
726
+ raise ValueError ('unexpected address family' )
727
+ addr_pairs_info = (((family , proto ), (None , None )),)
728
+ else :
729
+ # join address by (family, protocol)
730
+ addr_infos = collections .OrderedDict ()
731
+ for idx , addr in ((0 , local_addr ), (1 , remote_addr )):
732
+ if addr is not None :
733
+ assert isinstance (addr , tuple ) and len (addr ) == 2 , (
734
+ '2-tuple is expected' )
735
+
736
+ infos = yield from self .getaddrinfo (
737
+ * addr , family = family , type = socket .SOCK_DGRAM ,
738
+ proto = proto , flags = flags )
739
+ if not infos :
740
+ raise OSError ('getaddrinfo() returned empty list' )
741
+
742
+ for fam , _ , pro , _ , address in infos :
743
+ key = (fam , pro )
744
+ if key not in addr_infos :
745
+ addr_infos [key ] = [None , None ]
746
+ addr_infos [key ][idx ] = address
747
+
748
+ # each addr has to have info for each (family, proto) pair
749
+ addr_pairs_info = [
750
+ (key , addr_pair ) for key , addr_pair in addr_infos .items ()
751
+ if not ((local_addr and addr_pair [0 ] is None ) or
752
+ (remote_addr and addr_pair [1 ] is None ))]
753
+
754
+ if not addr_pairs_info :
755
+ raise ValueError ('can not get address information' )
756
+
757
+ exceptions = []
758
+
759
+ if reuse_address is None :
760
+ reuse_address = os .name == 'posix' and sys .platform != 'cygwin'
761
+
762
+ for ((family , proto ),
763
+ (local_address , remote_address )) in addr_pairs_info :
764
+ sock = None
765
+ r_addr = None
766
+ try :
767
+ sock = socket .socket (
768
+ family = family , type = socket .SOCK_DGRAM , proto = proto )
769
+ if reuse_address :
770
+ sock .setsockopt (
771
+ socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
772
+ if reuse_port :
773
+ if not hasattr (socket , 'SO_REUSEPORT' ):
774
+ raise ValueError (
775
+ 'reuse_port not supported by socket module' )
776
+ else :
777
+ sock .setsockopt (
778
+ socket .SOL_SOCKET , socket .SO_REUSEPORT , 1 )
779
+ if allow_broadcast :
780
+ sock .setsockopt (
781
+ socket .SOL_SOCKET , socket .SO_BROADCAST , 1 )
782
+ sock .setblocking (False )
783
+
784
+ if local_addr :
785
+ sock .bind (local_address )
786
+ if remote_addr :
787
+ yield from self .sock_connect (sock , remote_address )
788
+ r_addr = remote_address
789
+ except OSError as exc :
790
+ if sock is not None :
791
+ sock .close ()
792
+ exceptions .append (exc )
793
+ except :
794
+ if sock is not None :
795
+ sock .close ()
796
+ raise
797
+ else :
798
+ break
799
+ else :
800
+ raise exceptions [0 ]
767
801
768
802
protocol = protocol_factory ()
769
803
waiter = futures .Future (loop = self )
770
- transport = self ._make_datagram_transport (sock , protocol , r_addr ,
771
- waiter )
804
+ transport = self ._make_datagram_transport (
805
+ sock , protocol , r_addr , waiter )
772
806
if self ._debug :
773
807
if local_addr :
774
808
logger .info ("Datagram endpoint local_addr=%r remote_addr=%r "
@@ -804,7 +838,8 @@ def create_server(self, protocol_factory, host=None, port=None,
804
838
sock = None ,
805
839
backlog = 100 ,
806
840
ssl = None ,
807
- reuse_address = None ):
841
+ reuse_address = None ,
842
+ reuse_port = None ):
808
843
"""Create a TCP server.
809
844
810
845
The host parameter can be a string, in that case the TCP server is bound
@@ -857,8 +892,15 @@ def create_server(self, protocol_factory, host=None, port=None,
857
892
continue
858
893
sockets .append (sock )
859
894
if reuse_address :
860
- sock .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR ,
861
- True )
895
+ sock .setsockopt (
896
+ socket .SOL_SOCKET , socket .SO_REUSEADDR , True )
897
+ if reuse_port :
898
+ if not hasattr (socket , 'SO_REUSEPORT' ):
899
+ raise ValueError (
900
+ 'reuse_port not supported by socket module' )
901
+ else :
902
+ sock .setsockopt (
903
+ socket .SOL_SOCKET , socket .SO_REUSEPORT , True )
862
904
# Disable IPv4/IPv6 dual stack support (enabled by
863
905
# default on Linux) which makes a single socket
864
906
# listen on both address families.
0 commit comments