Exemplo n.º 1
0
    def pop(content, link_protocol):
        """
    Unpacks the first cell.

    :param bytes content: payload to decode
    :param int link_protocol: link protocol version

    :returns: (:class:`~stem.client.cell.Cell`, remainder) tuple

    :raises:
      * ValueError if content is malformed
      * NotImplementedError if unable to unpack this cell type
    """

        link_protocol = LinkProtocol.for_version(link_protocol)

        circ_id, content = link_protocol.circ_id_size.pop(content)
        command, content = Size.CHAR.pop(content)
        cls = Cell.by_value(command)

        if cls.IS_FIXED_SIZE:
            payload_len = FIXED_PAYLOAD_LEN
        else:
            payload_len, content = Size.SHORT.pop(content)

        if len(content) < payload_len:
            raise ValueError(
                '%s cell should have a payload of %i bytes, but only had %i' %
                (cls.NAME, payload_len, len(content)))

        payload, content = split(content, payload_len)
        return cls._unpack(payload, circ_id, link_protocol), content
Exemplo n.º 2
0
    def _pack(cls, link_protocol, payload, circ_id=None):
        """
    Provides bytes that can be used on the wire for these cell attributes.
    Format of a properly packed cell depends on if it's fixed or variable
    sized...

    ::

      Fixed:    [ CircuitID ][ Command ][ Payload ][ Padding ]
      Variable: [ CircuitID ][ Command ][ Size ][ Payload ]

    :param str name: cell command
    :param int link_protocol: link protocol version
    :param bytes payload: cell payload
    :param int circ_id: circuit id, if a CircuitCell

    :return: **bytes** with the encoded payload

    :raise: **ValueError** if cell type invalid or payload makes cell too large
    """

        if issubclass(cls, CircuitCell):
            if circ_id is None:
                raise ValueError('%s cells require a circuit identifier' %
                                 cls.NAME)
            elif circ_id < 1:
                raise ValueError(
                    'Circuit identifiers must a positive integer, not %s' %
                    circ_id)
        else:
            if circ_id is not None:
                raise ValueError(
                    '%s cells should not specify a circuit identifier' %
                    cls.NAME)

            circ_id = 0  # cell doesn't concern a circuit, default field to zero

        link_protocol = LinkProtocol.for_version(link_protocol)

        cell = bytearray()
        cell += link_protocol.circ_id_size.pack(circ_id)
        cell += Size.CHAR.pack(cls.VALUE)
        cell += b'' if cls.IS_FIXED_SIZE else Size.SHORT.pack(len(payload))
        cell += payload

        # pad fixed sized cells to the required length

        if cls.IS_FIXED_SIZE:
            if len(cell) > link_protocol.fixed_cell_len:
                raise ValueError(
                    'Cell of type %s is too large (%i bytes), must not be more than %i. Check payload size (was %i bytes)'
                    % (cls.NAME, len(cell), link_protocol.fixed_cell_len,
                       len(payload)))

            cell += ZERO * (link_protocol.fixed_cell_len - len(cell))

        return bytes(cell)
Exemplo n.º 3
0
 def __init__(self, orport, link_protocol):
     self.link_protocol = LinkProtocol.for_version(link_protocol)
     self._orport = orport
     self._orport_lock = threading.RLock()
     self._circuits = {}