@@ -689,6 +689,21 @@ cdef class Loop:
689689 else :
690690 fut.set_result(None )
691691
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+
692707 cdef _set_coroutine_wrapper(self , bint enabled):
693708 enabled = bool (enabled)
694709 if self ._coroutine_wrapper_set == enabled:
@@ -1003,7 +1018,7 @@ cdef class Loop:
10031018 int backlog = 100 ,
10041019 ssl = None ,
10051020 reuse_address = None , # ignored, libuv sets it
1006- reuse_port = None ): # ignored
1021+ reuse_port = None ):
10071022
10081023 cdef:
10091024 TCPServer tcp
@@ -1018,6 +1033,11 @@ cdef class Loop:
10181033 raise ValueError (
10191034 ' host/port and sock can not be specified at the same time' )
10201035
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+
10211041 if host == ' ' :
10221042 hosts = [None ]
10231043 elif (isinstance (host, str ) or not isinstance (host, col_Iterable)):
@@ -1036,8 +1056,15 @@ cdef class Loop:
10361056 for info in infos:
10371057 addrinfo = (< AddrInfo> info).data
10381058 while addrinfo != NULL :
1059+ if addrinfo.ai_family == uv.AF_UNSPEC:
1060+ raise RuntimeError (' AF_UNSPEC in DNS results' )
1061+
10391062 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())
10411068
10421069 try :
10431070 tcp.bind(addrinfo.ai_addr)
@@ -1057,7 +1084,8 @@ cdef class Loop:
10571084 else :
10581085 if sock is None :
10591086 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)
10611089 fileno = os_dup(sock.fileno())
10621090 try :
10631091 tcp.open(fileno)
@@ -1684,6 +1712,10 @@ cdef class Loop:
16841712 udp._attach_fileobj(sock)
16851713 else :
16861714 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' )
16871719
16881720 lads = None
16891721 if local_addr is not None :
@@ -1720,6 +1752,9 @@ cdef class Loop:
17201752 udp = UDPTransport.__new__ (UDPTransport)
17211753 udp._init(self , family)
17221754
1755+ if reuse_port:
1756+ self ._sock_set_reuseport(udp._fileno())
1757+
17231758 socket = udp._get_socket()
17241759 socket.bind((' 0.0.0.0' , 0 ))
17251760 else :
@@ -1728,6 +1763,8 @@ cdef class Loop:
17281763 try :
17291764 udp = UDPTransport.__new__ (UDPTransport)
17301765 udp._init(self , lai.ai_family)
1766+ if reuse_port:
1767+ self ._sock_set_reuseport(udp._fileno())
17311768 udp._bind(lai.ai_addr, reuse_address)
17321769 except Exception as ex:
17331770 lai = lai.ai_next
0 commit comments