import java.util.*;
import java.lang.reflect.*;
-public class Host extends Loader {
+public class Host extends File {
final String hostname;
public Host(String path, String hostname) { super(path); this.hostname = hostname; }
- public void changed(Watched w) {
- super.changed(w);
+ public void changed(File f) { }
/*
+ super.changed(w);
Log.debug(this, "changed(" + w + ")");
try {
ClassLoader cl = getClassLoader();
Log.warn(this, e);
}
*/
- }
}
*/
public interface Listener {
- public void accept(Connection c);
+ /** returns false if the connection was not handled */
+ public boolean accept(Connection c);
}
+++ /dev/null
-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
-// Licensed under the Apache Public Source License 2.0 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.jinetd;
-import org.ibex.io.*;
-import org.ibex.util.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.net.*;
-import java.util.zip.*;
-
-/** represents a file or directory which is scanned for updates */
-public class Loader extends Watcher {
-
- public /*synchronized*/ void scan() throws IOException { super.scan(); }
-
- private final TreeClassLoader classloader;
- public synchronized ClassLoader getClassLoader() { return classloader; }
- public Loader(String path) { this(path, Loader.class.getClassLoader()); }
- public Loader(String path, ClassLoader parent) { super(path); classloader = new TreeClassLoader(this, parent); }
- public void changed(Watched w) { /*FIXME*/ }
-
- private void fill(Vec vec, File dir) {
- if (!dir.exists()) return;
- if (!dir.isDirectory()) {
- if (!dir.getPath().endsWith(".java")) return;
- vec.addElement(dir.getAbsolutePath());
- } else {
- String[] list = dir.list();
- for(int i=0; i<list.length; i++)
- fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
- }
- }
-
- protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
- private void nuke() {
- if (tg.activeCount() == 0) return;
- Log.info(this, "killing all threads for: " + path);
- Log.info(this, " thread count before interrupt: " + tg.activeCount());
- tg.interrupt();
- try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
- Log.info(this, " thread count before kill: " + tg.activeCount());
- Thread[] all = new Thread[tg.activeCount()];
- tg.enumerate(all, true);
- for(int i=0; i<all.length; i++) Stream.kill(all[i]);
- try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
- Log.info(this, " thread count after kill: " + tg.activeCount());
- if (tg.activeCount() > 0) {
- Log.warn(this, " annoying threads:");
- Thread[] annoying = new Thread[tg.activeCount()];
- tg.enumerate(annoying, true);
- for(int i=0; i<annoying.length; i++) {
- Log.warn(this, " " + annoying[i]);
- StackTraceElement[] stack = annoying[i].getStackTrace();
- for(int j=0; j<stack.length; j++) Log.warn(this, " " + stack[j]);
- Log.warn(this, " ");
- }
- }
- }
-
-
-}
public class Main {
+ // Bootup //////////////////////////////////////////////////////////////////////////////
+
public static String ROOT;
public static String LOGFILE;
public static PrintStream LOGSTREAM;
+ public static String defaultDomain;
- private static void configureRoot() throws Exception {
- ROOT = System.getProperty("jinetd.root", null);
- if (ROOT == null) {
- ROOT = autoDetectRoot();
- System.setProperty("jinetd.root", ROOT);
+ static {
+ try {
+ System.err.println("jinetd starting...");
+ ROOT = System.getProperty("jinetd.root", null);
+ if (ROOT == null) System.setProperty("jinetd.root", ROOT = autoDetectRoot());
+ System.err.println(" jinetd.root = " + ROOT);
+ defaultDomain = System.getProperty("jinetd.hostname", null);
+ if (defaultDomain==null) try {
+ java.net.InetAddress localMachine = java.net.InetAddress.getLocalHost();
+ defaultDomain = localMachine.getHostName();
+ } catch(java.net.UnknownHostException uhe) { defaultDomain = "localhost"; }
+ System.err.println(" jinetd.hostname = " + defaultDomain);
+ LOGFILE = System.getProperty("jinetd.logfile", ROOT + File.separatorChar+"log.txt");
+ System.err.println(" jinetd.logfile = " + LOGFILE);
+ System.err.println(" redirecting stdout/stderr to logfile." + LOGFILE);
+ LOGSTREAM = new PrintStream(new FileOutputStream(LOGFILE, true));
+ System.setErr(LOGSTREAM);
+ System.setOut(LOGSTREAM);
+ } catch (Throwable e) {
+ throw new Error(e);
}
}
- private static void configureLogging() throws Exception {
- LOGFILE = System.getProperty("jinetd.logfile", ROOT + File.separatorChar+"log.txt");
- LOGSTREAM = new PrintStream(new FileOutputStream(LOGFILE, true));
- System.setErr(LOGSTREAM);
- System.setOut(LOGSTREAM);
- }
-
private static String autoDetectRoot() throws Exception {
if (!(Main.class.getClassLoader() instanceof URLClassLoader))
throw new Error("unable to detect jinetd.root because my ClassLoader is not an instanceof URLClassLoader");
" was not in any of the ClassLoader URLs");
}
- static {
- try {
- configureRoot();
- configureLogging();
- } catch (Throwable e) {
- throw new Error(e);
- }
+ public static void reboot() {
+ Log.flush();
+ System.exit(0);
}
public static void main(String[] s) throws Exception {
- Log.color = true;
- Root root = new Root(Root.root);
+ Root root = new Root(ROOT);
while(true) try {
if (root != null) { root.scan(); return; }
Thread.sleep(100);
import java.net.*;
import java.util.zip.*;
-
// Feature: port-level redirects
-public class Port extends Loader {
+public class Port extends TreeClassLoader {
final ThreadPool tp;
final InetAddress bindTo;
}
void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
+ private static final ClassLoader parentLoader = Port.class.getClassLoader();
private Port(String path, InetAddress bindTo, int port, ThreadPool tp) {
- super(path); this.bindTo = bindTo; this.port = port; this.tp = tp; }
-
- public void changed(Watched w) {
- //Log.warn(this, "Port: noticed change in " + w);
- super.changed(w);
- }
+ super(new File(path), parentLoader);
+ this.bindTo = bindTo; this.port = port; this.tp = tp; }
void dispatch(final Connection conn) throws Exception {
tp.appendTask(new Runnable() { public void run() {
String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
try {
- final ClassLoader cl = getClassLoader();
- Class c = cl.loadClass("org.ibex.mail.Main");
+ // FIXME FIXME
+ Class c = loadClass("org.ibex.mail.Main");
if (c == null) throw new RuntimeException("couldn't find listener");
Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
Log.clearnotes();
- Thread.currentThread().setContextClassLoader(cl);
+ Thread.currentThread().setContextClassLoader(Port.this);
Listener l = (Listener)c.newInstance();
l.accept(conn);
} catch (org.ibex.io.Stream.EOF eof) {
public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
public void run() {
try {
- Log.warn(this, "Now listening on address " + (bindTo == null ? "all interfaces" : bindTo.toString()) +
- ", port " + port);
+ Log.warn(this, "Now listening on address " + (bindTo==null?"all interfaces":bindTo.toString()) + ", port " + port);
ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
for(Socket s = ss.accept(); ; s = ss.accept()) try {
- dispatch(new Connection(s, "megacz.com"));
+ dispatch(new Connection(s, Main.defaultDomain));
} catch (Exception e) { Log.warn(Port.class, e); }
} catch (Exception e) { Log.error(Port.class, e);
} catch (Throwable t) {
Log.error(this, "serious error, aborting VM");
Log.error(this, t);
- Root.reboot();
+ Main.reboot();
}
}
}
import java.util.*;
import java.net.*;
-public class Root extends Loader {
+public class Root extends Watcher {
- public static String root = System.getProperty("jinetd.root", null);
-
- private final Host host;
- private final Watched port;
+ private final PortDir port;
private static final ThreadPool tp = new ThreadPool(10, 100);
- public Root(String path) {
+ public Root(String path) throws IOException {
super(path);
- host = new Host(path + File.separatorChar + "host", null);
+ if (!new File(path + File.separatorChar + "host").exists()) new File(path + File.separatorChar + "host").mkdirs();
+ if (!new File(path + File.separatorChar + "port").exists()) new File(path + File.separatorChar + "port").mkdirs();
port = new PortDir(path + File.separatorChar + "port");
+ watch(path + File.separatorChar + "host");
+ watch(path + File.separatorChar + "port");
+ scan();
}
- public Watched slash(String part) {
- if (part.equals("host")) return host;
- if (part.equals("port")) return port;
- if (part.equals("LIB")) return super.slash(part);
- if (part.endsWith(".jar")) return super.slash(part);
- return null;
- }
-
- public static void reboot() {
- Log.flush();
- System.exit(0);
- }
-
- public void changed(Watched w) {
- if (w.part.equals("host")) {
- Log.debug(this, "/host changed");
- } else if (w.part.equals("port")) {
- Log.debug(this, "/port changed");
- } else if (w.getAbsolutePath().endsWith(".jar")) {
+ public void changed(File w) throws IOException {
+ if (w.getName().equals("host")) Log.debug(this, "/host changed");
+ else if (w.getName().equals("port")) Log.debug(this, "/port changed");
+ /*
+ else if (w.getAbsolutePath().endsWith(".jar")) {
if (w.lastModifiedAtLastScan != -1) {
Log.error(this, "jinetd upgraded; bouncing the JVM....");
- reboot();
- }
- } else {
- Log.debug(this, "unknown directory " + w.part + " changed");
- }
+ Main.reboot();
+ } }
+ */
+ else Log.debug(this, "unknown directory " + w.getAbsolutePath() + " changed");
}
- private static class PortDir extends Watched {
- public PortDir(String path) { super(path); }
- public Watched slash(String part) {
+ private static class PortDir extends Watcher {
+ public PortDir(String path) throws IOException {
+ super(path);
+ String[] ports = new File(path).list();
+ for(int i=0; i<ports.length; i++) watch(path + File.separatorChar + ports[i]);
+ scan();
+ }
+
+ // FIXME: need to decommission old ports...
+ public void changed(File f) {
+ String part = f.getAbsolutePath();
+ part = f.getName();
+ // FIXME, use subdirs instead
String ipaddr = part.indexOf('_') == -1 ? null : part.substring(0, part.indexOf('_'));
String portnum = part.indexOf('_') == -1 ? part : part.substring(part.indexOf('_') + 1);
try {
- return Port.newPort(this.path + File.separatorChar + part,
- ipaddr == null ? null : InetAddress.getByName(ipaddr),
- portnum.equals("*") ? 0 : Integer.parseInt(portnum),
- tp);
+ Port.newPort(getAbsolutePath() + File.separatorChar + part,
+ ipaddr == null ? null : InetAddress.getByName(ipaddr),
+ portnum.equals("*") ? 0 : Integer.parseInt(portnum),
+ tp);
} catch (UnknownHostException e) { Log.warn(this, "can't resolve host for port directory: " + part);
} catch (NumberFormatException e) { Log.warn(this, "invalid port directory: " + part);
} catch (Exception e) { Log.warn(this, "error instantiating Port: " + part);
}
- return null;
}
}
this.lib = new File(root.getAbsolutePath() + File.separatorChar + "lib");
}
+ public Enumeration getLoadedClassNames() { return cache.keys(); }
+
// Classloading //////////////////////////////////////////////////////////////////////////////
public URL[] getURLs() {
return null;
}
+ // Experimental //////////////////////////////////////////////////////////////////////////////
+
+ protected ThreadGroup tg = null;
+ private void nuke() {
+ if (tg.activeCount() == 0) return;
+ Log.info(this, "killing all threads for: " + root.getAbsolutePath());
+ Log.info(this, " thread count before interrupt: " + tg.activeCount());
+ tg.interrupt();
+ try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
+ Log.info(this, " thread count before kill: " + tg.activeCount());
+ Thread[] all = new Thread[tg.activeCount()];
+ tg.enumerate(all, true);
+ for(int i=0; i<all.length; i++) Stream.kill(all[i]);
+ try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
+ Log.info(this, " thread count after kill: " + tg.activeCount());
+ if (tg.activeCount() > 0) {
+ Log.warn(this, " annoying threads:");
+ Thread[] annoying = new Thread[tg.activeCount()];
+ tg.enumerate(annoying, true);
+ for(int i=0; i<annoying.length; i++) {
+ Log.warn(this, " " + annoying[i]);
+ StackTraceElement[] stack = annoying[i].getStackTrace();
+ for(int j=0; j<stack.length; j++) Log.warn(this, " " + stack[j]);
+ Log.warn(this, " ");
+ }
+ }
+ }
+
}
+++ /dev/null
-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
-// Licensed under the Apache Public Source License 2.0 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.jinetd;
-import org.ibex.util.*;
-import java.io.*;
-import java.util.*;
-
-public class Watched extends File {
-
- // Instance //////////////////////////////////////////////////////////////////////////////
-
- private Hashtable cache = new Hashtable();
- long lastModifiedAtLastScan = -1;
- public final String path;
- public final String part;
-
- public Watcher watcher() { return ((Watched)all.get(getParent())).watcher(); }
- public Watched slash(String part) { return get(this.path + File.separatorChar + part); }
- public void scan() throws IOException {
- if (!exists()) { return; }
- if (lastModifiedAtLastScan != lastModified()) { watcher().changed(this); lastModifiedAtLastScan = lastModified(); }
- if (!isDirectory()) { return; }
- Vec removals = new Vec();
- for(Iterator i = cache.values().iterator(); i.hasNext();) {
- Watched w = ((Watched)i.next());
- if (w.exists()) w.scan();
- else { watcher().changed(w); removals.addElement(w.path.substring(this.path.length() + 1)); }
- }
- for(int i=0; i<removals.size(); i++) cache.remove(removals.elementAt(i));
- String[] kids = list();
- if (kids == null) return;
- for(int i=0; i<kids.length; i++) {
- Watched kid = (Watched)cache.get(kids[i]);
- if (kid == null) {
- kid = slash(kids[i]);
- if (kid == null) continue;
- cache.put(kids[i], kid);
- watcher().changed(kid);
- kid.scan();
- } else {
- kid.scan();
- }
- }
- }
-
-
- // Pooling //////////////////////////////////////////////////////////////////////////////
-
- private static WeakHashMap all = new WeakHashMap();
- protected Watched(String path) {
- super(path);
- this.path = path;
- this.part = path.substring(path.lastIndexOf(File.separatorChar) + 1);
- all.put(path, this);
- }
- private static Watched get(String path) {
- Watched ret = (Watched)all.get(path);
- if (ret == null) ret = new Watched(path);
- return ret;
- }
-}
import java.io.*;
import java.util.*;
-public abstract class Watcher extends Watched {
+public abstract class Watcher extends File {
+
protected Watcher(String path) { super(path); }
- public Watcher watcher() { return this; }
- public abstract void changed(Watched w);
- public synchronized void scan() throws IOException { super.scan(); }
+
+ public abstract void changed(File f) throws IOException;
+
+ private Vec watched = new Vec();
+
+ public void watch(File f) { watched.addElement(new Watched(f.getAbsolutePath())); }
+ public void watch(String s) { watch(getAbsolutePath() + File.separatorChar + s); }
+
+ public void scan() throws IOException {
+ for(int i=watched.size()-1; i>=0; i--)
+ ((Watched)(watched.elementAt(i))).scan();
+ }
+
+ private class Watched extends File {
+ long lastModifiedAtLastScan = -1;
+ public Watched(String s) { super(s); }
+ public void scan() throws IOException {
+ // FIXME
+ //if (!exists()) { Watcher.this.changed(this); Watcher.this.watched.remove(this); return; }
+ if (lastModifiedAtLastScan != lastModified()) { Watcher.this.changed(this); lastModifiedAtLastScan = lastModified(); }
+ }
+ }
}
+++ /dev/null
-// Copyright 2000-2005 the Contributors, as shown in the revision logs.
-// Licensed under the Apache Public Source License 2.0 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.jinetd;
-import org.ibex.util.*;
-import org.ibex.io.*;
-import java.net.*;
-import java.io.*;
-import java.util.*;
-
-public interface Worker {
- public void handleRequest(Connection c);
-}
-
-
-
-