1
0
mirror of https://github.com/ubf/ubf.git synced 2026-05-01 00:59:42 +00:00

GMT BZ29373: fix race condition just after connection establishment

The ubf listener has a window for a possible race condition just after
connection establishment.  TCP/IP data sent by the client can be
ignored before the contract driver process has been completely
initialized.  For normal ubf client and server interaction, this race
condition is not visiable due to the inherit network latency and to
client that is initially busy reading the server hello before sending
it's first request to the server.
This commit is contained in:
Joseph Wayne Norton
2010-11-10 11:25:10 +09:00
parent 5e5f157a4d
commit 59e4575f10
3 changed files with 42 additions and 37 deletions

View File

@@ -1,3 +1,7 @@
2010-11-10 11:30 JST norton
* src/contract_driver.erl, src/proc_socket_server.erl: Fix race
condition just after connection establishment.
2010-10-23 17:00 JST norton
* src/ubf.erl: Various fixes for UBF(a) decoder.

View File

@@ -31,6 +31,7 @@ loop(Module, Contract, Pid, Socket) ->
loop(Module, Contract, Pid, Socket, 16#ffffffff).
loop(Module, Contract, Pid, Socket, Timeout) ->
inet:setopts(Socket, [{active, true}]),
put('ubf_socket', Socket),
Cont = Module:init(Contract),
loop(Module, Contract, Pid, Socket, Timeout, Cont).

View File

@@ -59,8 +59,8 @@ start_raw_server(Name, Port, Max, SpawnOpts, Fun, PacketType, PacketSize) ->
undefined ->
Parent = self(),
Pid = erlang:spawn_opt(?MODULE, cold_start,
[Parent, Name, Port, Max, Fun, PacketType, PacketSize],
[link | SpawnOpts]),
[Parent, Name, Port, Max, Fun, PacketType, PacketSize],
[link | SpawnOpts]),
{ok, Pid};
_Pid ->
false
@@ -77,7 +77,7 @@ stop_server(Name) ->
undefined ->
ok;
Pid ->
ok = stop_server(Pid),
ok = stop_server(Pid),
(catch unregister(Name)),
ok
end.
@@ -89,20 +89,20 @@ server_port(Name) ->
server_port(Pid, Timeout) when is_pid(Pid) ->
Pid ! {port, self()},
receive
{Pid, Reply} ->
Reply
{Pid, Reply} ->
Reply
after Timeout ->
timeout
timeout
end;
server_port(Port, Timeout) when is_integer(Port) ->
Name = port_name(Port),
server_port(Name, Timeout);
server_port(Name, Timeout) ->
case whereis(Name) of
undefined ->
retrylater;
Pid ->
server_port(Pid, Timeout)
undefined ->
retrylater;
Pid ->
server_port(Pid, Timeout)
end.
@@ -112,20 +112,20 @@ server_status(Name) ->
server_status(Pid, Timeout) when is_pid(Pid) ->
Pid ! {status, self()},
receive
{Pid, Reply} ->
Reply
{Pid, Reply} ->
Reply
after Timeout ->
timeout
timeout
end;
server_status(Port, Timeout) when is_integer(Port) ->
Name = port_name(Port),
server_status(Name, Timeout);
server_status(Name, Timeout) ->
case whereis(Name) of
undefined ->
retrylater;
Pid ->
server_status(Pid, Timeout)
undefined ->
retrylater;
Pid ->
server_status(Pid, Timeout)
end.
@@ -135,27 +135,27 @@ server_children(Name) ->
server_children(Pid, Timeout) when is_pid(Pid) ->
Pid ! {children, self()},
receive
{Pid, Reply} ->
Reply
{Pid, Reply} ->
Reply
after Timeout ->
timeout
timeout
end;
server_children(Port, Timeout) when is_integer(Port) ->
Name = port_name(Port),
server_children(Name, Timeout);
server_children(Name, Timeout) ->
case whereis(Name) of
undefined ->
retrylater;
Pid ->
server_children(Pid, Timeout)
undefined ->
retrylater;
Pid ->
server_children(Pid, Timeout)
end.
cold_start(Parent, Name, Port, Max, Fun, PacketType, PacketSize) ->
process_flag(trap_exit, true),
DefaultListenOptions =
[binary, {nodelay, true}, {active, true}, {reuseaddr, true}, {backlog, 4096}],
[binary, {nodelay, true}, {active, false}, {reuseaddr, true}, {backlog, 4096}],
ListenOptions =
case {PacketType, PacketSize} of
{0,0} ->
@@ -168,13 +168,13 @@ cold_start(Parent, Name, Port, Max, Fun, PacketType, PacketSize) ->
DefaultListenOptions++[{packet,T}, {packet_size,S}]
end,
{ok, Listen} = gen_tcp:listen(Port, ListenOptions),
RegisterName =
if Name =/= undefined ->
Name;
true ->
{ok, RealPort} = inet:port(Listen),
port_name(RealPort)
end,
RegisterName =
if Name =/= undefined ->
Name;
true ->
{ok, RealPort} = inet:port(Listen),
port_name(RealPort)
end,
register(RegisterName, self()),
New = start_accept(Listen, Fun),
socket_loop(Parent, Listen, New, [], 0, Max, Fun).
@@ -200,7 +200,7 @@ socket_loop(Parent, Listen, New, Active, Num, Max, Fun) ->
Active1 = lists:delete(Pid, Active),
possibly_start_another(Parent, New, Listen, Active1, length(Active1), Max, Fun);
{port, From} ->
{ok, Port} = inet:port(Listen),
{ok, Port} = inet:port(Listen),
From ! {self(), Port},
socket_loop(Parent, Listen, New, Active, Num, Max, Fun);
{status, From} ->
@@ -210,8 +210,8 @@ socket_loop(Parent, Listen, New, Active, Num, Max, Fun) ->
From ! {self(), Active},
socket_loop(Parent, Listen, New, Active, Num, Max, Fun);
Other ->
io:format("*** YY Socket loop dropping:~p~n", [Other]),
socket_loop(Parent, Listen, New, Active, Num, Max, Fun)
io:format("*** YY Socket loop dropping:~p~n", [Other]),
socket_loop(Parent, Listen, New, Active, Num, Max, Fun)
end.
@@ -234,8 +234,8 @@ start_accept(Listen, Fun) ->
start_child(Parent, Listen, Fun) ->
case gen_tcp:accept(Listen) of
{ok, Socket} ->
Parent ! {started, self()}, % tell the controller
inet:setopts(Socket, [{active, true}]), % before we activate socket
%% Kick off the parent
Parent ! {started, self()},
%% Start the child
case (catch Fun(Socket)) of
{'EXIT', normal} ->