0x0000000000000000
  #   !ˆl–ßi~”*_)â€ÀŠãO)‹FÿÎ„i×ž¿Ì ?÷     !# Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
#
# This file is part of paramiko.
#
# Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.

"""
Abstraction for an SSH2 channel.
"""

import binascii
import os
import socket
import time
import threading
from functools import wraps

from paramiko import util
from paramiko.common import cMSG_CHANNEL_REQUEST, cMSG_CHANNEL_WINDOW_ADJUST, \
    cMSG_CHANNEL_DATA, cMSG_CHANNEL_EXTENDED_DATA, DEBUG, ERROR, \
    cMSG_CHANNEL_SUCCESS, cMSG_CHANNEL_FAILURE, cMSG_CHANNEL_EOF, \
    cMSG_CHANNEL_CLOSE
from paramiko.message import Message
from paramiko.py3compat import bytes_types
from paramiko.ssh_exception import SSHException
from paramiko.file import BufferedFile
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
from paramiko import pipe
from paramiko.util import ClosingContextManager


def open_only(func):
    """
    Decorator for `.Channel` methods which performs an openness check.

    :raises SSHException:
        If the wrapped method is called on an unopened `.Channel`.
    """
    @wraps(func)
    def _check(self, *args, **kwds):
        if (
            self.closed
            or self.eof_received
            or self.eof_sent
            or not self.active
        ):
            raise SSHException('Channel is not open')
        return func(self, *args, **kwds)
    return _check


class Channel (ClosingContextManager):
    """
    A secure tunnel across an SSH `.Transport`.  A Channel is meant to behave
    like a socket, and has an API that should be indistinguishable from the
    Python socket API.

    Because SSH2 has a windowing kind of flow control, if you stop reading data
    from a Channel and its buffer fills up, the server will be unable to send
    you any more data until you read some of it.  (This won't affect other
    channels on the same transport -- all channels on a single transport are
    flow-controlled independently.)  Similarly, if the server isn't reading
    data you send, calls to `send` may block, unless you set a timeout.  This
    is exactly like a normal network socket, so it shouldn't be too surprising.
    
    Instances of this class may be used as context managers.
    """

    def __init__(self, chanid):
        """
        Create a new channel.  The channel is not associated with any
        particular session or `.Transport` until the Transport attaches it.
        Normally you would only call this method from the constructor of a
        subclass of `.Channel`.

        :param int chanid:
            the ID of this channel, as passed by an existing `.Transport`.
        """
        #: Channel ID
        self.chanid = chanid
        #: Remote channel ID
        self.remote_chanid = 0
        #: `.Transport` managing this channel
        self.transport = None
        #: Whether the connection is presently active
        self.active = False
        self.eof_received = 0
        self.eof_sent = 0
        self.in_buffer = BufferedPipe()
        self.in_stderr_buffer = BufferedPipe()
        self.timeout = None
        #: Whether the connection has been closed
        self.closed = False
        self.ultra_debug = False
        self.lock = threading.Lock()
        self.out_buffer_cv = threading.Condition(self.lock)
        self.in_window_size = 0
        self.out_window_size = 0
        self.in_max