mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-17 01:26:25 +00:00
89 lines
3.7 KiB
Erlang
89 lines
3.7 KiB
Erlang
|
%%% Manager is a process that reads commands from a telnet-like
|
||
|
%%% socket, primarily to add mungers to the Registry under control of
|
||
|
%%% a test (though it could be more generally anything).
|
||
|
|
||
|
-module(manager).
|
||
|
-export([start/2,accept_loop/2,recv_loop/2]).
|
||
|
-import(gen_tcp, [listen/2, accept/1, recv/2, send/2]).
|
||
|
-import(string, [cspan/2, substr/3]).
|
||
|
|
||
|
start(Port, Config) ->
|
||
|
{ok, LSock} = listen(Port, [{packet,line},
|
||
|
{active,false},{reuseaddr,true}]),
|
||
|
Pid = spawn(?MODULE, accept_loop, [LSock, Config]),
|
||
|
ok = gen_tcp:controlling_process(LSock, Pid).
|
||
|
|
||
|
accept_loop(LSock, Config) ->
|
||
|
{ok, Sock} = accept(LSock),
|
||
|
spawn(?MODULE, recv_loop, [Sock, Config]),
|
||
|
accept_loop(LSock, Config).
|
||
|
|
||
|
recv_loop(Sock, Config) ->
|
||
|
case recv(Sock, 0) of
|
||
|
{ok, Msg} ->
|
||
|
%%
|
||
|
%% Take the input, strip off CRLF, slap on a dot so as to
|
||
|
%% make it nice for Erlang parser.
|
||
|
%%
|
||
|
ValidInput = lists:append(substr(Msg, 1, cspan(Msg, "\r\n")),
|
||
|
"."),
|
||
|
{ok,Tokens,_} = erl_scan:string(ValidInput),
|
||
|
{ok, Result} = erl_parse:parse_term(Tokens),
|
||
|
case Result of
|
||
|
{Path, shutdown} ->
|
||
|
%%
|
||
|
%% TODO: I think maybe instead of this, the path_mgr should be told
|
||
|
%% to do the actual socket closing. Then we wouldn't even need
|
||
|
%% the registry to know about the sockets at all.
|
||
|
%%
|
||
|
{ok, {_,_,PathSock,PathFwdSock,_}} = registry:lookup(Path),
|
||
|
gen_tcp:close(PathSock),
|
||
|
gen_tcp:close(PathFwdSock);
|
||
|
shutdown ->
|
||
|
send(Sock, "ok\r\n"),
|
||
|
halt(); % first try is rather crude
|
||
|
{config,Real} ->
|
||
|
send(Sock,
|
||
|
integer_to_list(
|
||
|
case lists:keysearch(Real, 2, Config) of
|
||
|
{value,{Spoof,Real}} -> Spoof;
|
||
|
false -> Real
|
||
|
end)),
|
||
|
send(Sock, "\r\n");
|
||
|
list ->
|
||
|
lists:foreach(fun ({Id,Path,_,_,_}) ->
|
||
|
{From,To} = Path,
|
||
|
send(Sock, integer_to_list(Id)),
|
||
|
send(Sock, " {"),
|
||
|
send(Sock, integer_to_list(From)),
|
||
|
send(Sock, ","),
|
||
|
send(Sock, integer_to_list(To)),
|
||
|
send(Sock, "}\r\n")
|
||
|
end, registry:all());
|
||
|
{Path, Command} ->
|
||
|
{ok, {_,_,_,_,Process}} = registry:lookup(Path),
|
||
|
path_mgr:update(Process, Path, Command);
|
||
|
|
||
|
Command ->
|
||
|
%%
|
||
|
%% Each half of a bidirectional path gets
|
||
|
%% registered to the same path_mgr process. So we
|
||
|
%% end up with duplicates if we just look at the list
|
||
|
%% of Pids.
|
||
|
%%
|
||
|
All = registry:all(),
|
||
|
AllPids = lists:map(fun (X) -> element(5, X) end, All),
|
||
|
DistinctPids = lists:usort(AllPids),
|
||
|
lists:foreach(fun (P) -> P ! {munger,Command} end,
|
||
|
DistinctPids)
|
||
|
end,
|
||
|
send(Sock, "ok\r\n"),
|
||
|
recv_loop(Sock, Config);
|
||
|
{error,closed} ->
|
||
|
ok
|
||
|
end.
|
||
|
|
||
|
|
||
|
%%% {{from,to},shutdown} -> look up the sockets, and close them
|
||
|
%%%
|