• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

emqx / esockd / 352

12 Dec 2023 09:17PM UTC coverage: 70.175%. First build
352

Pull #183

github

web-flow
Merge c60472aab into 5cb22a8b1
Pull Request #183: feat(listener): support changing options on the fly

143 of 177 new or added lines in 10 files covered. (80.79%)

800 of 1140 relevant lines covered (70.18%)

59.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.97
/src/esockd_dtls_listener.erl
1
%%--------------------------------------------------------------------
2
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
3
%%
4
%% Licensed under the Apache License, Version 2.0 (the "License");
5
%% you may not use this file except in compliance with the License.
6
%% You may obtain a copy of the License at
7
%%
8
%%     http://www.apache.org/licenses/LICENSE-2.0
9
%%
10
%% Unless required by applicable law or agreed to in writing, software
11
%% distributed under the License is distributed on an "AS IS" BASIS,
12
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
%% See the License for the specific language governing permissions and
14
%% limitations under the License.
15
%%--------------------------------------------------------------------
16

17
-module(esockd_dtls_listener).
18

19
-behaviour(gen_server).
20

21
-include("esockd.hrl").
22

23
-export([ start_link/4
24
        , start_supervised/1
25
        ]).
26

27
-export([ options/1
28
        , get_port/1
29
        , get_state/1
30
        ]).
31

32
%% gen_server callbacks
33
-export([ init/1
34
        , handle_call/3
35
        , handle_cast/2
36
        , handle_info/2
37
        , terminate/2
38
        , code_change/3
39
        ]).
40

41
-record(state, {
42
          proto     :: atom(),
43
          listen_on :: esockd:listen_on(),
44
          options   :: [esockd:option()],
45
          lsock     :: ssl:sslsocket(),
46
          laddr     :: inet:ip_address(),
47
          lport     :: inet:port_number()
48
         }).
49

50
-define(DEFAULT_DTLS_OPTIONS,
51
        [{protocol, dtls},
52
         {mode, binary},
53
         {reuseaddr, true}]).
54

55
-spec start_link(atom(), esockd:listen_on(), [esockd:option()], pid() | ignore)
56
      -> {ok, pid()} | ignore | {error, term()}.
57
start_link(Proto, ListenOn, Opts, AcceptorSup) ->
58
    gen_server:start_link(?MODULE, {Proto, ListenOn, Opts, AcceptorSup}, []).
10✔
59

60
-spec start_supervised(esockd:listener_ref())
61
      -> {ok, pid()} | ignore | {error, term()}.
62
start_supervised(ListenerRef = {Proto, ListenOn}) ->
63
    Opts = esockd_server:get_listener_prop(ListenerRef, options),
10✔
64
    case start_link(Proto, ListenOn, Opts, ignore) of
10✔
65
        {ok, Pid} ->
66
            _ = esockd_server:set_listener_prop(ListenerRef, listener, {?MODULE, Pid}),
10✔
67
            {ok, Pid};
10✔
68
        Error ->
NEW
69
            Error
×
70
    end.
71

72
-spec(options(pid()) -> [esockd:option()]).
73
options(Listener) ->
74
    gen_server:call(Listener, options).
×
75

76
-spec(get_port(pid()) -> inet:port_number()).
77
get_port(Listener) ->
78
    gen_server:call(Listener, get_port).
×
79

80
-spec get_state(pid())  -> proplists:proplist().
81
get_state(Listener) ->
82
    gen_server:call(Listener, get_state).
12✔
83

84
%%--------------------------------------------------------------------
85
%% gen_server callbacks
86
%%--------------------------------------------------------------------
87

88
init({Proto, ListenOn, Opts, _Ignore}) ->
89
    Port = port(ListenOn),
10✔
90
    process_flag(trap_exit, true),
10✔
91
    esockd_server:ensure_stats({Proto, ListenOn}),
10✔
92
    SockOpts = merge_addr(ListenOn, dltsopts(Opts)),
10✔
93
    %% Don't active the socket...
94
    case ssl:listen(Port, SockOpts) of
10✔
95
    %%case ssl:listen(Port, [{active, false} | proplists:delete(active, SockOpts)]) of
96
        {ok, LSock} ->
97
            {ok, {LAddr, LPort}} = ssl:sockname(LSock),
10✔
98
            %%error_logger:info_msg("~s listen on ~s:~p with ~p acceptors.~n",
99
            %%                      [Proto, inet:ntoa(LAddr), LPort, AcceptorNum]),
100
            {ok, #state{proto = Proto, listen_on = ListenOn, options = Opts,
10✔
101
                        lsock = LSock, laddr = LAddr, lport = LPort}};
102
        {error, Reason} ->
103
            error_logger:error_msg("~s failed to listen on ~p - ~p (~s)",
×
104
                                   [Proto, Port, Reason, inet:format_error(Reason)]),
105
            {stop, Reason}
×
106
    end.
107

108
dltsopts(Opts) ->
109
    DtlsOpts = proplists:delete(
10✔
110
                 handshake_timeout,
111
                 proplists:get_value(dtls_options, Opts, [])
112
                ),
113
    esockd:merge_opts(?DEFAULT_DTLS_OPTIONS, DtlsOpts).
10✔
114

115
port(Port) when is_integer(Port) -> Port;
10✔
116
port({_Addr, Port}) -> Port.
×
117

118
merge_addr(Port, SockOpts) when is_integer(Port) ->
119
    SockOpts;
10✔
120
merge_addr({Addr, _Port}, SockOpts) ->
121
    lists:keystore(ip, 1, SockOpts, {ip, Addr}).
×
122

123
handle_call(options, _From, State = #state{options = Opts}) ->
124
    {reply, Opts, State};
×
125

126
handle_call(get_port, _From, State = #state{lport = LPort}) ->
127
    {reply, LPort, State};
×
128

129
handle_call(get_state, _From, State = #state{lsock = LSock, lport = LPort}) ->
130
    Reply = [ {listen_sock, LSock}
12✔
131
            , {listen_port, LPort}
132
            ],
133
    {reply, Reply, State};
12✔
134

135
handle_call(Req, _From, State) ->
136
    error_logger:error_msg("[~s] Unexpected call: ~p", [?MODULE, Req]),
×
137
    {noreply, State}.
×
138

139
handle_cast(Msg, State) ->
140
    error_logger:error_msg("[~s] Unexpected cast: ~p", [?MODULE, Msg]),
×
141
    {noreply, State}.
×
142

143
handle_info(Info, State) ->
144
    error_logger:error_msg("[~s] Unexpected info: ~p", [?MODULE, Info]),
×
145
    {noreply, State}.
×
146

147
terminate(_Reason, #state{proto = Proto, listen_on = ListenOn,
148
                          lsock = LSock, laddr = Addr, lport = Port}) ->
149
    error_logger:info_msg("~s stopped on ~s~n", [Proto, esockd:format({Addr, Port})]),
10✔
150
    esockd_limiter:delete({listener, Proto, ListenOn}),
10✔
151
    esockd_server:del_stats({Proto, ListenOn}),
10✔
152
    esockd_transport:fast_close(LSock).
10✔
153

154
code_change(_OldVsn, State, _Extra) ->
155
    {ok, State}.
×
156

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc