<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: A Better Erlang TCP listening pattern: addressing the fast packet loss problem</title>
	<atom:link href="http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/feed/" rel="self" type="application/rss+xml" />
	<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/</link>
	<description>He just never stops talking</description>
	<lastBuildDate>Fri, 16 Dec 2011 00:30:46 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
	<item>
		<title>By: links for 2010-05-23 &#171; Donghai Ma</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-18566</link>
		<dc:creator>links for 2010-05-23 &#171; Donghai Ma</dc:creator>
		<pubDate>Mon, 24 May 2010 04:03:22 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-18566</guid>
		<description>[...] A Better Erlang TCP listening pattern: addressing the fast packet loss problem &#124; John Haugeland is F... (tags: erlang networking tcp programming pattern protocol) [...]</description>
		<content:encoded><![CDATA[<p>[...] A Better Erlang TCP listening pattern: addressing the fast packet loss problem | John Haugeland is F&#8230; (tags: erlang networking tcp programming pattern protocol) [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John Haugeland</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-964</link>
		<dc:creator>John Haugeland</dc:creator>
		<pubDate>Mon, 02 Feb 2009 03:46:27 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-964</guid>
		<description>Steve Vinoski&#039;s fixes are now implemented.  Not sure why it took me so long.</description>
		<content:encoded><![CDATA[<p>Steve Vinoski&#8217;s fixes are now implemented.  Not sure why it took me so long.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John Haugeland</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-955</link>
		<dc:creator>John Haugeland</dc:creator>
		<pubDate>Sat, 24 Jan 2009 00:21:30 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-955</guid>
		<description>Maxim: I agree and I disagree.

I disagree on grounds that it is possible to write software in Erlang without this vulnerability.  Primarily I consider this a documentation defect; someone which knew about this problem would not have an issue.

However, I agree, this is an unacceptable current threat level.  That&#039;s why I wrote a library fix. :D~</description>
		<content:encoded><![CDATA[<p>Maxim: I agree and I disagree.</p>
<p>I disagree on grounds that it is possible to write software in Erlang without this vulnerability.  Primarily I consider this a documentation defect; someone which knew about this problem would not have an issue.</p>
<p>However, I agree, this is an unacceptable current threat level.  That&#8217;s why I wrote a library fix. <img src='http://fullof.bs/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ~</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Maxim</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-956</link>
		<dc:creator>Maxim</dc:creator>
		<pubDate>Fri, 23 Jan 2009 15:00:25 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-956</guid>
		<description>To address the described issue (which is real) in my Erlang implementation I removed the possibility of changing the controlling process completely. There is just no controlling_process() call. The process which accepts the socket has to handle it all the way down to closure.

I think it is intolerable for such a robust system as Erlang to drop a few packets now and then.</description>
		<content:encoded><![CDATA[<p>To address the described issue (which is real) in my Erlang implementation I removed the possibility of changing the controlling process completely. There is just no controlling_process() call. The process which accepts the socket has to handle it all the way down to closure.</p>
<p>I think it is intolerable for such a robust system as Erlang to drop a few packets now and then.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Steve Vinoski</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-957</link>
		<dc:creator>Steve Vinoski</dc:creator>
		<pubDate>Thu, 01 Jan 2009 21:33:13 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-957</guid>
		<description>@John: the fix you made has some problems. First, it doesn&#039;t compile because controlling_process comes from the gen_tcp module, so you need to prefix the call with that module name. Second, the process that controls the socket is the only one that can call controlling_process to change ownership, so it can&#039;t be done where you put it.

Two other existing issues are: 1) closing the listening socket sends the accepting process into a tight CPU-eating loop because the closed condition is treated just as any other error, looping back to do another accept, and 2) it would be nice to be able to pass port 0 to the listener to have it open an ephemeral port and then have that port number returned to the caller (this helps make it easier to test, for one thing).

Find a patch for all these issues below.

Also, here&#039;s a test program. Apply the patch, then comment out the call to gen_tcp:controlling_process/2 to simulate svn version 98 of your code. Then compile everything and run the test, like this:

t:test().

It will work for the first case (the {active, false} case) only. Restore the call to gen_tcp:controlling_process/2 and recompile, then retry the test. All cases will then work fine. This is why I think your original code never worked. Here&#039;s the test code, feel free to use it as you like.

===================
-module(t).
-export([test/0, test/1]).
-author(&quot;Steve Vinoski &quot;).

test() -&gt;
    lists:map(fun test/1, [false, once, true]).

test(Active) -&gt;
    Self = self(),
    {ok, Pid, Port} = scutil:standard_listener(
                        fun(S, Opts) -&gt;
                                case proplists:get_value(active, Opts) of
                                    false -&gt;
                                        Msg = gen_tcp:recv(S, 14, 2000),
                                        io:format(&quot;active(false) handler received ~p~n&quot;, [Msg]);
                                    A -&gt;
                                        receive
                                            Msg -&gt;
                                                io:format(&quot;active(~p) handler msg: ~p~n&quot;, [A, Msg])
                                        after 2000 -&gt;
                                                io:format(&quot;active(~p) handler timed out~n&quot;, [A])
                                        end
                                end,
                                Self ! done,
                                exit(normal)
                        end, 0, [{packet, raw}, binary, {active, Active}]),
    {ok, P} = gen_tcp:connect(&quot;localhost&quot;, Port, [{packet, raw}, binary]),
    gen_tcp:send(P, &lt;&gt;),
    receive
        done -&gt; Pid ! terminate
    after 10000 -&gt; timeout
    end.
===================

And here&#039;s the patch:


Index: scutil.erl
===================================================================
--- scutil.erl	(revision 100)
+++ scutil.erl	(working copy)
@@ -2662,7 +2662,7 @@



-%% @spec standard_listener(Handler, Port, SocketOptions) -&gt; { ok, WorkerPid } &#124; { error, E }
+%% @spec standard_listener(Handler, Port, SocketOptions) -&gt; { ok, WorkerPid, ListeningPort } &#124; { error, E }

 %% @doc {@section Network} Listens on a socket and manages the fast packet loss problem.
 %%
@@ -2688,7 +2688,11 @@
     case gen_tcp:listen(Port, FixedOptions) of

         { ok, ListeningSocket } -&gt;
-            { ok, spawn(?MODULE, standard_listener_controller, [Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, 0]) };
+            ListeningPort = case Port of
+                                0 -&gt; {ok, LP} = inet:port(ListeningSocket), LP;
+                                _ -&gt; Port
+                            end,
+            { ok, spawn(?MODULE, standard_listener_controller, [Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, 0]), ListeningPort };

         { error, E } -&gt;
             { error, E }
@@ -2741,9 +2745,13 @@

         { ok, ConnectedSocket } -&gt;
             Controller ! serviced,
-            spawn(?MODULE, standard_listener_shunt, [Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus]),
+            Pid = spawn(?MODULE, standard_listener_shunt, [Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus]),
+            gen_tcp:controlling_process(ConnectedSocket, Pid),
             standard_listener_accept_loop(Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, Controller);

+        { error, closed } -&gt;
+            closed;
+
         { error, _E } -&gt;
             standard_listener_accept_loop(Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, Controller)

@@ -2757,7 +2765,6 @@

 standard_listener_shunt(Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus) -&gt;

-    controlling_process(ConnectedSocket, self()),
     CollectedOptions = proplists:delete(active, FixedOptions) ++ [{active, ActiveStatus}, {from_port, Port}],

     case ActiveStatus of</description>
		<content:encoded><![CDATA[<p>@John: the fix you made has some problems. First, it doesn&#8217;t compile because controlling_process comes from the gen_tcp module, so you need to prefix the call with that module name. Second, the process that controls the socket is the only one that can call controlling_process to change ownership, so it can&#8217;t be done where you put it.</p>
<p>Two other existing issues are: 1) closing the listening socket sends the accepting process into a tight CPU-eating loop because the closed condition is treated just as any other error, looping back to do another accept, and 2) it would be nice to be able to pass port 0 to the listener to have it open an ephemeral port and then have that port number returned to the caller (this helps make it easier to test, for one thing).</p>
<p>Find a patch for all these issues below.</p>
<p>Also, here&#8217;s a test program. Apply the patch, then comment out the call to gen_tcp:controlling_process/2 to simulate svn version 98 of your code. Then compile everything and run the test, like this:</p>
<p>t:test().</p>
<p>It will work for the first case (the {active, false} case) only. Restore the call to gen_tcp:controlling_process/2 and recompile, then retry the test. All cases will then work fine. This is why I think your original code never worked. Here&#8217;s the test code, feel free to use it as you like.</p>
<p>===================<br />
-module(t).<br />
-export([test/0, test/1]).<br />
-author(&#8220;Steve Vinoski &#8220;).</p>
<p>test() -&gt;<br />
    lists:map(fun test/1, [false, once, true]).</p>
<p>test(Active) -&gt;<br />
    Self = self(),<br />
    {ok, Pid, Port} = scutil:standard_listener(<br />
                        fun(S, Opts) -&gt;<br />
                                case proplists:get_value(active, Opts) of<br />
                                    false -&gt;<br />
                                        Msg = gen_tcp:recv(S, 14, 2000),<br />
                                        io:format(&#8220;active(false) handler received ~p~n&#8221;, [Msg]);<br />
                                    A -&gt;<br />
                                        receive<br />
                                            Msg -&gt;<br />
                                                io:format(&#8220;active(~p) handler msg: ~p~n&#8221;, [A, Msg])<br />
                                        after 2000 -&gt;<br />
                                                io:format(&#8220;active(~p) handler timed out~n&#8221;, [A])<br />
                                        end<br />
                                end,<br />
                                Self ! done,<br />
                                exit(normal)<br />
                        end, 0, [{packet, raw}, binary, {active, Active}]),<br />
    {ok, P} = gen_tcp:connect(&#8220;localhost&#8221;, Port, [{packet, raw}, binary]),<br />
    gen_tcp:send(P, &lt;&gt;),<br />
    receive<br />
        done -&gt; Pid ! terminate<br />
    after 10000 -&gt; timeout<br />
    end.<br />
===================</p>
<p>And here&#8217;s the patch:</p>
<p>Index: scutil.erl<br />
===================================================================<br />
&#8212; scutil.erl	(revision 100)<br />
+++ scutil.erl	(working copy)<br />
@@ -2662,7 +2662,7 @@</p>
<p>-%% @spec standard_listener(Handler, Port, SocketOptions) -&gt; { ok, WorkerPid } | { error, E }<br />
+%% @spec standard_listener(Handler, Port, SocketOptions) -&gt; { ok, WorkerPid, ListeningPort } | { error, E }</p>
<p> %% @doc {@section Network} Listens on a socket and manages the fast packet loss problem.<br />
 %%<br />
@@ -2688,7 +2688,11 @@<br />
     case gen_tcp:listen(Port, FixedOptions) of</p>
<p>         { ok, ListeningSocket } -&gt;<br />
-            { ok, spawn(?MODULE, standard_listener_controller, [Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, 0]) };<br />
+            ListeningPort = case Port of<br />
+                                0 -&gt; {ok, LP} = inet:port(ListeningSocket), LP;<br />
+                                _ -&gt; Port<br />
+                            end,<br />
+            { ok, spawn(?MODULE, standard_listener_controller, [Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, 0]), ListeningPort };</p>
<p>         { error, E } -&gt;<br />
             { error, E }<br />
@@ -2741,9 +2745,13 @@</p>
<p>         { ok, ConnectedSocket } -&gt;<br />
             Controller ! serviced,<br />
-            spawn(?MODULE, standard_listener_shunt, [Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus]),<br />
+            Pid = spawn(?MODULE, standard_listener_shunt, [Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus]),<br />
+            gen_tcp:controlling_process(ConnectedSocket, Pid),<br />
             standard_listener_accept_loop(Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, Controller);</p>
<p>+        { error, closed } -&gt;<br />
+            closed;<br />
+<br />
         { error, _E } -&gt;<br />
             standard_listener_accept_loop(Handler, Port, FixedOptions, ListeningSocket, ActiveStatus, Controller)</p>
<p>@@ -2757,7 +2765,6 @@</p>
<p> standard_listener_shunt(Handler, Port, FixedOptions, ConnectedSocket, ActiveStatus) -&gt;</p>
<p>-    controlling_process(ConnectedSocket, self()),<br />
     CollectedOptions = proplists:delete(active, FixedOptions) ++ [{active, ActiveStatus}, {from_port, Port}],</p>
<p>     case ActiveStatus of</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John Haugeland</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-963</link>
		<dc:creator>John Haugeland</dc:creator>
		<pubDate>Thu, 01 Jan 2009 18:56:18 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-963</guid>
		<description>How odd.  It works fine in the shell at this end.

Either way, fixed in Version 99.  You&#039;re added to the thanks table in Version 100.</description>
		<content:encoded><![CDATA[<p>How odd.  It works fine in the shell at this end.</p>
<p>Either way, fixed in Version 99.  You&#8217;re added to the thanks table in Version 100.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Steve Vinoski</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-962</link>
		<dc:creator>Steve Vinoski</dc:creator>
		<pubDate>Thu, 01 Jan 2009 18:53:21 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-962</guid>
		<description>@John: it doesn&#039;t work for me. If I set {active, false} then my handler works fine, but for once or true settings messages go to the accepting process, which I verified by doing a timed receive at the top of the listen_loop and putting a timeout on accept to force loop recursion. When active is once or false, the listening loop gets the message intended for the handler, while the handler&#039;s receive times out.

The inet:setopts documentation says nothing about transferring socket ownership, and a quick look through the R12B-5 sources doesn&#039;t seem to show any ownership transfer in inet:setopts or anything it calls.</description>
		<content:encoded><![CDATA[<p>@John: it doesn&#8217;t work for me. If I set {active, false} then my handler works fine, but for once or true settings messages go to the accepting process, which I verified by doing a timed receive at the top of the listen_loop and putting a timeout on accept to force loop recursion. When active is once or false, the listening loop gets the message intended for the handler, while the handler&#8217;s receive times out.</p>
<p>The inet:setopts documentation says nothing about transferring socket ownership, and a quick look through the R12B-5 sources doesn&#8217;t seem to show any ownership transfer in inet:setopts or anything it calls.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John Haugeland</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-961</link>
		<dc:creator>John Haugeland</dc:creator>
		<pubDate>Thu, 01 Jan 2009 18:35:05 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-961</guid>
		<description>Mr Vinoski: I was under the impression that setting inet options implicitly made another process the controlling process.  It&#039;s worth noting that the code does, in fact, work.

However, for the sake of writing explicit code, I will update both the example and the library code.</description>
		<content:encoded><![CDATA[<p>Mr Vinoski: I was under the impression that setting inet options implicitly made another process the controlling process.  It&#8217;s worth noting that the code does, in fact, work.</p>
<p>However, for the sake of writing explicit code, I will update both the example and the library code.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John Haugeland</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-960</link>
		<dc:creator>John Haugeland</dc:creator>
		<pubDate>Thu, 01 Jan 2009 18:33:39 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-960</guid>
		<description>Mr Parish: Yes, I suppose that could work.</description>
		<content:encoded><![CDATA[<p>Mr Parish: Yes, I suppose that could work.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Steve Vinoski</title>
		<link>http://fullof.bs/a-better-erlang-tcp-listening-pattern-addressingthe-fast-packet-loss-problem/comment-page-1/#comment-959</link>
		<dc:creator>Steve Vinoski</dc:creator>
		<pubDate>Thu, 01 Jan 2009 18:26:54 +0000</pubDate>
		<guid isPermaLink="false">http://fullof.bs/?p=466#comment-959</guid>
		<description>Unless I&#039;m missing something, if active is originally specified as anything but false, then the handler will never receive any messages because you never make it the controlling process.</description>
		<content:encoded><![CDATA[<p>Unless I&#8217;m missing something, if active is originally specified as anything but false, then the handler will never receive any messages because you never make it the controlling process.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

