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.
 
 
 
 

224 lines
7.0 KiB

  1. cdef __tcp_init_uv_handle(UVStream handle, Loop loop, unsigned int flags):
  2. cdef int err
  3. handle._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_tcp_t))
  4. if handle._handle is NULL:
  5. handle._abort_init()
  6. raise MemoryError()
  7. err = uv.uv_tcp_init_ex(handle._loop.uvloop,
  8. <uv.uv_tcp_t*>handle._handle,
  9. flags)
  10. if err < 0:
  11. handle._abort_init()
  12. raise convert_error(err)
  13. handle._finish_init()
  14. cdef __tcp_bind(UVStream handle, system.sockaddr* addr, unsigned int flags):
  15. cdef int err
  16. err = uv.uv_tcp_bind(<uv.uv_tcp_t *>handle._handle,
  17. addr, flags)
  18. if err < 0:
  19. exc = convert_error(err)
  20. raise exc
  21. cdef __tcp_open(UVStream handle, int sockfd):
  22. cdef int err
  23. err = uv.uv_tcp_open(<uv.uv_tcp_t *>handle._handle,
  24. <uv.uv_os_sock_t>sockfd)
  25. if err < 0:
  26. exc = convert_error(err)
  27. raise exc
  28. cdef __tcp_get_socket(UVSocketHandle handle):
  29. cdef:
  30. int buf_len = sizeof(system.sockaddr_storage)
  31. int fileno
  32. int err
  33. system.sockaddr_storage buf
  34. fileno = handle._fileno()
  35. err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>handle._handle,
  36. <system.sockaddr*>&buf,
  37. &buf_len)
  38. if err < 0:
  39. raise convert_error(err)
  40. return PseudoSocket(buf.ss_family, uv.SOCK_STREAM, 0, fileno)
  41. @cython.no_gc_clear
  42. cdef class TCPServer(UVStreamServer):
  43. @staticmethod
  44. cdef TCPServer new(Loop loop, object protocol_factory, Server server,
  45. unsigned int flags,
  46. object backlog,
  47. object ssl,
  48. object ssl_handshake_timeout,
  49. object ssl_shutdown_timeout):
  50. cdef TCPServer handle
  51. handle = TCPServer.__new__(TCPServer)
  52. handle._init(loop, protocol_factory, server, backlog,
  53. ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
  54. __tcp_init_uv_handle(<UVStream>handle, loop, flags)
  55. return handle
  56. cdef _new_socket(self):
  57. return __tcp_get_socket(<UVSocketHandle>self)
  58. cdef _open(self, int sockfd):
  59. self._ensure_alive()
  60. try:
  61. __tcp_open(<UVStream>self, sockfd)
  62. except Exception as exc:
  63. self._fatal_error(exc, True)
  64. else:
  65. self._mark_as_open()
  66. cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
  67. self._ensure_alive()
  68. try:
  69. __tcp_bind(<UVStream>self, addr, flags)
  70. except Exception as exc:
  71. self._fatal_error(exc, True)
  72. else:
  73. self._mark_as_open()
  74. cdef UVStream _make_new_transport(self, object protocol, object waiter):
  75. cdef TCPTransport tr
  76. tr = TCPTransport.new(self._loop, protocol, self._server, waiter)
  77. return <UVStream>tr
  78. @cython.no_gc_clear
  79. cdef class TCPTransport(UVStream):
  80. @staticmethod
  81. cdef TCPTransport new(Loop loop, object protocol, Server server,
  82. object waiter):
  83. cdef TCPTransport handle
  84. handle = TCPTransport.__new__(TCPTransport)
  85. handle._init(loop, protocol, server, waiter)
  86. __tcp_init_uv_handle(<UVStream>handle, loop, uv.AF_UNSPEC)
  87. handle.__peername_set = 0
  88. handle.__sockname_set = 0
  89. handle._set_nodelay()
  90. return handle
  91. cdef _set_nodelay(self):
  92. cdef int err
  93. self._ensure_alive()
  94. err = uv.uv_tcp_nodelay(<uv.uv_tcp_t*>self._handle, 1)
  95. if err < 0:
  96. raise convert_error(err)
  97. cdef _call_connection_made(self):
  98. # asyncio saves peername & sockname when transports are instantiated,
  99. # so that they're accessible even after the transport is closed.
  100. # We are doing the same thing here, except that we create Python
  101. # objects lazily, on request in get_extra_info()
  102. cdef:
  103. int err
  104. int buf_len
  105. buf_len = sizeof(system.sockaddr_storage)
  106. err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>self._handle,
  107. <system.sockaddr*>&self.__sockname,
  108. &buf_len)
  109. if err >= 0:
  110. # Ignore errors, this is an optional thing.
  111. # If something serious is going on, the transport
  112. # will crash later (in roughly the same way how
  113. # an asyncio transport would.)
  114. self.__sockname_set = 1
  115. buf_len = sizeof(system.sockaddr_storage)
  116. err = uv.uv_tcp_getpeername(<uv.uv_tcp_t*>self._handle,
  117. <system.sockaddr*>&self.__peername,
  118. &buf_len)
  119. if err >= 0:
  120. # Same as few lines above -- we don't really care
  121. # about error case here.
  122. self.__peername_set = 1
  123. UVBaseTransport._call_connection_made(self)
  124. def get_extra_info(self, name, default=None):
  125. if name == 'sockname':
  126. if self.__sockname_set:
  127. return __convert_sockaddr_to_pyaddr(
  128. <system.sockaddr*>&self.__sockname)
  129. elif name == 'peername':
  130. if self.__peername_set:
  131. return __convert_sockaddr_to_pyaddr(
  132. <system.sockaddr*>&self.__peername)
  133. return super().get_extra_info(name, default)
  134. cdef _new_socket(self):
  135. return __tcp_get_socket(<UVSocketHandle>self)
  136. cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
  137. self._ensure_alive()
  138. __tcp_bind(<UVStream>self, addr, flags)
  139. cdef _open(self, int sockfd):
  140. self._ensure_alive()
  141. __tcp_open(<UVStream>self, sockfd)
  142. cdef connect(self, system.sockaddr* addr):
  143. cdef _TCPConnectRequest req
  144. req = _TCPConnectRequest(self._loop, self)
  145. req.connect(addr)
  146. cdef class _TCPConnectRequest(UVRequest):
  147. cdef:
  148. TCPTransport transport
  149. uv.uv_connect_t _req_data
  150. def __cinit__(self, loop, transport):
  151. self.request = <uv.uv_req_t*>&self._req_data
  152. self.request.data = <void*>self
  153. self.transport = transport
  154. cdef connect(self, system.sockaddr* addr):
  155. cdef int err
  156. err = uv.uv_tcp_connect(<uv.uv_connect_t*>self.request,
  157. <uv.uv_tcp_t*>self.transport._handle,
  158. addr,
  159. __tcp_connect_callback)
  160. if err < 0:
  161. exc = convert_error(err)
  162. self.on_done()
  163. raise exc
  164. cdef void __tcp_connect_callback(uv.uv_connect_t* req, int status) with gil:
  165. cdef:
  166. _TCPConnectRequest wrapper
  167. TCPTransport transport
  168. wrapper = <_TCPConnectRequest> req.data
  169. transport = wrapper.transport
  170. if status < 0:
  171. exc = convert_error(status)
  172. else:
  173. exc = None
  174. try:
  175. transport._on_connect(exc)
  176. except BaseException as ex:
  177. wrapper.transport._fatal_error(ex, False)
  178. finally:
  179. wrapper.on_done()