Packages
amqp10_client
4.1.5-rc.2
4.2.1
4.2.0
retired
4.1.6
4.1.5
retired
4.1.5-rc.2
retired
4.1.5-rc.1
retired
4.1.5-1
4.0.3
4.0.3-rc.1
3.13.0-rc.2
3.13.0-rc.1
3.12.14
3.12.13
3.12.12
3.12.11
3.12.10
3.12.9
3.12.8
3.12.7
3.12.6
3.12.5
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.12.0-rc.4
3.12.0-rc.3
3.12.0-rc.2
3.12.0-rc.1
3.11.28
3.11.27
3.11.26
3.11.25
3.11.24
3.11.23
3.11.22
3.11.21
3.11.20
3.11.19
3.11.18
3.11.17
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.11.0-rc.2
3.11.0-rc.1
3.11.0-1
3.10.25
3.10.24
3.10.23
3.10.22
3.10.20
3.10.19
3.10.18
3.10.17
3.10.16
3.10.15
3.10.14
3.10.13
3.10.12
3.10.11
3.10.10
3.10.9
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
retired
3.10.2-1
3.10.1
retired
3.10.0
retired
3.10.0-rc.6
3.10.0-rc.5
3.10.0-rc.1
3.9.29
3.9.28
3.9.27
3.9.26
3.9.25
3.9.24
3.9.23
3.9.22
3.9.21
3.9.20
3.9.19
3.9.18
retired
3.9.17
3.9.16
3.9.15
3.8.35
3.8.34
3.8.33
3.8.32
3.8.31
3.8.30
0.0.0-rc.1
AMQP 1.0 client
Retired package: Release invalid - invalid
Current section
Files
Jump to
Current section
Files
src/amqp10_client_socket.erl
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2007-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
%%
-module(amqp10_client_socket).
-feature(maybe_expr, enable).
-export([connect/3,
set_active_once/1,
send/2,
close/1]).
-type socket() :: {tcp, gen_tcp:socket()} |
{ssl, ssl:sslsocket()} |
{ws, pid(), gun:stream_ref()}.
-export_type([socket/0]).
-define(TCP_OPTS, [binary,
{packet, 0},
{active, false},
{nodelay, true}]).
-spec connect(inet:hostname() | inet:ip_address(),
inet:port_number(),
amqp10_client_connection:connection_config()) ->
{ok, socket()} | {error, any()}.
connect(Host, Port, #{ws_path := Path} = Opts) ->
GunOpts = maps:merge(#{tcp_opts => [{nodelay, true}]},
maps:get(ws_opts, Opts, #{})),
maybe
{ok, _Started} ?= application:ensure_all_started(gun),
{ok, Pid} ?= gun:open(Host, Port, GunOpts),
MRef = monitor(process, Pid),
{ok, _HttpVsn} ?= gun:await_up(Pid, MRef),
{ok, StreamRef} ?= ws_upgrade(Pid, Path),
{ok, {ws, Pid, StreamRef}}
end;
connect(Host, Port, #{tls_opts := {secure_port, Opts0}}) ->
Opts = rabbit_ssl_options:fix_client(Opts0),
case ssl:connect(Host, Port, ?TCP_OPTS ++ Opts) of
{ok, S} ->
{ok, {ssl, S}};
Err ->
Err
end;
connect(Host, Port, _) ->
case gen_tcp:connect(Host, Port, ?TCP_OPTS) of
{ok, S} ->
{ok, {tcp, S}};
Err ->
Err
end.
ws_upgrade(Pid, Path) ->
StreamRef = gun:ws_upgrade(Pid,
Path,
[{<<"cache-control">>, <<"no-cache">>}],
#{protocols => [{<<"amqp">>, gun_ws_h}]}),
receive
{gun_upgrade, Pid, StreamRef, [<<"websocket">>], _Headers} ->
{ok, StreamRef};
{gun_response, Pid, _, _, Status, Headers} ->
{error, {ws_upgrade, Status, Headers}};
{gun_error, Pid, StreamRef, Reason} ->
{error, {ws_upgrade, Reason}}
after 5000 ->
{error, {ws_upgrade, timeout}}
end.
-spec set_active_once(socket()) -> ok.
set_active_once({tcp, Sock}) ->
ok = inet:setopts(Sock, [{active, once}]);
set_active_once({ssl, Sock}) ->
ok = ssl:setopts(Sock, [{active, once}]);
set_active_once({ws, _Pid, _Ref}) ->
%% Gun also has an active-like mode via the flow option and gun:update_flow.
%% It will even make Gun stop reading from the socket if flow is zero.
%% If needed, we can make use of it in future.
ok.
-spec send(socket(), iodata()) ->
ok | {error, any()}.
send({tcp, Socket}, Data) ->
gen_tcp:send(Socket, Data);
send({ssl, Socket}, Data) ->
ssl:send(Socket, Data);
send({ws, Pid, Ref}, Data) ->
gun:ws_send(Pid, Ref, {binary, Data}).
-spec close(socket()) ->
ok | {error, any()}.
close({tcp, Socket}) ->
gen_tcp:close(Socket);
close({ssl, Socket}) ->
ssl:close(Socket);
close({ws, Pid, _Ref}) ->
gun:shutdown(Pid).