[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[iaik-ssl] Library locked in multithread environment if one ip connection is blocked



Hi

I did the following:

1.) I modified the demo programm HttpsDemo.java that it can used as library class, passing
the target url as constructor and sending back the html result as vector.
2.) I wrote a main modul, that creates 4 threads who request an url in an infinite loop.
Thread 1 and 2 will call a valid https server with a valid url. Thread 3 an 4 will try an
other https server behind a firewall - but the firewall is configured not to allow https
connections (dropping all ip packets on port 443).

What happens:

- all is ok as long as only thread 1 and 2 are running..
- as soon 3 and thread 4 are additionally running: all threads 1..4 are blocked !!!

That thread 3 and 4 are blocked is normal. But thread 1 and 2 should not be blocked.
Thread
3 and 4 will not receive a reject from the server because the firewall drops the ip
packet.
But anyway. Thread 1 and 2 should work - but it dosn't.

This means: if I open at the same time more than one HttpsURLConnection and only one of
connection is blocked, this has an impact to all future HttpsURLConnections and they (all)
are also blocked,
also if one or more server are ready to response.

First it thougt that this is a jdk 1.1 problem, because there are several bugs on socket
level.
I tested it on java 1.1 with NT, Solaris and FreeBsd. Later I setup a Linux system with
java
1.2.2. - the result was always the same. I spent one week for testing. I think, this is a
synchronisation
problem inside the iSaSiLk library and the HttpsURLConnection(s) are not indepentment of
each other.

I tried the same thing with the normal URLConnection (port 80). In this case is all ok,
thread 1 & 2 always running - thread 3 and 4 blocked.

Source of the modified HttpsDemo.java
----------------------------------------

import java.io.*;
import java.net.*;
import java.util.*;

import iaik.security.ssl.*;
import iaik.protocol.https.*;
// import demo.DemoUtil;

import java.security.*;
import iaik.security.random.MetaSeedGenerator;
import iaik.security.random.SeedGenerator;


