1 package org.ibex.jinetd;
2 import org.ibex.util.*;
7 import java.util.zip.*;
9 public class Port extends Loader {
11 final InetAddress bindTo;
14 private static Hash cache = new Hash();
15 public static Port newPort(String path, InetAddress bindTo, int port) throws IOException {
16 String canonical = new File(path).getCanonicalPath();
17 Port p = (Port)cache.get(canonical);
18 if (p == null) cache.put(canonical, p = new Port(path, bindTo, port));
19 else Log.warn(Port.class, " sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
20 p.spawn(bindTo, port);
24 void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
25 private Port(String path, InetAddress bindTo, int port) {
31 public void changed(Watched w) {
32 //Log.warn(this, "Port: noticed change in " + w);
37 Class isListener(String name) throws ClassNotFoundException {
38 final ClassLoader cl = getClassLoader();
39 final Class c = cl.loadClass(name);
40 if (c == null) return null;
41 if (Listener.class.isAssignableFrom(c) && c != Listener.class) return c;
45 Class findListener() throws Exception {
47 String[] list = list();
48 for(int i=0; i<list.length; i++) {
49 if (!list[i].endsWith(".jar")) continue;
50 //Log.warn(this, "checking " + (this.path + File.separatorChar + list[i]));
51 File f = new File(this.path + File.separatorChar + list[i]);
52 FileInputStream fis = null;
54 fis = new FileInputStream(f);
55 ZipInputStream zis = new ZipInputStream(fis);
56 for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
57 String name = ze.getName();
58 if (name.endsWith(".class")) {
59 String classname = name.substring(0, name.length() - ".class".length()).replace('/', '.');
60 Class c = isListener(classname);
61 if (c != null) return c;
64 } finally { if (fis != null) fis.close(); }
66 return findListener(new File(getAbsolutePath() + File.separatorChar + "BIN"));
69 Class findListener(File f) throws Exception {
70 if (!f.exists()) return null;
71 if (!f.isDirectory()) {
72 if (!f.getAbsolutePath().endsWith(".class")) return null;
73 String name = f.getAbsolutePath().substring(getAbsolutePath().length() + 5);
74 name = name.substring(0, name.length() - ".class".length()).replace(File.separatorChar, '.');
75 Class c = isListener(name);
76 if (c != null) return c;
78 String[] list = f.list();
79 for(int i=0; i<list.length; i++) {
80 String classname = f.getAbsolutePath() + File.separatorChar + list[i];
81 Class c = findListener(new File(classname));
82 if (c != null) return c;
88 void dispatch(final Connection conn) throws Exception {
89 new Thread(tg, new Runnable() { public void run() {
90 String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
91 String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
93 Class c = findListener();
94 if (c == null) throw new RuntimeException("couldn't find listener");
95 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
97 final ClassLoader cl = getClassLoader();
98 Thread.currentThread().setContextClassLoader(cl);
99 Listener l = (Listener)c.newInstance();
101 } catch (org.ibex.io.Stream.EOF eof) {
102 Log.warn(this, "end of stream reached handling connection from " +
103 conn.getRemoteHostname() + ":" + conn.getRemotePort());
104 } catch (Exception e) {
105 Log.error(this, "Listener threw exception");
114 private class PortThread extends Thread {
117 public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
120 Log.warn(this, "Now listening on address " + (bindTo == null ? "all interfaces" : bindTo.toString()) +
122 ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
123 for(Socket s = ss.accept(); ; s = ss.accept()) try {
124 dispatch(new Connection(s, "megacz.com"));
125 } catch (Exception e) { Log.warn(Port.class, e); }
126 } catch (Exception e) { Log.error(Port.class, e);
127 } catch (Throwable t) {
128 Log.error(this, "serious error, aborting VM");