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

esl / MongooseIM / 16499779126

24 Jul 2025 02:03PM UTC coverage: 85.593% (-0.02%) from 85.614%
16499779126

Pull #4549

github

jacekwegr
Add TODO comments
Pull Request #4549: Support Erlang 28

50 of 68 new or added lines in 5 files covered. (73.53%)

289 existing lines in 7 files now uncovered.

28945 of 33817 relevant lines covered (85.59%)

51736.46 hits per line

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

87.78
/src/listeners/mongoose_xmpp_socket.erl
1
-module(mongoose_xmpp_socket).
2

3
-include_lib("public_key/include/public_key.hrl").
4

5
-define(DEF_SOCKET_OPTS,
6
        binary, {active, false}, {packet, raw},
7
        {send_timeout, 15000}, {send_timeout_close, true}).
8

9
-export([accept/4,
10
         connect/4,
11
         handle_data/2,
12
         activate/1,
13
         close/1,
14
         is_channel_binding_supported/1,
15
         export_key_materials/5,
16
         get_peer_certificate/1,
17
         has_peer_cert/2,
18
         tcp_to_tls/3,
19
         is_ssl/1,
20
         send_xml/2]).
21

22
-export([get_ip/1,
23
         get_transport/1,
24
         get_conn_type/1]).
25

26
-callback peername(state()) -> mongoose_transport:peer().
27
-callback tcp_to_tls(state(), mongoose_listener:options(), side()) ->
28
    {ok, state()} | {error, term()}.
29
-callback handle_data(state(), {tcp | ssl, term(), binary()}) ->
30
    binary() | {raw, [exml:element()]} | {error, term()}.
31
-callback activate(state()) -> ok.
32
-callback close(state()) -> ok.
33
-callback send_xml(state(), iodata() | exml_stream:element() | [exml_stream:element()]) ->
34
    ok | {error, atom()}.
35
-callback get_peer_certificate(state()) -> peercert_return().
36
-callback has_peer_cert(state(), mongoose_listener:options()) -> boolean().
37
-callback is_channel_binding_supported(state()) -> boolean().
38
-callback export_key_materials(state(), Labels, Contexts, WantedLengths, ConsumeSecret) ->
39
    {ok, ExportKeyMaterials} |
40
    {error, atom() | exporter_master_secret_already_consumed | bad_input}
41
      when
42
      Labels :: [binary()],
43
      Contexts :: [binary() | no_context],
44
      WantedLengths :: [non_neg_integer()],
45
      ConsumeSecret :: boolean(),
46
      ExportKeyMaterials :: binary() | [binary()].
47
-callback is_ssl(state()) -> boolean().
48

49
-record(ranch_tcp, {
50
          socket :: inet:socket(),
51
          connection_type = mongoose_listener:connection_type(),
52
          ranch_ref :: ranch:ref(),
53
          ip :: mongoose_transport:peer()
54
         }).
55

56
-record(ranch_ssl, {
57
          socket :: ssl:sslsocket(),
58
          connection_type :: mongoose_listener:connection_type(),
59
          ranch_ref :: ranch:ref(),
60
          ip :: mongoose_transport:peer(),
61
          verify_results = [] :: list()
62
         }).
63

64
-record(xmpp_socket, {
65
          module :: module(),
66
          state :: state(),
67
          connection_type = mongoose_listener:connection_type(),
68
          ip :: mongoose_transport:peer()
69
         }).
70

71
-type socket() :: #ranch_tcp{} | #ranch_ssl{} | #xmpp_socket{}.
72

73
-type state() :: term().
74
-type side() :: client | server.
75
-type conn_type() :: tcp | tls.
76
-type peercert_return() :: no_peer_cert | {bad_cert, term()} | {ok, #'Certificate'{}}.
77
-type with_tls_opts() :: #{tls := just_tls:options(), _ => _}.
78
-export_type([socket/0, state/0, side/0, conn_type/0, peercert_return/0]).
79

80
-spec accept(mongoose_listener:transport_module(),
81
             mongoose_listener:connection_type(),
82
             ranch:ref(),
83
             mongoose_listener:options()) -> socket().
84
accept(ranch_tcp, Type, Ref, LOpts) ->
85
    {ok, Socket, ConnDetails} = mongoose_listener:read_connection_details(Ref, ranch_tcp, LOpts),
65,634✔
86
    #{src_address := PeerIp, src_port := PeerPort} = ConnDetails,
65,623✔
87
    SocketState = #ranch_tcp{socket = Socket, connection_type = Type,
65,623✔
88
                             ranch_ref = Ref, ip = {PeerIp, PeerPort}},
