Google Answers Logo
View Question
 
Q: need Java applet to test whether user machine can receive incoming connections ( Answered 5 out of 5 stars,   1 Comment )
Question  
Subject: need Java applet to test whether user machine can receive incoming connections
Category: Computers > Programming
Asked by: bennetthaselton-ga
List Price: $175.00
Posted: 13 Jul 2003 08:17 PDT
Expires: 12 Aug 2003 08:17 PDT
Question ID: 229426
I need a straightforward Java applet written.  The purpose of the
applet is to determine whether a user's computer is able to receive
incoming connections on a given TCP port -- so that they can determine
whether they will be able to install a piece of software that acts as
a server and responds to incoming connections.  (There are a couple of
obstacles that might prevent a machine from listening for incoming
connections -- a hardware firewall, the built-in Windows XP firewall,
etc.)

The java applet should run on a Web page and take these parameters:
- listening_port
- detection_script_url
- success_url
- failure_url
- error_url

What the applet should do is:
1. start listening on the port number specified by listening_port
2. detect the user's local IP address, and send a request to the URL:
	- detection_script_url + '?ip=' + <local ip address>
3. the script at that URL will attempt to connect to the Java applet. 
The Java applet doesn't have to do anything in response to this.  But
once the script has attempted to connect, the script outputs either
"Yes" or "No" over HTTP -- or, it outputs something to indicate
whether the connection was successful.  I've heard that
XML/SOAP/something along those lines is the most supported way to pass
parameter information over the Web like that.  Since I'll be writing
the server-side script, just let me know what output you need.
4. If the script outputs that the connection was succcessful, the
applet redirects the browser to success_url.  If the script outputs
that the connection failed, the applet redirects the browser to
failure_url.  If there is an error accessing the script itself,
redirect the browser to error_url.

It may be that the Java applet has to be signed in order to listen for
incoming connections, even if it's just listening for incoming
connections from the same server that served it.  If that's the case,
please let me know what I have to do to get it signed, after it's
written.

Request for Question Clarification by answerguru-ga on 14 Jul 2003 15:01 PDT
Hi bennetthaselton-ga,

Just wanted to let you know that I've start working on this applet for
you - I will try to have it completed on Wednesday at the latest :)

answerguru-ga

Request for Question Clarification by answerguru-ga on 15 Jul 2003 23:49 PDT
Hi again,

This is just a note to other researchers who may want to take on this
question - due to time contraints I will not be able to answer and so
other researchers can answer if they so choose.

answerguru-ga

Clarification of Question by bennetthaselton-ga on 17 Jul 2003 15:05 PDT
OK, thanks.  Hope somebody else can take this on for me.  I think I'm
going to bump up the amount of money being offered.
Answer  
Subject: Re: need Java applet to test whether user machine can receive incoming connections
Answered By: rhansenne-ga on 28 Jul 2003 06:46 PDT
Rated:5 out of 5 stars
 
Hi,

I constructed an applet according to your specifications. 

This applet opens a socket on a given port, then contacts a server
script which will test the connection on that port. If the server
returns a response containing the string "SUCCESS" (the response can
be plain text, xml or soap as long as it contains this string in case
of success), the applet will redirect the user to the success page,
else the user will be redirected to the failure page. If the applet
fails to contact the server script, the user will be redirected to the
error page.

