I need to execute(run) a shell script which resides in the server(Solaris) from java. Please help me how to execute a file from java.? I have tried with sendCommand() of TelnetToClient. So please help me in running a file from my GUI.
The program goes like this.
TelnetToPort tele = new TelnetToPort("opmer3");
tele.login("root","root");
String command_ = "/usr/bin/bash /opt/nrl/logs/applications/ns/lccommands.sh";
tele.runComm(command_);
If you are looking for optimized solution for executing any scripts for your java class, then you can use Jsch with Google Expect4j libraries.
For jsch, go to http://www.jcraft.com/jsch/
For Expect4j, go to http://code.google.com/p/expect4j/
Following is small code sample for log in and executing file fro remote java class.
private Expect4j SSH(String hostname, String username,String password, int port) throws Exception {
JSch jsch = new JSch();
Session session = jsch.getSession(username, hostname, port);
if (password != null) {
session.setPassword(password);
}
Hashtable<String,String> config = new Hashtable<String,String>();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(60000);
channel = (ChannelShell) session.openChannel("shell");
Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
channel.connect();
return expect;
}
This method will open up SSH stream to remote server which will be used by expect4j for sending commands.
private boolean executeCommands() {
boolean isSuccess = true;
Closure closure = new Closure() {
public void run(ExpectState expectState) throws Exception {
buffer.append(expectState.getBuffer());
expectState.exp_continue();
}
};
List<Match> lstPattern = new ArrayList<Match>();
String[] regEx = SSHConstants.linuxPromptRegEx;
if (regEx != null && regEx.length > 0) {
synchronized (regEx) {
for (String regexElement : regEx) {//list of regx like, :>, /> etc. it is possible command prompts of your remote machine
try {
RegExpMatch mat = new RegExpMatch(regexElement, closure);
lstPattern.add(mat);
} catch (MalformedPatternException e) {
return false;
} catch(Exception e) {
return false;
}
}
lstPattern.add(new EofMatch( new Closure() { // should cause entire page to be collected
public void run(ExpectState state) {
}
}));
lstPattern.add(new TimeoutMatch(defaultTimeOut, new Closure() {
public void run(ExpectState state) {
}
}));
}
}
try {
Expect4j expect = SSH(objConfig.getHostAddress(), objConfig.getUserName(), objConfig.getPassword(), SSHConstants.SSH_PORT);
expect.setDefaultTimeout(defaultTimeOut);
if(isSuccess) {
for(String strCmd : lstCmds)
isSuccess = isSuccess(lstPattern,strCmd);
}
boolean isFailed = checkResult(expect.expect(lstPattern));
return !isFailed;
} catch (Exception ex) {
return false;
} finally {
closeConnection();
}
}
private boolean isSuccess(List<Match> objPattern,String strCommandPattern) {
try {
boolean isFailed = checkResult(expect.expect(objPattern));
if (!isFailed) {
expect.send(strCommandPattern);
expect.send("\r");
return true;
}
return false;
} catch (MalformedPatternException ex) {
return false;
} catch (Exception ex) {
return false;
}
}
Hope this help.
Thanks.
new ProcessBuilder("ssh", "root#opmer3", command_).start();
Related
I would like to stop my current transfer file with using method stopUpload() :
private ChannelSftp channelSftp
private ChannelSftp setupJsch() throws JSchException {
JSch jsch = new JSch();
jsch.setKnownHosts("/Users/john/.ssh/known_hosts");
Session jschSession = jsch.getSession(username, remoteHost);
jschSession.setPassword(password);
jschSession.connect();
return (ChannelSftp) jschSession.openChannel("sftp");
}
public void stopUpload()
{
channelSftp.disconnect();
}
public void whenUploadFileUsingJsch_thenSuccess() throws JSchException, SftpException {
ChannelSftp channelSftp = setupJsch();
channelSftp.connect();
String localFile = "src/main/resources/sample.txt";
String remoteDir = "remote_sftp_test/";
channelSftp.put(localFile, remoteDir + "jschFile.txt");
channelSftp.exit();
}
When stopUpload() run I have this error : Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
To cleanly cancel a JSch SFTP transfer, when you need, implement the SftpProgressMonitor interface:
public class CancellableProgressMonitor implements SftpProgressMonitor {
private boolean cancelled;
public CancellableProgressMonitor() {}
public void cancel() {
this.cancelled = true;
}
public bool wasCancelled() {
return this.cancelled;
}
public void init(int op, java.lang.String src, java.lang.String dest, long max) {
this.cancelled = false;
}
public boolean count(long bytes) {
return !this.cancelled;
}
public void end() {
}
}
And pass it to ChannelSftp.put:
CancellableProgressMonitor monitor = new CancellableProgressMonitor()
channelSftp.put(localFile, remoteDir + "jschFile.txt", monitor);
Call monitor.cancel() when you need to cancel the transfer.
public void stopUpload() {
monitor.cancel();
}
If you want to cleanup the partially transferred file:
String remoteFile = remoteDir + "jschFile.txt";
try {
channelSftp.put(localFile, remoteFile, monitor);
} catch (IOException e) {
if (monitor.wasCancelled() && channelSftp.getSession().isConnected()) {
try {
channelSftp.rm(remoteFile);
} catch (SftpException e) {
if (e.id == SSH_FX_NO_SUCH_FILE) {
// can happen if the transfer was cancelled
// before the file was even created
} else {
throw e;
}
}
}
throw e;
}
I have written a code to download file from the Remote machine through SFTP and it is working fine if I provide
sftpBean.downloadFile("/dd1.csv","C:\\test\\SFTP_1");
Filename and the directory where I want to download the file which is C drive.
My requirement is let say If I have multiple folder in side my sftproot(The folder which I shared for SFTP access) folder how can i traverse inside and outside the folder/directory and download the list of (for example all .CSV)files from that location.
Thanks in advance for your help.
*****************************************************************************
**This is the code that have logic.**
package sftp.bean;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
//class using for sftp function
public class SFTPBean {
// variable for sftp channel
private JSch mJschSession = null;
private Session mSSHSession = null;
// sftp channel
private ChannelSftp mChannelSftp = null;
// connect fucntion let connect to sftp server
public boolean connect(String strHostAddress, int iPort,
String strUserName, String strPassword) {
boolean blResult = false;
try {
// creating a new jsch session
this.mJschSession = new JSch();
// set sftp server no check key when login
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
this.mJschSession.setConfig(config);
// creating session with user, host port
this.mSSHSession = mJschSession.getSession(strUserName,
strHostAddress, iPort);
// set password
this.mSSHSession.setPassword(strPassword);
// connect to host
this.mSSHSession.connect();
// open sftp channel
this.mChannelSftp = (ChannelSftp) this.mSSHSession
.openChannel("sftp");
// connect to sftp session
this.mChannelSftp.connect();
if (this.mChannelSftp != null) {
blResult = true;
}
} catch (Exception exp) {
exp.printStackTrace();
}
return blResult;
}
// list file on sftp server
public Vector<LsEntry> listFile(String strPath) {
Vector<LsEntry> vtFile = null;
try {
vtFile = this.mChannelSftp.ls(strPath);
} catch (Exception exp) {
exp.printStackTrace();
}
return vtFile;
}
// download file
public boolean downloadFile(String strSftpFile, String strLocalFile) {
boolean blResult = false;
try {
this.mChannelSftp.get(strSftpFile, strLocalFile);
blResult = true;
} catch (Exception exp) {
exp.printStackTrace();
}
return blResult;
}
// upload file
public boolean uploadFile(String strLocalFile, String strSftpFile) {
boolean blResult = false;
try {
this.mChannelSftp.put(strLocalFile, strSftpFile);
blResult = true;
} catch (Exception exp) {
exp.printStackTrace();
}
return blResult;
}
// close session
public void close() {
try {
this.mChannelSftp.disconnect();
} catch (Exception exp) {
}
try {
this.mSSHSession.disconnect();
} catch (Exception exp) {
}
this.mChannelSftp = null;
this.mSSHSession = null;
this.mJschSession = null;
}
}
*************************************************************************
**this the code having main method to run the upper code :**
package sftp.main.demo;
import java.util.Vector;
import sftp.bean.SFTPBean;
import com.jcraft.jsch.ChannelSftp.LsEntry;
public class SFTPMainDemo {
// main class let exec demo
public static void main(String[] args) {
// TODO Auto-generated method stub
// now we start up run
SFTPBean sftpBean = new SFTPBean();
boolean blResult = sftpBean.connect("10.14.173.298", 22, "test",
"ab123");
if (blResult) {
System.out.println("Connect successed");
// now we will download file
// blResult =
// sftpBean.downloadFile("/dd1.csv","C:\\Work_old eclipse\\SFTP_Demo");
if (blResult) {
System.out.println("download successed");
} else {
System.out.println("u failed");
}
Vector<LsEntry> vtFiles = sftpBean.listFile("*.txt");
if (vtFiles != null) {
for (LsEntry lsEntry : vtFiles) {
System.out.println(lsEntry.getFilename() + "");
// System.out.println(lsEntry. + "");
}
}
sftpBean.close();
} else {
System.out.println("Connect failed.");
}
}
}
I have an executor service that runs new threads based upon reflection. I have one method that when run does not exit the thread and will hang program execution. I am unsure why this is, can anyone point me to what I'm missing?
Also, if any of the concurrency experts out there notice any problems I may run into, please let me know, I am rather green in concurrency....
Notes:
The connectToFTP method will be refactored to return ChannelSftp in the future.
downloadFromFTP returns false at the end as the method is not completed. I feel that this is the method that is causing the thread to hang. I just don't know why.
The goal of the method is to list each file within an SFTP directory.
from NetworkingShopCa.
#Override
public Object connectToFTP(String username, String password, String host, String port, FtpTypes ftpTypes) {
switch(ftpTypes){
case FTP:
LOGGER.error("Plain FTP is not implemented yet (if ever)");
break;
case FTPS:
FTPSClient client = new FTPSClient();
client.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
try {
client.connect(host);
client.enterLocalPassiveMode();
client.login(username, password);
} catch (IOException e) {
LOGGER.error(e.toString());
}
return client;
case SFTP:
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession(username, host);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
return sftpChannel;
} catch (JSchException e) {
// TODO Auto-generated catch block
LOGGER.error(e.toString());
}
break;
default:
LOGGER.error("Invalid FtpType");
break;
}
return false;
}
#Override
public boolean downloadFromFTP(String directory, String filename, boolean downloadAll,Object activeConnection) {
if(activeConnection instanceof ChannelSftp){
ChannelSftp sftpChannel = (ChannelSftp) activeConnection;
try {
sftpChannel.cd(directory);
//List our files within the directory
Vector vv = sftpChannel.ls(directory);
if (vv != null) {
for (int ii = 0; ii < vv.size(); ii++) {
Object obj = vv.elementAt(ii);
if (obj instanceof ChannelSftp.LsEntry) {
LOGGER.debug("[" + ((LsEntry) obj).getFilename() + "]");
}
}
}
} catch (SftpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
From main
runtimes.put(config.getInt("ESE_PRIORITY"),"RUN_ESE");
ExecutorService threadPool = Executors.newFixedThreadPool(totalRunnables);
LOGGER.info("Executing runtimes in order of priority.");
for(final int priority : runtimes.keySet()){
if(!threadPool.isShutdown() && !threadPool.isTerminated()){
//run the method denoted by the property
final java.lang.reflect.Method method = m.getClass().getMethod(runtimes.get(priority));
Future<?> f = threadPool.submit(new Runnable() {
#Override
public void run() {
try {
method.invoke(m);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
});
f.get();
}
}
public void RUN_ESE(){
LOGGER.info("Running ESE");
Networking networking = new NetworkingShopCa();
networking.downloadFromFTP("/toclient/order/processed", "", true, networking.connectToFTP("user", "password", "host", "", FtpTypes.SFTP));
}
--Edit--
Following a debugger downloadFromFTP executes fully, returns out of the method and goes to close the runnable when it hangs:
Line 1153 of ThreadPoolExecutor.java shows:
afterExecute(task, thrown);
Any ideas? For what its worth my build environment is:
Ubuntu 13.04 64 bit
OpenJDK 7 (ubuntu default) with attached sources.
Eclipse kepler
I want to check if server application is available. After server is started I want to stop checking until the server changes status. How to do that with my code:
private static final String SERVER_ADDRESS = "192.144.10.10";
private static final int TCP_SERVER_PORT = 8890;
private static boolean connected = false;
static Socket s;
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(task, 01, 5001); }
static TimerTask task = new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
if (connected == false)
{
System.out.println(hostAvailabilityCheck());
}
}
};
public static boolean hostAvailabilityCheck()
{
boolean available = true;
try {
if (connected == false)
{ (s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)).close();
}
}
catch (UnknownHostException e)
{ // unknown host
available = false;
s = null;
}
catch (IOException e) { // io exception, service probably not running
available = false;
s = null;
}
catch (NullPointerException e) {
available = false;
s=null;
}
return available;
}
Is there any better way to solve this?
The check method can be rewritten as follows (Java 7 and later):
public static boolean hostAvailabilityCheck() {
try (Socket s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)) {
return true;
} catch (IOException ex) {
/* ignore */
}
return false;
}
In addition to simplifying the exception handling, this eliminates a pesky Socket leak. (If you are concerned with the time taken to do this check, then set a connection timeout before attempting to connect: see Setting a timeout for socket operations)
But the problems with this approach are many-fold:
It only tests that something is listening for connections. If your service is behind a proxy ... or is managed by something like the inetd service ... then the accepted connections don't mean your service is actually working.
This is going to cause your service to "see" connections that close down without sending a request. So you'd better code your service to deal with this "gracefully".
Doing this repeatedly adds to network and server load.
If you set a short timeout because you don't want the test to "freeze", then you risk setting it too short and judging the host to be down when it isn't.
After server is started I want to stop checking until the server changes status
That is next to impossible. The reason is that you won't be able to tell whether the server has "changed status" without checking. Or at least, you won't be able to do this without implementing an elaborate status notification service where the server calls the client to tell it is changing status. (And if "change status" includes "die" or "lost network connection", then you won't be able to make that notification reliable ... if at all.)
public static boolean hostAvailabilityCheck() {
try (Socket s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)) {
return true;
} catch (IOException ex) {
/* ignore */
}
return false;
}
working, but the problem is that when you turn on the phone throught WI-FI it comes to a "screeching halt" and no action. for thought...=)
next code will be to work through WI-FI ... if you increase the connection time -
public static boolean isOnline() {
boolean b = true;
try{
InetSocketAddress sa = new InetSocketAddress("SERVER_IP_ADDRESS", PORT);
Socket ss = new Socket();
ss.connect(sa, 1); --> change from 1 to 500 (for example)
ss.close();
}catch(Exception e) {
b = false;
}
return b;
}
First check if server is running and the server accepts the connection.
public static boolean hostAvailabilityCheck()
{
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
boolean available = true;
try {
if (s.isConnected())
{ s.close();
}
}
catch (UnknownHostException e)
{ // unknown host
available = false;
s = null;
}
catch (IOException e) { // io exception, service probably not running
available = false;
s = null;
}
catch (NullPointerException e) {
available = false;
s=null;
}
return available;
}
I used this method for my ServerUtil.
public static boolean isOnline() {
boolean b = true;
try{
InetSocketAddress sa = new InetSocketAddress("SERVER_IP_ADDRESS", PORT);
Socket ss = new Socket();
ss.connect(sa, 1);
ss.close();
}catch(Exception e) {
b = false;
}
return b;
}
Due to a variety of reasons it became necessary to create our own proxy. Everything is working as it should through HTTP. As soon as we receive a CONNECT to tunnel through SSL is when everything goes wrong. What we do logically is take the CONNECT parse out the host and port so we know where we are sending future ssl requests and create a request to send back to the browser stating we have successfully made the ssl handshake like so:
HTTP/1.0 200 Connection established\r\nProxy-agent: test\r\n\r\n
What we expect to happen is that the browser once receiving this successful message will send us the next https request. However, instead we get sent another CONNECT request over and over.It is clear that is does not like the response we send back. The problem is that i'm not exactly sure why? Does the response back need to be sent back via an https socket? I just don't understand this process enough to move forward.
Here is my server class:
public class HttpServer extends Observable implements IWebServer, Runnable
{
int Port = -1;
int State = HttpState.IDLE;
ArrayList<WebTransactionEvent> History = new ArrayList<WebTransactionEvent>();
ArrayList<HttpService> myServices = new ArrayList<HttpService>();
SocketChannel myChannel = null;
boolean needResponse = false;
boolean shouldStop;
Logger logger = OpsToolsLogger.getLogger(HttpServer.class.getName());
Selector selector ;
static Hashtable<String, HttpServer> myInstances = new Hashtable<String, HttpServer>();
Hashtable<HttpTransaction, HttpService> myTaskTable = new Hashtable<HttpTransaction, HttpService>();
Vector<HttpTransaction> transactionQueue = new Vector<HttpTransaction>();
private HttpServer(){}
private HttpServer(int Port)
{
logger.log(Level.WARNING, "HttpServer: startup - listening to port: " + Port);
this.Port = Port;
shouldStop = false;
// Create the selector
try {
selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(Port));
this.registerSocket(serverChannel);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(this).start();
}
public static HttpServer getInstance(String port)
{
if( !myInstances.containsKey( port ) )
{
myInstances.put( port, new HttpServer(Integer.parseInt(port)));
}
return myInstances.get(port);
}
public int getState()
{
return State;
}
public void stop()
{
shouldStop = true;
}
public boolean needResponse()
{
return needResponse;
}
public HttpTransaction getNextTransaction()
{
if(transactionQueue.isEmpty())
{
return null;
}
//System.out.println("grabbing next trans");
HttpTransaction temp = transactionQueue.firstElement();
transactionQueue.remove(0);//pop trans from queue
return temp;
}
public void dropTransaction()
{
myTaskTable.clear();
needResponse = false;
}
public synchronized boolean respond(HttpTransaction transaction, IHttpResponse editedResponse, boolean closeConnection)
{
logger.log(Level.FINE, "HttpServer: responding ");
needResponse = false;
if(myTaskTable.isEmpty())
{
return false;
}
//see if there isn't a service object registered with that transaction
if(!myTaskTable.containsKey(transaction))
{
return false;
}
State = HttpState.SENDING_RESPONSE;
ManipulatedHttpTransaction myTrans = (ManipulatedHttpTransaction) transaction;
HttpResponse response = (HttpResponse) editedResponse;
myTrans.setManipulatedResponse( response );
HttpService serv = myTaskTable.get(transaction);
if(!serv.respond(myTrans.getManipulatedResponse(), closeConnection))
{
History.add( new WebTransactionEvent( myTrans, WebTransactionEvent.TRANSACTION_ERROR ) );
return false;
}
myTaskTable.remove(transaction);
History.add( new WebTransactionEvent( myTrans, WebTransactionEvent.TRANSACTION_COMPLETED ) );
needResponse = !myTaskTable.isEmpty();
return true;
}
public void registerSocket(ServerSocketChannel theSocket)
{
try {
theSocket.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run()
{
try {
while (!shouldStop ) {
// Wait for an event
selector.select();
// Get list of selection keys with pending events
Iterator it = selector.selectedKeys().iterator();
// Process each key
while (it.hasNext()) {
// Get the selection key
SelectionKey selKey = (SelectionKey)it.next();
// Remove it from the list to indicate that it is being processed
it.remove();
// Check if it's a connection request
if (selKey.isAcceptable()) {
// Get channel with connection request
ServerSocketChannel ssChannel = (ServerSocketChannel)selKey.channel();
SocketChannel theChannel = ssChannel.accept();
if(theChannel != null)
{
logger.log(Level.FINEST, "HttpServer: Connection established");
try
{
theChannel.configureBlocking(false);
}
catch(Exception e)
{
logger.log(Level.WARNING, "myChannel = null ( configureBlocking() )");
//bytesRead = -1;
}
myServices.add( new HttpService(this, theChannel ) );
needResponse = true;
}
//needResponse = !myTaskTable.isEmpty();
//System.out.println("need response: "+ needResponse);
}
}
}
} catch (IOException e) {
}
//shutdown
logger.log(Level.WARNING, "Server stopping - " + Port);
}
public ArrayList<WebTransactionEvent> getHistory()
{
return new ArrayList<WebTransactionEvent>(History);
}
public boolean switchServerToSSL()
{
//HttpService tempService = myTaskTable.get(PendingTransaction);
//tempService.useSSL = true;
return true;
}
/**
* Adds the transaction from browser to the transaction queue and also ties it to a service by adding it to myTasks map
* #param myTrans
* #param httpService
*/
public void addTransaction(ManipulatedHttpTransaction myTrans,
HttpService httpService) {
// TODO Auto-generated method stub
//ensure vector has room to add another transaction
if(transactionQueue.capacity() <= transactionQueue.size())
transactionQueue.ensureCapacity(transactionQueue.size() * 2);
transactionQueue.add(myTrans);//add transaction to queue
myTaskTable.put(myTrans, httpService);//tie the transaction toits service
// System.out.println("server notifying proxy: " + myTrans.getFullURL());
this.setChanged();
this.notifyObservers(myTrans);
}
}
Here is portion in proxy that handles a CONNECT:
if(tempTransaction.getOriginatingRequest().getMethod().contentEquals("CONNECT"))
{
/*tell the browser that the connection exists
*
* Each time you connect to an SSL-protected website, Burp generates a server certificate for that host, signed by the CA certificate
*
* The server certificates presented to the client (i.e. a web browser) are dynamically generated/signed by the proxy and contain most of the same fields as the original webserver certificate. The subject DN, serial number, validity dates, and extensions are preserved. However, the issuer DN is now set to the name of the proxy's self-signed
* certificate and the public/private keys of the proxy are used in creating the forged certificate. These forged certificates are cached (in memory) by the proxy, for better performance
*/
HttpResponse tunnelResponse = new HttpResponse("HTTP/1.0 200 Connection established\r\nProxy-agent: Ops Assistant\r\n\r\n");
tempTransaction.setResponse(tunnelResponse);
if(!finishResponse2(tempTransaction,tempTransaction.getResponse(), false));
{
//close the connection
}
myServer.switchServerToSSL();
}
Here is section sends request back to browser:
public boolean respond(IHttpResponse response, boolean closeConnection)
{
isCloseConnectionRequested = closeConnection;
try
{
if(useSSL)
{
ByteBuffer tmpBuffer = response.getData();
tmpBuffer.position(0);
myConnection.SecureWrite( tmpBuffer );
}
else
{
ByteBuffer tmpBuffer = response.getData();
tmpBuffer.position(0);
myConnection.Write(tmpBuffer);
}
if(closeConnection)
{
myChannel.close();
myChannel = null;
}
}
catch (Exception e)
{
isResponded = true;
return false;
}
isResponded = true;
return true;
}
Probably most important the socket class:
public class SocketConnection implements IConnection
{
public SocketChannel theSocketChannel;
public InetSocketAddress theRemoteAddress;
public int TimeoutThreshold;
private int TimeOutThreshold = 30;
private SSLEngine theSSLEngine;
private SSLContext theSSLContext;
private ByteBuffer inNetworkDataBuffer;
private ByteBuffer inAppDataBuffer;
private ByteBuffer outNetworkDataBuffer;
private ByteBuffer outAppDataBuffer;
//create outbound connection to host/port
public SocketConnection(String Host, int Port ) throws IOException
{
theRemoteAddress = new InetSocketAddress( Host, Port);
theSocketChannel = SocketChannel.open();
theSocketChannel.configureBlocking(false);
theSocketChannel.connect( theRemoteAddress );
theSocketChannel.finishConnect();
}
//use existing socket connection
public SocketConnection(SocketChannel existingChannel) throws IOException
{
theSocketChannel = existingChannel;
theSocketChannel.configureBlocking(false);
theRemoteAddress = new InetSocketAddress( existingChannel.socket().getInetAddress(), existingChannel.socket().getPort() );
}
public boolean setTimeOut(int newTimeOutThreshold)
{
TimeOutThreshold = newTimeOutThreshold;
return true;
}
public void waitForSocketToConnect() throws Exception
{
int i = 0;
while( !this.isConnected() )
{
this.finishConnect();
if(i>=3000)
{
throw new Exception();
}
i++;
try{Thread.sleep(10);}catch(Exception e){}
}
}
public boolean Write( ByteBuffer DataToSend )
{
try
{
//DataToSend.flip();
int numBytesWritten = theSocketChannel.write(DataToSend);
try
{
DataToSend.compact();
}
catch (ReadOnlyBufferException e)
{
DataToSend.rewind();
}
}
catch (IOException e)
{
// Connection may have been closed
}
return true;
}
public ByteBuffer Read()
{
ByteBuffer ResponseBytes = ByteBuffer.allocateDirect(0);
try
{
ByteBuffer netBuffer = ByteBuffer.wrap(new byte[10000]);
// Clear the buffer and read bytes from socket
netBuffer.clear();
int numBytesRead = theSocketChannel.read(netBuffer);
if(numBytesRead == -1)
return null; //-1 means we done return null as the flag
netBuffer.flip();
ByteBuffer tempBuffer = ByteBuffer.wrap(new byte[ ResponseBytes.limit() + netBuffer.limit() ]);
ResponseBytes.position(0);
netBuffer.position(0);
tempBuffer.put(ResponseBytes);
tempBuffer.put(netBuffer);
netBuffer.flip();
ResponseBytes = tempBuffer;
}
catch (IOException e)
{
// Connection may have been closed
e = e;
return ByteBuffer.wrap( e.getMessage().getBytes() );
}
return (ByteBuffer) ResponseBytes.flip();
}
public boolean SecureWrite( ByteBuffer DataToSend )
{
boolean writeSuccess = true;
try
{
//if we don't have a SSLEngine make one
if(theSSLEngine==null)
{
setupSSL();
}
//Convert Data
outAppDataBuffer.clear();
outAppDataBuffer.put(DataToSend);
outAppDataBuffer.flip();
SSLEngineResult sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
outAppDataBuffer.compact();
//outNetworkDataBuffer.flip();
//int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
if(sslResult.getStatus() == SSLEngineResult.Status.OK)
{
if(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
{
// Write bytes
outNetworkDataBuffer.flip();
int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
outNetworkDataBuffer.compact();
if(finishHandshake(sslResult))
{
DataToSend.rewind();
return SecureWrite(DataToSend);
}
else
{
return false;
}
}
else
{
// Write bytes
outNetworkDataBuffer.rewind();
Write(outNetworkDataBuffer);
}
}
else
{
}
}
catch(Exception e)
{
writeSuccess = false;
}
return writeSuccess;
}
public ByteBuffer SecureRead() throws ReadTimedOutException
{
int timeElapsed = 0;
ByteBuffer ResponseBytes = ByteBuffer.allocateDirect(0);
try
{
//if we don't have a SSLEngine make one
if(theSSLEngine==null)
{
setupSSL();
}
int consumedCount = 0;
SSLEngineResult sslResult;
do
{
//inNetworkDataBuffer.clear();
inNetworkDataBuffer.put( Read() );
inNetworkDataBuffer.flip();
sslResult = theSSLEngine.unwrap( inNetworkDataBuffer, inAppDataBuffer );
consumedCount += sslResult.bytesConsumed();
inNetworkDataBuffer.compact();
if( sslResult.getStatus() == SSLEngineResult.Status.OK )
{
if(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
{
if(finishHandshake(sslResult))
{
return SecureRead();
}
else
{
return ByteBuffer.allocateDirect(0);
}
}
else
{
timeElapsed = 0;
inAppDataBuffer.flip();
ByteBuffer tempBuffer = ByteBuffer.wrap(new byte[ ResponseBytes.limit() + inAppDataBuffer.limit() ]);
ResponseBytes.position(0);
inAppDataBuffer.position(0);
tempBuffer.put(ResponseBytes);
tempBuffer.put(inAppDataBuffer);
inAppDataBuffer.flip();
ResponseBytes = tempBuffer;
ResponseBytes.flip();
}
}
else
{
//the status wasn't ok
timeElapsed++;
}
}while(consumedCount < inNetworkDataBuffer.limit() && sslResult.getStatus() != SSLEngineResult.Status.OK);
}
catch (Exception e)
{
System.out.println(e.toString());
}
if(timeElapsed>=TimeOutThreshold)
{
throw new ReadTimedOutException();
}
return ResponseBytes;
}
public boolean Disconnect()
{
try
{
theSocketChannel.close();
}
catch(Exception e)
{
return false;
}
return true;
}
public boolean isClosed()
{
return !theSocketChannel.isOpen();
}
#Override
public String getHost()
{
return theRemoteAddress.getHostName();
}
#Override
public int getPort()
{
return theRemoteAddress.getPort();
}
public boolean isConnected()
{
return theSocketChannel.isConnected();
}
#Override
public boolean hasSecure()
{
return true;
}
public boolean finishConnect() throws Exception
{
return theSocketChannel.finishConnect();
}
private void setupSSL() throws NoSuchAlgorithmException, KeyManagementException
{
//create a new SSLEngine instance
System.setProperty( "javax.net.debug", "ssl");
TrustManager[] tm = new TrustManager[] { new NaiveTrustManager() };
SSLContext theSSLContext = SSLContext.getInstance ("TLS");
theSSLContext.init( new KeyManager[0], tm, new SecureRandom( ) );
theSSLEngine = theSSLContext.createSSLEngine( theRemoteAddress.getHostName(), theRemoteAddress.getPort());
theSSLEngine.setUseClientMode(true);
inNetworkDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getPacketBufferSize()]);
inAppDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getApplicationBufferSize()]);
outNetworkDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getPacketBufferSize()]);
outAppDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getApplicationBufferSize()]);
}
private boolean finishHandshake(SSLEngineResult sslResult)
{
boolean bFinished = false;
while(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.FINISHED)
{
if( sslResult.getStatus() == SSLEngineResult.Status.CLOSED )
{
bFinished = false;
//break;
}
if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK)
{
Runnable task;
while ((task=theSSLEngine.getDelegatedTask()) != null)
{
task.run();
}
try
{
//outNetworkDataBuffer.flip();
sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
//outNetworkDataBuffer.compact();
}
catch (SSLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
{
try
{
outAppDataBuffer.flip();
sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
outAppDataBuffer.compact();
} catch (SSLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if((sslResult.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) || (outNetworkDataBuffer.position() > 0))
{
try
{
outNetworkDataBuffer.flip();
int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
outNetworkDataBuffer.compact();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
else if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
{
try
{
int numBytes;
//read data from the socket into inNetworkBuffer
inNetworkDataBuffer.flip();
sslResult = theSSLEngine.unwrap( inNetworkDataBuffer, inAppDataBuffer );
inNetworkDataBuffer.compact();
if(theSSLEngine.isInboundDone())
{
}
else
{
numBytes = theSocketChannel.read(inNetworkDataBuffer);
numBytes = numBytes;
}
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
}
return true;
}
}
Anyone have any tips on how to best establish this handshake with the browser?
Have you read the Internet draft? The CONNECT is received in plaintext. You form the upstream connection and return the 'HTTP/1.0 200 Connection established' response. After that the proxy isn't processing requests and responses, it is just copying bytes in both directions, whatever they may happen to be. Specifically, the proxy isn't concerned with SSL in any way shape or form.