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
commit 58af9ccdd5a264080c4df7dec4f9894f490ee12b
Merge: 147a34c 81bad6e
Author: David Fifield <david(a)bamsoftware.com>
Date: Sat Jun 11 12:18:55 2011 -0700
Merge branch 'master' into rtmfp
Conflicts:
README
README | 6 +-
facilitator.py | 34 ++++++++---
notes.txt | 4 -
reconnector.py | 179 --------------------------------------------------------
4 files changed, 28 insertions(+), 195 deletions(-)
1
0

[flashproxy/master] Rename DEFAULT_FAC_POLL_INTERVAL to FACILITATOR_POLL_INTERVAL.
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit efed6d80241205315ae3f79724d0cd027a2319c1
Author: David Fifield <david(a)bamsoftware.com>
Date: Sat Jun 11 12:44:12 2011 -0700
Rename DEFAULT_FAC_POLL_INTERVAL to FACILITATOR_POLL_INTERVAL.
---
swfcat.as | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/swfcat.as b/swfcat.as
index dd2396d..d0aad9a 100644
--- a/swfcat.as
+++ b/swfcat.as
@@ -37,9 +37,9 @@ package
host: "127.0.0.1",
port: 9002
};
-
- /* Poll facilitator every 10 sec */
- private const DEFAULT_FAC_POLL_INTERVAL:uint = 10000;
+
+ // Milliseconds.
+ private const FACILITATOR_POLL_INTERVAL:int = 10000;
// Socket to Cirrus server
private var s_c:CirrusSocket;
@@ -185,7 +185,7 @@ package
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);
+ setTimeout(establish_facilitator_connection, FACILITATOR_POLL_INTERVAL);
});
if (proxy_mode) {
@@ -210,14 +210,14 @@ package
});
s_f.addEventListener(FacilitatorSocketEvent.REGISTRATIONS_EMPTY, function (e:Event):void {
puts("Facilitator: no registrations available.");
- setTimeout(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
+ setTimeout(establish_facilitator_connection, FACILITATOR_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);
+ setTimeout(establish_facilitator_connection, FACILITATOR_POLL_INTERVAL);
});
puts("Facilitator: posting registration.");
s_f.post_registration(s_c.id);
1
0

12 Jun '11
commit 15a659481601670a8081bec25e21686beb927138
Author: David Fifield <david(a)bamsoftware.com>
Date: Sat Jun 11 12:26:53 2011 -0700
Remove outdated information from README.
---
README | 52 +++++++++++++---------------------------------------
1 files changed, 13 insertions(+), 39 deletions(-)
diff --git a/README b/README
index 8597a96..ff12174 100644
--- a/README
+++ b/README
@@ -5,24 +5,12 @@ 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
+2. A "connector," which waits for connections from the Flash proxy 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.
+ called swfcat because it is like a netcat implemented in Flash.
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
@@ -46,40 +34,34 @@ variable CIRRUS_KEY so it can be found by Makefile.
To build, run
$ make
-Copy the resulting rtmfpcat.swf file to a web server.
+Copy the resulting swfcat.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.
+The facilitator runs on port 9002 by default.
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
-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
+ ./connector.py 127.0.0.1:9001 127.0.0.1:9002
+Also on the client, open up the browser to swfcat.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
+on Nate's server). swfcat 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,
+In a browser somewhere, open swfcat.swf and pass parameters telling it
+which facilitator to use and to operate in proxy mode.
+ http://www.example.com/swfcat.swf?proxy=true&facilitator=<FACILITATOR_IP>:9002&debug=1
+This swfcat 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).
+Tor relay.
Back on the client, start Tor with the following configuration:
UseBridges 1
@@ -92,7 +74,7 @@ If you see messages like
try deleting the files in ~/.tor or /var/lib/tor.
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.
+swfcat.swf (client and proxy), and eventually be able to build a circuit.
== Rationale
@@ -111,14 +93,6 @@ Clients register with the facilitator by sending an HTTP 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 Flash proxy also gets a client address over HTTP:
GET / HTTP/1.0\r\n
\r\n
1
0

