1*cda5da8dSAndroid Build Coastguard Worker"""Abstract Protocol base classes.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Worker__all__ = ( 4*cda5da8dSAndroid Build Coastguard Worker 'BaseProtocol', 'Protocol', 'DatagramProtocol', 5*cda5da8dSAndroid Build Coastguard Worker 'SubprocessProtocol', 'BufferedProtocol', 6*cda5da8dSAndroid Build Coastguard Worker) 7*cda5da8dSAndroid Build Coastguard Worker 8*cda5da8dSAndroid Build Coastguard Worker 9*cda5da8dSAndroid Build Coastguard Workerclass BaseProtocol: 10*cda5da8dSAndroid Build Coastguard Worker """Common base class for protocol interfaces. 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Worker Usually user implements protocols that derived from BaseProtocol 13*cda5da8dSAndroid Build Coastguard Worker like Protocol or ProcessProtocol. 14*cda5da8dSAndroid Build Coastguard Worker 15*cda5da8dSAndroid Build Coastguard Worker The only case when BaseProtocol should be implemented directly is 16*cda5da8dSAndroid Build Coastguard Worker write-only transport like write pipe 17*cda5da8dSAndroid Build Coastguard Worker """ 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Worker __slots__ = () 20*cda5da8dSAndroid Build Coastguard Worker 21*cda5da8dSAndroid Build Coastguard Worker def connection_made(self, transport): 22*cda5da8dSAndroid Build Coastguard Worker """Called when a connection is made. 23*cda5da8dSAndroid Build Coastguard Worker 24*cda5da8dSAndroid Build Coastguard Worker The argument is the transport representing the pipe connection. 25*cda5da8dSAndroid Build Coastguard Worker To receive data, wait for data_received() calls. 26*cda5da8dSAndroid Build Coastguard Worker When the connection is closed, connection_lost() is called. 27*cda5da8dSAndroid Build Coastguard Worker """ 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker def connection_lost(self, exc): 30*cda5da8dSAndroid Build Coastguard Worker """Called when the connection is lost or closed. 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Worker The argument is an exception object or None (the latter 33*cda5da8dSAndroid Build Coastguard Worker meaning a regular EOF is received or the connection was 34*cda5da8dSAndroid Build Coastguard Worker aborted or closed). 35*cda5da8dSAndroid Build Coastguard Worker """ 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker def pause_writing(self): 38*cda5da8dSAndroid Build Coastguard Worker """Called when the transport's buffer goes over the high-water mark. 39*cda5da8dSAndroid Build Coastguard Worker 40*cda5da8dSAndroid Build Coastguard Worker Pause and resume calls are paired -- pause_writing() is called 41*cda5da8dSAndroid Build Coastguard Worker once when the buffer goes strictly over the high-water mark 42*cda5da8dSAndroid Build Coastguard Worker (even if subsequent writes increases the buffer size even 43*cda5da8dSAndroid Build Coastguard Worker more), and eventually resume_writing() is called once when the 44*cda5da8dSAndroid Build Coastguard Worker buffer size reaches the low-water mark. 45*cda5da8dSAndroid Build Coastguard Worker 46*cda5da8dSAndroid Build Coastguard Worker Note that if the buffer size equals the high-water mark, 47*cda5da8dSAndroid Build Coastguard Worker pause_writing() is not called -- it must go strictly over. 48*cda5da8dSAndroid Build Coastguard Worker Conversely, resume_writing() is called when the buffer size is 49*cda5da8dSAndroid Build Coastguard Worker equal or lower than the low-water mark. These end conditions 50*cda5da8dSAndroid Build Coastguard Worker are important to ensure that things go as expected when either 51*cda5da8dSAndroid Build Coastguard Worker mark is zero. 52*cda5da8dSAndroid Build Coastguard Worker 53*cda5da8dSAndroid Build Coastguard Worker NOTE: This is the only Protocol callback that is not called 54*cda5da8dSAndroid Build Coastguard Worker through EventLoop.call_soon() -- if it were, it would have no 55*cda5da8dSAndroid Build Coastguard Worker effect when it's most needed (when the app keeps writing 56*cda5da8dSAndroid Build Coastguard Worker without yielding until pause_writing() is called). 57*cda5da8dSAndroid Build Coastguard Worker """ 58*cda5da8dSAndroid Build Coastguard Worker 59*cda5da8dSAndroid Build Coastguard Worker def resume_writing(self): 60*cda5da8dSAndroid Build Coastguard Worker """Called when the transport's buffer drains below the low-water mark. 61*cda5da8dSAndroid Build Coastguard Worker 62*cda5da8dSAndroid Build Coastguard Worker See pause_writing() for details. 63*cda5da8dSAndroid Build Coastguard Worker """ 64*cda5da8dSAndroid Build Coastguard Worker 65*cda5da8dSAndroid Build Coastguard Worker 66*cda5da8dSAndroid Build Coastguard Workerclass Protocol(BaseProtocol): 67*cda5da8dSAndroid Build Coastguard Worker """Interface for stream protocol. 68*cda5da8dSAndroid Build Coastguard Worker 69*cda5da8dSAndroid Build Coastguard Worker The user should implement this interface. They can inherit from 70*cda5da8dSAndroid Build Coastguard Worker this class but don't need to. The implementations here do 71*cda5da8dSAndroid Build Coastguard Worker nothing (they don't raise exceptions). 72*cda5da8dSAndroid Build Coastguard Worker 73*cda5da8dSAndroid Build Coastguard Worker When the user wants to requests a transport, they pass a protocol 74*cda5da8dSAndroid Build Coastguard Worker factory to a utility function (e.g., EventLoop.create_connection()). 75*cda5da8dSAndroid Build Coastguard Worker 76*cda5da8dSAndroid Build Coastguard Worker When the connection is made successfully, connection_made() is 77*cda5da8dSAndroid Build Coastguard Worker called with a suitable transport object. Then data_received() 78*cda5da8dSAndroid Build Coastguard Worker will be called 0 or more times with data (bytes) received from the 79*cda5da8dSAndroid Build Coastguard Worker transport; finally, connection_lost() will be called exactly once 80*cda5da8dSAndroid Build Coastguard Worker with either an exception object or None as an argument. 81*cda5da8dSAndroid Build Coastguard Worker 82*cda5da8dSAndroid Build Coastguard Worker State machine of calls: 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker start -> CM [-> DR*] [-> ER?] -> CL -> end 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker * CM: connection_made() 87*cda5da8dSAndroid Build Coastguard Worker * DR: data_received() 88*cda5da8dSAndroid Build Coastguard Worker * ER: eof_received() 89*cda5da8dSAndroid Build Coastguard Worker * CL: connection_lost() 90*cda5da8dSAndroid Build Coastguard Worker """ 91*cda5da8dSAndroid Build Coastguard Worker 92*cda5da8dSAndroid Build Coastguard Worker __slots__ = () 93*cda5da8dSAndroid Build Coastguard Worker 94*cda5da8dSAndroid Build Coastguard Worker def data_received(self, data): 95*cda5da8dSAndroid Build Coastguard Worker """Called when some data is received. 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker The argument is a bytes object. 98*cda5da8dSAndroid Build Coastguard Worker """ 99*cda5da8dSAndroid Build Coastguard Worker 100*cda5da8dSAndroid Build Coastguard Worker def eof_received(self): 101*cda5da8dSAndroid Build Coastguard Worker """Called when the other end calls write_eof() or equivalent. 102*cda5da8dSAndroid Build Coastguard Worker 103*cda5da8dSAndroid Build Coastguard Worker If this returns a false value (including None), the transport 104*cda5da8dSAndroid Build Coastguard Worker will close itself. If it returns a true value, closing the 105*cda5da8dSAndroid Build Coastguard Worker transport is up to the protocol. 106*cda5da8dSAndroid Build Coastguard Worker """ 107*cda5da8dSAndroid Build Coastguard Worker 108*cda5da8dSAndroid Build Coastguard Worker 109*cda5da8dSAndroid Build Coastguard Workerclass BufferedProtocol(BaseProtocol): 110*cda5da8dSAndroid Build Coastguard Worker """Interface for stream protocol with manual buffer control. 111*cda5da8dSAndroid Build Coastguard Worker 112*cda5da8dSAndroid Build Coastguard Worker Event methods, such as `create_server` and `create_connection`, 113*cda5da8dSAndroid Build Coastguard Worker accept factories that return protocols that implement this interface. 114*cda5da8dSAndroid Build Coastguard Worker 115*cda5da8dSAndroid Build Coastguard Worker The idea of BufferedProtocol is that it allows to manually allocate 116*cda5da8dSAndroid Build Coastguard Worker and control the receive buffer. Event loops can then use the buffer 117*cda5da8dSAndroid Build Coastguard Worker provided by the protocol to avoid unnecessary data copies. This 118*cda5da8dSAndroid Build Coastguard Worker can result in noticeable performance improvement for protocols that 119*cda5da8dSAndroid Build Coastguard Worker receive big amounts of data. Sophisticated protocols can allocate 120*cda5da8dSAndroid Build Coastguard Worker the buffer only once at creation time. 121*cda5da8dSAndroid Build Coastguard Worker 122*cda5da8dSAndroid Build Coastguard Worker State machine of calls: 123*cda5da8dSAndroid Build Coastguard Worker 124*cda5da8dSAndroid Build Coastguard Worker start -> CM [-> GB [-> BU?]]* [-> ER?] -> CL -> end 125*cda5da8dSAndroid Build Coastguard Worker 126*cda5da8dSAndroid Build Coastguard Worker * CM: connection_made() 127*cda5da8dSAndroid Build Coastguard Worker * GB: get_buffer() 128*cda5da8dSAndroid Build Coastguard Worker * BU: buffer_updated() 129*cda5da8dSAndroid Build Coastguard Worker * ER: eof_received() 130*cda5da8dSAndroid Build Coastguard Worker * CL: connection_lost() 131*cda5da8dSAndroid Build Coastguard Worker """ 132*cda5da8dSAndroid Build Coastguard Worker 133*cda5da8dSAndroid Build Coastguard Worker __slots__ = () 134*cda5da8dSAndroid Build Coastguard Worker 135*cda5da8dSAndroid Build Coastguard Worker def get_buffer(self, sizehint): 136*cda5da8dSAndroid Build Coastguard Worker """Called to allocate a new receive buffer. 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Worker *sizehint* is a recommended minimal size for the returned 139*cda5da8dSAndroid Build Coastguard Worker buffer. When set to -1, the buffer size can be arbitrary. 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker Must return an object that implements the 142*cda5da8dSAndroid Build Coastguard Worker :ref:`buffer protocol <bufferobjects>`. 143*cda5da8dSAndroid Build Coastguard Worker It is an error to return a zero-sized buffer. 144*cda5da8dSAndroid Build Coastguard Worker """ 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker def buffer_updated(self, nbytes): 147*cda5da8dSAndroid Build Coastguard Worker """Called when the buffer was updated with the received data. 148*cda5da8dSAndroid Build Coastguard Worker 149*cda5da8dSAndroid Build Coastguard Worker *nbytes* is the total number of bytes that were written to 150*cda5da8dSAndroid Build Coastguard Worker the buffer. 151*cda5da8dSAndroid Build Coastguard Worker """ 152*cda5da8dSAndroid Build Coastguard Worker 153*cda5da8dSAndroid Build Coastguard Worker def eof_received(self): 154*cda5da8dSAndroid Build Coastguard Worker """Called when the other end calls write_eof() or equivalent. 155*cda5da8dSAndroid Build Coastguard Worker 156*cda5da8dSAndroid Build Coastguard Worker If this returns a false value (including None), the transport 157*cda5da8dSAndroid Build Coastguard Worker will close itself. If it returns a true value, closing the 158*cda5da8dSAndroid Build Coastguard Worker transport is up to the protocol. 159*cda5da8dSAndroid Build Coastguard Worker """ 160*cda5da8dSAndroid Build Coastguard Worker 161*cda5da8dSAndroid Build Coastguard Worker 162*cda5da8dSAndroid Build Coastguard Workerclass DatagramProtocol(BaseProtocol): 163*cda5da8dSAndroid Build Coastguard Worker """Interface for datagram protocol.""" 164*cda5da8dSAndroid Build Coastguard Worker 165*cda5da8dSAndroid Build Coastguard Worker __slots__ = () 166*cda5da8dSAndroid Build Coastguard Worker 167*cda5da8dSAndroid Build Coastguard Worker def datagram_received(self, data, addr): 168*cda5da8dSAndroid Build Coastguard Worker """Called when some datagram is received.""" 169*cda5da8dSAndroid Build Coastguard Worker 170*cda5da8dSAndroid Build Coastguard Worker def error_received(self, exc): 171*cda5da8dSAndroid Build Coastguard Worker """Called when a send or receive operation raises an OSError. 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker (Other than BlockingIOError or InterruptedError.) 174*cda5da8dSAndroid Build Coastguard Worker """ 175*cda5da8dSAndroid Build Coastguard Worker 176*cda5da8dSAndroid Build Coastguard Worker 177*cda5da8dSAndroid Build Coastguard Workerclass SubprocessProtocol(BaseProtocol): 178*cda5da8dSAndroid Build Coastguard Worker """Interface for protocol for subprocess calls.""" 179*cda5da8dSAndroid Build Coastguard Worker 180*cda5da8dSAndroid Build Coastguard Worker __slots__ = () 181*cda5da8dSAndroid Build Coastguard Worker 182*cda5da8dSAndroid Build Coastguard Worker def pipe_data_received(self, fd, data): 183*cda5da8dSAndroid Build Coastguard Worker """Called when the subprocess writes data into stdout/stderr pipe. 184*cda5da8dSAndroid Build Coastguard Worker 185*cda5da8dSAndroid Build Coastguard Worker fd is int file descriptor. 186*cda5da8dSAndroid Build Coastguard Worker data is bytes object. 187*cda5da8dSAndroid Build Coastguard Worker """ 188*cda5da8dSAndroid Build Coastguard Worker 189*cda5da8dSAndroid Build Coastguard Worker def pipe_connection_lost(self, fd, exc): 190*cda5da8dSAndroid Build Coastguard Worker """Called when a file descriptor associated with the child process is 191*cda5da8dSAndroid Build Coastguard Worker closed. 192*cda5da8dSAndroid Build Coastguard Worker 193*cda5da8dSAndroid Build Coastguard Worker fd is the int file descriptor that was closed. 194*cda5da8dSAndroid Build Coastguard Worker """ 195*cda5da8dSAndroid Build Coastguard Worker 196*cda5da8dSAndroid Build Coastguard Worker def process_exited(self): 197*cda5da8dSAndroid Build Coastguard Worker """Called when subprocess has exited.""" 198*cda5da8dSAndroid Build Coastguard Worker 199*cda5da8dSAndroid Build Coastguard Worker 200*cda5da8dSAndroid Build Coastguard Workerdef _feed_data_to_buffered_proto(proto, data): 201*cda5da8dSAndroid Build Coastguard Worker data_len = len(data) 202*cda5da8dSAndroid Build Coastguard Worker while data_len: 203*cda5da8dSAndroid Build Coastguard Worker buf = proto.get_buffer(data_len) 204*cda5da8dSAndroid Build Coastguard Worker buf_len = len(buf) 205*cda5da8dSAndroid Build Coastguard Worker if not buf_len: 206*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError('get_buffer() returned an empty buffer') 207*cda5da8dSAndroid Build Coastguard Worker 208*cda5da8dSAndroid Build Coastguard Worker if buf_len >= data_len: 209*cda5da8dSAndroid Build Coastguard Worker buf[:data_len] = data 210*cda5da8dSAndroid Build Coastguard Worker proto.buffer_updated(data_len) 211*cda5da8dSAndroid Build Coastguard Worker return 212*cda5da8dSAndroid Build Coastguard Worker else: 213*cda5da8dSAndroid Build Coastguard Worker buf[:buf_len] = data[:buf_len] 214*cda5da8dSAndroid Build Coastguard Worker proto.buffer_updated(buf_len) 215*cda5da8dSAndroid Build Coastguard Worker data = data[buf_len:] 216*cda5da8dSAndroid Build Coastguard Worker data_len = len(data) 217