1111import functools
1212import socket
1313import warnings
14+ import weakref
1415try :
1516 import ssl
1617except ImportError : # pragma: no cover
@@ -64,6 +65,7 @@ def __init__(self, selector=None):
6465 logger .debug ('Using selector: %s' , selector .__class__ .__name__ )
6566 self ._selector = selector
6667 self ._make_self_pipe ()
68+ self ._transports = weakref .WeakValueDictionary ()
6769
6870 def _make_socket_transport (self , sock , protocol , waiter = None , * ,
6971 extra = None , server = None ):
@@ -115,7 +117,7 @@ def _socketpair(self):
115117 raise NotImplementedError
116118
117119 def _close_self_pipe (self ):
118- self .remove_reader (self ._ssock .fileno ())
120+ self ._remove_reader (self ._ssock .fileno ())
119121 self ._ssock .close ()
120122 self ._ssock = None
121123 self ._csock .close ()
@@ -128,7 +130,7 @@ def _make_self_pipe(self):
128130 self ._ssock .setblocking (False )
129131 self ._csock .setblocking (False )
130132 self ._internal_fds += 1
131- self .add_reader (self ._ssock .fileno (), self ._read_from_self )
133+ self ._add_reader (self ._ssock .fileno (), self ._read_from_self )
132134
133135 def _process_self_data (self , data ):
134136 pass
@@ -163,8 +165,8 @@ def _write_to_self(self):
163165
164166 def _start_serving (self , protocol_factory , sock ,
165167 sslcontext = None , server = None , backlog = 100 ):
166- self .add_reader (sock .fileno (), self ._accept_connection ,
167- protocol_factory , sock , sslcontext , server , backlog )
168+ self ._add_reader (sock .fileno (), self ._accept_connection ,
169+ protocol_factory , sock , sslcontext , server , backlog )
168170
169171 def _accept_connection (self , protocol_factory , sock ,
170172 sslcontext = None , server = None , backlog = 100 ):
@@ -194,7 +196,7 @@ def _accept_connection(self, protocol_factory, sock,
194196 'exception' : exc ,
195197 'socket' : sock ,
196198 })
197- self .remove_reader (sock .fileno ())
199+ self ._remove_reader (sock .fileno ())
198200 self .call_later (constants .ACCEPT_RETRY_DELAY ,
199201 self ._start_serving ,
200202 protocol_factory , sock , sslcontext , server ,
@@ -244,8 +246,18 @@ def _accept_connection2(self, protocol_factory, conn, extra,
244246 context ['transport' ] = transport
245247 self .call_exception_handler (context )
246248
247- def add_reader (self , fd , callback , * args ):
248- """Add a reader callback."""
249+ def _ensure_fd_no_transport (self , fd ):
250+ try :
251+ transport = self ._transports [fd ]
252+ except KeyError :
253+ pass
254+ else :
255+ if not transport .is_closing ():
256+ raise RuntimeError (
257+ 'File descriptor {!r} is used by transport {!r}' .format (
258+ fd , transport ))
259+
260+ def _add_reader (self , fd , callback , * args ):
249261 self ._check_closed ()
250262 handle = events .Handle (callback , args , self )
251263 try :
@@ -260,8 +272,7 @@ def add_reader(self, fd, callback, *args):
260272 if reader is not None :
261273 reader .cancel ()
262274
263- def remove_reader (self , fd ):
264- """Remove a reader callback."""
275+ def _remove_reader (self , fd ):
265276 if self .is_closed ():
266277 return False
267278 try :
@@ -282,8 +293,7 @@ def remove_reader(self, fd):
282293 else :
283294 return False
284295
285- def add_writer (self , fd , callback , * args ):
286- """Add a writer callback.."""
296+ def _add_writer (self , fd , callback , * args ):
287297 self ._check_closed ()
288298 handle = events .Handle (callback , args , self )
289299 try :
@@ -298,7 +308,7 @@ def add_writer(self, fd, callback, *args):
298308 if writer is not None :
299309 writer .cancel ()
300310
301- def remove_writer (self , fd ):
311+ def _remove_writer (self , fd ):
302312 """Remove a writer callback."""
303313 if self .is_closed ():
304314 return False
@@ -321,6 +331,26 @@ def remove_writer(self, fd):
321331 else :
322332 return False
323333
334+ def add_reader (self , fd , callback , * args ):
335+ """Add a reader callback."""
336+ self ._ensure_fd_no_transport (fd )
337+ return self ._add_reader (fd , callback , * args )
338+
339+ def remove_reader (self , fd ):
340+ """Remove a reader callback."""
341+ self ._ensure_fd_no_transport (fd )
342+ return self ._remove_reader (fd )
343+
344+ def add_writer (self , fd , callback , * args ):
345+ """Add a writer callback.."""
346+ self ._ensure_fd_no_transport (fd )
347+ return self ._add_writer (fd , callback , * args )
348+
349+ def remove_writer (self , fd ):
350+ """Remove a writer callback."""
351+ self ._ensure_fd_no_transport (fd )
352+ return self ._remove_writer (fd )
353+
324354 def sock_recv (self , sock , n ):
325355 """Receive data from the socket.
326356
@@ -494,17 +524,17 @@ def _process_events(self, event_list):
494524 fileobj , (reader , writer ) = key .fileobj , key .data
495525 if mask & selectors .EVENT_READ and reader is not None :
496526 if reader ._cancelled :
497- self .remove_reader (fileobj )
527+ self ._remove_reader (fileobj )
498528 else :
499529 self ._add_callback (reader )
500530 if mask & selectors .EVENT_WRITE and writer is not None :
501531 if writer ._cancelled :
502- self .remove_writer (fileobj )
532+ self ._remove_writer (fileobj )
503533 else :
504534 self ._add_callback (writer )
505535
506536 def _stop_serving (self , sock ):
507- self .remove_reader (sock .fileno ())
537+ self ._remove_reader (sock .fileno ())
508538 sock .close ()
509539
510540
@@ -539,6 +569,7 @@ def __init__(self, loop, sock, protocol, extra=None, server=None):
539569 self ._closing = False # Set when close() called.
540570 if self ._server is not None :
541571 self ._server ._attach ()
572+ loop ._transports [self ._sock_fd ] = self
542573
543574 def __repr__ (self ):
544575 info = [self .__class__ .__name__ ]
@@ -584,10 +615,10 @@ def close(self):
584615 if self ._closing :
585616 return
586617 self ._closing = True
587- self ._loop .remove_reader (self ._sock_fd )
618+ self ._loop ._remove_reader (self ._sock_fd )
588619 if not self ._buffer :
589620 self ._conn_lost += 1
590- self ._loop .remove_writer (self ._sock_fd )
621+ self ._loop ._remove_writer (self ._sock_fd )
591622 self ._loop .call_soon (self ._call_connection_lost , None )
592623
593624 # On Python 3.3 and older, objects with a destructor part of a reference
@@ -619,10 +650,10 @@ def _force_close(self, exc):
619650 return
620651 if self ._buffer :
621652 self ._buffer .clear ()
622- self ._loop .remove_writer (self ._sock_fd )
653+ self ._loop ._remove_writer (self ._sock_fd )
623654 if not self ._closing :
624655 self ._closing = True
625- self ._loop .remove_reader (self ._sock_fd )
656+ self ._loop ._remove_reader (self ._sock_fd )
626657 self ._conn_lost += 1
627658 self ._loop .call_soon (self ._call_connection_lost , exc )
628659
@@ -659,7 +690,7 @@ def __init__(self, loop, sock, protocol, waiter=None,
659690
660691 self ._loop .call_soon (self ._protocol .connection_made , self )
661692 # only start reading when connection_made() has been called
662- self ._loop .call_soon (self ._loop .add_reader ,
693+ self ._loop .call_soon (self ._loop ._add_reader ,
663694 self ._sock_fd , self ._read_ready )
664695 if waiter is not None :
665696 # only wake up the waiter when connection_made() has been called
@@ -672,7 +703,7 @@ def pause_reading(self):
672703 if self ._paused :
673704 raise RuntimeError ('Already paused' )
674705 self ._paused = True
675- self ._loop .remove_reader (self ._sock_fd )
706+ self ._loop ._remove_reader (self ._sock_fd )
676707 if self ._loop .get_debug ():
677708 logger .debug ("%r pauses reading" , self )
678709
@@ -682,7 +713,7 @@ def resume_reading(self):
682713 self ._paused = False
683714 if self ._closing :
684715 return
685- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
716+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
686717 if self ._loop .get_debug ():
687718 logger .debug ("%r resumes reading" , self )
688719
@@ -706,7 +737,7 @@ def _read_ready(self):
706737 # We're keeping the connection open so the
707738 # protocol can write more, but we still can't
708739 # receive more, so remove the reader callback.
709- self ._loop .remove_reader (self ._sock_fd )
740+ self ._loop ._remove_reader (self ._sock_fd )
710741 else :
711742 self .close ()
712743
@@ -739,7 +770,7 @@ def write(self, data):
739770 if not data :
740771 return
741772 # Not all was written; register write handler.
742- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
773+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
743774
744775 # Add it to the buffer.
745776 self ._buffer .extend (data )
@@ -755,15 +786,15 @@ def _write_ready(self):
755786 except (BlockingIOError , InterruptedError ):
756787 pass
757788 except Exception as exc :
758- self ._loop .remove_writer (self ._sock_fd )
789+ self ._loop ._remove_writer (self ._sock_fd )
759790 self ._buffer .clear ()
760791 self ._fatal_error (exc , 'Fatal write error on socket transport' )
761792 else :
762793 if n :
763794 del self ._buffer [:n ]
764795 self ._maybe_resume_protocol () # May append to buffer.
765796 if not self ._buffer :
766- self ._loop .remove_writer (self ._sock_fd )
797+ self ._loop ._remove_writer (self ._sock_fd )
767798 if self ._closing :
768799 self ._call_connection_lost (None )
769800 elif self ._eof :
@@ -834,28 +865,28 @@ def _on_handshake(self, start_time):
834865 try :
835866 self ._sock .do_handshake ()
836867 except ssl .SSLWantReadError :
837- self ._loop .add_reader (self ._sock_fd ,
838- self ._on_handshake , start_time )
868+ self ._loop ._add_reader (self ._sock_fd ,
869+ self ._on_handshake , start_time )
839870 return
840871 except ssl .SSLWantWriteError :
841- self ._loop .add_writer (self ._sock_fd ,
842- self ._on_handshake , start_time )
872+ self ._loop ._add_writer (self ._sock_fd ,
873+ self ._on_handshake , start_time )
843874 return
844875 except BaseException as exc :
845876 if self ._loop .get_debug ():
846877 logger .warning ("%r: SSL handshake failed" ,
847878 self , exc_info = True )
848- self ._loop .remove_reader (self ._sock_fd )
849- self ._loop .remove_writer (self ._sock_fd )
879+ self ._loop ._remove_reader (self ._sock_fd )
880+ self ._loop ._remove_writer (self ._sock_fd )
850881 self ._sock .close ()
851882 self ._wakeup_waiter (exc )
852883 if isinstance (exc , Exception ):
853884 return
854885 else :
855886 raise
856887
857- self ._loop .remove_reader (self ._sock_fd )
858- self ._loop .remove_writer (self ._sock_fd )
888+ self ._loop ._remove_reader (self ._sock_fd )
889+ self ._loop ._remove_writer (self ._sock_fd )
859890
860891 peercert = self ._sock .getpeercert ()
861892 if not hasattr (self ._sslcontext , 'check_hostname' ):
@@ -883,7 +914,7 @@ def _on_handshake(self, start_time):
883914
884915 self ._read_wants_write = False
885916 self ._write_wants_read = False
886- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
917+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
887918 self ._protocol_connected = True
888919 self ._loop .call_soon (self ._protocol .connection_made , self )
889920 # only wake up the waiter when connection_made() has been called
@@ -905,7 +936,7 @@ def pause_reading(self):
905936 if self ._paused :
906937 raise RuntimeError ('Already paused' )
907938 self ._paused = True
908- self ._loop .remove_reader (self ._sock_fd )
939+ self ._loop ._remove_reader (self ._sock_fd )
909940 if self ._loop .get_debug ():
910941 logger .debug ("%r pauses reading" , self )
911942
@@ -915,7 +946,7 @@ def resume_reading(self):
915946 self ._paused = False
916947 if self ._closing :
917948 return
918- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
949+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
919950 if self ._loop .get_debug ():
920951 logger .debug ("%r resumes reading" , self )
921952
@@ -927,16 +958,16 @@ def _read_ready(self):
927958 self ._write_ready ()
928959
929960 if self ._buffer :
930- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
961+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
931962
932963 try :
933964 data = self ._sock .recv (self .max_size )
934965 except (BlockingIOError , InterruptedError , ssl .SSLWantReadError ):
935966 pass
936967 except ssl .SSLWantWriteError :
937968 self ._read_wants_write = True
938- self ._loop .remove_reader (self ._sock_fd )
939- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
969+ self ._loop ._remove_reader (self ._sock_fd )
970+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
940971 except Exception as exc :
941972 self ._fatal_error (exc , 'Fatal read error on SSL transport' )
942973 else :
@@ -961,7 +992,7 @@ def _write_ready(self):
961992 self ._read_ready ()
962993
963994 if not (self ._paused or self ._closing ):
964- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
995+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
965996
966997 if self ._buffer :
967998 try :
@@ -970,10 +1001,10 @@ def _write_ready(self):
9701001 n = 0
9711002 except ssl .SSLWantReadError :
9721003 n = 0
973- self ._loop .remove_writer (self ._sock_fd )
1004+ self ._loop ._remove_writer (self ._sock_fd )
9741005 self ._write_wants_read = True
9751006 except Exception as exc :
976- self ._loop .remove_writer (self ._sock_fd )
1007+ self ._loop ._remove_writer (self ._sock_fd )
9771008 self ._buffer .clear ()
9781009 self ._fatal_error (exc , 'Fatal write error on SSL transport' )
9791010 return
@@ -984,7 +1015,7 @@ def _write_ready(self):
9841015 self ._maybe_resume_protocol () # May append to buffer.
9851016
9861017 if not self ._buffer :
987- self ._loop .remove_writer (self ._sock_fd )
1018+ self ._loop ._remove_writer (self ._sock_fd )
9881019 if self ._closing :
9891020 self ._call_connection_lost (None )
9901021
@@ -1002,7 +1033,7 @@ def write(self, data):
10021033 return
10031034
10041035 if not self ._buffer :
1005- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
1036+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
10061037
10071038 # Add it to the buffer.
10081039 self ._buffer .extend (data )
@@ -1022,7 +1053,7 @@ def __init__(self, loop, sock, protocol, address=None,
10221053 self ._address = address
10231054 self ._loop .call_soon (self ._protocol .connection_made , self )
10241055 # only start reading when connection_made() has been called
1025- self ._loop .call_soon (self ._loop .add_reader ,
1056+ self ._loop .call_soon (self ._loop ._add_reader ,
10261057 self ._sock_fd , self ._read_ready )
10271058 if waiter is not None :
10281059 # only wake up the waiter when connection_made() has been called
@@ -1072,7 +1103,7 @@ def sendto(self, data, addr=None):
10721103 self ._sock .sendto (data , addr )
10731104 return
10741105 except (BlockingIOError , InterruptedError ):
1075- self ._loop .add_writer (self ._sock_fd , self ._sendto_ready )
1106+ self ._loop ._add_writer (self ._sock_fd , self ._sendto_ready )
10761107 except OSError as exc :
10771108 self ._protocol .error_received (exc )
10781109 return
@@ -1106,6 +1137,6 @@ def _sendto_ready(self):
11061137
11071138 self ._maybe_resume_protocol () # May append to buffer.
11081139 if not self ._buffer :
1109- self ._loop .remove_writer (self ._sock_fd )
1140+ self ._loop ._remove_writer (self ._sock_fd )
11101141 if self ._closing :
11111142 self ._call_connection_lost (None )
0 commit comments