12 Jun '11
commit e8f3ca392f37f326dac975a6827a9d4e71eb6c50
Author: David Fifield <david(a)bamsoftware.com>
Date: Sat Jun 11 12:29:17 2011 -0700
Use the same connector as in master branch.
Instead of coding different default ports, just document the
command-line parameters you need to use to make the difference.
---
connector.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/connector.py b/connector.py
index 731fa19..27fff61 100755
--- a/connector.py
+++ b/connector.py
@@ -12,8 +12,8 @@ import time
import urllib
import xml.sax.saxutils
-DEFAULT_REMOTE_ADDRESS = "127.0.0.1"
-DEFAULT_REMOTE_PORT = 9002
+DEFAULT_REMOTE_ADDRESS = "0.0.0.0"
+DEFAULT_REMOTE_PORT = 9000
DEFAULT_LOCAL_ADDRESS = "127.0.0.1"
DEFAULT_LOCAL_PORT = 9001
DEFAULT_FACILITATOR_PORT = 9002
@@ -281,7 +281,7 @@ def register():
spec = format_addr((None, options.remote_addr[1]))
log(u"Registering \"%s\" with %s." % (spec, format_addr(options.facilitator_addr)))
http = httplib.HTTPConnection(*options.facilitator_addr)
- http.request("POST", "/", urllib.urlencode({"client": spec}), {"Content-Type":"application/x-www-form-urlencoded"})
+ http.request("POST", "/", urllib.urlencode({"client": spec}))
http.close()
return True
1
0
commit 8ae82797738a29167cf1c6b1326b20b1794f2997
Author: David Fifield <david(a)bamsoftware.com>
Date: Sat Jun 11 13:45:18 2011 -0700
Use a separate Badge class for UI.
Ported from rtmfp branch.
---
swfcat.as | 162 ++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 92 insertions(+), 70 deletions(-)
diff --git a/swfcat.as b/swfcat.as
index 4aa430b..8d893b2 100644
--- a/swfcat.as
+++ b/swfcat.as
@@ -36,23 +36,16 @@ package
/* TextField for debug output. */
private var output_text:TextField;
- private var fac_addr:Object;
+ /* UI shown when debug is off. */
+ private var badge:Badge;
/* Number of proxy pairs currently connected (up to
MAX_NUM_PROXY_PAIRS). */
private var num_proxy_pairs:int = 0;
- /* Number of proxy pairs ever connected. */
- private var total_proxy_pairs:int = 0;
- public var rate_limit:RateLimit;
+ private var fac_addr:Object;
- /* Badge with a client counter */
- [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 var rate_limit:RateLimit;
public function puts(s:String):void
{
@@ -60,20 +53,6 @@ package
output_text.scrollV = output_text.maxScrollV;
}
- public 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(".");;
- }
-
public function swfcat()
{
// Absolute positioning.
@@ -87,38 +66,7 @@ package
output_text.backgroundColor = 0x001f0f;
output_text.textColor = 0x44cc44;
- /* 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();
+ badge = new Badge();
if (RATE_LIMIT)
rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISTORY, RATE_LIMIT_HISTORY);
@@ -138,13 +86,8 @@ package
if (this.loaderInfo.parameters["debug"])
addChild(output_text);
- else {
- addChild(new BadgeImage());
- /* Tried unsuccessfully to add counter to badge. */
- /* For now, need two addChilds :( */
- addChild(tot_client_count_tf);
- addChild(cur_client_count_tf);
- }
+ else
+ addChild(badge);
fac_addr = get_param_addr("facilitator", DEFAULT_FACILITATOR_ADDR);
if (!fac_addr) {
@@ -236,17 +179,13 @@ package
}
num_proxy_pairs++;
- total_proxy_pairs++;
- /* Update the client count on the badge. */
- update_client_count();
+ badge.proxy_begin();
proxy_pair = new ProxyPair(this, client_addr, relay_addr);
proxy_pair.addEventListener(Event.COMPLETE, function(e:Event):void {
proxy_pair.log("Complete.");
-
num_proxy_pairs--;
- /* Update the client count on the badge. */
- update_client_count();
+ badge.proxy_end();
});
proxy_pair.connect();
@@ -272,6 +211,8 @@ package
}
import flash.display.Sprite;
+import flash.text.TextFormat;
+import flash.text.TextField;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
@@ -284,6 +225,87 @@ import flash.utils.clearTimeout;
import flash.utils.getTimer;
import flash.utils.setTimeout;
+class Badge extends flash.display.Sprite
+{
+ /* Number of proxy pairs currently connected. */
+ private var num_proxy_pairs:int = 0;
+ /* Number of proxy pairs ever connected. */
+ private var total_proxy_pairs:int = 0;
+
+ [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 Badge()
+ {
+ /* 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;
+
+ addChild(new BadgeImage());
+ addChild(tot_client_count_tf);
+ addChild(cur_client_count_tf);
+
+ /* Update the client counter on badge. */
+ update_client_count();
+ }
+
+ public function proxy_begin():void
+ {
+ num_proxy_pairs++;
+ total_proxy_pairs++;
+ update_client_count();
+ }
+
+ public function proxy_end():void
+ {
+ num_proxy_pairs--;
+ update_client_count();
+ }
+
+ 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(".");
+ }
+}
+
class RateLimit
{
public function RateLimit()
1
0
commit a7cdef5eaddee994257579f0b2db01c65164eda4
Author: ellitron <jdellit(a)stanford.edu>
Date: Fri May 27 12:27:00 2011 -0700
Added badge
---
badge_con_counter.png | Bin 0 -> 270 bytes
return_of_the_rtmfpcat.as | 157 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 138 insertions(+), 19 deletions(-)
diff --git a/badge_con_counter.png b/badge_con_counter.png
new file mode 100644
index 0000000..d832e24
Binary files /dev/null and b/badge_con_counter.png differ
diff --git a/return_of_the_rtmfpcat.as b/return_of_the_rtmfpcat.as
index a1d14cc..e512408 100644
--- a/return_of_the_rtmfpcat.as
+++ b/return_of_the_rtmfpcat.as
@@ -54,13 +54,15 @@ package
private static const DEFAULT_CIRCON_TIMEOUT:uint = 4000;
+ private static const DEFAULT_PEER_CON_TIMEOUT:uint = 4000;
+
/* Maximum connections. */
private const DEFAULT_MAXIMUM_RCP_PAIRS:uint = 1;
/* Milliseconds. */
private const FACILITATOR_POLL_INTERVAL:int = 10000;
- private var max_rcp_pairs;
+ private var max_rcp_pairs:uint;
/* TextField for debug output. */
private var output_text:TextField;
@@ -90,19 +92,42 @@ package
/* Number of connected RTMFPConnectionPairs. */
private var rcp_pairs:uint;
+ private var rcp_pairs_total:uint;
private var rtmfp_data_counter:uint;
/* Keep track of facilitator polling timer. */
private var fac_poll_timeo_id:uint;
+ /* Badge with a client counter */
+ [Embed(source="badge_con_counter.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;
+
/* Put a string to the screen. */
public function puts(s:String):void
{
output_text.appendText(s + "\n");
output_text.scrollV = output_text.maxScrollV;
}
-
+
+ public function update_client_count():void
+ {
+ /* Update total client count. */
+ if (String(rcp_pairs_total).length == 1)
+ tot_client_count_tf.text = "0" + String(rcp_pairs_total);
+ else
+ tot_client_count_tf.text = String(rcp_pairs_total);
+
+ /* Update current client count. */
+ cur_client_count_tf.text = "";
+ for(var i:Number=0; i<rcp_pairs; i++)
+ cur_client_count_tf.appendText(".");;
+ }
+
public function return_of_the_rtmfpcat()
{
// Absolute positioning.
@@ -115,6 +140,38 @@ package
output_text.background = true;
output_text.backgroundColor = 0x001f0f;
output_text.textColor = 0x44cc44;
+
+ /* 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();
/* Initialize connection pair count. */
rcp_pairs = 0;
@@ -136,7 +193,16 @@ package
puts("Parameters loaded.");
proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
- addChild(output_text);
+
+ if(this.loaderInfo.parameters["debug"] != null)
+ addChild(output_text);
+
+ addChild(new BadgeImage());
+ /* Tried unsuccessfully to add counter to badge. */
+ /* For now, need two addChilds :( */
+ addChild(tot_client_count_tf);
+ addChild(cur_client_count_tf);
+
fac_spec = this.loaderInfo.parameters["facilitator"];
if (fac_spec) {
@@ -180,6 +246,9 @@ package
else
max_rcp_pairs = DEFAULT_MAXIMUM_RCP_PAIRS;
+ if(this.loaderInfo.parameters["start"])
+ rtmfp_data_counter = this.loaderInfo.parameters["start"];
+
main();
}
@@ -254,8 +323,14 @@ package
var rcp:RTMFPConnectionPair = new RTMFPConnectionPair(circon, tor_addr, output_text);
rcp.addEventListener(Event.CONNECT, rcp_connect_event);
+ rcp.addEventListener(Event.UNLOAD, function (e:Event):void {
+ /* Failed to connect to peer... continue loop. */
+ puts("RTMFPConnectionPair: Timed out connecting to peer!");
+ if(rcp_pairs < max_rcp_pairs)
+ poll_for_id();
+ });
rcp.addEventListener(Event.CLOSE, rcp_close_event);
- rcp.connect(client_id, client_data);
+ rcp.connect(client_id, client_data, DEFAULT_PEER_CON_TIMEOUT);
} else {
/* Need to clear any outstanding timers to ensure
* that only one timer ever runs. */
@@ -277,6 +352,10 @@ package
puts("RTMFPConnectionPair connected");
rcp_pairs++;
+ rcp_pairs_total++;
+
+ /* Update the client count on the badge. */
+ update_client_count();
if(proxy_mode) {
if(rcp_pairs < max_rcp_pairs) {
@@ -304,6 +383,9 @@ package
rcp_pairs--;
+ /* Update the client count on the badge. */
+ update_client_count();
+
/* FIXME: Do I need to unregister the event listeners so
* that the system can garbage collect the rcp object? */
if(proxy_mode) {
@@ -402,6 +484,8 @@ class RTMFPSocket extends EventDispatcher
/* Keeps the state of our connectedness. */
public var connected:Boolean;
+ private var connect_timeo_id:uint;
+
private var output_text:TextField;
/* Put a string to the screen. */
@@ -437,15 +521,26 @@ class RTMFPSocket extends EventDispatcher
send_stream.publish(data);
}
- public function connect(clientID:String, data:String):void
+ private function connect_timeout():void
+ {
+ puts("RTMFPSocket: Timed out connecting to peer");
+ close();
+ /* OK this is not so nice, because I wanted an Event.TIMEOUT event, but flash gives us none such event :( */
+ dispatchEvent(new Event(Event.UNLOAD));
+ }
+
+ public function connect(clientID:String, data:String, timeout:uint):void
{
puts("RTMFPSocket: connecting to peer...");
+ connect_timeo_id = setTimeout(connect_timeout, timeout);
+
this.data = data;
send_stream = new NetStream(circon, NetStream.DIRECT_CONNECTIONS);
var client:Object = new Object();
client.onPeerConnect = function (peer:NetStream):Boolean {
+ clearTimeout(connect_timeo_id);
puts("RTMFPSocket: connected to peer");
connected = true;
dispatchEvent(new Event(Event.CONNECT));
@@ -605,18 +700,48 @@ class RTMFPConnectionPair extends EventDispatcher
this.output_text = output_text;
}
- public function connect(clientID:String, rtmfp_data:String):void
+ public function connect(clientID:String, rtmfp_data:String, timeout:uint):void
{
s_r = new RTMFPSocket(circon, output_text);
s_r.addEventListener(Event.CONNECT, rtmfp_connect_event);
+ s_r.addEventListener(Event.UNLOAD, function (e:Event):void {
+ dispatchEvent(new Event(Event.UNLOAD));
+ });
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ /* It's possible that we receive data before we're connected
+ * to the tor-side of the connection. In this case we want
+ * to buffer the data. */
+ if(!s_t.connected) {
+ puts("MASSIVE ATTACK!");
+ } else {
+ var bytes:ByteArray = new ByteArray();
+ s_r.readBytes(bytes, 0, e.bytesLoaded);
+ puts("RTMFPConnectionPair: RTMFP: read " + bytes.length + " bytes.");
+ s_t.writeBytes(bytes);
+ }
+ });
s_r.addEventListener(Event.CLOSE, rtmfp_close_event);
- s_r.connect(clientID, rtmfp_data);
+ s_r.connect(clientID, rtmfp_data, timeout);
}
public function listen(rtmfp_data:String):void
{
s_r = new RTMFPSocket(circon, output_text);
s_r.addEventListener(Event.CONNECT, rtmfp_connect_event);
+ s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ /* It's possible that we receive data before we're connected
+ * to the tor-side of the connection. In this case we want
+ * to buffer the data. */
+ if(!s_t.connected) {
+ puts("MASSIVE ATTACK!");
+ } else {
+ var bytes:ByteArray = new ByteArray();
+ s_r.readBytes(bytes, 0, e.bytesLoaded);
+ puts("RTMFPConnectionPair: RTMFP: read " + bytes.length + " bytes.");
+ s_t.writeBytes(bytes);
+ }
+ });
+
s_r.addEventListener(Event.CLOSE, rtmfp_close_event);
s_r.listen(rtmfp_data);
}
@@ -630,18 +755,6 @@ class RTMFPConnectionPair extends EventDispatcher
s_t = new Socket();
s_t.addEventListener(Event.CONNECT, function (e:Event):void {
puts("RTMFPConnectionPair: Tor: connected to " + tor_addr.host + ":" + tor_addr.port + ".");
- s_r.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_r.readBytes(bytes, 0, e.bytesLoaded);
- puts("RTMFPConnectionPair: RTMFP: read " + bytes.length + " bytes.");
- s_t.writeBytes(bytes);
- });
- s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
- var bytes:ByteArray = new ByteArray();
- s_t.readBytes(bytes, 0, e.bytesLoaded);
- puts("RTMFPConnectionPair: Tor: read " + bytes.length + " bytes.");
- s_r.writeBytes(bytes);
- });
dispatchEvent(new Event(Event.CONNECT));
});
s_t.addEventListener(Event.CLOSE, function (e:Event):void {
@@ -652,6 +765,12 @@ class RTMFPConnectionPair extends EventDispatcher
s_r.close();
dispatchEvent(new Event(Event.CLOSE));
});
+ s_t.addEventListener(ProgressEvent.SOCKET_DATA, function (e:ProgressEvent):void {
+ var bytes:ByteArray = new ByteArray();
+ s_t.readBytes(bytes, 0, e.bytesLoaded);
+ puts("RTMFPConnectionPair: Tor: read " + bytes.length + " bytes.");
+ s_r.writeBytes(bytes);
+ });
s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
puts("RTMFPConnectionPair: Tor: I/O error: " + e.text + ".");
});
1
0

