                 return;
             }
 
-            tor_addr = DEFAULT_TOR_ADDR;
-
             go();
         }
 
-        /* We connect first to the Tor relay; once that happens we connect to
-           the facilitator to get a client address; once we have the address
-           of a waiting client then we connect to the client and BAM! we're in business. */
         private function go():void
         {
-            s_t = new Socket();
-
-            s_t.addEventListener(Event.CONNECT, tor_connected);
-            s_t.addEventListener(Event.CLOSE, function (e:Event):void {
-                puts("Tor: closed.");
-                if (s_c.connected)
-                    s_c.close();
-            });
-            s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
-                puts("Tor: I/O error: " + e.text + ".");
-                if (s_c.connected)
-                    s_c.close();
-            });
-            s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
-                puts("Tor: security error: " + e.text + ".");
-                if (s_c.connected)
-                    s_c.close();
-            });
-
-            puts("Tor: connecting to " + tor_addr.host + ":" + tor_addr.port + ".");
-            s_t.connect(tor_addr.host, tor_addr.port);
-        }
-
-        private function tor_connected(e:Event):void
-        {
-            /* Got a connection to tor, now let's get served a client from the facilitator */
             s_f = new Socket();
 
-            puts("Tor: connected.");
             s_f.addEventListener(Event.CONNECT, fac_connected);
             s_f.addEventListener(Event.CLOSE, function (e:Event):void {
                 puts("Facilitator: closed connection.");
             });
             s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
                 puts("Facilitator: I/O error: " + e.text + ".");
-                if (s_t.connected)
-                    s_t.close();
             });
             s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
                 puts("Facilitator: security error: " + e.text + ".");
-                if (s_t.connected)
-                    s_t.close();
             });
 
             puts("Facilitator: connecting to " + fac_addr.host + ":" + fac_addr.port + ".");


        private var output_text:TextField;

        // Socket to Tor relay.
        private var s_t:Socket;
        // Socket to facilitator.
        private var s_f:Socket;
        // Socket to client.
        private var s_c:Socket;

        private var fac_addr:Object;
        private var tor_addr:Object;

        private function puts(s:String):void
        {
            output_text.appendText(s + "\n");
            output_text.scrollV = output_text.maxScrollV;

        }
    }
}

import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;

/* An instance of a client-relay connection. */
class ProxyPair
{
    // Address ({host, port}) of client.
    private var addr_c:Object;
    // Address ({host, port}) of relay.
    private var addr_r:Object;

    // Socket to client.
    private var s_c:Socket;
    // Socket to relay.
    private var s_r:Socket;

    // Parent swfcat, for UI updates.
    private var ui:swfcat;

    private function log(msg:String):void
    {
        ui.puts(id() + ": " + msg)
    }

    // String describing this pair for output.
    private function id():String
    {
        return "<" + this.addr_c.host + ":" + this.addr_c.port +
            "," + this.addr_r.host + ":" + this.addr_r.port + ">";
    }

    public function ProxyPair(ui:swfcat, addr_c:Object, addr_r:Object)
    {
        this.ui = ui;
        this.addr_c = addr_c;
        this.addr_r = addr_r;
    }

    public function connect():void
    {
        s_r = new Socket();

        s_r.addEventListener(Event.CONNECT, tor_connected);
        s_r.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Tor: closed.");
            if (s_c.connected)
                s_c.close();
        });
        s_r.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Tor: I/O error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
        });
        s_r.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Tor: security error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
        });

        log("Tor: connecting to " + addr_r.host + ":" + addr_r.port + ".");
        s_r.connect(addr_r.host, addr_r.port);
    }

    private function tor_connected(e:Event):void
    {
        log("Tor: connected.");

        s_c = new Socket();

        s_c.addEventListener(Event.CONNECT, client_connected);
        s_c.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Client: closed.");
            if (s_r.connected)
                s_r.close();
        });
        s_c.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Client: I/O error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
        });
        s_c.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Client: security error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
        });

        log("Client: connecting to " + addr_c.host + ":" + addr_c.port + ".");
        s_c.connect(addr_c.host, addr_c.port);
    }

    private function client_connected(e:Event):void
    {
        log("Client: connected.");

        s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
            var bytes:ByteArray = new ByteArray();
            s_r.readBytes(bytes, 0, e.bytesLoaded);
            log("Tor: read " + bytes.length + ".");
            s_c.writeBytes(bytes);
        });
        s_c.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
            var bytes:ByteArray = new ByteArray();
            s_c.readBytes(bytes, 0, e.bytesLoaded);
            log("Client: read " + bytes.length + ".");
            s_r.writeBytes(bytes);
        });
    }
}
