./ct_report/coverage/mongoose_udp_listener.COVER.html

1 %%==============================================================================
2 %% Copyright 2018 Erlang Solutions Ltd.
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(mongoose_udp_listener).
18 -author('konrad.zemek@erlang-solutions.com').
19
20 -include("mongoose.hrl").
21
22 -type udp_listen_option() :: gen_udp:option()
23 | {ip, _}
24 | {fd, pos_integer()}
25 | {ifaddr, _}
26 | inet:address_family()
27 | {port, inet:port_number()}.
28
29 -export([start_link/6, init/6]).
30
31 %% Internal
32 -export([recv_loop/3]).
33
34 -ignore_xref([start_link/6, init/6]).
35
36 %%--------------------------------------------------------------------
37 %% API
38 %%--------------------------------------------------------------------
39
40 -spec start_link(Id :: mongoose_listener_config:listener_id(),
41 Module :: atom(),
42 Opts :: [any(), ...],
43 SockOpts :: [udp_listen_option()],
44 Port :: inet:port_number(),
45 IPS :: [any()]) -> any().
46 start_link(Id, Module, Opts, SockOpts, Port, IPS) ->
47
:-(
proc_lib:start_link(?MODULE, init, [Id, Module, Opts, SockOpts, Port, IPS]).
48
49 -spec init(Id :: mongoose_listener_config:listener_id(),
50 Module :: atom(),
51 Opts :: [any(), ...],
52 SockOpts :: [udp_listen_option()],
53 Port :: inet:port_number(),
54 IPS :: [any()]) -> no_return().
55 init(Id, Module, Opts, SockOpts, Port, IPS) ->
56
:-(
case gen_udp:open(Port, [binary, {active, false}, {reuseaddr, true}
57 | SockOpts]) of
58 {ok, Socket} ->
59 %% Inform my parent that this port was opened succesfully
60
:-(
proc_lib:init_ack({ok, self()}),
61
:-(
recv_loop(Socket, Module, Opts);
62 {error, Reason} ->
63
:-(
ejabberd_listener:socket_error(Reason, Id, Module, SockOpts, Port, IPS)
64 end.
65
66 %%--------------------------------------------------------------------
67 %% Helpers
68 %%--------------------------------------------------------------------
69
70 -spec recv_loop(Socket :: port(),
71 Module :: atom(),
72 Opts :: [any(), ...]) -> no_return().
73 recv_loop(Socket, Module, Opts) ->
74
:-(
case gen_udp:recv(Socket, 0) of
75 {ok, {Addr, Port, Packet}} ->
76
:-(
try Module:udp_recv(Socket, Addr, Port, Packet, Opts)
77 catch Class:Reason:Stacktrace ->
78
:-(
?LOG_ERROR(#{what => udp_listener_recv_failed,
79 text => <<"Failed to process UDP packet">>,
80 socket => Socket, handler_module => Module,
81 ip => Addr, port => Port,
82 class => Class, reason => Reason,
83
:-(
stacktrace => Stacktrace, udp_packet => Packet})
84 end,
85
:-(
?MODULE:recv_loop(Socket, Module, Opts);
86 {error, Reason} ->
87
:-(
?LOG_ERROR(#{what => udp_listener_recv_failed,
88 text => <<"Unexpected UDP error">>,
89 socket => Socket, handler_module => Module,
90
:-(
reason => ejabberd_listener:format_error(Reason)}),
91
:-(
exit({error, Reason})
92 end.
Line Hits Source