I am developing a proxy server based on java. For simple http request, proxy server is working. But for HTTPS Connection, connection gets timed out. Here are the steps I did. I first read one line from input stream and created a socket connecting Server. After that I gave 200 Status to client. After that I asynchronously read and write between Client Socket and Server socket. But currently this isn't working and connection gets timedout and I couldn't debug the problem.
public class ProxyServer extends Thread {
private String host;
private int port;
private ServerSocket serverSocket;
private InputStream proxyToClientIP;
private OutputStream proxyToClientOP;
private InputStream proxyToServerIP;
private OutputStream proxyToServerOP;
private Socket socket;
private Socket socketFromProxyServer;
ProxyServer(ServerSocket serverSocket, Socket socket) {
this.serverSocket = serverSocket;
this.socket = socket;
this.start();
}
public void run() {
processInputRequest();
}
public void processInputRequest() {
try {
proxyToClientIP = socket.getInputStream();
proxyToClientOP = socket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(proxyToClientIP));
String hostDetails = reader.readLine();
System.out.println(hostDetails);
boolean isConnect = false;
//Need to parse request and find req type as GET or CONNECT
//As of now we assume it to be Connect request
if (!isConnect) {
processGetRequest();
} else {
processConnectRequest();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void processConnectRequest() {
//Need to get host name from request. Currently Hardcoded for developing purpose
host = "harish-4072";
port = 8383;
try {
socketFromProxyServer = new Socket(host, port);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(proxyToClientOP));
writer.write("HTTP/1.1 200 Connection established\r\n" + "\r\n");
writer.flush();
proxyToServerOP = socketFromProxyServer.getOutputStream();
proxyToServerIP = socketFromProxyServer.getInputStream();
proxyRequest();
} catch (IOException ex) {
System.out.println(ex);
}
}
public void proxyRequest() {
try {
new Thread() {
#Override
public void run() {
try {
byte[] read = new byte[1024];
int in;
System.out.println("Reading");
while ((in = proxyToClientIP.read(read)) != -1) {
proxyToServerOP.write(read, 0, in);
proxyToServerOP.flush();
}
} catch (SocketException e) {
System.out.println(e);
} catch (IOException ex) {
}
}
}.start();
byte[] reply = new byte[1024];
int out;
System.out.println("Writing");
while ((out = proxyToServerIP.read(reply)) != -1) {
proxyToClientOP.write(reply, 0, out);
proxyToClientOP.flush();
}
} catch (IOException ex) {
}
public void processGetRequest() {
//
}
}
I first read one line from input stream and created a socket connecting Server. ... After that I asynchronously read and write between Client Socket and Server socket.
The problem is that you are reading only a single line while you would need to read the full HTTP request header from the client, i.e. everything up to the end of the request header (\r\n\r\n).
Because you fail to do so the unread parts of the HTTP request are forwarded to the server. But the server is expecting the start of the TLS handshake and these data confuse the server. This might result in hanging or aborting, depending on the content of the data and one the kind of server.
Related
I am trying to create a Modbus setup as follows:
client <----> IED <----> Modbus Server
IED has the IP 192.168.x.x and Modbus Server uses localhost as IP. All entities are in the same VM. The client is supposed to send a request to the IED,the IED forwards it to the server and the server responds to the IED.
The problem is the IED receives the request from the master which is stored in a byte array but transmitting the request to the server does not work. Wireshark traces show that the TCP connection is established with the server but request is not transmitted.
See the code below:
public class App {
public static void main(String[] args) {
IEDServer iedServer = new IEDServer();
iedServer.start(502);
}
}
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
public class IEDServer {
private ServerSocket serverSocket;
public void start (int port){
try {
InetAddress inetAddress = InetAddress.getByName("192.168.20.138");
serverSocket = new ServerSocket(port, 1024, inetAddress);
while (true){
new ClientHandler(serverSocket.accept()).start();
System.out.println("Connection accepted");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop(){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.Socket;
public class ClientHandler extends Thread{
private Socket clientSocket;
private DataOutputStream out;
private DataInputStream in;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
//connection from client
out = new DataOutputStream (clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
// in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// String readline;
//for connection to modbus server
Socket modbusSocket = new Socket("127.0.0.1",502);
modbusSocket.setSoTimeout(10000);
DataOutputStream modbus_out = new DataOutputStream (clientSocket.getOutputStream());
DataInputStream modbus_in = new DataInputStream(clientSocket.getInputStream());
byte [] modbus_bytes = {};
//read Modbus bytes from client to get client request
modbus_bytes = in.readAllBytes();
System.out.println("Modbus request: ");
for (byte b: modbus_bytes){
System.out.print(b);
}
System.out.println();
//transfer modbus request to modbus server
modbus_out.write(modbus_bytes, 0, modbus_bytes.length);
//get response from modbus server
modbus_bytes = modbus_in.readAllBytes();
System.out.println("Modbus response: ");
for (byte b: modbus_bytes){
System.out.print(b);
}
System.out.println();
//transfer response to client
out.write(modbus_bytes,0,modbus_bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
//close TCP connection
try {
in.close();
out.close();
clientSocket.close();
System.out.println("Connection terminated");
} catch (IOException e) {
e.printStackTrace();
System.out.println("Connection termination failed");
}
}
}
Also find below, the wireshark screenshot
Call DataOutputStream.flush() after DataOutputStream.write() to force the bytes to be send
I managed to fix it. I mistakenly passed clientSocketinstead of modbusSocketas a parameter to the modbus_inand modbus_outStream instances. I also had to poll for availability of data before reading and then writing. Also, I noticed that the client-side closed the TCP session while the server-side had it open. So I ensured that the connection was closed after each query.
Please find modified code below for ClientHandler:
import java.io.*;
import java.net.Socket;
public class ClientHandler extends Thread {
private Socket clientSocket;
private Socket modbusSocket;
private DataOutputStream out, modbus_out;
private DataInputStream in, modbus_in;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
System.out.println(clientSocket.getInetAddress());
try {
out = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream()));
in = new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
// in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// String readline;
//for connection to modbus server
modbusSocket = new Socket("127.0.0.1", 502);
// modbusSocket.setSoTimeout(10000);
modbus_out = new DataOutputStream(new BufferedOutputStream(modbusSocket.getOutputStream()));
modbus_in = new DataInputStream(new BufferedInputStream(modbusSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
//connection from client
if (in.available() > 0) {
//read Modbus bytes from client to get client request
System.out.println("===============Begin reading===============");
byte[] modbus_bytes = new byte[in.available()];
in.read(modbus_bytes);
System.out.println("Modbus request: ");
for (byte b : modbus_bytes) {
System.out.print(b);
}
System.out.println();
//transfer modbus request to modbus server
modbus_out.write(modbus_bytes);
modbus_out.flush();
System.out.println("Written to modbus server");
while (modbus_in.available() == 0) {
System.out.println("Waiting for device response...");
}
System.out.println("\nDevice response ready");
//get response from modbus server
modbus_bytes = new byte[modbus_in.available()];
modbus_in.read(modbus_bytes);
System.out.print("Modbus response: ");
for (byte b : modbus_bytes) {
System.out.print(b);
}
System.out.println("\nSending response to client");
//transfer response to client
out.write(modbus_bytes);
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
//close TCP connection
try {
// in.close();
// out.close();
clientSocket.close();
modbusSocket.close();
System.out.println("===========Connection terminated==============");
} catch (IOException e) {
e.printStackTrace();
System.out.println("Connection termination failed");
}
}
}
I have an application that has to send data via TCP socket to another application. This is a 1 way stream from client to server. When sending data the client must retry/reconnect and try to insure all data is sent should the receiver/listener/server die/disappear or drop the connection. My code is as follow:
public class TCPSocket implements Closeable {
private static final int SIXTY_FOUR_KB = 65536;
private final String ip;
private final int port;
private Socket socket;
private BufferedOutputStream writer;
public TCPSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public TCPSocket connect() throws ConnectException {
try {
socket = new Socket(ip, port);
socket.setSendBufferSize(SIXTY_FOUR_KB);
writer = new BufferedOutputStream(socket.getOutputStream(), SIXTY_FOUR_KB);
} catch (Exception e) {
throw new ConnectException(e.getMessage());
}
return this;
}
public void write(String message) throws InterruptedException {
boolean succeeded = true;
do {
try {
writer.write(message.getBytes(StandardCharsets.UTF_8));
writer.write("\n".getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
System.out.println(e.getMessage());
succeeded = false;
// Exponential backoff to go here
try {
System.out.println("Attempting reconnection");
tryClose();
connect();
} catch (ConnectException connectException) {
System.out.println(connectException.getMessage());
}
}
} while (!succeeded);
}
private void tryClose() {
try {
close();
} catch (Exception ex) {
System.out.println("Failed closing TCPSocket");
}
}
#Override
public void close() throws IOException {
if (writer != null) {
writer.flush();
writer.close();
writer = null;
}
if (socket != null && !socket.isClosed()) {
socket.close();
socket = null;
}
}
}
N.B: Reason for using the BufferedOutputStream is because I'm sending small messages and all other methods couldn't get the same throughput in real world test scenario.
This all works as expected for me however I have a few points.
Is this the right way to do this or totally insane and will cause
serious problems?
When trying to clean up and close connections and the writer before
opening a new connection the following error is thrown and I am
unable to close the bufferedOutputStream
java.net.SocketException: Connection reset by peer: socket write error
If I socket.shutdownOutput(); before attempting to close the output stream then that also throws an exception. What is the correct way to clean up and reconnect?
working with sockets on this problem. I wrote the implementation of Http and TCP servers. HTTP works completely correctly, so I can send requests to the server one by one. What can not be said about the TCP server, the first request leaves and is handled correctly, but when you try to send the following request, throws this exception:
java.net.SocketException: Software caused connection abort: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:134)
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
at Main.main(Main.java:24)
After that, the client side is closed, and the server side continues to work.HTTP and TCP are implemented from the same Server class, which starts the server.
MyServer:
public abstract class Server implements Runnable {
private final Socket clientSocket;
public Server(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream()))) {
String req = getRequest(reader);
setResponse(output, req);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Class that starts the server:
public class RunServer extends Thread {
private final int port;
private ExecutorService executorService;
private String serverType;
private ServerFactoryContainer serverFactoryContainer;
public RunServer(String serverType, int port) {
this.port = port;
this.executorService = Executors.newFixedThreadPool(4);
this.serverType = serverType;
this.serverFactoryContainer = new ServerFactoryContainer();
}
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (!isInterrupted()) {
Socket clientSocket;
try {
clientSocket = serverSocket.accept();
executorService.execute(serverFactoryContainer.getServerFactory(serverType).createServer(clientSocket));
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
TCP client-side:
public class Main {
public static void main(String[] args) throws IOException {
String req;
String resp;
try (Socket clientSocket = new Socket(InetAddress.getLocalHost(), Constants.ServerConstant.TCP_PORT);
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
while (true) {
System.out.println("Write command [get count] or [get item]");
req = inFromClient.readLine().toLowerCase();
outToServer.writeBytes(req + "\n"); // I get an exception here when I send a request to the server
resp = inFromServer.readLine();
if (!resp.isEmpty()) {
System.out.println(resp);
}
if (req.equals("exit")) {
System.exit(1);
}
}
}
}
Why do I get the exception that I indicated above when I resubmit the request to the TCP server and why is this exception not thrown when sending a second request to the HTTP server?
#Override
protected String getRequest(BufferedReader input) throws IOException {
return input.readLine();
}
#Override
protected void setResponse(BufferedWriter output, String request) throws IOException {
String result = serverCommandController.execute(RequestParser.tcpParserCommand(request));
output.write(result);
output.flush();
}
You are closing the client connection before the client is done. Try this in your Server class:
#Override
public void run()
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream())))
{
while (clientSocket.isConnected())
{
String req = getRequest(reader);
setResponse(output, req);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Your server appears to close the socket after sending a response. After that, the client will not be able to send further requests without opening a new connection. Typically, the server allows the client to control the fate of the connection, so that the client can send multiple requests. Your client could send a "close" request to indicate to the server that the client intends to close the socket and does not expect a response.
I am new to google protocol buffer . I am writing a client server application where client send request object to server and server return response. Currently when i send object to server neither the server respond nor throw any exception. Probably it stuck on line
Request request = Request.parseFrom(bytes);
where Request and Response are my message classes generated by protocol buffer.
My code samples are as follows
public class TCPServer {
final static Logger logger = Logger.getLogger(TCPServer.class.getName());
static int PORT = 6789;
public static void main(String argv[]) throws Exception
{
ServerSocket socket = new ServerSocket(PORT);
Socket connectionSocket = null;
while(true)
{
try{
connectionSocket = socket.accept();
}catch (IOException e) {
System.out.println("Could not listen on port:" + PORT);
System.exit(-1);
}
Thread thread = new Thread(new ServerConnection(connectionSocket));
thread.start();
}
}
}
public class ServerConnection implements Runnable{
static final Logger logger = Logger.getLogger(ServerConnection.class.getName());
String clientInput;
String serverOutput = null;
Socket connectionSocket = null;
ServerConnection(Socket connectionSocket){
this.connectionSocket = connectionSocket;
}
public void run() {
try {
InputStream input = connectionSocket.getInputStream();
ObjectInputStream inFromClient = new ObjectInputStream(input);
ObjectOutputStream outToClient = new ObjectOutputStream(connectionSocket.getOutputStream());
serveRequest(inFromClient , outToClient);
outToClient.flush();
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
System.out.println("Exception occured in ServerConnection run() method");
}
}
public void serveRequest(InputStream inFromClient, OutputStream outToClient){
try {
System.out.println("Recieving data from client");
ResponseReciever response = new ResponseReciever();
ObjectInputStream input = (ObjectInputStream) inFromClient;
byte size = input.readByte();
byte []bytes = new byte[size];
input.readFully(bytes);
Request request = Request.parseFrom(bytes);
System.out.println("Request recieved");
response.createResponse(request.getId(),request.getMessage(),true).writeTo(outToClient);
System.out.println("Response send");
} catch (Exception ex) {
logger.log(Level.SEVERE, null, ex);
System.out.println("Exception occured in ServerConnection serverRequest() method");
}
}
And my client look like this
public class TCPClient {
final static Logger logger = Logger.getLogger(TCPClient.class.getName());
private static int PORT = 6789;
private static String HOST_NAME = "localhost";
private static boolean isOpen = true;
private Socket openConnection(final String hostName,final int port){
Socket clientSocket = null;
try {
clientSocket = new Socket(HOST_NAME, PORT);
} catch (IOException e) {
logger.log(Level.SEVERE, "Exception occured while connecting to server", e);
}
return clientSocket;
}
private void closeConnection(Socket clientSocket){
try {
logger.log(Level.INFO, "Closing the connection");
clientSocket.close();
isOpen = false;
} catch (IOException e) {
logger.log(Level.SEVERE, "Exception occured while closing the connection", e);
}
}
public void sendToServer(OutputStream output){
try {
System.out.println("Sending data to server");
RequestSender requestSender = new RequestSender();
Request request = requestSender.getRequest(1,"param1","param2",23L,"Its message",true);
ObjectOutputStream outputStream = (ObjectOutputStream)output;
request.writeTo(outputStream);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
public void recieveFromServer(InputStream input){
try {
System.out.println("Recieving data from server");
Response response = Response.parseFrom(input);
System.out.println(response.getId());
System.out.println(response.getResponse());
System.out.println(response.getError());
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
public static void main(String argv[]) throws Exception
{
ObjectOutputStream outToServer = null;
InputStream inFromServer = null;
TCPClient client = new TCPClient();
try {
while(isOpen)
{
Socket clientSocket = client.openConnection(HOST_NAME, PORT);
outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
inFromServer = new ObjectInputStream(clientSocket.getInputStream());
client.sendToServer(outToServer);
client.recieveFromServer(inFromServer);
}
}catch (Exception e) {
logger.log(Level.SEVERE, "Exception occured ", e);
System.out.println("Exception occured in TCPClient main() method");
System.exit(1);
}
}
}
I am unable to find what is wrong in the code. Please let me know if you find something missing.
It works by using writeDelimtedTo(outputStream) and parseDelimitedFrom(inputStream) instead of writeTo(outputStream) and parseFrom(inputStream). So by putting the following code on server and client sides the program works.
Server side:
InputStream input = connectionSocket.getInputStream();
OutputStream output = connectionSocket.getOutputStream();
Request request = null;
while ((request = Request.parseDelimitedFrom(input)) != null) {
System.out.println(request.toString());
}
Client side:
Socket clientSocket = client.openConnection(HOST_NAME, PORT);
Request request = getRequest();
OutputStream output = clientSocket.getOutputStream();
InputStream input = clientSocket.getInputStream();
request.writeDelimitedTo(output);
If you start sending protocol buffers over the wire - then you will need to "frame" them. The problem is reported and solved with this question: does protobuf need a network packet header?
Instead of writing all this code, you could checkout https://code.google.com/p/protobuf-rpc-pro/ and see if it satisfies your requirements for RPC between java server and java clients.
Hi i have a server socket that listens for requests from a client socket and my code doesnt seem to retrieve the data from its inputstream on data sent from the client socket.
below is the server socket code that listens for connections and handles the requests
public void startlistener() {
serverSocket = new ServerSocket(PORT);
listening = true;
thread.start();
Log.print(TAG, "startlistener");
}
public void stopListener() {
thread.stop();
listening = false;
Log.print(TAG, "stopListener");
}
public void run() {
while (listening) {
try {
Log.d(TAG, "inside server listener loop");
Socket accept = serverSocket.accept();
String data = getData(accept);
httpHandler.handleRequest(data, accept);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getData(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
Log.print(TAG, "getData");
int c = 0;
StringBuffer buffer = new StringBuffer();
//goes as far as here and then freezes/doesnt retrieve anything from the input stream
while ((c = in.read()) != -1) {
buffer.append((char) c);
}
return buffer.toString();
}
Here is my testcase
private static final String HTTP_REQUEST = "HTTP/1.0 408 Request Time-out"
+ newLine + "Cache-Control: no-cache" + newLine
+ "Connection: close" + newLine + "Content-Type: text/html";
public void testSocketConnection() {
try {
httpProxy = new HttpProxy(testHttpHandler);
httpProxy.startlistener();
testSocket = new Socket("localhost", HttpProxy.PORT);
OutputStream outputStream = testSocket.getOutputStream();
InputStream inputStream = testSocket.getInputStream();
outputStream.write(HTTP_REQUEST.getBytes());
} catch (UnknownHostException e) {
httpProxy.stopListener();
e.printStackTrace();
fail(e.toString());
} catch (IOException e) {
httpProxy.stopListener();
e.printStackTrace();
fail(e.toString());
}
}
Your client doesn't close the socket. Your server reads the socket until EOS, which will never arrive as your client doesn't close the socket.
NB don't handle client I/O in the accepting thread. Start a separate thread.