public class SC_SSL_geturl implements Runnable
// ======================================================================================
{
 private final static String PROVIDER_CLASS_NAME = "iaik.security.provider.IAIK";

 public static final int SSL_NOSTATUS = -1;
 public static final int SSL_SANITY_TIMEOUT = 2;
 public static final int SSL_MALFORMED_URL = 3;
 public static final int SSL_NO_URL_CONNECTION = 4;
 public static final int SSL_PROTOCOL_FAILURE = 5;
 public static final int SSL_UNKNOWN_HOST = 6;
 public static final int SSL_NO_ROUTE_TO_HOST = 7;
 public static final int SSL_NO_SERVER_RESPONSE = 8;
 public static final int SSL_HTTP_PROTOCOL_FAILURE = 9;


 // internal data
 private int  timeout     = 30;   // seconds

 private String urlString    = "";
 private String browser     = "";
 private Vector htmlResult    = null;
 private String htmlResultString  = "";   // used only for MD5
 private long socketProtocolOpenTime = -1;
 private long dataExchangeTime  = -1;
 private int  dataExchangeSize  = -1;

 private boolean acceptAll = false;
 private boolean AuthUserFlag = false;
 private String AuthUsername = "";
 private String AuthPassword = "";

 // result
 private volatile int  SSL_Status = SSL_NOSTATUS;   // result detail
 private volatile int  SSL_ThreadStatus = SSL_NOSTATUS; // result detail
 private volatile Exception failureException = null;

 // ssl connection
 private volatile HttpsURLConnection connection = null;
 private volatile InputStream in = null;
 private volatile BufferedReader reader = null;

 // ssl initialisation
 private static volatile boolean firstTime = true;
 private static volatile int  currentThreadCount = 0;


 public SC_SSL_geturl(String url, String browserEmulation)
 // --- constructor ------------------------------------------------------------------
 {
  urlString = "https://";
  urlString = urlString + url;

  browser = browserEmulation;

  synchronized(this)
  {
   if (firstTime)
   {
    // demo.DemoUtil.initDemos();
    initRandom();
    addIaikProvider();

    System.getProperties().put("java.protocol.handler.pkgs", "iaik.protocol");
    firstTime = false;
   }
  }
 }


 public SC_SSL_geturl(String url, String browserEmulation, boolean all)
 // --- constructor ------------------------------------------------------------------
 {
  this(url, browserEmulation);
  acceptAll = all;
 }


 public int execute()
 // ----------------------------------------------------------------------------------
 {
  Thread t = new Thread(this);
  t.start();

  // wait timeout sec to die
  try { t.join(timeout * 1000); } catch (InterruptedException ie) {}

  // tread not dead ?
  if (t.isAlive())
  {
   // t.stop();
   SSL_Status = SSL_SANITY_TIMEOUT;
   logMsg("*** frozen IP connection aborted after " + timeout + " seconds ***");
  }
  else
   SSL_Status = SSL_ThreadStatus;

  /*
  if (reader != null)
   try { reader.close(); } catch (Exception ex) { System.out.println(">>> reader.close()
failed"); }
  if (in != null)
   try { in.close(); } catch (Exception ex) { System.out.println(">>> in.close() failed");
}
  if (connection != null)
   try { connection.disconnect(); } catch (Exception ex) { System.out.println(">>>
connection.disconnect() failed"); }
  */

  return SSL_Status;
 }


 public void run()
 // ----------------------------------------------------------------------------------
 {
  URL url = null;
  currentThreadCount++;
  long threadStartTime = System.currentTimeMillis();
  logMsg("started - [" + urlString + "] - Thread Count=" + currentThreadCount + " ...");

  // make new result vector
     htmlResult = new Vector();
  htmlResultString = "";

  // create url
  try
  {
   url = new URL(urlString);
  }
  catch (MalformedURLException mex)
  {
   System.out.println("" + mex);
   failureException = mex;

   SSL_ThreadStatus = SSL_MALFORMED_URL;
   htmlResult = null;
   currentThreadCount--;
   logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
   return;
  }

  // try to open connection
  try
  {
   connection = (HttpsURLConnection)url.openConnection();
  }
  catch (IOException ioe)
  {
   System.out.println("" + ioe);
   failureException = ioe;

   SSL_ThreadStatus = SSL_NO_URL_CONNECTION;
   htmlResult = null;
   currentThreadCount--;
   logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
   return;
  }

  // setup ssl context
  SSLContext context = (SSLContext) new SSLClientContext();
  context.setAllowedProtocolVersions(SSLContext.VERSION_SSL20, SSLContext.VERSION_SSL30);
  context.setCacheTerminatedSessions(false);
  if (acceptAll) {
    // SC_SSL_chainVerifier allows all certificates!!!
    context.setChainVerifier(new SC_SSL_chainVerifier());
  }
  connection.setSSLContext(context);

  // setup connection
  connection.setDefaultUseCaches(false);
  connection.setUseCaches(false);

  if (browser.length() > 0)
   connection.setRequestProperty("User-Agent", browser);
  else
   connection.setRequestProperty("User-Agent", " ");

  if (AuthUserFlag)
  {
   String access = SC_Base64Encoder.encode(AuthUsername + ":" + AuthPassword);
   connection.setRequestProperty("Authorization", "Basic " + access);
  }

  // connect now
  long startTime = System.currentTimeMillis();
  try
  {
   in = connection.getInputStream();
   reader = Utils.getASCIIReader(in);
  }
  catch (IOException iex)
  {
   System.out.println("" + iex);
   failureException = iex;

   SSL_ThreadStatus = SSL_PROTOCOL_FAILURE;
   htmlResult = null;
   htmlResultString = "";
   currentThreadCount--;
   logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
   return;
  }

  // get html response code
  try
  {
   SSL_ThreadStatus = connection.getResponseCode();

   if (SSL_ThreadStatus != 200)
   {
    htmlResult = null;
    htmlResultString = "";
    currentThreadCount--;
    logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
    return;
   }
  }
  catch (IOException xxx)  // java bug, file not found is an io execption !!!
  {
   System.out.println("" + xxx);
   failureException = xxx;

   java.io.FileNotFoundException f;
   java.net.UnknownHostException h;
   java.net.NoRouteToHostException n;

   f = new java.io.FileNotFoundException();
   h = new java.net.UnknownHostException();
   n = new java.net.NoRouteToHostException();

   htmlResult = null;
   htmlResultString = "";

   if (f.getClass() == xxx.getClass())
   {
    SSL_ThreadStatus = 404; // file not found
    currentThreadCount--;
    logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
    return;
   }

   if (h.getClass() == xxx.getClass())
   {
    SSL_ThreadStatus = SSL_UNKNOWN_HOST;
    currentThreadCount--;
    logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
    return;
   }

   if (n.getClass() == xxx.getClass())
   {
    SSL_ThreadStatus = SSL_NO_ROUTE_TO_HOST;
    currentThreadCount--;
    logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
    return;
   }

   SSL_ThreadStatus = SSL_HTTP_PROTOCOL_FAILURE;
   currentThreadCount--;
   logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
   return;
  }

  try
  {
   SSLSocket sssl = connection.getSSLSocket();
   // logMsg("socket so timeout=" + sssl.getSoTimeout());
   sssl.setSoTimeout(timeout * 1000);
   // logMsg("socket so timeout=" + sssl.getSoTimeout());
  }
  catch (Exception sx) { logMsg("unable to access ssl socket / setSoTimeout(): " + sx); }


  socketProtocolOpenTime = System.currentTimeMillis() - startTime;
  startTime = System.currentTimeMillis();

  // read html output
  try
  {
   while (true)
   {
    String line = reader.readLine();

    if (line == null )
     break;

    htmlResultString = htmlResultString + line + "\n";
    if (dataExchangeSize == -1)
     dataExchangeSize = line.length();
    else
     dataExchangeSize = dataExchangeSize + line.length();

    if (line.trim().length() == 0)
     continue;

    htmlResult.addElement(new String(line));
   }
   dataExchangeTime = System.currentTimeMillis() - startTime;

  }
  catch (IOException iex)
  {
   System.out.println("" + iex);
   failureException = iex;

   SSL_ThreadStatus = SSL_NO_SERVER_RESPONSE;
   htmlResult = null;
   htmlResultString = "";
   currentThreadCount--;
   logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
   return;
  }

  try { reader.close(); } catch (Exception ex) { System.out.println(">>> reader.close()
failed"); }
  reader = null;
  try { in.close(); } catch (Exception ex) { System.out.println(">>> in.close() failed");
}
  in = null;
  try { connection.disconnect(); } catch (Exception ex) { System.out.println(">>>
connection.disconnect() failed"); }
  connection = null;
  currentThreadCount--;

  logMsg("... done (" +  getStatusText(SSL_ThreadStatus) + ") - Exec Time=" +
(System.currentTimeMillis() - threadStartTime) + " ms - Thread Count=" +
currentThreadCount);
 }


 public void setTimeout(int seconds)
 // ----------------------------------------------------------------------------------
 {
  timeout = seconds;
 }


 public void setAuth(String username, String password)
 // ----------------------------------------------------------------------------------
 {
  AuthUserFlag = true;
  AuthUsername = username;
  AuthPassword = password;
 }


 public Vector getHtml()
 // ----------------------------------------------------------------------------------
 {
  return htmlResult;
 }


 public int getStatus()
 // ----------------------------------------------------------------------------------
 {
  return SSL_Status;
 }


 public String getStatusText(int status)
 // ----------------------------------------------------------------------------------
 {
  switch (status)
  {
   case SSL_NOSTATUS:
    return ("*** no status / not initialized ***");
   case SSL_SANITY_TIMEOUT:
    return ("Communication Timeout expired after " + timeout + " Seconds");
   case SSL_MALFORMED_URL:
    return ("Malformed URL");
   case SSL_NO_URL_CONNECTION:
    return ("Unable to open URL Connection");
   case SSL_PROTOCOL_FAILURE:
    return ("SSL Protocol Failure");
   case SSL_UNKNOWN_HOST:
    return ("Unknown Host");
   case SSL_NO_ROUTE_TO_HOST:
    return ("No Route to Host");
   case SSL_NO_SERVER_RESPONSE:
    return ("No Response from Server");
   case SSL_HTTP_PROTOCOL_FAILURE:
    return ("HTTP Protocol Failure");
   default:
    if (status >= 100)
     return ("HTTP Server Response Code " + status);
    else
     return ("*** unknown status " + status + " / internal error");
  }
 }


 public long getTotalResponseTime()
 // ----------------------------------------------------------------------------------
 {
  if (dataExchangeTime >= 0)
   return socketProtocolOpenTime + dataExchangeTime;
  else
   return -1;
 }


 public long getSocketProtocolOpenTime()
 // ----------------------------------------------------------------------------------
 {
  return socketProtocolOpenTime;
 }


 public long getDataExchangeTime()
 // ----------------------------------------------------------------------------------
 {
  return dataExchangeTime;
 }


 public int getDataExchangeSize()
 // ----------------------------------------------------------------------------------
 {
  return dataExchangeSize;
 }


 public Exception getFailureException()
 // ----------------------------------------------------------------------------------
 {
  return failureException;
 }


 private static synchronized void logMsg(String msg)
 // ----------------------------------------------------------------------------------
 {
  String prefix = "SC_SSL_geturl " + Thread.currentThread().getName();

  try
  {
   System.out.println(SCI.dateToTerminalText(SC_Time.currentDate(),"ECT" ,SCI.ENGLISH ) +
" "  + prefix + ":   " + msg);
  }
  catch (Exception e)
  {
   System.out.println("??-??-???? ??:??:??" + "   " + msg);
  }
 }


 // ********************** ssl utilities (from iSaSiLk3.0 demo) **********************

 private static void addIaikProvider()
 // ----------------------------------------------------------------------------------
 {
     addProvider(PROVIDER_CLASS_NAME);
 }


 private static void addProvider(String name)
 // ----------------------------------------------------------------------------------
 {
  try
  {
   Class clazz = Class.forName(name);
   Provider provider = (Provider)clazz.newInstance();
   Security.addProvider(provider);
  }
  catch (ClassNotFoundException ex)
  {
   System.out.println("Provider IAIK not found. Add iaik_jce.jar or iaik_jce_full.jar to
your classpath.");
   System.out.println("If you are going to use a different provider please take a look at
Readme.html!");
   System.exit(0);
  }
  catch (Exception ex)
  {
   System.out.println("Error adding provider:");
   ex.printStackTrace(System.err);
   System.exit(0);
  }
 }

 private static void initRandom()
 // ----------------------------------------------------------------------------------
 {
  // System.out.println("Quick-starting random number generator (not for use in production
systems!)...");
  Random random = new Random();
  byte[] seed = new byte[20];
  random.nextBytes(seed);
  MetaSeedGenerator.setSeed(seed);
  SeedGenerator.setDefault(MetaSeedGenerator.class);
 }



}








--
Mailinglist-archive at http://jcewww.iaik.at/mailarchive/iaik-ssl/sslthreads.html

To unsubscribe send an email to listserv@iaik.at with the folowing content: UNSUBSCRIBE iaik-ssl