123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- // Thomas Nagy, 2011
- // TODO security
- // TODO handle all exceptions properly
- import java.util.HashMap;
- import java.util.Map;
- import java.util.List;
- import java.util.Date;
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.Collections;
- import java.lang.Math;
- import java.lang.StringBuilder;
- import java.io.*;
- import java.net.*;
- import java.security.*;
- public class Netcache implements Runnable, Comparator<Object[]> {
- private static int PORT_UPLOAD = 11001;
- private static int PORT_DOWNLOAD = 12001;
- private static String CACHEDIR = "/tmp/wafcache/";
- private static long MAX = 10l * 1024l * 1024l * 1024l;
- private static double CLEANRATIO = 0.8;
- private static int BUF = 16 * 8192;
- private final static HashMap<String, Object[]> flist = new HashMap<String, Object[]>();
- private Socket sock = null;
- private int port = 0;
- public Netcache(Socket sock, int port) {
- this.sock = sock;
- this.port = port;
- }
- public void run () {
- try {
- if (sock != null)
- {
- while (true) {
- InputStream in = sock.getInputStream();
- OutputStream out = sock.getOutputStream();
- byte b[] = new byte[128];
- int off = 0;
- while (off < b.length) {
- off += in.read(b, off, b.length - off);
- }
- //System.out.println(new String(b));
- String[] args = new String(b).split(",");
- if (args[0].equals("LST")) {
- lst(args, in, out);
- }
- else if (args[0].equals("PUT") && port == PORT_UPLOAD) {
- put(args, in, out);
- }
- else if (args[0].equals("GET") && port == PORT_DOWNLOAD) {
- get(args, in, out);
- }
- else if (args[0].equals("CLEAN") && port == PORT_UPLOAD) {
- clean(args, in, out);
- }
- else if (args[0].equals("BYE")) {
- sock.close();
- break;
- }
- else {
- System.out.println("Invalid command " + new String(b) + " on port " + this.port);
- sock.close();
- break;
- }
- }
- } else {
- // magic trick to avoid creating a new inner class
- ServerSocket server = new ServerSocket(port);
- server.setReuseAddress(true);
- while(true) {
- Netcache tmp = new Netcache(server.accept(), port);
- Thread t = new Thread(tmp);
- t.start();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void lst(String[] args, InputStream in, OutputStream out) throws IOException {
- StringBuilder b = new StringBuilder();
- int k = 0;
- synchronized(flist) {
- for (String name : flist.keySet()) {
- b.append(name);
- if (k <= flist.size()) {
- k++;
- b.append("\n");
- }
- }
- }
- byte[] ret = b.toString().getBytes();
- String header = String.format("%-128s", String.format("%d,", ret.length));
- out.write(header.getBytes());
- out.write(ret);
- }
- public void put(String[] args, InputStream in, OutputStream out) throws IOException {
- File cachedir = new File(CACHEDIR);
- File temp = File.createTempFile("foo", ".suffix", cachedir);
- long size = new Long(args[3].trim());
- //System.out.println("" + args[1] + " " + args[2] + " " + args[3] + " " + args.length);
- byte[] buf = new byte[BUF];
- long cnt = 0;
- OutputStream w = new FileOutputStream(temp);
- try {
- while (cnt < size) {
- int c = in.read(buf, 0, (int) Math.min(BUF, size-cnt));
- if (c == 0) {
- throw new RuntimeException("Connection closed too early");
- }
- w.write(buf, 0, c);
- cnt += c;
- }
- } finally {
- w.close();
- }
- /*if (cnt != size) {
- System.out.println("error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
- }*/
- File parent = new File(new File(new File(CACHEDIR), args[1].substring(0, 2)), args[1]);
- File dest = new File(parent, args[2]);
- try {
- dest.getParentFile().mkdirs();
- } catch (Exception e) {
- }
- if (!temp.renameTo(dest)) {
- throw new RuntimeException("Could not rename the file");
- }
- long total = 0;
- for (File f : parent.listFiles()) {
- total += f.length();
- }
- synchronized(flist) {
- if (flist.containsKey(parent.getName())) {
- flist.get(parent.getName())[0] = parent.lastModified();
- }
- else
- {
- flist.put(parent.getName(), new Object[] {parent.lastModified(), total, parent.getName()});
- }
- }
- }
- public void get(String[] args, InputStream in, OutputStream out) throws IOException {
- File f = new File(new File(new File(new File(CACHEDIR), args[1].substring(0, 2)), args[1]), args[2].trim());
- long fsize = -1;
- try {
- fsize = f.length();
- } catch (Exception e) {
- // return -1 to the client
- }
- String ret = String.format("%-128s", String.format("%d,", fsize));
- out.write(ret.getBytes());
- byte[] buf = new byte[BUF];
- long cnt = 0;
- InputStream s = new FileInputStream(f);
- try {
- while (cnt < fsize) {
- long c = s.read(buf);
- cnt += c;
- out.write(buf, 0, (int) c);
- }
- } finally {
- s.close();
- }
- File parent = f.getParentFile();
- Date d = new Date();
- parent.setLastModified(d.getTime());
- synchronized(flist) {
- flist.get(parent.getName())[0] = parent.lastModified();
- }
- }
- public void clean(String[] args, InputStream in, OutputStream out) throws IOException {
- synchronized(flist) {
- long total = 0;
- for (Map.Entry<String, Object[]> entry : flist.entrySet()) {
- total += (Long) entry.getValue()[1];
- }
- List<Object[]> k = new ArrayList<Object[]>(flist.values());
- Collections.sort(k, this);
- int cur = 0;
- while (total > MAX * CLEANRATIO) {
- Object[] kk = k.get(cur);
- String name = (String) kk[2];
- File f = new File(new File(new File(CACHEDIR), name.substring(0, 2)), name);
- //System.out.println("removing " + cur + " " + kk[0] + " " + kk[1] + " " + f.getAbsolutePath());
- rm(f);
- total -= (Long) kk[1];
- flist.remove(name);
- cur++;
- }
- }
- }
- public static void init_flist() {
- synchronized(flist) {
- flist.clear();
- File dir = new File(CACHEDIR);
- try {
- dir.mkdirs();
- } catch (Exception e) {
- }
- for (File d : dir.listFiles()) {
- if (!d.isDirectory()) continue;
- for (File sd : d.listFiles()) {
- if (!sd.isDirectory()) continue;
- long total = 0;
- for (File f : sd.listFiles()) {
- total += f.length();
- }
- //System.out.println(sd.getName());
- flist.put(sd.getName(), new Object[] {sd.lastModified(), total, sd.getName()});
- }
- }
- }
- }
- public int compare(Object[] a, Object[] b) {
- return ((Long) a[0]).compareTo((Long) b[0]);
- }
- public static void rm(File dir) {
- if (dir.isDirectory()) {
- for (File f: dir.listFiles())
- {
- rm(f);
- }
- }
- dir.delete();
- }
- public static void main(String[] args) {
- init_flist();
- System.out.println("ready (" + flist.keySet().size() + " dirs)");
- // different ports for upload and download, another port could be added for the clean command
- Thread upload = null;
- if (PORT_UPLOAD != PORT_DOWNLOAD) {
- Netcache tmp = new Netcache(null, PORT_UPLOAD);
- upload = new Thread(tmp);
- upload.start();
- }
- Netcache tmp = new Netcache(null, PORT_DOWNLOAD);
- tmp.run();
- }
- }
|