@@ -689,6 +689,21 @@ cdef class Loop:
689
689
else :
690
690
fut.set_result(None )
691
691
692
+ cdef _sock_set_reuseport(self , int fd):
693
+ cdef:
694
+ int err
695
+ int reuseport_flag = 1
696
+
697
+ err = system.setsockopt(
698
+ fd,
699
+ uv.SOL_SOCKET,
700
+ SO_REUSEPORT,
701
+ < char * > & reuseport_flag,
702
+ sizeof(reuseport_flag))
703
+
704
+ if err < 0 :
705
+ raise convert_error(- errno.errno)
706
+
692
707
cdef _set_coroutine_wrapper(self , bint enabled):
693
708
enabled = bool (enabled)
694
709
if self ._coroutine_wrapper_set == enabled:
@@ -1003,7 +1018,7 @@ cdef class Loop:
1003
1018
int backlog = 100 ,
1004
1019
ssl = None ,
1005
1020
reuse_address = None , # ignored, libuv sets it
1006
- reuse_port = None ): # ignored
1021
+ reuse_port = None ):
1007
1022
1008
1023
cdef:
1009
1024
TCPServer tcp
@@ -1018,6 +1033,11 @@ cdef class Loop:
1018
1033
raise ValueError (
1019
1034
' host/port and sock can not be specified at the same time' )
1020
1035
1036
+ reuse_port = bool (reuse_port)
1037
+ if reuse_port and not has_SO_REUSEPORT:
1038
+ raise ValueError (
1039
+ ' reuse_port not supported by socket module' )
1040
+
1021
1041
if host == ' ' :
1022
1042
hosts = [None ]
1023
1043
elif (isinstance (host, str ) or not isinstance (host, col_Iterable)):
@@ -1036,8 +1056,15 @@ cdef class Loop:
1036
1056
for info in infos:
1037
1057
addrinfo = (< AddrInfo> info).data
1038
1058
while addrinfo != NULL :
1059
+ if addrinfo.ai_family == uv.AF_UNSPEC:
1060
+ raise RuntimeError (' AF_UNSPEC in DNS results' )
1061
+
1039
1062
tcp = TCPServer.new(
1040
- self , protocol_factory, server, ssl)
1063
+ self , protocol_factory, server, ssl,
1064
+ addrinfo.ai_family)
1065
+
1066
+ if reuse_port:
1067
+ self ._sock_set_reuseport(tcp._fileno())
1041
1068
1042
1069
try :
1043
1070
tcp.bind(addrinfo.ai_addr)
@@ -1057,7 +1084,8 @@ cdef class Loop:
1057
1084
else :
1058
1085
if sock is None :
1059
1086
raise ValueError (' Neither host/port nor sock were specified' )
1060
- tcp = TCPServer.new(self , protocol_factory, server, ssl)
1087
+ tcp = TCPServer.new(self , protocol_factory, server, ssl,
1088
+ uv.AF_UNSPEC)
1061
1089
fileno = os_dup(sock.fileno())
1062
1090
try :
1063
1091
tcp.open(fileno)
@@ -1684,6 +1712,10 @@ cdef class Loop:
1684
1712
udp._attach_fileobj(sock)
1685
1713
else :
1686
1714
reuse_address = bool (reuse_address)
1715
+ reuse_port = bool (reuse_port)
1716
+ if reuse_port and not has_SO_REUSEPORT:
1717
+ raise ValueError (
1718
+ ' reuse_port not supported by socket module' )
1687
1719
1688
1720
lads = None
1689
1721
if local_addr is not None :
@@ -1720,6 +1752,9 @@ cdef class Loop:
1720
1752
udp = UDPTransport.__new__ (UDPTransport)
1721
1753
udp._init(self , family)
1722
1754
1755
+ if reuse_port:
1756
+ self ._sock_set_reuseport(udp._fileno())
1757
+
1723
1758
socket = udp._get_socket()
1724
1759
socket.bind((' 0.0.0.0' , 0 ))
1725
1760
else :
@@ -1728,6 +1763,8 @@ cdef class Loop:
1728
1763
try :
1729
1764
udp = UDPTransport.__new__ (UDPTransport)
1730
1765
udp._init(self , lai.ai_family)
1766
+ if reuse_port:
1767
+ self ._sock_set_reuseport(udp._fileno())
1731
1768
udp._bind(lai.ai_addr, reuse_address)
1732
1769
except Exception as ex:
1733
1770
lai = lai.ai_next
0 commit comments