Current section
Files
Jump to
Current section
Files
src/neon@tcp.erl
-module(neon@tcp).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/neon/tcp.gleam").
-export([new/2, ip_version/2, timeout/2, connect/1, send/2, 'receive'/3, active/1, passive/1, controlling_process/2, select/2, shutdown/1, listen/2, accept/2, close/1, port/1]).
-export_type([tcp/0, tcp_error/0, tcp_message/0, connect_options/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type tcp() :: any().
-type tcp_error() :: closed |
timeout |
system_limit |
not_owner |
invalid_pid |
{posix, neon@net:posix()} |
{tcp_error, binary()}.
-type tcp_message() :: {packet, tcp(), bitstring()} |
{socket_closed, tcp()} |
{socket_error, tcp(), tcp_error()}.
-opaque connect_options() :: {connect_options,
neon@net:address(),
neon@net:port_(),
neon@net:ip_version(),
neon@net:timeout_()}.
-file("src/neon/tcp.gleam", 55).
?DOC(
" Creates connection options for the given address and port.\n"
"\n"
" Defaults to IPv4 if the address is a `net.hostname`. Default timeout is set to `infinity`.\n"
).
-spec new(neon@net:address(), neon@net:port_()) -> connect_options().
new(Address, Port) ->
Ip_version = begin
_pipe = neon@net:address_to_ip_version(Address),
gleam@option:unwrap(_pipe, ipv4)
end,
{connect_options, Address, Port, Ip_version, infinity}.
-file("src/neon/tcp.gleam", 64).
?DOC(" Sets the IP version for the connection.\n").
-spec ip_version(connect_options(), neon@net:ip_version()) -> connect_options().
ip_version(Opts, Ip_version) ->
{connect_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
Ip_version,
erlang:element(5, Opts)}.
-file("src/neon/tcp.gleam", 72).
?DOC(" Sets the connection timeout.\n").
-spec timeout(connect_options(), neon@net:timeout_()) -> connect_options().
timeout(Opts, Timeout) ->
{connect_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
Timeout}.
-file("src/neon/tcp.gleam", 77).
?DOC(" Establishes a TCP connection using the given options.\n").
-spec connect(connect_options()) -> {ok, tcp()} | {error, tcp_error()}.
connect(Opts) ->
_pipe = erlang:element(2, Opts),
tcp_ffi:connect(
_pipe,
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts)
).
-file("src/neon/tcp.gleam", 83).
?DOC(" Sends data over a TCP socket.\n").
-spec send(tcp(), bitstring()) -> {ok, nil} | {error, tcp_error()}.
send(Socket, Payload) ->
tcp_ffi:send(Socket, Payload).
-file("src/neon/tcp.gleam", 91).
?DOC(
" Receives data from a TCP socket.\n"
"\n"
" The `length` parameter specifies the number of bytes to receive. Use `0`\n"
" to receive whatever data is available. Must be non-negative.\n"
).
-spec 'receive'(tcp(), integer(), neon@net:timeout_()) -> {ok, bitstring()} |
{error, tcp_error()}.
'receive'(Socket, Length, Timeout) ->
case Length >= 0 of
true ->
tcp_ffi:recv(Socket, Length, Timeout);
false ->
{error, {tcp_error, <<"Length must be non-negative"/utf8>>}}
end.
-file("src/neon/tcp.gleam", 106).
?DOC(
" Sets the socket to active mode.\n"
"\n"
" In active mode, incoming data is delivered as messages to the socket\n"
" owner's mailbox. Use `select` to handle these messages.\n"
).
-spec active(tcp()) -> {ok, tcp()} | {error, tcp_error()}.
active(Socket) ->
tcp_ffi:active(Socket).
-file("src/neon/tcp.gleam", 113).
?DOC(
" Sets the socket to passive mode.\n"
"\n"
" In passive mode, data must be read explicitly using `receive`.\n"
).
-spec passive(tcp()) -> {ok, tcp()} | {error, tcp_error()}.
passive(Socket) ->
tcp_ffi:passive(Socket).
-file("src/neon/tcp.gleam", 120).
?DOC(
" Change the controlling process of a socket.\n"
"\n"
" The controlling process is the process that the socket sends messages to.\n"
).
-spec controlling_process(tcp(), gleam@erlang@process:pid_()) -> {ok, nil} |
{error, tcp_error()}.
controlling_process(Socket, Pid) ->
tcp_ffi:controlling_process(Socket, Pid).
-file("src/neon/tcp.gleam", 132).
?DOC(
" Adds TCP message handlers to a selector for use with active mode sockets.\n"
"\n"
" In active mode, incoming data, close notifications, and errors are\n"
" delivered as messages to the socket owner's mailbox. Use this function\n"
" to register handlers for these messages on a `Selector`.\n"
).
-spec select(gleam@erlang@process:selector(DWZ), fun((tcp_message()) -> DWZ)) -> gleam@erlang@process:selector(DWZ).
select(Selector, Mapper) ->
Mapping = fun(Msg) -> Mapper(tcp_ffi:handle_tcp_message(Msg)) end,
_pipe = Selector,
_pipe@1 = gleam@erlang@process:select_record(
_pipe,
erlang:binary_to_atom(<<"tcp"/utf8>>),
2,
Mapping
),
_pipe@2 = gleam@erlang@process:select_record(
_pipe@1,
erlang:binary_to_atom(<<"tcp_closed"/utf8>>),
1,
Mapping
),
gleam@erlang@process:select_record(
_pipe@2,
erlang:binary_to_atom(<<"tcp_error"/utf8>>),
2,
Mapping
).
-file("src/neon/tcp.gleam", 145).
?DOC(" Shuts down the socket for both reading and writing.\n").
-spec shutdown(tcp()) -> {ok, nil} | {error, tcp_error()}.
shutdown(Socket) ->
tcp_ffi:shutdown(Socket).
-file("src/neon/tcp.gleam", 150).
?DOC(" Creates a listening TCP socket bound to the given port and IP address.\n").
-spec listen(neon@net:port_(), neon@net:ip_address()) -> {ok, tcp()} |
{error, tcp_error()}.
listen(Port, Ip_address) ->
tcp_ffi:listen(Port, Ip_address).
-file("src/neon/tcp.gleam", 160).
?DOC(
" Accepts an incoming connection on a listening socket.\n"
"\n"
" Blocks until a connection arrives or the timeout expires.\n"
).
-spec accept(tcp(), neon@net:timeout_()) -> {ok, tcp()} | {error, tcp_error()}.
accept(Socket, Timeout) ->
tcp_ffi:accept(Socket, Timeout).
-file("src/neon/tcp.gleam", 167).
?DOC(
" Closes a TCP socket.\n"
"\n"
" This function is idempotent and always returns `Nil`.\n"
).
-spec close(tcp()) -> nil.
close(Socket) ->
tcp_ffi:close(Socket).
-file("src/neon/tcp.gleam", 174).
?DOC(
" Returns the port number assigned to a socket by the operating system.\n"
"\n"
" Useful when listening on port 0 (OS-assigned).\n"
).
-spec port(tcp()) -> {ok, neon@net:port_()} | {error, nil}.
port(Socket) ->
_pipe = inet_ffi:port(Socket),
gleam@result:'try'(_pipe, fun neon@net:port/1).