- lazy val input = new InputStream;
-
- class OutputStream private[Connection] extends java.io.OutputStream {
- override def write(b: Int) { write(Array[Byte](b.toByte), 0, 1); }
- override def write(buf: Array[Byte]) { write(buf, 0, buf.length); }
- override def write(buf: Array[Byte], start: Int, len: Int)
- { send(conn, buf, start, len); }
- override def close() { closeconn(conn, CF_CLOSEWR); }
+}
+
+private def withTrigger[T](body: Wrapper => T): T = {
+ val trig = getTrigger();
+ try { body(trig) }
+ finally { putTrigger(trig); }
+}
+
+def interruptWithTrigger[T](body: Wrapper => T): T = {
+ /* interruptWithTrigger { TRIG => BODY }
+ *
+ * Execute BODY and return its result. If the thread receives an
+ * interrupt, the trigger TRIG will be pulled. See `interruptably' for the
+ * full semantics.
+ */
+
+ withTrigger { trig =>
+ interruptably { body(trig) } onInterrupt { trigger(trig); }
+ };
+}
+
+/*----- Glue for the VPN server -------------------------------------------*/
+
+/* The lock class. This is only a class because they're much easier to find
+ * than loose objects through JNI.
+ */
+private class ServerLock;
+
+/* Exceptions. */
+class NameResolutionException(msg: String) extends Exception(msg);
+class InitializationException(msg: String) extends Exception(msg);
+
+/* Primitive operations. */
+@native protected def open_tun(): Int;
+@native protected def base_init();
+@native protected def setup_resolver();
+@native def load_keys(priv: CString, pub: CString, tag: CString);
+@native def unload_keys();
+@native def bind(host: CString, svc: CString);
+@native def unbind();
+@native def mark(seq: Int);
+@native def run();
+@native protected def send(buf: CString, start: Int, len: Int,
+ trig: Wrapper);
+@native protected def recv(buf: CString, start: Int, len: Int,
+ trig: Wrapper): Int;
+
+base_init();
+setup_resolver();
+
+/* Tunnel descriptor plumbing. */
+val pending = HashMap[String, Int]();
+
+def getTunnelFd(peer: CString): Int =
+ pending synchronized { pending(peer.toJString) };
+def storeTunnelFd(peer: String, fd: Int)
+ { pending synchronized { pending(peer) = fd; } }
+def withdrawTunnelFd(peer: String)
+ { pending synchronized { pending -= peer; } }
+def withTunnelFd[T](peer: String, fd: Int)(body: => T): T = {
+ storeTunnelFd(peer, fd);
+ try { body } finally { withdrawTunnelFd(peer); }
+}
+
+/* Server I/O. */
+lazy val serverInput: InputStream = new InputStream {
+ override def read(): Int = {
+ val buf = new Array[Byte](1);
+ val n = read(buf, 0, 1);
+ if (n < 0) -1 else buf(0)&0xff;