You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

414 lines
12 KiB

  1. cdef __port_to_int(port, proto):
  2. if type(port) is int:
  3. return port
  4. if port is None or port == '' or port == b'':
  5. return 0
  6. try:
  7. return int(port)
  8. except (ValueError, TypeError):
  9. pass
  10. if isinstance(port, bytes):
  11. port = port.decode()
  12. if isinstance(port, str) and proto is not None:
  13. if proto == uv.IPPROTO_TCP:
  14. return socket_getservbyname(port, 'tcp')
  15. elif proto == uv.IPPROTO_UDP:
  16. return socket_getservbyname(port, 'udp')
  17. raise OSError('service/proto not found')
  18. cdef __convert_sockaddr_to_pyaddr(const system.sockaddr* addr):
  19. # Converts sockaddr structs into what Python socket
  20. # module can understand:
  21. # - for IPv4 a tuple of (host, port)
  22. # - for IPv6 a tuple of (host, port, flowinfo, scope_id)
  23. cdef:
  24. char buf[128] # INET6_ADDRSTRLEN is usually 46
  25. int err
  26. system.sockaddr_in *addr4
  27. system.sockaddr_in6 *addr6
  28. if addr.sa_family == uv.AF_INET:
  29. addr4 = <system.sockaddr_in*>addr
  30. err = uv.uv_ip4_name(addr4, buf, sizeof(buf))
  31. if err < 0:
  32. raise convert_error(err)
  33. return (
  34. PyUnicode_FromString(buf),
  35. system.ntohs(addr4.sin_port)
  36. )
  37. elif addr.sa_family == uv.AF_INET6:
  38. addr6 = <system.sockaddr_in6*>addr
  39. err = uv.uv_ip6_name(addr6, buf, sizeof(buf))
  40. if err < 0:
  41. raise convert_error(err)
  42. return (
  43. PyUnicode_FromString(buf),
  44. system.ntohs(addr6.sin6_port),
  45. system.ntohl(addr6.sin6_flowinfo),
  46. addr6.sin6_scope_id
  47. )
  48. raise RuntimeError("cannot convert sockaddr into Python object")
  49. @cython.freelist(DEFAULT_FREELIST_SIZE)
  50. cdef class SockAddrHolder:
  51. cdef:
  52. int family
  53. system.sockaddr_storage addr
  54. Py_ssize_t addr_size
  55. cdef LruCache sockaddrs = LruCache(maxsize=DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE)
  56. cdef __convert_pyaddr_to_sockaddr(int family, object addr,
  57. system.sockaddr* res):
  58. cdef:
  59. int err
  60. int addr_len
  61. int scope_id = 0
  62. int flowinfo = 0
  63. char *buf
  64. Py_ssize_t buflen
  65. SockAddrHolder ret
  66. ret = sockaddrs.get(addr, None)
  67. if ret is not None and ret.family == family:
  68. memcpy(res, &ret.addr, ret.addr_size)
  69. return
  70. ret = SockAddrHolder.__new__(SockAddrHolder)
  71. if family == uv.AF_INET:
  72. if not isinstance(addr, tuple):
  73. raise TypeError('AF_INET address must be tuple')
  74. if len(addr) != 2:
  75. raise ValueError('AF_INET address must be tuple of (host, port)')
  76. host, port = addr
  77. if isinstance(host, str):
  78. try:
  79. # idna codec is rather slow, so we try ascii first.
  80. host = host.encode('ascii')
  81. except UnicodeEncodeError:
  82. host = host.encode('idna')
  83. if not isinstance(host, (bytes, bytearray)):
  84. raise TypeError('host must be a string or bytes object')
  85. port = __port_to_int(port, None)
  86. ret.addr_size = sizeof(system.sockaddr_in)
  87. err = uv.uv_ip4_addr(host, <int>port, <system.sockaddr_in*>&ret.addr)
  88. if err < 0:
  89. raise convert_error(err)
  90. elif family == uv.AF_INET6:
  91. if not isinstance(addr, tuple):
  92. raise TypeError('AF_INET6 address must be tuple')
  93. addr_len = len(addr)
  94. if addr_len < 2 or addr_len > 4:
  95. raise ValueError(
  96. 'AF_INET6 must be a tuple of 2-4 parameters: '
  97. '(host, port, flowinfo?, scope_id?)')
  98. host = addr[0]
  99. if isinstance(host, str):
  100. try:
  101. # idna codec is rather slow, so we try ascii first.
  102. host = host.encode('ascii')
  103. except UnicodeEncodeError:
  104. host = host.encode('idna')
  105. if not isinstance(host, (bytes, bytearray)):
  106. raise TypeError('host must be a string or bytes object')
  107. port = __port_to_int(addr[1], None)
  108. if addr_len > 2:
  109. flowinfo = addr[2]
  110. if addr_len > 3:
  111. scope_id = addr[3]
  112. ret.addr_size = sizeof(system.sockaddr_in6)
  113. err = uv.uv_ip6_addr(host, port, <system.sockaddr_in6*>&ret.addr)
  114. if err < 0:
  115. raise convert_error(err)
  116. (<system.sockaddr_in6*>&ret.addr).sin6_flowinfo = flowinfo
  117. (<system.sockaddr_in6*>&ret.addr).sin6_scope_id = scope_id
  118. elif family == uv.AF_UNIX:
  119. if isinstance(addr, str):
  120. addr = addr.encode(sys_getfilesystemencoding())
  121. elif not isinstance(addr, bytes):
  122. raise TypeError('AF_UNIX address must be a str or a bytes object')
  123. PyBytes_AsStringAndSize(addr, &buf, &buflen)
  124. if buflen > 107:
  125. raise ValueError(
  126. f'unix socket path {addr!r} is longer than 107 characters')
  127. ret.addr_size = sizeof(system.sockaddr_un)
  128. memset(&ret.addr, 0, sizeof(system.sockaddr_un))
  129. (<system.sockaddr_un*>&ret.addr).sun_family = uv.AF_UNIX
  130. memcpy((<system.sockaddr_un*>&ret.addr).sun_path, buf, buflen)
  131. else:
  132. raise ValueError(
  133. f'expected AF_INET, AF_INET6, or AF_UNIX family, got {family}')
  134. ret.family = family
  135. sockaddrs[addr] = ret
  136. memcpy(res, &ret.addr, ret.addr_size)
  137. cdef __static_getaddrinfo(object host, object port,
  138. int family, int type,
  139. int proto,
  140. system.sockaddr *addr):
  141. if proto not in {0, uv.IPPROTO_TCP, uv.IPPROTO_UDP}:
  142. return
  143. if _is_sock_stream(type):
  144. proto = uv.IPPROTO_TCP
  145. elif _is_sock_dgram(type):
  146. proto = uv.IPPROTO_UDP
  147. else:
  148. return
  149. try:
  150. port = __port_to_int(port, proto)
  151. except Exception:
  152. return
  153. hp = (host, port)
  154. if family == uv.AF_UNSPEC:
  155. try:
  156. __convert_pyaddr_to_sockaddr(uv.AF_INET, hp, addr)
  157. except Exception:
  158. pass
  159. else:
  160. return (uv.AF_INET, type, proto)
  161. try:
  162. __convert_pyaddr_to_sockaddr(uv.AF_INET6, hp, addr)
  163. except Exception:
  164. pass
  165. else:
  166. return (uv.AF_INET6, type, proto)
  167. else:
  168. try:
  169. __convert_pyaddr_to_sockaddr(family, hp, addr)
  170. except Exception:
  171. pass
  172. else:
  173. return (family, type, proto)
  174. cdef __static_getaddrinfo_pyaddr(object host, object port,
  175. int family, int type,
  176. int proto, int flags):
  177. cdef:
  178. system.sockaddr_storage addr
  179. object triplet
  180. triplet = __static_getaddrinfo(
  181. host, port, family, type,
  182. proto, <system.sockaddr*>&addr)
  183. if triplet is None:
  184. return
  185. af, type, proto = triplet
  186. try:
  187. pyaddr = __convert_sockaddr_to_pyaddr(<system.sockaddr*>&addr)
  188. except Exception:
  189. return
  190. return af, type, proto, '', pyaddr
  191. @cython.freelist(DEFAULT_FREELIST_SIZE)
  192. cdef class AddrInfo:
  193. cdef:
  194. system.addrinfo *data
  195. def __cinit__(self):
  196. self.data = NULL
  197. def __dealloc__(self):
  198. if self.data is not NULL:
  199. uv.uv_freeaddrinfo(self.data) # returns void
  200. self.data = NULL
  201. cdef void set_data(self, system.addrinfo *data):
  202. self.data = data
  203. cdef unpack(self):
  204. cdef:
  205. list result = []
  206. system.addrinfo *ptr
  207. if self.data is NULL:
  208. raise RuntimeError('AddrInfo.data is NULL')
  209. ptr = self.data
  210. while ptr != NULL:
  211. if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
  212. result.append((
  213. ptr.ai_family,
  214. ptr.ai_socktype,
  215. ptr.ai_protocol,
  216. ('' if ptr.ai_canonname is NULL else
  217. (<bytes>ptr.ai_canonname).decode()),
  218. __convert_sockaddr_to_pyaddr(ptr.ai_addr)
  219. ))
  220. ptr = ptr.ai_next
  221. return result
  222. @staticmethod
  223. cdef int isinstance(object other):
  224. return type(other) is AddrInfo
  225. cdef class AddrInfoRequest(UVRequest):
  226. cdef:
  227. system.addrinfo hints
  228. object callback
  229. uv.uv_getaddrinfo_t _req_data
  230. def __cinit__(self, Loop loop,
  231. bytes host, bytes port,
  232. int family, int type, int proto, int flags,
  233. object callback):
  234. cdef:
  235. int err
  236. char *chost
  237. char *cport
  238. if host is None:
  239. chost = NULL
  240. else:
  241. chost = <char*>host
  242. if port is None:
  243. cport = NULL
  244. else:
  245. cport = <char*>port
  246. if cport is NULL and chost is NULL:
  247. self.on_done()
  248. msg = system.gai_strerror(socket_EAI_NONAME).decode('utf-8')
  249. ex = socket_gaierror(socket_EAI_NONAME, msg)
  250. callback(ex)
  251. return
  252. memset(&self.hints, 0, sizeof(system.addrinfo))
  253. self.hints.ai_flags = flags
  254. self.hints.ai_family = family
  255. self.hints.ai_socktype = type
  256. self.hints.ai_protocol = proto
  257. self.request = <uv.uv_req_t*> &self._req_data
  258. self.callback = callback
  259. self.request.data = <void*>self
  260. err = uv.uv_getaddrinfo(loop.uvloop,
  261. <uv.uv_getaddrinfo_t*>self.request,
  262. __on_addrinfo_resolved,
  263. chost,
  264. cport,
  265. &self.hints)
  266. if err < 0:
  267. self.on_done()
  268. callback(convert_error(err))
  269. cdef class NameInfoRequest(UVRequest):
  270. cdef:
  271. object callback
  272. uv.uv_getnameinfo_t _req_data
  273. def __cinit__(self, Loop loop, callback):
  274. self.request = <uv.uv_req_t*> &self._req_data
  275. self.callback = callback
  276. self.request.data = <void*>self
  277. cdef query(self, system.sockaddr *addr, int flags):
  278. cdef int err
  279. err = uv.uv_getnameinfo(self.loop.uvloop,
  280. <uv.uv_getnameinfo_t*>self.request,
  281. __on_nameinfo_resolved,
  282. addr,
  283. flags)
  284. if err < 0:
  285. self.on_done()
  286. self.callback(convert_error(err))
  287. cdef void __on_addrinfo_resolved(uv.uv_getaddrinfo_t *resolver,
  288. int status, system.addrinfo *res) with gil:
  289. if resolver.data is NULL:
  290. aio_logger.error(
  291. 'AddrInfoRequest callback called with NULL resolver.data')
  292. return
  293. cdef:
  294. AddrInfoRequest request = <AddrInfoRequest> resolver.data
  295. Loop loop = request.loop
  296. object callback = request.callback
  297. AddrInfo ai
  298. try:
  299. if status < 0:
  300. callback(convert_error(status))
  301. else:
  302. ai = AddrInfo()
  303. ai.set_data(res)
  304. callback(ai)
  305. except Exception as ex:
  306. loop._handle_exception(ex)
  307. finally:
  308. request.on_done()
  309. cdef void __on_nameinfo_resolved(uv.uv_getnameinfo_t* req,
  310. int status,
  311. const char* hostname,
  312. const char* service) with gil:
  313. cdef:
  314. NameInfoRequest request = <NameInfoRequest> req.data
  315. Loop loop = request.loop
  316. object callback = request.callback
  317. try:
  318. if status < 0:
  319. callback(convert_error(status))
  320. else:
  321. callback(((<bytes>hostname).decode(),
  322. (<bytes>service).decode()))
  323. except Exception as ex:
  324. loop._handle_exception(ex)
  325. finally:
  326. request.on_done()