89
    activate(SocketState),
65,623✔
90
    SocketState;
65,623✔
91
accept(ranch_ssl, Type, Ref, LOpts) ->
92
    {ok, Socket, ConnDetails} = mongoose_listener:read_connection_details(Ref, ranch_ssl, LOpts),
13,890✔
93
    #{src_address := PeerIp, src_port := PeerPort} = ConnDetails,
10,279✔
94
    SocketState = #ranch_ssl{socket = Socket, connection_type = Type,
10,279✔
95
                             ranch_ref = Ref, ip = {PeerIp, PeerPort}},
96
    activate(SocketState),
10,279✔
97
    SocketState;
10,279✔
98
accept(Module, Type, State, _LOpts) ->
99
    PeerIp = Module:peername(State),
3,005✔
100
    SocketState = #xmpp_socket{module = Module, state = State,
3,005✔
101
                               connection_type = Type, ip = PeerIp},
102
    activate(SocketState),
3,005✔
103
    SocketState.
3,005✔
104

105
-spec connect(mongoose_addr_list:addr(),
106
              with_tls_opts(),
107
              mongoose_listener:connection_type(),
108
              timeout()) -> socket() | {error, timeout | inet:posix() | any()}.
109
connect(#{ip_tuple := Addr, ip_version := Inet, port := Port, tls := false}, Opts, Type, Timeout) ->
110
    SockOpts = socket_options(false, Inet, Opts),
340✔
111
    case gen_tcp:connect(Addr, Port, SockOpts, Timeout) of
340✔
112
        {ok, Socket} ->
113
            SocketState = #ranch_tcp{socket = Socket, connection_type = Type,
340✔
114
                                     ranch_ref = {self(), Type}, ip = {Addr, Port}},
115
            activate(SocketState),
340✔
116
            SocketState;
340✔
117
        {error, Reason} ->
118
            {error, Reason}
×
119
    end;
120
connect(#{ip_tuple := Addr, ip_version := Inet, port := Port, tls := true}, Opts, Type, Timeout) ->
121
    SockOpts = socket_options(true, Inet, Opts),
26✔
122
    case ssl:connect(Addr, Port, SockOpts, Timeout) of
26✔
123
        {ok, Socket} ->
124
            SocketState = #ranch_ssl{socket = Socket, connection_type = Type,
26✔
125
                                     ranch_ref = {self(), Type}, ip = {Addr, Port}},
126
            activate(SocketState),
26✔
127
            SocketState;
26✔
128
        {error, Reason} ->
129
            {error, Reason}
×
130
    end.
131

132
-spec socket_options(true, inet | inet6, with_tls_opts()) -> [ssl:tls_client_option()];
133
                    (false, inet | inet6, with_tls_opts()) -> [gen_tcp:connect_option()].
