11
11
import functools
12
12
import socket
13
13
import warnings
14
+ import weakref
14
15
try :
15
16
import ssl
16
17
except ImportError : # pragma: no cover
@@ -64,6 +65,7 @@ def __init__(self, selector=None):
64
65
logger .debug ('Using selector: %s' , selector .__class__ .__name__ )
65
66
self ._selector = selector
66
67
self ._make_self_pipe ()
68
+ self ._transports = weakref .WeakValueDictionary ()
67
69
68
70
def _make_socket_transport (self , sock , protocol , waiter = None , * ,
69
71
extra = None , server = None ):
@@ -115,7 +117,7 @@ def _socketpair(self):
115
117
raise NotImplementedError
116
118
117
119
def _close_self_pipe (self ):
118
- self .remove_reader (self ._ssock .fileno ())
120
+ self ._remove_reader (self ._ssock .fileno ())
119
121
self ._ssock .close ()
120
122
self ._ssock = None
121
123
self ._csock .close ()
@@ -128,7 +130,7 @@ def _make_self_pipe(self):
128
130
self ._ssock .setblocking (False )
129
131
self ._csock .setblocking (False )
130
132
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 )
132
134
133
135
def _process_self_data (self , data ):
134
136
pass
@@ -163,8 +165,8 @@ def _write_to_self(self):
163
165
164
166
def _start_serving (self , protocol_factory , sock ,
165
167
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 )
168
170
169
171
def _accept_connection (self , protocol_factory , sock ,
170
172
sslcontext = None , server = None , backlog = 100 ):
@@ -194,7 +196,7 @@ def _accept_connection(self, protocol_factory, sock,
194
196
'exception' : exc ,
195
197
'socket' : sock ,
196
198
})
197
- self .remove_reader (sock .fileno ())
199
+ self ._remove_reader (sock .fileno ())
198
200
self .call_later (constants .ACCEPT_RETRY_DELAY ,
199
201
self ._start_serving ,
200
202
protocol_factory , sock , sslcontext , server ,
@@ -244,8 +246,18 @@ def _accept_connection2(self, protocol_factory, conn, extra,
244
246
context ['transport' ] = transport
245
247
self .call_exception_handler (context )
246
248
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 ):
249
261
self ._check_closed ()
250
262
handle = events .Handle (callback , args , self )
251
263
try :
@@ -260,8 +272,7 @@ def add_reader(self, fd, callback, *args):
260
272
if reader is not None :
261
273
reader .cancel ()
262
274
263
- def remove_reader (self , fd ):
264
- """Remove a reader callback."""
275
+ def _remove_reader (self , fd ):
265
276
if self .is_closed ():
266
277
return False
267
278
try :
@@ -282,8 +293,7 @@ def remove_reader(self, fd):
282
293
else :
283
294
return False
284
295
285
- def add_writer (self , fd , callback , * args ):
286
- """Add a writer callback.."""
296
+ def _add_writer (self , fd , callback , * args ):
287
297
self ._check_closed ()
288
298
handle = events .Handle (callback , args , self )
289
299
try :
@@ -298,7 +308,7 @@ def add_writer(self, fd, callback, *args):
298
308
if writer is not None :
299
309
writer .cancel ()
300
310
301
- def remove_writer (self , fd ):
311
+ def _remove_writer (self , fd ):
302
312
"""Remove a writer callback."""
303
313
if self .is_closed ():
304
314
return False
@@ -321,6 +331,26 @@ def remove_writer(self, fd):
321
331
else :
322
332
return False
323
333
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
+
324
354
def sock_recv (self , sock , n ):
325
355
"""Receive data from the socket.
326
356
@@ -494,17 +524,17 @@ def _process_events(self, event_list):
494
524
fileobj , (reader , writer ) = key .fileobj , key .data
495
525
if mask & selectors .EVENT_READ and reader is not None :
496
526
if reader ._cancelled :
497
- self .remove_reader (fileobj )
527
+ self ._remove_reader (fileobj )
498
528
else :
499
529
self ._add_callback (reader )
500
530
if mask & selectors .EVENT_WRITE and writer is not None :
501
531
if writer ._cancelled :
502
- self .remove_writer (fileobj )
532
+ self ._remove_writer (fileobj )
503
533
else :
504
534
self ._add_callback (writer )
505
535
506
536
def _stop_serving (self , sock ):
507
- self .remove_reader (sock .fileno ())
537
+ self ._remove_reader (sock .fileno ())
508
538
sock .close ()
509
539
510
540
@@ -539,6 +569,7 @@ def __init__(self, loop, sock, protocol, extra=None, server=None):
539
569
self ._closing = False # Set when close() called.
540
570
if self ._server is not None :
541
571
self ._server ._attach ()
572
+ loop ._transports [self ._sock_fd ] = self
542
573
543
574
def __repr__ (self ):
544
575
info = [self .__class__ .__name__ ]
@@ -584,10 +615,10 @@ def close(self):
584
615
if self ._closing :
585
616
return
586
617
self ._closing = True
587
- self ._loop .remove_reader (self ._sock_fd )
618
+ self ._loop ._remove_reader (self ._sock_fd )
588
619
if not self ._buffer :
589
620
self ._conn_lost += 1
590
- self ._loop .remove_writer (self ._sock_fd )
621
+ self ._loop ._remove_writer (self ._sock_fd )
591
622
self ._loop .call_soon (self ._call_connection_lost , None )
592
623
593
624
# On Python 3.3 and older, objects with a destructor part of a reference
@@ -618,10 +649,10 @@ def _force_close(self, exc):
618
649
return
619
650
if self ._buffer :
620
651
self ._buffer .clear ()
621
- self ._loop .remove_writer (self ._sock_fd )
652
+ self ._loop ._remove_writer (self ._sock_fd )
622
653
if not self ._closing :
623
654
self ._closing = True
624
- self ._loop .remove_reader (self ._sock_fd )
655
+ self ._loop ._remove_reader (self ._sock_fd )
625
656
self ._conn_lost += 1
626
657
self ._loop .call_soon (self ._call_connection_lost , exc )
627
658
@@ -658,7 +689,7 @@ def __init__(self, loop, sock, protocol, waiter=None,
658
689
659
690
self ._loop .call_soon (self ._protocol .connection_made , self )
660
691
# only start reading when connection_made() has been called
661
- self ._loop .call_soon (self ._loop .add_reader ,
692
+ self ._loop .call_soon (self ._loop ._add_reader ,
662
693
self ._sock_fd , self ._read_ready )
663
694
if waiter is not None :
664
695
# only wake up the waiter when connection_made() has been called
@@ -671,7 +702,7 @@ def pause_reading(self):
671
702
if self ._paused :
672
703
raise RuntimeError ('Already paused' )
673
704
self ._paused = True
674
- self ._loop .remove_reader (self ._sock_fd )
705
+ self ._loop ._remove_reader (self ._sock_fd )
675
706
if self ._loop .get_debug ():
676
707
logger .debug ("%r pauses reading" , self )
677
708
@@ -681,7 +712,7 @@ def resume_reading(self):
681
712
self ._paused = False
682
713
if self ._closing :
683
714
return
684
- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
715
+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
685
716
if self ._loop .get_debug ():
686
717
logger .debug ("%r resumes reading" , self )
687
718
@@ -705,7 +736,7 @@ def _read_ready(self):
705
736
# We're keeping the connection open so the
706
737
# protocol can write more, but we still can't
707
738
# receive more, so remove the reader callback.
708
- self ._loop .remove_reader (self ._sock_fd )
739
+ self ._loop ._remove_reader (self ._sock_fd )
709
740
else :
710
741
self .close ()
711
742
@@ -738,7 +769,7 @@ def write(self, data):
738
769
if not data :
739
770
return
740
771
# Not all was written; register write handler.
741
- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
772
+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
742
773
743
774
# Add it to the buffer.
744
775
self ._buffer .extend (data )
@@ -754,15 +785,15 @@ def _write_ready(self):
754
785
except (BlockingIOError , InterruptedError ):
755
786
pass
756
787
except Exception as exc :
757
- self ._loop .remove_writer (self ._sock_fd )
788
+ self ._loop ._remove_writer (self ._sock_fd )
758
789
self ._buffer .clear ()
759
790
self ._fatal_error (exc , 'Fatal write error on socket transport' )
760
791
else :
761
792
if n :
762
793
del self ._buffer [:n ]
763
794
self ._maybe_resume_protocol () # May append to buffer.
764
795
if not self ._buffer :
765
- self ._loop .remove_writer (self ._sock_fd )
796
+ self ._loop ._remove_writer (self ._sock_fd )
766
797
if self ._closing :
767
798
self ._call_connection_lost (None )
768
799
elif self ._eof :
@@ -833,28 +864,28 @@ def _on_handshake(self, start_time):
833
864
try :
834
865
self ._sock .do_handshake ()
835
866
except ssl .SSLWantReadError :
836
- self ._loop .add_reader (self ._sock_fd ,
837
- self ._on_handshake , start_time )
867
+ self ._loop ._add_reader (self ._sock_fd ,
868
+ self ._on_handshake , start_time )
838
869
return
839
870
except ssl .SSLWantWriteError :
840
- self ._loop .add_writer (self ._sock_fd ,
841
- self ._on_handshake , start_time )
871
+ self ._loop ._add_writer (self ._sock_fd ,
872
+ self ._on_handshake , start_time )
842
873
return
843
874
except BaseException as exc :
844
875
if self ._loop .get_debug ():
845
876
logger .warning ("%r: SSL handshake failed" ,
846
877
self , exc_info = True )
847
- self ._loop .remove_reader (self ._sock_fd )
848
- self ._loop .remove_writer (self ._sock_fd )
878
+ self ._loop ._remove_reader (self ._sock_fd )
879
+ self ._loop ._remove_writer (self ._sock_fd )
849
880
self ._sock .close ()
850
881
self ._wakeup_waiter (exc )
851
882
if isinstance (exc , Exception ):
852
883
return
853
884
else :
854
885
raise
855
886
856
- self ._loop .remove_reader (self ._sock_fd )
857
- self ._loop .remove_writer (self ._sock_fd )
887
+ self ._loop ._remove_reader (self ._sock_fd )
888
+ self ._loop ._remove_writer (self ._sock_fd )
858
889
859
890
peercert = self ._sock .getpeercert ()
860
891
if not hasattr (self ._sslcontext , 'check_hostname' ):
@@ -882,7 +913,7 @@ def _on_handshake(self, start_time):
882
913
883
914
self ._read_wants_write = False
884
915
self ._write_wants_read = False
885
- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
916
+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
886
917
self ._protocol_connected = True
887
918
self ._loop .call_soon (self ._protocol .connection_made , self )
888
919
# only wake up the waiter when connection_made() has been called
@@ -904,7 +935,7 @@ def pause_reading(self):
904
935
if self ._paused :
905
936
raise RuntimeError ('Already paused' )
906
937
self ._paused = True
907
- self ._loop .remove_reader (self ._sock_fd )
938
+ self ._loop ._remove_reader (self ._sock_fd )
908
939
if self ._loop .get_debug ():
909
940
logger .debug ("%r pauses reading" , self )
910
941
@@ -914,7 +945,7 @@ def resume_reading(self):
914
945
self ._paused = False
915
946
if self ._closing :
916
947
return
917
- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
948
+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
918
949
if self ._loop .get_debug ():
919
950
logger .debug ("%r resumes reading" , self )
920
951
@@ -926,16 +957,16 @@ def _read_ready(self):
926
957
self ._write_ready ()
927
958
928
959
if self ._buffer :
929
- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
960
+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
930
961
931
962
try :
932
963
data = self ._sock .recv (self .max_size )
933
964
except (BlockingIOError , InterruptedError , ssl .SSLWantReadError ):
934
965
pass
935
966
except ssl .SSLWantWriteError :
936
967
self ._read_wants_write = True
937
- self ._loop .remove_reader (self ._sock_fd )
938
- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
968
+ self ._loop ._remove_reader (self ._sock_fd )
969
+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
939
970
except Exception as exc :
940
971
self ._fatal_error (exc , 'Fatal read error on SSL transport' )
941
972
else :
@@ -960,7 +991,7 @@ def _write_ready(self):
960
991
self ._read_ready ()
961
992
962
993
if not (self ._paused or self ._closing ):
963
- self ._loop .add_reader (self ._sock_fd , self ._read_ready )
994
+ self ._loop ._add_reader (self ._sock_fd , self ._read_ready )
964
995
965
996
if self ._buffer :
966
997
try :
@@ -969,10 +1000,10 @@ def _write_ready(self):
969
1000
n = 0
970
1001
except ssl .SSLWantReadError :
971
1002
n = 0
972
- self ._loop .remove_writer (self ._sock_fd )
1003
+ self ._loop ._remove_writer (self ._sock_fd )
973
1004
self ._write_wants_read = True
974
1005
except Exception as exc :
975
- self ._loop .remove_writer (self ._sock_fd )
1006
+ self ._loop ._remove_writer (self ._sock_fd )
976
1007
self ._buffer .clear ()
977
1008
self ._fatal_error (exc , 'Fatal write error on SSL transport' )
978
1009
return
@@ -983,7 +1014,7 @@ def _write_ready(self):
983
1014
self ._maybe_resume_protocol () # May append to buffer.
984
1015
985
1016
if not self ._buffer :
986
- self ._loop .remove_writer (self ._sock_fd )
1017
+ self ._loop ._remove_writer (self ._sock_fd )
987
1018
if self ._closing :
988
1019
self ._call_connection_lost (None )
989
1020
@@ -1001,7 +1032,7 @@ def write(self, data):
1001
1032
return
1002
1033
1003
1034
if not self ._buffer :
1004
- self ._loop .add_writer (self ._sock_fd , self ._write_ready )
1035
+ self ._loop ._add_writer (self ._sock_fd , self ._write_ready )
1005
1036
1006
1037
# Add it to the buffer.
1007
1038
self ._buffer .extend (data )
@@ -1021,7 +1052,7 @@ def __init__(self, loop, sock, protocol, address=None,
1021
1052
self ._address = address
1022
1053
self ._loop .call_soon (self ._protocol .connection_made , self )
1023
1054
# only start reading when connection_made() has been called
1024
- self ._loop .call_soon (self ._loop .add_reader ,
1055
+ self ._loop .call_soon (self ._loop ._add_reader ,
1025
1056
self ._sock_fd , self ._read_ready )
1026
1057
if waiter is not None :
1027
1058
# only wake up the waiter when connection_made() has been called
@@ -1071,7 +1102,7 @@ def sendto(self, data, addr=None):
1071
1102
self ._sock .sendto (data , addr )
1072
1103
return
1073
1104
except (BlockingIOError , InterruptedError ):
1074
- self ._loop .add_writer (self ._sock_fd , self ._sendto_ready )
1105
+ self ._loop ._add_writer (self ._sock_fd , self ._sendto_ready )
1075
1106
except OSError as exc :
1076
1107
self ._protocol .error_received (exc )
1077
1108
return
@@ -1105,6 +1136,6 @@ def _sendto_ready(self):
1105
1136
1106
1137
self ._maybe_resume_protocol () # May append to buffer.
1107
1138
if not self ._buffer :
1108
- self ._loop .remove_writer (self ._sock_fd )
1139
+ self ._loop ._remove_writer (self ._sock_fd )
1109
1140
if self ._closing :
1110
1141
self ._call_connection_lost (None )
0 commit comments