[flashproxy/master] Merge branch 'rtmfp' of ssh://upload.bamsoftware.com/~dcf/flashproxy into rtmfp
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit 07752417d9a42099bc0c869b0ebac1862f72baa4
Merge: 7c4ca7b a7cdef5
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 03:46:27 2011 -0700
Merge branch 'rtmfp' of ssh://upload.bamsoftware.com/~dcf/flashproxy into rtmfp
badge_con_counter.png | Bin 0 -> 270 bytes
return_of_the_rtmfpcat.as | 234 +++++++++++++++++++++++++++++++++++++--------
2 files changed, 192 insertions(+), 42 deletions(-)
1
0

12 Jun '11
commit 7a302499ef39988d560790a220d4f05f5f1b2e9b
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 04:02:36 2011 -0700
Adding some comments and removing clutter
---
rtmfp/CirrusSocket.as | 2 ++
rtmfp/RTMFPSocket.as | 17 +----------------
2 files changed, 3 insertions(+), 16 deletions(-)
diff --git a/rtmfp/CirrusSocket.as b/rtmfp/CirrusSocket.as
index d9996f2..9e97c7d 100644
--- a/rtmfp/CirrusSocket.as
+++ b/rtmfp/CirrusSocket.as
@@ -49,6 +49,8 @@ package rtmfp
connection.addEventListener(NetStatusEvent.NET_STATUS, on_net_status_event);
connection.addEventListener(IOErrorEvent.IO_ERROR, on_io_error_event);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, on_security_error_event);
+
+ /* Set up a client object to handle the hello callback */
var client:Object = new Object();
client.onRelay = on_hello;
connection.client = client;
diff --git a/rtmfp/RTMFPSocket.as b/rtmfp/RTMFPSocket.as
index 783a0e0..6e9a45e 100644
--- a/rtmfp/RTMFPSocket.as
+++ b/rtmfp/RTMFPSocket.as
@@ -45,8 +45,7 @@ package rtmfp
}
/* Tears down this RTMFPSocket, closing both its streams.
- To be used when destroying this object. If you just want
- to disconnect from a client, call disconnect() below */
+ To be used when destroying this object. */
public function close():void
{
if (send_stream != null) {
@@ -82,19 +81,6 @@ package rtmfp
RTMFPSocketClient(recv_stream.client).connect_acknowledged);
}
- public function disconnect():void
- {
- if (recv_stream != null) {
- if (recv_stream.client != null) {
- recv_stream.client.removeEventListener(ProgressEvent.SOCKET_DATA, on_data_available);
- recv_stream.client.removeEventListener(RTMFPSocketClient.CONNECT_ACKNOWLEDGED, on_connect_acknowledged);
- }
- recv_stream.removeEventListener(NetStatusEvent.NET_STATUS, on_recv_stream_event);
- recv_stream.close();
- recv_stream = null;
- }
- }
-
/* In RTMFP, you open a listening socket by publishing a named
stream that others can connect to instead of listening on a port.
You register this stream with the Cirrus server via the Cirrus
@@ -132,7 +118,6 @@ package rtmfp
}
}
-
public function writeBytes(bytes:ByteArray):void
{
if (send_stream != null && peer_connected) {
1
0

[flashproxy/master] New version of rtmfpcat that works with reconnection
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit 7c4ca7bf575684c35773605e522ee118c1f8f0bf
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 03:45:18 2011 -0700
New version of rtmfpcat that works with reconnection
---
Makefile | 2 +-
rtmfp/CirrusSocket.as | 140 +++++++++++++
rtmfp/FacilitatorSocket.as | 115 +++++++++++
rtmfp/ProxyPair.as | 125 ++++++++++++
rtmfp/RTMFPSocket.as | 340 +++++++++++++++-----------------
rtmfp/RTMFPSocketClient.as | 34 ++--
rtmfp/events/CirrusSocketEvent.as | 22 ++
rtmfp/events/FacilitatorSocketEvent.as | 22 ++
rtmfp/events/RTMFPSocketEvent.as | 13 +-
rtmfpcat.as | 240 ++++++++++++-----------
10 files changed, 729 insertions(+), 324 deletions(-)
diff --git a/Makefile b/Makefile
index bc1f8bf..3595385 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
MXMLC ?= mxmlc
-TARGETS = rtmfpcat.swf return_of_the_rtmfpcat.swf
+TARGETS = rtmfpcat.swf
all: $(TARGETS)
diff --git a/rtmfp/CirrusSocket.as b/rtmfp/CirrusSocket.as
new file mode 100644
index 0000000..d9996f2
--- /dev/null
+++ b/rtmfp/CirrusSocket.as
@@ -0,0 +1,140 @@
+/* CirrusSocket abstraction
+ * ------------------------
+ * Manages the NetConnection portion of RTMFP and also handles
+ * the handshake between two Flash players to decide what their
+ * data stream names will be.
+ *
+ * TODO: consider using farNonce/nearNonce instead of sending bytes?
+ */
+
+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.utils.clearInterval;
+ import flash.utils.setInterval;
+
+ import rtmfp.RTMFPSocket;
+ import rtmfp.events.CirrusSocketEvent;
+ import rtmfp.events.RTMFPSocketEvent;
+
+ [Event(name=CirrusSocketEvent.CONNECT_CLOSED, type="com.flashproxy.rtmfp.events.CirrusSocketEvent")]
+ [Event(name=CirrusSocketEvent.CONNECT_FAILED, type="com.flashproxy.rtmfp.events.CirrusSocketEvent")]
+ [Event(name=CirrusSocketEvent.CONNECT_SUCCESS, type="com.flashproxy.rtmfp.events.CirrusSocketEvent")]
+ [Event(name=CirrusSocketEvent.HELLO_RECEIVED, type="com.flashproxy.rtmfp.events.CirrusSocketEvent")]
+ public class CirrusSocket extends EventDispatcher
+ {
+ private static const CONNECT_TIMEOUT:uint = 4000; // in milliseconds
+
+ /* We'll append a unique number to the DATA_STREAM_PREFIX for each
+ new stream we create so that we have unique streams per player. */
+ private static const DATA_STREAM_PREFIX:String = "DATA";
+ private var data_stream_suffix:uint = 0;
+
+ /* Connection to the Cirrus rendezvous service */
+ public var connection:NetConnection;
+
+ /* Timeouts */
+ private var connect_timeout:int;
+ private var hello_timeout:int;
+
+ public function CirrusSocket()
+ {
+ connection = new NetConnection();
+ connection.addEventListener(NetStatusEvent.NET_STATUS, on_net_status_event);
+ connection.addEventListener(IOErrorEvent.IO_ERROR, on_io_error_event);
+ connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, on_security_error_event);
+ var client:Object = new Object();
+ client.onRelay = on_hello;
+ connection.client = client;
+ }
+
+ public function connect(addr:String, key:String):void
+ {
+ if (!this.connected) {
+ connect_timeout = setInterval(fail, CONNECT_TIMEOUT);
+ connection.connect(addr, key);
+ } else {
+ throw new Error("Cannot connect Cirrus socket: already connected.");
+ }
+ }
+
+ public function close():void
+ {
+ if (this.connected) {
+ connection.close();
+ } else {
+ throw new Error("Cannot close Cirrus socket: not connected.");
+ }
+ }
+
+ public function get connected():Boolean
+ {
+ return (connection != null && connection.connected);
+ }
+
+ public function get id():String
+ {
+ if (this.connected) {
+ return connection.nearID;
+ }
+
+ return null;
+ }
+
+ public function get local_stream_name():String
+ {
+ return DATA_STREAM_PREFIX + data_stream_suffix;
+ }
+
+ /* Sends a hello message to the Flash player with Cirrus ID "id"
+ We use this new call protocol outlined here:
+ http://forums.adobe.com/thread/780788?tstart=0 */
+ public function send_hello(id:String):void
+ {
+ if (this.connected) {
+ connection.call("relay", null, id, local_stream_name);
+ } else {
+ throw new Error("Cannot send hello: Cirrus socket not connected.");
+ }
+ }
+
+/*************************** PRIVATE HELPER FUNCTIONS *************************/
+
+ private function fail():void
+ {
+ clearInterval(connect_timeout);
+ dispatchEvent(new CirrusSocketEvent(CirrusSocketEvent.CONNECT_FAILED));
+ }
+
+ private function on_hello(peer:String, ...args):void
+ {
+ var stream:String = args[0];
+ dispatchEvent(new CirrusSocketEvent(CirrusSocketEvent.HELLO_RECEIVED, peer, stream));
+ data_stream_suffix++;
+ }
+
+ private function on_io_error_event(event:IOErrorEvent):void
+ {
+ fail();
+ }
+
+ private function on_net_status_event(event:NetStatusEvent):void
+ {
+ if (event.info.code == "NetConnection.Connect.Success") {
+ clearInterval(connect_timeout);
+ dispatchEvent(new CirrusSocketEvent(CirrusSocketEvent.CONNECT_SUCCESS));
+ }
+ }
+
+ private function on_security_error_event(event:SecurityErrorEvent):void
+ {
+ fail();
+ }
+ }
+}
diff --git a/rtmfp/FacilitatorSocket.as b/rtmfp/FacilitatorSocket.as
new file mode 100644
index 0000000..e175290
--- /dev/null
+++ b/rtmfp/FacilitatorSocket.as
@@ -0,0 +1,115 @@
+package rtmfp
+{
+ 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.clearInterval;
+ import flash.utils.setInterval;
+
+ 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;
+
+ 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 get_registration():void
+ {
+ if (!connected) return;
+ socket.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
+ }
+
+ 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");
+ }
+
+ private function fail():void
+ {
+ clearInterval(connection_timeout);
+ dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_FAILED));
+ }
+
+ private function on_close_event(event:Event):void
+ {
+ close();
+ dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_CLOSED));
+ }
+
+ private function on_connect_event(event:Event):void
+ {
+ connected = true;
+ dispatchEvent(new FacilitatorSocketEvent(FacilitatorSocketEvent.CONNECT_SUCCESS));
+ }
+
+ private function on_io_error_event(event:IOErrorEvent):void
+ {
+ fail();
+ }
+
+ private function on_progress_event(event:ProgressEvent):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));
+ }
+ }
+
+ private function on_security_error_event(event:SecurityErrorEvent):void
+ {
+ fail();
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/rtmfp/ProxyPair.as b/rtmfp/ProxyPair.as
new file mode 100644
index 0000000..42d4b81
--- /dev/null
+++ b/rtmfp/ProxyPair.as
@@ -0,0 +1,125 @@
+package rtmfp
+{
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.net.Socket;
+ import flash.utils.ByteArray;
+
+ import rtmfp.CirrusSocket;
+ import rtmfp.RTMFPSocket;
+ import rtmfp.events.RTMFPSocketEvent;
+
+ public class ProxyPair extends EventDispatcher
+ {
+ private var parent:rtmfpcat;
+
+ private var s_r:RTMFPSocket;
+ private var s_t:Socket;
+
+ private var tor_host:String;
+ private var tor_port:uint;
+
+ public function ProxyPair(parent:rtmfpcat, s_c:CirrusSocket, tor_host:String, tor_port:uint)
+ {
+ this.parent = parent;
+ this.tor_host = tor_host;
+ this.tor_port = tor_port;
+
+ setup_rtmfp_socket(s_c);
+ setup_tor_socket();
+ }
+
+ public function close():void
+ {
+ 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);
+ }
+
+ public function get connected():Boolean
+ {
+ return (s_r.connected && s_t.connected);
+ }
+
+ public function listen(stream:String):void
+ {
+ s_r.listen(stream);
+ }
+
+ 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.PUBLISH_STARTED, 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.");
+ 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.CONNECT_FAILED, function (e:RTMFPSocketEvent):void {
+ puts("Peering failed.");
+ });
+ }
+
+ 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);
+ });
+ dispatchEvent(new Event(Event.CONNECT));
+ });
+ s_t.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("Tor: closed connection.");
+ close();
+ });
+ s_t.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
+ puts("Tor: I/O error: " + e.text + ".");
+ close();
+ });
+ s_t.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
+ puts("Tor: security error: " + e.text + ".");
+ close();
+ });
+ }
+
+ private function puts(s:String):void
+ {
+ parent.puts(s);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/rtmfp/RTMFPSocket.as b/rtmfp/RTMFPSocket.as
index d524699..783a0e0 100644
--- a/rtmfp/RTMFPSocket.as
+++ b/rtmfp/RTMFPSocket.as
@@ -1,13 +1,3 @@
-/* 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;
@@ -19,213 +9,205 @@ package rtmfp
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.ByteArray;
- import flash.utils.clearInterval;
- import flash.utils.setInterval;
+ import flash.utils.clearTimeout;
import flash.utils.setTimeout;
-
+
+ import rtmfp.CirrusSocket;
import rtmfp.RTMFPSocketClient;
+ import rtmfp.events.CirrusSocketEvent;
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=RTMFPSocketEvent.CONNECT_FAILED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.CONNECT_CLOSED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.CONNECT_SUCCESS, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.PEER_CONNECTED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.PEER_DISCONNECTED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.PLAY_STARTED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.PUBLISH_STARTED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
+ [Event(name=RTMFPSocketEvent.PUBLISH_FAILED, type="com.flashproxy.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;
+ {
+ private const CONNECT_TIMEOUT:uint = 10000;
+
+ private var s_c:CirrusSocket;
+
+ private var recv_stream:NetStream;
+ private var send_stream:NetStream;
+
+ private var connect_timeout:int;
+
+ public function RTMFPSocket(s_c:CirrusSocket)
+ {
+ this.s_c = s_c;
+ recv_stream = null;
+ send_stream = null;
+ connect_timeout = 0;
+ }
+
+ /* Tears down this RTMFPSocket, closing both its streams.
+ To be used when destroying this object. If you just want
+ to disconnect from a client, call disconnect() below */
+ public function close():void
+ {
+ if (send_stream != null) {
+ s_c.connection.removeEventListener(NetStatusEvent.NET_STATUS, on_stream_disconnection_event);
+ send_stream.close();
+ }
+
+ if (recv_stream != null) {
+ recv_stream.close();
}
-
- return null;
- }
-
- public function get connected():Boolean
- {
- return (connection != null && connection.connected);
}
- public function readBytes(bytes:ByteArray):void
+ /* In RTMFP, you connect to a remote socket by requesting to
+ "play" the data being published on a named stream by the
+ host identified by id. The connection request goes through
+ the Cirrus server which handles the mapping from id/stream
+ to IP/port and any necessary NAT traversal. */
+ public function connect(id:String, stream:String):void
{
- recvStream.client.bytes.readBytes(bytes);
- }
-
- public function writeBytes(bytes:ByteArray):void
+ recv_stream = new NetStream(s_c.connection, id);
+ var client:RTMFPSocketClient = new RTMFPSocketClient();
+ client.addEventListener(ProgressEvent.SOCKET_DATA, on_data_available, false, 0, true);
+ client.addEventListener(RTMFPSocketClient.CONNECT_ACKNOWLEDGED, on_connect_acknowledged, false, 0, true);
+ recv_stream.client = client;
+ recv_stream.addEventListener(NetStatusEvent.NET_STATUS, on_recv_stream_event);
+ recv_stream.play(stream);
+ connect_timeout = setTimeout(on_connect_timeout, CONNECT_TIMEOUT, recv_stream);
+ }
+
+ public function get connected():Boolean
{
- sendStream.send("dataAvailable", bytes);
- }
-
+ return (recv_stream != null && recv_stream.client != null &&
+ RTMFPSocketClient(recv_stream.client).connect_acknowledged);
+ }
+
+ public function disconnect():void
+ {
+ if (recv_stream != null) {
+ if (recv_stream.client != null) {
+ recv_stream.client.removeEventListener(ProgressEvent.SOCKET_DATA, on_data_available);
+ recv_stream.client.removeEventListener(RTMFPSocketClient.CONNECT_ACKNOWLEDGED, on_connect_acknowledged);
+ }
+ recv_stream.removeEventListener(NetStatusEvent.NET_STATUS, on_recv_stream_event);
+ recv_stream.close();
+ recv_stream = null;
+ }
+ }
+
+ /* In RTMFP, you open a listening socket by publishing a named
+ stream that others can connect to instead of listening on a port.
+ You register this stream with the Cirrus server via the Cirrus
+ socket so that it can redirect connection requests for an id/stream
+ tuple to this socket. */
+ public function listen(stream:String):void
+ {
+ // apparently streams don't get disconnection events, only the NetConnection
+ // object does...bleh.
+ s_c.connection.addEventListener(NetStatusEvent.NET_STATUS, on_stream_disconnection_event);
+
+ send_stream = new NetStream(s_c.connection, NetStream.DIRECT_CONNECTIONS);
+ send_stream.addEventListener(NetStatusEvent.NET_STATUS, on_send_stream_event);
+ var client:Object = new Object();
+ client.onPeerConnect = on_peer_connect;
+ send_stream.client = client;
+ send_stream.publish(stream);
+ }
+
public function get peer():String
{
- return this.peerID;
+ if (!connected) return null;
+ return recv_stream.farID;
}
-
- 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
+
+ public function get peer_connected():Boolean
{
- 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);
+ return send_stream.peerStreams.length > 0;
}
-
- private function fail():void
+
+ public function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void
{
- clearInterval(connectionTimeout);
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAIL));
+ if (recv_stream != null && recv_stream.client != null) {
+ recv_stream.client.bytes.readBytes(bytes, offset, length);
+ }
}
- private function onDataAvailable(event:ProgressEvent):void
- {
- dispatchEvent(event);
- }
- private function onIOErrorEvent(event:IOErrorEvent):void
+ public function writeBytes(bytes:ByteArray):void
{
- fail();
+ if (send_stream != null && peer_connected) {
+ send_stream.send(RTMFPSocketClient.DATA_AVAILABLE, bytes);
+ }
}
-
- private function onNetStatusEvent(event:NetStatusEvent):void
+
+ /* Listens for acknowledgement of a connection attempt to a
+ remote peer. */
+ private function on_connect_acknowledged(event:Event):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;
- }
+ clearTimeout(connect_timeout);
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS, recv_stream));
}
- private function onPeerConnect(peer:NetStream):Boolean
+ /* If we don't get a connection acknowledgement by the time this
+ timeout function is called, we punt. */
+ private function on_connect_timeout(peer:NetStream):void
{
- // establish a bidirectional stream with the peer
- if (peerID == null) {
- this.peer = peer.farID;
+ if (!this.connected) {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_FAILED, recv_stream));
}
-
- // 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
+
+ private function on_data_available(event:ProgressEvent):void
{
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_SUCCESS, recvStream));
+ dispatchEvent(event);
}
-
- private function onPeerConnectTimeout(peer:NetStream):void
+
+ private function on_recv_stream_event(event:NetStatusEvent):void
{
- if (!recvStream.client) return;
- if (!RTMFPSocketClient(recvStream.client).peerConnectAcknowledged) {
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEERING_FAIL, recvStream));
- }
+ /* empty, here for symmetry */
}
- private function onSecurityErrorEvent(event:SecurityErrorEvent):void
+ /* This function gets called whenever someone tries to connect
+ to this socket's send_stream tuple. We don't want multiple
+ peers connecting at once, so we disallow that. The socket
+ acknowledges the connection back to the peer with the
+ SET_CONNECTION_ACKNOWLEDGED message. */
+ private function on_peer_connect(peer:NetStream):Boolean
{
- fail();
+ if (peer_connected) {
+ return false;
+ }
+
+ peer.send(RTMFPSocketClient.SET_CONNECT_ACKNOWLEDGED);
+
+ // need to do this in a timeout so that this function can
+ // return true to finalize the connection before firing the event
+ setTimeout(function (stream:NetStream):void {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_CONNECTED, stream));
+ }, 0, peer);
+
+ return true;
}
-
- private function onSendStreamEvent(event:NetStatusEvent):void
+
+ private function on_send_stream_event(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;
+ case "NetStream.Publish.Start":
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_STARTED));
+ break;
+ case "NetStream.Publish.BadName":
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PUBLISH_FAILED));
+ break;
+ default:
+ break;
}
}
- private function onRecvStreamEvent(event:NetStatusEvent):void
+
+ private function on_stream_disconnection_event(event:NetStatusEvent):void
{
- switch (event.info.code) {
- case ("NetStream.Publish.Start") :
- case ("NetStream.Play.Reset") :
- case ("NetStream.Play.Start") :
- break;
+ if (event.info.code == "NetStream.Connect.Closed") {
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED));
+ //disconnect();
}
}
}
diff --git a/rtmfp/RTMFPSocketClient.as b/rtmfp/RTMFPSocketClient.as
index e2f93ef..7469a53 100644
--- a/rtmfp/RTMFPSocketClient.as
+++ b/rtmfp/RTMFPSocketClient.as
@@ -5,20 +5,20 @@ package rtmfp
import flash.events.ProgressEvent;
import flash.utils.ByteArray;
- [Event(name="peerConnectAcknowledged", type="flash.events.Event")]
+ [Event(name=RTMFPSocketClient.CONNECT_ACKNOWLEDGED, type="flash.events.Event")]
public dynamic class RTMFPSocketClient extends EventDispatcher {
- public static const PEER_CONNECT_ACKNOWLEDGED:String = "peerConnectAcknowledged";
+ public static const DATA_AVAILABLE:String = "data_available";
+ public static const CONNECT_ACKNOWLEDGED:String = "connectAcknowledged";
+ public static const SET_CONNECT_ACKNOWLEDGED:String = "set_connect_acknowledged";
private var _bytes:ByteArray;
- private var _peerID:String;
- private var _peerConnectAcknowledged:Boolean;
+ private var _connect_acknowledged:Boolean;
public function RTMFPSocketClient()
{
super();
_bytes = new ByteArray();
- _peerID = null;
- _peerConnectAcknowledged = false;
+ _connect_acknowledged = false;
}
public function get bytes():ByteArray
@@ -26,32 +26,22 @@ package rtmfp
return _bytes;
}
- public function dataAvailable(bytes:ByteArray):void
+ 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));
}
- public function get peerConnectAcknowledged():Boolean
+ public function get connect_acknowledged():Boolean
{
- return _peerConnectAcknowledged;
+ return _connect_acknowledged;
}
- public function setPeerConnectAcknowledged():void
+ public function set_connect_acknowledged():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;
+ _connect_acknowledged = true;
+ dispatchEvent(new Event(CONNECT_ACKNOWLEDGED));
}
}
}
diff --git a/rtmfp/events/CirrusSocketEvent.as b/rtmfp/events/CirrusSocketEvent.as
new file mode 100644
index 0000000..831ad73
--- /dev/null
+++ b/rtmfp/events/CirrusSocketEvent.as
@@ -0,0 +1,22 @@
+package rtmfp.events
+{
+ import flash.events.Event;
+
+ public class CirrusSocketEvent extends Event
+ {
+ public static const CONNECT_CLOSED:String = "connectClosed";
+ public static const CONNECT_FAILED:String = "connectFailed";
+ public static const CONNECT_SUCCESS:String = "connectSuccess";
+ public static const HELLO_RECEIVED:String = "helloReceived";
+
+ public var peer:String;
+ public var stream:String;
+
+ public function CirrusSocketEvent(type:String, peer:String = null, stream:String = null, bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(type, bubbles, cancelable);
+ this.peer = peer;
+ this.stream = stream;
+ }
+ }
+}
diff --git a/rtmfp/events/FacilitatorSocketEvent.as b/rtmfp/events/FacilitatorSocketEvent.as
new file mode 100644
index 0000000..a0599aa
--- /dev/null
+++ b/rtmfp/events/FacilitatorSocketEvent.as
@@ -0,0 +1,22 @@
+package rtmfp.events
+{
+ import flash.events.Event;
+
+ public class FacilitatorSocketEvent extends Event
+ {
+ public static const CONNECT_CLOSED:String = "connectClosed";
+ public static const CONNECT_FAILED:String = "connectFailed";
+ public static const CONNECT_SUCCESS:String = "connectSuccess";
+ public static const REGISTRATION_RECEIVED:String = "registrationReceived";
+ public static const REGISTRATION_FAILED:String = "registrationFailed";
+ public static const REGISTRATIONS_EMPTY:String = "registrationsEmpty";
+
+ public var client:String;
+
+ public function FacilitatorSocketEvent(type:String, client:String = null, bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(type, bubbles, cancelable);
+ this.client = client;
+ }
+ }
+}
diff --git a/rtmfp/events/RTMFPSocketEvent.as b/rtmfp/events/RTMFPSocketEvent.as
index 5bc08e5..87a7e09 100644
--- a/rtmfp/events/RTMFPSocketEvent.as
+++ b/rtmfp/events/RTMFPSocketEvent.as
@@ -5,20 +5,21 @@ package rtmfp.events
public class RTMFPSocketEvent extends Event
{
+ public static const CONNECT_FAILED:String = "connectFailed";
public static const CONNECT_SUCCESS:String = "connectSuccess";
- public static const CONNECT_FAIL:String = "connectFail";
- public static const PUBLISH_START:String = "publishStart";
+ public static const CONNECT_CLOSED:String = "connectClosed"
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 static const PLAY_STARTED:String = "playStarted";
+ public static const PUBLISH_STARTED:String = "publishStarted";
+ public static const PUBLISH_FAILED:String = "publishFailed";
public var stream:NetStream;
- public function RTMFPSocketEvent(type:String, streamVal:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
+ public function RTMFPSocketEvent(type:String, stream:NetStream = null, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
- stream = streamVal;
+ this.stream = stream;
}
}
}
diff --git a/rtmfpcat.as b/rtmfpcat.as
index d01bb37..866175e 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -5,46 +5,54 @@ package
import flash.display.StageScaleMode;
import flash.text.TextField;
import flash.text.TextFormat;
- 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 flash.utils.clearInterval;
+ import flash.utils.setInterval;
- import rtmfp.RTMFPSocket;
- import rtmfp.events.RTMFPSocketEvent;
+ import rtmfp.CirrusSocket;
+ import rtmfp.FacilitatorSocket;
+ import rtmfp.ProxyPair;
+ import rtmfp.events.CirrusSocketEvent;
+ import rtmfp.events.FacilitatorSocketEvent;
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 */
+ /* Adobe's Cirrus server and Nate's key */
+ private const DEFAULT_CIRRUS_ADDR:String = "rtmfp://p2p.rtmfp.net";
+ private const DEFAULT_CIRRUS_KEY:String = RTMFP::CIRRUS_KEY;
+
+ /* Nate's facilitator -- serves a crossdomain policy */
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
+ };
+
+ /* Poll facilitator every 3 sec if in proxy mode and haven't found
+ anyone to proxy */
+ private const DEFAULT_FAC_POLL_INTERVAL:uint = 3000;
- // Milliseconds.
- private const FACILITATOR_POLL_INTERVAL:int = 10000;
-
+ // Socket to Cirrus server
+ private var s_c:CirrusSocket;
// 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;
+ private var s_f:FacilitatorSocket;
+ // Handle local-remote traffic
+ private var p_p:ProxyPair;
+
+ private var proxy_mode:Boolean;
+
+ private var fac_poll_interval:uint;
/* TextField for debug output. */
private var output_text:TextField;
@@ -52,14 +60,6 @@ package
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.
@@ -72,7 +72,8 @@ package
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);
@@ -82,11 +83,10 @@ package
{
var fac_spec:String;
var tor_spec:String;
-
+
puts("Parameters loaded.");
proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
- addChild(output_text);
fac_spec = this.loaderInfo.parameters["facilitator"];
if (fac_spec) {
@@ -109,10 +109,11 @@ package
return;
}
} else {
- if (proxy_mode)
+ if (proxy_mode) {
tor_addr = DEFAULT_TOR_PROXY_ADDR;
- else
+ } else {
tor_addr = DEFAULT_TOR_CLIENT_ADDR;
+ }
}
main();
@@ -121,105 +122,106 @@ package
/* The main logic begins here, after start-up issues are taken care of. */
private function main():void
{
- establishRTMFPConnection();
+ establish_cirrus_connection();
}
- private function establishRTMFPConnection():void
+ private function establish_cirrus_connection():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_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();
+ }
});
- s_r.addEventListener(RTMFPSocketEvent.CONNECT_FAIL, function (e:Event):void {
+ s_c.addEventListener(CirrusSocketEvent.CONNECT_FAILED, function (e:CirrusSocketEvent):void {
puts("Error: failed to connect to Cirrus.");
});
- s_r.addEventListener(RTMFPSocketEvent.PUBLISH_START, function(e:RTMFPSocketEvent):void {
- puts("Publishing started.");
+ s_c.addEventListener(CirrusSocketEvent.CONNECT_CLOSED, function (e:CirrusSocketEvent):void {
+ puts("Cirrus: closed connection.");
});
- 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_c.addEventListener(CirrusSocketEvent.HELLO_RECEIVED, function (e:CirrusSocketEvent):void {
+ puts("Cirrus: received hello from peer " + e.peer);
+
+ /* don't bother if we already have a proxy going */
+ if (p_p != null && p_p.connected) {
+ return;
+ }
+
+ /* if we're in proxy mode, we should have already set
+ up a proxy pair */
+ if (!proxy_mode) {
+ start_proxy_pair();
+ s_c.send_hello(e.peer);
+ }
+ p_p.connect(e.peer, e.stream);
});
-
- s_r.connect();
+
+ s_c.connect(DEFAULT_CIRRUS_ADDR, DEFAULT_CIRRUS_KEY);
}
- private function establishTorConnection():void
+ private function establish_facilitator_connection():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_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_t.connect(tor_addr.host, tor_addr.port);
+ s_f.addEventListener(FacilitatorSocketEvent.CONNECT_FAILED, function (e:Event):void {
+ puts("Facilitator: connect failed.");
+ });
+ 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 {
+ 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.");
+ });
+ } else {
+ s_f.addEventListener(FacilitatorSocketEvent.REGISTRATION_FAILED, function (e:Event):void {
+ puts("Facilitator: registration failed.");
+ });
+ }
+ s_f.connect(fac_addr.host, fac_addr.port);
}
-
- private function establishFacilitatorConnection():void
+
+ private function start_proxy_pair():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.");
+ 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.addEventListener(Event.CONNECT, function (e:Event):void {
+ puts("ProxyPair: connected!");
+ });
+ p_p.addEventListener(Event.CLOSE, function (e:Event):void {
+ puts("ProxyPair: connection closed.");
+ p_p = null;
if (proxy_mode) {
- setTimeout(establishFacilitatorConnection, FACILITATOR_POLL_INTERVAL);
+ fac_poll_interval = setInterval(establish_facilitator_connection, DEFAULT_FAC_POLL_INTERVAL);
+ } else {
+ establish_facilitator_connection();
}
});
- 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);
+ p_p.listen(s_c.local_stream_name);
}
/* 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
+ private function parse_addr_spec(spec:String):Object
{
var parts:Array;
var addr:Object;
@@ -233,5 +235,11 @@ package
return addr;
}
+
+ public function puts(s:String):void
+ {
+ output_text.appendText(s + "\n");
+ output_text.scrollV = output_text.maxScrollV;
+ }
}
}
1
0

[flashproxy/master] Attempted to fix stream disconnection notification, also trying to fix whitespace
by dcf@torproject.org 12 Jun '11
by dcf@torproject.org 12 Jun '11
12 Jun '11
commit 60e2c5afa70435c9f336bf33097717ff24573515
Author: Nate Hardison <nate(a)rescomp-09-154551.stanford.edu>
Date: Thu Jun 2 10:50:09 2011 -0700
Attempted to fix stream disconnection notification, also trying to fix whitespace
---
rtmfp/CirrusSocket.as | 28 +++++++++++++-------------
rtmfp/RTMFPSocket.as | 53 +++++++++++++++++++++++++-----------------------
rtmfpcat.as | 3 ++
3 files changed, 45 insertions(+), 39 deletions(-)
diff --git a/rtmfp/CirrusSocket.as b/rtmfp/CirrusSocket.as
index 9e97c7d..071ac0d 100644
--- a/rtmfp/CirrusSocket.as
+++ b/rtmfp/CirrusSocket.as
@@ -31,10 +31,10 @@ package rtmfp
{
private static const CONNECT_TIMEOUT:uint = 4000; // in milliseconds
- /* We'll append a unique number to the DATA_STREAM_PREFIX for each
+ /* We'll append a unique number to the DATA_STREAM_PREFIX for each
new stream we create so that we have unique streams per player. */
private static const DATA_STREAM_PREFIX:String = "DATA";
- private var data_stream_suffix:uint = 0;
+ private var data_stream_suffix:uint = 0;
/* Connection to the Cirrus rendezvous service */
public var connection:NetConnection;
@@ -94,18 +94,18 @@ package rtmfp
return DATA_STREAM_PREFIX + data_stream_suffix;
}
- /* Sends a hello message to the Flash player with Cirrus ID "id"
- We use this new call protocol outlined here:
- http://forums.adobe.com/thread/780788?tstart=0 */
- public function send_hello(id:String):void
- {
- if (this.connected) {
- connection.call("relay", null, id, local_stream_name);
- } else {
- throw new Error("Cannot send hello: Cirrus socket not connected.");
- }
- }
-
+ /* Sends a hello message to the Flash player with Cirrus ID "id"
+ We use this new call protocol outlined here:
+ http://forums.adobe.com/thread/780788?tstart=0 */
+ public function send_hello(id:String):void
+ {
+ if (this.connected) {
+ connection.call("relay", null, id, local_stream_name);
+ } else {
+ throw new Error("Cannot send hello: Cirrus socket not connected.");
+ }
+ }
+
/*************************** PRIVATE HELPER FUNCTIONS *************************/
private function fail():void
diff --git a/rtmfp/RTMFPSocket.as b/rtmfp/RTMFPSocket.as
index 6e9a45e..bcbee67 100644
--- a/rtmfp/RTMFPSocket.as
+++ b/rtmfp/RTMFPSocket.as
@@ -27,26 +27,28 @@ package rtmfp
[Event(name=RTMFPSocketEvent.PUBLISH_FAILED, type="com.flashproxy.rtmfp.events.RTMFPSocketEvent")]
public class RTMFPSocket extends EventDispatcher
{
- private const CONNECT_TIMEOUT:uint = 10000;
+ private const CONNECT_TIMEOUT:uint = 10000;
private var s_c:CirrusSocket;
- private var recv_stream:NetStream;
+ private var recv_stream:NetStream;
private var send_stream:NetStream;
- private var connect_timeout:int;
+ private var peer_stream:NetStream;
+
+ private var connect_timeout:int;
public function RTMFPSocket(s_c:CirrusSocket)
{
this.s_c = s_c;
recv_stream = null;
- send_stream = null;
- connect_timeout = 0;
+ send_stream = null;
+ connect_timeout = 0;
}
- /* Tears down this RTMFPSocket, closing both its streams.
- To be used when destroying this object. */
- public function close():void
+ /* Tears down this RTMFPSocket, closing both its streams.
+ To be used when destroying this object. */
+ public function close():void
{
if (send_stream != null) {
s_c.connection.removeEventListener(NetStatusEvent.NET_STATUS, on_stream_disconnection_event);
@@ -81,23 +83,23 @@ package rtmfp
RTMFPSocketClient(recv_stream.client).connect_acknowledged);
}
- /* In RTMFP, you open a listening socket by publishing a named
+ /* In RTMFP, you open a listening socket by publishing a named
stream that others can connect to instead of listening on a port.
You register this stream with the Cirrus server via the Cirrus
socket so that it can redirect connection requests for an id/stream
tuple to this socket. */
public function listen(stream:String):void
{
- // apparently streams don't get disconnection events, only the NetConnection
- // object does...bleh.
- s_c.connection.addEventListener(NetStatusEvent.NET_STATUS, on_stream_disconnection_event);
+ // apparently streams don't get disconnection events, only the NetConnection
+ // object does...bleh.
+ s_c.connection.addEventListener(NetStatusEvent.NET_STATUS, on_stream_disconnection_event);
send_stream = new NetStream(s_c.connection, NetStream.DIRECT_CONNECTIONS);
- send_stream.addEventListener(NetStatusEvent.NET_STATUS, on_send_stream_event);
- var client:Object = new Object();
- client.onPeerConnect = on_peer_connect;
- send_stream.client = client;
- send_stream.publish(stream);
+ send_stream.addEventListener(NetStatusEvent.NET_STATUS, on_send_stream_event);
+ var client:Object = new Object();
+ client.onPeerConnect = on_peer_connect;
+ send_stream.client = client;
+ send_stream.publish(stream);
}
public function get peer():String
@@ -113,16 +115,16 @@ package rtmfp
public function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void
{
- if (recv_stream != null && recv_stream.client != null) {
- recv_stream.client.bytes.readBytes(bytes, offset, length);
- }
+ if (recv_stream != null && recv_stream.client != null) {
+ recv_stream.client.bytes.readBytes(bytes, offset, length);
+ }
}
public function writeBytes(bytes:ByteArray):void
{
if (send_stream != null && peer_connected) {
- send_stream.send(RTMFPSocketClient.DATA_AVAILABLE, bytes);
- }
+ send_stream.send(RTMFPSocketClient.DATA_AVAILABLE, bytes);
+ }
}
/* Listens for acknowledgement of a connection attempt to a
@@ -130,7 +132,7 @@ package rtmfp
private function on_connect_acknowledged(event:Event):void
{
clearTimeout(connect_timeout);
- dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS, recv_stream));
+ dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.CONNECT_SUCCESS, recv_stream));
}
/* If we don't get a connection acknowledgement by the time this
@@ -163,6 +165,7 @@ package rtmfp
return false;
}
+ peer_stream = peer;
peer.send(RTMFPSocketClient.SET_CONNECT_ACKNOWLEDGED);
// need to do this in a timeout so that this function can
@@ -190,10 +193,10 @@ package rtmfp
private function on_stream_disconnection_event(event:NetStatusEvent):void
{
- if (event.info.code == "NetStream.Connect.Closed") {
+ if (event.info.code == "NetStream.Connect.Closed" && event.info.stream === peer_stream) {
dispatchEvent(new RTMFPSocketEvent(RTMFPSocketEvent.PEER_DISCONNECTED));
- //disconnect();
}
}
}
}
+
diff --git a/rtmfpcat.as b/rtmfpcat.as
index 866175e..25099dd 100644
--- a/rtmfpcat.as
+++ b/rtmfpcat.as
@@ -49,6 +49,8 @@ package
private var s_f:FacilitatorSocket;
// Handle local-remote traffic
private var p_p:ProxyPair;
+
+ private var proxy_pairs:Array;
private var proxy_mode:Boolean;
@@ -87,6 +89,7 @@ package
puts("Parameters loaded.");
proxy_mode = (this.loaderInfo.parameters["proxy"] != null);
+ proxy_pairs = new Array();
fac_spec = this.loaderInfo.parameters["facilitator"];
if (fac_spec) {
1
0