+// 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.*;
public class Port extends Loader {
- private final InetAddress bindTo;
- private final int port;
- private final Thread listener;
+ final InetAddress bindTo;
+ final int port;
+
+ private static Hash cache = new Hash();
+ public static Port newPort(String path, InetAddress bindTo, int port) throws IOException {
+ String canonical = new File(path).getCanonicalPath();
+ Port p = (Port)cache.get(canonical);
+ if (p == null) cache.put(canonical, p = new Port(path, bindTo, port));
+ else Log.warn(Port.class, " sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
+ p.spawn(bindTo, port);
+ return p;
+ }
- public Port(String path, InetAddress bindTo, int port) {
+ void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
+ private Port(String path, InetAddress bindTo, int port) {
super(path);
this.bindTo = bindTo;
this.port = port;
- this.listener = new PortThread();
- listener.start();
}
public void changed(Watched w) {
super.changed(w);
}
- boolean dispatch(final Connection conn) throws Exception {
+
+ Class isListener(String name) throws ClassNotFoundException {
+ final ClassLoader cl = getClassLoader();
+ final Class c = cl.loadClass(name);
+ if (c == null) return null;
+ if (Listener.class.isAssignableFrom(c) && c != Listener.class) return c;
+ return null;
+ }
+
+ Class findListener() throws Exception {
getClassLoader();
String[] list = list();
for(int i=0; i<list.length; i++) {
ZipInputStream zis = new ZipInputStream(fis);
for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
String name = ze.getName();
- if (name.endsWith(".class"))
- if (dispatch(conn, name.substring(0, name.length() - ".class".length()).replace('/', '.')))
- return true;
+ if (name.endsWith(".class")) {
+ String classname = name.substring(0, name.length() - ".class".length()).replace('/', '.');
+ Class c = isListener(classname);
+ if (c != null) return c;
+ }
}
} finally { if (fis != null) fis.close(); }
}
- if (check(conn, new File(getAbsolutePath() + File.separatorChar + "BIN"))) return true;
- return false;
+ return findListener(new File(getAbsolutePath() + File.separatorChar + "BIN"));
}
- boolean check(Connection conn, File f) throws Exception {
- if (!f.exists()) return false;
+ Class findListener(File f) throws Exception {
+ if (!f.exists()) return null;
if (!f.isDirectory()) {
- if (!f.getAbsolutePath().endsWith(".class")) return false;
+ if (!f.getAbsolutePath().endsWith(".class")) return null;
String name = f.getAbsolutePath().substring(getAbsolutePath().length() + 5);
name = name.substring(0, name.length() - ".class".length()).replace(File.separatorChar, '.');
- if (dispatch(conn, name)) return true;
+ Class c = isListener(name);
+ if (c != null) return c;
} else {
String[] list = f.list();
- for(int i=0; i<list.length; i++)
- if (check(conn, new File(f.getAbsolutePath() + File.separatorChar + list[i])))
- return true;
+ for(int i=0; i<list.length; i++) {
+ String classname = f.getAbsolutePath() + File.separatorChar + list[i];
+ Class c = findListener(new File(classname));
+ if (c != null) return c;
+ }
}
- return false;
+ return null;
}
- boolean dispatch(final Connection conn, String name) throws Exception {
- try {
- final ClassLoader cl = getClassLoader();
- final Class c = cl.loadClass(name);
- if (c == null) return false;
- if (!(Listener.class.isAssignableFrom(c) && c != Listener.class)) return false;
- Log.info(this, "dispatching connection on port " + port + " to " + c.getName());
- new Thread(tg, new Runnable() { public void run() {
+ void dispatch(final Connection conn) throws Exception {
+ new Thread(tg, new Runnable() { public void run() {
+ String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
+ String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
+ try {
+ Class c = findListener();
+ if (c == null) throw new RuntimeException("couldn't find listener");
+ Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
Log.clearnotes();
+ final ClassLoader cl = getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
- try {
- Listener l = (Listener)c.newInstance();
- l.accept(conn);
- } catch (Exception e) {
- Log.error(c, "Listener threw exception");
- Log.error(c, e);
- } finally {
- conn.close();
- }
- } }).start();
- return true;
- } catch (Exception e) { Log.error(this, e); }
- return false;
+ Listener l = (Listener)c.newInstance();
+ l.accept(conn);
+ } catch (org.ibex.io.Stream.EOF eof) {
+ Log.warn(this, "end of stream reached handling connection from " +
+ conn.getRemoteHostname() + ":" + conn.getRemotePort());
+ } catch (Exception e) {
+ Log.error(this, e);
+ conn.close();
+ } finally {
+ conn.close();
+ }
+ } }).start();
}
private class PortThread extends Thread {
+ InetAddress bindTo;
+ int port;
+ 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);
ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
for(Socket s = ss.accept(); ; s = ss.accept()) try {
- if (!dispatch(new Connection(s, "megacz.com"))) {
- Log.warn(this, "no handler for connection on port " + port);
- s.close();
- }
+ dispatch(new Connection(s, "megacz.com"));
} catch (Exception e) { Log.warn(Port.class, e); }
} catch (Exception e) { Log.error(Port.class, e);
} catch (Throwable t) {