The applet will pass the client ip address to the script as a
parameter "ip", however this will only work if the applet is signed
(which you're free to do). Even if the applet is signed, however, it
is still possible an internal network address is returned in stead of
the internet ip. Ideally, the script will determine the actual client
ip from the request.

I included a sample servlet script, implemented as a java servlet (and
an alternative in the form of a jsp page), which tests the socket
connection and retrieves the actual client ip from the request. The
client ip will usually be correct, except if a non-transparant proxy
is used by the client. Notice that the server where the script is
hosted needs to allow direct (non-http) tcp connections, for the
script to be able to contact the client.

You can retrieve the applet archive, as well as the source code to the
applet and scripts here:
http://users.pandora.be/rami/tcp/

The applet can be used in debug mode, in which case it will not
redirect, but simply display the parameters, result and error messages
(if any). Debug mode

can be used with the "debug" parameter:

 <APPLET CODE="TCPApplet" ARCHIVE="TCPApplet.jar" WIDTH=600
HEIGHT=200>
  <param name="listening_port" value="1234">
  <param name="detection_script_url" value="script.jsp">
  <param name="success_url" value="success.html">
  <param name="failure_url" value="failure.html">
  <param name="error_url" value="error.html">
  <param name="socket_timeout" value="5000">
  <param name="debug" value="true">
 </APPLET>

To enable the redirect mode, use the applet as follows:

 <APPLET CODE="TCPApplet" ARCHIVE="TCPApplet.jar" WIDTH=0 HEIGHT=0>
  <param name="listening_port" value="1234">
  <param name="detection_script_url" value="script.jsp">
  <param name="success_url" value="success.html">
  <param name="failure_url" value="failure.html">
  <param name="error_url" value="error.html">
  <param name="socket_timeout" value="5000">
 </APPLET>

The "socket_timeout" parameter is optional (defaults to 10000) and
defines the time the socket remains open (in ms).

If the applet is not signed, the script url should be hosted on the
same server the applet was downloaded from! Use relative path names in
this case (the applet will automaticall append the code base to the
url, except if the url starts with "http://").


Below you'll find a printout of the applet source:


//--------------------- START APPLET --------------------- //
import java.applet.*;
import java.io.*;
import java.net.*;

import java.awt.*;

/**
 * This applet opens a socket on a given port, then contacts a server
script
 * which will test the connection on that port. If the server returns
a response
 * containing the string "SUCCESS", the applet will redirect the user
to the success
 * page, else the user will be redirected to the failure page. If the
applet fails
 * to contact the server script, the user will be redirected to the
error page.
 * The applet will pass the client ip address to the script as a
parameter "ip",
 * however this will only work if the applet is signed and may be a
network
 * address. Ideally, the script will determine the actual client ip
from the request.
 */
public class TCPApplet
    extends Applet {

  // applet parameters names
  private static final String PARAM_PORT = "listening_port";
  private static final String PARAM_SCRIPT = "detection_script_url";
  private static final String PARAM_SUCCESS = "success_url";
  private static final String PARAM_FAILURE = "failure_url";
  private static final String PARAM_ERROR = "error_url";
  private static final String PARAM_TIMEOUT = "socket_timeout";
  private static final String PARAM_DEBUG = "debug";

  // the expected success string to be contained in the server script
response
  private static final String RESPONSE_SUCCESS = "SUCCESS";

  // applet parameters
  private String listenPort;
  private String scriptUrl;
  private String successUrl;
  private String failureUrl;
  private String errorUrl;
  private boolean debug;
  private int socketTimeOut;

  /**
   * This thread opens a connection for a time period defined by
   * "socket_timeout" and excepts connections from a server script.
   */
  private class PortListnerThread
      implements Runnable {

    public void run() {
      ServerSocket socket = null;
      Socket connectionSocket = null;
      try {
        // open a socket on the defined port
        socket = new ServerSocket(Integer.parseInt(listenPort));
        socket.setSoTimeout(socketTimeOut);
        connectionSocket = socket.accept();
        BufferedReader in =
          new BufferedReader(new
InputStreamReader(connectionSocket.getInputStream()));
        // read some input from socket, to allow server script to test
connection
        in.readLine();
      }
      catch (Exception exc) {
        System.out.println(exc.getMessage());
      }
      finally {
        if (connectionSocket != null) {
          try {
            connectionSocket.close();
          }
          catch (Exception exc) {}
        }
        if (socket != null) {
          try {
            socket.close();
          }
          catch (Exception exc) {}
        }
      }

    }

  }

  /**
   * Initializes the applet and retrieves the applet parameters
   */
  public void init() {
    listenPort = getParameter(PARAM_PORT);
    scriptUrl = getParameter(PARAM_SCRIPT);
    successUrl = getParameter(PARAM_SUCCESS);
    failureUrl = getParameter(PARAM_FAILURE);
    errorUrl = getParameter(PARAM_ERROR);
    debug = "true".equalsIgnoreCase(getParameter(PARAM_DEBUG));
    try {
      socketTimeOut = Integer.parseInt(getParameter(PARAM_TIMEOUT));
    } catch (Exception exc) {
      // default socket timeout: 10 seconds
      socketTimeOut = 10000;
    }
    // lookup local ip address and add it to the script url
    String ipAddress = null;
    try {
         // this will only work if the applet is signed! Else
127.0.0.1 will be returned
         // furthermore, on networks, the internal network address
will be returned
         InetAddress ia = InetAddress.getLocalHost();
         ipAddress = ia.getHostAddress();
    } catch (Exception exc) {
      // unable to determine local ip address
      ipAddress = "127.0.0.1";
    }
    scriptUrl += "?ip="+ipAddress;

  }

  /**
   * Writes debug info in debug mode or redirects to the correct url
otherwise
   */
  public void paint(Graphics g) {
    if (debug) {
      // Show debug info
      g.drawString("Port is: " + listenPort, 20, 20);
      g.drawString("Script url is: " + scriptUrl, 20, 40);
      g.drawString("Success url is: " + successUrl, 20, 60);
      g.drawString("Failure url is: " + failureUrl, 20, 80);
      g.drawString("Error url is: " + errorUrl, 20, 100);
      g.drawString("Socket timeout is: " + socketTimeOut + "ms", 20,
120);
      try {
        g.drawString("Result is: " + checkPort(), 20, 140);
      }
      catch (Exception exc) {
        g.drawString("Exception: " + exc.getMessage(), 20, 140);
      }
    } else {
      // perform redirect
      try {
        String result = checkPort();
        URL redirectURL;
        if (result.startsWith("http://"))
          redirectURL = new URL(scriptUrl);
        else
          redirectURL = new URL(getCodeBase(),result);

        getAppletContext().showDocument(redirectURL);
      }
      catch (MalformedURLException mue) {
        mue.printStackTrace();
      }
    }

  }

  /**
   * Starts a thread listner on the defined port and queries the
server script.
   * If the script response contains "SUCCESS", the success url is
returned,
   * otherwise the failure url is returned. If the server cannot be
contacted,
   * the error url is returned.
   */
  private String checkPort() {

    // open a socket listner thread for the server to connect to
    Thread listner = new Thread(new PortListnerThread());
    listner.start();

    try {
      // contact the server script
      StringBuffer scriptResponse = new StringBuffer();
      URL url;
      if (scriptUrl.startsWith("http://"))
        url = new URL(scriptUrl);
      else
        url = new URL(getCodeBase(),scriptUrl);
      URLConnection conn = url.openConnection();
      conn.setRequestProperty("Accept", "text/*");

      // read script response
      BufferedReader reader =
          new BufferedReader(new
                            
InputStreamReader(conn.getInputStream()));
      String line = null;
      while ( (line = reader.readLine()) != null) {
        scriptResponse.append(line);
      }
      reader.close();
      if (scriptResponse.toString().toUpperCase().indexOf(RESPONSE_SUCCESS)>0)
        return successUrl;
      else return failureUrl;
    } catch (Exception exc) {
      exc.printStackTrace();
      return errorUrl;
    }

  }

}
//--------------------- END APPLET --------------------- //



A sample server script JSP might look something like this:



<%
      // Sample server script
      try{

      // open a socket to client
      java.net.Socket clientSocket = new
java.net.Socket(request.getRemoteAddr(), 1234);

      java.io.DataOutputStream outToServer =
          new java.io.DataOutputStream(clientSocket.getOutputStream());

      // write anything to the socket to test the connection
      outToServer.writeBytes("socket test");

      clientSocket.close();

%>SOCKET CONNECT SUCCESS<%

    }
    catch (Exception exc) {

%>SOCKET CONNECT FAILED<%

    }
%>


A Java servlet version of the same script would be:



//--------------------- START SERVLET --------------------- //
import java.io.*;
import java.util.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;

/**
 * Sample servlet to test the applet functionality
 */
public class TCPServlet
    extends HttpServlet {

  private static final String PARAM_IP = "ip";
  private static final int PORT = 1234;

  /**
   * Handle applet requests
   */
  public void doGet(HttpServletRequest req, HttpServletResponse res)
throws
      IOException, ServletException {

    try {

      // the ip returned by the applet (might be network address)
      String ip = req.getParameter(PARAM_IP);

      // the actual client request ip
      String clientIp = req.getRemoteAddr();

      // open a socket
      Socket clientSocket = new Socket(clientIp, PORT);

      DataOutputStream outToServer =
          new DataOutputStream(clientSocket.getOutputStream());

      // write anything to the socket to test the connection
      outToServer.writeBytes("socket test");

      clientSocket.close();

      // return a response containing the "SUCCESS" string to the
applet
      res.getOutputStream().print("SOCKET CONNECT SUCCESS");

    }
    catch (Exception exc) {
      res.getOutputStream().print("SOCKET CONNECT FAILED");
    }
    res.getOutputStream().close();

  }

}

//--------------------- END SERVLET --------------------- //


The applet has been tested using the Java Virtual Machine plugin. I
haven't had the chance of testing it on the Microsoft Virtual Machine
yet. I'll do that as soon as possible and post an updated version if
problems would occur.


I hope this allows you to complete your project. If you have any
questions or problems feel free to ask for clarification!

Kind regards,

rhansenne-ga.

Request for Answer Clarification by bennetthaselton-ga on 10 Aug 2003 08:55 PDT
Hi rhansenne-ga,

I apologize for the delay in responding.  I have set my Google Answers
preferences to email me whenever someone posts an answer to one of my
questions, but for some reason, none of the mails sent from their
server have ever gotten through to me.  I've emailed back and forth
with Google asking what's going on, and offered to help debug the
problem if they wanted to send me a couple of test messages and I
could tell them which ones I received, but until then, I'll just have
to remember to log in more often to check whether any of my questions
have updated status.

OK, I downloaded the JAR file that you posted in your directory, and
uploaded it to:
http://www.peacefire.org/holder/java-port-listener-2/loader.html
with the "debug" value set to "true" in the HTML.

I haven't set up the server-side script yet though.  So when I load it
in Netscape 7.0, it gives the correct result:

Port is: 1234
Script url is: script.jsp?ip=127.0.0.1
Success url is: success.html
Failure url is: failure.html
Error url is: error.html
Socket timeout is: 5000ms
Result is: error.html

But when I load it in Internet Explorer (IE 6.0.2800.1106 on Windows
XP Home SP1), I get the error message in the status bar:
"load: class TCPApplet not found"

Is there any way to make it work in IE?  We really need to support IE
since it's used by the vast majority of users.

-Bennett

Clarification of Answer by rhansenne-ga on 11 Aug 2003 02:50 PDT
Hi bennetthaselton-ga,

The applet worked correctly under both Netscape and IE (6.0) with the
Sun JVM plugin. I've now tested it under IE with the Microsoft JVM and
it indeed gave the same error you mentioned. So I recompiled the
source with the Microsoft SDK and now it runs without problems on
both. I updated the jar and classes on
http://users.pandora.be/rami/tcp/ . Please try the new version and let
me know if it works.

I also set up the script on a host supporting JSP, so you can see the
applet at work:
http://www.mycgiserver.com/~rhansenne/tcp/
The actual script is set up at:
http://www.mycgiserver.com/~rhansenne/tcp/script.jsp
(it will of course fail to connect if you call it directly, since no
socket will be opened on the client)

This script will first attempt to connect to the address passed as
parameter by the applet (which will be wrong if the client is part of
a network or the applet is unsigned) and if that fails, it will try to
connect to the host address retrieved from the request (which should
succeed, unless of the client is behind a firewall or ip masquerading
proxy).

Best regards,

rhansenne-ga.

Request for Answer Clarification by bennetthaselton-ga on 11 Aug 2003 13:36 PDT
Hi Rhansenne,

Thanks for the update.  Two questions:

1) You'd said that you tested the first version and it worked in NS
and IE with the Sun JVM plugin, but then the newer version had to be
recompiled to work with the Microsoft JVM plugin.  Does the newer
version also still work with the Sun JVM plugin?  For a typical user,
what JVM will they have on their machine by default, the Sun JVM?  If
I had the Microsoft JVM and was getting different results from what
most users would have seen, could that have been because I installed
Visual J++ on my machine?  (In an abortive attempt to write this
applet myself :) )

