SSH connection leaving stale sessions on the server - java

I am programatically trying to connect to ssh running remotely. I am running a tomcat server instance. Whenever i need, from the code, i create a session, connect and execute a few commands that are needed within a try block and then close off the connection that was created as part of the finally block at all the places. Things work well and fine, but at some cases when i execute a w or netstat command on the ssh server, I see a few connections that are idle for more than a few hours and the ip address of those connections shows the connection to be from my application, but my java heap dump does not show any instance of my class in the memory, but i see ganymed related class instances in the heap.
I am using ganymed-ssh-260 library to connect to my server.
Is this something that someone has already seen?
Attaching the code snippet that connectes the ssh to the server
public class SSHExecutor{
private OutputStream stdin;
private InputStream stdout;
private InputStream stderr;
private Session sess;
private Connection conn;
public void createConnection(String hostname, int port, String userName, String password) throws Exception {
try {
conn = new Connection(hostname, port);
final boolean isAuthenticated = publicKeyAccess(hostname, userName, password);
if (!isAuthenticated) {
throw new IOException("Authentication failed.");
}
sess = conn.openSession();
final int xWidth = 90;
final int yWidth = 80;
sess.requestPTY("dumb", xWidth, yWidth, 0, 0, null);
sess.startShell();
stdin = sess.getStdin();
stdout = sess.getStdout();
stderr = sess.getStderr();
isConnectionActive = true;
final String response = getResponse();
if (response != null && response.toLowerCase().contains(ObjectConstants.CURRENTLY_NOT_AVAILABLE)) {
throw new IOException("Account is currently not available.");
}
} catch (Exception e) {
log.error("Problem in CreateConnection", e);
isConnectionActive = false;
throw e;
}
}
public String getResponse() {
final StringBuffer responseData = new StringBuffer();
try {
final int byteValue = 8192;
final byte[] buffer = new byte[byteValue];
try {
while (true) {
if ((stdout.available() == 0) && (stderr.available() == 0)) {
int conditions = 1;
if (promptString != null && promptString.length() > 0) {
final int fiveThousand = 5000;
conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA
| ChannelCondition.STDERR_DATA | ChannelCondition.EOF, fiveThousand);
} else {
conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA
| ChannelCondition.STDERR_DATA | ChannelCondition.EOF,
ObjectConstants.THOUSAND_FIVE_HUNDRED);
}
if ((conditions & ChannelCondition.TIMEOUT) != 0) {
break;
}
if ((conditions & ChannelCondition.EOF) != 0) {
if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) {
break;
}
}
}
while (stdout.available() > 0) {
final int len = stdout.read(buffer);
if (len > 0) {
responseData.append(new String(buffer, 0, len));
}
}
while (stderr.available() > 0) {
final int len = stderr.read(buffer);
if (len > 0) {
responseData.append(new String(buffer, 0, len));
}
}
if (promptString != null && promptString.length() > 0) {
if (responseData.indexOf(promptString) != -1) {
break;
}
}
}
} catch (Exception e) {
log.error("Read Error :", e);
}
} catch (Exception e) {
log.error("getResponse Error ", e);
}
return responseData.toString();
}
public String executeCommand(String command) throws IOException {
String response = null;
if (isConnectionActive && stdin != null) {
try {
stdin.write(command.getBytes());
stdin.flush();
response = getResponse();
} catch (IOException ie) {
throw ie;
} catch (Exception e) {
log.error("Exception in executeCommandForPage()", e);
response = e.getMessage();
}
} else {
response = "Connection not active.";
}
return response;
}
public void closeConnection() {
if (stderr != null) {
try {
stderr.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (stdout != null) {
try {
stdout.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (stdin != null) {
try {
stdin.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (sess != null) {
try {
sess.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
}
}

You're creating a local Connection variable but you're testing what must be a member variable, which is always null, so you're never closing it.
If authentication fails you're leaking the connection.

Related

Android Java: Proxy-App without Port-Forwarding

I have to create a simple rotating proxy application where 100 requests get evenly distributed to 10 devices. I've got the following structure:
WebServer with a Java-SocketServer running. All Android devices are connected to this Socket-Server to be able to know which devices are currently online and for determining which device should be used for the next request.
10 Android devices in different networks. They are connected to the Socket Server and are waiting for requests that should be forwarded to the remote address and then sent back to the SocketServer.
In easy words: I basically have to create an application similar like Honeygain, Peer2Profit or IPRoyal Pawns so that I can later do requests like this:
//Use "-x" to set Proxy-IP and Proxy-Port
curl -x ANDROID_DEVICE_IP:PORT -L https://www.google.com
I managed to have an always running proxy service in an Android application. It basically looks like this and just forwards HTTP-Requests from Port 1440 to the desired remote address and then sends the response back to the original client. The Proxy basically works fine.
public class ProxyServerThread extends Thread {
public static void main(String[] args) {
(new ProxyServerThread()).run();
}
public ProxyServerThread() {
super("Server Thread");
}
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(1440)) {
Socket socket;
try {
while ((socket = serverSocket.accept()) != null) {
(new Handler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
return;
}
}
public static class Handler extends Thread {
public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\\.[01])", Pattern.CASE_INSENSITIVE);
private final Socket clientSocket;
private boolean previousWasR = false;
public Handler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
String request = readLine(clientSocket);
System.out.println(request);
Matcher matcher = CONNECT_PATTERN.matcher(request);
if (matcher.matches()) {
String header;
do {
header = readLine(clientSocket);
} while (!"".equals(header));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(), "ISO-8859-1");
final Socket forwardSocket;
try {
forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2)));
System.out.println(forwardSocket);
} catch (IOException | NumberFormatException e) {
e.printStackTrace(); // TODO: implement catch
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
return;
}
try {
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
Thread remoteToClient = new Thread() {
#Override
public void run() {
forwardData(forwardSocket, clientSocket);
}
};
remoteToClient.start();
try {
if (previousWasR) {
int read = clientSocket.getInputStream().read();
if (read != -1) {
if (read != '\n') {
forwardSocket.getOutputStream().write(read);
}
forwardData(clientSocket, forwardSocket);
} else {
if (!forwardSocket.isOutputShutdown()) {
forwardSocket.shutdownOutput();
}
if (!clientSocket.isInputShutdown()) {
clientSocket.shutdownInput();
}
}
} else {
forwardData(clientSocket, forwardSocket);
}
} finally {
try {
remoteToClient.join();
} catch (InterruptedException e) {
e.printStackTrace(); // TODO: implement catch
}
}
} finally {
forwardSocket.close();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
}
private static void forwardData(Socket inputSocket, Socket outputSocket) {
try {
InputStream inputStream = inputSocket.getInputStream();
try {
OutputStream outputStream = outputSocket.getOutputStream();
try {
byte[] buffer = new byte[4096];
int read;
do {
read = inputStream.read(buffer);
if (read > 0) {
outputStream.write(buffer, 0, read);
if (inputStream.available() < 1) {
outputStream.flush();
}
}
} while (read >= 0);
} finally {
if (!outputSocket.isOutputShutdown()) {
outputSocket.shutdownOutput();
}
}
} finally {
if (!inputSocket.isInputShutdown()) {
inputSocket.shutdownInput();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
private String readLine(Socket socket) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int next;
readerLoop:
while ((next = socket.getInputStream().read()) != -1) {
if (previousWasR && next == '\n') {
previousWasR = false;
continue;
}
previousWasR = false;
switch (next) {
case '\r':
previousWasR = true;
break readerLoop;
case '\n':
break readerLoop;
default:
byteArrayOutputStream.write(next);
break;
}
}
return byteArrayOutputStream.toString("ISO-8859-1");
}
}
}
Here comes the Problem:
Everything works fine but only on the local network. I cannot manage to get this to work without port forwarding. Since all devices are on their mobile cellular data I need a way to be able to connect to the device anyway.
How do the mentioned apps manage to connect to the devices?

Why can i recieve broadcasts, but not communicate with a specific socket in my App?

First some Information regarding my Setup.
I have a S8 Cellphone, where i run this App, based upon the AR-Devkit demo from Google.
public void closeSocket(DatagramSocket socket) {
if (socket != null && socket.isConnected() ) {
while (!socket.isConnected()) {
socket.disconnect();
try {
Thread.sleep(SpringAR.TIME_OUT_IN_BROADCAST);
} catch (InterruptedException e) {
Log.d(SpringAR.protocollDebugLogPrefix, " Socket Closing interrupted");
e.printStackTrace();
}
}
}
if (socket != null && !socket.isClosed()) {
socket.close();
while (!socket.isClosed()) {
try {
Thread.sleep(SpringAR.TIME_OUT_IN_BROADCAST);
} catch (InterruptedException e) {
Log.d(SpringAR.protocollDebugLogPrefix, " Socket Closing interrupted");
e.printStackTrace();
}
}
}
}
public DatagramSocket createSocket(InetAddress ipAddress, int port) {
try {
DatagramSocket socket = new DatagramSocket(null);
InetSocketAddress address = new InetSocketAddress(ipAddress, port);
socket.setReuseAddress(true);
socket.bind(address);
return socket;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public DatagramSocket getBroadcastListenerSocket() throws IOException {
InetSocketAddress anyAdress = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 9000);
DatagramSocket socket = new DatagramSocket(null);
socket.setSoTimeout(30);
socket.setReuseAddress(true);
socket.bind(anyAdress);
return socket;
}
public DatagramSocket getBroadcastSenderSocket(DatagramSocket oldSocket) {
DatagramSocket socket = null;
try {
ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
socket = getSocket(oldSocket, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, null);
socket.setBroadcast(true);
socket.setSoTimeout(SpringAR.TIME_OF_FRAME_IN_MS);
} catch (IOException e) {
e.printStackTrace();
}
return socket;
}
public DatagramSocket getSocket(DatagramSocket oldSocket, InetAddress ipAddress, int port, InetAddress targetAddress) {
if (oldSocket != null ) {
closeSocket(oldSocket);
}
DatagramSocket socket = null;
try {
socket = createSocket(ipAddress, port);
socket.setBroadcast(false);
socket.setSoTimeout(SpringAR.TIME_OF_FRAME_IN_MS);
if (targetAddress != null)
socket.connect(targetAddress, port);
} catch (SocketException e) {
e.printStackTrace();
}
return socket;
}
public class DatagramReciever extends Thread {
private String datagramToSend = "";
private boolean newDatagramToSend = false;
private DatagramPacket snd_packet;
DatagramSocket senderSocket = null;
DatagramSocket listenerSocket = null;
private DatagramSocket broadCastListenerSocket;
//Buffer gettters and setters
private int writeBuffer = 0;
private SpringAR.comStates oldState;
int getReadBuffer() {
if (writeBuffer == 1) return 0;
return 1;
}
void switchBuffer() {
recieveByteIndex = 0;
writeBuffer = getReadBuffer();
}
public String dbg_message = "";
//Management Communication Headers
public void kill() {
closeSocket(senderSocket);
closeSocket(listenerSocket);
closeSocket(broadCastListenerSocket);
}
public void run() {
try {
initializeBroadcastConnection();
while (true) {
//Recieving Datagramm
DatagramPacket rcv_packet = new DatagramPacket(rcv_message[writeBuffer], rcv_message[writeBuffer].length);
boolean NewMessageArrived = true;
try {
listenerSocket.receive(rcv_packet);
} catch (SocketTimeoutException e) {
NewMessageArrived = false;
}
//Watchdog
handleWatchDogTimer(State);
//TODO Delete String conversion
if (NewMessageArrived) {
dbg_message = new String(rcv_message[writeBuffer], 0, rcv_packet.getLength(), "US-ASCII");
Log.d(SpringAR.dataDebugLogPrefix, "" + rcv_packet.getAddress().getHostAddress() + ": " + dbg_message.trim() + " of " + rcv_packet.getLength() + "length ");
}
if (validatePackageSender(rcv_packet)) {
connectionStateMachine(rcv_message, rcv_packet);
}
//Sending Datagram
if (newDatagramToSend && hostIpAddress != null) {
//Log.d(SpringAR.protocollDebugLogPrefix, "Server sending: " + datagramToSend);
byte[] snd_message = datagramToSend.getBytes();
try {
snd_packet = packSendPackageByState(snd_message);
assert (snd_packet != null);
senderSocket.send(snd_packet);
newDatagramToSend = false;
} catch (IOException e1) {
e1.printStackTrace();
//causes Caused by: android.system.ErrnoException: sendto failed: EINVAL (Invalid argument)
Log.e(SpringAR.protocollDebugLogPrefix, "Server Error in State: " + State.name());
break;
}
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
private void initializeBroadcastConnection() throws IOException {
ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
senderSocket = getSocket(null, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, null);
broadCastListenerSocket = getBroadcastListenerSocket();
listenerSocket = broadCastListenerSocket;
Log.d(SpringAR.protocollDebugLogPrefix, "initializeBroadcastConnection completed");
}
// handles management traffic like configurstion files
private void connectionStateMachine(byte[][] payload, DatagramPacket rcv_packet) throws IOException {
//Reset triggered by Host
if (comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveResetHeaderByte) != SpringAR.STRING_NOT_FOUND) {
State = SpringAR.comStates.STATE_resetCommunication;
}
Log.d(SpringAR.protocollDebugLogPrefix, "ConnectionStateMachine: " + State.name());
switch (State) {
case STATE_resetCommunication: {
messageCounter = 0;
listenerSocket = broadCastListenerSocket;
hostIpAddress = comonUtils.getBroadcastAddress(context);
senderSocket = getBroadcastSenderSocket(senderSocket);
setSendToSpringMessage(SpringAR.sendResetHeader);
State = SpringAR.comStates.STATE_broadCastHeader;
return;
}
case STATE_broadCastHeader: {
if (comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveHostReplyHeaderByte) != SpringAR.STRING_NOT_FOUND) {
Log.d(SpringAR.protocollDebugLogPrefix, " Host Reply Header recieved");
//Extract the hostIp
String hostIpAdressAsString = new String(payload[writeBuffer]);
hostIpAdressAsString = hostIpAdressAsString.replace(SpringAR.recieveHostReplyHeader, "").trim();
Log.d(SpringAR.dataDebugLogPrefix, hostIpAdressAsString);
hostIpAddress = InetAddress.getByName(hostIpAdressAsString);
//Set Connection from broadcast to target
ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
Log.d(SpringAR.protocollDebugLogPrefix, " New Device Adress " + ARDeviceAddress);
senderSocket = getSocket(senderSocket, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, hostIpAddress);
listenerSocket = senderSocket;
State = SpringAR.comStates.STATE_sendCFG;
return;
}
setSendToSpringMessage(SpringAR.sendBroadcasteHeader);
delayByMs(SpringAR.TIME_OUT_IN_BROADCAST);
return;
}
case STATE_sendCFG: {
if ( SpringAR.STRING_NOT_FOUND != comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveCFGHeaderByte )) {
State = SpringAR.comStates.STATE_sendRecieveData;
return;
}
setSendToSpringMessage(SpringAR.formConfigurationMessage());
return;
}
case STATE_sendRecieveData: {
if ( SpringAR.STRING_NOT_FOUND != comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveDataHeaderByte)) {
writeRecievedDataToBuffer(payload[writeBuffer], rcv_packet.getLength());
}
break;
}
default:
Log.d(SpringAR.protocollDebugLogPrefix, "Connection State Machine invalid state");
}
}
https://github.com/PicassoCT/arcore-android-sdk/blob/6c9b48a3d520e039cd48bc2af7354ccdec857736/arcore-android-sdk/samples/hello_ar/app/src/main/java/com/google/ar/core/examples/app/common/tcpClient/Server.java
All the testing is happening in a home-WiFi Setup, where the desktop with the host-application is directly attached to the WiFi-Router.
What is working thus far:
The device can broadcast its presence.
The host can broadcast its configuration.
The Device can not communicate from IP to IP on the host. Both sides have fixed IP set.
I can communicate with the App PacketSender with the host-Application, and ruled a failure on its part out.
I also built a smaller debug-loop, to only send udp-packets back and forth, which also worked.
Thank you for your time
Change this line:
socket.setSoTimeout(30);
to
socket.setSoTimeout(1000);
You've got a fairly complex state machine going here, and it's difficult to discern what is happening without having logs to look at. I would summarize your state machine like this:
Broadcast a configuration message
Spend 30ms listening for a response
If no response is received, block for SpringAR.TIME_OF_FRAME_IN_MS (not included in your code; I assume it is 1000ms), and loop back to #1
If a response was received, send a reply directly to the peer, and go to #2
#4 is the step that isn't happening. The likely reason (based on the Wireshark dump) is that it's taking 68ms for ARDevice's response to reach "Host". You only gave it 30ms. There could be a number of reasons it's taking so long, but that's beyond the scope of your question.

Client-Server, Object Input/Output, DeadLock

I am pretty new to writing client/server based apps. both server and client classes are kicked off in threads. New to using Object Output/input streams over tcp aswell. Have never had fun with serialization. In my application I am trying to use Object Input/Output Streaming but it looks like opening them is causing my application dies. The funny thing is that if I comment two lines:
outStream = new ObjectOutputStream(socket.getOutputStream());
inStream = new ObjectInputStream(socket.getInputStream());
Connection works nicely and app proceeds to the next panels etc. But I am still not capable of sending any objects throughout the socket. When I literally try to open those streams. It still connects but app get freezed. I 've got two questions:
first: is it better to use serialization
second: if I can use Object streaming, how should I open them? Can I do it inside the server/client thread?
Thanks for Your time
Here is the code of ClientApp:
public void run()
{
while (true)
{
try // odswiezanie co sekunde
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
try // polaczenie
{
if (connecting)
{
socket = new Socket(hostIP, port);
JOptionPane.showMessageDialog(null, "Connection established!");
connected = true;
connecting = false;
frame.settingPanelForClient.bPlayerName.setText("Put the ships on your board!");
outStream = new ObjectOutputStream(socket.getOutputStream());
inStream = new ObjectInputStream(socket.getInputStream());
connectionEstablished(frame);
}
}
catch (UnknownHostException e)
{
JOptionPane.showMessageDialog(frame, "Unknown server!");
connected = false;
}
catch (IOException e)
{
JOptionPane.showMessageDialog(frame,"An Error occured while trying to connect to the server!");
e.getMessage();
e.printStackTrace();
connected = false;
}
catch (IllegalThreadStateException e)
{
e.printStackTrace();
}
try // odbior obiektow
{
if(connected)
{
while(!opponentIsReady){
System.out.println("wszedlem do connected!(klient) ");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do klienta!");
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}}
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
Do you use Serializable interface for the Map object ?
If you still frozen at a step, its maybe because you try to read object (from server or client) and you didn't send it by the other side. While the object is not read it will wait for content.
I dont know how work your server, but you read response twice when oppenentReady is false.
if (inStream.readObject() != null) {
if (inStream.readObject() instanceof Boolean) {
//...
}
}
If this is not the expected behavior, you should store it in local variable.
Once again, this's smt I want to implement(in steps)
1. user choose to open connection(he becomes a server and waits for a client
to connect) - done.
2. second user choose to connect(becomes a client and connects to the
second player(server) - done.
3. Both get message that the connection is established and they are moved
to the next Panel where they do specific operations - done.
4.When anyone of them finishes, I want to tell it to the second guy
(it is represented by a boolean local varable) - here comes the problem.
5. When both have finished, they should be moved to the next Panel where
they play.(before they start playing, Maps that they have set in the previous Panel
should be sent to each other.
Next steps I can handle if Only I knew maybe not how to send those informations
but where to place sending code because it seems to be in the wrong place. Here is the full code of client/server classes:
connecting - is set to true in the other class after pushing the button.
iAmready - is set to true when player finishes setting up the map and should be sent to opponent,
because it triggers a specific operation by setting opponentIsReady to true when obtained.
public class ClientApp implements Runnable
{
public static String hostIP = "127.0.0.1";
public static int port = 1000;
public static boolean connected = false;
public static boolean connecting = false;
public static boolean iAmReady = false;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public final Frame frame;
public static Map mapToGet;
public static Map mapToSend;
public ClientApp(Frame parent)
{
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
#Override
public void run()
{
while (true)
{
try // odswiezanie co sekunde
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
try // polaczenie
{
if (connecting)
{
socket = new Socket(hostIP, port);
JOptionPane.showMessageDialog(null, "Connection established!");
connected = true;
connecting = false;
frame.settingPanelForClient.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
}
}
catch (UnknownHostException e)
{
JOptionPane.showMessageDialog(frame, "Unknown server!");
connected = false;
}
catch (IOException e)
{
JOptionPane.showMessageDialog(frame,"An Error occured while trying to connect to the server!");
e.getMessage();
e.printStackTrace();
connected = false;
}
catch (IllegalThreadStateException e)
{
e.printStackTrace();
}
try // odbior obiektow
{
if(connected)
{
FileOutputStream out = new FileOutputStream("/tmp/message.ser");
outStream = new ObjectOutputStream(out);
FileInputStream in = new FileInputStream("/tmp/message.ser");
inStream = new ObjectInputStream(in);
while(!opponentIsReady){
System.out.println("wszedlem do connected!(klient) ");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do klienta!");
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady && iAmReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}
inStream.close();
outStream.close();
in.close();
out.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
public static void connectionEstablished(Frame frame)
{
frame.remove(frame.connectPanel);
frame.getContentPane().add(frame.settingPanelForClient);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame)
{
frame.remove(frame.settingPanelForClient);
frame.getContentPane().add(frame.opponentsMove);
frame.validate();
frame.repaint();
}
public static Map getMap()
{
try
{
if (connected)
if (inStream.readObject() != null && inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public static void sendMap()
{
if (connected)
if (mapToSend != null)
{
try
{
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public class ServerApp implements Runnable
{
public static int port = 1000;
public static boolean connected = false;
public static boolean connecting = false;
public static boolean iAmReady = false;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ServerSocket hostServer = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public static Map mapToGet;
public static Map mapToSend;
final Frame frame;
public ServerApp(Frame parent)
{
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
#Override
public void run()
{
while(true)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
try
{
if (connecting)
{
hostServer = new ServerSocket(port);
socket = hostServer.accept();
connected = true;
connecting = false;
JOptionPane.showMessageDialog(null, "Connection Established!");
frame.settingPanelForServer.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
}
}
catch (UnknownHostException e)
{
connected = connecting = false;
}
catch (IOException e)
{
connected = connecting = false;
}
try // odbior obiektow
{
if(connected)
{
while(!opponentIsReady){
System.out.println("wszedlem do connected(server)");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
inStream = new ObjectInputStream(socket.getInputStream());
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do servera!");
outStream = new ObjectOutputStream(socket.getOutputStream());
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady && iAmReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}}
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
public static void connectionEstablished(Frame frame)
{
frame.remove(frame.waitPanel);
frame.getContentPane().add(frame.settingPanelForServer);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame)
{
frame.remove(frame.settingPanelForServer);
frame.getContentPane().add(frame.playPanelForServer);
frame.validate();
frame.repaint();
}
public static Map getMap()
{
try
{
if (connected)
if (inStream.readObject() != null && inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public static void sendMap()
{
if (connected)
if (mapToSend != null)
{
try
{
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
As i said before, you can not use readObject() more than once for the same object.
Example,
Use:
Object objectRead=inStream.readObject();
if (objectRead != null) {
if (objectRead instanceof Boolean) {
opponentIsReady = Boolean.valueOf(objectRead);
System.out.println(opponentIsReady);
} else if (objectRead instanceof Map) {
mapToGet = (Map) objectRead;
}
}
Instead of:
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
I think you didn't understand how it works:
When the client/server connection is etablished you can use Threads to read or write objects.
I give you code that you can test to understand how it works:
ServerApp:
public class ServerApp implements Runnable {
public static int port = 1000;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ServerSocket hostServer = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public static Map mapToGet;
public static Map mapToSend;
final Frame frame;
private boolean connected = false;
public ServerApp(Frame parent) {
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
#Override
public void run() {
// Server initialization side
try {
hostServer = new ServerSocket(port);
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
// Accept will wait until a client try to connect
socket = hostServer.accept();
JOptionPane.showMessageDialog(null, "Connection Established!");
// Init streams when connection is etablished
inStream = new ObjectInputStream(socket.getInputStream());
outStream = new ObjectOutputStream(socket.getOutputStream());
frame.settingPanelForServer.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
connected = true;
} catch (IOException ex) {
Logger.getLogger(ServerApp.class.getName()).log(
Level.SEVERE, null, ex);
}
int x = 0;
// The loop is made to send/receive all messages
while (connected) {
try {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(ServerApp.class.getName()).log(
Level.SEVERE, null, ex);
}
Object o = String.format("I send you a message (%s)", x++);
outStream.writeObject(o);
Object response = inStream.readObject();
System.out.println("Response: " + response);
} catch (IOException ex) {
Logger.getLogger(ServerApp.class.getName()).log(
Level.SEVERE, null, ex);
connected = false;
} catch (ClassNotFoundException ex) {
Logger.getLogger(ServerApp.class.getName()).log(
Level.SEVERE, null, ex);
connected = false;
}
}
System.err.println("Connection closed");
}
public static void connectionEstablished(Frame frame) {
frame.remove(frame.waitPanel);
frame.getContentPane().add(frame.settingPanelForServer);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame) {
frame.remove(frame.settingPanelForServer);
frame.getContentPane().add(frame.playPanelForServer);
frame.validate();
frame.repaint();
}
public static Map getMap() {
try {
if (inStream.readObject() != null && inStream.readObject() instanceof Map) {
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void sendMap() {
if (mapToSend != null) {
try {
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ClientApp:
public class ClientApp implements Runnable {
public static String hostIP = "127.0.0.1";
public static int port = 1000;
public static boolean connected = false;
public static boolean connecting = true;
public static boolean iAmReady = false;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public final Frame frame;
public static Map mapToGet;
public static Map mapToSend;
public ClientApp(Frame parent) {
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
#Override
public void run() {
try {
// Client initialization side
socket = new Socket(hostIP, port);
// If the socket connection succeed it pass, else execption is thrown
JOptionPane.showMessageDialog(null, "Connection Established!");
// Initialize streams
outStream = new ObjectOutputStream(socket.getOutputStream());
inStream = new ObjectInputStream(socket.getInputStream());
frame.settingPanelForClient.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
connected=true;
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(
Level.SEVERE, null, ex);
}
// The loop will receive server message and send response
while (connected) {
try {
Object serverMessage = inStream.readObject();
System.out.println("Server sent: " + serverMessage);
Object myResponse = String.format("I received %s", serverMessage);
outStream.writeObject(myResponse);
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(
Level.SEVERE, null, ex);
connected=false;
} catch (ClassNotFoundException ex) {
Logger.getLogger(ClientApp.class.getName()).log(
Level.SEVERE, null, ex);
connected=false;
}
}
System.err.println("Connection closed");
}
public static void connectionEstablished(Frame frame) {
frame.remove(frame.connectPanel);
frame.getContentPane().add(frame.settingPanelForClient);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame) {
frame.remove(frame.settingPanelForClient);
frame.getContentPane().add(frame.opponentsMove);
frame.validate();
frame.repaint();
}
public static Map getMap() {
try {
if (connected) {
if (inStream.readObject() != null && inStream.readObject() instanceof Map) {
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void sendMap() {
if (connected) {
if (mapToSend != null) {
try {
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

Reading and Writing to Sockets, Java

I have a little problem with reading and writing to Sockets in my Server/Client Java application. Server have connection to database. I want to send an object "Employee" consist User Data (Name, Surname, Password) to Server, then Server look up to database about this user and resend to Client information - positive (1) or negative (-1).
First, when I want to send an object Employee, I've got :
"java.net.SocketException: Software caused connection abort: socket write error"
I have my Firewall turned off.
Second, when I want to send and receive just int through writeInt - readInt method for test, I can't to read anything on Server.
What's the problem? Please help.
Code Server:
class ClientCommunication implements Runnable {
private Socket incoming;
public ClientCommunication(Socket clientSocket) {
incoming = clientSocket;
}
public void run() {
try {
synchronized (this) {
try {
serverObjectOutput = new ObjectOutputStream(
incoming.getOutputStream());
serverObjectInput = new ObjectInputStream(
incoming.getInputStream());
} finally {
incoming.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
synchronized(this) {
while (true) {
try{
int operation = serverObjectInput.readInt();
switch(operation) {
case 1:
Employee employee = (Employee) serverObjectInput.readObject();
String SelectUserDataSQL = "SELECT COUNT(*) AS COUNT FROM pracownik where Imie = ? AND Nazwisko = ? AND Haslo = ?";
PreparedStatement CheckEmployeeLogin;
CheckEmployeeLogin = conn.prepareStatement(SelectUserDataSQL);
CheckEmployeeLogin.setString(1, employee.getFirstName());
CheckEmployeeLogin.setString(2, employee.getLastName());
CheckEmployeeLogin.setString(3, new String(employee.getPassword()));
ResultSet resultSQL = CheckEmployeeLogin.executeQuery();
if (resultSQL.next())
if (resultSQL.getInt("COUNT") == 0)
serverObjectOutput.writeInt(1);
else serverObjectOutput.writeInt(-1);
break;
}
} catch(IOException | ClassNotFoundException | SQLException ex)
{
}
}
}
}
}
class ServerStart implements Runnable {
private int portNumber;
public ServerStart(int portNumber) {
this.portNumber = portNumber;
}
public void run() {
try {
conn = getConnection();
stat = conn.createStatement();
} catch (SQLException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
serverSocket = new ServerSocket(portNumber);
} catch (IOException e) {
e.printStackTrace();
}
try {
while (true) {
Socket incoming = serverSocket.accept();
clientSockets.add(incoming);
Runnable r = new ClientCommunication(incoming);
Thread t = new Thread(r);
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code Client:
public void actionPerformed(ActionEvent e) {
if (isConnected == false) {
String ServerIP = ip.getText().trim();
int ServerPort = Integer
.parseInt(port.getText().trim());
try {
ClientSocket = new Socket(ServerIP, ServerPort);
clientObjectInput = new ObjectInputStream(
ClientSocket.getInputStream());
clientObjectOutput = new ObjectOutputStream(
ClientSocket.getOutputStream());
isConnected = true;
} catch (IOException ex) {
}
synchronized (this) {
try {
ClientLoginFrame login = new ClientLoginFrame();
Employee employee = login.getEmployee();
clientObjectOutput.writeObject(employee);
int result = clientObjectInput.readInt();
if(result == 1)
{
// DO SOMETHING
}
else {
ClientSocket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
});
}
add an ex.printStackTrace() to see what is happening in your
catch(IOException | ClassNotFoundException | SQLException ex)
Server side, on your ClientCommunication class: it seems you are closing the socket before entering the while loop. So the socket is already closed and cannot send/receive messages. You should NOT call incoming.close() there, but at the end of your run() method.

Trying to tunnel through https via a proxy built from ground up browser never responds back?

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.

Categories

Resources