Esempio n. 1
0
 async def closeConnection(self, connection: Connection, reason: Optional[str]=None) -> None:
     '''
     End and close an existing connection:
     Acknowledge or inform the peer about EOF, then close.
     '''
     if connection and not connection.writer.transport.is_closing():
         # Tell transport the reason
         if reason:
             await self.send_message(reason, connection)
         try:
             connection.state['closed'] = time.time()
             if connection.reader.at_eof():
                 self.logger.debug('Transport closed by peer')
                 connection.reader.feed_eof()
                 await self.handlePeerDisconnect(connection)
             else:
                 self.logger.debug(f'Transport closed by {self.name}')
                 if connection.writer.can_write_eof(): connection.writer.write_eof()
             await asyncio.sleep(.1)
             connection.writer.close()
             await connection.writer.wait_closed()
         except:
             pass
         finally:
             # Make sure we set this in any case
             if not connection.state['closed']:
                 connection.state['closed'] = time.time()
             self.logger.debug('Transport writer closed')
Esempio n. 2
0
 def _assembleConnection(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> Connection:
     '''
     Template method: Assemble a connection object based on the info we get from the reader/writer.
     Might be overridden by a subclass method to set different parameters
     '''
     return Connection(
         socket=writer.get_extra_info('socket'),
         sslctx=None,
         sslobj=None,
         pid=None,
         uid=None,
         gid=None,
         cert=None,
         peer_address=None,
         host_address=None,
         reader=reader,
         writer=writer,
         read_handlers=set(),
         write_handlers=set(),
         state={
             'mode': self.mode or ConnectionType.PERSISTENT,
             'created': time.time(),
             'updated': time.time(),
             'closed': None
             }
         )
Esempio n. 3
0
 def _assembleConnection(self, reader: asyncio.StreamReader,
                         writer: asyncio.StreamWriter) -> Connection:
     sock = writer.get_extra_info('socket')
     credentials = sock.getsockopt(socket.SOL_SOCKET, socket.SO_PEERCRED,
                                   struct.calcsize('3i'))
     pid, uid, gid = struct.unpack('3i', credentials)
     return Connection(socket=sock,
                       sslctx=writer.get_extra_info('sslcontext')
                       if self.sslctx else None,
                       sslobj=writer.get_extra_info('ssl_object')
                       if self.sslctx else None,
                       pid=pid,
                       uid=uid,
                       gid=gid,
                       peer_cert=writer.get_extra_info('peercert')
                       if self.sslctx else None,
                       peer_address=None,
                       host_address=None,
                       reader=reader,
                       writer=writer,
                       read_handlers=set(),
                       write_handlers=set(),
                       state={
                           'mode': self.mode or ConnectionType.PERSISTENT,
                           'created': time.time(),
                           'updated': time.time(),
                           'closed': None
                       })
Esempio n. 4
0
 def _assembleConnection(self, reader: asyncio.StreamReader,
                         writer: asyncio.StreamWriter) -> Connection:
     sock = writer.get_extra_info('socket')
     return Connection(socket=sock,
                       sslctx=writer.get_extra_info('sslcontext')
                       if self.sslctx else None,
                       sslobj=writer.get_extra_info('ssl_object')
                       if self.sslctx else None,
                       pid=os.getpid(),
                       uid=os.getuid(),
                       gid=os.getgid(),
                       peer_cert=writer.get_extra_info('peercert')
                       if self.sslctx else None,
                       peer_address=sock.getpeername(),
                       host_address=sock.getsockname(),
                       reader=reader,
                       writer=writer,
                       read_handlers=set(),
                       write_handlers=set(),
                       state={
                           'mode': self.mode or ConnectionType.PERSISTENT,
                           'created': time.time(),
                           'updated': time.time(),
                           'closed': None
                       })
Esempio n. 5
0
    async def _handleConnection(self, connection: Connection) -> None:
        '''
        Handle the connection and listen for incoming messages until we receive an EOF.
        '''
        try:
            # Authenticate
            auth = await self.authenticateConnection(connection)
            if auth:
                self.logger.debug(
                    'Client connection was successfully authenticated')
            else:
                await self.rejectConnection(connection,
                                            'Could not authenticate')
                return

            # Read data depending on the connection type and handle it
            raw = None
            chunks = 0
            chunksize = self.chunksize
            while not connection.reader.at_eof():
                try:
                    # Update the connection
                    connection.state['updated'] = time.time()

                    # Read up to the limit or as many chunks until the limit
                    if self.chunksize:
                        # Make sure we read as many chunks till reaching the limit
                        if self.limit:
                            chunksize = min(self.limit, self.chunksize)
                            consumed = chunks * self.chunksize
                            rest = self.limit - consumed
                            if self.limit == chunksize and chunks > 0:
                                self.logger.error(
                                    f'Set message size limit of {self.limit} bytes is smaller than chunksize {chunksize}. Closing connection.'
                                )
                                break
                            if rest <= 0:
                                self.logger.debug(
                                    f'Total message size limit of {self.limit} bytes reached. Closing connection.'
                                )
                                break
                            chunksize = chunksize if rest > chunksize else rest
                        raw = await connection.reader.read(chunksize)
                        chunks += 1
                    # Read line by line (Respecting set limit)
                    elif self.lines:
                        try:
                            raw = await connection.reader.readuntil(
                                separator=self.line_separator.encode())
                        except asyncio.LimitOverrunError as e:
                            raw = await connection.reader.read(
                                e.consumed + len(self.line_separator.encode()))
                            await self.handleLimitExceedance(
                                connection, raw, True)
                            continue
                        except asyncio.IncompleteReadError as e:
                            if len(e.partial) > 0:
                                raw = e.partial
                            else:
                                continue
                        except asyncio.CancelledError as e:
                            raise e
                        except Exception as e:
                            continue
                    # Default read (Respecting set limit)
                    else:
                        raw = await connection.reader.read(self.limit or -1)

                    # Handle the received message or message fragment
                    if raw and not len(raw) == 0:
                        message = Message(data=raw, sender=connection)
                        # Never launch another message handler while we're being shutdown (this task getting already cancelled)
                        if not self._shutdown and not connection.state[
                                'closed']:
                            reader = asyncio.ensure_future(
                                self.handleMessage(message), loop=self.loop)
                            reader.add_done_callback(
                                lambda task: connection.read_handlers.remove(
                                    task) if connection.read_handlers and task
                                in connection.read_handlers else None)
                            connection.read_handlers.add(reader)
                except asyncio.CancelledError:
                    return  # We return as the connection closing is handled by self.close()
                except Exception as e:
                    self.logger.error(f'Transport error ({e})')
        except asyncio.CancelledError:
            return  # We return as the connection closing is handled by self.close()
        except ConnectionError as e:
            await self.handleConnectionFailure(connection)
            return
        except Exception as e:
            self.logger.error(f'Transport error ({e})')

        # Close the connection (It will be automatically removed from the pool)
        await self.closeConnection(connection)