/home/runner/work/textgroup/textgroup/_build/test/cover/ct/textgroup_acceptor.html

1 %%% Textgroup server.
2 %%%
3 %%% Copyright (c) 2022, 2023 Holger Weiss <holger@zedat.fu-berlin.de>.
4 %%% All rights reserved.
5 %%%
6 %%% Licensed under the Apache License, Version 2.0 (the "License");
7 %%% you may not use this file except in compliance with the License.
8 %%% You may obtain a copy of the License at
9 %%%
10 %%% http://www.apache.org/licenses/LICENSE-2.0
11 %%%
12 %%% Unless required by applicable law or agreed to in writing, software
13 %%% distributed under the License is distributed on an "AS IS" BASIS,
14 %%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 %%% See the License for the specific language governing permissions and
16 %%% limitations under the License.
17
18 -module(textgroup_acceptor).
19 -export([start_link/1]).
20 -export([init/1]).
21 -export([loop/1]).
22 -export([system_continue/3,
23 system_terminate/4,
24 system_code_change/4]).
25 -export_type([state/0]).
26
27 -include_lib("kernel/include/logger.hrl").
28
29 -record(acceptor_state,
30 {parent :: pid() | undefined,
31 listener :: gen_tcp:socket() | undefined}).
32
33 -opaque state() :: #acceptor_state{}.
34
35 %% API.
36
37 -spec start_link(gen_tcp:socket()) -> term() | {error, term()}.
38 start_link(Listener) ->
39 6 ?LOG_DEBUG("Creating acceptor process"),
40 6 State = #acceptor_state{parent = self(), listener = Listener},
41 6 proc_lib:start_link(?MODULE, init, [State]).
42
43 -spec init(state()) -> no_return().
44 init(State) ->
45 6 ?LOG_DEBUG("Initializing acceptor process"),
46 6 process_flag(trap_exit, true),
47 6 proc_lib:init_ack({ok, self()}),
48 6 loop(State).
49
50 -spec system_continue(pid(), [sys:dbg_opt()], state()) -> no_return().
51 system_continue(_Parent, _Debug, State) ->
52 5 ?LOG_DEBUG("Continuing acceptor process after handling system message"),
53 5 loop(State).
54
55 -spec system_terminate(term(), pid(), [sys:dbg_opt()], state()) -> no_return().
56 system_terminate(Reason, _Parent, _Debug, _State) ->
57 1 ?LOG_DEBUG("Terminating acceptor process (~p)", [Reason]),
58 1 exit(Reason).
59
60 -spec system_code_change(state(), module(), term() | undefined, term())
61 -> {ok, state()}.
62 system_code_change(State, _Mod, _OldVsn, _Extra) ->
63
:-(
?LOG_DEBUG("Got code change request"),
64
:-(
{ok, State}.
65
66 %% Internal functions.
67
68 -spec loop(state()) -> no_return().
69 loop(#acceptor_state{parent = Parent, listener = Listener} = State) ->
70 32 case gen_tcp:accept(Listener, timer:seconds(3)) of
71 {ok, Socket} ->
72 6 ok = handle_connection(Socket);
73 {error, timeout} ->
74 21 ok
75 end,
76 27 receive
77 {system, From, Request} ->
78 5 sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
79 {'EXIT', Parent, Reason} ->
80 1 system_terminate(Reason, Parent, [], State);
81 Msg ->
82
:-(
?LOG_ERROR("Got unexpected message: ~p", [Msg]),
83
:-(
?MODULE:loop(State)
84 after 0 ->
85 21 ?MODULE:loop(State)
86 end.
87
88 -spec handle_connection(gen_tcp:socket()) -> ok.
89 handle_connection(Socket) ->
90 6 {ok, {LAddr, LPort}} = inet:sockname(Socket),
91 6 {ok, {RAddr, RPort}} = inet:peername(Socket),
92 6 ?LOG_INFO("Accepting connection: ~s:~B -> ~s:~B",
93 [inet:ntoa(RAddr), RPort,
94 6 inet:ntoa(LAddr), LPort]),
95 6 ok = textgroup_client:start(Socket).
Line Hits Source