tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 213377 discussions

[flashproxy/master] Adding in David's rate limiting code to rtmfpcat
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit ab4e90626b6f6a7152c79b2d2aeeae601deb9d64
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 13:23:08 2011 -0700
Adding in David's rate limiting code to rtmfpcat
---
rtmfp/ProxyPair.as | 218 +++++++++++++++++++++++++++++++++++++-------
rtmfp/RTMFPSocketClient.as | 5 +-
rtmfpcat.as | 38 +++-----
3 files changed, 202 insertions(+), 59 deletions(-)
diff --git a/rtmfp/ProxyPair.as b/rtmfp/ProxyPair.as
index 42d4b81..fb184cc 100644
--- a/rtmfp/ProxyPair.as
+++ b/rtmfp/ProxyPair.as
@@ -7,6 +7,8 @@ package rtmfp
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
+ import flash.utils.clearTimeout;
+ import flash.utils.setTimeout;
import rtmfp.CirrusSocket;
import rtmfp.RTMFPSocket;
@@ -14,20 +16,41 @@ package rtmfp
public class ProxyPair extends EventDispatcher
{
- private var parent:rtmfpcat;
+ private var ui:rtmfpcat;
private var s_r:RTMFPSocket;
private var s_t:Socket;
private var tor_host:String;
private var tor_port:uint;
+
+ private var p2t_schedule:Array;
+ private var t2p_schedule:Array;
+
+ // Bytes per second. Set to undefined to disable limit.
+ public const RATE_LIMIT:Number = 10000;
+ // Seconds.
+ private const RATE_LIMIT_HISTORY:Number = 5.0;
+
+ private var rate_limit:RateLimit;
+
+ // Callback id.
+ private var flush_id:uint;
- public function ProxyPair(parent:rtmfpcat, s_c:CirrusSocket, tor_host:String, tor_port:uint)
+ public function ProxyPair(ui:rtmfpcat, s_c:CirrusSocket, tor_host:String, tor_port:uint)
{
- this.parent = parent;
+ this.ui = ui;
this.tor_host = tor_host;
this.tor_port = tor_port;
+ this.p2t_schedule = new Array();
+ this.t2p_schedule = new Array();
+
+ if (RATE_LIMIT)
+ rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISTORY, RATE_LIMIT_HISTORY);
+ else
+ rate_limit = new RateUnlimit();
+
setup_rtmfp_socket(s_c);
setup_tor_socket();
}
@@ -61,65 +84,196 @@ package rtmfp
private function setup_rtmfp_socket(s_c:CirrusSocket):void
{
s_r = new RTMFPSocket(s_c);
- s_r.addEventListener(RTMFPSocketEvent.PLAY_STARTED, function (e:RTMFPSocketEvent):void {
- puts("Play started.");
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAILED, function (e:RTMFPSocketEvent):void {
+ ui.puts("Peering failed.");
});
- s_r.addEventListener(RTMFPSocketEvent.PUBLISH_STARTED, function (e:RTMFPSocketEvent):void {
- puts("Publishing started.");
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:RTMFPSocketEvent):void {
+ ui.puts("Peering success.");
+ s_t.connect(tor_host, tor_port);
});
s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function (e:RTMFPSocketEvent):void {
- puts("Peer connected.");
+ ui.puts("Peer connected.");
});
s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function (e:RTMFPSocketEvent):void {
- puts("Peer disconnected.");
+ ui.puts("Peer disconnected.");
close();
});
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:RTMFPSocketEvent):void {
- puts("Peering success.");
- s_t.connect(tor_host, tor_port);
+ s_r.addEventListener(RTMFPSocketEvent.PLAY_STARTED, function (e:RTMFPSocketEvent):void {
+ ui.puts("Play started.");
});
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAILED, function (e:RTMFPSocketEvent):void {
- puts("Peering failed.");
+ s_r.addEventListener(RTMFPSocketEvent.PUBLISH_STARTED, function (e:RTMFPSocketEvent):void {
+ ui.puts("Publishing started.");
});
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, proxy_to_tor);
}
private function setup_tor_socket():void
{
s_t = new Socket();
s_t.addEventListener(Event.CONNECT, function (e:Event):void {
- puts("Tor: connected to " + tor_host + ":" + tor_port + ".");
- s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_t.readBytes(bytes, 0, e.bytesLoaded);
- puts("RTMFPSocket: Tor: read " + bytes.length + " bytes.");
- s_r.writeBytes(bytes);
- });
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_r.readBytes(bytes, 0, e.bytesLoaded);
- puts("RTMFPSocket: RTMFP: read " + bytes.length + " bytes.");
- s_t.writeBytes(bytes);
- });
+ ui.puts("Tor: connected to " + tor_host + ":" + tor_port + ".");
dispatchEvent(new Event(Event.CONNECT));
});
s_t.addEventListener(Event.CLOSE, function (e:Event):void {
- puts("Tor: closed connection.");
+ ui.puts("Tor: closed connection.");
close();
});
s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- puts("Tor: I/O error: " + e.text + ".");
+ ui.puts("Tor: I/O error: " + e.text + ".");
close();
});
s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- puts("Tor: security error: " + e.text + ".");
+ ui.puts("Tor: security error: " + e.text + ".");
close();
});
+ s_t.addEventListener(ProgressEvent.SOCKET_DATA, tor_to_proxy);
}
- private function puts(s:String):void
+ private function tor_to_proxy(e:ProgressEvent):void
+ {
+ t2p_schedule.push(e.bytesLoaded);
+ flush();
+ }
+
+ private function proxy_to_tor(e:ProgressEvent):void
{
- parent.puts(s);
+ p2t_schedule.push(e.bytesLoaded);
+ flush();
}
+ /* Send as much data as the rate limit currently allows. */
+ private function flush():void
+ {
+ if (flush_id)
+ clearTimeout(flush_id);
+ flush_id = undefined;
+
+ if (!(s_r.connected && s_t.connected))
+ /* Can't do anything until both sockets are connected. */
+ return;
+
+ while (!rate_limit.is_limited() && (p2t_schedule.length > 0 || t2p_schedule.length > 0)) {
+ var numBytes:uint;
+ var bytes:ByteArray;
+
+ if (p2t_schedule.length > 0) {
+ numBytes = p2t_schedule.shift();
+ bytes = new ByteArray();
+ s_r.readBytes(bytes, 0, numBytes);
+ ui.puts("ProxyPair: RTMFP: read " + bytes.length + " bytes.");
+ s_t.writeBytes(bytes);
+ rate_limit.update(numBytes);
+ }
+ if (t2p_schedule.length > 0) {
+ numBytes = t2p_schedule.shift();
+ bytes = new ByteArray();
+ s_t.readBytes(bytes, 0, numBytes);
+ ui.puts("ProxyPair: Tor: read " + bytes.length + " bytes.");
+ s_r.writeBytes(bytes);
+ rate_limit.update(numBytes);
+ }
+ }
+
+ /* Call again when safe, if necessary. */
+ if (p2t_schedule.length > 0 || t2p_schedule.length > 0)
+ flush_id = setTimeout(flush, rate_limit.when() * 1000);
+ }
+ }
+}
+
+import flash.utils.getTimer;
+
+class RateLimit
+{
+ public function RateLimit()
+ {
+ }
+
+ public function update(n:Number):Boolean
+ {
+ return true;
+ }
+
+ public function when():Number
+ {
+ return 0.0;
+ }
+
+ public function is_limited():Boolean
+ {
+ return false;
+ }
+}
+
+class RateUnlimit extends RateLimit
+{
+ public function RateUnlimit()
+ {
+ }
+
+ public override function update(n:Number):Boolean
+ {
+ return true;
+ }
+
+ public override function when():Number
+ {
+ return 0.0;
+ }
+
+ public override function is_limited():Boolean
+ {
+ return false;
+ }
+}
+
+class BucketRateLimit extends RateLimit
+{
+ private var amount:Number;
+ private var capacity:Number;
+ private var time:Number;
+ private var last_update:uint;
+
+ public function BucketRateLimit(capacity:Number, time:Number)
+ {
+ this.amount = 0.0;
+ /* capacity / time is the rate we are aiming for. */
+ this.capacity = capacity;
+ this.time = time;
+ this.last_update = getTimer();
+ }
+
+ private function age():void
+ {
+ var now:uint;
+ var delta:Number;
+
+ now = getTimer();
+ delta = (now - last_update) / 1000.0;
+ last_update = now;
+
+ amount -= delta * capacity / time;
+ if (amount < 0.0)
+ amount = 0.0;
+ }
+
+ public override function update(n:Number):Boolean
+ {
+ age();
+ amount += n;
+
+ return amount <= capacity;
+ }
+
+ public override function when():Number
+ {
+ age();
+ return (amount - capacity) / (capacity / time);
+ }
+
+ public override function is_limited():Boolean
+ {
+ age();
+ return amount > capacity;
}
}
\ No newline at end of file
diff --git a/rtmfp/RTMFPSocketClient.as b/rtmfp/RTMFPSocketClient.as
index 7469a53..b917bcb 100644
--- a/rtmfp/RTMFPSocketClient.as
+++ b/rtmfp/RTMFPSocketClient.as
@@ -28,9 +28,8 @@ package rtmfp
public function data_available(bytes:ByteArray):void
{
- this._bytes.clear();
- bytes.readBytes(this._bytes);
- dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, this._bytes.bytesAvailable, this._bytes.length));
+ bytes.readBytes(_bytes, _bytes.length, 0);
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, _bytes.bytesAvailable, _bytes.bytesAvailable));
}
public function get connect_acknowledged():Boolean
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 25099dd..2273bc9 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -6,8 +6,7 @@ package
import flash.text.TextField;
import flash.text.TextFormat;
import flash.events.Event;
- import flash.utils.clearInterval;
- import flash.utils.setInterval;
+ import flash.utils.setTimeout;
import rtmfp.CirrusSocket;
import rtmfp.FacilitatorSocket;
@@ -39,9 +38,8 @@ package
port: 9001
};
- /* Poll facilitator every 3 sec if in proxy mode and haven't found
- anyone to proxy */
- private const DEFAULT_FAC_POLL_INTERVAL:uint = 3000;
+ /* Poll facilitator every 10 sec */
+ private const DEFAULT_FAC_POLL_INTERVAL:uint = 10000;
// Socket to Cirrus server
private var s_c:CirrusSocket;
@@ -54,8 +52,6 @@ package
private var proxy_mode:Boolean;
- private var fac_poll_interval:uint;
-
/* TextField for debug output. */
private var output_text:TextField;
@@ -80,6 +76,12 @@ package
// Wait until the query string parameters are loaded.
this.loaderInfo.addEventListener(Event.COMPLETE, loaderinfo_complete);
}
+
+ public function puts(s:String):void
+ {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
+ }
private function loaderinfo_complete(e:Event):void
{
@@ -133,11 +135,7 @@ package
s_c = new CirrusSocket();
s_c.addEventListener(CirrusSocketEvent.CONNECT_SUCCESS, function (e:CirrusSocketEvent):void {
puts("Cirrus: connected with id " + s_c.id + ".");
- if (proxy_mode) {
- fac_poll_interval = setInterval(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
- } else {
- establish_facilitator_connection();
- }
+ establish_facilitator_connection();
});
s_c.addEventListener(CirrusSocketEvent.CONNECT_FAILED, function (e:CirrusSocketEvent):void {
puts("Error: failed to connect to Cirrus.");
@@ -180,6 +178,7 @@ package
});
s_f.addEventListener(FacilitatorSocketEvent.CONNECT_FAILED, function (e:Event):void {
puts("Facilitator: connect failed.");
+ setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
s_f.addEventListener(FacilitatorSocketEvent.CONNECT_CLOSED, function (e:Event):void {
puts("Facilitator: connect closed.");
@@ -188,16 +187,17 @@ package
if (proxy_mode) {
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATION_RECEIVED, function (e:FacilitatorSocketEvent):void {
puts("Facilitator: got registration " + e.client);
- clearInterval(fac_poll_interval);
start_proxy_pair();
s_c.send_hello(e.client);
});
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATIONS_EMPTY, function (e:Event):void {
puts("Facilitator: no registrations available.");
+ setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
} else {
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATION_FAILED, function (e:Event):void {
puts("Facilitator: registration failed.");
+ setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
}
s_f.connect(fac_addr.host, fac_addr.port);
@@ -213,11 +213,7 @@ package
p_p.addEventListener(Event.CLOSE, function (e:Event):void {
puts("ProxyPair: connection closed.");
p_p = null;
- if (proxy_mode) {
- fac_poll_interval = setInterval(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
- } else {
- establish_facilitator_connection();
- }
+ establish_facilitator_connection();
});
p_p.listen(s_c.local_stream_name);
}
@@ -238,11 +234,5 @@ package
return addr;
}
-
- public function puts(s:String):void
- {
- output_text.appendText(s + "\n");
- output_text.scrollV = output_text.maxScrollV;
- }
}
}
1
0

[flashproxy/master] Using URLLoader in the FacilitatorSocket, Facilitator now speaks true HTTP
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit fbffb6fce47047c877d8dc4d2a83bcb4ee2926ea
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 19:49:49 2011 -0700
Using URLLoader in the FacilitatorSocket, Facilitator now speaks true HTTP
---
facilitator.py | 55 +++++++++++++++++---
rtmfp/FacilitatorSocket.as | 121 ++++++++++++++++++++------------------------
rtmfpcat.as | 19 ++-----
3 files changed, 106 insertions(+), 89 deletions(-)
diff --git a/facilitator.py b/facilitator.py
index c9859db..0ea86a1 100755
--- a/facilitator.py
+++ b/facilitator.py
@@ -10,6 +10,7 @@ import socket
import sys
import threading
import time
+import urllib
DEFAULT_ADDRESS = "0.0.0.0"
DEFAULT_PORT = 9002
@@ -190,31 +191,47 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
log(u"proxy %s connects" % format_addr(self.client_address))
+ if self.path == "/crossdomain.xml":
+ self.send_crossdomain()
+ return
+
+ client = ""
reg = REGS.fetch()
if reg:
log(u"proxy %s gets %s (now %d)" % (format_addr(self.client_address), unicode(reg), len(REGS)))
- self.request.send(str(reg))
+ client = str(reg)
else:
log(u"proxy %s gets none" % format_addr(self.client_address))
+ client = "Registration list empty"
+
+ response = "client=%s" % urllib.quote(client)
+ self.send_response(200)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Content-Length', str(len(response)))
+ self.end_headers()
+ self.wfile.write(response)
def do_POST(self):
- data = self.rfile.readline(1024).strip()
- try:
- vals = cgi.parse_qs(data, False, True)
- except ValueError, e:
- log(u"client %s POST syntax error: %s" % (format_addr(self.client_address), repr(str(e))))
+ data = cgi.FieldStorage(fp = self.rfile, headers = self.headers,
+ environ = {'REQUEST_METHOD' : 'POST',
+ 'CONTENT_TYPE' : self.headers['Content-Type']})
+
+ if self.path == "/crossdomain.xml":
+ self.send_crossdomain()
return
- client_specs = vals.get("client")
- if client_specs is None or len(client_specs) != 1:
+ client_specs = data["client"]
+ if client_specs is None or client_specs.value is None:
log(u"client %s missing \"client\" param" % format_addr(self.client_address))
+ self.send_error(404)
return
- val = client_specs[0]
+ val = client_specs.value
try:
reg = Reg.parse(val, self.client_address[0])
except ValueError, e:
log(u"client %s syntax error in %s: %s" % (format_addr(self.client_address), repr(val), repr(str(e))))
+ self.send_error(404)
return
log(u"client %s regs %s -> %s" % (format_addr(self.client_address), val, unicode(reg)))
@@ -222,10 +239,30 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
log(u"client %s %s (now %d)" % (format_addr(self.client_address), unicode(reg), len(REGS)))
else:
log(u"client %s %s (already present, now %d)" % (format_addr(self.client_address), unicode(reg), len(REGS)))
+
+ response = ""
+
+ self.send_response(200)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Content-Length', str(len(response)))
+ self.send_header('Connection', 'close')
+ self.end_headers()
+ self.wfile.write(response)
def log_message(self, format, *args):
msg = format % args
log(u"message from HTTP handler for %s: %s" % (format_addr(self.client_address), repr(msg)))
+
+ def send_crossdomain(self):
+ crossdomain = """\
+<cross-domain-policy>
+ <allow-access-from domain="*" to-ports="%s"/>
+</cross-domain-policy>\r\n""" % (address[1])
+ self.send_response(200)
+ self.send_header('Content-Type', 'application/xml')
+ self.send_header('Content-Length', str(len(crossdomain)))
+ self.end_headers()
+ self.wfile.write(crossdomain)
REGS = RegSet()
diff --git a/rtmfp/FacilitatorSocket.as b/rtmfp/FacilitatorSocket.as
index e175290..32c8a7d 100644
--- a/rtmfp/FacilitatorSocket.as
+++ b/rtmfp/FacilitatorSocket.as
@@ -1,108 +1,94 @@
package rtmfp
{
- import flash.net.Socket;
import flash.events.Event;
import flash.events.EventDispatcher;
+ import flash.events.HTTPStatusEvent;
import flash.events.IOErrorEvent;
- import flash.events.NetStatusEvent;
- import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
- import flash.utils.clearInterval;
- import flash.utils.setInterval;
+ import flash.net.URLLoader;
+ import flash.net.URLLoaderDataFormat;
+ import flash.net.URLRequest;
+ import flash.net.URLRequestMethod;
+ import flash.net.URLVariables;
+ import flash.system.Security;
import rtmfp.events.FacilitatorSocketEvent;
- [Event(name=FacilitatorSocketEvent.CONNECT_CLOSED, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
[Event(name=FacilitatorSocketEvent.CONNECT_FAILED, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
- [Event(name=FacilitatorSocketEvent.CONNECT_SUCCESS, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
[Event(name=FacilitatorSocketEvent.REGISTRATION_FAILED, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
[Event(name=FacilitatorSocketEvent.REGISTRATION_RECEIVED, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
[Event(name=FacilitatorSocketEvent.REGISTRATIONS_EMPTY, type="com.flashproxy.rtmfp.events.FacilitatorSocketEvent")]
public class FacilitatorSocket extends EventDispatcher
{
- private var socket:Socket;
- private var connected:Boolean;
- private var connection_timeout:uint;
+ private var host:String;
+ private var port:uint;
- public function FacilitatorSocket()
- {
- socket = null;
- connected = false;
- }
-
- public function close():void
- {
- connected = false;
- if (socket != null) {
- socket.removeEventListener(Event.CONNECT, on_connect_event);
- socket.removeEventListener(Event.CLOSE, on_close_event);
- socket.removeEventListener(IOErrorEvent.IO_ERROR, on_io_error_event);
- socket.removeEventListener(ProgressEvent.SOCKET_DATA, on_progress_event);
- socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, on_security_error_event);
- if (connected) {
- socket.close();
- }
- }
- }
-
- public function connect(host:String, port:uint):void
- {
- if (socket != null || connected) {
- return;
- }
-
- socket = new Socket();
- socket.addEventListener(Event.CONNECT, on_connect_event);
- socket.addEventListener(Event.CLOSE, on_close_event);
- socket.addEventListener(IOErrorEvent.IO_ERROR, on_io_error_event);
- socket.addEventListener(ProgressEvent.SOCKET_DATA, on_progress_event);
- socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, on_security_error_event);
- socket.connect(host, port);
+ public function FacilitatorSocket(host:String, port:uint)
+ {
+ this.host = host;
+ this.port = port;
}
public function get_registration():void
{
- if (!connected) return;
- socket.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
+ make_request(URLRequestMethod.GET);
}
public function post_registration(registration_data:String):void
- {
- if (!connected) return;
- socket.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + registration_data + "\r\n");
+ {
+ var data:URLVariables = new URLVariables();
+ data.client = registration_data;
+ make_request(URLRequestMethod.POST, data);
}
private function fail():void
{
- clearInterval(connection_timeout);
dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_FAILED));
}
- private function on_close_event(event:Event):void
+ private function make_request(method:String, data:URLVariables = null):void
{
- close();
- dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_CLOSED));
+ var request:URLRequest = new URLRequest(url)
+ request.data = data;
+ request.method = method;
+
+ var url_loader:URLLoader = new URLLoader();
+ url_loader = new URLLoader();
+ url_loader.dataFormat = URLLoaderDataFormat.VARIABLES;
+
+ url_loader.addEventListener(Event.COMPLETE, on_complete_event);
+ url_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, on_http_status_event);
+ url_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, on_security_error_event);
+ url_loader.addEventListener(IOErrorEvent.IO_ERROR, on_io_error_event);
+
+ url_loader.load(request);
}
- private function on_connect_event(event:Event):void
+ private function on_complete_event(event:Event):void
{
- connected = true;
- dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_SUCCESS));
+ try {
+ var client_id:String = event.target.data.client;
+ if (client_id == "Registration list empty") {
+ dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.REGISTRATIONS_EMPTY));
+ } else {
+ dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.REGISTRATION_RECEIVED, client_id));
+ }
+ } catch (e:Error) {
+ /* error is thrown for POST when we don't care about
+ the response anyways */
+ }
+
+ event.target.close()
}
- private function on_io_error_event(event:IOErrorEvent):void
+ private function on_http_status_event(event:HTTPStatusEvent):void
{
- fail();
+ /* empty for now */
}
- private function on_progress_event(event:ProgressEvent):void
+ private function on_io_error_event(event:IOErrorEvent):void
{
- var client_id:String = socket.readUTFBytes(event.bytesLoaded);
- if (client_id == "Registration list empty") {
- dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.REGISTRATIONS_EMPTY));
- } else {
- dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.REGISTRATION_RECEIVED, client_id));
- }
+ fail();
}
private function on_security_error_event(event:SecurityErrorEvent):void
@@ -110,6 +96,9 @@ package rtmfp
fail();
}
-
+ private function get url():String
+ {
+ return "http://" + host + ":" + port;
+ }
}
}
\ No newline at end of file
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 713fc45..224fe56 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -166,23 +166,11 @@ package
private function establish_facilitator_connection():void
{
- s_f = new FacilitatorSocket();
- s_f.addEventListener(FacilitatorSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
- if (proxy_mode) {
- puts("Facilitator: getting registration.");
- s_f.get_registration();
- } else {
- puts("Facilitator: posting registration.");
- s_f.post_registration(s_c.id);
- }
- });
+ s_f = new FacilitatorSocket(fac_addr.host, fac_addr.port);
s_f.addEventListener(FacilitatorSocketEvent.CONNECT_FAILED, function (e:Event):void {
puts("Facilitator: connect failed.");
setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
- s_f.addEventListener(FacilitatorSocketEvent.CONNECT_CLOSED, function (e:Event):void {
- puts("Facilitator: connect closed.");
- });
if (proxy_mode) {
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATION_RECEIVED, function (e:FacilitatorSocketEvent):void {
@@ -194,13 +182,16 @@ package
puts("Facilitator: no registrations available.");
setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
+ puts("Facilitator: getting registration.");
+ s_f.get_registration();
} else {
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATION_FAILED, function (e:Event):void {
puts("Facilitator: registration failed.");
setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
});
+ puts("Facilitator: posting registration.");
+ s_f.post_registration(s_c.id);
}
- s_f.connect(fac_addr.host, fac_addr.port);
}
private function start_proxy_pair():void
1
0

[flashproxy/master] Changing terminology to use relay/proxy instead of Tor/RTMFP
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit 3a8df84e3bb8dcc16d411a4c2fb9f4e005f313c8
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 13:47:34 2011 -0700
Changing terminology to use relay/proxy instead of Tor/RTMFP
---
rtmfp/ProxyPair.as | 112 ++++++++++++++++++++++++++--------------------------
rtmfpcat.as | 26 ++++++------
2 files changed, 69 insertions(+), 69 deletions(-)
diff --git a/rtmfp/ProxyPair.as b/rtmfp/ProxyPair.as
index fb184cc..159abde 100644
--- a/rtmfp/ProxyPair.as
+++ b/rtmfp/ProxyPair.as
@@ -18,126 +18,126 @@ package rtmfp
{
private var ui:rtmfpcat;
- private var s_r:RTMFPSocket;
- private var s_t:Socket;
+ private var s_p:RTMFPSocket;
+ private var s_r:Socket;
- private var tor_host:String;
- private var tor_port:uint;
+ private var relay_host:String;
+ private var relay_port:uint;
- private var p2t_schedule:Array;
- private var t2p_schedule:Array;
+ private var p2r_schedule:Array;
+ private var r2p_schedule:Array;
// Bytes per second. Set to undefined to disable limit.
public const RATE_LIMIT:Number = 10000;
// Seconds.
- private const RATE_LIMIT_HISTORY:Number = 5.0;
+ private const RATE_LIMIT_HISrelayY:Number = 5.0;
private var rate_limit:RateLimit;
// Callback id.
private var flush_id:uint;
- public function ProxyPair(ui:rtmfpcat, s_c:CirrusSocket, tor_host:String, tor_port:uint)
+ public function ProxyPair(ui:rtmfpcat, s_c:CirrusSocket, relay_host:String, relay_port:uint)
{
this.ui = ui;
- this.tor_host = tor_host;
- this.tor_port = tor_port;
+ this.relay_host = relay_host;
+ this.relay_port = relay_port;
- this.p2t_schedule = new Array();
- this.t2p_schedule = new Array();
+ this.p2r_schedule = new Array();
+ this.r2p_schedule = new Array();
if (RATE_LIMIT)
- rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISTORY, RATE_LIMIT_HISTORY);
+ rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISrelayY, RATE_LIMIT_HISrelayY);
else
rate_limit = new RateUnlimit();
setup_rtmfp_socket(s_c);
- setup_tor_socket();
+ setup_relay_socket();
}
public function close():void
{
+ if (s_p.connected) {
+ s_p.close();
+ }
if (s_r.connected) {
s_r.close();
}
- if (s_t.connected) {
- s_t.close();
- }
dispatchEvent(new Event(Event.CLOSE));
}
public function connect(peer:String, stream:String):void
{
- s_r.connect(peer, stream);
+ s_p.connect(peer, stream);
}
public function get connected():Boolean
{
- return (s_r.connected && s_t.connected);
+ return (s_p.connected && s_r.connected);
}
public function listen(stream:String):void
{
- s_r.listen(stream);
+ s_p.listen(stream);
}
private function setup_rtmfp_socket(s_c:CirrusSocket):void
{
- s_r = new RTMFPSocket(s_c);
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAILED, function (e:RTMFPSocketEvent):void {
+ s_p = new RTMFPSocket(s_c);
+ s_p.addEventListener(RTMFPSocketEvent.CONNECT_FAILED, function (e:RTMFPSocketEvent):void {
ui.puts("Peering failed.");
});
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:RTMFPSocketEvent):void {
+ s_p.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:RTMFPSocketEvent):void {
ui.puts("Peering success.");
- s_t.connect(tor_host, tor_port);
+ s_r.connect(relay_host, relay_port);
});
- s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function (e:RTMFPSocketEvent):void {
+ s_p.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function (e:RTMFPSocketEvent):void {
ui.puts("Peer connected.");
});
- s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function (e:RTMFPSocketEvent):void {
+ s_p.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function (e:RTMFPSocketEvent):void {
ui.puts("Peer disconnected.");
close();
});
- s_r.addEventListener(RTMFPSocketEvent.PLAY_STARTED, function (e:RTMFPSocketEvent):void {
+ s_p.addEventListener(RTMFPSocketEvent.PLAY_STARTED, function (e:RTMFPSocketEvent):void {
ui.puts("Play started.");
});
- s_r.addEventListener(RTMFPSocketEvent.PUBLISH_STARTED, function (e:RTMFPSocketEvent):void {
+ s_p.addEventListener(RTMFPSocketEvent.PUBLISH_STARTED, function (e:RTMFPSocketEvent):void {
ui.puts("Publishing started.");
});
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, proxy_to_tor);
+ s_p.addEventListener(ProgressEvent.SOCKET_DATA, proxy_to_relay);
}
- private function setup_tor_socket():void
+ private function setup_relay_socket():void
{
- s_t = new Socket();
- s_t.addEventListener(Event.CONNECT, function (e:Event):void {
- ui.puts("Tor: connected to " + tor_host + ":" + tor_port + ".");
+ s_r = new Socket();
+ s_r.addEventListener(Event.CONNECT, function (e:Event):void {
+ ui.puts("Relay: connected to " + relay_host + ":" + relay_port + ".");
dispatchEvent(new Event(Event.CONNECT));
});
- s_t.addEventListener(Event.CLOSE, function (e:Event):void {
- ui.puts("Tor: closed connection.");
+ s_r.addEventListener(Event.CLOSE, function (e:Event):void {
+ ui.puts("Relay: closed connection.");
close();
});
- s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- ui.puts("Tor: I/O error: " + e.text + ".");
+ s_r.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ ui.puts("Relay: I/O error: " + e.text + ".");
close();
});
- s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- ui.puts("Tor: security error: " + e.text + ".");
+ s_r.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ ui.puts("Relay: security error: " + e.text + ".");
close();
});
- s_t.addEventListener(ProgressEvent.SOCKET_DATA, tor_to_proxy);
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, relay_to_proxy);
}
- private function tor_to_proxy(e:ProgressEvent):void
+ private function relay_to_proxy(e:ProgressEvent):void
{
- t2p_schedule.push(e.bytesLoaded);
+ r2p_schedule.push(e.bytesLoaded);
flush();
}
- private function proxy_to_tor(e:ProgressEvent):void
+ private function proxy_to_relay(e:ProgressEvent):void
{
- p2t_schedule.push(e.bytesLoaded);
+ p2r_schedule.push(e.bytesLoaded);
flush();
}
@@ -148,34 +148,34 @@ package rtmfp
clearTimeout(flush_id);
flush_id = undefined;
- if (!(s_r.connected && s_t.connected))
+ if (!(s_p.connected && s_r.connected))
/* Can't do anything until both sockets are connected. */
return;
- while (!rate_limit.is_limited() && (p2t_schedule.length > 0 || t2p_schedule.length > 0)) {
+ while (!rate_limit.is_limited() && (p2r_schedule.length > 0 || r2p_schedule.length > 0)) {
var numBytes:uint;
var bytes:ByteArray;
- if (p2t_schedule.length > 0) {
- numBytes = p2t_schedule.shift();
+ if (p2r_schedule.length > 0) {
+ numBytes = p2r_schedule.shift();
bytes = new ByteArray();
- s_r.readBytes(bytes, 0, numBytes);
+ s_p.readBytes(bytes, 0, numBytes);
ui.puts("ProxyPair: RTMFP: read " + bytes.length + " bytes.");
- s_t.writeBytes(bytes);
+ s_r.writeBytes(bytes);
rate_limit.update(numBytes);
}
- if (t2p_schedule.length > 0) {
- numBytes = t2p_schedule.shift();
+ if (r2p_schedule.length > 0) {
+ numBytes = r2p_schedule.shift();
bytes = new ByteArray();
- s_t.readBytes(bytes, 0, numBytes);
- ui.puts("ProxyPair: Tor: read " + bytes.length + " bytes.");
- s_r.writeBytes(bytes);
+ s_r.readBytes(bytes, 0, numBytes);
+ ui.puts("ProxyPair: Relay: read " + bytes.length + " bytes.");
+ s_p.writeBytes(bytes);
rate_limit.update(numBytes);
}
}
/* Call again when safe, if necessary. */
- if (p2t_schedule.length > 0 || t2p_schedule.length > 0)
+ if (p2r_schedule.length > 0 || r2p_schedule.length > 0)
flush_id = setTimeout(flush, rate_limit.when() * 1000);
}
}
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 2273bc9..713fc45 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -33,7 +33,7 @@ package
/* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
crossdomain policy. */
- private const DEFAULT_TOR_PROXY_ADDR:Object = {
+ private const DEFAULT_TOR_RELAY_ADDR:Object = {
host: "173.255.221.44",
port: 9001
};
@@ -56,7 +56,7 @@ package
private var output_text:TextField;
private var fac_addr:Object;
- private var tor_addr:Object;
+ private var relay_addr:Object;
public function rtmfpcat()
{
@@ -86,7 +86,7 @@ package
private function loaderinfo_complete(e:Event):void
{
var fac_spec:String;
- var tor_spec:String;
+ var relay_spec:String;
puts("Parameters loaded.");
@@ -104,20 +104,20 @@ package
} else {
fac_addr = DEFAULT_FACILITATOR_ADDR;
}
-
- tor_spec = this.loaderInfo.parameters["tor"];
- if (tor_spec) {
- puts("Tor spec: \"" + tor_spec + "\"");
- tor_addr = parse_addr_spec(tor_spec);
- if (!tor_addr) {
- puts("Error: Tor spec must be in the form \"host:port\".");
+
+ relay_spec = this.loaderInfo.parameters["relay"];
+ if (relay_spec) {
+ puts("Relay spec: \"" + relay_spec + "\"");
+ relay_addr = parse_addr_spec(relay_spec);
+ if (!relay_addr) {
+ puts("Error: Relay spec must be in the form \"host:port\".");
return;
}
} else {
if (proxy_mode) {
- tor_addr = DEFAULT_TOR_PROXY_ADDR;
+ relay_addr = DEFAULT_TOR_RELAY_ADDR;
} else {
- tor_addr = DEFAULT_TOR_CLIENT_ADDR;
+ relay_addr = DEFAULT_TOR_CLIENT_ADDR;
}
}
@@ -206,7 +206,7 @@ package
private function start_proxy_pair():void
{
puts("Starting proxy pair on stream " + s_c.local_stream_name);
- p_p = new ProxyPair(this, s_c, tor_addr.host, tor_addr.port);
+ p_p = new ProxyPair(this, s_c, relay_addr.host, relay_addr.port);
p_p.addEventListener(Event.CONNECT, function (e:Event):void {
puts("ProxyPair: connected!");
});
1
0
commit 781f10234c6a11af9a781b08df8dedf2a9bdac8f
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 20:20:43 2011 -0700
Incorporated badge into rtmfpcat
---
rtmfpcat.as | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 137 insertions(+), 13 deletions(-)
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 224fe56..37701e8 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -50,47 +50,62 @@ package
private var proxy_pairs:Array;
+ private var debug_mode:Boolean;
private var proxy_mode:Boolean;
/* TextField for debug output. */
private var output_text:TextField;
+
+ /* Badge for display */
+ private var badge:InternetFreedomBadge;
private var fac_addr:Object;
private var relay_addr:Object;
public function rtmfpcat()
{
+ proxy_mode = false;
+ debug_mode = false;
+
// Absolute positioning.
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
-
- output_text = new TextField();
- output_text.width = stage.stageWidth;
- output_text.height = stage.stageHeight;
- output_text.background = true;
- output_text.backgroundColor = 0x001f0f;
- output_text.textColor = 0x44cc44;
- addChild(output_text);
- puts("Starting.");
// Wait until the query string parameters are loaded.
this.loaderInfo.addEventListener(Event.COMPLETE, loaderinfo_complete);
}
public function puts(s:String):void
{
- output_text.appendText(s + "\n");
- output_text.scrollV = output_text.maxScrollV;
+ if (output_text != null) {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
+ }
}
private function loaderinfo_complete(e:Event):void
{
var fac_spec:String;
var relay_spec:String;
-
- puts("Parameters loaded.");
+ debug_mode = (this.loaderInfo.parameters["debug"] != null)
proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
+ if (proxy_mode && !debug_mode) {
+ badge = new InternetFreedomBadge(this);
+ badge.display();
+ } else {
+ output_text = new TextField();
+ output_text.width = stage.stageWidth;
+ output_text.height = stage.stageHeight;
+ output_text.background = true;
+ output_text.backgroundColor = 0x001f0f;
+ output_text.textColor = 0x44cc44;
+ addChild(output_text);
+ }
+
+ puts("Starting: parameters loaded.");
+
+ /* TODO: use this to have multiple proxies going at once */
proxy_pairs = new Array();
fac_spec = this.loaderInfo.parameters["facilitator"];
@@ -157,6 +172,9 @@ package
if (!proxy_mode) {
start_proxy_pair();
s_c.send_hello(e.peer);
+ } else if (!debug_mode && badge != null) {
+ badge.total_proxy_pairs++;
+ badge.num_proxy_pairs++;
}
p_p.connect(e.peer, e.stream);
});
@@ -204,6 +222,9 @@ package
p_p.addEventListener(Event.CLOSE, function (e:Event):void {
puts("ProxyPair: connection closed.");
p_p = null;
+ if (proxy_mode && !debug_mode && badge != null) {
+ badge.num_proxy_pairs++;
+ }
establish_facilitator_connection();
});
p_p.listen(s_c.local_stream_name);
@@ -227,3 +248,106 @@ package
}
}
}
+
+import flash.text.TextField;
+import flash.text.TextFormat;
+
+class InternetFreedomBadge {
+
+ private var ui:rtmfpcat;
+
+ private var _num_proxy_pairs:uint;
+ private var _total_proxy_pairs:uint;
+
+ [Embed(source="badge.png")]
+ private var BadgeImage:Class;
+ private var tot_client_count_tf:TextField;
+ private var tot_client_count_fmt:TextFormat;
+ private var cur_client_count_tf:TextField;
+ private var cur_client_count_fmt:TextFormat;
+
+ public function InternetFreedomBadge(ui:rtmfpcat)
+ {
+ this.ui = ui;
+ _num_proxy_pairs = 0;
+ _total_proxy_pairs = 0;
+
+ /* Setup client counter for badge. */
+ tot_client_count_fmt = new TextFormat();
+ tot_client_count_fmt.color = 0xFFFFFF;
+ tot_client_count_fmt.align = "center";
+ tot_client_count_fmt.font = "courier-new";
+ tot_client_count_fmt.bold = true;
+ tot_client_count_fmt.size = 10;
+ tot_client_count_tf = new TextField();
+ tot_client_count_tf.width = 20;
+ tot_client_count_tf.height = 17;
+ tot_client_count_tf.background = false;
+ tot_client_count_tf.defaultTextFormat = tot_client_count_fmt;
+ tot_client_count_tf.x=47;
+ tot_client_count_tf.y=0;
+
+ cur_client_count_fmt = new TextFormat();
+ cur_client_count_fmt.color = 0xFFFFFF;
+ cur_client_count_fmt.align = "center";
+ cur_client_count_fmt.font = "courier-new";
+ cur_client_count_fmt.bold = true;
+ cur_client_count_fmt.size = 10;
+ cur_client_count_tf = new TextField();
+ cur_client_count_tf.width = 20;
+ cur_client_count_tf.height = 17;
+ cur_client_count_tf.background = false;
+ cur_client_count_tf.defaultTextFormat = cur_client_count_fmt;
+ cur_client_count_tf.x=47;
+ cur_client_count_tf.y=6;
+
+ /* Update the client counter on badge. */
+ update_client_count();
+ }
+
+ public function display():void
+ {
+ ui.addChild(new BadgeImage());
+ /* Tried unsuccessfully to add counter to badge. */
+ /* For now, need two addChilds :( */
+ ui.addChild(tot_client_count_tf);
+ ui.addChild(cur_client_count_tf);
+ }
+
+ public function get num_proxy_pairs():uint
+ {
+ return _num_proxy_pairs;
+ }
+
+ public function set num_proxy_pairs(amount:uint):void
+ {
+ _num_proxy_pairs = amount;
+ update_client_count();
+ }
+
+ public function get total_proxy_pairs():uint
+ {
+ return _total_proxy_pairs;
+ }
+
+ public function set total_proxy_pairs(amount:uint):void
+ {
+ _total_proxy_pairs = amount;
+ /* note: doesn't update, so be sure to update this
+ before you update num_proxy_pairs! */
+ }
+
+ private function update_client_count():void
+ {
+ /* Update total client count. */
+ if (String(total_proxy_pairs).length == 1)
+ tot_client_count_tf.text = "0" + String(total_proxy_pairs);
+ else
+ tot_client_count_tf.text = String(total_proxy_pairs);
+
+ /* Update current client count. */
+ cur_client_count_tf.text = "";
+ for(var i:Number = 0; i < num_proxy_pairs; i++)
+ cur_client_count_tf.appendText(".");
+ }
+}
1
0
commit 4ba49ccb6c04da8565f06923a30734aa765414cd
Merge: d5c1258 9b584d0
Author: David Fifield <david(a)bamsoftware.com>
Date: Tue May 24 22:56:05 2011 -0700
Merge branch 'master' into rtmfp
badge.png | Bin 264 -> 682 bytes
badge_con_counter.png | Bin 270 -> 0 bytes
nat-birthday.py | 132 -----------------------------------
notes.txt | 2 -
swfcat.as | 184 +++++++++++++++++++++++++++++++++++++++++++++----
5 files changed, 170 insertions(+), 148 deletions(-)
diff --cc swfcat.as
index 76de948,6f4be0c..108f6eb
--- a/swfcat.as
+++ b/swfcat.as
@@@ -45,13 -50,13 +50,15 @@@ packag
/* Number of proxy pairs ever connected. */
private var total_proxy_pairs:int = 0;
+ public var rate_limit:RateLimit;
+
/* Badge with a client counter */
- [Embed(source="badge_con_counter.png")]
+ [Embed(source="badge.png")]
private var BadgeImage:Class;
- private var client_count_tf:TextField;
- private var client_count_fmt:TextFormat;
+ private var tot_client_count_tf:TextField;
+ private var tot_client_count_fmt:TextFormat;
+ private var cur_client_count_tf:TextField;
+ private var cur_client_count_fmt:TextFormat;
public function puts(s:String):void
{
1
0
commit 389c5f56f79bed8c5d220fa8a6bf05666951292e
Author: David Fifield <david(a)bamsoftware.com>
Date: Tue May 24 23:16:51 2011 -0700
Whitespace.
---
rtmfp/RTMFPSocket.as | 283 +++++++++++++++--------------
rtmfp/RTMFPSocketClient.as | 110 ++++++------
rtmfp/events/RTMFPSocketEvent.as | 43 ++---
rtmfpcat.as | 372 +++++++++++++++++++-------------------
4 files changed, 404 insertions(+), 404 deletions(-)
diff --git a/rtmfp/RTMFPSocket.as b/rtmfp/RTMFPSocket.as
index bb00994..d524699 100644
--- a/rtmfp/RTMFPSocket.as
+++ b/rtmfp/RTMFPSocket.as
@@ -1,10 +1,10 @@
/* RTMFPSocket abstraction
* Author: Nate Hardison, May 2011
- *
+ *
* This code is heavily based off of BelugaFile, an open-source
* Air file-transfer application written by Nicholas Bliyk.
* Website: http://www.belugafile.com/
- * Source: http://code.google.com/p/belugafile/
+ * Source: http://code.google.com/p/belugafile/
*
*/
@@ -22,210 +22,211 @@ package rtmfp
import flash.utils.clearInterval;
import flash.utils.setInterval;
import flash.utils.setTimeout;
-
+
import rtmfp.RTMFPSocketClient;
import rtmfp.events.RTMFPSocketEvent;
[Event(name="connectSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="connectFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="publishStart", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peerConnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peeringSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peeringFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peerDisconnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="connectFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="publishStart", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peerConnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peeringSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peeringFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peerDisconnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
public class RTMFPSocket extends EventDispatcher
{
/* The name of the "media" to pass between peers */
private static const DATA:String = "data";
- private static const DEFAULT_CIRRUS_ADDRESS:String = "rtmfp://p2p.rtmfp.net";
- private static const DEFAULT_CIRRUS_KEY:String = RTMFP::CIRRUS_KEY;
- private static const DEFAULT_CONNECT_TIMEOUT:uint = 4000;
-
+ private static const DEFAULT_CIRRUS_ADDRESS:String = "rtmfp://p2p.rtmfp.net";
+ private static const DEFAULT_CIRRUS_KEY:String = RTMFP::CIRRUS_KEY;
+ private static const DEFAULT_CONNECT_TIMEOUT:uint = 4000;
+
/* Connection to the Cirrus rendezvous service */
private var connection:NetConnection;
-
- /* ID of the peer to connect to */
- private var peerID:String;
-
- /* Data streams to be established with peer */
- private var sendStream:NetStream;
- private var recvStream:NetStream;
-
- /* Timeouts */
- private var connectionTimeout:int;
- private var peerConnectTimeout:uint;
+
+ /* ID of the peer to connect to */
+ private var peerID:String;
+
+ /* Data streams to be established with peer */
+ private var sendStream:NetStream;
+ private var recvStream:NetStream;
+
+ /* Timeouts */
+ private var connectionTimeout:int;
+ private var peerConnectTimeout:uint;
public function RTMFPSocket(){}
-
+
public function connect(addr:String = DEFAULT_CIRRUS_ADDRESS, key:String = DEFAULT_CIRRUS_KEY):void
{
- connection = new NetConnection();
- connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
- connection.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
- connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
- connection.connect(addr + "/" + key);
- connectionTimeout = setInterval(fail, DEFAULT_CONNECT_TIMEOUT);
+ connection = new NetConnection();
+ connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
+ connection.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
+ connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
+ connection.connect(addr + "/" + key);
+ connectionTimeout = setInterval(fail, DEFAULT_CONNECT_TIMEOUT);
}
public function close():void
{
- connection.close();
+ connection.close();
}
public function get id():String
{
- if (connection != null && connection.connected) {
- return connection.nearID;
- }
-
- return null;
+ if (connection != null && connection.connected) {
+ return connection.nearID;
+ }
+
+ return null;
}
-
+
public function get connected():Boolean
{
- return (connection != null && connection.connected);
+ return (connection != null && connection.connected);
}
-
+
public function readBytes(bytes:ByteArray):void
{
- recvStream.client.bytes.readBytes(bytes);
+ recvStream.client.bytes.readBytes(bytes);
}
public function writeBytes(bytes:ByteArray):void
{
- sendStream.send("dataAvailable", bytes);
+ sendStream.send("dataAvailable", bytes);
}
-
+
public function get peer():String
{
- return this.peerID;
+ return this.peerID;
}
public function set peer(peerID:String):void
{
- if (peerID == null || peerID.length == 0) {
- throw new Error("Peer ID is null/empty.")
- } else if (peerID == connection.nearID) {
- throw new Error("Peer ID cannot be the same as our ID.");
- } else if (this.peerID == peerID) {
- throw new Error("Already connected to peer " + peerID + ".");
- } else if (this.recvStream != null) {
- throw new Error("Cannot connect to a second peer.");
- }
-
- this.peerID = peerID;
-
- recvStream = new NetStream(connection, peerID);
- var client:RTMFPSocketClient = new RTMFPSocketClient();
- client.addEventListener(ProgressEvent.SOCKET_DATA, onDataAvailable, false, 0, true);
- client.addEventListener(RTMFPSocketClient.PEER_CONNECT_ACKNOWLEDGED, onPeerConnectAcknowledged, false, 0, true);
- recvStream.client = client;
- recvStream.addEventListener(NetStatusEvent.NET_STATUS, onRecvStreamEvent);
- recvStream.play(DATA);
- setTimeout(onPeerConnectTimeout, peerConnectTimeout, recvStream);
- }
-
+ if (peerID == null || peerID.length == 0) {
+ throw new Error("Peer ID is null/empty.")
+ } else if (peerID == connection.nearID) {
+ throw new Error("Peer ID cannot be the same as our ID.");
+ } else if (this.peerID == peerID) {
+ throw new Error("Already connected to peer " + peerID + ".");
+ } else if (this.recvStream != null) {
+ throw new Error("Cannot connect to a second peer.");
+ }
+
+ this.peerID = peerID;
+
+ recvStream = new NetStream(connection, peerID);
+ var client:RTMFPSocketClient = new RTMFPSocketClient();
+ client.addEventListener(ProgressEvent.SOCKET_DATA, onDataAvailable, false, 0, true);
+ client.addEventListener(RTMFPSocketClient.PEER_CONNECT_ACKNOWLEDGED, onPeerConnectAcknowledged, false, 0, true);
+ recvStream.client = client;
+ recvStream.addEventListener(NetStatusEvent.NET_STATUS, onRecvStreamEvent);
+ recvStream.play(DATA);
+ setTimeout(onPeerConnectTimeout, peerConnectTimeout, recvStream);
+ }
+
private function startPublishStream():void
{
- sendStream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS);
- sendStream.addEventListener(NetStatusEvent.NET_STATUS, onSendStreamEvent);
- var o:Object = new Object();
- o.onPeerConnect = onPeerConnect;
- sendStream.client = o;
- sendStream.publish(DATA);
+ sendStream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS);
+ sendStream.addEventListener(NetStatusEvent.NET_STATUS, onSendStreamEvent);
+ var o:Object = new Object();
+ o.onPeerConnect = onPeerConnect;
+ sendStream.client = o;
+ sendStream.publish(DATA);
}
-
+
private function fail():void
{
- clearInterval(connectionTimeout);
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAIL));
+ clearInterval(connectionTimeout);
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAIL));
}
-
+
private function onDataAvailable(event:ProgressEvent):void
{
- dispatchEvent(event);
+ dispatchEvent(event);
}
-
+
private function onIOErrorEvent(event:IOErrorEvent):void
{
- fail();
+ fail();
}
-
+
private function onNetStatusEvent(event:NetStatusEvent):void
{
- switch (event.info.code) {
- case "NetConnection.Connect.Success" :
- clearInterval(connectionTimeout);
- startPublishStream();
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS));
- break;
- case "NetStream.Connect.Success" :
- break;
- case "NetStream.Publish.BadName" :
- fail();
- break;
- case "NetStream.Connect.Closed" :
- // we've disconnected from the peer
- // can reset to accept another
- // clear the publish stream and re-publish another
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED, recvStream));
- break;
- }
- }
-
+ switch (event.info.code) {
+ case "NetConnection.Connect.Success" :
+ clearInterval(connectionTimeout);
+ startPublishStream();
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS));
+ break;
+ case "NetStream.Connect.Success" :
+ break;
+ case "NetStream.Publish.BadName" :
+ fail();
+ break;
+ case "NetStream.Connect.Closed" :
+ // we've disconnected from the peer
+ // can reset to accept another
+ // clear the publish stream and re-publish another
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED, recvStream));
+ break;
+ }
+ }
+
private function onPeerConnect(peer:NetStream):Boolean
{
- // establish a bidirectional stream with the peer
- if (peerID == null) {
- this.peer = peer.farID;
- }
-
- // disallow additional peers connecting to us
- if (peer.farID != peerID) return false;
-
- peer.send("setPeerConnectAcknowledged");
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_CONNECTED, peer));
-
- return true;
- }
-
+ // establish a bidirectional stream with the peer
+ if (peerID == null) {
+ this.peer = peer.farID;
+ }
+
+ // disallow additional peers connecting to us
+ if (peer.farID != peerID)
+ return false;
+
+ peer.send("setPeerConnectAcknowledged");
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_CONNECTED, peer));
+
+ return true;
+ }
+
private function onPeerConnectAcknowledged(event:Event):void
{
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_SUCCESS, recvStream));
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_SUCCESS, recvStream));
}
-
+
private function onPeerConnectTimeout(peer:NetStream):void
{
- if (!recvStream.client) return;
- if (!RTMFPSocketClient(recvStream.client).peerConnectAcknowledged) {
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_FAIL, recvStream));
- }
+ if (!recvStream.client) return;
+ if (!RTMFPSocketClient(recvStream.client).peerConnectAcknowledged) {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_FAIL, recvStream));
+ }
}
-
+
private function onSecurityErrorEvent(event:SecurityErrorEvent):void
{
- fail();
+ fail();
}
-
+
private function onSendStreamEvent(event:NetStatusEvent):void
{
- switch (event.info.code) {
- case ("NetStream.Publish.Start") :
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_START));
- break;
- case ("NetStream.Play.Reset") :
- case ("NetStream.Play.Start") :
- break;
- }
- }
- private function onRecvStreamEvent(event:NetStatusEvent):void
- {
- switch (event.info.code) {
- case ("NetStream.Publish.Start") :
- case ("NetStream.Play.Reset") :
- case ("NetStream.Play.Start") :
- break;
- }
- }
+ switch (event.info.code) {
+ case ("NetStream.Publish.Start") :
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_START));
+ break;
+ case ("NetStream.Play.Reset") :
+ case ("NetStream.Play.Start") :
+ break;
+ }
+ }
+ private function onRecvStreamEvent(event:NetStatusEvent):void
+ {
+ switch (event.info.code) {
+ case ("NetStream.Publish.Start") :
+ case ("NetStream.Play.Reset") :
+ case ("NetStream.Play.Start") :
+ break;
+ }
+ }
}
}
diff --git a/rtmfp/RTMFPSocketClient.as b/rtmfp/RTMFPSocketClient.as
index d9fcffa..e2f93ef 100644
--- a/rtmfp/RTMFPSocketClient.as
+++ b/rtmfp/RTMFPSocketClient.as
@@ -1,57 +1,57 @@
package rtmfp
{
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.ProgressEvent;
- import flash.utils.ByteArray;
-
- [Event(name="peerConnectAcknowledged", type="flash.events.Event")]
- public dynamic class RTMFPSocketClient extends EventDispatcher {
- public static const PEER_CONNECT_ACKNOWLEDGED:String = "peerConnectAcknowledged";
-
- private var _bytes:ByteArray;
- private var _peerID:String;
- private var _peerConnectAcknowledged:Boolean;
-
- public function RTMFPSocketClient()
- {
- super();
- _bytes = new ByteArray();
- _peerID = null;
- _peerConnectAcknowledged = false;
- }
-
- public function get bytes():ByteArray
- {
- return _bytes;
- }
-
- public function dataAvailable(bytes:ByteArray):void
- {
- this._bytes.clear();
- bytes.readBytes(this._bytes);
- dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, this._bytes.bytesAvailable, this._bytes.length));
- }
-
- public function get peerConnectAcknowledged():Boolean
- {
- return _peerConnectAcknowledged;
- }
-
- public function setPeerConnectAcknowledged():void
- {
- _peerConnectAcknowledged = true;
- dispatchEvent(new Event(PEER_CONNECT_ACKNOWLEDGED));
- }
-
- public function get peerID():String
- {
- return _peerID;
- }
-
- public function set peerID(id:String):void
- {
- _peerID = id;
- }
- }
-}
\ No newline at end of file
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.ProgressEvent;
+ import flash.utils.ByteArray;
+
+ [Event(name="peerConnectAcknowledged", type="flash.events.Event")]
+ public dynamic class RTMFPSocketClient extends EventDispatcher {
+ public static const PEER_CONNECT_ACKNOWLEDGED:String = "peerConnectAcknowledged";
+
+ private var _bytes:ByteArray;
+ private var _peerID:String;
+ private var _peerConnectAcknowledged:Boolean;
+
+ public function RTMFPSocketClient()
+ {
+ super();
+ _bytes = new ByteArray();
+ _peerID = null;
+ _peerConnectAcknowledged = false;
+ }
+
+ public function get bytes():ByteArray
+ {
+ return _bytes;
+ }
+
+ public function dataAvailable(bytes:ByteArray):void
+ {
+ this._bytes.clear();
+ bytes.readBytes(this._bytes);
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, this._bytes.bytesAvailable, this._bytes.length));
+ }
+
+ public function get peerConnectAcknowledged():Boolean
+ {
+ return _peerConnectAcknowledged;
+ }
+
+ public function setPeerConnectAcknowledged():void
+ {
+ _peerConnectAcknowledged = true;
+ dispatchEvent(new Event(PEER_CONNECT_ACKNOWLEDGED));
+ }
+
+ public function get peerID():String
+ {
+ return _peerID;
+ }
+
+ public function set peerID(id:String):void
+ {
+ _peerID = id;
+ }
+ }
+}
diff --git a/rtmfp/events/RTMFPSocketEvent.as b/rtmfp/events/RTMFPSocketEvent.as
index c5b4af1..5bc08e5 100644
--- a/rtmfp/events/RTMFPSocketEvent.as
+++ b/rtmfp/events/RTMFPSocketEvent.as
@@ -1,25 +1,24 @@
package rtmfp.events
{
- import flash.events.Event;
- import flash.net.NetStream;
+ import flash.events.Event;
+ import flash.net.NetStream;
- public class RTMFPSocketEvent extends Event
- {
- public static const CONNECT_SUCCESS:String = "connectSuccess";
- public static const CONNECT_FAIL:String = "connectFail";
- public static const PUBLISH_START:String = "publishStart";
- public static const PEER_CONNECTED:String = "peerConnected";
- public static const PEER_DISCONNECTED:String = "peerDisconnected";
- public static const PEERING_SUCCESS:String = "peeringSuccess";
- public static const PEERING_FAIL:String = "peeringFail";
-
- public var stream:NetStream;
-
- public function RTMFPSocketEvent(type:String, streamVal:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
- {
- super(type, bubbles, cancelable);
- stream = streamVal;
- }
-
- }
-}
\ No newline at end of file
+ public class RTMFPSocketEvent extends Event
+ {
+ public static const CONNECT_SUCCESS:String = "connectSuccess";
+ public static const CONNECT_FAIL:String = "connectFail";
+ public static const PUBLISH_START:String = "publishStart";
+ public static const PEER_CONNECTED:String = "peerConnected";
+ public static const PEER_DISCONNECTED:String = "peerDisconnected";
+ public static const PEERING_SUCCESS:String = "peeringSuccess";
+ public static const PEERING_FAIL:String = "peeringFail";
+
+ public var stream:NetStream;
+
+ public function RTMFPSocketEvent(type:String, streamVal:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(type, bubbles, cancelable);
+ stream = streamVal;
+ }
+ }
+}
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 328274a..d4766c4 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -11,198 +11,198 @@ package
import flash.events.SecurityErrorEvent;
import flash.utils.ByteArray;
import flash.utils.setTimeout;
-
+
import rtmfp.RTMFPSocket;
import rtmfp.events.RTMFPSocketEvent;
import Utils;
-
- public class rtmfpcat extends Sprite {
-
- /* Nate's facilitator -- also serving a crossdomain policy */
- private const DEFAULT_FAC_ADDR:Object = {
- host: "128.12.179.80",
- port: 9002
- };
-
- private const DEFAULT_TOR_CLIENT_ADDR:Object = {
- host: "127.0.0.1",
- port: 3333
- };
-
- /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
- crossdomain policy. */
- private const DEFAULT_TOR_PROXY_ADDR:Object = {
- host: "173.255.221.44",
- port: 9001
- };
-
- // Milliseconds.
- private const FACILITATOR_POLL_INTERVAL:int = 10000;
-
- private var output_text:TextField;
-
- private var s_f:Socket;
- private var s_r:RTMFPSocket;
- private var s_t:Socket;
-
- private var fac_addr:Object;
- private var tor_addr:Object;
-
- private var proxy_mode:Boolean;
-
- public function rtmfpcat()
- {
- output_text = new TextField();
- output_text.width = 400;
- output_text.height = 300;
- output_text.background = true;
- output_text.backgroundColor = 0x001f0f;
- output_text.textColor = 0x44CC44;
- addChild(output_text);
-
- puts("Starting.");
-
- this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
- }
-
- private function puts(s:String):void
- {
- output_text.appendText(s + "\n");
- output_text.scrollV = output_text.maxScrollV;
- }
-
- private function onLoaderInfoComplete(e:Event):void
- {
- var fac_spec:String;
- var tor_spec:String;
-
- puts("Parameters loaded.");
-
- proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
-
- fac_spec = this.loaderInfo.parameters["facilitator"];
- if (!fac_spec) {
- puts("No \"facilitator\" specification provided...using default.");
- fac_addr = DEFAULT_FAC_ADDR;
- } else {
- puts("Facilitator spec: \"" + fac_spec + "\"");
- fac_addr = Utils.parseAddrSpec(fac_spec);
+
+ public class rtmfpcat extends Sprite
+ {
+ /* Nate's facilitator -- also serving a crossdomain policy */
+ private const DEFAULT_FAC_ADDR:Object = {
+ host: "128.12.179.80",
+ port: 9002
+ };
+
+ private const DEFAULT_TOR_CLIENT_ADDR:Object = {
+ host: "127.0.0.1",
+ port: 3333
+ };
+
+ /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
+ crossdomain policy. */
+ private const DEFAULT_TOR_PROXY_ADDR:Object = {
+ host: "173.255.221.44",
+ port: 9001
+ };
+
+ // Milliseconds.
+ private const FACILITATOR_POLL_INTERVAL:int = 10000;
+
+ private var output_text:TextField;
+
+ private var s_f:Socket;
+ private var s_r:RTMFPSocket;
+ private var s_t:Socket;
+
+ private var fac_addr:Object;
+ private var tor_addr:Object;
+
+ private var proxy_mode:Boolean;
+
+ public function rtmfpcat()
+ {
+ output_text = new TextField();
+ output_text.width = 400;
+ output_text.height = 300;
+ output_text.background = true;
+ output_text.backgroundColor = 0x001f0f;
+ output_text.textColor = 0x44CC44;
+ addChild(output_text);
+
+ puts("Starting.");
+
+ this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
}
-
- if (!fac_addr) {
- puts("Error: Facilitator spec must be in the form \"host:port\".");
- return;
+
+ private function puts(s:String):void
+ {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
}
-
- tor_spec = this.loaderInfo.parameters["tor"];
- if (!tor_spec) {
- puts("No Tor specification provided...using default.");
- if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
- else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
- } else {
- puts("Tor spec: \"" + tor_spec + "\"")
- tor_addr = Utils.parseAddrSpec(tor_spec);
+
+ private function onLoaderInfoComplete(e:Event):void
+ {
+ var fac_spec:String;
+ var tor_spec:String;
+
+ puts("Parameters loaded.");
+
+ proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
+
+ fac_spec = this.loaderInfo.parameters["facilitator"];
+ if (!fac_spec) {
+ puts("No \"facilitator\" specification provided...using default.");
+ fac_addr = DEFAULT_FAC_ADDR;
+ } else {
+ puts("Facilitator spec: \"" + fac_spec + "\"");
+ fac_addr = Utils.parseAddrSpec(fac_spec);
+ }
+
+ if (!fac_addr) {
+ puts("Error: Facilitator spec must be in the form \"host:port\".");
+ return;
+ }
+
+ tor_spec = this.loaderInfo.parameters["tor"];
+ if (!tor_spec) {
+ puts("No Tor specification provided...using default.");
+ if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
+ else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
+ } else {
+ puts("Tor spec: \"" + tor_spec + "\"")
+ tor_addr = Utils.parseAddrSpec(tor_spec);
+ }
+
+ if (!tor_addr) {
+ puts("Error: Tor spec must be in the form \"host:port\".");
+ return;
+ }
+
+ establishRTMFPConnection();
}
- if (!tor_addr) {
- puts("Error: Tor spec must be in the form \"host:port\".");
- return;
+ private function establishRTMFPConnection():void
+ {
+ s_r = new RTMFPSocket();
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
+ puts("Cirrus: connected with id " + s_r.id + ".");
+ establishFacilitatorConnection();
+ });
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
+ puts("Error: failed to connect to Cirrus.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
+ puts("Publishing started.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
+ puts("Peer connected.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
+ puts("Peer disconnected.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
+ puts("Peering success.");
+ establishTorConnection();
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
+ puts("Peering fail.");
+ });
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var bytes:ByteArray = new ByteArray();
+ s_r.readBytes(bytes);
+ puts("RTMFP: read " + bytes.length + " bytes.");
+ s_t.writeBytes(bytes);
+ });
+
+ s_r.connect();
+ }
+
+ private function establishTorConnection():void
+ {
+ s_t = new Socket();
+ s_t.addEventListener(Event.CONNECT, function (e:Event):void {
+ puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
+ });
+ s_t.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("Tor: closed connection.");
+ });
+ s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ puts("Tor: I/O error: " + e.text + ".");
+ });
+ s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var bytes:ByteArray = new ByteArray();
+ s_t.readBytes(bytes, 0, e.bytesLoaded);
+ puts("Tor: read " + bytes.length + " bytes.");
+ s_r.writeBytes(bytes);
+ });
+ s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ puts("Tor: security error: " + e.text + ".");
+ });
+
+ s_t.connect(tor_addr.host, tor_addr.port);
}
- establishRTMFPConnection();
- }
-
- private function establishRTMFPConnection():void
- {
- s_r = new RTMFPSocket();
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
- puts("Cirrus: connected with id " + s_r.id + ".");
- establishFacilitatorConnection();
- });
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
- puts("Error: failed to connect to Cirrus.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
- puts("Publishing started.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
- puts("Peer connected.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
- puts("Peer disconnected.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
- puts("Peering success.");
- establishTorConnection();
- });
- s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
- puts("Peering fail.");
- });
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_r.readBytes(bytes);
- puts("RTMFP: read " + bytes.length + " bytes.");
- s_t.writeBytes(bytes);
- });
-
- s_r.connect();
- }
-
- private function establishTorConnection():void
- {
- s_t = new Socket();
- s_t.addEventListener(Event.CONNECT, function (e:Event):void {
- puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
- });
- s_t.addEventListener(Event.CLOSE, function (e:Event):void {
- puts("Tor: closed connection.");
- });
- s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- puts("Tor: I/O error: " + e.text + ".");
- });
- s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_t.readBytes(bytes, 0, e.bytesLoaded);
- puts("Tor: read " + bytes.length + " bytes.");
- s_r.writeBytes(bytes);
- });
- s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- puts("Tor: security error: " + e.text + ".");
- });
-
- s_t.connect(tor_addr.host, tor_addr.port);
- }
-
- private function establishFacilitatorConnection():void
- {
- s_f = new Socket();
- s_f.addEventListener(Event.CONNECT, function (e:Event):void {
- puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
- if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
- else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
- });
- s_f.addEventListener(Event.CLOSE, function (e:Event):void {
- puts("Facilitator: connection closed.");
- if (proxy_mode) {
- setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
- }
- });
- s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- puts("Facilitator: I/O error: " + e.text + ".");
- });
- s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
- puts("Facilitator: got \"" + clientID + "\"");
- if (clientID != "Registration list empty") {
- puts("Connecting to " + clientID + ".");
- s_r.peer = clientID;
- }
- });
- s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- puts("Facilitator: security error: " + e.text + ".");
- });
-
- s_f.connect(fac_addr.host, fac_addr.port);
- }
- }
-}
\ No newline at end of file
+ private function establishFacilitatorConnection():void
+ {
+ s_f = new Socket();
+ s_f.addEventListener(Event.CONNECT, function (e:Event):void {
+ puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
+ if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
+ else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
+ });
+ s_f.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("Facilitator: connection closed.");
+ if (proxy_mode) {
+ setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
+ }
+ });
+ s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ puts("Facilitator: I/O error: " + e.text + ".");
+ });
+ s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
+ puts("Facilitator: got \"" + clientID + "\"");
+ if (clientID != "Registration list empty") {
+ puts("Connecting to " + clientID + ".");
+ s_r.peer = clientID;
+ }
+ });
+ s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ puts("Facilitator: security error: " + e.text + ".");
+ });
+
+ s_f.connect(fac_addr.host, fac_addr.port);
+ }
+ }
+}
1
0

