File: manager.erl

package info (click to toggle)
db 5.1.29-9%2Bdeb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 150,396 kB
  • sloc: ansic: 400,169; java: 94,399; tcl: 70,967; sh: 37,399; cs: 30,758; cpp: 21,132; perl: 14,227; xml: 9,854; makefile: 3,777; yacc: 1,003; awk: 942; sql: 801; erlang: 461; python: 216; php: 24; asm: 14
file content (80 lines) | stat: -rw-r--r-- 3,395 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
%%% 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/1,accept_loop/1,recv_loop/1]).
-import(gen_tcp, [listen/2, accept/1, recv/2, send/2]).
-import(string, [cspan/2, substr/3]).

start(Port) ->
    {ok, LSock} = listen(Port, [{packet,line},
                                {active,false},{reuseaddr,true}]),
    Pid = spawn(?MODULE, accept_loop, [LSock]),
    ok = gen_tcp:controlling_process(LSock, Pid).

accept_loop(LSock) ->
    {ok, Sock} = accept(LSock),
    spawn(?MODULE, recv_loop, [Sock]),
    accept_loop(LSock).

recv_loop(Sock) ->
    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
                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);
        {error,closed} ->
            ok
    end.


%%% {{from,to},shutdown} -> look up the sockets, and close them
%%%