1111 code_change /3 ,
1212 terminate /2 ]).
1313
14- % % public api
14+ -record (state , {
15+ pool ,
16+ listen_opts ,
17+ pool_opts ,
18+ socket ,
19+ mref
20+ }).
1521
22+ % % public api
1623start_link (Pool , ListenOpts , AcceptorOpts ) ->
1724 gen_server :start_link (? MODULE , [Pool , ListenOpts , AcceptorOpts ], []).
1825
1926% % gen_server api
2027
2128init ([Pool , ListenOpts , PoolOpts ]) ->
29+ {ok , # state {pool = Pool , pool_opts = PoolOpts , listen_opts = ListenOpts }, 0 }.
30+
31+ handle_call (Req , _ , State ) ->
32+ {stop , {bad_call , Req }, State }.
33+
34+ handle_cast (Req , State ) ->
35+ {stop , {bad_cast , Req }, State }.
36+ handle_info (timeout , State ) ->
37+ case start_listener (State ) of
38+ {ok , {Socket , MRef }} ->
39+ {noreply , State # state {socket = Socket , mref = MRef }};
40+ _ ->
41+ erlang :send_after (5000 , self (), timeout ),
42+ {noreply , State }
43+ end ;
44+ handle_info ({'DOWN' , MRef , port , Socket , _Reason }, # state {mref = MRef , socket = Socket } = State ) ->
45+ catch gen_tcp :close (Socket ),
46+ erlang :send_after (5000 , self (), timeout ),
47+ {noreply , State };
48+ handle_info (_Msg , State ) ->
49+ {noreply , State }.
50+
51+ code_change (_ , State , _ ) ->
52+ {ok , State }.
53+
54+ terminate (_Reason , {Socket , MRef }) ->
55+ % % Socket may already be down but need to ensure it is closed to avoid
56+ % % eaddrinuse error on restart
57+ % % this takes care of that, unless of course this process is killed...
58+ case demonitor (MRef , [flush , info ]) of
59+ true -> gen_tcp :close (Socket );
60+ false -> ok
61+ end .
62+
63+ % % ------------------------------------------------------------------
64+ % % Internal functions
65+ % % ------------------------------------------------------------------
66+ start_listener (# state {
67+ pool = Pool ,
68+ listen_opts = ListenOpts ,
69+ pool_opts = PoolOpts } = _State ) ->
2270 Port = maps :get (port , ListenOpts , 8080 ),
2371 IPAddress = maps :get (ip , ListenOpts , {0 , 0 , 0 , 0 }),
2472 AcceptorPoolSize = maps :get (size , PoolOpts , 10 ),
@@ -27,8 +75,7 @@ init([Pool, ListenOpts, PoolOpts]) ->
2775 {reuseaddr , true },
2876 {backlog , 32768 },
2977 {keepalive , true }]),
30- % % Trapping exit so can close socket in terminate/2
31- _ = process_flag (trap_exit , true ),
78+
3279 Opts = [{active , false }, {mode , binary }, {packet , raw }, {ip , IPAddress } | SocketOpts ],
3380 case gen_tcp :listen (Port , Opts ) of
3481 {ok , Socket } ->
@@ -78,30 +125,7 @@ init([Pool, ListenOpts, PoolOpts]) ->
78125 socket_not_found ->
79126 noop
80127 end ,
81- {stop , eaddrinuse };
128+ {error , eaddrinuse };
82129 {error , Reason } ->
83- {stop , Reason }
84- end .
85-
86- handle_call (Req , _ , State ) ->
87- {stop , {bad_call , Req }, State }.
88-
89- handle_cast (Req , State ) ->
90- {stop , {bad_cast , Req }, State }.
91-
92- handle_info ({'DOWN' , MRef , port , Socket , Reason }, {Socket , MRef } = State ) ->
93- {stop , Reason , State };
94- handle_info (_ , State ) ->
95- {noreply , State }.
96-
97- code_change (_ , State , _ ) ->
98- {ok , State }.
99-
100- terminate (_Reason , {Socket , MRef }) ->
101- % % Socket may already be down but need to ensure it is closed to avoid
102- % % eaddrinuse error on restart
103- % % this takes care of that, unless of course this process is killed...
104- case demonitor (MRef , [flush , info ]) of
105- true -> gen_tcp :close (Socket );
106- false -> ok
130+ {error , Reason }
107131 end .
0 commit comments