コード例 #1
0
ファイル: connection.py プロジェクト: kgiusti/proton-tools
class Connection(object):
    """Provides network I/O for a Proton connection via a socket-like object.
    """
    def __init__(self, socket, eventHandler, name=None):
        """socket - Python socket. Expected to be configured and connected.
        name - optional name for this SocketTransport
        """
        self._name = name
        self._socket = socket
        self._pn_transport = Transport()
        self._pn_connection = Connection()
        self._pn_transport.bind(self._pn_connection)
        self._pn_transport.trace(proton.Transport.TRACE_FRM)
        self._handler = eventHandler
        self._read_done = False
        self._write_done = False
        self._next_tick = 0

        self._sasl_done = False
        self._pn_connection.open()


    def fileno(self):
        """Allows use of a Connection by the python select() call.
        """
        return self._socket.fileno()

    @property
    # @todo - hopefully remove
    def transport(self):
        return self._pn_transport

    @property
    # @todo - hopefully remove
    def connection(self):
        return self._pn_connection

    @property
    def socket(self):
        return self._socket

    @property
    def name(self):
        return self._name

    @property
    # @todo - think about server side use of this!
    def sasl(self):
        return self._pn_transport.sasl()

    def tick(self, now):
        """Invoke the transport's tick method.  'now' is seconds since Epoch.
        Returns the timestamp for the next tick, or zero if no next tick.
        """
        self._next_tick = self._pn_transport.tick(now)
        return self._next_tick

    @property
    def next_tick(self):
        """Timestamp for next call to tick()
        """
        return self._next_tick

    @property
    def need_read(self):
        """True when the Transport requires data from the network layer.
        """
        return (not self._read_done) and self._pn_transport.capacity() > 0

    @property
    def need_write(self):
        """True when the Transport has data to write to the network layer.
        """
        return (not self._write_done) and self._pn_transport.pending() > 0

    def read_input(self):
        """Read from the network layer and processes all data read.  Can
        support both blocking and non-blocking sockets.
        """
        if self._read_done:
            return None

        c = self._pn_transport.capacity()
        if c < 0:
            try:
                self._socket.shutdown(socket.SHUT_RD)
            except:
                pass
            self._read_done = True
            return None

        if c > 0:
            try:
                buf = self._socket.recv(c)
                if buf:
                    self._pn_transport.push(buf)
                    return len(buf)
                # else socket closed
                self._pn_transport.close_tail()
                self._read_done = True
                return None
            except socket.timeout, e:
                raise  # let the caller handle this
            except socket.error, e:
                err = e.args[0]
                if (err != errno.EAGAIN and
                    err != errno.EWOULDBLOCK and
                    err != errno.EINTR):
                    # otherwise, unrecoverable:
                    self._pn_transport.close_tail()
                    self._read_done = True
                raise
            except:  # beats me...