summaryrefslogtreecommitdiff
path: root/lib/kernel/src/socket.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src/socket.erl')
-rw-r--r--lib/kernel/src/socket.erl1270
1 files changed, 800 insertions, 470 deletions
diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl
index ccacb84293..02e199d088 100644
--- a/lib/kernel/src/socket.erl
+++ b/lib/kernel/src/socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2020-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2020-2023. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
debug/1, socket_debug/1, use_registry/1,
info/0, info/1,
i/0, i/1, i/2,
+ tables/0, table/1,
monitor/1, cancel_monitor/1,
supports/0, supports/1, supports/2,
is_supported/1, is_supported/2, is_supported/3,
@@ -87,6 +88,10 @@
select_handle/0,
select_info/0,
+ completion_tag/0,
+ completion_handle/0,
+ completion_info/0,
+
invalid/0,
socket_counters/0,
@@ -151,15 +156,18 @@
%% We need #file_descriptor{} for sendfile/2,3,4,5
-include("file_int.hrl").
+%% -define(DBG(T), erlang:display({{self(), ?MODULE, ?LINE, ?FUNCTION_NAME}, T})).
+
%% Also in prim_socket
-define(REGISTRY, socket_registry).
-type invalid() :: {invalid, What :: term()}.
-type info() ::
- #{counters := #{atom() := non_neg_integer()},
- iov_max := non_neg_integer(),
- use_registry := boolean()}.
+ #{counters := #{atom() := non_neg_integer()},
+ iov_max := non_neg_integer(),
+ use_registry := boolean(),
+ io_backend := #{name := atom()}}.
-type socket_counters() :: #{read_byte := non_neg_integer(),
read_fails := non_neg_integer(),
@@ -771,18 +779,27 @@
%% Interface term formats
%%
--opaque select_tag() :: atom() | {atom(), ContData :: term()}.
+-opaque select_tag() :: atom() | {atom(), ContData :: term()}.
+-opaque completion_tag() :: atom(). % | {atom(), ContData :: term()}.
-type select_handle() :: reference().
+-type completion_handle() :: reference().
-type select_info() ::
{select_info,
SelectTag :: select_tag(),
SelectHandle :: select_handle()}.
+-type completion_info() ::
+ {completion_info,
+ CompletionTag :: completion_tag(),
+ CompletionHandle :: completion_handle()}.
-define(SELECT_INFO(Tag, SelectHandle),
{select_info, Tag, SelectHandle}).
+-define(COMPLETION_INFO(Tag, CompletionHandle),
+ {completion_info, Tag, CompletionHandle}).
+
%% ===========================================================================
%%
@@ -988,6 +1005,17 @@ use_registry(D) when is_boolean(D) ->
prim_socket:use_registry(D).
+tables() ->
+ #{protocols => table(protocols),
+ options => table(options),
+ ioctl_requests => table(ioctl_requests),
+ ioctl_flags => table(ioctl_flags),
+ msg_flags => table(msg_flags)}.
+
+table(Table) ->
+ prim_socket:p_get(Table).
+
+
%% ===========================================================================
%%
%% i/0,1,2 - List sockets
@@ -1111,12 +1139,23 @@ i_socket_info(_Proto, _Socket, #{domain := Domain} = _Info, domain) ->
atom_to_list(Domain);
i_socket_info(_Proto, _Socket, #{type := Type} = _Info, type) ->
string:to_upper(atom_to_list(Type));
-i_socket_info(Proto, _Socket, _Info, protocol) ->
- string:to_upper(atom_to_list(Proto));
+i_socket_info(Proto, _Socket, #{type := Type} = _Info, protocol) ->
+ string:to_upper(atom_to_list(if
+ (Proto =:= 0) ->
+ case Type of
+ stream -> tcp;
+ dgram -> udp;
+ _ -> unknown
+ end;
+ true ->
+ Proto
+ end));
i_socket_info(_Proto, Socket, _Info, fd) ->
- case socket:getopt(Socket, otp, fd) of
+ try socket:getopt(Socket, otp, fd) of
{ok, FD} -> integer_to_list(FD);
{error, _} -> " "
+ catch
+ _:_ -> " "
end;
i_socket_info(_Proto, _Socket, #{owner := Pid} = _Info, owner) ->
pid_to_list(Pid);
@@ -1128,11 +1167,14 @@ i_socket_info(Proto, Socket, _Info, local_address) ->
" "
end;
i_socket_info(Proto, Socket, _Info, remote_address) ->
- case peername(Socket) of
+ try peername(Socket) of
{ok, Addr} ->
fmt_sockaddr(Addr, Proto);
{error, _} ->
" "
+ catch
+ _:_ ->
+ " "
end;
i_socket_info(_Proto, _Socket,
#{counters := #{read_byte := N}} = _Info, recv) ->
@@ -1552,59 +1594,77 @@ connect(Socket, SockAddr) ->
-spec connect(Socket, SockAddr, Timeout :: 'nowait') ->
'ok' |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- SockAddr :: sockaddr(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid() | 'already';
-
- (Socket, SockAddr, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ SockAddr :: sockaddr(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid() | 'already' |
+ 'not_bound' |
+ {add_socket, posix()} |
+ {update_connect_context, posix()};
+
+ (Socket, SockAddr, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- SockAddr :: sockaddr(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid() | 'already';
+ Socket :: socket(),
+ SockAddr :: sockaddr(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid() | 'already' |
+ 'not_bound' |
+ {add_socket, posix()} |
+ {update_connect_context, posix()};
(Socket, SockAddr, Timeout :: 'infinity') ->
'ok' |
{'error', Reason} when
Socket :: socket(),
SockAddr :: sockaddr(),
- Reason :: posix() | 'closed' | invalid() | 'already';
+ Reason :: posix() | 'closed' | invalid() | 'already' |
+ 'not_bound' |
+ {add_socket, posix()} |
+ {update_connect_context, posix()};
(Socket, SockAddr, Timeout :: non_neg_integer()) ->
'ok' |
{'error', Reason} when
Socket :: socket(),
SockAddr :: sockaddr(),
- Reason :: posix() | 'closed' | invalid() | 'already' | 'timeout'.
+ Reason :: posix() | 'closed' | invalid() | 'already' |
+ 'not_bound' | 'timeout' |
+ {add_socket, posix()} |
+ {update_connect_context, posix()}.
%% <KOLLA>
%% Is it possible to connect with family = local for the (dest) sockaddr?
%% </KOLLA>
-connect(?socket(SockRef), SockAddr, Timeout)
+connect(?socket(SockRef), SockAddr, TimeoutOrHandle)
when is_reference(SockRef) ->
- case deadline(Timeout) of
+ case deadline(TimeoutOrHandle) of
invalid ->
- erlang:error({invalid, {timeout, Timeout}});
+ erlang:error({invalid, {timeout, TimeoutOrHandle}});
nowait ->
- SelectHandle = make_ref(),
- connect_nowait(SockRef, SockAddr, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- connect_nowait(SockRef, SockAddr, SelectHandle);
+ Handle = make_ref(),
+ connect_nowait(SockRef, SockAddr, Handle);
+ handle ->
+ Handle = TimeoutOrHandle,
+ connect_nowait(SockRef, SockAddr, Handle);
Deadline ->
connect_deadline(SockRef, SockAddr, Deadline)
end;
connect(Socket, SockAddr, Timeout) ->
erlang:error(badarg, [Socket, SockAddr, Timeout]).
-connect_nowait(SockRef, SockAddr, SelectHandle) ->
- case prim_socket:connect(SockRef, SelectHandle, SockAddr) of
+connect_nowait(SockRef, SockAddr, Handle) ->
+ case prim_socket:connect(SockRef, Handle, SockAddr) of
select ->
- {select, ?SELECT_INFO(connect, SelectHandle)};
+ {select, ?SELECT_INFO(connect, Handle)};
+ completion ->
+ {completion, ?COMPLETION_INFO(connect, Handle)};
Result ->
Result
end.
@@ -1624,6 +1684,18 @@ connect_deadline(SockRef, SockAddr, Deadline) ->
_ = cancel(SockRef, connect, Ref),
{error, timeout}
end;
+ completion ->
+ %% Connecting...
+ Timeout = timeout(Deadline),
+ receive
+ ?socket_msg(_Socket, completion, {Ref, CompletionStatus}) ->
+ CompletionStatus;
+ ?socket_msg(_Socket, abort, {Ref, Reason}) ->
+ {error, Reason}
+ after Timeout ->
+ _ = cancel(SockRef, connect, Ref),
+ {error, timeout}
+ end;
Result ->
Result
end.
@@ -1650,7 +1722,7 @@ connect(Socket) ->
-spec listen(Socket) -> 'ok' | {'error', Reason} when
Socket :: socket(),
- Reason :: posix() | 'closed'.
+ Reason :: posix() | 'closed' | 'not_bound'.
listen(Socket) ->
listen(Socket, ?ESOCK_LISTEN_BACKLOG_DEFAULT).
@@ -1683,34 +1755,50 @@ accept(ListenSocket) ->
-spec accept(ListenSocket, Timeout :: 'nowait') ->
{'ok', Socket} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
ListenSocket :: socket(),
Socket :: socket(),
SelectInfo :: select_info(),
- Reason :: posix() | closed | invalid();
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | closed | invalid() |
+ {create_accept_socket, posix()} |
+ {add_accept_socket, posix()} |
+ {update_accept_context, posix()};
- (ListenSocket, SelectHandle :: select_handle()) ->
+ (ListenSocket, Handle :: select_handle() | completion_handle()) ->
{'ok', Socket} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
ListenSocket :: socket(),
Socket :: socket(),
SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid() |
+ {create_accept_socket, posix()} |
+ {add_socket, posix()} |
+ {update_accept_context, posix()};
(ListenSocket, Timeout :: 'infinity') ->
{'ok', Socket} |
{'error', Reason} when
ListenSocket :: socket(),
Socket :: socket(),
- Reason :: posix() | 'closed' | invalid();
+ Reason :: posix() | 'closed' | invalid() |
+ {create_accept_socket, posix()} |
+ {add_socket, posix()} |
+ {update_accept_context, posix()};
(ListenSocket, Timeout :: non_neg_integer()) ->
{'ok', Socket} |
{'error', Reason} when
ListenSocket :: socket(),
Socket :: socket(),
- Reason :: posix() | 'closed' | invalid() | 'timeout'.
+ Reason :: posix() | 'closed' | invalid() | 'timeout' |
+ {create_accept_socket, posix()} |
+ {add_socket, posix()} |
+ {update_accept_context, posix()}.
accept(?socket(LSockRef), Timeout)
when is_reference(LSockRef) ->
@@ -1718,23 +1806,25 @@ accept(?socket(LSockRef), Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- accept_nowait(LSockRef, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- accept_nowait(LSockRef, SelectHandle);
+ Handle = make_ref(),
+ accept_nowait(LSockRef, Handle);
+ handle ->
+ Handle = Timeout,
+ accept_nowait(LSockRef, Handle);
Deadline ->
accept_deadline(LSockRef, Deadline)
end;
accept(ListenSocket, Timeout) ->
erlang:error(badarg, [ListenSocket, Timeout]).
-accept_nowait(LSockRef, SelectHandle) ->
- case prim_socket:accept(LSockRef, SelectHandle) of
+accept_nowait(LSockRef, Handle) ->
+ case prim_socket:accept(LSockRef, Handle) of
select ->
- {select, ?SELECT_INFO(accept, SelectHandle)};
+ {select, ?SELECT_INFO(accept, Handle)};
+ completion ->
+ {completion, ?COMPLETION_INFO(accept, Handle)};
Result ->
- accept_result(LSockRef, SelectHandle, Result)
+ accept_result(LSockRef, Handle, Result)
end.
accept_deadline(LSockRef, Deadline) ->
@@ -1754,6 +1844,22 @@ accept_deadline(LSockRef, Deadline) ->
_ = cancel(LSockRef, accept, AccRef),
{error, timeout}
end;
+ completion ->
+ %% Each call is non-blocking, but even then it takes
+ %% *some* time, so just to be sure, recalculate before
+ %% the receive.
+ Timeout = timeout(Deadline),
+ receive
+ %% CompletionStatus = {ok, Socket} | {error, Reason}
+ ?socket_msg(?socket(LSockRef), completion,
+ {AccRef, CompletionStatus}) ->
+ CompletionStatus;
+ ?socket_msg(_Socket, abort, {AccRef, Reason}) ->
+ {error, Reason}
+ after Timeout ->
+ _ = cancel(LSockRef, accept, AccRef),
+ {error, timeout}
+ end;
Result ->
accept_result(LSockRef, AccRef, Result)
end.
@@ -1814,31 +1920,35 @@ send(Socket, Data) ->
RestData :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Data, SelectHandle :: 'nowait') ->
+ (Socket, Data, Handle :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Data, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Data :: iodata(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Data, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Timeout :: 'infinity') ->
'ok' |
@@ -1870,33 +1980,37 @@ send(Socket, Data, Timeout) ->
send(Socket, Data, ?ESOCK_SEND_FLAGS_DEFAULT, Timeout).
--spec send(Socket, Data, Flags, SelectHandle :: 'nowait') ->
+-spec send(Socket, Data, Flags, Handle :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Flags :: [msg_flag() | integer()],
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Data, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Data :: iodata(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Data, Flags, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Flags :: [msg_flag() | integer()],
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Flags, Timeout :: 'infinity') ->
'ok' |
@@ -1929,12 +2043,12 @@ send(Socket, Data, Timeout) ->
{'select', {SelectInfo, RestData}} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Cont :: select_info(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Cont :: select_info(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Cont, SelectHandle :: select_handle()) ->
'ok' |
@@ -1984,7 +2098,7 @@ send(?socket(SockRef), Data, ?SELECT_INFO(SelectTag, _) = Cont, Timeout)
nowait ->
SelectHandle = make_ref(),
send_nowait_cont(SockRef, Data, ContData, SelectHandle);
- select_handle ->
+ handle ->
SelectHandle = Timeout,
send_nowait_cont(SockRef, Data, ContData, SelectHandle);
Deadline ->
@@ -2001,11 +2115,11 @@ send(?socket(SockRef), Data, Flags, Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- send_nowait(SockRef, Data, Flags, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- send_nowait(SockRef, Data, Flags, SelectHandle);
+ Handle = make_ref(),
+ send_nowait(SockRef, Data, Flags, Handle);
+ handle ->
+ Handle = Timeout,
+ send_nowait(SockRef, Data, Flags, Handle);
Deadline ->
send_deadline(SockRef, Data, Flags, Deadline)
end;
@@ -2024,40 +2138,45 @@ send(?socket(SockRef) = Socket, Data, Flags, Timeout)
send(Socket, Data, Flags, Timeout) ->
erlang:error(badarg, [Socket, Data, Flags, Timeout]).
-send_nowait(SockRef, Bin, Flags, SelectHandle) ->
+send_nowait(SockRef, Bin, Flags, Handle) ->
send_common_nowait_result(
- SelectHandle, send,
- prim_socket:send(SockRef, Bin, Flags, SelectHandle)).
+ Handle, send,
+ prim_socket:send(SockRef, Bin, Flags, Handle)).
+%% On Windows, writes either succeed directly (it their entirety),
+%% they are scheduled (completion) or they fail. *No* partial success,
+%% and therefor no need to handle theme here (in cont).
send_nowait_cont(SockRef, Bin, Cont, SelectHandle) ->
send_common_nowait_result(
SelectHandle, send,
prim_socket:send(SockRef, Bin, Cont, SelectHandle)).
send_deadline(SockRef, Bin, Flags, Deadline) ->
- SelectHandle = make_ref(),
+ Handle = make_ref(),
HasWritten = false,
send_common_deadline_result(
- SockRef, Bin, SelectHandle, Deadline, HasWritten,
+ SockRef, Bin, Handle, Deadline, HasWritten,
send, fun send_deadline_cont/5,
- prim_socket:send(SockRef, Bin, Flags, SelectHandle)).
+ prim_socket:send(SockRef, Bin, Flags, Handle)).
send_deadline_cont(SockRef, Bin, Cont, Deadline, HasWritten) ->
- SelectHandle = make_ref(),
+ Handle = make_ref(),
send_common_deadline_result(
- SockRef, Bin, SelectHandle, Deadline, HasWritten,
+ SockRef, Bin, Handle, Deadline, HasWritten,
send, fun send_deadline_cont/5,
- prim_socket:send(SockRef, Bin, Cont, SelectHandle)).
+ prim_socket:send(SockRef, Bin, Cont, Handle)).
-compile({inline, [send_common_nowait_result/3]}).
-send_common_nowait_result(SelectHandle, Op, Result) ->
+send_common_nowait_result(Handle, Op, Result) ->
case Result of
+ completion ->
+ {completion, ?COMPLETION_INFO(Op, Handle)};
{select, ContData} ->
- {select, ?SELECT_INFO({Op, ContData}, SelectHandle)};
+ {select, ?SELECT_INFO({Op, ContData}, Handle)};
{select, Data, ContData} ->
- {select, {?SELECT_INFO({Op, ContData}, SelectHandle), Data}};
+ {select, {?SELECT_INFO({Op, ContData}, Handle), Data}};
%%
Result ->
Result
@@ -2065,7 +2184,7 @@ send_common_nowait_result(SelectHandle, Op, Result) ->
-compile({inline, [send_common_deadline_result/8]}).
send_common_deadline_result(
- SockRef, Data, SelectHandle, Deadline, HasWritten,
+ SockRef, Data, Handle, Deadline, HasWritten,
Op, Fun, SendResult) ->
%%
case SendResult of
@@ -2073,26 +2192,40 @@ send_common_deadline_result(
%% Would block, wait for continuation
Timeout = timeout(Deadline),
receive
- ?socket_msg(_Socket, select, SelectHandle) ->
+ ?socket_msg(_Socket, select, Handle) ->
Fun(SockRef, Data, Cont, Deadline, HasWritten);
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
send_common_error(Reason, Data, HasWritten)
after Timeout ->
- _ = cancel(SockRef, Op, SelectHandle),
+ _ = cancel(SockRef, Op, Handle),
send_common_error(timeout, Data, HasWritten)
end;
{select, Data_1, Cont} ->
%% Partial send success, wait for continuation
Timeout = timeout(Deadline),
receive
- ?socket_msg(_Socket, select, SelectHandle) ->
+ ?socket_msg(_Socket, select, Handle) ->
Fun(SockRef, Data_1, Cont, Deadline, true);
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
send_common_error(Reason, Data_1, true)
after Timeout ->
- _ = cancel(SockRef, Op, SelectHandle),
+ _ = cancel(SockRef, Op, Handle),
send_common_error(timeout, Data_1, true)
end;
+
+ completion ->
+ %% Would block, wait for continuation
+ Timeout = timeout(Deadline),
+ receive
+ ?socket_msg(_Socket, completion, {Handle, CompletionStatus}) ->
+ CompletionStatus;
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
+ send_common_error(Reason, Data, false)
+ after Timeout ->
+ _ = cancel(SockRef, Op, Handle),
+ send_common_error(timeout, Data, false)
+ end;
+
%%
{error, {_Reason, RestIOV}} = Error when is_list(RestIOV) ->
Error;
@@ -2165,45 +2298,49 @@ sendto(Socket, Data, Dest_Cont) ->
RestData :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Data, Dest, SelectHandle :: 'nowait') ->
+ (Socket, Data, Dest, Handle :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: sockaddr(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Data, Dest, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Data, Dest, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: sockaddr(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Dest, Timeout :: 'infinity') ->
'ok' |
{'ok', RestData} |
{'error', Reason} |
{'error', {Reason, RestData}}
- when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: sockaddr(),
- RestData :: binary(),
- Reason :: posix() | 'closed' | invalid();
+ when
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ RestData :: binary(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Dest, Timeout :: non_neg_integer()) ->
'ok' |
@@ -2224,12 +2361,12 @@ sendto(Socket, Data, Dest_Cont) ->
{'select', {SelectInfo, RestData}} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Cont :: select_info(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Cont :: select_info(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Cont, SelectHandle :: select_handle()) ->
'ok' |
@@ -2238,12 +2375,12 @@ sendto(Socket, Data, Dest_Cont) ->
{'select', {SelectInfo, RestData}} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Cont :: select_info(),
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Cont :: select_info(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Cont, Timeout :: 'infinity') ->
'ok' |
@@ -2301,35 +2438,39 @@ sendto(Socket, Data, Dest, Timeout) ->
sendto(Socket, Data, Dest, ?ESOCK_SENDTO_FLAGS_DEFAULT, Timeout).
--spec sendto(Socket, Data, Dest, Flags, SelectHandle :: 'nowait') ->
+-spec sendto(Socket, Data, Dest, Flags, Handle :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: sockaddr(),
- Flags :: [msg_flag() | integer()],
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Data, Dest, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Data, Dest, Flags, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason}
when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: sockaddr(),
- Flags :: [msg_flag() | integer()],
- RestData :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Dest, Flags, Timeout :: 'infinity') ->
'ok' |
@@ -2366,9 +2507,9 @@ sendto(?socket(SockRef), Data, Dest, Flags, Timeout)
nowait ->
SelectHandle = make_ref(),
sendto_nowait(SockRef, Data, Dest, Flags, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- sendto_nowait(SockRef, Data, Dest, Flags, SelectHandle);
+ handle ->
+ Handle = Timeout,
+ sendto_nowait(SockRef, Data, Dest, Flags, Handle);
Deadline ->
HasWritten = false,
sendto_deadline(SockRef, Data, Dest, Flags, Deadline, HasWritten)
@@ -2395,37 +2536,38 @@ sendto_timeout_cont(SockRef, Bin, Cont, Timeout) ->
nowait ->
SelectHandle = make_ref(),
sendto_nowait_cont(SockRef, Bin, Cont, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- sendto_nowait_cont(SockRef, Bin, Cont, SelectHandle);
+ handle ->
+ Handle = Timeout,
+ sendto_nowait_cont(SockRef, Bin, Cont, Handle);
Deadline ->
HasWritten = false,
sendto_deadline_cont(SockRef, Bin, Cont, Deadline, HasWritten)
end.
-sendto_nowait(SockRef, Bin, To, Flags, SelectHandle) ->
+sendto_nowait(SockRef, Bin, To, Flags, Handle) ->
send_common_nowait_result(
- SelectHandle, sendto,
- prim_socket:sendto(SockRef, Bin, To, Flags, SelectHandle)).
+ Handle, sendto,
+ prim_socket:sendto(SockRef, Bin, To, Flags, Handle)).
-sendto_nowait_cont(SockRef, Bin, Cont, SelectHandle) ->
+sendto_nowait_cont(SockRef, Bin, Cont, Handle) ->
send_common_nowait_result(
- SelectHandle, sendto,
- prim_socket:sendto(SockRef, Bin, Cont, SelectHandle)).
+ Handle, sendto,
+ prim_socket:sendto(SockRef, Bin, Cont, Handle)).
sendto_deadline(SockRef, Bin, To, Flags, Deadline, HasWritten) ->
- SelectHandle = make_ref(),
+ Handle = make_ref(),
send_common_deadline_result(
- SockRef, Bin, SelectHandle, Deadline, HasWritten,
+ SockRef, Bin, Handle, Deadline, HasWritten,
sendto, fun sendto_deadline_cont/5,
- prim_socket:sendto(SockRef, Bin, To, Flags, SelectHandle)).
+ prim_socket:sendto(SockRef, Bin, To, Flags, Handle)).
sendto_deadline_cont(SockRef, Bin, Cont, Deadline, HasWritten) ->
- SelectHandle = make_ref(),
+ Handle = make_ref(),
send_common_deadline_result(
- SockRef, Bin, SelectHandle, Deadline, HasWritten,
+ SockRef, Bin, Handle, Deadline, HasWritten,
sendto, fun sendto_deadline_cont/5,
- prim_socket:sendto(SockRef, Bin, Cont, SelectHandle)).
+ prim_socket:sendto(SockRef, Bin, Cont, Handle)).
+
%% ---------------------------------------------------------------------------
%%
@@ -2480,28 +2622,32 @@ sendmsg(Socket, Msg) ->
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, RestData}}
when
- Socket :: socket(),
- Msg :: msg_send(),
- RestData :: erlang:iovec(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Msg, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Msg :: msg_send(),
+ RestData :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Msg, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, RestData}}
when
- Socket :: socket(),
- Msg :: msg_send(),
- RestData :: erlang:iovec(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Msg :: msg_send(),
+ RestData :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Msg, Timeout :: 'infinity') ->
'ok' |
@@ -2533,35 +2679,39 @@ sendmsg(Socket, Msg, Timeout) ->
sendmsg(Socket, Msg, ?ESOCK_SENDMSG_FLAGS_DEFAULT, Timeout).
--spec sendmsg(Socket, Msg, Flags, SelectHandle :: 'nowait') ->
+-spec sendmsg(Socket, Msg, Flags, Timeout :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, RestData}}
when
- Socket :: socket(),
- Msg :: msg_send(),
- Flags :: [msg_flag() | integer()],
- RestData :: erlang:iovec(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Msg, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Msg :: msg_send(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Msg, Flags, Handle :: select_handle() | completion_handle()) ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, RestData}}
when
- Socket :: socket(),
- Msg :: msg_send(),
- Flags :: [msg_flag() | integer()],
- RestData :: erlang:iovec(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Msg :: msg_send(),
+ Flags :: [msg_flag() | integer()],
+ RestData :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Msg, Flags, Timeout :: 'infinity') ->
'ok' |
@@ -2587,20 +2737,22 @@ sendmsg(Socket, Msg, Timeout) ->
RestData :: erlang:iovec(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Data, Cont, SelectHandle :: 'nowait') ->
+ (Socket, Data, Cont, Timeout :: 'nowait') ->
'ok' |
{'ok', RestData} |
{'select', SelectInfo} |
{'select', {SelectInfo, RestData}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, RestData}}
when
- Socket :: socket(),
- Data :: msg_send() | erlang:iovec(),
- Cont :: select_info(),
- RestData :: erlang:iovec(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Data :: msg_send() | erlang:iovec(),
+ Cont :: select_info(),
+ RestData :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Data, Cont, SelectHandle :: select_handle()) ->
'ok' |
@@ -2664,11 +2816,11 @@ sendmsg(?socket(SockRef), #{iov := IOV} = Msg, Flags, Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- sendmsg_nowait(SockRef, Msg, Flags, SelectHandle, IOV);
- select_handle ->
- SelectHandle = Timeout,
- sendmsg_nowait(SockRef, Msg, Flags, SelectHandle, IOV);
+ Handle = make_ref(),
+ sendmsg_nowait(SockRef, Msg, Flags, Handle, IOV);
+ handle ->
+ Handle = Timeout,
+ sendmsg_nowait(SockRef, Msg, Flags, Handle, IOV);
Deadline ->
HasWritten = false,
sendmsg_deadline(SockRef, Msg, Flags, Deadline, HasWritten, IOV)
@@ -2683,7 +2835,7 @@ sendmsg_timeout_cont(SockRef, RestData, Cont, Timeout) ->
nowait ->
SelectHandle = make_ref(),
sendmsg_nowait_cont(SockRef, RestData, Cont, SelectHandle);
- select_handle ->
+ handle ->
SelectHandle = Timeout,
sendmsg_nowait_cont(SockRef, RestData, Cont, SelectHandle);
Deadline ->
@@ -2692,10 +2844,10 @@ sendmsg_timeout_cont(SockRef, RestData, Cont, Timeout) ->
SockRef, RestData, Cont, Deadline, HasWritten)
end.
-sendmsg_nowait(SockRef, Msg, Flags, SelectHandle, IOV) ->
+sendmsg_nowait(SockRef, Msg, Flags, Handle, IOV) ->
send_common_nowait_result(
- SelectHandle, sendmsg,
- prim_socket:sendmsg(SockRef, Msg, Flags, SelectHandle, IOV)).
+ Handle, sendmsg,
+ prim_socket:sendmsg(SockRef, Msg, Flags, Handle, IOV)).
sendmsg_nowait_cont(SockRef, RestData, Cont, SelectHandle) ->
send_common_nowait_result(
@@ -2703,11 +2855,11 @@ sendmsg_nowait_cont(SockRef, RestData, Cont, SelectHandle) ->
prim_socket:sendmsg(SockRef, RestData, Cont, SelectHandle)).
sendmsg_deadline(SockRef, Msg, Flags, Deadline, HasWritten, IOV) ->
- SelectHandle = make_ref(),
+ Handle = make_ref(),
send_common_deadline_result(
- SockRef, IOV, SelectHandle, Deadline, HasWritten,
+ SockRef, IOV, Handle, Deadline, HasWritten,
sendmsg, fun sendmsg_deadline_cont/5,
- prim_socket:sendmsg(SockRef, Msg, Flags, SelectHandle, IOV)).
+ prim_socket:sendmsg(SockRef, Msg, Flags, Handle, IOV)).
sendmsg_deadline_cont(SockRef, Data, Cont, Deadline, HasWritten) ->
SelectHandle = make_ref(),
@@ -2716,6 +2868,7 @@ sendmsg_deadline_cont(SockRef, Data, Cont, Deadline, HasWritten) ->
sendmsg, fun sendmsg_deadline_cont/5,
prim_socket:sendmsg(SockRef, Data, Cont, SelectHandle)).
+
%% ===========================================================================
%%
%% sendfile - send a file on a socket
@@ -2901,7 +3054,7 @@ sendfile_int(SockRef, State, Timeout) ->
nowait ->
SelectHandle = make_ref(),
sendfile_nowait(SockRef, State, SelectHandle);
- select_handle ->
+ handle ->
SelectHandle = Timeout,
sendfile_nowait(SockRef, State, SelectHandle);
Deadline ->
@@ -3043,52 +3196,55 @@ recv(Socket) ->
recv(Socket, Flags) when is_list(Flags) ->
recv(Socket, 0, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
-recv(Socket, Length) ->
- recv(
- Socket, Length,
- ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
+recv(Socket, Length) when is_integer(Length) andalso (Length >= 0) ->
+ recv(Socket, Length,
+ ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recv(Socket, Flags, SelectHandle :: 'nowait') ->
+-spec recv(Socket, Flags, Handle :: 'nowait') ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Flags, Timeout :: 'infinity') ->
{'ok', Data} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
+ Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Data :: binary(),
- Reason :: posix() | 'closed' | invalid();
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Flags, Timeout :: non_neg_integer()) ->
{'ok', Data} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
+ Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Data :: binary(),
- Reason :: posix() | 'closed' | invalid() | 'timeout';
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid() | 'timeout';
(Socket, Length, Flags) ->
{'ok', Data} |
@@ -3100,47 +3256,51 @@ recv(Socket, Length) ->
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Length, SelectHandle :: 'nowait') ->
+ (Socket, Length, Handle :: 'nowait') ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Length, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Length, Handle :: select_handle() | completion_handle()) ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Length, Timeout :: 'infinity') ->
{'ok', Data} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Data :: binary(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Length, Timeout :: non_neg_integer()) ->
{'ok', Data} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Data :: binary(),
- Reason :: posix() | 'closed' | invalid() | 'timeout'.
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid() | 'timeout'.
recv(Socket, Flags, Timeout) when is_list(Flags) ->
recv(Socket, 0, Flags, Timeout);
@@ -3149,31 +3309,35 @@ recv(Socket, Length, Flags) when is_list(Flags) ->
recv(Socket, Length, Timeout) ->
recv(Socket, Length, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
--spec recv(Socket, Length, Flags, SelectHandle :: 'nowait') ->
+-spec recv(Socket, Length, Flags, Handle :: 'nowait') ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Length, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Length, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', Data} |
{'select', SelectInfo} |
{'select', {SelectInfo, Data}} |
+ {'completion', CompletionInfo} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Length, Flags, Timeout :: 'infinity') ->
{'ok', Data} |
@@ -3189,11 +3353,11 @@ recv(Socket, Length, Timeout) ->
{'ok', Data} |
{'error', Reason} |
{'error', {Reason, Data}} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Data :: binary(),
- Reason :: posix() | 'closed' | invalid() | 'timeout'.
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid() | 'timeout'.
recv(?socket(SockRef), Length, Flags, Timeout)
when is_reference(SockRef),
@@ -3203,11 +3367,11 @@ recv(?socket(SockRef), Length, Flags, Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- recv_nowait(SockRef, Length, Flags, SelectHandle, <<>>);
- select_handle ->
- SelectHandle = Timeout,
- recv_nowait(SockRef, Length, Flags, SelectHandle, <<>>);
+ Handle = make_ref(),
+ recv_nowait(SockRef, Length, Flags, Handle, <<>>);
+ handle ->
+ Handle = Timeout,
+ recv_nowait(SockRef, Length, Flags, Handle, <<>>);
zero ->
case prim_socket:recv(SockRef, Length, Flags, zero) of
ok ->
@@ -3224,8 +3388,8 @@ recv(Socket, Length, Flags, Timeout) ->
%% We will only recurse with Length == 0 if Length is 0,
%% so Length == 0 means to return all available data also when recursing
-recv_nowait(SockRef, Length, Flags, SelectHandle, Acc) ->
- case prim_socket:recv(SockRef, Length, Flags, SelectHandle) of
+recv_nowait(SockRef, Length, Flags, Handle, Acc) ->
+ case prim_socket:recv(SockRef, Length, Flags, Handle) of
{more, Bin} ->
%% We got what we requested but will not waste more time
%% although there might be more data available
@@ -3233,23 +3397,28 @@ recv_nowait(SockRef, Length, Flags, SelectHandle, Acc) ->
{select, Bin} ->
%% We got less than requested so the caller will
%% get a select message when there might be more to read
- {select, {?SELECT_INFO(recv, SelectHandle), bincat(Acc, Bin)}};
+ {select, {?SELECT_INFO(recv, Handle), bincat(Acc, Bin)}};
select ->
%% The caller will get a select message when there
%% might be data to read
if
byte_size(Acc) =:= 0 ->
- {select, ?SELECT_INFO(recv, SelectHandle)};
+ {select, ?SELECT_INFO(recv, Handle)};
true ->
- {select, {?SELECT_INFO(recv, SelectHandle), Acc}}
+ {select, {?SELECT_INFO(recv, Handle), Acc}}
end;
+ completion ->
+ %% The caller will get a completion message (with the
+ %% result) when the data arrives. *No* further action
+ %% is required.
+ {completion, ?COMPLETION_INFO(recv, Handle)};
Result ->
recv_result(Acc, Result)
end.
recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
- SelectHandle = make_ref(),
- case prim_socket:recv(SockRef, Length, Flags, SelectHandle) of
+ Handle = make_ref(),
+ case prim_socket:recv(SockRef, Length, Flags, Handle) of
{more, Bin} ->
%% There is more data readily available
%% - repeat unless time's up
@@ -3262,12 +3431,13 @@ recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
true ->
{ok, bincat(Acc, Bin)}
end;
+
%%
{select, Bin} ->
%% We got less than requested
Timeout = timeout(Deadline),
receive
- ?socket_msg(?socket(SockRef), select, SelectHandle) ->
+ ?socket_msg(?socket(SockRef), select, Handle) ->
if
0 < Timeout ->
%% Recv more
@@ -3277,10 +3447,10 @@ recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
true ->
{error, {timeout, bincat(Acc, Bin)}}
end;
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
{error, {Reason, bincat(Acc, Bin)}}
after Timeout ->
- _ = cancel(SockRef, recv, SelectHandle),
+ _ = cancel(SockRef, recv, Handle),
{error, {timeout, bincat(Acc, Bin)}}
end;
%%
@@ -3288,14 +3458,15 @@ recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
%% We first got some data and are then asked to wait,
%% but we only want the first that comes
%% - cancel and return what we have
- _ = cancel(SockRef, recv, SelectHandle),
+ _ = cancel(SockRef, recv, Handle),
{ok, Acc};
+ %%
select ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
Timeout = timeout(Deadline),
receive
- ?socket_msg(?socket(SockRef), select, SelectHandle) ->
+ ?socket_msg(?socket(SockRef), select, Handle) ->
if
0 < Timeout ->
%% Retry
@@ -3304,12 +3475,62 @@ recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
true ->
recv_error(Acc, timeout)
end;
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
recv_error(Acc, Reason)
after Timeout ->
- _ = cancel(SockRef, recv, SelectHandle),
+ _ = cancel(SockRef, recv, Handle),
recv_error(Acc, timeout)
end;
+
+ %%
+ completion ->
+ %% There is nothing just now, but we will be notified when the
+ %% data has been read (with a completion message).
+ Timeout = timeout(Deadline),
+ receive
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, {ok, _Bin} = OK})
+ when (Length =:= 0) ->
+ recv_result(Acc, OK);
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, {ok, Bin} = OK})
+ when (Length =:= byte_size(Bin)) ->
+ recv_result(Acc, OK);
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, {ok, Bin}}) ->
+ if
+ 0 < Timeout ->
+ %% Recv more
+ recv_deadline(
+ SockRef, Length - byte_size(Bin), Flags,
+ Deadline, bincat(Acc, Bin));
+ true ->
+ {error, {timeout, bincat(Acc, Bin)}}
+ end;
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, {error, Reason}}) ->
+ recv_error(Acc, Reason);
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
+ recv_error(Acc, Reason)
+ after Timeout ->
+ _ = cancel(SockRef, recv, Handle),
+ recv_error(Acc, timeout)
+ end;
+
+ %% We got some data, but not all
+ {ok, Bin} when (Length > byte_size(Bin)) ->
+ Timeout = timeout(Deadline),
+ if
+ 0 < Timeout ->
+ %% Recv more
+ recv_deadline(
+ SockRef, Length - byte_size(Bin), Flags,
+ Deadline, bincat(Acc, Bin));
+ true ->
+ {error, {timeout, bincat(Acc, Bin)}}
+ end;
+
+ %%
Result ->
recv_result(Acc, Result)
end.
@@ -3332,6 +3553,7 @@ recv_error(Acc, Reason) ->
{error, {Reason, Acc}}
end.
+
%% ---------------------------------------------------------------------------
%%
%% With recvfrom we get messages, which means that regardless of how
@@ -3382,27 +3604,31 @@ recvfrom(Socket, BufSz) ->
?ESOCK_RECV_FLAGS_DEFAULT,
?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recvfrom(Socket, Flags, SelectHandle :: 'nowait') ->
+-spec recvfrom(Socket, Flags, Handle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Flags, Timeout :: 'infinity') ->
{'ok', {Source, Data}} |
@@ -3432,27 +3658,31 @@ recvfrom(Socket, BufSz) ->
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, SelectHandle :: 'nowait') ->
+ (Socket, BufSz, Handle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, BufSz, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz, Handle :: select_handle() | completion_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, BufSz, Timeout :: 'infinity') ->
{'ok', {Source, Data}} |
@@ -3479,29 +3709,33 @@ recvfrom(Socket, BufSz, Flags) when is_list(Flags) ->
recvfrom(Socket, BufSz, Timeout) ->
recvfrom(Socket, BufSz, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
--spec recvfrom(Socket, BufSz, Flags, SelectHandle :: 'nowait') ->
+-spec recvfrom(Socket, BufSz, Flags, Handle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, BufSz, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Source :: sockaddr_recv(),
- Data :: binary(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, BufSz, Flags, Timeout :: 'infinity') ->
{'ok', {Source, Data}} |
@@ -3531,11 +3765,11 @@ recvfrom(?socket(SockRef), BufSz, Flags, Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags);
- select_handle ->
- SelectHandle = Timeout,
- recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags);
+ Handle = make_ref(),
+ recvfrom_nowait(SockRef, BufSz, Handle, Flags);
+ handle ->
+ Handle = Timeout,
+ recvfrom_nowait(SockRef, BufSz, Handle, Flags);
zero ->
case prim_socket:recvfrom(SockRef, BufSz, Flags, zero) of
ok ->
@@ -3549,30 +3783,48 @@ recvfrom(?socket(SockRef), BufSz, Flags, Timeout)
recvfrom(Socket, BufSz, Flags, Timeout) ->
erlang:error(badarg, [Socket, BufSz, Flags, Timeout]).
-recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags) ->
- case prim_socket:recvfrom(SockRef, BufSz, Flags, SelectHandle) of
- select ->
- {select, ?SELECT_INFO(recvfrom, SelectHandle)};
+recvfrom_nowait(SockRef, BufSz, Handle, Flags) ->
+ case prim_socket:recvfrom(SockRef, BufSz, Flags, Handle) of
+ select = Tag ->
+ {Tag, ?SELECT_INFO(recvfrom, Handle)};
+ completion = Tag ->
+ {Tag, ?COMPLETION_INFO(recvfrom, Handle)};
Result ->
recvfrom_result(Result)
end.
recvfrom_deadline(SockRef, BufSz, Flags, Deadline) ->
- SelectHandle = make_ref(),
- case prim_socket:recvfrom(SockRef, BufSz, Flags, SelectHandle) of
+ Handle = make_ref(),
+ case prim_socket:recvfrom(SockRef, BufSz, Flags, Handle) of
select ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
Timeout = timeout(Deadline),
receive
- ?socket_msg(?socket(SockRef), select, SelectHandle) ->
+ ?socket_msg(?socket(SockRef), select, Handle) ->
recvfrom_deadline(SockRef, BufSz, Flags, Deadline);
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
{error, Reason}
after Timeout ->
- _ = cancel(SockRef, recvfrom, SelectHandle),
+ _ = cancel(SockRef, recvfrom, Handle),
{error, timeout}
end;
+
+ completion ->
+ %% There is nothing just now, but we will be notified when there
+ %% is something to read (a completion message).
+ Timeout = timeout(Deadline),
+ receive
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, CompletionStatus}) ->
+ recvfrom_result(CompletionStatus);
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
+ {error, Reason}
+ after Timeout ->
+ _ = cancel(SockRef, recvfrom, Handle),
+ {error, timeout}
+ end;
+
Result ->
recvfrom_result(Result)
end.
@@ -3612,20 +3864,24 @@ recvmsg(Socket) ->
(Socket, Timeout :: 'nowait') ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
- (Socket, SelectHandle :: select_handle()) ->
+ (Socket, Handle :: select_handle() | completion_handle()) ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Timeout :: 'infinity') ->
{'ok', Msg} |
@@ -3647,27 +3903,31 @@ recvmsg(Socket, Timeout) ->
recvmsg(Socket, 0, 0, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
--spec recvmsg(Socket, BufSz, CtrlSz, SelectHandle :: 'nowait') ->
+-spec recvmsg(Socket, BufSz, CtrlSz, Timeout :: 'nowait') ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, BufSz, CtrlSz, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz, CtrlSz, Handle :: select_handle() | completion_handle()) ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, BufSz, CtrlSz, Timeout :: 'infinity') ->
{'ok', Msg} |
@@ -3694,22 +3954,26 @@ recvmsg(Socket, BufSz, CtrlSz, Timeout) ->
-spec recvmsg(Socket, Flags, Timeout :: 'nowait') ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- Flags :: [msg_flag() | integer()],
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, Flags, Timeout :: 'infinity') ->
{'ok', Msg} |
@@ -3743,29 +4007,33 @@ recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz), is_integer(CtrlSz) ->
?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recvmsg(Socket, BufSz, CtrlSz, Flags, SelectHandle :: 'nowait') ->
+-spec recvmsg(Socket, BufSz, CtrlSz, Flags, Timeout :: 'nowait') ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
-
- (Socket, BufSz, CtrlSz, Flags, SelectHandle :: select_handle()) ->
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz, CtrlSz, Flags, Handle :: select_handle() | completion_handle()) ->
{'ok', Msg} |
{'select', SelectInfo} |
+ {'completion', CompletionInfo} |
{'error', Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- Flags :: [msg_flag() | integer()],
- Msg :: msg_recv(),
- SelectInfo :: select_info(),
- Reason :: posix() | 'closed' | invalid();
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Flags :: [msg_flag() | integer()],
+ Msg :: msg_recv(),
+ SelectInfo :: select_info(),
+ CompletionInfo :: completion_info(),
+ Reason :: posix() | 'closed' | invalid();
(Socket, BufSz, CtrlSz, Flags, Timeout :: 'infinity') ->
{'ok', Msg} |
@@ -3796,11 +4064,11 @@ recvmsg(?socket(SockRef), BufSz, CtrlSz, Flags, Timeout)
invalid ->
erlang:error({invalid, {timeout, Timeout}});
nowait ->
- SelectHandle = make_ref(),
- recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, SelectHandle);
- select_handle ->
- SelectHandle = Timeout,
- recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, SelectHandle);
+ Handle = make_ref(),
+ recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle);
+ handle ->
+ Handle = Timeout,
+ recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle);
zero ->
case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, zero) of
ok ->
@@ -3814,36 +4082,55 @@ recvmsg(?socket(SockRef), BufSz, CtrlSz, Flags, Timeout)
recvmsg(Socket, BufSz, CtrlSz, Flags, Timeout) ->
erlang:error(badarg, [Socket, BufSz, CtrlSz, Flags, Timeout]).
-recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, SelectHandle) ->
- case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, SelectHandle) of
+recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle) ->
+ case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, Handle) of
select ->
- {select, ?SELECT_INFO(recvmsg, SelectHandle)};
+ {select, ?SELECT_INFO(recvmsg, Handle)};
+ completion ->
+ {completion, ?COMPLETION_INFO(recvmsg, Handle)};
Result ->
recvmsg_result(Result)
end.
recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline) ->
- SelectHandle = make_ref(),
- case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, SelectHandle) of
+ Handle = make_ref(),
+ case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, Handle) of
select ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
Timeout = timeout(Deadline),
receive
- ?socket_msg(?socket(SockRef), select, SelectHandle) ->
+ ?socket_msg(?socket(SockRef), select, Handle) ->
recvmsg_deadline(
SockRef, BufSz, CtrlSz, Flags, Deadline);
- ?socket_msg(_Socket, abort, {SelectHandle, Reason}) ->
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
+ {error, Reason}
+ after Timeout ->
+ _ = cancel(SockRef, recvmsg, Handle),
+ {error, timeout}
+ end;
+
+ completion ->
+ %% There is nothing just now, but we will be notified when there
+ %% is something to read (a completion message).
+ Timeout = timeout(Deadline),
+ receive
+ ?socket_msg(?socket(SockRef), completion,
+ {Handle, CompletionStatus}) ->
+ recvmsg_result(CompletionStatus);
+ ?socket_msg(_Socket, abort, {Handle, Reason}) ->
{error, Reason}
after Timeout ->
- _ = cancel(SockRef, recvmsg, SelectHandle),
+ _ = cancel(SockRef, recvmsg, Handle),
{error, timeout}
end;
+
Result ->
recvmsg_result(Result)
end.
recvmsg_result(Result) ->
+ %% ?DBG([{result, Result}]),
case Result of
{ok, _Msg} = OK ->
OK;
@@ -4258,9 +4545,14 @@ ioctl(Socket, SetRequest, Arg1, Arg2) ->
%%
-spec cancel(Socket, SelectInfo) -> 'ok' | {'error', Reason} when
- Socket :: socket(),
- SelectInfo :: select_info(),
- Reason :: 'closed' | invalid().
+ Socket :: socket(),
+ SelectInfo :: select_info(),
+ Reason :: 'closed' | invalid();
+
+ (Socket, CompletionInfo) -> 'ok' | {'error', Reason} when
+ Socket :: socket(),
+ CompletionInfo :: completion_info(),
+ Reason :: 'closed' | invalid().
cancel(?socket(SockRef), ?SELECT_INFO(SelectTag, SelectHandle) = SelectInfo)
when is_reference(SockRef) ->
@@ -4278,21 +4570,43 @@ cancel(?socket(SockRef), ?SELECT_INFO(SelectTag, SelectHandle) = SelectInfo)
Result ->
Result
end;
-cancel(Socket, SelectInfo) ->
- erlang:error(badarg, [Socket, SelectInfo]).
+cancel(?socket(SockRef),
+ ?COMPLETION_INFO(CompletionTag, CompletionHandle) = CompletionInfo)
+ when is_reference(SockRef) ->
+ case CompletionTag of
+ {Op, _} when is_atom(Op) ->
+ ok;
+ Op when is_atom(Op) ->
+ ok
+ end,
+ case cancel(SockRef, Op, CompletionHandle) of
+ ok ->
+ ok;
+ invalid ->
+ {error, {invalid, CompletionInfo}};
+ Result ->
+ Result
+ end;
+cancel(Socket, Info) ->
+ erlang:error(badarg, [Socket, Info]).
-cancel(SockRef, Op, SelectHandle) ->
- case prim_socket:cancel(SockRef, Op, SelectHandle) of
+cancel(SockRef, Op, Handle) ->
+ case prim_socket:cancel(SockRef, Op, Handle) of
select_sent ->
- flush_select_msg(SockRef, SelectHandle),
- _ = flush_abort_msg(SockRef, SelectHandle),
+ _ = flush_select_msg(SockRef, Handle),
+ _ = flush_abort_msg(SockRef, Handle),
ok;
not_found ->
- _ = flush_abort_msg(SockRef, SelectHandle),
+ _ = flush_completion_msg(SockRef, Handle),
+ _ = flush_abort_msg(SockRef, Handle),
invalid;
Result ->
- _ = flush_abort_msg(SockRef, SelectHandle),
+ %% Since we do not actually if we are using
+ %% select or completion here, so flush both...
+ _ = flush_select_msg(SockRef, Handle),
+ _ = flush_completion_msg(SockRef, Handle),
+ _ = flush_abort_msg(SockRef, Handle),
Result
end.
@@ -4304,6 +4618,14 @@ flush_select_msg(SockRef, Ref) ->
ok
end.
+flush_completion_msg(SockRef, Ref) ->
+ receive
+ ?socket_msg(?socket(SockRef), completion, {Ref, Result}) ->
+ Result
+ after 0 ->
+ ok
+ end.
+
flush_abort_msg(SockRef, Ref) ->
receive
?socket_msg(?socket(SockRef), abort, {Ref, Reason}) ->
@@ -4319,39 +4641,14 @@ flush_abort_msg(SockRef, Ref) ->
%%
%% ===========================================================================
-%% formated_timestamp() ->
-%% format_timestamp(os:timestamp()).
-
-%% format_timestamp(Now) ->
-%% N2T = fun(N) -> calendar:now_to_local_time(N) end,
-%% format_timestamp(Now, N2T, true).
-
-%% format_timestamp({_N1, _N2, N3} = N, N2T, true) ->
-%% FormatExtra = ".~.2.0w",
-%% ArgsExtra = [N3 div 10000],
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra);
-%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) ->
-%% FormatExtra = "",
-%% ArgsExtra = [],
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra).
-
-%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) ->
-%% {Date, Time} = N2T(N),
-%% {YYYY,MM,DD} = Date,
-%% {Hour,Min,Sec} = Time,
-%% FormatDate =
-%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra,
-%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra),
-%% lists:flatten(FormatDate).
-
deadline(Timeout) ->
case Timeout of
nowait ->
Timeout;
infinity ->
Timeout;
- SelectHandle when is_reference(SelectHandle) ->
- select_handle;
+ Handle when is_reference(Handle) ->
+ handle;
0 ->
zero;
_ when is_integer(Timeout), 0 < Timeout ->
@@ -4362,7 +4659,7 @@ deadline(Timeout) ->
timeout(Deadline) ->
case Deadline of
- %% nowait | select_handle shall not be passed here
+ %% nowait | handle shall not be passed here
%%
infinity ->
Deadline;
@@ -4392,6 +4689,39 @@ bincat(<<_/binary>> = A, <<_/binary>> = B) ->
f(F, A) ->
lists:flatten(io_lib:format(F, A)).
+%% mq() ->
+%% pi(messages).
+
+%% pi(Item) ->
+%% {Item, Val} = process_info(self(), Item),
+%% Val.
+
+
+%% formated_timestamp() ->
+%% format_timestamp(os:timestamp()).
+
+%% format_timestamp(Now) ->
+%% N2T = fun(N) -> calendar:now_to_local_time(N) end,
+%% format_timestamp(Now, N2T, true).
+
+%% format_timestamp({_N1, _N2, N3} = N, N2T, true) ->
+%% FormatExtra = ".~.2.0w",
+%% ArgsExtra = [N3 div 10000],
+%% format_timestamp(N, N2T, FormatExtra, ArgsExtra);
+%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) ->
+%% FormatExtra = "",
+%% ArgsExtra = [],
+%% format_timestamp(N, N2T, FormatExtra, ArgsExtra).
+
+%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) ->
+%% {Date, Time} = N2T(N),
+%% {YYYY,MM,DD} = Date,
+%% {Hour,Min,Sec} = Time,
+%% FormatDate =
+%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra,
+%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra),
+%% lists:flatten(FormatDate).
+
%% p(F) ->
%% p(F, []).