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.
5 package org.ibex.jinetd;
6 import org.ibex.util.*;
11 import java.util.zip.*;
13 // Feature: port-level redirects
14 public class Port extends TreeClassLoader {
17 final InetAddress bindTo;
20 private static Hash cache = new Hash();
21 public static Port newPort(String path, InetAddress bindTo, int port, ThreadPool tp) throws IOException {
22 String canonical = new File(path).getCanonicalPath();
23 Port p = (Port)cache.get(canonical);
24 if (p == null) cache.put(canonical, p = new Port(path, bindTo, port, tp));
25 else Log.warn(Port.class, " sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
26 p.spawn(bindTo, port);
30 void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
31 private static final ClassLoader parentLoader = Port.class.getClassLoader();
32 private Port(String path, InetAddress bindTo, int port, ThreadPool tp) {
33 super(new File(path), parentLoader);
34 this.bindTo = bindTo; this.port = port; this.tp = tp; }
36 void dispatch(final Connection conn) throws Exception {
37 tp.appendTask(new Runnable() { public void run() {
38 String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
39 String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
42 Class c = loadClass("org.ibex.mail.Main");
43 if (c == null) throw new RuntimeException("couldn't find listener");
44 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
46 Thread.currentThread().setContextClassLoader(Port.this);
47 Listener l = (Listener)c.newInstance();
49 } catch (org.ibex.io.Stream.EOF eof) {
50 Log.warn(this, "end of stream reached handling connection from " +
51 conn.getRemoteHostname() + ":" + conn.getRemotePort());
52 } catch (Exception e) {
61 private class PortThread extends Thread {
64 public PortThread(InetAddress bindTo, int port) { this.bindTo = bindTo; this.port = port; }
67 Log.warn(this, "Now listening on address " + (bindTo==null?"all interfaces":bindTo.toString()) + ", port " + port);
68 ServerSocket ss = bindTo == null ? new ServerSocket(port) : new ServerSocket(port, 0, bindTo);
69 for(Socket s = ss.accept(); ; s = ss.accept()) try {
70 dispatch(new Connection(s, Main.defaultDomain));
71 } catch (Exception e) { Log.warn(Port.class, e); }
72 } catch (Exception e) { Log.error(Port.class, e);
73 } catch (Throwable t) {
74 Log.error(this, "serious error, aborting VM");