licensing update to APSL 2.0
[org.ibex.jinetd.git] / src / org / ibex / jinetd / Port.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.jinetd;
6 import org.ibex.util.*;
7 import org.ibex.io.*;
8 import java.io.*;
9 import java.util.*;
10 import java.net.*;
11 import java.util.zip.*;
12
13 public class Port extends Loader {
14
15     final InetAddress bindTo;
16     final int port;
17
18     private static Hash cache = new Hash();
19     public static Port newPort(String path, InetAddress bindTo, int port) throws IOException {
20         String canonical = new File(path).getCanonicalPath();
21         Port p = (Port)cache.get(canonical);
22         if (p == null) cache.put(canonical, p = new Port(path, bindTo, port));
23         else Log.warn(Port.class, "   sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
24         p.spawn(bindTo, port);
25         return p;
26     }
27
28     void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
29     private Port(String path, InetAddress bindTo, int port) {
30         super(path);
31         this.bindTo = bindTo;
32         this.port = port;
33     }
34
35     public void changed(Watched w) {
36         //Log.warn(this, "Port: noticed change in " + w);
37         super.changed(w);
38     }
39
40
41     Class isListener(String name) throws ClassNotFoundException {
42         final ClassLoader cl = getClassLoader();
43         final Class c = cl.loadClass(name);
44         if (c == null) return null;
45         if (Listener.class.isAssignableFrom(c) && c != Listener.class) return c;
46         return null;
47     }
48
49     Class findListener() throws Exception {
50         getClassLoader();
51         String[] list = list();
52         for(int i=0; i<list.length; i++) {
53             if (!list[i].endsWith(".jar")) continue;
54             //Log.warn(this, "checking " + (this.path + File.separatorChar + list[i]));
55             File f = new File(this.path + File.separatorChar + list[i]);
56             FileInputStream fis = null;
57             try {
58                 fis = new FileInputStream(f);
59                 ZipInputStream zis = new ZipInputStream(fis);
60                 for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
61                     String name = ze.getName();
62                     if (name.endsWith(".class")) {
63                         String classname = name.substring(0, name.length() - ".class".length()).replace('/', '.');
64                         Class c = isListener(classname);
65                         if (c != null) return c;
66                     }
67                 }
68             } finally { if (fis != null) fis.close(); }
69         }
70         return findListener(new File(getAbsolutePath() + File.separatorChar + "BIN"));
71     }
72
73     Class findListener(File f) throws Exception {
74         if (!f.exists()) return null;
75         if (!f.isDirectory()) {
76             if (!f.getAbsolutePath().endsWith(".class")) return null;
77             String name = f.getAbsolutePath().substring(getAbsolutePath().length() + 5);
78             name = name.substring(0, name.length() - ".class".length()).replace(File.separatorChar, '.');
79             Class c = isListener(name);
80             if (c != null) return c;
81         } else {
82             String[] list = f.list();
83             for(int i=0; i<list.length; i++) {
84                 String classname = f.getAbsolutePath() + File.separatorChar + list[i];
85                 Class c = findListener(new File(classname));
86                 if (c != null) return c;
87             }
88         }
89         return null;
90     }
91
92     void dispatch(final Connection conn) throws Exception {
93         new Thread(tg, new Runnable() { public void run() {
94             String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
95             String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
96             try {
97                 Class c = findListener();
98                 if (c == null) throw new RuntimeException("couldn't find listener");
99                 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
100                 Log.clearnotes();
101                 final ClassLoader cl = getClassLoader();
102                 Thread.currentThread().setContextClassLoader(cl);
103                 Listener l = (Listener)c.newInstance();
104                 l.accept(conn);
105             } catch (org.ibex.io.Stream.EOF eof) {
106                 Log.warn(this, "end of stream reached handling connection from " +
107                          conn.getRemoteHostname() + ":" + conn.getRemotePort());
108             } catch (Exception e) {
109                 Log.error(this, e);
110                 conn.close();
111             } finally {
112                 conn.close();
113             }
114         } }).start();
115     }
116
117     private class PortThread extends Thread {
118         InetAddress bindTo;
119         int port;
120         public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
121         public void run() {
122             try {
123                 Log.warn(this, "Now listening on address " + (bindTo == null ? "all interfaces" : bindTo.toString()) +
124                          ", port " + port);
125                 ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
126                 for(Socket s = ss.accept(); ; s = ss.accept()) try {
127                     dispatch(new Connection(s, "megacz.com"));
128                 } catch (Exception e) { Log.warn(Port.class, e); }
129             } catch (Exception e) { Log.error(Port.class, e);
130             } catch (Throwable t) {
131                 Log.error(this, "serious error, aborting VM");
132                 Log.error(this, t);
133                 Root.reboot();
134             }
135         }
136     }
137 }