12 Jun '11
commit 9f3a2b7d607edbbd328e8116b666d442fb2743d0
Author: David Fifield <david(a)bamsoftware.com>
Date: Tue May 24 23:48:17 2011 -0700
Make rtmfpcat more uniform with swfcat.
---
Utils.as | 25 -------------
rtmfpcat.as | 112 ++++++++++++++++++++++++++++++++++++----------------------
2 files changed, 69 insertions(+), 68 deletions(-)
diff --git a/Utils.as b/Utils.as
deleted file mode 100644
index 48f9a62..0000000
--- a/Utils.as
+++ /dev/null
@@ -1,25 +0,0 @@
-package
-{
-
- public class Utils {
-
- /* Parse an address in the form "host:port". Returns an Object with
- keys "host" (String) and "port" (int). Returns null on error. */
- public static function parseAddrSpec(spec:String):Object
- {
- var parts:Array;
- var addr:Object;
-
- parts = spec.split(":", 2);
- if (parts.length != 2 || !parseInt(parts[1]))
- return null;
- addr = {}
- addr.host = parts[0];
- addr.port = parseInt(parts[1]);
-
- return addr;
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/rtmfpcat.as b/rtmfpcat.as
index d4766c4..49fcdeb 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -1,7 +1,10 @@
package
{
import flash.display.Sprite;
+ import flash.display.StageAlign;
+ import flash.display.StageScaleMode;
import flash.text.TextField;
+ import flash.text.TextFormat;
import flash.net.Socket;
import flash.events.Event;
import flash.events.EventDispatcher;
@@ -14,64 +17,68 @@ package
import rtmfp.RTMFPSocket;
import rtmfp.events.RTMFPSocketEvent;
- import Utils;
public class rtmfpcat extends Sprite
{
+ /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
+ crossdomain policy. */
+ private const DEFAULT_TOR_PROXY_ADDR:Object = {
+ host: "173.255.221.44",
+ port: 9001
+ };
/* Nate's facilitator -- also serving a crossdomain policy */
- private const DEFAULT_FAC_ADDR:Object = {
+ private const DEFAULT_FACILITATOR_ADDR:Object = {
host: "128.12.179.80",
port: 9002
};
-
private const DEFAULT_TOR_CLIENT_ADDR:Object = {
host: "127.0.0.1",
port: 3333
};
- /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
- crossdomain policy. */
- private const DEFAULT_TOR_PROXY_ADDR:Object = {
- host: "173.255.221.44",
- port: 9001
- };
-
// Milliseconds.
private const FACILITATOR_POLL_INTERVAL:int = 10000;
- private var output_text:TextField;
-
+ // Socket to facilitator.
private var s_f:Socket;
+ // Socket to RTMFP peer (flash proxy).
private var s_r:RTMFPSocket;
+ // Socket to local Tor client.
private var s_t:Socket;
+ /* TextField for debug output. */
+ private var output_text:TextField;
+
private var fac_addr:Object;
private var tor_addr:Object;
private var proxy_mode:Boolean;
+ public function puts(s:String):void
+ {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
+ }
+
public function rtmfpcat()
{
+ // Absolute positioning.
+ stage.scaleMode = StageScaleMode.NO_SCALE;
+ stage.align = StageAlign.TOP_LEFT;
+
output_text = new TextField();
- output_text.width = 400;
- output_text.height = 300;
+ output_text.width = stage.stageWidth;
+ output_text.height = stage.stageHeight;
output_text.background = true;
output_text.backgroundColor = 0x001f0f;
- output_text.textColor = 0x44CC44;
- addChild(output_text);
+ output_text.textColor = 0x44cc44;
puts("Starting.");
-
- this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
- }
-
- private function puts(s:String):void
- {
- output_text.appendText(s + "\n");
- output_text.scrollV = output_text.maxScrollV;
+ // Wait until the query string parameters are loaded.
+ this.loaderInfo.addEventListener(Event.COMPLETE, loaderinfo_complete);
}
- private function onLoaderInfoComplete(e:Event):void
+ private function loaderinfo_complete(e:Event):void
{
var fac_spec:String;
var tor_spec:String;
@@ -79,36 +86,38 @@ package
puts("Parameters loaded.");
proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
+ addChild(output_text);
fac_spec = this.loaderInfo.parameters["facilitator"];
- if (!fac_spec) {
- puts("No \"facilitator\" specification provided...using default.");
- fac_addr = DEFAULT_FAC_ADDR;
- } else {
+ if (fac_spec) {
puts("Facilitator spec: \"" + fac_spec + "\"");
- fac_addr = Utils.parseAddrSpec(fac_spec);
- }
-
- if (!fac_addr) {
+ fac_addr = parse_addr_spec(fac_spec);
+ if (!fac_addr) {
puts("Error: Facilitator spec must be in the form \"host:port\".");
return;
+ }
+ } else {
+ fac_addr = DEFAULT_FACILITATOR_ADDR;
}
tor_spec = this.loaderInfo.parameters["tor"];
- if (!tor_spec) {
- puts("No Tor specification provided...using default.");
- if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
- else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
+ if (tor_spec) {
+ puts("Tor spec: \"" + tor_spec + "\"");
+ tor_addr = parse_addr_spec(tor_spec);
+ if (!tor_addr) {
+ puts("Error: Tor spec must be in the form \"host:port\".");
+ return;
+ }
} else {
- puts("Tor spec: \"" + tor_spec + "\"")
- tor_addr = Utils.parseAddrSpec(tor_spec);
+ tor_addr = DEFAULT_TOR_CLIENT_ADDR;
}
- if (!tor_addr) {
- puts("Error: Tor spec must be in the form \"host:port\".");
- return;
- }
+ main();
+ }
+ /* The main logic begins here, after start-up issues are taken care of. */
+ private function main():void
+ {
establishRTMFPConnection();
}
@@ -204,5 +213,22 @@ package
s_f.connect(fac_addr.host, fac_addr.port);
}
+
+ /* Parse an address in the form "host:port". Returns an Object with
+ keys "host" (String) and "port" (int). Returns null on error. */
+ private static function parse_addr_spec(spec:String):Object
+ {
+ var parts:Array;
+ var addr:Object;
+
+ parts = spec.split(":", 2);
+ if (parts.length != 2 || !parseInt(parts[1]))
+ return null;
+ addr = {}
+ addr.host = parts[0];
+ addr.port = parseInt(parts[1]);
+
+ return addr;
+ }
}
}
1
0
commit d5c1258762ff34b369f9fb6cef651122c3436cdc
Author: David Fifield <david(a)bamsoftware.com>
Date: Tue May 24 22:55:34 2011 -0700
Flatten the com/rtmfp hierarchy.
So that parallel files in the master branch are in the same place in
this branch.
---
Makefile | 2 +-
README | 88 ++++---
Utils.as | 25 ++
com/rtmfpcat/Makefile | 11 -
com/rtmfpcat/README | 118 ---------
com/rtmfpcat/Utils.as | 25 --
com/rtmfpcat/connector.py | 326 -------------------------
com/rtmfpcat/facilitator.py | 146 -----------
com/rtmfpcat/rtmfp/RTMFPSocket.as | 231 -----------------
com/rtmfpcat/rtmfp/RTMFPSocketClient.as | 57 -----
com/rtmfpcat/rtmfp/events/RTMFPSocketEvent.as | 25 --
com/rtmfpcat/rtmfpcat.as | 208 ----------------
connector.py | 4 +-
facilitator.py | 11 +-
rtmfp/RTMFPSocket.as | 231 +++++++++++++++++
rtmfp/RTMFPSocketClient.as | 57 +++++
rtmfp/events/RTMFPSocketEvent.as | 25 ++
rtmfpcat.as | 208 ++++++++++++++++
swfcat.as | 82 +-----
19 files changed, 622 insertions(+), 1258 deletions(-)
diff --git a/Makefile b/Makefile
index 5390327..3595385 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
MXMLC ?= mxmlc
-TARGETS = swfcat.swf com/rtmfpcat/rtmfpcat.swf
+TARGETS = rtmfpcat.swf
all: $(TARGETS)
diff --git a/README b/README
index 755ba01..17fadf5 100644
--- a/README
+++ b/README
@@ -5,12 +5,24 @@ Adobe Flash proxy running on another computer. The Flash proxy can be
run just by opening a web page in a computer that has Flash Player
installed.
+This RTMFP version leverages the NAT-punching capabilities of Adobe's
+Cirrus server, making it possible for clients behind a NAT to still
+get access to Tor. The big operational difference between this version
+and the swfcat version is that now the client must maintain a rtmfpcat
+running in client mode open in his/her browser. The client's rtmfpcat
+talks to the rtmfpcat proxy running on another computer (location uncertain)
+via the UDP-based RTMFP to funnel data to a Tor relay/bridge.
+
There are five main parts. Our terminology for each part is in quotes.
1. The Tor "client," running on someone's localhost.
-2. A "connector," which waits for connections from the Flash proxy and
+2. A "connector," which waits for connections from the client's rtmfpcat and
the Tor client, and joins them together.
3. A Flash "proxy," running in someone's web browser. This piece is
- called swfcat because it is like a netcat implemented in Flash.
+ called rtmfpcat (totally ripped off of swfcat) because it is like a
+ netcat implemented in Flash. The rtmfpcat exists on both the local
+ and remote ends since it's the easiest way to take advantage of RTMFP.
+ We could get rid of the client-side rtmfpcat by making the connector
+ speak RTMFP, but that's too much work for now.
4. A "facilitator," a pseudo-HTTP server that keeps a list of clients
that want a connection, and hands them out to proxies.
5. A Tor "relay," which is just a normal Tor relay except that its host
@@ -18,9 +30,7 @@ There are five main parts. Our terminology for each part is in quotes.
== Quick start
-A demonstration page that doesn't require building anything is here:
-
-http://www.stanford.edu/~dcf/tor/
+Will put up a demo page soon.
=== Building
@@ -29,34 +39,40 @@ Download the (free software) Flex SDK.
Put its bin directory in your PATH. The important executable is mxmlc.
To build, run
$ make
-Copy the resulting swfcat.swf file to a web server.
+Copy the resulting rtmfpcat.swf file to a web server.
On the computer that will be the facilitator, run
- sudo ./crossdomaind.py
- ./facilitator.py
+ sudo ./crossdomaind.py
+ ./facilitator.py
crossdomaind.py needs to be run on any server that will accept
connections from a Flash proxy. It serves a chunk of data on port 843.
-The facilitator runs on port 9002 by default.
+The facilitator runs on port 9002 by default. Note that this is a different
+facilitator script than the swfcat one, since this facilitator needs to
+deal with Cirrus client IDs instead of ip:port tuples.
The client needs to be running a version of Tor that supports the
Socks4Proxy configuration. This means version 0.2.2.1-alpha or
later--not the current stable release.
On the client, run
- ./connector.py -f <FACILITATOR_IP>
-Replace <FACILITATOR_IP> with the IP address of the facilitator. (If you
-are running the facilitator locally, be sure to use an external IP
-address, not 127.0.0.1.) The connector informs the facilitator that it
-wants a connection, then listens on 0.0.0.0:9000 and 127.0.0.1:9001. The
-Flash proxy will connect on port 9000 and the local Tor will connect on
-9001.
-
-In a browser somewhere, open swfcat.swf and pass a parameter telling it
-the facilitator to use, for example
- http://www.example.com/swfcat.swf?facilitator=<FACILITATOR_IP>:9002&debug=1
-The facilitator will return the client address that was registered by
-connector.py, and the Flash proxy will open a connection to a hardcoded
-Tor relay and the given client.
+ ./connector.py
+This is a modified form of the swfcat connector.py that has different
+defaults, equivalent to passing 127.0.0.1:9001 for [LOCAL][:PORT] and
+127.0.0.1:3333 [REMOTE][:PORT] to the swfcat connector.
+
+Also on the client, open up the browser to rtmfpcat.swf. Passing no
+arguments should give you good defaults (expects the facilitator running
+on Nate's server). rtmfpcat will connect to the Cirrus server to
+obtain a client ID which it then registers with the facilitator.
+
+In a browser somewhere, open rtmfpcat.swf and pass the "?proxy=true" query
+string, telling it to operate in proxy mode.
+ http://www.example.com/rtmfpcat.swf?proxy=true
+This rtmfpcat will also connect to the Cirrus server to obtain a client ID,
+and then it will ping the facilitator to check if there are any registered
+client IDs. If there is one, it will open a RTMFP connection (coordinated
+by the Cirrus server) to the client and an additional connection to a
+hardcoded Tor relay (David's bridge, nicknamed eRYaZuvY02FpExln).
Back on the client, start Tor with the following configuration:
UseBridges 1
@@ -68,8 +84,8 @@ If you see messages like
[notice] no known bridge descriptors running yet; stalling
try deleting the files in ~/.tor or /var/lib/tor.
-You will be able to see byte counts flowing in the browser displaying
-swfcat.swf, and eventually be able to build a circuit.
+You will be able to see byte counts flowing in both browsers displaying
+rtmfpcat.swf (client and proxy), and eventually be able to build a circuit.
== Rationale
@@ -81,22 +97,26 @@ changing pool of addresses.
== Design notes
-The Tor relay address is hardcoded in swfcat.as. It could be any relay,
+The Tor relay address is hardcoded in rtmfpcat.as. It could be any relay,
with the caveat that the server also has to serve a crossdomain policy.
-The Tor client needs to be able to listen for an incoming connection,
-which generally means not being behind NAT.
-
-Clients register with the facilitator by sending an HTTP-like message:
+Client rtmfpcats register with the facilitator by sending an HTTP-like message:
POST / HTTP/1.0\r\n
\r\n
- client=:9000
+ client=<CIRRUS-CLIENT-ID>
+
+The <CIRRUS-CLIENT-ID> is returned by Adobe's developer Cirrus server
+as soon as the rtfmpcat can connect to it. Each rtmfpcat needs to connect
+to a server like this to get one of these client IDs, since the Cirrus
+server uses these to coordinate RTMFP connections (including NAT punching).
+The need to communicate with a Cirrus server in addition to a facilitator is
+one of the major weaknesses of this design.
-The Flash proxy also gets a client address using something like HTTP:
+The proxy rtmfpcat gets a client id using something like HTTP:
GET / HTTP/1.0\r\n
\r\n
-The server sends back an address specification (no HTTP header):
- 192.168.0.102:8888
+The server sends back an id specification (no HTTP header):
+ 51ae8ed56c3705e4ad3755cdd3328c27720984778bfff71d9ec9f2647331d39b
== ActionScript programming
diff --git a/Utils.as b/Utils.as
new file mode 100644
index 0000000..48f9a62
--- /dev/null
+++ b/Utils.as
@@ -0,0 +1,25 @@
+package
+{
+
+ public class Utils {
+
+ /* Parse an address in the form "host:port". Returns an Object with
+ keys "host" (String) and "port" (int). Returns null on error. */
+ public static function parseAddrSpec(spec:String):Object
+ {
+ var parts:Array;
+ var addr:Object;
+
+ parts = spec.split(":", 2);
+ if (parts.length != 2 || !parseInt(parts[1]))
+ return null;
+ addr = {}
+ addr.host = parts[0];
+ addr.port = parseInt(parts[1]);
+
+ return addr;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/com/rtmfpcat/Makefile b/com/rtmfpcat/Makefile
deleted file mode 100644
index fbcfc20..0000000
--- a/com/rtmfpcat/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-MXMLC ?= mxmlc
-
-TARGETS = rtmfpcat.swf
-
-all: $(TARGETS)
-
-%.swf: %.as
- $(MXMLC) -output $@ $^
-
-clean:
- rm -f $(TARGETS)
diff --git a/com/rtmfpcat/README b/com/rtmfpcat/README
deleted file mode 100644
index 0432a63..0000000
--- a/com/rtmfpcat/README
+++ /dev/null
@@ -1,118 +0,0 @@
-== Introduction
-
-This is a set of tools that make it possible to connect Tor through an
-Adobe Flash proxy running on another computer. The Flash proxy can be
-run just by opening a web page in a computer that has Flash Player
-installed.
-
-This RTMFP version leverages the NAT-punching capabilities of Adobe's
-Cirrus server, making it possible for clients behind a NAT to still
-get access to Tor. The big operational difference between this version
-and the swfcat version is that now the client must maintain a rtmfpcat
-running in client mode open in his/her browser. The client's rtmfpcat
-talks to the rtmfpcat proxy running on another computer (location uncertain)
-via the UDP-based RTMFP to funnel data to a Tor relay/bridge.
-
-There are five main parts. Our terminology for each part is in quotes.
-1. The Tor "client," running on someone's localhost.
-2. A "connector," which waits for connections from the client's rtmfpcat and
- the Tor client, and joins them together.
-3. A Flash "proxy," running in someone's web browser. This piece is
- called rtmfpcat (totally ripped off of swfcat) because it is like a
- netcat implemented in Flash. The rtmfpcat exists on both the local
- and remote ends since it's the easiest way to take advantage of RTMFP.
- We could get rid of the client-side rtmfpcat by making the connector
- speak RTMFP, but that's too much work for now.
-4. A "facilitator," a pseudo-HTTP server that keeps a list of clients
- that want a connection, and hands them out to proxies.
-5. A Tor "relay," which is just a normal Tor relay except that its host
- must also serve a Flash crossdomain policy.
-
-== Quick start
-
-Will put up a demo page soon.
-
-=== Building
-
-Download the (free software) Flex SDK.
- http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK
-Put its bin directory in your PATH. The important executable is mxmlc.
-To build, run
- $ make
-Copy the resulting rtmfpcat.swf file to a web server.
-
-On the computer that will be the facilitator, run
- sudo ./crossdomaind.py
- ./facilitator.py
-crossdomaind.py needs to be run on any server that will accept
-connections from a Flash proxy. It serves a chunk of data on port 843.
-The facilitator runs on port 9002 by default. Note that this is a different
-facilitator script than the swfcat one, since this facilitator needs to
-deal with Cirrus client IDs instead of ip:port tuples.
-
-On the client, run
- ./connector.py
-This is a modified form of the swfcat connector.py that has different
-defaults, equivalent to passing 127.0.0.1:9001 for [LOCAL][:PORT] and
-127.0.0.1:3333 [REMOTE][:PORT] to the swfcat connector.
-
-Also on the client, open up the browser to rtmfpcat.swf. Passing no
-arguments should give you good defaults (expects the facilitator running
-on Nate's server). rtmfpcat will connect to the Cirrus server to
-obtain a client ID which it then registers with the facilitator.
-
-In a browser somewhere, open rtmfpcat.swf and pass the "?proxy=true" query
-string, telling it to operate in proxy mode.
- http://www.example.com/rtmfpcat.swf?proxy=true
-This rtmfpcat will also connect to the Cirrus server to obtain a client ID,
-and then it will ping the facilitator to check if there are any registered
-client IDs. If there is one, it will open a RTMFP connection (coordinated
-by the Cirrus server) to the client and an additional connection to a
-hardcoded Tor relay (David's bridge, nicknamed eRYaZuvY02FpExln).
-
-Back on the client, start Tor with the following configuration:
- UseBridges 1
- Bridge 127.0.0.1:9001
- Socks4Proxy 127.0.0.1:9001
-
-You will be able to see byte counts flowing in both browsers displaying
-rtmfpcat.swf (client and proxy), and eventually be able to build a circuit.
-
-== Rationale
-
-The purpose of this project is to create many, generally ephemeral
-bridge IP addresses, with the goal of outpacing a censor's ability to
-block them. Rather than increasing the number of bridges at static
-addresses, we aim to make existing bridges reachable by a larger and
-changing pool of addresses.
-
-== Design notes
-
-The Tor relay address is hardcoded in rtmfpcat.as. It could be any relay,
-with the caveat that the server also has to serve a crossdomain policy.
-
-Client rtmfpcats register with the facilitator by sending an HTTP-like message:
- POST / HTTP/1.0\r\n
- \r\n
- client=<CIRRUS-CLIENT-ID>
-
-The <CIRRUS-CLIENT-ID> is returned by Adobe's developer Cirrus server
-as soon as the rtfmpcat can connect to it. Each rtmfpcat needs to connect
-to a server like this to get one of these client IDs, since the Cirrus
-server uses these to coordinate RTMFP connections (including NAT punching).
-The need to communicate with a Cirrus server in addition to a facilitator is
-one of the major weaknesses of this design.
-
-The proxy rtmfpcat gets a client id using something like HTTP:
- GET / HTTP/1.0\r\n
- \r\n
-The server sends back an id specification (no HTTP header):
- 51ae8ed56c3705e4ad3755cdd3328c27720984778bfff71d9ec9f2647331d39b
-
-== ActionScript programming
-
-A good tutorial on ActionScript programming with the Flex tools, with
-sample code:
-
-http://www.senocular.com/flash/tutorials/as3withmxmlc/
-http://www.senocular.com/flash/tutorials/as3withmxmlc/AS3Flex2b3StarterFiles.zip
diff --git a/com/rtmfpcat/Utils.as b/com/rtmfpcat/Utils.as
deleted file mode 100644
index 48f9a62..0000000
--- a/com/rtmfpcat/Utils.as
+++ /dev/null
@@ -1,25 +0,0 @@
-package
-{
-
- public class Utils {
-
- /* Parse an address in the form "host:port". Returns an Object with
- keys "host" (String) and "port" (int). Returns null on error. */
- public static function parseAddrSpec(spec:String):Object
- {
- var parts:Array;
- var addr:Object;
-
- parts = spec.split(":", 2);
- if (parts.length != 2 || !parseInt(parts[1]))
- return null;
- addr = {}
- addr.host = parts[0];
- addr.port = parseInt(parts[1]);
-
- return addr;
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/com/rtmfpcat/connector.py b/com/rtmfpcat/connector.py
deleted file mode 100755
index 63bbc5c..0000000
--- a/com/rtmfpcat/connector.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/env python
-
-import getopt
-import httplib
-import re
-import select
-import socket
-import struct
-import sys
-import time
-import urllib
-import xml.sax.saxutils
-
-DEFAULT_REMOTE_ADDRESS = "127.0.0.1"
-DEFAULT_REMOTE_PORT = 3333
-DEFAULT_LOCAL_ADDRESS = "127.0.0.1"
-DEFAULT_LOCAL_PORT = 9001
-DEFAULT_FACILITATOR_PORT = 9002
-
-def usage(f = sys.stdout):
- print >> f, """\
-Usage: %(progname)s -f FACILITATOR[:PORT] [LOCAL][:PORT] [REMOTE][:PORT]
-Wait for connections on a local and a remote port. When any pair of connections
-exists, data is ferried between them until one side is closed. By default
-LOCAL is "%(local)s" and REMOTE is "%(remote)s".
-
-The local connection acts as a SOCKS4a proxy, but the host and port in the SOCKS
-request are ignored and the local connection is always joined to a remote
-connection.
-
-If the -f option is given, then the REMOTE address is advertised to the given
-FACILITATOR.
- -f, --facilitator=HOST[:PORT] advertise willingness to receive connections to
- HOST:PORT. By default PORT is %(fac_port)d.
- -h, --help show this help.\
-""" % {
- "progname": sys.argv[0],
- "local": format_addr((DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)),
- "remote": format_addr((DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)),
- "fac_port": DEFAULT_FACILITATOR_PORT,
-}
-
-def parse_addr_spec(spec, defhost = None, defport = None):
- host = None
- port = None
- m = None
- # IPv6 syntax.
- if not m:
- m = re.match(r'^\[(.+)\]:(\d+)$', spec)
- if m:
- host, port = m.groups()
- af = socket.AF_INET6
- if not m:
- m = re.match(r'^\[(.+)\]:?$', spec)
- if m:
- host, = m.groups()
- af = socket.AF_INET6
- # IPv4 syntax.
- if not m:
- m = re.match(r'^(.+):(\d+)$', spec)
- if m:
- host, port = m.groups()
- af = socket.AF_INET
- if not m:
- m = re.match(r'^:?(\d+)$', spec)
- if m:
- port, = m.groups()
- af = 0
- if not m:
- host = spec
- af = 0
- host = host or defhost
- port = port or defport
- if not (host and port):
- raise ValueError("Bad address specification \"%s\"" % spec)
- return host, int(port)
-
-def format_addr(addr):
- host, port = addr
- if not host:
- return u":%d" % port
- # Numeric IPv6 address?
- try:
- addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
- af = addrs[0][0]
- except socket.gaierror, e:
- af = 0
- if af == socket.AF_INET6:
- return u"[%s]:%d" % (host, port)
- else:
- return u"%s:%d" % (host, port)
-
-facilitator_addr = None
-
-opts, args = getopt.gnu_getopt(sys.argv[1:], "f:h", ["facilitator", "help"])
-for o, a in opts:
- if o == "-f" or o == "--facilitator":
- facilitator_addr = parse_addr_spec(a, None, DEFAULT_FACILITATOR_PORT)
- elif o == "-h" or o == "--help":
- usage()
- sys.exit()
-
-if len(args) == 0:
- local_addr = (DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
- remote_addr = (DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
-elif len(args) == 1:
- local_addr = parse_addr_spec(args[0], DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
- remote_addr = (DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
-elif len(args) == 2:
- local_addr = parse_addr_spec(args[0], DEFAULT_LOCAL_ADDRESS, DEFAULT_LOCAL_PORT)
- remote_addr = parse_addr_spec(args[1], DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
-else:
- usage(sys.stderr)
- sys.exit(1)
-
-
-class RemotePending(object):
- """A class encapsulating a socket and a time of connection."""
- def __init__(self, fd):
- self.fd = fd
- self.birthday = time.time()
-
- def fileno(self):
- return self.fd.fileno()
-
- def is_expired(self, timeout):
- return time.time() - self.birthday > timeout
-
-def listen_socket(addr):
- """Return a nonblocking socket listening on the given address."""
- addrinfo = socket.getaddrinfo(addr[0], addr[1], 0, socket.SOCK_STREAM, socket.IPPROTO_TCP)[0]
- s = socket.socket(addrinfo[0], addrinfo[1], addrinfo[2])
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.bind(addr)
- s.listen(10)
- s.setblocking(0)
- return s
-
-# How long to wait for a crossdomain policy request before deciding that this is
-# a normal socket.
-CROSSDOMAIN_TIMEOUT = 2.0
-
-# Local socket, accepting SOCKS requests from localhost
-local_s = listen_socket(local_addr)
-# Remote socket, accepting both crossdomain policy requests and remote proxy
-# connections.
-remote_s = listen_socket(remote_addr)
-
-# Sockets that may be crossdomain policy requests or may be normal remote
-# connections.
-crossdomain_pending = []
-# Remote connection sockets.
-remotes = []
-# New local sockets waiting to finish their SOCKS negotiation.
-socks_pending = []
-# Local Tor sockets, after SOCKS negotiation.
-locals = []
-
-# Bidirectional mapping between local sockets and remote sockets.
-local_for = {}
-remote_for = {}
-
-
-def handle_policy_request(fd):
- print "handle_policy_request"
- addr = fd.getpeername()
- data = fd.recv(100)
- if data == "<policy-file-request/>\0":
- print "Sending crossdomain policy to %s." % format_addr(addr)
- fd.sendall("""
-<cross-domain-policy>
-<allow-access-from domain="*" to-ports="%s"/>
-</cross-domain-policy>
-\0""" % xml.sax.saxutils.escape(str(remote_addr[1])))
- elif data == "":
- print "No data from %s." % format_addr(addr)
- else:
- print "Unexpected data from %s." % format_addr(addr)
-
-def grab_string(s, pos):
- """Grab a NUL-terminated string from the given string, starting at the given
- offset. Return (pos, str) tuple, or (pos, None) on error."""
- i = pos
- while i < len(s):
- if s[i] == '\0':
- return (i + 1, s[pos:i])
- i += 1
- return pos, None
-
-def parse_socks_request(data):
- try:
- ver, cmd, dport, o1, o2, o3, o4 = struct.unpack(">BBHBBBB", data[:8])
- except struct.error:
- print "Couldn't unpack SOCKS4 header."
- return None
- if ver != 4:
- print "SOCKS header has wrong version (%d)." % ver
- return None
- if cmd != 1:
- print "SOCKS header had wrong command (%d)." % cmd
- return None
- pos, userid = grab_string(data, 8)
- if userid is None:
- print "Couldn't read userid from SOCKS header."
- return None
- if o1 == 0 and o2 == 0 and o3 == 0 and o4 != 0:
- pos, dest = grab_string(data, pos)
- if dest is None:
- print "Couldn't read destination from SOCKS4a header."
- return None
- else:
- dest = "%d.%d.%d.%d" % (o1, o2, o3, o4)
- return dest, dport
-
-def handle_socks_request(fd):
- print "handle_socks_request"
- addr = fd.getpeername()
- data = fd.recv(100)
- dest_addr = parse_socks_request(data)
- if dest_addr is None:
- # Error reply.
- fd.sendall(struct.pack(">BBHBBBB", 0, 91, 0, 0, 0, 0, 0))
- return False
- print "Got SOCKS request for %s." % format_addr(dest_addr)
- fd.sendall(struct.pack(">BBHBBBB", 0, 90, dest_addr[1], 127, 0, 0, 1))
- # Note we throw away the requested address and port.
- return True
-
-def handle_remote_connection(fd):
- print "handle_remote_connection"
- match_proxies()
-
-def handle_local_connection(fd):
- print "handle_local_connection"
- if facilitator_addr:
- register(facilitator_addr, remote_addr[1])
- match_proxies()
-
-def register(addr, port):
- spec = format_addr((None, port))
- print "Registering \"%s\" with %s." % (spec, format_addr(addr))
- http = httplib.HTTPConnection(*addr)
- http.request("POST", "/", urllib.urlencode({"client": spec}))
- http.close()
-
-def match_proxies():
- while locals and remotes:
- remote = remotes.pop(0)
- local = locals.pop(0)
- remote_addr, remote_port = remote.getpeername()
- local_addr, local_port = local.getpeername()
- print "Linking %s and %s." % (format_addr(local.getpeername()), format_addr(remote.getpeername()))
- remote_for[local] = remote
- local_for[remote] = local
-
-if facilitator_addr:
- register(facilitator_addr, remote_addr[1])
-
-while True:
- rset = [remote_s, local_s] + crossdomain_pending + socks_pending + remote_for.keys() + local_for.keys() + remotes
- rset, _, _ = select.select(rset, [], [], CROSSDOMAIN_TIMEOUT)
- for fd in rset:
- if fd == remote_s:
- remote_c, addr = fd.accept()
- print "Remote connection from %s." % format_addr(addr)
- crossdomain_pending.append(RemotePending(remote_c))
- elif fd == local_s:
- local_c, addr = fd.accept()
- print "Local connection from %s." % format_addr(addr)
- socks_pending.append(local_c)
- if facilitator_addr:
- register(facilitator_addr, remote_addr[1])
- elif fd in crossdomain_pending:
- print "Data from crossdomain-pending %s." % format_addr(addr)
- handle_policy_request(fd.fd)
- fd.fd.close()
- crossdomain_pending.remove(fd)
- elif fd in socks_pending:
- print "SOCKS request from %s." % format_addr(addr)
- if handle_socks_request(fd):
- locals.append(fd)
- handle_local_connection(fd)
- else:
- fd.close()
- socks_pending.remove(fd)
- elif fd in local_for:
- local = local_for[fd]
- data = fd.recv(1024)
- if not data:
- print "EOF from remote %s." % format_addr(fd.getpeername())
- fd.close()
- local.close()
- del local_for[fd]
- del remote_for[local]
- if facilitator_addr:
- register(facilitator_addr, remote_addr[1])
- else:
- local.sendall(data)
- elif fd in remote_for:
- remote = remote_for[fd]
- data = fd.recv(1024)
- if not data:
- print "EOF from local %s." % format_addr(fd.getpeername())
- fd.close()
- remote.close()
- del remote_for[fd]
- del local_for[remote]
- else:
- remote.sendall(data)
- elif fd in remotes:
- data = fd.recv(1024)
- if not data:
- print "EOF from unconnected remote %s." % format_addr(fd.getpeername())
- else:
- print "Data from unconnected remote %s." % format_addr(fd.getpeername())
- fd.close()
- remotes.remove(fd)
- match_proxies()
- while crossdomain_pending:
- pending = crossdomain_pending[0]
- if not pending.is_expired(CROSSDOMAIN_TIMEOUT):
- break
- print "Expired pending crossdomain from %s." % format_addr(pending.fd.getpeername())
- crossdomain_pending.pop(0)
- remotes.append(pending.fd)
- handle_remote_connection(pending.fd)
diff --git a/com/rtmfpcat/facilitator.py b/com/rtmfpcat/facilitator.py
deleted file mode 100755
index 8c6a44e..0000000
--- a/com/rtmfpcat/facilitator.py
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/env python
-
-import BaseHTTPServer
-import getopt
-import cgi
-import re
-import sys
-import socket
-from collections import deque
-
-DEFAULT_ADDRESS = "0.0.0.0"
-DEFAULT_PORT = 9002
-
-def usage(f = sys.stdout):
- print >> f, """\
-Usage: %(progname)s <OPTIONS> [HOST] [PORT]
-Flash bridge facilitator: Register client addresses with HTTP POST requests
-and serve them out again with HTTP GET. Listen on HOST and PORT, by default
-%(addr)s %(port)d.
- -h, --help show this help.\
-""" % {
- "progname": sys.argv[0],
- "addr": DEFAULT_ADDRESS,
- "port": DEFAULT_PORT,
-}
-
-REGS = deque()
-
-class Reg(object):
- def __init__(self, id):
- self.id = id
-
- def __unicode__(self):
- return u"%s" % (self.id)
-
- def __str__(self):
- return unicode(self).encode("UTF-8")
-
- def __cmp__(self, other):
- return cmp((self.id), (other.id))
-
- @staticmethod
- def parse(spec, defhost = None, defport = None):
- host = None
- port = None
- m = re.match(r'^\[(.+)\]:(\d*)$', spec)
- if m:
- host, port = m.groups()
- af = socket.AF_INET6
- else:
- m = re.match(r'^(.*):(\d*)$', spec)
- if m:
- host, port = m.groups()
- if host:
- af = socket.AF_INET
- else:
- # Has to be guessed from format of defhost.
- af = 0
- host = host or defhost
- port = port or defport
- if not (host and port):
- raise ValueError("Bad address specification \"%s\"" % spec)
-
- try:
- addrs = socket.getaddrinfo(host, port, af, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
- except socket.gaierror, e:
- raise ValueError("Bad host or port: \"%s\" \"%s\": %s" % (host, port, str(e)))
- if not addrs:
- raise ValueError("Bad host or port: \"%s\" \"%s\"" % (host, port))
-
- af = addrs[0][0]
- host, port = socket.getnameinfo(addrs[0][4], socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
- return Reg(af, host, int(port))
-
-def fetch_reg():
- """Get a client registration, or None if none is available."""
- if not REGS:
- return None
- return REGS.popleft()
-
-class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
- def do_GET(self):
- print "From " + str(self.client_address) + " received: GET:",
- reg = fetch_reg()
- if reg:
- print "Handing out " + str(reg) + ". Clients: " + str(len(REGS))
- self.request.send(str(reg))
- else:
- print "Registration list is empty"
- self.request.send("Registration list empty")
-
- def do_POST(self):
- print "From " + str(self.client_address) + " received: POST:",
- data = self.rfile.readline().strip()
- print data + " :",
- try:
- vals = cgi.parse_qs(data, False, True)
- except ValueError, e:
- print "Syntax error in POST:", str(e)
- return
-
- client_specs = vals.get("client")
- if client_specs is None or len(client_specs) != 1:
- print "In POST: need exactly one \"client\" param"
- return
- val = client_specs[0]
-
- try:
- reg = Reg(val)
- except ValueError, e:
- print "Can't parse client \"%s\": %s" % (val, str(e))
- return
-
- if reg not in list(REGS):
- REGS.append(reg)
- print "Registration " + str(reg) + " added. Registrations: " + str(len(REGS))
- else:
- print "Registration " + str(reg) + " already present. Registrations: " + str(len(REGS))
-
-opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help"])
-for o, a in opts:
- if o == "-h" or o == "--help":
- usage()
- sys.exit()
-
-if len(args) == 0:
- address = (DEFAULT_ADDRESS, DEFAULT_PORT)
-elif len(args) == 1:
- # Either HOST or PORT may be omitted; figure out which one.
- if args[0].isdigit():
- address = (DEFAULT_ADDRESS, args[0])
- else:
- address = (args[0], DEFAULT_PORT)
-elif len(args) == 2:
- address = (args[0], args[1])
-else:
- usage(sys.stderr)
- sys.exit(1)
-
-# Setup the server
-server = BaseHTTPServer.HTTPServer(address, Handler)
-
-print "Starting Facilitator on " + str(address) + "..."
-
-# Run server... Single threaded serving of requests...
-server.serve_forever()
diff --git a/com/rtmfpcat/rtmfp/RTMFPSocket.as b/com/rtmfpcat/rtmfp/RTMFPSocket.as
deleted file mode 100644
index bb00994..0000000
--- a/com/rtmfpcat/rtmfp/RTMFPSocket.as
+++ /dev/null
@@ -1,231 +0,0 @@
-/* RTMFPSocket abstraction
- * Author: Nate Hardison, May 2011
- *
- * This code is heavily based off of BelugaFile, an open-source
- * Air file-transfer application written by Nicholas Bliyk.
- * Website: http://www.belugafile.com/
- * Source: http://code.google.com/p/belugafile/
- *
- */
-
-package rtmfp
-{
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.IOErrorEvent;
- import flash.events.NetStatusEvent;
- import flash.events.ProgressEvent;
- import flash.events.SecurityErrorEvent;
- import flash.net.NetConnection;
- import flash.net.NetStream;
- import flash.utils.ByteArray;
- import flash.utils.clearInterval;
- import flash.utils.setInterval;
- import flash.utils.setTimeout;
-
- import rtmfp.RTMFPSocketClient;
- import rtmfp.events.RTMFPSocketEvent;
-
- [Event(name="connectSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="connectFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="publishStart", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peerConnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peeringSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peeringFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- [Event(name="peerDisconnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
- public class RTMFPSocket extends EventDispatcher
- {
- /* The name of the "media" to pass between peers */
- private static const DATA:String = "data";
- private static const DEFAULT_CIRRUS_ADDRESS:String = "rtmfp://p2p.rtmfp.net";
- private static const DEFAULT_CIRRUS_KEY:String = RTMFP::CIRRUS_KEY;
- private static const DEFAULT_CONNECT_TIMEOUT:uint = 4000;
-
- /* Connection to the Cirrus rendezvous service */
- private var connection:NetConnection;
-
- /* ID of the peer to connect to */
- private var peerID:String;
-
- /* Data streams to be established with peer */
- private var sendStream:NetStream;
- private var recvStream:NetStream;
-
- /* Timeouts */
- private var connectionTimeout:int;
- private var peerConnectTimeout:uint;
-
- public function RTMFPSocket(){}
-
- public function connect(addr:String = DEFAULT_CIRRUS_ADDRESS, key:String = DEFAULT_CIRRUS_KEY):void
- {
- connection = new NetConnection();
- connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
- connection.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
- connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
- connection.connect(addr + "/" + key);
- connectionTimeout = setInterval(fail, DEFAULT_CONNECT_TIMEOUT);
- }
-
- public function close():void
- {
- connection.close();
- }
-
- public function get id():String
- {
- if (connection != null && connection.connected) {
- return connection.nearID;
- }
-
- return null;
- }
-
- public function get connected():Boolean
- {
- return (connection != null && connection.connected);
- }
-
- public function readBytes(bytes:ByteArray):void
- {
- recvStream.client.bytes.readBytes(bytes);
- }
-
- public function writeBytes(bytes:ByteArray):void
- {
- sendStream.send("dataAvailable", bytes);
- }
-
- public function get peer():String
- {
- return this.peerID;
- }
-
- public function set peer(peerID:String):void
- {
- if (peerID == null || peerID.length == 0) {
- throw new Error("Peer ID is null/empty.")
- } else if (peerID == connection.nearID) {
- throw new Error("Peer ID cannot be the same as our ID.");
- } else if (this.peerID == peerID) {
- throw new Error("Already connected to peer " + peerID + ".");
- } else if (this.recvStream != null) {
- throw new Error("Cannot connect to a second peer.");
- }
-
- this.peerID = peerID;
-
- recvStream = new NetStream(connection, peerID);
- var client:RTMFPSocketClient = new RTMFPSocketClient();
- client.addEventListener(ProgressEvent.SOCKET_DATA, onDataAvailable, false, 0, true);
- client.addEventListener(RTMFPSocketClient.PEER_CONNECT_ACKNOWLEDGED, onPeerConnectAcknowledged, false, 0, true);
- recvStream.client = client;
- recvStream.addEventListener(NetStatusEvent.NET_STATUS, onRecvStreamEvent);
- recvStream.play(DATA);
- setTimeout(onPeerConnectTimeout, peerConnectTimeout, recvStream);
- }
-
- private function startPublishStream():void
- {
- sendStream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS);
- sendStream.addEventListener(NetStatusEvent.NET_STATUS, onSendStreamEvent);
- var o:Object = new Object();
- o.onPeerConnect = onPeerConnect;
- sendStream.client = o;
- sendStream.publish(DATA);
- }
-
- private function fail():void
- {
- clearInterval(connectionTimeout);
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAIL));
- }
-
- private function onDataAvailable(event:ProgressEvent):void
- {
- dispatchEvent(event);
- }
-
- private function onIOErrorEvent(event:IOErrorEvent):void
- {
- fail();
- }
-
- private function onNetStatusEvent(event:NetStatusEvent):void
- {
- switch (event.info.code) {
- case "NetConnection.Connect.Success" :
- clearInterval(connectionTimeout);
- startPublishStream();
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS));
- break;
- case "NetStream.Connect.Success" :
- break;
- case "NetStream.Publish.BadName" :
- fail();
- break;
- case "NetStream.Connect.Closed" :
- // we've disconnected from the peer
- // can reset to accept another
- // clear the publish stream and re-publish another
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED, recvStream));
- break;
- }
- }
-
- private function onPeerConnect(peer:NetStream):Boolean
- {
- // establish a bidirectional stream with the peer
- if (peerID == null) {
- this.peer = peer.farID;
- }
-
- // disallow additional peers connecting to us
- if (peer.farID != peerID) return false;
-
- peer.send("setPeerConnectAcknowledged");
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_CONNECTED, peer));
-
- return true;
- }
-
- private function onPeerConnectAcknowledged(event:Event):void
- {
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_SUCCESS, recvStream));
- }
-
- private function onPeerConnectTimeout(peer:NetStream):void
- {
- if (!recvStream.client) return;
- if (!RTMFPSocketClient(recvStream.client).peerConnectAcknowledged) {
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_FAIL, recvStream));
- }
- }
-
- private function onSecurityErrorEvent(event:SecurityErrorEvent):void
- {
- fail();
- }
-
- private function onSendStreamEvent(event:NetStatusEvent):void
- {
- switch (event.info.code) {
- case ("NetStream.Publish.Start") :
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_START));
- break;
- case ("NetStream.Play.Reset") :
- case ("NetStream.Play.Start") :
- break;
- }
- }
- private function onRecvStreamEvent(event:NetStatusEvent):void
- {
- switch (event.info.code) {
- case ("NetStream.Publish.Start") :
- case ("NetStream.Play.Reset") :
- case ("NetStream.Play.Start") :
- break;
- }
- }
- }
-}
diff --git a/com/rtmfpcat/rtmfp/RTMFPSocketClient.as b/com/rtmfpcat/rtmfp/RTMFPSocketClient.as
deleted file mode 100644
index d9fcffa..0000000
--- a/com/rtmfpcat/rtmfp/RTMFPSocketClient.as
+++ /dev/null
@@ -1,57 +0,0 @@
-package rtmfp
-{
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.ProgressEvent;
- import flash.utils.ByteArray;
-
- [Event(name="peerConnectAcknowledged", type="flash.events.Event")]
- public dynamic class RTMFPSocketClient extends EventDispatcher {
- public static const PEER_CONNECT_ACKNOWLEDGED:String = "peerConnectAcknowledged";
-
- private var _bytes:ByteArray;
- private var _peerID:String;
- private var _peerConnectAcknowledged:Boolean;
-
- public function RTMFPSocketClient()
- {
- super();
- _bytes = new ByteArray();
- _peerID = null;
- _peerConnectAcknowledged = false;
- }
-
- public function get bytes():ByteArray
- {
- return _bytes;
- }
-
- public function dataAvailable(bytes:ByteArray):void
- {
- this._bytes.clear();
- bytes.readBytes(this._bytes);
- dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, this._bytes.bytesAvailable, this._bytes.length));
- }
-
- public function get peerConnectAcknowledged():Boolean
- {
- return _peerConnectAcknowledged;
- }
-
- public function setPeerConnectAcknowledged():void
- {
- _peerConnectAcknowledged = true;
- dispatchEvent(new Event(PEER_CONNECT_ACKNOWLEDGED));
- }
-
- public function get peerID():String
- {
- return _peerID;
- }
-
- public function set peerID(id:String):void
- {
- _peerID = id;
- }
- }
-}
\ No newline at end of file
diff --git a/com/rtmfpcat/rtmfp/events/RTMFPSocketEvent.as b/com/rtmfpcat/rtmfp/events/RTMFPSocketEvent.as
deleted file mode 100644
index c5b4af1..0000000
--- a/com/rtmfpcat/rtmfp/events/RTMFPSocketEvent.as
+++ /dev/null
@@ -1,25 +0,0 @@
-package rtmfp.events
-{
- import flash.events.Event;
- import flash.net.NetStream;
-
- public class RTMFPSocketEvent extends Event
- {
- public static const CONNECT_SUCCESS:String = "connectSuccess";
- public static const CONNECT_FAIL:String = "connectFail";
- public static const PUBLISH_START:String = "publishStart";
- public static const PEER_CONNECTED:String = "peerConnected";
- public static const PEER_DISCONNECTED:String = "peerDisconnected";
- public static const PEERING_SUCCESS:String = "peeringSuccess";
- public static const PEERING_FAIL:String = "peeringFail";
-
- public var stream:NetStream;
-
- public function RTMFPSocketEvent(type:String, streamVal:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
- {
- super(type, bubbles, cancelable);
- stream = streamVal;
- }
-
- }
-}
\ No newline at end of file
diff --git a/com/rtmfpcat/rtmfpcat.as b/com/rtmfpcat/rtmfpcat.as
deleted file mode 100644
index 328274a..0000000
--- a/com/rtmfpcat/rtmfpcat.as
+++ /dev/null
@@ -1,208 +0,0 @@
-package
-{
- import flash.display.Sprite;
- import flash.text.TextField;
- import flash.net.Socket;
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.IOErrorEvent;
- import flash.events.NetStatusEvent;
- import flash.events.ProgressEvent;
- import flash.events.SecurityErrorEvent;
- import flash.utils.ByteArray;
- import flash.utils.setTimeout;
-
- import rtmfp.RTMFPSocket;
- import rtmfp.events.RTMFPSocketEvent;
- import Utils;
-
- public class rtmfpcat extends Sprite {
-
- /* Nate's facilitator -- also serving a crossdomain policy */
- private const DEFAULT_FAC_ADDR:Object = {
- host: "128.12.179.80",
- port: 9002
- };
-
- private const DEFAULT_TOR_CLIENT_ADDR:Object = {
- host: "127.0.0.1",
- port: 3333
- };
-
- /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
- crossdomain policy. */
- private const DEFAULT_TOR_PROXY_ADDR:Object = {
- host: "173.255.221.44",
- port: 9001
- };
-
- // Milliseconds.
- private const FACILITATOR_POLL_INTERVAL:int = 10000;
-
- private var output_text:TextField;
-
- private var s_f:Socket;
- private var s_r:RTMFPSocket;
- private var s_t:Socket;
-
- private var fac_addr:Object;
- private var tor_addr:Object;
-
- private var proxy_mode:Boolean;
-
- public function rtmfpcat()
- {
- output_text = new TextField();
- output_text.width = 400;
- output_text.height = 300;
- output_text.background = true;
- output_text.backgroundColor = 0x001f0f;
- output_text.textColor = 0x44CC44;
- addChild(output_text);
-
- puts("Starting.");
-
- this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
- }
-
- private function puts(s:String):void
- {
- output_text.appendText(s + "\n");
- output_text.scrollV = output_text.maxScrollV;
- }
-
- private function onLoaderInfoComplete(e:Event):void
- {
- var fac_spec:String;
- var tor_spec:String;
-
- puts("Parameters loaded.");
-
- proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
-
- fac_spec = this.loaderInfo.parameters["facilitator"];
- if (!fac_spec) {
- puts("No \"facilitator\" specification provided...using default.");
- fac_addr = DEFAULT_FAC_ADDR;
- } else {
- puts("Facilitator spec: \"" + fac_spec + "\"");
- fac_addr = Utils.parseAddrSpec(fac_spec);
- }
-
- if (!fac_addr) {
- puts("Error: Facilitator spec must be in the form \"host:port\".");
- return;
- }
-
- tor_spec = this.loaderInfo.parameters["tor"];
- if (!tor_spec) {
- puts("No Tor specification provided...using default.");
- if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
- else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
- } else {
- puts("Tor spec: \"" + tor_spec + "\"")
- tor_addr = Utils.parseAddrSpec(tor_spec);
- }
-
- if (!tor_addr) {
- puts("Error: Tor spec must be in the form \"host:port\".");
- return;
- }
-
- establishRTMFPConnection();
- }
-
- private function establishRTMFPConnection():void
- {
- s_r = new RTMFPSocket();
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
- puts("Cirrus: connected with id " + s_r.id + ".");
- establishFacilitatorConnection();
- });
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
- puts("Error: failed to connect to Cirrus.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
- puts("Publishing started.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
- puts("Peer connected.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
- puts("Peer disconnected.");
- });
- s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
- puts("Peering success.");
- establishTorConnection();
- });
- s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
- puts("Peering fail.");
- });
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_r.readBytes(bytes);
- puts("RTMFP: read " + bytes.length + " bytes.");
- s_t.writeBytes(bytes);
- });
-
- s_r.connect();
- }
-
- private function establishTorConnection():void
- {
- s_t = new Socket();
- s_t.addEventListener(Event.CONNECT, function (e:Event):void {
- puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
- });
- s_t.addEventListener(Event.CLOSE, function (e:Event):void {
- puts("Tor: closed connection.");
- });
- s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- puts("Tor: I/O error: " + e.text + ".");
- });
- s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_t.readBytes(bytes, 0, e.bytesLoaded);
- puts("Tor: read " + bytes.length + " bytes.");
- s_r.writeBytes(bytes);
- });
- s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- puts("Tor: security error: " + e.text + ".");
- });
-
- s_t.connect(tor_addr.host, tor_addr.port);
- }
-
- private function establishFacilitatorConnection():void
- {
- s_f = new Socket();
- s_f.addEventListener(Event.CONNECT, function (e:Event):void {
- puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
- if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
- else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
- });
- s_f.addEventListener(Event.CLOSE, function (e:Event):void {
- puts("Facilitator: connection closed.");
- if (proxy_mode) {
- setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
- }
- });
- s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
- puts("Facilitator: I/O error: " + e.text + ".");
- });
- s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
- puts("Facilitator: got \"" + clientID + "\"");
- if (clientID != "Registration list empty") {
- puts("Connecting to " + clientID + ".");
- s_r.peer = clientID;
- }
- });
- s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
- puts("Facilitator: security error: " + e.text + ".");
- });
-
- s_f.connect(fac_addr.host, fac_addr.port);
- }
- }
-}
\ No newline at end of file
diff --git a/connector.py b/connector.py
index f836d5f..df8f929 100755
--- a/connector.py
+++ b/connector.py
@@ -12,8 +12,8 @@ import time
import urllib
import xml.sax.saxutils
-DEFAULT_REMOTE_ADDRESS = "0.0.0.0"
-DEFAULT_REMOTE_PORT = 9000
+DEFAULT_REMOTE_ADDRESS = "127.0.0.1"
+DEFAULT_REMOTE_PORT = 3333
DEFAULT_LOCAL_ADDRESS = "127.0.0.1"
DEFAULT_LOCAL_PORT = 9001
DEFAULT_FACILITATOR_PORT = 9002
diff --git a/facilitator.py b/facilitator.py
index d909f5f..fde81b7 100755
--- a/facilitator.py
+++ b/facilitator.py
@@ -63,18 +63,17 @@ def format_addr(addr):
return u"%s:%d" % (host, port)
class Reg(object):
- def __init__(self, host, port):
- self.host = host
- self.port = port
+ def __init__(self, id):
+ self.id = id
def __unicode__(self):
- return format_addr((self.host, self.port))
+ return u"%s" % (self.id)
def __str__(self):
return unicode(self).encode("UTF-8")
def __cmp__(self, other):
- return cmp((self.host, self.port), (other.host, other.port))
+ return cmp((self.id), (other.id))
@staticmethod
def parse(spec, defhost = None, defport = None):
@@ -167,7 +166,7 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
val = client_specs[0]
try:
- reg = Reg.parse(val, self.client_address[0])
+ reg = Reg(val)
except ValueError, e:
log(u"client %s syntax error in %s: %s" % (format_addr(self.client_address), repr(val), repr(str(e))))
return
diff --git a/rtmfp/RTMFPSocket.as b/rtmfp/RTMFPSocket.as
new file mode 100644
index 0000000..bb00994
--- /dev/null
+++ b/rtmfp/RTMFPSocket.as
@@ -0,0 +1,231 @@
+/* RTMFPSocket abstraction
+ * Author: Nate Hardison, May 2011
+ *
+ * This code is heavily based off of BelugaFile, an open-source
+ * Air file-transfer application written by Nicholas Bliyk.
+ * Website: http://www.belugafile.com/
+ * Source: http://code.google.com/p/belugafile/
+ *
+ */
+
+package rtmfp
+{
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.NetStatusEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.net.NetConnection;
+ import flash.net.NetStream;
+ import flash.utils.ByteArray;
+ import flash.utils.clearInterval;
+ import flash.utils.setInterval;
+ import flash.utils.setTimeout;
+
+ import rtmfp.RTMFPSocketClient;
+ import rtmfp.events.RTMFPSocketEvent;
+
+ [Event(name="connectSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="connectFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="publishStart", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peerConnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peeringSuccess", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peeringFail", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name="peerDisconnected", type="com.jscat.rtmfp.events.RTMFPSocketEvent")]
+ public class RTMFPSocket extends EventDispatcher
+ {
+ /* The name of the "media" to pass between peers */
+ private static const DATA:String = "data";
+ private static const DEFAULT_CIRRUS_ADDRESS:String = "rtmfp://p2p.rtmfp.net";
+ private static const DEFAULT_CIRRUS_KEY:String = RTMFP::CIRRUS_KEY;
+ private static const DEFAULT_CONNECT_TIMEOUT:uint = 4000;
+
+ /* Connection to the Cirrus rendezvous service */
+ private var connection:NetConnection;
+
+ /* ID of the peer to connect to */
+ private var peerID:String;
+
+ /* Data streams to be established with peer */
+ private var sendStream:NetStream;
+ private var recvStream:NetStream;
+
+ /* Timeouts */
+ private var connectionTimeout:int;
+ private var peerConnectTimeout:uint;
+
+ public function RTMFPSocket(){}
+
+ public function connect(addr:String = DEFAULT_CIRRUS_ADDRESS, key:String = DEFAULT_CIRRUS_KEY):void
+ {
+ connection = new NetConnection();
+ connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
+ connection.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
+ connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
+ connection.connect(addr + "/" + key);
+ connectionTimeout = setInterval(fail, DEFAULT_CONNECT_TIMEOUT);
+ }
+
+ public function close():void
+ {
+ connection.close();
+ }
+
+ public function get id():String
+ {
+ if (connection != null && connection.connected) {
+ return connection.nearID;
+ }
+
+ return null;
+ }
+
+ public function get connected():Boolean
+ {
+ return (connection != null && connection.connected);
+ }
+
+ public function readBytes(bytes:ByteArray):void
+ {
+ recvStream.client.bytes.readBytes(bytes);
+ }
+
+ public function writeBytes(bytes:ByteArray):void
+ {
+ sendStream.send("dataAvailable", bytes);
+ }
+
+ public function get peer():String
+ {
+ return this.peerID;
+ }
+
+ public function set peer(peerID:String):void
+ {
+ if (peerID == null || peerID.length == 0) {
+ throw new Error("Peer ID is null/empty.")
+ } else if (peerID == connection.nearID) {
+ throw new Error("Peer ID cannot be the same as our ID.");
+ } else if (this.peerID == peerID) {
+ throw new Error("Already connected to peer " + peerID + ".");
+ } else if (this.recvStream != null) {
+ throw new Error("Cannot connect to a second peer.");
+ }
+
+ this.peerID = peerID;
+
+ recvStream = new NetStream(connection, peerID);
+ var client:RTMFPSocketClient = new RTMFPSocketClient();
+ client.addEventListener(ProgressEvent.SOCKET_DATA, onDataAvailable, false, 0, true);
+ client.addEventListener(RTMFPSocketClient.PEER_CONNECT_ACKNOWLEDGED, onPeerConnectAcknowledged, false, 0, true);
+ recvStream.client = client;
+ recvStream.addEventListener(NetStatusEvent.NET_STATUS, onRecvStreamEvent);
+ recvStream.play(DATA);
+ setTimeout(onPeerConnectTimeout, peerConnectTimeout, recvStream);
+ }
+
+ private function startPublishStream():void
+ {
+ sendStream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS);
+ sendStream.addEventListener(NetStatusEvent.NET_STATUS, onSendStreamEvent);
+ var o:Object = new Object();
+ o.onPeerConnect = onPeerConnect;
+ sendStream.client = o;
+ sendStream.publish(DATA);
+ }
+
+ private function fail():void
+ {
+ clearInterval(connectionTimeout);
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAIL));
+ }
+
+ private function onDataAvailable(event:ProgressEvent):void
+ {
+ dispatchEvent(event);
+ }
+
+ private function onIOErrorEvent(event:IOErrorEvent):void
+ {
+ fail();
+ }
+
+ private function onNetStatusEvent(event:NetStatusEvent):void
+ {
+ switch (event.info.code) {
+ case "NetConnection.Connect.Success" :
+ clearInterval(connectionTimeout);
+ startPublishStream();
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS));
+ break;
+ case "NetStream.Connect.Success" :
+ break;
+ case "NetStream.Publish.BadName" :
+ fail();
+ break;
+ case "NetStream.Connect.Closed" :
+ // we've disconnected from the peer
+ // can reset to accept another
+ // clear the publish stream and re-publish another
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED, recvStream));
+ break;
+ }
+ }
+
+ private function onPeerConnect(peer:NetStream):Boolean
+ {
+ // establish a bidirectional stream with the peer
+ if (peerID == null) {
+ this.peer = peer.farID;
+ }
+
+ // disallow additional peers connecting to us
+ if (peer.farID != peerID) return false;
+
+ peer.send("setPeerConnectAcknowledged");
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_CONNECTED, peer));
+
+ return true;
+ }
+
+ private function onPeerConnectAcknowledged(event:Event):void
+ {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_SUCCESS, recvStream));
+ }
+
+ private function onPeerConnectTimeout(peer:NetStream):void
+ {
+ if (!recvStream.client) return;
+ if (!RTMFPSocketClient(recvStream.client).peerConnectAcknowledged) {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_FAIL, recvStream));
+ }
+ }
+
+ private function onSecurityErrorEvent(event:SecurityErrorEvent):void
+ {
+ fail();
+ }
+
+ private function onSendStreamEvent(event:NetStatusEvent):void
+ {
+ switch (event.info.code) {
+ case ("NetStream.Publish.Start") :
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_START));
+ break;
+ case ("NetStream.Play.Reset") :
+ case ("NetStream.Play.Start") :
+ break;
+ }
+ }
+ private function onRecvStreamEvent(event:NetStatusEvent):void
+ {
+ switch (event.info.code) {
+ case ("NetStream.Publish.Start") :
+ case ("NetStream.Play.Reset") :
+ case ("NetStream.Play.Start") :
+ break;
+ }
+ }
+ }
+}
diff --git a/rtmfp/RTMFPSocketClient.as b/rtmfp/RTMFPSocketClient.as
new file mode 100644
index 0000000..d9fcffa
--- /dev/null
+++ b/rtmfp/RTMFPSocketClient.as
@@ -0,0 +1,57 @@
+package rtmfp
+{
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.ProgressEvent;
+ import flash.utils.ByteArray;
+
+ [Event(name="peerConnectAcknowledged", type="flash.events.Event")]
+ public dynamic class RTMFPSocketClient extends EventDispatcher {
+ public static const PEER_CONNECT_ACKNOWLEDGED:String = "peerConnectAcknowledged";
+
+ private var _bytes:ByteArray;
+ private var _peerID:String;
+ private var _peerConnectAcknowledged:Boolean;
+
+ public function RTMFPSocketClient()
+ {
+ super();
+ _bytes = new ByteArray();
+ _peerID = null;
+ _peerConnectAcknowledged = false;
+ }
+
+ public function get bytes():ByteArray
+ {
+ return _bytes;
+ }
+
+ public function dataAvailable(bytes:ByteArray):void
+ {
+ this._bytes.clear();
+ bytes.readBytes(this._bytes);
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, this._bytes.bytesAvailable, this._bytes.length));
+ }
+
+ public function get peerConnectAcknowledged():Boolean
+ {
+ return _peerConnectAcknowledged;
+ }
+
+ public function setPeerConnectAcknowledged():void
+ {
+ _peerConnectAcknowledged = true;
+ dispatchEvent(new Event(PEER_CONNECT_ACKNOWLEDGED));
+ }
+
+ public function get peerID():String
+ {
+ return _peerID;
+ }
+
+ public function set peerID(id:String):void
+ {
+ _peerID = id;
+ }
+ }
+}
\ No newline at end of file
diff --git a/rtmfp/events/RTMFPSocketEvent.as b/rtmfp/events/RTMFPSocketEvent.as
new file mode 100644
index 0000000..c5b4af1
--- /dev/null
+++ b/rtmfp/events/RTMFPSocketEvent.as
@@ -0,0 +1,25 @@
+package rtmfp.events
+{
+ import flash.events.Event;
+ import flash.net.NetStream;
+
+ public class RTMFPSocketEvent extends Event
+ {
+ public static const CONNECT_SUCCESS:String = "connectSuccess";
+ public static const CONNECT_FAIL:String = "connectFail";
+ public static const PUBLISH_START:String = "publishStart";
+ public static const PEER_CONNECTED:String = "peerConnected";
+ public static const PEER_DISCONNECTED:String = "peerDisconnected";
+ public static const PEERING_SUCCESS:String = "peeringSuccess";
+ public static const PEERING_FAIL:String = "peeringFail";
+
+ public var stream:NetStream;
+
+ public function RTMFPSocketEvent(type:String, streamVal:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(type, bubbles, cancelable);
+ stream = streamVal;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/rtmfpcat.as b/rtmfpcat.as
new file mode 100644
index 0000000..328274a
--- /dev/null
+++ b/rtmfpcat.as
@@ -0,0 +1,208 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.net.Socket;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.NetStatusEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.utils.ByteArray;
+ import flash.utils.setTimeout;
+
+ import rtmfp.RTMFPSocket;
+ import rtmfp.events.RTMFPSocketEvent;
+ import Utils;
+
+ public class rtmfpcat extends Sprite {
+
+ /* Nate's facilitator -- also serving a crossdomain policy */
+ private const DEFAULT_FAC_ADDR:Object = {
+ host: "128.12.179.80",
+ port: 9002
+ };
+
+ private const DEFAULT_TOR_CLIENT_ADDR:Object = {
+ host: "127.0.0.1",
+ port: 3333
+ };
+
+ /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
+ crossdomain policy. */
+ private const DEFAULT_TOR_PROXY_ADDR:Object = {
+ host: "173.255.221.44",
+ port: 9001
+ };
+
+ // Milliseconds.
+ private const FACILITATOR_POLL_INTERVAL:int = 10000;
+
+ private var output_text:TextField;
+
+ private var s_f:Socket;
+ private var s_r:RTMFPSocket;
+ private var s_t:Socket;
+
+ private var fac_addr:Object;
+ private var tor_addr:Object;
+
+ private var proxy_mode:Boolean;
+
+ public function rtmfpcat()
+ {
+ output_text = new TextField();
+ output_text.width = 400;
+ output_text.height = 300;
+ output_text.background = true;
+ output_text.backgroundColor = 0x001f0f;
+ output_text.textColor = 0x44CC44;
+ addChild(output_text);
+
+ puts("Starting.");
+
+ this.loaderInfo.addEventListener(Event.COMPLETE, onLoaderInfoComplete);
+ }
+
+ private function puts(s:String):void
+ {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
+ }
+
+ private function onLoaderInfoComplete(e:Event):void
+ {
+ var fac_spec:String;
+ var tor_spec:String;
+
+ puts("Parameters loaded.");
+
+ proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
+
+ fac_spec = this.loaderInfo.parameters["facilitator"];
+ if (!fac_spec) {
+ puts("No \"facilitator\" specification provided...using default.");
+ fac_addr = DEFAULT_FAC_ADDR;
+ } else {
+ puts("Facilitator spec: \"" + fac_spec + "\"");
+ fac_addr = Utils.parseAddrSpec(fac_spec);
+ }
+
+ if (!fac_addr) {
+ puts("Error: Facilitator spec must be in the form \"host:port\".");
+ return;
+ }
+
+ tor_spec = this.loaderInfo.parameters["tor"];
+ if (!tor_spec) {
+ puts("No Tor specification provided...using default.");
+ if (proxy_mode) tor_addr = DEFAULT_TOR_PROXY_ADDR;
+ else tor_addr = DEFAULT_TOR_CLIENT_ADDR;
+ } else {
+ puts("Tor spec: \"" + tor_spec + "\"")
+ tor_addr = Utils.parseAddrSpec(tor_spec);
+ }
+
+ if (!tor_addr) {
+ puts("Error: Tor spec must be in the form \"host:port\".");
+ return;
+ }
+
+ establishRTMFPConnection();
+ }
+
+ private function establishRTMFPConnection():void
+ {
+ s_r = new RTMFPSocket();
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_SUCCESS, function (e:Event):void {
+ puts("Cirrus: connected with id " + s_r.id + ".");
+ establishFacilitatorConnection();
+ });
+ s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
+ puts("Error: failed to connect to Cirrus.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
+ puts("Publishing started.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEER_CONNECTED, function(e:RTMFPSocketEvent):void {
+ puts("Peer connected.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEER_DISCONNECTED, function(e:RTMFPSocketEvent):void {
+ puts("Peer disconnected.");
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEERING_SUCCESS, function(e:RTMFPSocketEvent):void {
+ puts("Peering success.");
+ establishTorConnection();
+ });
+ s_r.addEventListener(RTMFPSocketEvent.PEERING_FAIL, function(e:RTMFPSocketEvent):void {
+ puts("Peering fail.");
+ });
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var bytes:ByteArray = new ByteArray();
+ s_r.readBytes(bytes);
+ puts("RTMFP: read " + bytes.length + " bytes.");
+ s_t.writeBytes(bytes);
+ });
+
+ s_r.connect();
+ }
+
+ private function establishTorConnection():void
+ {
+ s_t = new Socket();
+ s_t.addEventListener(Event.CONNECT, function (e:Event):void {
+ puts("Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
+ });
+ s_t.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("Tor: closed connection.");
+ });
+ s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ puts("Tor: I/O error: " + e.text + ".");
+ });
+ s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var bytes:ByteArray = new ByteArray();
+ s_t.readBytes(bytes, 0, e.bytesLoaded);
+ puts("Tor: read " + bytes.length + " bytes.");
+ s_r.writeBytes(bytes);
+ });
+ s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ puts("Tor: security error: " + e.text + ".");
+ });
+
+ s_t.connect(tor_addr.host, tor_addr.port);
+ }
+
+ private function establishFacilitatorConnection():void
+ {
+ s_f = new Socket();
+ s_f.addEventListener(Event.CONNECT, function (e:Event):void {
+ puts("Facilitator: connected to " + fac_addr.host + ":" + fac_addr.port + ".");
+ if (proxy_mode) s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
+ else s_f.writeUTFBytes("POST / HTTP/1.0\r\n\r\nclient=" + s_r.id + "\r\n");
+ });
+ s_f.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("Facilitator: connection closed.");
+ if (proxy_mode) {
+ setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
+ }
+ });
+ s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ puts("Facilitator: I/O error: " + e.text + ".");
+ });
+ s_f.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var clientID:String = s_f.readMultiByte(e.bytesLoaded, "utf-8");
+ puts("Facilitator: got \"" + clientID + "\"");
+ if (clientID != "Registration list empty") {
+ puts("Connecting to " + clientID + ".");
+ s_r.peer = clientID;
+ }
+ });
+ s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ puts("Facilitator: security error: " + e.text + ".");
+ });
+
+ s_f.connect(fac_addr.host, fac_addr.port);
+ }
+ }
+}
\ No newline at end of file
diff --git a/swfcat.as b/swfcat.as
index fd3625d..76de948 100644
--- a/swfcat.as
+++ b/swfcat.as
@@ -249,7 +249,6 @@ import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
-import flash.utils.setInterval;
/* An instance of a client-relay connection. */
class ProxyPair extends EventDispatcher
@@ -266,19 +265,6 @@ class ProxyPair extends EventDispatcher
// Parent swfcat, for UI updates.
private var ui:swfcat;
-
- // Proxy transfer rate limit in KB/s
- private var rate_limit:uint;
-
- // Default limit is 10KB/s
- private const DEFAULT_RATE_LIMIT:uint = 10000;
-
- private var curr_rate:Number;
- private var historical_rate:Number;
- private var lifetime:uint;
-
- // in milliseconds
- private const DEFAULT_RATE_TIMEOUT:uint = 1000;
public function log(msg:String):void
{
@@ -292,16 +278,11 @@ class ProxyPair extends EventDispatcher
"," + this.addr_r.host + ":" + this.addr_r.port + ">";
}
- public function ProxyPair(ui:swfcat, addr_c:Object, addr_r:Object, rate_limit:uint = DEFAULT_RATE_LIMIT)
+ public function ProxyPair(ui:swfcat, addr_c:Object, addr_r:Object)
{
this.ui = ui;
this.addr_c = addr_c;
this.addr_r = addr_r;
- this.rate_limit = rate_limit;
- this.curr_rate = 0.0;
- this.historical_rate = 0.0;
- this.lifetime = 0;
- setInterval(update_transfer_rate, DEFAULT_RATE_TIMEOUT)
}
public function connect():void
@@ -365,53 +346,18 @@ class ProxyPair extends EventDispatcher
private function client_connected(e:Event):void
{
log("Client: connected.");
- add_data_listeners();
- }
-
- private function add_data_listeners():void
- {
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, transfer_to_client);
- s_c.addEventListener(ProgressEvent.SOCKET_DATA, transfer_to_relay);
- }
-
- private function remove_data_listeners():void
- {
- s_r.removeEventListener(ProgressEvent.SOCKET_DATA, transfer_to_client);
- s_c.removeEventListener(ProgressEvent.SOCKET_DATA, transfer_to_relay);
- }
-
- private function transfer_to_client(e:ProgressEvent):void
- {
- log("Tor: read " + e.bytesLoaded + ".");
- transfer_bytes(s_r, s_c, e.bytesLoaded);
- }
-
- private function transfer_to_relay(e:ProgressEvent):void
- {
- log("Client: read " + e.bytesLoaded + ".");
- transfer_bytes(s_c, s_r, e.bytesLoaded);
- }
-
- private function transfer_bytes(src:Socket, dst:Socket, num_bytes:uint):void
- {
- var bytes:ByteArray = new ByteArray();
- src.readBytes(bytes, 0, num_bytes);
- dst.writeBytes(bytes);
- curr_rate += num_bytes;
- if (rate_limit_exceeded()) remove_data_listeners();
- }
-
- private function rate_limit_exceeded():Boolean
- {
- return curr_rate > rate_limit;
- }
-
- private function update_transfer_rate():void
- {
- lifetime++;
- historical_rate = (0.7 * historical_rate + 0.3 * curr_rate) / lifetime;
- curr_rate = historical_rate;
- log("Historical rate: " + historical_rate);
- log("Current rate: " + curr_rate);
+
+ 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);
+ });
}
}
1
0
commit 6c616f701d878246f82b59df0cf4415a861f6ff8
Merge: fd7c1d3 b875382
Author: ellitron <jdellit(a)stanford.edu>
Date: Wed May 25 11:06:13 2011 -0700
merged move of com into main branch
Makefile | 2 +-
README | 88 ++++---
badge.png | Bin 264 -> 682 bytes
badge_con_counter.png | Bin 270 -> 0 bytes
com/rtmfpcat/Makefile | 11 -
com/rtmfpcat/README | 118 ---------
com/rtmfpcat/Utils.as | 25 --
com/rtmfpcat/connector.py | 326 -------------------------
com/rtmfpcat/facilitator.py | 146 -----------
com/rtmfpcat/rtmfp/RTMFPSocket.as | 232 ------------------
com/rtmfpcat/rtmfp/RTMFPSocketClient.as | 57 -----
com/rtmfpcat/rtmfp/events/RTMFPSocketEvent.as | 25 --
com/rtmfpcat/rtmfpcat.as | 208 ----------------
connector.py | 4 +-
facilitator.py | 11 +-
nat-birthday.py | 132 ----------
notes.txt | 2 -
rtmfp/RTMFPSocket.as | 232 ++++++++++++++++++
rtmfp/RTMFPSocketClient.as | 57 +++++
rtmfp/events/RTMFPSocketEvent.as | 24 ++
rtmfpcat.as | 237 ++++++++++++++++++
swfcat.as | 230 +++++++++++++-----
22 files changed, 778 insertions(+), 1389 deletions(-)
1
0
commit fd7c1d376ec99450745545dc9b54a5213128f6ac
Author: ellitron <jdellit(a)stanford.edu>
Date: Tue May 24 19:54:32 2011 -0700
removed two spaces from close body
---
com/rtmfpcat/rtmfp/RTMFPSocket.as | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/com/rtmfpcat/rtmfp/RTMFPSocket.as b/com/rtmfpcat/rtmfp/RTMFPSocket.as
index 2d634f0..450e520 100644
--- a/com/rtmfpcat/rtmfp/RTMFPSocket.as
+++ b/com/rtmfpcat/rtmfp/RTMFPSocket.as
@@ -69,7 +69,7 @@ package rtmfp
public function close():void
{
- connection.close();
+ connection.close();
}
public function get id():String
1
0