diff --git a/briar-core/src/org/briarproject/reporting/DevReportServer.java b/briar-core/src/org/briarproject/reporting/DevReportServer.java new file mode 100644 index 0000000000000000000000000000000000000000..897756eeb317ddf073ddd06cf1bcc21abf82c518 --- /dev/null +++ b/briar-core/src/org/briarproject/reporting/DevReportServer.java @@ -0,0 +1,143 @@ +package org.briarproject.reporting; + +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.Semaphore; + +public class DevReportServer { + + private static final String FILE_PREFIX = "report-"; + private static final String FILE_SUFFIX = ".enc"; + private static final int MAX_REPORT_LENGTH = 1024 * 1024; + private static final int MIN_REQUEST_INTERVAL_MS = 60 * 1000; // 1 minute + private static final int MAX_TOKENS = 1000; + + private final InetSocketAddress listenAddress; + private final File reportDir; + + private DevReportServer(InetSocketAddress listenAddress, File reportDir) { + this.listenAddress = listenAddress; + this.reportDir = reportDir; + } + + private void listen() throws IOException { + ServerSocket ss = new ServerSocket(); + ss.bind(listenAddress); + TokenBucket bucket = new TokenBucket(); + bucket.start(); + try { + while (true) { + Socket s = ss.accept(); + System.out.println("Incoming connection"); + bucket.waitForToken(); + new ReportSaver(s).start(); + } + } catch (InterruptedException e) { + System.err.println("Interrupted while listening"); + } finally { + ss.close(); + } + } + + public static void main(String[] args) throws Exception { + if (args.length != 3) { + System.err.println("Usage:"); + System.err.println("DevReportServer <addr> <port> <report_dir>"); + System.exit(1); + } + int port = Integer.parseInt(args[1]); + InetSocketAddress listenAddress = new InetSocketAddress(args[0], port); + File reportDir = new File(args[2]); + System.out.println("Listening on " + listenAddress); + System.out.println("Saving reports to " + reportDir); + new DevReportServer(listenAddress, reportDir).listen(); + } + + private static class TokenBucket extends Thread { + + private final Semaphore semaphore = new Semaphore(MAX_TOKENS); + + private TokenBucket() { + setDaemon(true); + } + + private void waitForToken() throws InterruptedException { + // Wait for a token to become available and remove it + semaphore.acquire(); + } + + @Override + public void run() { + try { + while (true) { + // If the bucket isn't full, add a token + if (semaphore.availablePermits() < MAX_TOKENS) { + System.out.println("Adding token to bucket"); + semaphore.release(); + } + Thread.sleep(MIN_REQUEST_INTERVAL_MS); + } + } catch (InterruptedException e) { + System.err.println("Interrupted while sleeping"); + } + } + } + + private class ReportSaver extends Thread { + + private final Socket socket; + + private ReportSaver(Socket socket) { + this.socket = socket; + setDaemon(true); + } + + @Override + public void run() { + InputStream in = null; + File reportFile = null; + OutputStream out = null; + try { + in = socket.getInputStream(); + reportDir.mkdirs(); + reportFile = File.createTempFile(FILE_PREFIX, FILE_SUFFIX, + reportDir); + out = new FileOutputStream(reportFile); + System.out.println("Saving report to " + reportFile); + byte[] b = new byte[4096]; + int length = 0; + while (true) { + int read = in.read(b); + if (read == -1) break; + if (length + read > MAX_REPORT_LENGTH) + throw new IOException("Report is too long"); + out.write(b, 0, read); + length += read; + } + out.flush(); + System.out.println("Saved " + length + " bytes"); + } catch (IOException e) { + e.printStackTrace(); + if (reportFile != null) reportFile.delete(); + } finally { + tryToClose(in); + tryToClose(out); + } + } + + private void tryToClose(Closeable c) { + try { + if (c != null) c.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +}