Help needed in HTTP Tunneling - urgent

Hi all,

I urgently need a working code sample of aclient which sends requests to a server that redirects the request to an RMI server via RMI servlet.

Does any of you familiar of such a code sample?

Thanks

[238 byte] By [Lior_Levya] at [2007-11-27 11:20:50]
# 1

The client isn't any different from a normal RMI client. HTTP tunnelling is automatic when enabled at the server end.

ejpa at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 2

My current client contains the following:

LocateRegistry.getRegistry(host, port, RMISocketFactory.getDefaultSocketFactory());

Don't I need to change it to:

LocateRegistry.getRegistry(host, port, new sun.rmi.transport.proxy.RMIHttpToCGISocketFactory());

Lior_Levya at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 3

I already answered that. No.

ejpa at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 4

[nobr]I'm sorry, but HTTP Tunneling is not working for me. I must have done something wrong.

Let me describe my configuration:

I have a server behind NAT router which connected to apache2 and tomcat 4.1 web servers. The apache2 and tomcat are not connected between them.

I deployed war file on tomcat which contains the servlet for the HTTP Tunneling which its code is:

public class RmiHttpTunnelerServlet extends HttpServlet

{

public void init(ServletConfig config) throws ServletException

{

super.init(config);

System.out.println("Simplified RMI Servlet Handler loaded successfully.");

}

public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException

{

try

{

String queryString = req.getQueryString();

String command, param;

int delim = queryString.indexOf("=");

if (delim == -1)

{

command = queryString;

param = "";

}

else

{

command = queryString.substring(0, delim);

param = queryString.substring(delim + 1);

}

if (command.equalsIgnoreCase("forward"))

{

try

{

ServletForwardCommand.execute(req, res, param);

}

catch (ServletClientException e)

{

returnClientError(res, "client error : " + e.getMessage( ));

e.printStackTrace();

}

catch (ServletServerException e)

{

returnServerError(res, "internal server error : " + e.getMessage());

e.printStackTrace();

}

}

else

{

returnClientError(res, "invalid command: " + command);

}

}

catch (Exception e)

{

returnServerError(res, "internal error: " + e.getMessage());

e.printStackTrace();

}

}

public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException

{

returnClientError(res, "GET Operation not supported: Can only forward POST requests.");

}

public void doPut(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException

{

returnClientError(res, "PUT Operation not supported: Can only forward POST requests.");

}

public String getServletInfo()

{

return "Simplified RMI Call Forwarding Servlet Servlet.<br>\n ";

}

private static void returnClientError(HttpServletResponse res, String message) throws IOException

{

res.sendError(HttpServletResponse.SC_BAD_REQUEST,

"<HTML><HEAD><TITLE>Java RMI Client Error < / TITLE > < / HEAD > < BODY > " +

"<H1>Java RMI Client Error</H1>" + message + "</BODY></HTML>");

System.err.println(HttpServletResponse.SC_BAD_REQUEST + "Java RMI Client Error" + message);

}

private static void returnServerError(HttpServletResponse res,

String message) throws IOException

{

res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,

"<HTML><HEAD>< TITLE > Java RMI Server Error < / TITLE > < / HEAD > < BODY > " +

"<H1>Java RMI Server Error < / H1 > " + message + " < / BODY > < / HTML > ");

System.err.println(HttpServletResponse.SC_INTERNAL_SERVER_ERROR + "Java RMI Server Error : " + message);

}

}

There is also a utility class:

