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"
);
}
}
}