134
socket_options(true, Inet, #{tls := TlsOpts}) ->
135
    [Inet, ?DEF_SOCKET_OPTS | just_tls:make_client_opts(TlsOpts)];
26✔
136
socket_options(false, Inet, _) ->
137
    [Inet, ?DEF_SOCKET_OPTS].
340✔
138

139
-spec activate(socket()) -> ok | {error, term()}.
140
activate(#ranch_tcp{socket = Socket}) ->
141
    ranch_tcp:setopts(Socket, [{active, once}]);
599,962✔
142
activate(#ranch_ssl{socket = Socket}) ->
143
    ranch_ssl:setopts(Socket, [{active, once}]);
42,224✔
144
activate(#xmpp_socket{module = Module, state = State}) ->
145
    Module:activate(State).
28,566✔
146

147
-spec tcp_to_tls(socket(), with_tls_opts(), side()) -> {ok, socket()} | {error, term()}.
148
tcp_to_tls(#ranch_tcp{socket = TcpSocket, connection_type = Type, ranch_ref = Ref, ip = Ip},
149
           #{tls := TlsConfig}, Side) ->
150
    inet:setopts(TcpSocket, [{active, false}]),
1,038✔
151
    Ret = case Side of
1,038✔
152
        server ->
153
            SslOpts = just_tls:make_server_opts(TlsConfig),
900✔
154
            ssl:handshake(TcpSocket, SslOpts, 5000);
900✔
155
        client ->
156
            SslOpts = just_tls:make_client_opts(TlsConfig),
138✔
157
            ssl:connect(TcpSocket, SslOpts, 5000)
138✔
158
    end,
159
    VerifyResults = just_tls:receive_verify_results(),
1,038✔
160
    case Ret of
1,038✔
161
        {ok, SslSocket} ->
162
            ssl:setopts(SslSocket, [{active, once}]),
981✔
163
            {ok, #ranch_ssl{socket = SslSocket, connection_type = Type,
981✔
164
                            ranch_ref = Ref, ip = Ip, verify_results = VerifyResults}};
165
        {error, Reason} ->
166
            {error, Reason}
57✔
167
    end;
168
tcp_to_tls(#ranch_ssl{}, _, _) ->
169
    {error, already_tls_connection};
×
170
tcp_to_tls(#xmpp_socket{module = Module, state = State} = C2SSocket, LOpts, Mode) ->
171
    case Module:tcp_to_tls(State, LOpts, Mode) of
×
172
        {ok, NewState} ->
173
            {ok, C2SSocket#xmpp_socket{state = NewState}};
×
174
        Error ->
175
            Error
×
176
    end.
177

178
-spec handle_data(socket(), {tcp | ssl, term(), binary()}) ->
179
    binary() | {raw, [term()]} | {error, term()}.
180
handle_data(#ranch_tcp{connection_type = Type}, {tcp, _, Data}) ->
181
    mongoose_instrument:execute(tcp_data_in, #{connection_type => Type}, #{byte_size => iolist_size(Data)}),
534,065✔
182
    Data;
534,065✔
183
handle_data(#ranch_ssl{connection_type = Type}, {ssl, _, Data}) ->
184
    mongoose_instrument:execute(tls_data_in, #{connection_type => Type}, #{byte_size => iolist_size(Data)}),
31,925✔
185
    Data;
31,925✔
186
handle_data(#xmpp_socket{module = Module, state = State, connection_type = Type}, Payload) ->
187
    mongoose_instrument:execute(tcp_data_in, #{connection_type => Type}, #{byte_size => 0}),
25,561✔
188
    Module:handle_data(State, Payload).
25,561✔
189

190
-spec close(socket()) -> ok.
191
close(#ranch_tcp{socket = Socket}) ->
192
    ranch_tcp:close(Socket);
64,932✔
193
close(#ranch_ssl{socket = Socket}) ->
194
    ranch_ssl:close(Socket);
11,244✔
195
close(#xmpp_socket{module = Module, state = State}) ->
196
    Module:close(State).
3,005✔
197

198
-spec send_xml(socket(), exml_stream:element() | [exml_stream:element()]) -> ok | {error, atom()}.
199
send_xml(#ranch_tcp{socket = Socket, connection_type = Type}, XML) ->
200
    Data = exml:to_iolist(XML),
787,956✔
201
    mongoose_instrument:execute(tcp_data_out, #{connection_type => Type}, #{byte_size => iolist_size(Data)}),
787,956✔
202
    ranch_tcp:send(Socket, Data);
787,956✔
203
send_xml(#ranch_ssl{socket = Socket, connection_type = Type}, XML) ->
204
    Data = exml:to_iolist(XML),
52,576✔
205
    mongoose_instrument:execute(tls_data_out, #{connection_type => Type}, #{byte_size => iolist_size(Data)}),
52,576✔
206
    ranch_ssl:send(Socket, Data);
52,576✔
207
send_xml(#xmpp_socket{module = Module, state = State, connection_type = Type}, XML) ->
208
    mongoose_instrument:execute(tcp_data_out, #{connection_type => Type}, #{byte_size => exml:xml_size(XML)}),
33,447✔
209
    Module:send_xml(State, XML).
33,447✔
210

211
-spec get_peer_certificate(socket()) -> peercert_return().
212
get_peer_certificate(#ranch_tcp{}) ->
213
    no_peer_cert;
470✔
214
get_peer_certificate(#ranch_ssl{socket = Socket, verify_results = []}) ->
215
    case ssl:peercert(Socket) of
1,646✔
216
        {ok, PeerCert} ->
217
            {ok, public_key:pkix_decode_cert(PeerCert, plain)};
1,443✔
218
        _ -> no_peer_cert
203✔
219
    end;
220
get_peer_certificate(#ranch_ssl{verify_results = [Err | _]}) ->
221
    {bad_cert, just_tls:error_to_list(Err)};
33✔
222
get_peer_certificate(#xmpp_socket{module = Module, state = State}) ->
223
    Module:get_peer_certificate(State).
132✔
224

225
-spec has_peer_cert(socket(), mongoose_listener:options()) -> boolean().
226
has_peer_cert(Socket, _LOpts) ->
227
    case get_peer_certificate(Socket) of
1,498✔
228
        {ok, _} -> true;
962✔
229
        _ -> false
536✔
230
    end.
231

232
-spec is_ssl(socket()) -> boolean().
233
is_ssl(#ranch_tcp{}) ->
234
    false;
190,422✔
235
is_ssl(#ranch_ssl{}) ->
236
    true;
53,984✔
237
is_ssl(#xmpp_socket{module = Module, state = State}) ->
238
    Module:is_ssl(State).
8,806✔
239

240
-spec get_transport(socket()) -> module().
241
get_transport(#ranch_tcp{}) ->
242
    ranch_tcp;
×
243
get_transport(#ranch_ssl{}) ->
244
    ranch_ssl;
×
245
get_transport(#xmpp_socket{module = Module}) ->
246
    Module.
×
247

248
-spec get_conn_type(socket()) -> conn_type().
249
get_conn_type(Socket) ->
250
    case is_ssl(Socket) of
72,020✔
251
        true -> tls;
7,368✔
252
        false -> tcp
64,652✔
253
    end.
254

255
-spec get_ip(socket()) -> mongoose_transport:peer().
256
get_ip(#ranch_tcp{ip = Ip}) ->
257
    Ip;
129,219✔
258
get_ip(#ranch_ssl{ip = Ip}) ->
259
    Ip;
17,610✔
260
get_ip(#xmpp_socket{module = Module, state = State}) ->
261
    Module:peername(State).
5,867✔
262

263
-spec is_channel_binding_supported(socket()) -> boolean().
264
-spec export_key_materials(socket(), Labels, Contexts, WantedLengths, ConsumeSecret) ->
265
    {ok, ExportKeyMaterials} |
266
    {error, undefined_tls_material | exporter_master_secret_already_consumed | bad_input}
267
      when
268
      Labels :: [binary()],
269
      Contexts :: [binary() | no_context],
270
      WantedLengths :: [non_neg_integer()],
271
      ConsumeSecret :: boolean(),
272
      ExportKeyMaterials :: binary() | [binary()].
273

274
-if(?OTP_RELEASE >= 27).
275
is_channel_binding_supported(#ranch_ssl{}) ->
276
    true;
20,812✔
277
is_channel_binding_supported(#ranch_tcp{}) ->
278
    false;
121,539✔
279
is_channel_binding_supported(#xmpp_socket{module = Module, state = State}) ->
280
    Module:is_channel_binding_supported(State).
4,772✔
281

282
export_key_materials(#ranch_ssl{socket = Socket}, Labels, Contexts, WantedLengths, ConsumeSecret) ->
283
    ssl:export_key_materials(Socket, Labels, Contexts, WantedLengths, ConsumeSecret);
2,151✔
284
export_key_materials(#ranch_tcp{}, _, _, _, _) ->
UNCOV
285
    {error, undefined_tls_material};
×
286
export_key_materials(#xmpp_socket{module = Module, state = State},
287
                     Labels, Contexts, WantedLengths, ConsumeSecret) ->
UNCOV
288
    Module:export_key_materials(State, Labels, Contexts, WantedLengths, ConsumeSecret).
×
289
-else.
290
is_channel_binding_supported(#ranch_ssl{}) ->
291
    false;
292
is_channel_binding_supported(#ranch_tcp{}) ->
293
    false;
294
is_channel_binding_supported(#xmpp_socket{module = Module, state = State}) ->
295
    Module:is_channel_binding_supported(State).
296

297
export_key_materials(#ranch_tcp{}, _, _, _, _) ->
298
    {error, undefined_tls_material};
299
export_key_materials(#ranch_ssl{}, _, _, _, _) ->
300
    {error, undefined_tls_material};
301
export_key_materials(#xmpp_socket{module = Module, state = State},
302
                     Labels, Contexts, WantedLengths, ConsumeSecret) ->
303
    Module:export_key_materials(State, Labels, Contexts, WantedLengths, ConsumeSecret).
304
-endif.
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