blob: d3760cf84cee0760fcd24eec23bd6e6edb74509a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 xored software, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.ssh.internal.core;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jsch.core.IJSchService;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
public class ChannelPool {
private final String userName;
private final int port;
private final String hostName;
private String password;
private Session session;
private final List<ChannelSftp> freeChannels = new ArrayList<ChannelSftp>();
private final Map<ChannelSftp, ChannelUsageInfo> usedChannels = new IdentityHashMap<ChannelSftp, ChannelUsageInfo>();
private static class ChannelUsageInfo {
private final Object context;
public ChannelUsageInfo(Object context) {
this.context = context;
}
}
/**
* @param userName
* @param hostName
* @param port
*/
public ChannelPool(String userName, String hostName, int port) {
this.userName = userName;
this.hostName = hostName;
this.port = port;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
private final class LocalUserInfo implements UserInfo,
UIKeyboardInteractive {
public void showMessage(String arg0) {
}
public boolean promptYesNo(String arg0) {
return false;
}
public boolean promptPassword(String arg0) {
return true;
}
public boolean promptPassphrase(String arg0) {
return false;
}
public String getPassword() {
return password;
}
public String getPassphrase() {
return ""; //$NON-NLS-1$
}
public String[] promptKeyboardInteractive(String destination,
String name, String instruction, String[] prompt, boolean[] echo) {
final String p = password;
return p != null ? new String[] { p } : null;
}
}
protected synchronized void connectSession() throws JSchException {
if (session == null) {
IJSchService service = Activator.getDefault().getJSch();
session = service.createSession(hostName, port, userName);
session.setTimeout(0);
session.setServerAliveInterval(300000);
session.setServerAliveCountMax(6);
session.setPassword(password); // Set password
// directly
UserInfo ui = new LocalUserInfo();
session.setUserInfo(ui);
}
if (!session.isConnected()) {
// Connect with default timeout
session.connect(60 * 1000);
}
}
protected ChannelSftp acquireChannel(final Object context, int tryCount) {
for (;;) {
try {
return acquireChannel(context);
} catch (JSchException ex) {
Activator.log(ex);
if (--tryCount <= 0) {
return null;
}
}
}
}
protected synchronized ChannelSftp acquireChannel(Object context)
throws JSchException {
try {
connectSession();
while (!freeChannels.isEmpty()) {
final ChannelSftp channel = freeChannels.remove(freeChannels
.size() - 1);
if (channel.isConnected()) {
usedChannels.put(channel, createUsageInfo(context));
return channel;
}
}
final ChannelSftp channel = (ChannelSftp) session
.openChannel("sftp"); //$NON-NLS-1$
if (!channel.isConnected()) {
channel.connect();
}
usedChannels.put(channel, createUsageInfo(context));
return channel;
} catch (JSchException e) {
// String eToStr = e.toString();
boolean needLog = true;
// if (eToStr.indexOf("Auth cancel") >= 0 || eToStr.indexOf("Auth fail") >= 0 || eToStr.indexOf("session is down") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
// if (session.isConnected()) {
// session.disconnect();
// session = null;
// }
// }
disconnect();
if (needLog) {
Activator.error("Failed to create direct connection", e); //$NON-NLS-1$
}
throw e;
// if (session != null) {
// session.disconnect();
// session = null;
// }
}
}
/**
* @return
*/
private ChannelUsageInfo createUsageInfo(Object context) {
return new ChannelUsageInfo(context);
}
protected void releaseChannel(ChannelSftp channel) {
usedChannels.remove(channel);
freeChannels.add(channel);
}
public void disconnect() {
for (ChannelSftp channel : freeChannels) {
channel.disconnect();
}
freeChannels.clear();
// TODO log used connections
for (Map.Entry<ChannelSftp, ChannelUsageInfo> entry : usedChannels
.entrySet()) {
entry.getKey().disconnect();
}
usedChannels.clear();
if (session != null) {
session.disconnect();
session = null;
}
}
public boolean isConnected() {
return session != null && session.isConnected();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((hostName == null) ? 0 : hostName.hashCode());
result = prime * result + port;
result = prime * result
+ ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChannelPool other = (ChannelPool) obj;
if (hostName == null) {
if (other.hostName != null)
return false;
} else if (!hostName.equals(other.hostName))
return false;
if (port != other.port)
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
}