src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -166,6 +166,7 @@ run.set(false); try { ((SshCommandFactory) sshd.getCommandFactory()).stop(); sshd.stop(); } catch (InterruptedException e) { log.error("SSH Daemon stop interrupted", e); src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java
@@ -48,6 +48,14 @@ private static final Logger log = LoggerFactory.getLogger(BaseCommand.class); private static final int PRIVATE_STATUS = 1 << 30; public final static int STATUS_CANCEL = PRIVATE_STATUS | 1; public final static int STATUS_NOT_FOUND = PRIVATE_STATUS | 2; public final static int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3; protected InputStream in; protected OutputStream out; @@ -86,6 +94,8 @@ @Override public void destroy() { log.debug("destroying " + getClass().getName()); session = null; ctx = null; } src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -48,20 +48,34 @@ private List<String> args = new ArrayList<String>(); private final Set<Class<? extends BaseCommand>> commands; private final Map<String, DispatchCommand> dispatchers; private final List<BaseCommand> instantiated; private Map<String, Class<? extends BaseCommand>> map; private Map<String, BaseCommand> dispatchers; protected DispatchCommand() { commands = new HashSet<Class<? extends BaseCommand>>(); dispatchers = Maps.newHashMap(); instantiated = new ArrayList<BaseCommand>(); } @Override public void destroy() { super.destroy(); commands.clear(); map = null; for (BaseCommand command : instantiated) { command.destroy(); } for (DispatchCommand dispatcher : dispatchers.values()) { dispatcher.destroy(); } } protected void registerDispatcher(UserModel user, Class<? extends DispatchCommand> cmd) { if (!cmd.isAnnotationPresent(CommandMetaData.class)) { throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), CommandMetaData.class.getName())); } if (dispatchers == null) { dispatchers = Maps.newHashMap(); } CommandMetaData meta = cmd.getAnnotation(CommandMetaData.class); @@ -108,10 +122,9 @@ CommandMetaData meta = cmd.getAnnotation(CommandMetaData.class); map.put(meta.name(), cmd); } if (dispatchers != null) { for (Map.Entry<String, BaseCommand> entry : dispatchers.entrySet()) { for (Map.Entry<String, DispatchCommand> entry : dispatchers.entrySet()) { map.put(entry.getKey(), entry.getValue().getClass()); } } } return map; @@ -163,6 +176,7 @@ BaseCommand cmd = null; try { cmd = c.newInstance(); instantiated.add(cmd); } catch (Exception e) { throw new UnloggedFailure(1, MessageFormat.format("Failed to instantiate {0} command", commandName)); } src/main/java/com/gitblit/transport/ssh/commands/SshCommandFactory.java
@@ -20,6 +20,8 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,6 +41,7 @@ import com.gitblit.utils.IdGenerator; import com.gitblit.utils.WorkQueue; import com.google.common.util.concurrent.Atomics; import com.google.common.util.concurrent.ThreadFactoryBuilder; /** * @@ -50,6 +53,7 @@ private final IGitblit gitblit; private final ScheduledExecutorService startExecutor; private final ExecutorService destroyExecutor; public SshCommandFactory(IGitblit gitblit, IdGenerator idGenerator) { this.gitblit = gitblit; @@ -57,6 +61,15 @@ int threads = 2;// cfg.getInt("sshd","commandStartThreads", 2); WorkQueue workQueue = new WorkQueue(idGenerator); startExecutor = workQueue.createQueue(threads, "SshCommandStart"); destroyExecutor = Executors.newSingleThreadExecutor( new ThreadFactoryBuilder() .setNameFormat("SshCommandDestroy-%s") .setDaemon(true) .build()); } public void stop() { destroyExecutor.shutdownNow(); } public RootDispatcher createRootDispatcher(SshDaemonClient client, String commandLine) { @@ -166,27 +179,23 @@ } private int translateExit(final int rc) { return rc; // // switch (rc) { // case BaseCommand.STATUS_NOT_ADMIN: // return 1; // // case BaseCommand.STATUS_CANCEL: // return 15 /* SIGKILL */; // // case BaseCommand.STATUS_NOT_FOUND: // return 127 /* POSIX not found */; // // default: // return rc; // } switch (rc) { case BaseCommand.STATUS_NOT_ADMIN: return 1; case BaseCommand.STATUS_CANCEL: return 15 /* SIGKILL */; case BaseCommand.STATUS_NOT_FOUND: return 127 /* POSIX not found */; default: return rc; } } private void log(final int rc) { if (logged.compareAndSet(false, true)) { // log.onExecute(cmd, rc); logger.info("onExecute: {} exits with: {}", cmd.getClass().getSimpleName(), rc); } } @@ -196,27 +205,22 @@ Future<?> future = task.getAndSet(null); if (future != null) { future.cancel(true); // destroyExecutor.execute(new Runnable() { // @Override // public void run() { // onDestroy(); // } // }); destroyExecutor.execute(new Runnable() { @Override public void run() { onDestroy(); } }); } } @SuppressWarnings("unused") private void onDestroy() { synchronized (this) { if (cmd != null) { // final Context old = sshScope.set(ctx); try { cmd.destroy(); // log(BaseCommand.STATUS_CANCEL); } finally { // ctx = null; cmd = null; // sshScope.set(old); } } } src/main/java/com/gitblit/transport/ssh/git/BaseGitCommand.java
@@ -44,6 +44,16 @@ protected Repository repo; @Override public void destroy() { super.destroy(); repositoryResolver = null; receivePackFactory = null; uploadPackFactory = null; repo = null; } @Override public void start(final Environment env) { startThread(new RepositoryCommandRunnable() { @Override src/main/java/com/gitblit/transport/ssh/git/GitDispatcher.java
@@ -44,6 +44,15 @@ } @Override public void destroy() { super.destroy(); repositoryResolver = null; receivePackFactory = null; uploadPackFactory = null; } @Override protected void registerCommands(UserModel user) { registerCommand(user, Upload.class); registerCommand(user, Receive.class);