blob: 69fa43e8b6511a9599f467eb522e03e6a72e4862 [file] [log] [blame]
Yury Selivanov6370f342017-12-10 18:36:12 -05001"""Abstract Protocol base classes."""
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07002
Yury Selivanov6370f342017-12-10 18:36:12 -05003__all__ = (
4 'BaseProtocol', 'Protocol', 'DatagramProtocol',
Yury Selivanov631fd382018-01-28 16:30:26 -05005 'SubprocessProtocol', 'BufferedProtocol',
Yury Selivanov6370f342017-12-10 18:36:12 -05006)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07007
8
9class BaseProtocol:
Guido van Rossum9204af42013-11-30 15:35:42 -080010 """Common base class for protocol interfaces.
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070011
12 Usually user implements protocols that derived from BaseProtocol
13 like Protocol or ProcessProtocol.
14
15 The only case when BaseProtocol should be implemented directly is
16 write-only transport like write pipe
17 """
18
Andrew Svetlov53445012018-12-11 19:07:05 +020019 __slots__ = ()
20
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070021 def connection_made(self, transport):
22 """Called when a connection is made.
23
24 The argument is the transport representing the pipe connection.
25 To receive data, wait for data_received() calls.
26 When the connection is closed, connection_lost() is called.
27 """
28
29 def connection_lost(self, exc):
30 """Called when the connection is lost or closed.
31
32 The argument is an exception object or None (the latter
33 meaning a regular EOF is received or the connection was
34 aborted or closed).
35 """
36
Guido van Rossum355491d2013-10-18 15:17:11 -070037 def pause_writing(self):
38 """Called when the transport's buffer goes over the high-water mark.
39
40 Pause and resume calls are paired -- pause_writing() is called
41 once when the buffer goes strictly over the high-water mark
42 (even if subsequent writes increases the buffer size even
43 more), and eventually resume_writing() is called once when the
44 buffer size reaches the low-water mark.
45
46 Note that if the buffer size equals the high-water mark,
47 pause_writing() is not called -- it must go strictly over.
48 Conversely, resume_writing() is called when the buffer size is
49 equal or lower than the low-water mark. These end conditions
50 are important to ensure that things go as expected when either
51 mark is zero.
52
53 NOTE: This is the only Protocol callback that is not called
54 through EventLoop.call_soon() -- if it were, it would have no
55 effect when it's most needed (when the app keeps writing
56 without yielding until pause_writing() is called).
57 """
58
59 def resume_writing(self):
60 """Called when the transport's buffer drains below the low-water mark.
61
62 See pause_writing() for details.
63 """
64
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070065
66class Protocol(BaseProtocol):
Guido van Rossum9204af42013-11-30 15:35:42 -080067 """Interface for stream protocol.
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070068
69 The user should implement this interface. They can inherit from
70 this class but don't need to. The implementations here do
71 nothing (they don't raise exceptions).
72
73 When the user wants to requests a transport, they pass a protocol
74 factory to a utility function (e.g., EventLoop.create_connection()).
75
76 When the connection is made successfully, connection_made() is
77 called with a suitable transport object. Then data_received()
78 will be called 0 or more times with data (bytes) received from the
79 transport; finally, connection_lost() will be called exactly once
80 with either an exception object or None as an argument.
81
82 State machine of calls:
83
84 start -> CM [-> DR*] [-> ER?] -> CL -> end
Victor Stinner54a231d2015-01-29 13:33:15 +010085
86 * CM: connection_made()
87 * DR: data_received()
88 * ER: eof_received()
89 * CL: connection_lost()
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070090 """
91
Andrew Svetlov53445012018-12-11 19:07:05 +020092 __slots__ = ()
93
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070094 def data_received(self, data):
95 """Called when some data is received.
96
97 The argument is a bytes object.
98 """
99
100 def eof_received(self):
101 """Called when the other end calls write_eof() or equivalent.
102
103 If this returns a false value (including None), the transport
104 will close itself. If it returns a true value, closing the
105 transport is up to the protocol.
106 """
107
108
Yury Selivanov631fd382018-01-28 16:30:26 -0500109class BufferedProtocol(BaseProtocol):
110 """Interface for stream protocol with manual buffer control.
111
Serhiy Storchakabac2d5b2018-03-28 22:14:26 +0300112 Important: this has been added to asyncio in Python 3.7
Yury Selivanov07627e92018-01-28 23:51:08 -0500113 *on a provisional basis*! Consider it as an experimental API that
Yury Selivanov631fd382018-01-28 16:30:26 -0500114 might be changed or removed in Python 3.8.
115
116 Event methods, such as `create_server` and `create_connection`,
117 accept factories that return protocols that implement this interface.
118
119 The idea of BufferedProtocol is that it allows to manually allocate
120 and control the receive buffer. Event loops can then use the buffer
121 provided by the protocol to avoid unnecessary data copies. This
122 can result in noticeable performance improvement for protocols that
123 receive big amounts of data. Sophisticated protocols can allocate
124 the buffer only once at creation time.
125
126 State machine of calls:
127
128 start -> CM [-> GB [-> BU?]]* [-> ER?] -> CL -> end
129
130 * CM: connection_made()
131 * GB: get_buffer()
132 * BU: buffer_updated()
133 * ER: eof_received()
134 * CL: connection_lost()
135 """
136
Andrew Svetlov53445012018-12-11 19:07:05 +0200137 __slots__ = ()
138
Yury Selivanovdbf10222018-05-28 14:31:28 -0400139 def get_buffer(self, sizehint):
Yury Selivanov631fd382018-01-28 16:30:26 -0500140 """Called to allocate a new receive buffer.
141
Yury Selivanovdbf10222018-05-28 14:31:28 -0400142 *sizehint* is a recommended minimal size for the returned
143 buffer. When set to -1, the buffer size can be arbitrary.
144
Yury Selivanov631fd382018-01-28 16:30:26 -0500145 Must return an object that implements the
146 :ref:`buffer protocol <bufferobjects>`.
Yury Selivanovdbf10222018-05-28 14:31:28 -0400147 It is an error to return a zero-sized buffer.
Yury Selivanov631fd382018-01-28 16:30:26 -0500148 """
149
150 def buffer_updated(self, nbytes):
151 """Called when the buffer was updated with the received data.
152
153 *nbytes* is the total number of bytes that were written to
154 the buffer.
155 """
156
157 def eof_received(self):
158 """Called when the other end calls write_eof() or equivalent.
159
160 If this returns a false value (including None), the transport
161 will close itself. If it returns a true value, closing the
162 transport is up to the protocol.
163 """
164
165
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700166class DatagramProtocol(BaseProtocol):
Guido van Rossum9204af42013-11-30 15:35:42 -0800167 """Interface for datagram protocol."""
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700168
Andrew Svetlov53445012018-12-11 19:07:05 +0200169 __slots__ = ()
170
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700171 def datagram_received(self, data, addr):
172 """Called when some datagram is received."""
173
Guido van Rossum2335de72013-11-15 16:51:48 -0800174 def error_received(self, exc):
175 """Called when a send or receive operation raises an OSError.
176
177 (Other than BlockingIOError or InterruptedError.)
178 """
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700179
180
181class SubprocessProtocol(BaseProtocol):
Guido van Rossum9204af42013-11-30 15:35:42 -0800182 """Interface for protocol for subprocess calls."""
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700183
Andrew Svetlov53445012018-12-11 19:07:05 +0200184 __slots__ = ()
185
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700186 def pipe_data_received(self, fd, data):
Guido van Rossum2335de72013-11-15 16:51:48 -0800187 """Called when the subprocess writes data into stdout/stderr pipe.
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700188
Yury Selivanovdec1a452014-02-18 22:27:48 -0500189 fd is int file descriptor.
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700190 data is bytes object.
191 """
192
193 def pipe_connection_lost(self, fd, exc):
194 """Called when a file descriptor associated with the child process is
195 closed.
196
197 fd is the int file descriptor that was closed.
198 """
199
200 def process_exited(self):
Guido van Rossum2335de72013-11-15 16:51:48 -0800201 """Called when subprocess has exited."""
Victor Stinner79790bc2018-06-08 00:25:52 +0200202
203
Victor Stinnerff6c0772018-06-08 10:32:06 +0200204def _feed_data_to_buffered_proto(proto, data):
Victor Stinner79790bc2018-06-08 00:25:52 +0200205 data_len = len(data)
206 while data_len:
207 buf = proto.get_buffer(data_len)
208 buf_len = len(buf)
209 if not buf_len:
210 raise RuntimeError('get_buffer() returned an empty buffer')
211
212 if buf_len >= data_len:
213 buf[:data_len] = data
214 proto.buffer_updated(data_len)
215 return
216 else:
217 buf[:buf_len] = data[:buf_len]
218 proto.buffer_updated(buf_len)
219 data = data[buf_len:]
220 data_len = len(data)