logging fixlet
[org.ibex.jinetd.git] / src / org / ibex / jinetd / Port.java
1 package org.ibex.jinetd;
2 import org.ibex.util.*;
3 import org.ibex.io.*;
4 import java.io.*;
5 import java.util.*;
6 import java.net.*;
7 import java.util.zip.*;
8
9 public class Port extends Loader {
10
11     final InetAddress bindTo;
12     final int port;
13
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);
21         return p;
22     }
23
24     void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
25     private Port(String path, InetAddress bindTo, int port) {
26         super(path);
27         this.bindTo = bindTo;
28         this.port = port;
29     }
30
31     public void changed(Watched w) {
32         //Log.warn(this, "Port: noticed change in " + w);
33         super.changed(w);
34     }
35
36
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;
42         return null;
43     }
44
45     Class findListener() throws Exception {
46         getClassLoader();
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;
53             try {
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;
62                     }
63                 }
64             } finally { if (fis != null) fis.close(); }
65         }
66         return findListener(new File(getAbsolutePath() + File.separatorChar + "BIN"));
67     }
68
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;
77         } else {
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;
83             }
84         }
85         return null;
86     }
87
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();
92             try {
93                 Class c = findListener();
94                 if (c == null) throw new RuntimeException("couldn't find listener");
95                 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
96                 Log.clearnotes();
97                 final ClassLoader cl = getClassLoader();
98                 Thread.currentThread().setContextClassLoader(cl);
99                 Listener l = (Listener)c.newInstance();
100                 l.accept(conn);
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, e);
106                 conn.close();
107             } finally {
108                 conn.close();
109             }
110         } }).start();
111     }
112
113     private class PortThread extends Thread {
114         InetAddress bindTo;
115         int port;
116         public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
117         public void run() {
118             try {
119                 Log.warn(this, "Now listening on address " + (bindTo == null ? "all interfaces" : bindTo.toString()) +
120                          ", port " + port);
121                 ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
122                 for(Socket s = ss.accept(); ; s = ss.accept()) try {
123                     dispatch(new Connection(s, "megacz.com"));
124                 } catch (Exception e) { Log.warn(Port.class, e); }
125             } catch (Exception e) { Log.error(Port.class, e);
126             } catch (Throwable t) {
127                 Log.error(this, "serious error, aborting VM");
128                 Log.error(this, t);
129                 Root.reboot();
130             }
131         }
132     }
133 }