Guest User

Untitled

a guest
Jan 4th, 2019
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 4.70 KB | None | 0 0
  1. %% Copyright (C) 2003 Joakim Grebenö <jocke@gleipnir.com>.
  2. %% All rights reserved.
  3. %%
  4. %% Redistribution and use in source and binary forms, with or without
  5. %% modification, are permitted provided that the following conditions
  6. %% are met:
  7. %%
  8. %% 1. Redistributions of source code must retain the above copyright
  9. %%    notice, this list of conditions and the following disclaimer.
  10. %% 2. Redistributions in binary form must reproduce the above
  11. %%    copyright notice, this list of conditions and the following
  12. %%    disclaimer in the documentation and/or other materials provided
  13. %%    with the distribution.
  14. %%
  15. %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  16. %% OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. %% WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. %% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  19. %% DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. %% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  21. %% GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23. %% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  24. %% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  
  27. -module(tcp_serv).
  28. -vsn("1.13").
  29. -author('jocke@gleipnir.com').
  30. -export([start_link/1, start_link/2, stop/1, stop/2]).
  31. -export([init/2, start_session/3]).
  32. -export([system_continue/3, system_terminate/4]).
  33.  
  34. -include("log.hrl").
  35.  
  36. -record(state, {
  37.       %% int()
  38.       max_sessions,
  39.       %% {M, F, A}
  40.       %% M = F = atom()
  41.       %% A = [term()]
  42.       session_handler,
  43.       %% [pid()]
  44.       session_list,
  45.       %% socket()
  46.       listen_socket,
  47.       %% pid()
  48.       parent,
  49.       %% term()
  50.       debug_info
  51.      }).
  52.  
  53. %% Exported: start_link/{1,2}
  54.  
  55. start_link(Args) -> start_link(Args, 60000).
  56.    
  57. start_link(Args, Timeout) ->
  58.     Pid = proc_lib:spawn_link(?MODULE, init, [self(), Args]),
  59.     receive
  60.     {Pid, started} -> {ok, Pid};
  61.     {Pid, Reason} -> {error, Reason}
  62.     after Timeout -> {error, timeout}
  63.     end.
  64.  
  65. %% Exported: stop/{1,2}
  66.  
  67. stop(Pid) -> stop(Pid, 15000).
  68.  
  69. stop(Pid, Timeout) ->
  70.     Pid ! {self(), stop},
  71.     receive
  72.     {Pid, Reply} -> Reply
  73.     after
  74.     Timeout -> {error, timeout}
  75.     end.
  76.  
  77. %% Exported: init/2
  78.  
  79. init(Parent, [Port, MaxSessions, OptionList, SessionHandler]) ->
  80.     process_flag(trap_exit, true),
  81.     case gen_tcp:listen(Port, OptionList) of
  82.     {ok, ListenSocket} ->
  83.         self() ! start_session,
  84.         Parent ! {self(), started},
  85.         loop(#state{max_sessions = MaxSessions,
  86.             session_handler = SessionHandler,
  87.             session_list = [],
  88.             listen_socket = ListenSocket,
  89.             parent = Parent});
  90.     Reason -> Parent ! {self(), {not_started, Reason}}
  91.     end.
  92.  
  93. loop(#state{session_list = SessionList, listen_socket = ListenSocket,
  94.         parent = Parent} = State) ->
  95.     receive
  96.     {From, stop} ->
  97.         cleanup(State),
  98.         From ! {self(), ok};
  99.     start_session when length(SessionList) > State#state.max_sessions ->
  100.         timer:sleep(5000),
  101.         self() ! start_session,
  102.         loop(State);
  103.     start_session ->
  104.         A = [self(), State#state.session_handler, ListenSocket],
  105.         Pid = proc_lib:spawn_link(?MODULE, start_session, A),
  106.         loop(State#state{session_list = [Pid|SessionList]});
  107.         {'EXIT', Parent, Reason} ->
  108.         cleanup(State),
  109.             exit(Reason);
  110.     {'EXIT', Pid, Reason} ->
  111.         case lists:member(Pid, SessionList) of
  112.         true ->
  113.             PurgedSessionList = lists:delete(Pid, SessionList),
  114.             loop(State#state{session_list = PurgedSessionList});
  115.         false ->
  116.             ?ERROR_LOG({ignoring, {'EXIT', Pid, Reason}}),
  117.             loop(State)
  118.         end;
  119.     {system, From, Request} ->
  120.             sys:handle_system_msg(Request, From, Parent, ?MODULE,
  121.                   State#state.debug_info, State);  
  122.     UnknownMessage ->
  123.         ?ERROR_LOG({unknown_message, UnknownMessage}),
  124.         loop(State)
  125.     end.
  126.  
  127. cleanup(State) -> gen_tcp:close(State#state.listen_socket).
  128.  
  129. %% Exported: start_seesion/3
  130.  
  131. start_session(Parent, {M, F, A}, ListenSocket) ->
  132.     case gen_tcp:accept(ListenSocket) of
  133.     {ok, Socket} ->
  134.         Parent ! start_session,
  135.         case apply(M, F, [Socket|A]) of
  136.         ok -> gen_tcp:close(Socket);
  137.         {error, closed} -> ok;
  138.         {error, Reason} ->
  139.             ?ERROR_LOG({M, F, Reason}),
  140.             gen_tcp:close(Socket)
  141.         end;
  142.     {error, Reason} ->
  143.         timer:sleep(5000),
  144.         Parent ! start_session
  145.     end.
  146.  
  147. %% Exported: system_continue/3
  148.  
  149. system_continue(Parent, DebugInfo, State) ->
  150.     loop(State#state{parent = Parent, debug_info = DebugInfo}).
  151.  
  152. %% Exported: system_terminate/3
  153.  
  154. system_terminate(Reason, Parent, DebugInfo, State) ->
  155.     cleanup(State),
  156.     exit(Reason).
Add Comment
Please, Sign In to add comment