2) I'm reading the instructions at:
http://forum.java.sun.com/thread.jsp?thread=174214&forum=63&message=1883852
which describe how to sign a Java applet -- they describe how to sign
it in your own testing environment (doesn't cost anything, but it will
only work on your own machine) and then how to sign it so that it will
work for other users over the Web (you have to pay money to VeriSign
or some other signing authority, but the general public will be able
to use it without getting scary warning messages in their browser). 
Has it been tested yet as a signed applet?  If not, and I'm testing it
for the first time in "signed" mode, then I'll let you know afterwards
if it works.

-Bennett

Request for Answer Clarification by bennetthaselton-ga on 11 Aug 2003 16:18 PDT
OK, I went to
http://forum.java.sun.com/thread.jsp?thread=174214&forum=63&message=1883852
and followed the instructions to get the TCPApplet.jar file
self-signed.  Now, when you open the signed TCPApplet.jar file in
WinZip, it contains two new files, Tstkey.rsa and Tstkey.sf.  So I
uploaded it and loaded it from this page using Netscape 7:
http://www.peacefire.org/holder/java-port-listener-2/loader.html
(To use your detection script, I had to set "detection_script_url" to
theh absolute URL for your script,
"http://www.mycgiserver.com/~rhansenne/tcp/script.jsp".  This worked
fine, even though they're on different servers.)

When I do that, Netscape gives me a prompt with the info:
>>>
Do you want to install and run signed applet distributed by "Bennett
Haselton"?
Publisher authenticity verified by: "Peacefire"
- The security certificate was issued by a company that is not
trusted.
- The security certificate has not expired and is still valid.
[etc.]
>>>
which is what you'd expect for a self-signed applet.  I pick the
option to say, Yes, install and run the applet.  When I do that, the
applet outputs "Result is: success.html", as expected.

However, I then shut down the browser and turned on the Windows XP
firewall, to block incoming connections, then went back to
http://www.peacefire.org/holder/java-port-listener-2/loader.html
using Netscape 7, it correctly displays my IP address, but this time,
no Result: line is outputted.  In fact the applet hangs, so that if I
drag some other window over the applet region, an image of that
window's contents will remain in that region.  If I look in the
Netscape 7 java console, however, it displays the line, "Accept timed
out".

Presumably this is a bug -- if the socket connection times out, then
the debug area of the applet should display "Result is: failure.html".

Same results if I load the JAR file from a page without the debug
parameter:
http://www.peacefire.org/holder/java-port-listener-2/loader-non-debug.html
If I load the page in Netscape 7 with the firewall turned off, then I
get redirected to "success.html" (which is currently 404 Not Found,
I'll put it there later) as expected.  But if I load it with the
firewall turned on, then "Accept timed out" gets written to the Java
console, and the applet hangs.

The other problem is that I still can't get IE to recognize it as a
signed applet.  Going to
http://www.peacefire.org/holder/java-port-listener-2/loader.html
still displays "ip=127.0.0.1" at the end of the "Script url" debug
line.  I already signed the JAR file using the steps at
http://forum.java.sun.com/thread.jsp?thread=174214&forum=63&message=1883852
and I even opened the tstcert.crt file (the one used to sign
TCPApplet.jar) and "installed" it into IE, so that now when I
double-click the local tstcert.crt file, it says it's trusted.  How do
I get IE to recognize the applet as signed, so it will allow it to
perform the requested operations?

Clarification of Answer by rhansenne-ga on 13 Aug 2003 03:57 PDT
Hi Bennett,

The previous version of the applet only placed a timeout on the socket
connection. I updated the code and jar on http://users.pandora.be/rami
with a new version which times the url connection with the server
script as well. The applet should now never block longer than the
specified timeout, even if a local firewall or server problem prevents
the applet from contacting the server script. In case the server
script cannot be accessed, the "error" url is returned.

(Note that the sample server script i put up is located on a slow
server and doesn't always respond within the specified timeout
settings)

The applet should now work fine under your Netscape set-up (which
presumably uses the Sun VM). Under IE the applet indeed needs to be
signed, as the MS VM doesn't allow unsigned applets to open a local
socket (or determine the local IP).

Thus far i've only tried a signed version under the Sun VM, which
worked fine on Netscape. I'll try it under IE and the MS VM later
today and I'll let you know the results.

rhansenne-ga.

Clarification of Answer by rhansenne-ga on 13 Aug 2003 03:57 PDT
Wrong link in previous message - should be:
http://users.pandora.be/rami/tcp

Clarification of Answer by rhansenne-ga on 13 Aug 2003 07:21 PDT
Hi again, 

Another small code update...

I tried the signed applet under IE and the MS VM and it works
correctly if you provide a signed cab file. You can find signed
versions of the jar and cab archives under
http://users.pandora.be/rami .

If you want to sign the code yourself, these are the commands i used
to compile the code, create and sign the cab file:

jvc /d . TCPApplet.java
dubuild TCPApplet.cab . /D "TCPApplet" /I *.class /V 1,1,23,0
setreg 1 true
makecert -sk MyKeyName -n "CN=Rami Hansenne" MyTestCert.cer
cert2spc MyTestCert.cer MyTestCert.spc
signcode -j javasign.dll -jp LOW -spc MyTestCert.spc -k MyKeyName
TCPApplet.cab

A full explanation can be found here:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q193877

Since you've installed Visual J++, these commands should be available
to you. If they aren't, you can download the MS Java SDK here:
ftp://ftp.crystalpoint.com/updates/ovweb/sdkjava40.exe

You can now combine the jar (netscape) and cab (ie) into a single
applet call, such that the applet works for both browsers and both
virtual machines. Simply modify your applet tag into:

<APPLET code="TCPApplet.class" WIDTH=600 HEIGHT=200>
  <param name="archive" value="TCPApplet.jar">
  <param name="cabbase" value="TCPApplet.cab">
  ...
</APPLET>

Sample page:
http://www.mycgiserver.com/~rhansenne/tcp/
(since the script server is quite slow, sometimes "error" might be
thrown if the timeout passes before the script responds).

The signed applet now correctly determines the client ip (ideally the
script will check both this ip and the ip detected in the request for
a socket connection, since the ip detected by the applet might be a
local network ip and the ip detected by the script might be a
proxy-ip).

Sincerely,

rhansenne-ga.

Clarification of Answer by rhansenne-ga on 13 Aug 2003 07:22 PDT
Again, the first link should be: 
http://users.pandora.be/rami/tcp
bennetthaselton-ga rated this answer:5 out of 5 stars and gave an additional tip of: $100.00
Very thorough, very helpful in fixing problems, and even went beyond
what I asked (developed a server-side script to help with the applet).

Comments  
Subject: Re: need Java applet to test whether user machine can receive incoming connections
From: rhansenne-ga on 19 Aug 2003 02:25 PDT
 
Thanks for the generous tip!

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy