package org.bouncycastle.test.est; import java.io.File; import java.io.IOException; import java.net.Socket; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Structure; public class ESTServerUtils { private static final Lock lock = new ReentrantLock(); public static File makeRelativeToServerHome(String path) throws Exception { String ciscoHome = System.getenv("CISCO_EST_SERVER_HOME"); if (ciscoHome == null) { File f = new File("cisco"); if (f.exists()) { ciscoHome = f.getCanonicalPath(); } else { throw new RuntimeException("CISCO_EST_SERVER_HOME not defined."); } } return new File(ciscoHome, path).getCanonicalFile(); } public static ServerInstance startServer(final EstServerConfig config) { final CLibrary server = (CLibrary)Native.loadLibrary("estserverwrap", CLibrary.class); final CountDownLatch exited = new CountDownLatch(1); Thread t = new Thread(new Runnable() { public void run() { try { if (lock.tryLock(60, TimeUnit.SECONDS)) { try { server.start_server(config); exited.countDown(); } finally { lock.unlock(); } } else { throw new IllegalStateException("Unable to obtain server lock."); } } catch (Throwable t) { throw new RuntimeException(t.getMessage(), t); } } }); t.setPriority(Thread.MIN_PRIORITY); t.start(); waitForSocket(config.tcpPort); return new ServerInstance(server, config, exited); } public static void waitForSocket(int port) { long notAfter = System.currentTimeMillis() + 5000; for (; System.currentTimeMillis() < notAfter; ) { Socket sock = null; try { Thread.sleep(100); sock = new Socket("127.0.0.1", port); break; } catch (Exception ex) { // Ignored. } finally { if (sock != null) { try { sock.close(); } catch (IOException e) { // Ignore this as well. } } } } } /** * Holds the server and the configuration */ public static class ServerInstance { private final CLibrary server; private final EstServerConfig estServerConfig; private final CountDownLatch exited; public ServerInstance(CLibrary server, EstServerConfig estServerConfig, CountDownLatch exited) { this.server = server; this.estServerConfig = estServerConfig; this.exited = exited; } public CLibrary getServer() { return server; } public EstServerConfig getEstServerConfig() { return estServerConfig; } public void stopServer() throws Exception { server.stop_server(); exited.await(60, TimeUnit.SECONDS); } } public interface CLibrary extends Library { int start_server(EstServerConfig config); void stop_server(); } public static class EstServerConfig extends Structure { public String srp; public boolean enforceCsr; public String httpAuthToken; public int manualEnroll; public boolean useDigestAuth; public boolean useBasicAuth; public boolean writeCSRToFile; public boolean disableHTTPAuth; public boolean disableHTTPWhenTLSSucceeds; public boolean verbose; public boolean enableCRLChecks; public boolean enableCheckPOPtoTLSUID; public boolean useIPV6; public int sleepDelay; public int tcpPort; public String serverCertPemFile; public String serverKeyPemFile; public String realm; public boolean fipsMode; public String estCSRAttr; public String estCACERTSResp; public String estTRUSTEDCerts; public String openSSLConfigFile; protected List<String> getFieldOrder() { return Arrays.asList("srp", "enforceCsr", "httpAuthToken", "manualEnroll", "useDigestAuth", "useBasicAuth", "writeCSRToFile", "disableHTTPAuth", "disableHTTPWhenTLSSucceeds", "verbose", "enableCRLChecks", "enableCheckPOPtoTLSUID", "useIPV6", "sleepDelay", "tcpPort", "serverCertPemFile", "serverKeyPemFile", "realm", "fipsMode", "estCSRAttr", "estCACERTSResp", "estTRUSTEDCerts", "openSSLConfigFile" ); } } }