Skip to content

Commit 17fe7ba

Browse files
committed
tcp: Cache peername & sockname in TCPTransport._call_connection_made
1 parent 31d4e1f commit 17fe7ba

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

tests/test_tcp.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,14 @@ async def test_client(addr):
362362
self.assertFalse(t._paused)
363363

364364
sock = t.get_extra_info('socket')
365-
self.assertTrue(isinstance(sock, socket.socket))
365+
sockname = sock.getsockname()
366+
peername = sock.getpeername()
366367

368+
self.assertTrue(isinstance(sock, socket.socket))
367369
self.assertEqual(t.get_extra_info('sockname'),
368-
sock.getsockname())
369-
370+
sockname)
370371
self.assertEqual(t.get_extra_info('peername'),
371-
sock.getpeername())
372+
peername)
372373

373374
t.write(b'OK') # We want server to fail.
374375

@@ -378,6 +379,13 @@ async def test_client(addr):
378379

379380
await fut
380381

382+
# Test that peername and sockname are available after
383+
# the transport is closed.
384+
self.assertEqual(t.get_extra_info('peername'),
385+
peername)
386+
self.assertEqual(t.get_extra_info('sockname'),
387+
sockname)
388+
381389
async def start_server():
382390
srv = await asyncio.start_server(
383391
handle_client,

tests/test_udp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def test_create_datagram_endpoint_sock(self):
112112
assert False, 'Can not create socket.'
113113

114114
with sock:
115-
f = self.loop.create_connection(
115+
f = self.loop.create_datagram_endpoint(
116116
lambda: MyDatagramProto(loop=self.loop), sock=sock)
117117
tr, pr = self.loop.run_until_complete(f)
118118
self.assertIsInstance(pr, MyDatagramProto)

uvloop/handles/tcp.pxd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ cdef class TCPServer(UVStreamServer):
88

99

1010
cdef class TCPTransport(UVStream):
11+
cdef:
12+
bint __peername_set
13+
bint __sockname_set
14+
system.sockaddr_storage __peername
15+
system.sockaddr_storage __sockname
16+
1117
cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
1218
cdef open(self, int sockfd)
1319
cdef connect(self, system.sockaddr* addr)

uvloop/handles/tcp.pyx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,53 @@ cdef class TCPTransport(UVStream):
102102
handle = TCPTransport.__new__(TCPTransport)
103103
handle._init(loop, protocol, server, waiter)
104104
__tcp_init_uv_handle(<UVStream>handle, loop)
105+
handle.__peername_set = 0
106+
handle.__sockname_set = 0
105107
return handle
106108

109+
cdef _call_connection_made(self):
110+
# asyncio saves peername & sockname when transports are instantiated,
111+
# so that they're accessible even after the transport is closed.
112+
# We are doing the same thing here, except that we create Python
113+
# objects lazily, on request in get_extra_info()
114+
115+
cdef:
116+
int err
117+
int buf_len
118+
119+
buf_len = sizeof(system.sockaddr_storage)
120+
err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>self._handle,
121+
<system.sockaddr*>&self.__sockname,
122+
&buf_len)
123+
if err >= 0:
124+
# Ignore errors, this is an optional thing.
125+
# If something serious is going on, the transport
126+
# will crash later (in roughly the same way how
127+
# an asyncio transport would.)
128+
self.__sockname_set = 1
129+
130+
buf_len = sizeof(system.sockaddr_storage)
131+
err = uv.uv_tcp_getpeername(<uv.uv_tcp_t*>self._handle,
132+
<system.sockaddr*>&self.__peername,
133+
&buf_len)
134+
if err >= 0:
135+
# Same as few lines above -- we don't really care
136+
# about error case here.
137+
self.__peername_set = 1
138+
139+
UVBaseTransport._call_connection_made(self)
140+
141+
def get_extra_info(self, name, default=None):
142+
if name == 'sockname':
143+
if self.__sockname_set:
144+
return __convert_sockaddr_to_pyaddr(
145+
<system.sockaddr*>&self.__sockname)
146+
elif name == 'peername':
147+
if self.__peername_set:
148+
return __convert_sockaddr_to_pyaddr(
149+
<system.sockaddr*>&self.__peername)
150+
return super().get_extra_info(name, default)
151+
107152
cdef _new_socket(self):
108153
return __tcp_get_socket(<UVSocketHandle>self)
109154

uvloop/includes/uv.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ cdef extern from "../vendor/libuv/include/uv.h" nogil:
328328

329329
int uv_tcp_getsockname(const uv_tcp_t* handle, system.sockaddr* name,
330330
int* namelen)
331+
int uv_tcp_getpeername(const uv_tcp_t* handle, system.sockaddr* name,
332+
int* namelen)
331333

332334
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
333335
const system.sockaddr* addr, uv_connect_cb cb)

0 commit comments

Comments
 (0)