Tachyon /Users/simon/.local/share/uv/python/cpython-3.15.0-macos-aarch64-none/lib/python3.15/asyncio/selector_events.py
103
Self Samples
245
Cumulative
19
Lines Hit
0.84%
% of Total
31
Max Self
62
Max Total
Intensity:
Cold Hot
Self Time
Total Time
Show All
Hot Only
Heat
Specialization
Line
Self
Total
Code
1
"""Event loop using a selector and related classes.
2
3
A selector is a "notify-when-ready" multiplexer. For a subclass which
4
also includes support for signal handling, see the unix_events sub-module.
5
"""
6
7
__all__ = 'BaseSelectorEventLoop',
8
9
import collections
10
import errno
11
import functools
12
import itertools
13
import os
14
import selectors
15
import socket
16
import warnings
17
import weakref
18
try:
19
import ssl
20
except ImportError: # pragma: no cover
21
ssl = None
22
23
from . import base_events
24
from . import constants
25
from . import events
26
from . import futures
27
from . import protocols
28
from . import sslproto
29
from . import transports
30
from . import trsock
31
from .log import logger
32
33
_HAS_SENDMSG = hasattr(socket.socket, 'sendmsg')
34
35
if _HAS_SENDMSG:
36
try:
37
SC_IOV_MAX = os.sysconf('SC_IOV_MAX')
38
except OSError:
39
# Fallback to send
40
_HAS_SENDMSG = False
41
42
def _test_selector_event(selector, fd, event):
43
# Test if the selector is monitoring 'event' events
44
# for the file descriptor 'fd'.
45
try:
46
key = selector.get_key(fd)
47
except KeyError:
48
return False
49
else:
50
return bool(key.events & event)
51
52
53
class BaseSelectorEventLoop(base_events.BaseEventLoop):
54
"""Selector event loop.
55
56
See events.EventLoop for API specification.
57
"""
58
59
def __init__(self, selector=None):
60
super().__init__()
61
62
if selector is None:
63
selector = selectors.DefaultSelector()
64
logger.debug('Using selector: %s', selector.__class__.__name__)
65
self._selector = selector
66
self._make_self_pipe()
67
self._transports = weakref.WeakValueDictionary()
68
69
def _make_socket_transport(self, sock, protocol, waiter=None, *,
70
extra=None, server=None, context=None):
71
self._ensure_fd_no_transport(sock)
72
4
5
return _SelectorSocketTransport(self, sock, protocol, waiter,
73
extra, server, context=context)
74
75
def _make_ssl_transport(
76
self, rawsock, protocol, sslcontext, waiter=None,
77
*, server_side=False, server_hostname=None,
78
extra=None, server=None,
79
ssl_handshake_timeout=constants.SSL_HANDSHAKE_TIMEOUT,
80
ssl_shutdown_timeout=constants.SSL_SHUTDOWN_TIMEOUT,
81
context=None,
82
):
83
self._ensure_fd_no_transport(rawsock)
84
ssl_protocol = sslproto.SSLProtocol(
85
self, protocol, sslcontext, waiter,
86
server_side, server_hostname,
87
ssl_handshake_timeout=ssl_handshake_timeout,
88
ssl_shutdown_timeout=ssl_shutdown_timeout,
89
)
90
_SelectorSocketTransport(self, rawsock, ssl_protocol,
91
extra=extra, server=server, context=context)
92
return ssl_protocol._app_transport
93
94
def _make_datagram_transport(self, sock, protocol,
95
address=None, waiter=None, extra=None):
96
self._ensure_fd_no_transport(sock)
97
return _SelectorDatagramTransport(self, sock, protocol,
98
address, waiter, extra)
99
100
def close(self):
101
if self.is_running():
102
raise RuntimeError("Cannot close a running event loop")
103
if self.is_closed():
104
return
105
self._close_self_pipe()
106
super().close()
107
if self._selector is not None:
108
self._selector.close()
109
self._selector = None
110
111
def _close_self_pipe(self):
112
self._remove_reader(self._ssock.fileno())
113
self._ssock.close()
114
self._ssock = None
115
self._csock.close()
116
self._csock = None
117
self._internal_fds -= 1
118
119
def _make_self_pipe(self):
120
# A self-socket, really. :-)
121
self._ssock, self._csock = socket.socketpair()
122
self._ssock.setblocking(False)
123
self._csock.setblocking(False)
124
self._internal_fds += 1
125
self._add_reader(self._ssock.fileno(), self._read_from_self)
126
127
def _process_self_data(self, data):
128
pass
129
130
def _read_from_self(self):
131
while True:
132
try:
133
1
1
data = self._ssock.recv(4096)
134
if not data:
135
break
136
self._process_self_data(data)
137
except InterruptedError:
138
continue
139
except BlockingIOError:
140
1
1
break
141
142
def _write_to_self(self):
143
# This may be called from a different thread, possibly after
144
# _close_self_pipe() has been called or even while it is
145
# running. Guard for self._csock being None or closed. When
146
# a socket is closed, send() raises OSError (with errno set to
147
# EBADF, but let's not rely on the exact error code).
148
csock = self._csock
149
if csock is None:
150
return
151
152
try:
153
csock.send(b'\0')
154
except OSError:
155
if self._debug:
156
logger.debug("Fail to write a null byte into the "
157
"self-pipe socket",
158
exc_info=True)
159
160
def _start_serving(self, protocol_factory, sock,
161
sslcontext=None, server=None, backlog=100,
162
ssl_handshake_timeout=constants.SSL_HANDSHAKE_TIMEOUT,
163
ssl_shutdown_timeout=constants.SSL_SHUTDOWN_TIMEOUT, context=None):
164
self._add_reader(sock.fileno(), self._accept_connection,
165
protocol_factory, sock, sslcontext, server, backlog,
166
ssl_handshake_timeout, ssl_shutdown_timeout, context)
167
168
def _accept_connection(
169
self, protocol_factory, sock,
170
sslcontext=None, server=None, backlog=100,
171
ssl_handshake_timeout=constants.SSL_HANDSHAKE_TIMEOUT,
172
ssl_shutdown_timeout=constants.SSL_SHUTDOWN_TIMEOUT, context=None):
173
# This method is only called once for each event loop tick where the
174
# listening socket has triggered an EVENT_READ. There may be multiple
175
# connections waiting for an .accept() so it is called in a loop.
176
# See https://bugs.python.org/issue27906 for more details.
177
for _ in range(backlog + 1):
178
try:
179
3
21
conn, addr = sock.accept()
180
if self._debug:
181
logger.debug("%r got a new connection from %r: %r",
182
server, addr, conn)
183
conn.setblocking(False)
184
except ConnectionAbortedError:
185
# Discard connections that were aborted before accept().
186
continue
187
except (BlockingIOError, InterruptedError):
188
# Early exit because of a signal or
189
# the socket accept buffer is empty.
190
return
191
except OSError as exc:
192
# There's nowhere to send the error, so just log it.
193
if exc.errno in (errno.EMFILE, errno.ENFILE,
194
errno.ENOBUFS, errno.ENOMEM):
195
# Some platforms (e.g. Linux keep reporting the FD as
196
# ready, so we remove the read handler temporarily.
197
# We'll try again in a while.
198
self.call_exception_handler({
199
'message': 'socket.accept() out of system resource',
200
'exception': exc,
201
'socket': trsock.TransportSocket(sock),
202
})
203
self._remove_reader(sock.fileno())
204
self.call_later(constants.ACCEPT_RETRY_DELAY,
205
self._start_serving,
206
protocol_factory, sock, sslcontext, server,
207
backlog, ssl_handshake_timeout,
208
ssl_shutdown_timeout, context)
209
else:
210
raise # The event loop will catch, log and ignore it.
211
else:
212
extra = {'peername': addr}
213
conn_context = context.copy() if context is not None else None
214
accept = self._accept_connection2(
215
protocol_factory, conn, extra, sslcontext, server,
216
ssl_handshake_timeout, ssl_shutdown_timeout, context=conn_context)
217
1
self.create_task(accept, context=conn_context)
218
219
async def _accept_connection2(
220
self, protocol_factory, conn, extra,
221
sslcontext=None, server=None,
222
ssl_handshake_timeout=constants.SSL_HANDSHAKE_TIMEOUT,
223
ssl_shutdown_timeout=constants.SSL_SHUTDOWN_TIMEOUT, context=None):
224
protocol = None
225
transport = None
226
try:
227
protocol = protocol_factory()
228
waiter = self.create_future()
229
if sslcontext:
230
transport = self._make_ssl_transport(
231
conn, protocol, sslcontext, waiter=waiter,
232
server_side=True, extra=extra, server=server,
233
ssl_handshake_timeout=ssl_handshake_timeout,
234
ssl_shutdown_timeout=ssl_shutdown_timeout,
235
context=context)
236
else:
237
1
9
transport = self._make_socket_transport(
238
conn, protocol, waiter=waiter, extra=extra,
239
server=server, context=context)
240
241
try:
242
await waiter
243
except BaseException:
244
transport.close()
245
# gh-109534: When an exception is raised by the SSLProtocol object the
246
# exception set in this future can keep the protocol object alive and
247
# cause a reference cycle.
248
waiter = None
249
raise
250
# It's now up to the protocol to handle the connection.
251
252
except (SystemExit, KeyboardInterrupt):
253
raise
254
except BaseException as exc:
255
if self._debug:
256
context = {
257
'message':
258
'Error on transport creation for incoming connection',
259
'exception': exc,
260
}
261
if protocol is not None:
262
context['protocol'] = protocol
263
if transport is not None:
264
context['transport'] = transport
265
self.call_exception_handler(context)
266
267
def _ensure_fd_no_transport(self, fd):
268
fileno = fd
269
if not isinstance(fileno, int):
270
try:
271
fileno = int(fileno.fileno())
272
except (AttributeError, TypeError, ValueError):
273
# This code matches selectors._fileobj_to_fd function.
274
raise ValueError(f"Invalid file object: {fd!r}") from None
275
transport = self._transports.get(fileno)
276
if transport and not transport.is_closing():
277
raise RuntimeError(
278
f'File descriptor {fd!r} is used by transport '
279
f'{transport!r}')
280
281
def _add_reader(self, fd, callback, *args, context=None):
282
self._check_closed()
283
handle = events.Handle(callback, args, self, context=context)
284
key = self._selector.get_map().get(fd)
285
if key is None:
286
self._selector.register(fd, selectors.EVENT_READ,
287
(handle, None))
288
else:
289
mask, (reader, writer) = key.events, key.data
290
self._selector.modify(fd, mask | selectors.EVENT_READ,
291
(handle, writer))
292
if reader is not None:
293
reader.cancel()
294
return handle
295
296
def _remove_reader(self, fd):
297
if self.is_closed():
298
return False
299
key = self._selector.get_map().get(fd)
300
if key is None:
301
return False
302
mask, (reader, writer) = key.events, key.data
303
mask &= ~selectors.EVENT_READ
304
if not mask:
305
self._selector.unregister(fd)
306
else:
307
self._selector.modify(fd, mask, (None, writer))
308
309
if reader is not None:
310
reader.cancel()
311
return True
312
else:
313
return False
314
315
def _add_writer(self, fd, callback, *args, context=None):
316
self._check_closed()
317
handle = events.Handle(callback, args, self, context=context)
318
key = self._selector.get_map().get(fd)
319
if key is None:
320
self._selector.register(fd, selectors.EVENT_WRITE,
321
(None, handle))
322
else:
323
mask, (reader, writer) = key.events, key.data
324
self._selector.modify(fd, mask | selectors.EVENT_WRITE,
325
(reader, handle))
326
if writer is not None:
327
writer.cancel()
328
return handle
329
330
def _remove_writer(self, fd):
331
"""Remove a writer callback."""
332
if self.is_closed():
333
return False
334
key = self._selector.get_map().get(fd)
335
if key is None:
336
return False
337
mask, (reader, writer) = key.events, key.data
338
# Remove both writer and connector.
339
mask &= ~selectors.EVENT_WRITE
340
if not mask:
341
self._selector.unregister(fd)
342
else:
343
self._selector.modify(fd, mask, (reader, None))
344
345
if writer is not None:
346
writer.cancel()
347
return True
348
else:
349
return False
350
351
def add_reader(self, fd, callback, *args):
352
"""Add a reader callback."""
353
self._ensure_fd_no_transport(fd)
354
self._add_reader(fd, callback, *args)
355
356
def remove_reader(self, fd):
357
"""Remove a reader callback."""
358
self._ensure_fd_no_transport(fd)
359
return self._remove_reader(fd)
360
361
def add_writer(self, fd, callback, *args):
362
"""Add a writer callback.."""
363
self._ensure_fd_no_transport(fd)
364
self._add_writer(fd, callback, *args)
365
366
def remove_writer(self, fd):
367
"""Remove a writer callback."""
368
self._ensure_fd_no_transport(fd)
369
return self._remove_writer(fd)
370
371
async def sock_recv(self, sock, n):
372
"""Receive data from the socket.
373
374
The return value is a bytes object representing the data received.
375
The maximum amount of data to be received at once is specified by
376
nbytes.
377
"""
378
base_events._check_ssl_socket(sock)
379
if self._debug and sock.gettimeout() != 0:
380
raise ValueError("the socket must be non-blocking")
381
try:
382
return sock.recv(n)
383
except (BlockingIOError, InterruptedError):
384
pass
385
fut = self.create_future()
386
fd = sock.fileno()
387
self._ensure_fd_no_transport(fd)
388
handle = self._add_reader(fd, self._sock_recv, fut, sock, n)
389
fut.add_done_callback(
390
functools.partial(self._sock_read_done, fd, handle=handle))
391
return await fut
392
393
def _sock_read_done(self, fd, fut, handle=None):
394
if handle is None or not handle.cancelled():
395
self.remove_reader(fd)
396
397
def _sock_recv(self, fut, sock, n):
398
# _sock_recv() can add itself as an I/O callback if the operation can't
399
# be done immediately. Don't use it directly, call sock_recv().
400
if fut.done():
401
return
402
try:
403
data = sock.recv(n)
404
except (BlockingIOError, InterruptedError):
405
return # try again next time
406
except (SystemExit, KeyboardInterrupt):
407
raise
408
except BaseException as exc:
409
fut.set_exception(exc)
410
else:
411
fut.set_result(data)
412
413
async def sock_recv_into(self, sock, buf):
414
"""Receive data from the socket.
415
416
The received data is written into *buf* (a writable buffer).
417
The return value is the number of bytes written.
418
"""
419
base_events._check_ssl_socket(sock)
420
if self._debug and sock.gettimeout() != 0:
421
raise ValueError("the socket must be non-blocking")
422
try:
423
return sock.recv_into(buf)
424
except (BlockingIOError, InterruptedError):
425
pass
426
fut = self.create_future()
427
fd = sock.fileno()
428
self._ensure_fd_no_transport(fd)
429
handle = self._add_reader(fd, self._sock_recv_into, fut, sock, buf)
430
fut.add_done_callback(
431
functools.partial(self._sock_read_done, fd, handle=handle))
432
return await fut
433
434
def _sock_recv_into(self, fut, sock, buf):
435
# _sock_recv_into() can add itself as an I/O callback if the operation
436
# can't be done immediately. Don't use it directly, call
437
# sock_recv_into().
438
if fut.done():
439
return
440
try:
441
nbytes = sock.recv_into(buf)
442
except (BlockingIOError, InterruptedError):
443
return # try again next time
444
except (SystemExit, KeyboardInterrupt):
445
raise
446
except BaseException as exc:
447
fut.set_exception(exc)
448
else:
449
fut.set_result(nbytes)
450
451
async def sock_recvfrom(self, sock, bufsize):
452
"""Receive a datagram from a datagram socket.
453
454
The return value is a tuple of (bytes, address) representing the
455
datagram received and the address it came from.
456
The maximum amount of data to be received at once is specified by
457
nbytes.
458
"""
459
base_events._check_ssl_socket(sock)
460
if self._debug and sock.gettimeout() != 0:
461
raise ValueError("the socket must be non-blocking")
462
try:
463
return sock.recvfrom(bufsize)
464
except (BlockingIOError, InterruptedError):
465
pass
466
fut = self.create_future()
467
fd = sock.fileno()
468
self._ensure_fd_no_transport(fd)
469
handle = self._add_reader(fd, self._sock_recvfrom, fut, sock, bufsize)
470
fut.add_done_callback(
471
functools.partial(self._sock_read_done, fd, handle=handle))
472
return await fut
473
474
def _sock_recvfrom(self, fut, sock, bufsize):
475
# _sock_recvfrom() can add itself as an I/O callback if the operation
476
# can't be done immediately. Don't use it directly, call
477
# sock_recvfrom().
478
if fut.done():
479
return
480
try:
481
result = sock.recvfrom(bufsize)
482
except (BlockingIOError, InterruptedError):
483
return # try again next time
484
except (SystemExit, KeyboardInterrupt):
485
raise
486
except BaseException as exc:
487
fut.set_exception(exc)
488
else:
489
fut.set_result(result)
490
491
async def sock_recvfrom_into(self, sock, buf, nbytes=0):
492
"""Receive data from the socket.
493
494
The received data is written into *buf* (a writable buffer).
495
The return value is a tuple of (number of bytes written, address).
496
"""
497
base_events._check_ssl_socket(sock)
498
if self._debug and sock.gettimeout() != 0:
499
raise ValueError("the socket must be non-blocking")
500
if not nbytes:
501
nbytes = len(buf)
502
503
try:
504
return sock.recvfrom_into(buf, nbytes)
505
except (BlockingIOError, InterruptedError):
506
pass
507
fut = self.create_future()
508
fd = sock.fileno()
509
self._ensure_fd_no_transport(fd)
510
handle = self._add_reader(fd, self._sock_recvfrom_into, fut, sock, buf,
511
nbytes)
512
fut.add_done_callback(
513
functools.partial(self._sock_read_done, fd, handle=handle))
514
return await fut
515
516
def _sock_recvfrom_into(self, fut, sock, buf, bufsize):
517
# _sock_recv_into() can add itself as an I/O callback if the operation
518
# can't be done immediately. Don't use it directly, call
519
# sock_recv_into().
520
if fut.done():
521
return
522
try:
523
result = sock.recvfrom_into(buf, bufsize)
524
except (BlockingIOError, InterruptedError):
525
return # try again next time
526
except (SystemExit, KeyboardInterrupt):
527
raise
528
except BaseException as exc:
529
fut.set_exception(exc)
530
else:
531
fut.set_result(result)
532
533
async def sock_sendall(self, sock, data):
534
"""Send data to the socket.
535
536
The socket must be connected to a remote socket. This method
537
continues to send data from data until either all data has been
538
sent or an error occurs. None is returned on success. On error,
539
an exception is raised, and there is no way to determine how much
540
data, if any, was successfully processed by the receiving end of
541
the connection.
542
"""
543
base_events._check_ssl_socket(sock)
544
if self._debug and sock.gettimeout() != 0:
545
raise ValueError("the socket must be non-blocking")
546
try:
547
n = sock.send(data)
548
except (BlockingIOError, InterruptedError):
549
n = 0
550
551
if n == len(data):
552
# all data sent
553
return
554
555
fut = self.create_future()
556
fd = sock.fileno()
557
self._ensure_fd_no_transport(fd)
558
# use a trick with a list in closure to store a mutable state
559
handle = self._add_writer(fd, self._sock_sendall, fut, sock,
560
memoryview(data), [n])
561
fut.add_done_callback(
562
functools.partial(self._sock_write_done, fd, handle=handle))
563
return await fut
564
565
def _sock_sendall(self, fut, sock, view, pos):
566
if fut.done():
567
# Future cancellation can be scheduled on previous loop iteration
568
return
569
start = pos[0]
570
try:
571
n = sock.send(view[start:])
572
except (BlockingIOError, InterruptedError):
573
return
574
except (SystemExit, KeyboardInterrupt):
575
raise
576
except BaseException as exc:
577
fut.set_exception(exc)
578
return
579
580
start += n
581
582
if start == len(view):
583
fut.set_result(None)
584
else:
585
pos[0] = start
586
587
async def sock_sendto(self, sock, data, address):
588
"""Send a datagram from sock to address.
589
590
The socket does not have to be connected. This method sends the
591
whole datagram in a single call. Return the number of bytes sent.
592
"""
593
base_events._check_ssl_socket(sock)
594
if self._debug and sock.gettimeout() != 0:
595
raise ValueError("the socket must be non-blocking")
596
try:
597
return sock.sendto(data, address)
598
except (BlockingIOError, InterruptedError):
599
pass
600
601
fut = self.create_future()
602
fd = sock.fileno()
603
self._ensure_fd_no_transport(fd)
604
# use a trick with a list in closure to store a mutable state
605
handle = self._add_writer(fd, self._sock_sendto, fut, sock, data,
606
address)
607
fut.add_done_callback(
608
functools.partial(self._sock_write_done, fd, handle=handle))
609
return await fut
610
611
def _sock_sendto(self, fut, sock, data, address):
612
if fut.done():
613
# Future cancellation can be scheduled on previous loop iteration
614
return
615
try:
616
n = sock.sendto(data, 0, address)
617
except (BlockingIOError, InterruptedError):
618
return
619
except (SystemExit, KeyboardInterrupt):
620
raise
621
except BaseException as exc:
622
fut.set_exception(exc)
623
else:
624
fut.set_result(n)
625
626
async def sock_connect(self, sock, address):
627
"""Connect to a remote socket at address.
628
629
This method is a coroutine.
630
"""
631
base_events._check_ssl_socket(sock)
632
if self._debug and sock.gettimeout() != 0:
633
raise ValueError("the socket must be non-blocking")
634
635
if sock.family == socket.AF_INET or (
636
base_events._HAS_IPv6 and sock.family == socket.AF_INET6):
637
resolved = await self._ensure_resolved(
638
address, family=sock.family, type=sock.type, proto=sock.proto,
639
loop=self,
640
)
641
_, _, _, _, address = resolved[0]
642
643
fut = self.create_future()
644
self._sock_connect(fut, sock, address)
645
try:
646
return await fut
647
finally:
648
# Needed to break cycles when an exception occurs.
649
fut = None
650
651
def _sock_connect(self, fut, sock, address):
652
fd = sock.fileno()
653
try:
654
sock.connect(address)
655
except (BlockingIOError, InterruptedError):
656
# Issue #23618: When the C function connect() fails with EINTR, the
657
# connection runs in background. We have to wait until the socket
658
# becomes writable to be notified when the connection succeed or
659
# fails.
660
self._ensure_fd_no_transport(fd)
661
handle = self._add_writer(
662
fd, self._sock_connect_cb, fut, sock, address)
663
fut.add_done_callback(
664
functools.partial(self._sock_write_done, fd, handle=handle))
665
except (SystemExit, KeyboardInterrupt):
666
raise
667
except BaseException as exc:
668
fut.set_exception(exc)
669
else:
670
fut.set_result(None)
671
finally:
672
fut = None
673
674
def _sock_write_done(self, fd, fut, handle=None):
675
if handle is None or not handle.cancelled():
676
self.remove_writer(fd)
677
678
def _sock_connect_cb(self, fut, sock, address):
679
if fut.done():
680
return
681
682
try:
683
err = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
684
if err != 0:
685
# Jump to any except clause below.
686
raise OSError(err, f'Connect call failed {address}')
687
except (BlockingIOError, InterruptedError):
688
# socket is still registered, the callback will be retried later
689
pass
690
except (SystemExit, KeyboardInterrupt):
691
raise
692
except BaseException as exc:
693
fut.set_exception(exc)
694
else:
695
fut.set_result(None)
696
finally:
697
fut = None
698
699
async def sock_accept(self, sock):
700
"""Accept a connection.
701
702
The socket must be bound to an address and listening for
703
connections. The return value is a pair (conn, address) where
704
conn is a new socket object usable to send and receive data on the
705
connection, and address is the address bound to the socket on the
706
other end of the connection.
707
"""
708
base_events._check_ssl_socket(sock)
709
if self._debug and sock.gettimeout() != 0:
710
raise ValueError("the socket must be non-blocking")
711
fut = self.create_future()
712
self._sock_accept(fut, sock)
713
return await fut
714
715
def _sock_accept(self, fut, sock):
716
# gh-153761: _sock_accept must not scheduled with already cancelled future
717
if fut.done():
718
return
719
fd = sock.fileno()
720
try:
721
conn, address = sock.accept()
722
conn.setblocking(False)
723
except (BlockingIOError, InterruptedError):
724
self._ensure_fd_no_transport(fd)
725
handle = self._add_reader(fd, self._sock_accept, fut, sock)
726
fut.add_done_callback(
727
functools.partial(self._sock_read_done, fd, handle=handle))
728
except (SystemExit, KeyboardInterrupt):
729
raise
730
except BaseException as exc:
731
fut.set_exception(exc)
732
else:
733
fut.set_result((conn, address))
734
735
async def _sendfile_native(self, transp, file, offset, count):
736
del self._transports[transp._sock_fd]
737
resume_reading = transp.is_reading()
738
transp.pause_reading()
739
await transp._make_empty_waiter()
740
try:
741
return await self.sock_sendfile(transp._sock, file, offset, count,
742
fallback=False)
743
finally:
744
transp._reset_empty_waiter()
745
if resume_reading:
746
transp.resume_reading()
747
self._transports[transp._sock_fd] = transp
748
749
def _process_events(self, event_list):
750
3
3
for key, mask in event_list:
751
2
2
fileobj, (reader, writer) = key.fileobj, key.data
752
if mask & selectors.EVENT_READ and reader is not None:
753
if reader._cancelled:
754
self._remove_reader(fileobj)
755
else:
756
self._add_callback(reader)
757
if mask & selectors.EVENT_WRITE and writer is not None:
758
if writer._cancelled:
759
self._remove_writer(fileobj)
760
else:
761
self._add_callback(writer)
762
763
def _stop_serving(self, sock):
764
self._remove_reader(sock.fileno())
765
sock.close()
766
767
768
class _SelectorTransport(transports._FlowControlMixin,
769
transports.Transport):
770
771
max_size = 256 * 1024 # Buffer size passed to recv().
772
773
# Attribute used in the destructor: it must be set even if the constructor
774
# is not called (see _SelectorSslTransport which may start by raising an
775
# exception)
776
_sock = None
777
778
def __init__(self, loop, sock, protocol, extra=None, server=None, context=None):
779
super().__init__(extra, loop)
780
self._extra['socket'] = trsock.TransportSocket(sock)
781
try:
782
self._extra['sockname'] = sock.getsockname()
783
except OSError:
784
self._extra['sockname'] = None
785
if 'peername' not in self._extra:
786
try:
787
self._extra['peername'] = sock.getpeername()
788
except socket.error:
789
self._extra['peername'] = None
790
self._sock = sock
791
self._sock_fd = sock.fileno()
792
self._context = context
793
self._protocol_connected = False
794
self.set_protocol(protocol)
795
796
self._server = server
797
self._buffer = collections.deque()
798
self._buffer_size = 0
799
self._conn_lost = 0 # Set when call to connection_lost scheduled.
800
self._closing = False # Set when close() called.
801
self._paused = False # Set when pause_reading() called
802
803
if self._server is not None:
804
self._server._attach(self)
805
loop._transports[self._sock_fd] = self
806
807
def __repr__(self):
808
info = [self.__class__.__name__]
809
if self._sock is None:
810
info.append('closed')
811
elif self._closing:
812
info.append('closing')
813
info.append(f'fd={self._sock_fd}')
814
# test if the transport was closed
815
if self._loop is not None and not self._loop.is_closed():
816
polling = _test_selector_event(self._loop._selector,
817
self._sock_fd, selectors.EVENT_READ)
818
if polling:
819
info.append('read=polling')
820
else:
821
info.append('read=idle')
822
823
polling = _test_selector_event(self._loop._selector,
824
self._sock_fd,
825
selectors.EVENT_WRITE)
826
if polling:
827
state = 'polling'
828
else:
829
state = 'idle'
830
831
bufsize = self.get_write_buffer_size()
832
info.append(f'write=<{state}, bufsize={bufsize}>')
833
return '<{}>'.format(' '.join(info))
834
835
def abort(self):
836
self._force_close(None)
837
838
def set_protocol(self, protocol):
839
self._protocol = protocol
840
self._protocol_connected = True
841
842
def get_protocol(self):
843
return self._protocol
844
845
def is_closing(self):
846
return self._closing
847
848
def is_reading(self):
849
return not self.is_closing() and not self._paused
850
851
def pause_reading(self):
852
if not self.is_reading():
853
return
854
self._paused = True
855
self._loop._remove_reader(self._sock_fd)
856
if self._loop.get_debug():
857
logger.debug("%r pauses reading", self)
858
859
def resume_reading(self):
860
if self._closing or not self._paused:
861
return
862
self._paused = False
863
self._add_reader(self._sock_fd, self._read_ready)
864
if self._loop.get_debug():
865
logger.debug("%r resumes reading", self)
866
867
def close(self):
868
if self._closing:
869
return
870
self._closing = True
871
self._loop._remove_reader(self._sock_fd)
872
if not self._buffer:
873
self._conn_lost += 1
874
self._loop._remove_writer(self._sock_fd)
875
self._call_soon(self._call_connection_lost, None)
876
877
def __del__(self, _warn=warnings.warn):
878
if self._sock is not None:
879
_warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
880
self._sock.close()
881
if self._server is not None:
882
self._server._detach(self)
883
884
def _fatal_error(self, exc, message='Fatal error on transport'):
885
# Should be called from exception handler only.
886
if isinstance(exc, OSError):
887
if self._loop.get_debug():
888
logger.debug("%r: %s", self, message, exc_info=True)
889
else:
890
self._loop.call_exception_handler({
891
'message': message,
892
'exception': exc,
893
'transport': self,
894
'protocol': self._protocol,
895
})
896
self._force_close(exc)
897
898
def _force_close(self, exc):
899
if self._conn_lost:
900
return
901
if self._buffer:
902
self._buffer.clear()
903
self._buffer_size = 0
904
self._loop._remove_writer(self._sock_fd)
905
if not self._closing:
906
self._closing = True
907
self._loop._remove_reader(self._sock_fd)
908
self._conn_lost += 1
909
self._call_soon(self._call_connection_lost, exc)
910
911
def _call_connection_lost(self, exc):
912
try:
913
if self._protocol_connected:
914
self._protocol.connection_lost(exc)
915
finally:
916
2
11
self._sock.close()
917
self._sock = None
918
self._protocol = None
919
self._loop = None
920
server = self._server
921
if server is not None:
922
server._detach(self)
923
self._server = None
924
925
def get_write_buffer_size(self):
926
return self._buffer_size
927
928
def _add_reader(self, fd, callback, *args):
929
if not self.is_reading():
930
return
931
self._loop._add_reader(fd, callback, *args, context=self._context)
932
933
def _add_writer(self, fd, callback, *args):
934
self._loop._add_writer(fd, callback, *args, context=self._context)
935
936
def _call_soon(self, callback, *args):
937
self._loop.call_soon(callback, *args, context=self._context)
938
939
class _SelectorSocketTransport(_SelectorTransport):
940
941
_start_tls_compatible = True
942
_sendfile_compatible = constants._SendfileMode.TRY_NATIVE
943
944
def __init__(self, loop, sock, protocol, waiter=None,
945
extra=None, server=None, context=None):
946
self._read_ready_cb = None
947
1
1
super().__init__(loop, sock, protocol, extra, server, context)
948
self._eof = False
949
self._empty_waiter = None
950
if _HAS_SENDMSG:
951
self._write_ready = self._write_sendmsg
952
else:
953
self._write_ready = self._write_send
954
# Disable the Nagle algorithm -- small writes will be
955
# sent without waiting for the TCP ACK. This generally
956
# decreases the latency (in some cases significantly.)
957
base_events._set_nodelay(self._sock)
958
959
self._call_soon(self._protocol.connection_made, self)
960
# only start reading when connection_made() has been called
961
self._call_soon(self._add_reader, self._sock_fd, self._read_ready)
962
if waiter is not None:
963
# only wake up the waiter when connection_made() has been called
964
self._call_soon(futures._set_result_unless_cancelled, waiter, None)
965
966
def set_protocol(self, protocol):
967
if isinstance(protocol, protocols.BufferedProtocol):
968
self._read_ready_cb = self._read_ready__get_buffer
969
else:
970
self._read_ready_cb = self._read_ready__data_received
971
972
super().set_protocol(protocol)
973
974
def _read_ready(self):
975
2
62
self._read_ready_cb()
976
977
def _read_ready__get_buffer(self):
978
if self._conn_lost:
979
return
980
981
try:
982
buf = self._protocol.get_buffer(-1)
983
if not len(buf):
984
raise RuntimeError('get_buffer() returned an empty buffer')
985
except (SystemExit, KeyboardInterrupt):
986
raise
987
except BaseException as exc:
988
self._fatal_error(
989
exc, 'Fatal error: protocol.get_buffer() call failed.')
990
return
991
992
try:
993
nbytes = self._sock.recv_into(buf)
994
except (BlockingIOError, InterruptedError):
995
return
996
except (SystemExit, KeyboardInterrupt):
997
raise
998
except BaseException as exc:
999
self._fatal_error(exc, 'Fatal read error on socket transport')
1000
return
1001
1002
if not nbytes:
1003
self._read_ready__on_eof()
1004
return
1005
1006
try:
1007
self._protocol.buffer_updated(nbytes)
1008
except (SystemExit, KeyboardInterrupt):
1009
raise
1010
except BaseException as exc:
1011
self._fatal_error(
1012
exc, 'Fatal error: protocol.buffer_updated() call failed.')
1013
1014
def _read_ready__data_received(self):
1015
if self._conn_lost:
1016
return
1017
try:
1018
18
20
data = self._sock.recv(self.max_size)
1019
except (BlockingIOError, InterruptedError):
1020
return
1021
except (SystemExit, KeyboardInterrupt):
1022
raise
1023
except BaseException as exc:
1024
self._fatal_error(exc, 'Fatal read error on socket transport')
1025
return
1026
1027
if not data:
1028
self._read_ready__on_eof()
1029
return
1030
1031
try:
1032
8
40
self._protocol.data_received(data)
1033
except (SystemExit, KeyboardInterrupt):
1034
raise
1035
except BaseException as exc:
1036
self._fatal_error(
1037
exc, 'Fatal error: protocol.data_received() call failed.')
1038
1039
def _read_ready__on_eof(self):
1040
if self._loop.get_debug():
1041
logger.debug("%r received EOF", self)
1042
1043
try:
1044
keep_open = self._protocol.eof_received()
1045
except (SystemExit, KeyboardInterrupt):
1046
raise
1047
except BaseException as exc:
1048
self._fatal_error(
1049
exc, 'Fatal error: protocol.eof_received() call failed.')
1050
return
1051
1052
if keep_open:
1053
# We're keeping the connection open so the
1054
# protocol can write more, but we still can't
1055
# receive more, so remove the reader callback.
1056
self._loop._remove_reader(self._sock_fd)
1057
else:
1058
self.close()
1059
1060
def write(self, data):
1061
if not isinstance(data, (bytes, bytearray, memoryview)):
1062
raise TypeError(f'data argument must be a bytes, bytearray, or memoryview '
1063
f'object, not {type(data).__name__!r}')
1064
if self._eof:
1065
raise RuntimeError('Cannot call write() after write_eof()')
1066
if self._empty_waiter is not None:
1067
raise RuntimeError('unable to write; sendfile is in progress')
1068
if not data:
1069
return
1070
1071
if self._conn_lost:
1072
if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
1073
logger.warning('socket.send() raised exception.')
1074
self._conn_lost += 1
1075
return
1076
1077
if not self._buffer:
1078
# Optimization: try to send now.
1079
try:
1080
31
31
n = self._sock.send(data)
1081
except (BlockingIOError, InterruptedError):
1082
pass
1083
except (SystemExit, KeyboardInterrupt):
1084
raise
1085
except BaseException as exc:
1086
self._fatal_error(exc, 'Fatal write error on socket transport')
1087
return
1088
else:
1089
1
1
data = memoryview(data)[n:]
1090
if not data:
1091
return
1092
# Not all was written; register write handler.
1093
self._add_writer(self._sock_fd, self._write_ready)
1094
1095
# Add it to the buffer.
1096
self._buffer.append(data)
1097
self._buffer_size += len(data)
1098
self._maybe_pause_protocol()
1099
1100
def _get_sendmsg_buffer(self):
1101
return itertools.islice(self._buffer, SC_IOV_MAX)
1102
1103
def _write_sendmsg(self):
1104
assert self._buffer, 'Data should not be empty'
1105
if self._conn_lost:
1106
return
1107
try:
1108
22
22
nbytes = self._sock.sendmsg(self._get_sendmsg_buffer())
1109
1
1
self._adjust_leftover_buffer(nbytes)
1110
except (BlockingIOError, InterruptedError):
1111
pass
1112
except (SystemExit, KeyboardInterrupt):
1113
raise
1114
except BaseException as exc:
1115
self._loop._remove_writer(self._sock_fd)
1116
self._buffer.clear()
1117
self._buffer_size = 0
1118
self._fatal_error(exc, 'Fatal write error on socket transport')
1119
if self._empty_waiter is not None:
1120
self._empty_waiter.set_exception(exc)
1121
else:
1122
1
1
self._maybe_resume_protocol() # May append to buffer.
1123
if not self._buffer:
1124
self._loop._remove_writer(self._sock_fd)
1125
if self._empty_waiter is not None:
1126
self._empty_waiter.set_result(None)
1127
# gh-156512: don't let _call_connection_lost be called twice
1128
if self._closing and not self._conn_lost:
1129
self._conn_lost += 1
1130
self._call_connection_lost(None)
1131
elif self._eof:
1132
self._sock.shutdown(socket.SHUT_WR)
1133
1134
def _adjust_leftover_buffer(self, nbytes: int) -> None:
1135
self._buffer_size -= nbytes
1136
buffer = self._buffer
1137
while nbytes:
1138
b = buffer.popleft()
1139
b_len = len(b)
1140
if b_len <= nbytes:
1141
nbytes -= b_len
1142
else:
1143
buffer.appendleft(b[nbytes:])
1144
break
1145
1146
def _write_send(self):
1147
assert self._buffer, 'Data should not be empty'
1148
if self._conn_lost:
1149
return
1150
try:
1151
buffer = self._buffer.popleft()
1152
n = self._sock.send(buffer)
1153
if n != len(buffer):
1154
# Not all data was written
1155
self._buffer.appendleft(buffer[n:])
1156
self._buffer_size -= n
1157
except (BlockingIOError, InterruptedError):
1158
self._buffer.appendleft(buffer)
1159
return
1160
except (SystemExit, KeyboardInterrupt):
1161
raise
1162
except BaseException as exc:
1163
self._loop._remove_writer(self._sock_fd)
1164
self._buffer.clear()
1165
self._buffer_size = 0
1166
self._fatal_error(exc, 'Fatal write error on socket transport')
1167
if self._empty_waiter is not None:
1168
self._empty_waiter.set_exception(exc)
1169
else:
1170
self._maybe_resume_protocol() # May append to buffer.
1171
if not self._buffer:
1172
self._loop._remove_writer(self._sock_fd)
1173
if self._empty_waiter is not None:
1174
self._empty_waiter.set_result(None)
1175
# gh-156512: don't let _call_connection_lost be called twice
1176
if self._closing and not self._conn_lost:
1177
self._conn_lost += 1
1178
self._call_connection_lost(None)
1179
elif self._eof:
1180
self._sock.shutdown(socket.SHUT_WR)
1181
1182
def write_eof(self):
1183
if self._closing or self._eof:
1184
return
1185
self._eof = True
1186
if not self._buffer:
1187
self._sock.shutdown(socket.SHUT_WR)
1188
1189
def writelines(self, list_of_data):
1190
if self._eof:
1191
raise RuntimeError('Cannot call writelines() after write_eof()')
1192
if self._empty_waiter is not None:
1193
raise RuntimeError('unable to writelines; sendfile is in progress')
1194
if not list_of_data:
1195
return
1196
1197
if self._conn_lost:
1198
if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
1199
logger.warning('socket.send() raised exception.')
1200
self._conn_lost += 1
1201
return
1202
1203
for data in list_of_data:
1204
# gh-155888: an empty chunk can never be drained, so never buffer it
1205
if not data:
1206
continue
1207
self._buffer.append(memoryview(data))
1208
self._buffer_size += len(data)
1209
if not self._buffer:
1210
return
1211
self._write_ready()
1212
# If the entire buffer couldn't be written, register a write handler
1213
if self._buffer:
1214
self._add_writer(self._sock_fd, self._write_ready)
1215
self._maybe_pause_protocol()
1216
1217
def can_write_eof(self):
1218
return True
1219
1220
def _call_connection_lost(self, exc):
1221
try:
1222
1
12
super()._call_connection_lost(exc)
1223
finally:
1224
self._write_ready = None
1225
if self._empty_waiter is not None:
1226
self._empty_waiter.set_exception(
1227
ConnectionError("Connection is closed by peer"))
1228
1229
def _make_empty_waiter(self):
1230
if self._empty_waiter is not None:
1231
raise RuntimeError("Empty waiter is already set")
1232
self._empty_waiter = self._loop.create_future()
1233
if not self._buffer:
1234
self._empty_waiter.set_result(None)
1235
return self._empty_waiter
1236
1237
def _reset_empty_waiter(self):
1238
self._empty_waiter = None
1239
1240
def close(self):
1241
self._read_ready_cb = None
1242
super().close()
1243
1244
1245
class _SelectorDatagramTransport(_SelectorTransport, transports.DatagramTransport):
1246
1247
_buffer_factory = collections.deque
1248
_header_size = 8
1249
1250
def __init__(self, loop, sock, protocol, address=None,
1251
waiter=None, extra=None):
1252
super().__init__(loop, sock, protocol, extra)
1253
self._address = address
1254
self._buffer_size = 0
1255
self._call_soon(self._protocol.connection_made, self)
1256
# only start reading when connection_made() has been called
1257
self._call_soon(self._add_reader, self._sock_fd, self._read_ready)
1258
if waiter is not None:
1259
# only wake up the waiter when connection_made() has been called
1260
self._call_soon(futures._set_result_unless_cancelled, waiter, None)
1261
1262
def get_write_buffer_size(self):
1263
return self._buffer_size
1264
1265
def _read_ready(self):
1266
if self._conn_lost:
1267
return
1268
try:
1269
data, addr = self._sock.recvfrom(self.max_size)
1270
except (BlockingIOError, InterruptedError):
1271
pass
1272
except OSError as exc:
1273
self._protocol.error_received(exc)
1274
except (SystemExit, KeyboardInterrupt):
1275
raise
1276
except BaseException as exc:
1277
self._fatal_error(exc, 'Fatal read error on datagram transport')
1278
else:
1279
self._protocol.datagram_received(data, addr)
1280
1281
def sendto(self, data, addr=None):
1282
if not isinstance(data, (bytes, bytearray, memoryview)):
1283
raise TypeError(f'data argument must be a bytes-like object, '
1284
f'not {type(data).__name__!r}')
1285
1286
if self._address:
1287
if addr not in (None, self._address):
1288
raise ValueError(
1289
f'Invalid address: must be None or {self._address}')
1290
addr = self._address
1291
1292
if self._conn_lost and self._address:
1293
if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
1294
logger.warning('socket.send() raised exception.')
1295
self._conn_lost += 1
1296
return
1297
1298
if not self._buffer:
1299
# Attempt to send it right away first.
1300
try:
1301
if self._extra['peername']:
1302
self._sock.send(data)
1303
else:
1304
self._sock.sendto(data, addr)
1305
return
1306
except (BlockingIOError, InterruptedError):
1307
self._add_writer(self._sock_fd, self._sendto_ready)
1308
except OSError as exc:
1309
self._protocol.error_received(exc)
1310
return
1311
except (SystemExit, KeyboardInterrupt):
1312
raise
1313
except BaseException as exc:
1314
self._fatal_error(
1315
exc, 'Fatal write error on datagram transport')
1316
return
1317
1318
# Ensure that what we buffer is immutable.
1319
self._buffer.append((bytes(data), addr))
1320
self._buffer_size += len(data) + self._header_size
1321
self._maybe_pause_protocol()
1322
1323
def _sendto_ready(self):
1324
while self._buffer:
1325
data, addr = self._buffer.popleft()
1326
self._buffer_size -= len(data) + self._header_size
1327
try:
1328
if self._extra['peername']:
1329
self._sock.send(data)
1330
else:
1331
self._sock.sendto(data, addr)
1332
except (BlockingIOError, InterruptedError):
1333
self._buffer.appendleft((data, addr)) # Try again later.
1334
self._buffer_size += len(data) + self._header_size
1335
break
1336
except OSError as exc:
1337
self._protocol.error_received(exc)
1338
return
1339
except (SystemExit, KeyboardInterrupt):
1340
raise
1341
except BaseException as exc:
1342
self._fatal_error(
1343
exc, 'Fatal write error on datagram transport')
1344
return
1345
1346
self._maybe_resume_protocol() # May append to buffer.
1347
if not self._buffer:
1348
self._loop._remove_writer(self._sock_fd)
1349
if self._closing:
1350
self._call_connection_lost(None)