| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| /** | |
| * This file is based on sshd-contrib Apache SSHD Mina project. Original commit: | |
| * https://github.com/apache/mina-sshd/commit/11b33dee37b5b9c71a40a8a98a42007e3687131e | |
| */ | |
| package com.google.gerrit.sshd; | |
| import com.google.common.flogger.FluentLogger; | |
| import java.io.IOException; | |
| import org.apache.sshd.common.AttributeRepository.AttributeKey; | |
| import org.apache.sshd.common.SshConstants; | |
| import org.apache.sshd.common.channel.Channel; | |
| import org.apache.sshd.common.channel.ChannelListener; | |
| import org.apache.sshd.common.channel.exception.SshChannelNotFoundException; | |
| import org.apache.sshd.common.session.ConnectionService; | |
| import org.apache.sshd.common.session.Session; | |
| import org.apache.sshd.common.session.helpers.DefaultUnknownChannelReferenceHandler; | |
| import org.apache.sshd.common.util.buffer.Buffer; | |
| /** | |
| * Makes sure that the referenced "unknown" channel identifier is one that was assigned in | |
| * the past. <B>Note:</B> it relies on the fact that the default {@code ConnectionService} | |
| * implementation assigns channels identifiers in ascending order. | |
| * | |
| * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a> | |
| */ | |
| public class ChannelIdTrackingUnknownChannelReferenceHandler | |
| extends DefaultUnknownChannelReferenceHandler implements ChannelListener { | |
| private static final FluentLogger logger = FluentLogger.forEnclosingClass(); | |
| public static final AttributeKey<Long> LAST_CHANNEL_ID_KEY = new AttributeKey<>(); | |
| public static final ChannelIdTrackingUnknownChannelReferenceHandler TRACKER = | |
| new ChannelIdTrackingUnknownChannelReferenceHandler(); | |
| public ChannelIdTrackingUnknownChannelReferenceHandler() { | |
| super(); | |
| } | |
| @Override | |
| public void channelInitialized(Channel channel) { | |
| long channelId = channel.getChannelId(); | |
| Session session = channel.getSession(); | |
| Long lastTracked = session.setAttribute(LAST_CHANNEL_ID_KEY, channelId); | |
| logger.atFine().log( | |
| "channelInitialized(%s) updated last tracked channel ID %s => %s", | |
| channel, lastTracked, channelId); | |
| } | |
| @Override | |
| public Channel handleUnknownChannelCommand( | |
| ConnectionService service, byte cmd, long channelId, Buffer buffer) throws IOException { | |
| Session session = service.getSession(); | |
| Long lastTracked = session.getAttribute(LAST_CHANNEL_ID_KEY); | |
| if ((lastTracked != null) && (channelId <= lastTracked.intValue())) { | |
| // Use TRACE level in order to avoid messages flooding | |
| logger.atFinest().log( | |
| "handleUnknownChannelCommand(%s) apply default handling for %s on channel=%s (lastTracked=%s)", | |
| session, SshConstants.getCommandMessageName(cmd), channelId, lastTracked); | |
| return super.handleUnknownChannelCommand(service, cmd, channelId, buffer); | |
| } | |
| throw new SshChannelNotFoundException( | |
| channelId, | |
| "Received " | |
| + SshConstants.getCommandMessageName(cmd) | |
| + " on unassigned channel " | |
| + channelId | |
| + " (last assigned=" | |
| + lastTracked | |
| + ")"); | |
| } | |
| } |