📄 ssh2channel.java
字号:
/****************************************************************************** * * Copyright (c) 1999-2003 AppGate Network Security AB. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code as * defined in and that are subject to the MindTerm Public Source License, * Version 2.0, (the 'License'). You may not use this file except in compliance * with the License. * * You should have received a copy of the MindTerm Public Source License * along with this software; see the file LICENSE. If not, write to * AppGate Network Security AB, Otterhallegatan 2, SE-41118 Goteborg, SWEDEN * *****************************************************************************/package com.mindbright.ssh2;import java.util.Vector;import java.util.Enumeration;/** * This is the abstract base class for all channels as defined in the connection * protocol spec. Each channel has a specific type (e.g. session). Each channel * type is implemented by a subclass to this class. This base class makes no * assumptions as to how data is handled by the channel it only implements * methods which are used from the multiplexing code in * <code>SSH2Connection</code>. * <p> * When implementing a new channel type or implementing an existing one * differntly from what available one typically subclasses * <code>SSH2StreamChannel</code> instead of <code>SSH2Channel</code> directly * since it implements the notion of streams (through use of * <code>java.io.InputStream</code> and <code>java.io.OutputStream</code>) and * flow control. Only a very specific implementation of a channel would need to * subclass <code>SSH2Channel</code> directly. * * @see SSH2Connection * @see SSH2StreamChannel */public abstract class SSH2Channel { public final static int STATUS_UNDEFINED = 0; public final static int STATUS_OPEN = 1; public final static int STATUS_CLOSED = 2; public final static int STATUS_FAILED = 3; protected SSH2Connection connection; protected Vector closeListeners; protected int channelType; protected int channelId; protected int peerChanId; protected int rxMaxPktSz; protected int rxInitWinSz; protected int rxCurrWinSz; protected int txInitWinSz; protected int txCurrWinSz; protected int txMaxPktSz; protected volatile boolean eofSent; protected volatile boolean eofReceived; protected volatile boolean closeReceived; protected volatile boolean closeSent; protected volatile boolean deleted; protected Object creator; protected Object openMonitor; protected int openStatus; /** * Create a new channel of the given type. The channel is * associated with an ssh connections. * * @param channelType Type of channel to create. Channel types are * defined in <code>SSH2Connection</code> and starts with * <code>CH_TYPE</code>. * @param connection The ssh connection to associate the channel with. * @param creator The object the channel is created from. */ protected SSH2Channel(int channelType, SSH2Connection connection, Object creator) { this.channelType = channelType; this.connection = connection; this.creator = creator; this.rxInitWinSz = connection.getPreferences(). getIntPreference(SSH2Preferences.RX_INIT_WIN_SZ); this.rxCurrWinSz = this.rxInitWinSz; this.rxMaxPktSz = connection.getPreferences(). getIntPreference(SSH2Preferences.RX_MAX_PKT_SZ); this.openStatus = STATUS_UNDEFINED; this.openMonitor = new Object(); connection.addChannel(this); } /** * Handle the open confirmation packet from the transport layer. * * @param pdu Confirmation packet. */ protected synchronized final void openConfirmation(SSH2TransportPDU pdu) { int peerChanId = pdu.readInt(); int txInitWinSz = pdu.readInt(); int txMaxPktSz = pdu.readInt(); init(peerChanId, txInitWinSz, txMaxPktSz); openConfirmationImpl(pdu); switch(channelType) { case SSH2Connection.CH_TYPE_FWD_TCPIP: connection.getEventHandler().localForwardedConnect(connection, (SSH2Listener)creator, this); break; case SSH2Connection.CH_TYPE_DIR_TCPIP: // Must check if creator is a SSH2Listener since it can be created // without a socket (i.e. an "internal" connection) // if(creator instanceof SSH2Listener) { connection.getEventHandler().localDirectConnect(connection, (SSH2Listener)creator, this); } break; case SSH2Connection.CH_TYPE_SESSION: connection.getEventHandler().localSessionConnect(connection, this); break; case SSH2Connection.CH_TYPE_X11: connection.getEventHandler().localX11Connect(connection, (SSH2Listener)creator, this); break; /* !!! TODO case SSH2Connection.CH_TYPE_AUTH_AGENT: connection.getEventHandler().localDirectConnect(connection, (SSH2Listener)creator, this); break; */ } synchronized (openMonitor) { this.openStatus = STATUS_OPEN; openMonitor.notifyAll(); } connection.getLog().info("SSH2Channel", "open confirmation, ch. #" + channelId + ", init-winsz = " + this.txInitWinSz + ", max-pktsz = " + this.txMaxPktSz); } /** * Called when the channel open failed. * * @param reasonCode Code which tells why the open failed. See the * ssh protocol drafts for values. * @param reasonText A text explaining why the open failed. * @param langTag Tag identifying the language of the reason text. */ protected synchronized final void openFailure(int reasonCode, String reasonText, String langTag) { closeSent = true; eofSent = true; boolean keepChannel = openFailureImpl(reasonCode, reasonText, langTag); connection.getEventHandler().localChannelOpenFailure(connection, this, reasonCode, reasonText, langTag); if(!keepChannel) { connection.delChannel(this); } synchronized (openMonitor) { this.openStatus = STATUS_FAILED; openMonitor.notifyAll(); } connection.getLog().info("SSH2Channel", "open failure on ch. #" + channelId + ", reason: " + reasonText); } /** * Handle a window adjust message. * * @param pdu The window adjust packet. */ protected final void windowAdjust(SSH2TransportPDU pdu) { int inc = pdu.readInt(); windowAdjustImpl(inc); } /** * Handle incoming data on the channel. * * @param pdu The data packet. */ protected void data(SSH2TransportPDU pdu) { } /** * Handle incoming extended data on the channel. * * @param pdu The data packet. */ protected void extData(SSH2TransportPDU pdu) { } /** * Handle incoming channel request. * * @param pdu The request packet. */ protected final void handleRequest(SSH2TransportPDU pdu) { String reqType = pdu.readJavaString(); boolean wantReply = pdu.readBoolean(); handleRequestImpl(reqType, wantReply, pdu); } /** * Handle positive request response. * * @param pdu The response packet. */ protected void requestSuccess(SSH2TransportPDU pdu) { } /** * Handle negative request response. * * @param pdu The response packet. */ protected void requestFailure(SSH2TransportPDU pdu) { } /** * Check if this channel can be terminated. The channel can be * terminated when it had sent and received the close request. */ private final void checkTermination() { if(closeSent && closeReceived && !deleted) { deleted = true; connection.delChannel(this); if(closeListeners != null) { Enumeration e = closeListeners.elements(); while(e.hasMoreElements()) { SSH2ChannelCloseListener closeListener = (SSH2ChannelCloseListener)e.nextElement(); closeListener.closed(this); } } synchronized (openMonitor) { openStatus = STATUS_CLOSED; openMonitor.notifyAll(); } } } /** * Handle the recipent of an EOF. */ protected final void recvEOF() { if(eofReceived) { connection.getLog().debug("SSH2Channel", "ch. # " + channelId + " received multiple EOFs"); } eofReceived = true; eofImpl(); if(eofSent) { sendClose(); } } /** * Handle the recipent of an channel close message. */ protected final synchronized void recvClose() { if(!closeReceived) { closeReceived = true; eofSent = true; closeImpl(); sendClose(); connection.getLog().debug("SSH2Channel", "closing ch. #" + channelId + " (" + getType() + ")"); connection.getEventHandler().channelClosed(connection, this); } checkTermination(); } /** * Send channel EOF. */ protected final void sendEOF() { if(!eofSent && !closeSent) { SSH2TransportPDU pdu = SSH2TransportPDU.createOutgoingPacket(SSH2.MSG_CHANNEL_EOF); pdu.writeInt(peerChanId); connection.transmit(pdu); eofSent = true; } } /** * Send a channel close request. */ protected final synchronized void sendClose() { if(!closeSent) { closeSent = true; SSH2TransportPDU pdu = SSH2TransportPDU.createOutgoingPacket(SSH2.MSG_CHANNEL_CLOSE); pdu.writeInt(peerChanId); connection.transmit(pdu); } checkTermination(); } protected void init(int peerChanId, int txInitWinSz, int txMaxPktSz) { int prefTxMaxPktSz = connection.getPreferences(). getIntPreference(SSH2Preferences.TX_MAX_PKT_SZ); txMaxPktSz = (txMaxPktSz > prefTxMaxPktSz ? prefTxMaxPktSz : txMaxPktSz); this.peerChanId = peerChanId; this.txInitWinSz = txInitWinSz; this.txMaxPktSz = txMaxPktSz; this.txCurrWinSz = txInitWinSz; } protected void transmit(SSH2TransportPDU pdu) { if(!closeSent) { connection.transmit(pdu); } } /** * Checks if the channel currently is open or not. * * @return The status. One of <code>STATUS_OPEN</code>, * <code>STATUS_CLOSED</code> or <code>STATUS_FAILED</code> */ public int openStatus() { synchronized (openMonitor) { if(openStatus == STATUS_UNDEFINED) { try { openMonitor.wait(); } catch (InterruptedException e) { /* don't care, someone interrupted us on purpose */ } } return openStatus; } } /** * Wait until the channel is closed. */ public void waitUntilClosed() { synchronized (openMonitor) { while(openStatus != STATUS_CLOSED) { try { openMonitor.wait(); } catch (InterruptedException e) { /* don't care, someone interrupted us on purpose */ } } } } /** * Close the channel. */ public final synchronized void close() { if(!connection.getTransport().isConnected()) { recvClose(); } sendClose(); } /** * Get the type of channel. * * @return The channel type. */ public String getType() { return SSH2Connection.channelTypes[channelType]; } /** * Get the local id of the channel. * * @return The local channel id. */ public int getId() { return channelId; } /** * Get the peer if of the channel. * * @return The peer channel id. */ public int getPeerId() { return peerChanId; } /** * Get the channel creator object reference. * * @return The channel creator. */ public Object getCreator() { return creator; } /** * Get the connection a channel is using. * * @return The connection object. */ public SSH2Connection getConnection() { return connection; } /** * Channel specific handling of open confirmations. * * @param pdu Confirmation packet. */ protected abstract void openConfirmationImpl(SSH2TransportPDU pdu); /** * Channel specific handling of open failures. * * @param reasonCode Code which tells why the open failed. See the * ssh protocol drafts for values. * @param reasonText A text explaining why the open failed. * @param langTag Tag identifying the language of the reason text. */ protected abstract boolean openFailureImpl(int reasonCode, String reasonText, String langTag); /** * Channel specific implementation of window adjust messages. * * @param inc The amount to increase the window with. */ protected abstract void windowAdjustImpl(int inc); /** * Channel specific handler for the recipent of an EOF. */ protected abstract void eofImpl(); /** * Channel specific handler for the recipent of a channel close message. */ protected abstract void closeImpl(); /** * Channel specific handler for incoming channel requests. * * @param reqType The type of request. * @param wantReply True if an reply is expected. * @param pdu The actual channel request. */ protected abstract void handleRequestImpl(String reqType, boolean wantReply, SSH2TransportPDU pdu); /** * Add a listener which is notified when the channel is closed. * * @param closeListener The listener to add. */ public final void addCloseListener(SSH2ChannelCloseListener closeListener) { if(closeListeners == null) { closeListeners = new Vector(); } closeListeners.removeElement(closeListener); closeListeners.addElement(closeListener); } /** * Remove a listener which were to be notified when the channel * were closed. * * @param closeListener The listener to remove. */ public void removeCloseListener(SSH2ChannelCloseListener closeListener) { if(closeListeners != null) { closeListeners.removeElement(closeListener); if(closeListeners.size() == 0) { closeListeners = null; } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -