tons of changes
[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
14 // Feature: port-level redirects
15 public class Port extends Loader {
16
17     final ThreadPool tp;
18     final InetAddress bindTo;
19     final int port;
20
21     private static Hash cache = new Hash();
22     public static Port newPort(String path, InetAddress bindTo, int port, ThreadPool tp) throws IOException {
23         String canonical = new File(path).getCanonicalPath();
24         Port p = (Port)cache.get(canonical);
25         if (p == null) cache.put(canonical, p = new Port(path, bindTo, port, tp));
26         else Log.warn(Port.class, "   sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
27         p.spawn(bindTo, port);
28         return p;
29     }
30
31     void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
32     private Port(String path, InetAddress bindTo, int port, ThreadPool tp) { 
33         super(path); this.bindTo = bindTo; this.port = port; this.tp = tp; }
34
35     public void changed(Watched w) {
36         //Log.warn(this, "Port: noticed change in " + w);
37         super.changed(w);
38     }
39
40     void dispatch(final Connection conn) throws Exception {
41         tp.appendTask(new Runnable() { public void run() {
42             String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
43             String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
44             try {
45                 final ClassLoader cl = getClassLoader();
46                 Class c = cl.loadClass("org.ibex.mail.Main");
47                 if (c == null) throw new RuntimeException("couldn't find listener");
48                 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
49                 Log.clearnotes();
50                 Thread.currentThread().setContextClassLoader(cl);
51                 Listener l = (Listener)c.newInstance();
52                 l.accept(conn);
53             } catch (org.ibex.io.Stream.EOF eof) {
54                 Log.warn(this, "end of stream reached handling connection from " +
55                          conn.getRemoteHostname() + ":" + conn.getRemotePort());
56             } catch (Exception e) {
57                 Log.error(this, e);
58                 conn.close();
59             } finally {
60                 conn.close();
61             }
62         } });
63     }
64
65     private class PortThread extends Thread {
66         InetAddress bindTo;
67         int port;
68         public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
69         public void run() {
70             try {
71                 Log.warn(this, "Now listening on address " + (bindTo == null ? "all interfaces" : bindTo.toString()) +
72                          ", port " + port);
73                 ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
74                 for(Socket s = ss.accept(); ; s = ss.accept()) try {
75                     dispatch(new Connection(s, "megacz.com"));
76                 } catch (Exception e) { Log.warn(Port.class, e); }
77             } catch (Exception e) { Log.error(Port.class, e);
78             } catch (Throwable t) {
79                 Log.error(this, "serious error, aborting VM");
80                 Log.error(this, t);
81                 Root.reboot();
82             }
83         }
84     }
85 }