/// <summary> /// Process packet about this channel. /// </summary> /// <param name="packetType">a packet type (message number)</param> /// <param name="packetFragment">a packet image except message number and recipient channel.</param> public void ProcessPacket(SSH2PacketType packetType, DataFragment packetFragment) { if (_state == State.Closed) { return; // ignore } DataFragment dataFragmentArg; uint dataTypeCodeArg; lock (_stateSync) { switch (_state) { case State.InitiatedByServer: break; case State.InitiatedByClient: if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { SSH2DataReader reader = new SSH2DataReader(packetFragment); RemoteChannel = reader.ReadUInt32(); _serverWindowSizeLeft = reader.ReadUInt32(); _serverMaxPacketSize = reader.ReadUInt32(); _state = State.Established; Monitor.PulseAll(_stateSync); // notifies state change dataFragmentArg = reader.GetRemainingDataView(); goto OnEstablished; // do it out of the lock block } if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) { SSH2DataReader reader = new SSH2DataReader(packetFragment); uint reasonCode = reader.ReadUInt32(); string description = reader.ReadUTF8String(); string lang = reader.ReadString(); goto RequestFailed; // do it out of the lock block } break; case State.Closing: if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_CLOSE) { goto SetStateClosedByClient; // do it out of the lock block } break; case State.Established: case State.Ready: if (ProcessPacketSub(packetType, packetFragment) == SubPacketProcessResult.Consumed) { return; } switch (packetType) { case SSH2PacketType.SSH_MSG_CHANNEL_DATA: { SSH2DataReader reader = new SSH2DataReader(packetFragment); int len = reader.ReadInt32(); dataFragmentArg = reader.GetRemainingDataView(len); AdjustWindowSize(len); } goto OnData; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { SSH2DataReader reader = new SSH2DataReader(packetFragment); dataTypeCodeArg = reader.ReadUInt32(); int len = reader.ReadInt32(); dataFragmentArg = reader.GetRemainingDataView(len); AdjustWindowSize(len); } goto OnExtendedData; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: { SSH2DataReader reader = new SSH2DataReader(packetFragment); string request = reader.ReadString(); bool wantReply = reader.ReadBool(); if (wantReply) { //we reject unknown requests including keep-alive check Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) .WriteUInt32(RemoteChannel) ); } } break; case SSH2PacketType.SSH_MSG_CHANNEL_EOF: goto OnEOF; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE: Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_CLOSE) .WriteUInt32(RemoteChannel) ); goto SetStateClosedByServer; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST: { SSH2DataReader reader = new SSH2DataReader(packetFragment); uint bytesToAdd = reader.ReadUInt32(); // some servers may not send SSH_MSG_CHANNEL_WINDOW_ADJUST. // it is dangerous to wait this message in send procedure _serverWindowSizeLeft += bytesToAdd; } goto OnWindowAdjust; case SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS: case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: { _channelRequestResult.TrySet(packetType == SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS, 1000); } break; default: goto OnUnhandledPacket; } break; // case State.Ready } } return; OnEstablished: _protocolEventManager.Trace( "CH[{0}] remoteCH={1} remoteWindowSize={2} remoteMaxPacketSize={3}", LocalChannel, RemoteChannel, _serverWindowSizeLeft, _serverMaxPacketSize); _handler.OnEstablished(dataFragmentArg); OnChannelEstablished(); return; RequestFailed: _protocolEventManager.Trace("CH[{0}] request failed", LocalChannel); RequestFailed(); return; SetStateClosedByClient: _protocolEventManager.Trace("CH[{0}] closed completely", LocalChannel); SetStateClosed(false); return; SetStateClosedByServer: _protocolEventManager.Trace("CH[{0}] closed by server", LocalChannel); SetStateClosed(true); return; OnData: _handler.OnData(dataFragmentArg); return; OnExtendedData: _handler.OnExtendedData(dataTypeCodeArg, dataFragmentArg); return; OnEOF: _protocolEventManager.Trace("CH[{0}] caught EOF", LocalChannel); _handler.OnEOF(); return; OnWindowAdjust: _protocolEventManager.Trace( "CH[{0}] adjusted remote window size to {1}", LocalChannel, _serverWindowSizeLeft); return; OnUnhandledPacket: _handler.OnUnhandledPacket((byte)packetType, packetFragment); return; }
private void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader re) { switch (pt) { case SSH2PacketType.SSH_MSG_CHANNEL_DATA: { int len = re.ReadInt32(); DataFragment frag = re.GetRemainingDataView(len); receiver.OnData(frag.Data, frag.Offset, frag.Length); } break; case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { int t = re.ReadInt32(); byte[] data = re.ReadByteString(); receiver.OnExtendedData(t, data); } break; case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: { string request = re.ReadString(); bool reply = re.ReadBool(); if (request == "exit-status") { int status = re.ReadInt32(); } else if (reply) { //we reject unknown requests including keep-alive check Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) .WriteInt32(_remoteID) ); } } break; case SSH2PacketType.SSH_MSG_CHANNEL_EOF: receiver.OnChannelEOF(); break; case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE: _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); receiver.OnChannelClosed(); break; case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } break; default: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } Debug.WriteLine("Unknown Packet " + pt); break; } }