public class ServletForwardCommand {

public static void execute(HttpServletRequest request, HttpServletResponse response, String stringifiedPort)

throws ServletClientException, ServletServerException, IOException {

int port = convertStringToPort(stringifiedPort);

Socket connectionToLocalServer = null;

try {

connectionToLocalServer = connectToLocalServer(port);

forwardRequest(request, connectionToLocalServer);

forwardResponse(response, connectionToLocalServer);

} finally {

if (null != connectionToLocalServer) {

connectionToLocalServer.close();

}

}

}

private static int convertStringToPort(String stringfiedPort) throws ServletClientException {

int returnValue;

try {

returnValue = Integer.parseInt(stringfiedPort);

} catch (NumberFormatException e) {

throw new ServletClientException("invalid port number: " + stringfiedPort);

}

if (returnValue <= 0 || returnValue > 0xFFFF) {

throw new ServletClientException("invalid port: " + returnValue);

}

if (returnValue < 1024) {

throw new ServletClientException("permission denied for port: " + returnValue);

}

return returnValue;

}

private static Socket connectToLocalServer(int port) throws ServletServerException {

Socket returnValue;

try {

returnValue = new Socket(InetAddress.getLocalHost(), port);

} catch (IOException e) {

throw new ServletServerException("could not connect to " + "local port");

}

return returnValue;

}

private static void forwardRequest(HttpServletRequest request, Socket connectionToLocalServer)

throws IOException, ServletClientException, ServletServerException {

byte buffer[];

DataInputStream clientIn = new DataInputStream(request.getInputStream());

buffer = new byte[request.getContentLength()];

try {

clientIn.readFully(buffer);

} catch (EOFException e) {

throw new ServletClientException("unexpected EOF " + "reading request body");

} catch (IOException e) {

throw new ServletClientException("error reading request" + " body");

}

DataOutputStream socketOut = null;

// send to local server in HTTP

try {

socketOut = new DataOutputStream(connectionToLocalServer.getOutputStream());

socketOut.writeBytes("POST / HTTP/1.0\r\n");

socketOut.writeBytes("Content-length: " + request.getContentLength() + "\r\n\r\n");

socketOut.write(buffer);

socketOut.flush();

} catch (IOException e) {

throw new ServletServerException("error writing to server");

}

}

private static void forwardResponse(HttpServletResponse response, Socket connectionToLocalServer)

throws IOException, ServletClientException, ServletServerException {

byte[] buffer;

DataInputStream socketIn;

try {

socketIn = new DataInputStream(connectionToLocalServer.getInputStream());

} catch (IOException e) {

throw new ServletServerException("error reading from " + "server");

}

String key = "Content-length:".toLowerCase();

boolean contentLengthFound = false;

String line;

int responseContentLength = -1;

do {

try {

line = socketIn.readLine();

} catch (IOException e) {

throw new ServletServerException("error reading from server");

}

if (line == null) {

throw new ServletServerException("unexpected EOF reading server response");

}

if (line.toLowerCase().startsWith(key)) {

responseContentLength = Integer.parseInt(line.substring(key.length()).trim());

contentLengthFound = true;

}

}

while ((line.length() != 0) &&

(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));

if (!contentLengthFound || responseContentLength < 0)

throw new ServletServerException("missing or invalid content length in server response");

buffer = new byte[responseContentLength];

try {

socketIn.readFully(buffer);

} catch (EOFException e) {

throw new ServletServerException("unexpected EOF reading server response");

} catch (IOException e) {

throw new ServletServerException("error reading from server");

}

response.setStatus(HttpServletResponse.SC_OK);

response.setContentType("application/octet-stream");

response.setContentLength(buffer.length);

try {

OutputStream out = response.getOutputStream();

out.write(buffer);

out.flush();

} catch (IOException e) {

throw new ServletServerException("error writing response");

}

}

}

I checked also with packets monitoring tool, I couldn't see any http transportation.

Any help will be appreciated.[/nobr]

Lior_Levya at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 5

I forgot to mention that I receive the following exception:

java.rmi.ConnectIOException: Exception creating connection to: 10.17.6.7; nested exception is: java.io.IOException: Network is unreachable: connect

Lior_Levya at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 6

I don't know where any of that code comes from, but Sun supply an RMI forwarding servlet that works with the samples in the JDK.

If you're getting 'network unreachable' it probably means the server is exporting itself via its private address, not the NAT box's address. Set java.rmi.server.hostname at the server to the NAT box's address and arrange for all the required port forwarding there.

ejpa at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 7

Thanks for your reply.

I have 2 questions regarding your last post:

1. Could you please provide the name of that servlet or where I can find it?

2. If I use the java.rmi.server.hostname parameter, why would I need the servlet? I already succeeded connecting the server behind the NAT router with that parameter but it caused me a problem that I couldn't connect the server fron the inside network. This is the reason I removed this parameters and tried to connect using HTTP Tunneling.

Lior_Levya at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 8

> 1. Could you please provide the name of that

> servlet or where I can find it?

On my box it's in C:\Program Files\Java\jdk1.5.0_01\docs\guide\rmi\archives\rmizervlethandler.zip.

> 2. If I use the

> java.rmi.server.hostname parameter, why would

> I need the servlet?

Because your sysadmin may not want to open anything except port 80. If he will do that, you're right, you don't need it.

> I already succeeded connecting

> the server behind the NAT router with that parameter

> but it caused me a problem that I couldn't connect

> the server fron the inside network. This is the

> reason I removed this parameters and tried to connect

> using HTTP Tunneling.

You'll get the same problem. It's caused by the internal clients not being allowed to connect to the external address. HTTP tunnelling can't fix that.

ejpa at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 9

You wrote: It's caused by the internal clients not being allowed to connect to the external address

I checked with the sysadmin and all the ports are open, it means that I don't need the servlet, right?

So how can I force the system to let the internal client to connect to the external address?

Lior_Levya at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...
# 10

It's not a question of the ports being open, it's a question of whether the internal clients can connect to the external IP address. Talk to your netadmin about this, there's nothing you can do about it in Java.

ejpa at 2007-7-29 14:44:58 > top of Java-index,Core,Core APIs...