Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:26
erlang
3103-kernel-esock-Add-function-socket-sendv-and...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 3103-kernel-esock-Add-function-socket-sendv-and-use-of-it.patch of Package erlang
From acfa2d0863e314440e8391de5ba08839484810c3 Mon Sep 17 00:00:00 2001 From: Micael Karlberg <bmk@erlang.org> Date: Thu, 7 Mar 2024 14:17:25 +0100 Subject: [PATCH 03/11] [kernel|esock] Add function (socket) sendv and use of it Add function socket:sendv/2,3,4 and use of it in gen_tcp_socket. OTP-18845 --- lib/kernel/src/gen_tcp_socket.erl | 34 +++-- lib/kernel/src/socket.erl | 226 +++++++++++++++++++++++++++++- 2 files changed, 250 insertions(+), 10 deletions(-) diff --git a/lib/kernel/src/gen_tcp_socket.erl b/lib/kernel/src/gen_tcp_socket.erl index e3dc2dd1d8..b6d06d2b2e 100644 --- a/lib/kernel/src/gen_tcp_socket.erl +++ b/lib/kernel/src/gen_tcp_socket.erl @@ -507,17 +507,19 @@ accept(?MODULE_socket(ListenServer, ListenSocket), Timeout) -> send(?MODULE_socket(Server, Socket), Data) -> case socket:getopt(Socket, {otp,meta}) of {ok, - #{packet := Packet, + #{packet := Packet, send_timeout := SendTimeout} = Meta} -> if Packet =:= 1; Packet =:= 2; Packet =:= 4 -> - Size = iolist_size(Data), + Data2 = iolist_to_binary(Data), + Size = byte_size(Data2), %% ?DBG([{packet, Packet}, {data_size, Size}]), - Header = <<?header(Packet, Size)>>, - Header_Data = [Header, Data], - Result = socket_send(Socket, Header_Data, SendTimeout), + Header = <<?header(Packet, Size)>>, + Header_Data = [Header, Data2], + Result = socket_sendv(Socket, + Header_Data, SendTimeout), send_result(Server, Header_Data, Meta, Result); true -> Result = socket_send(Socket, Data, SendTimeout), @@ -532,11 +534,13 @@ send(?MODULE_socket(Server, Socket), Data) -> send_result(Server, Data, Meta, Result) -> %% ?DBG([{meta, Meta}, {send_result, Result}]), case Result of - {error, {timeout, RestData}} when is_binary(RestData) -> + {error, {timeout, RestData}} when is_binary(RestData) orelse + is_list(RestData) -> send_timeout(Server, RestData, Meta); {error, timeout} -> send_timeout(Server, Data, Meta); - {error, {Reason, RestData}} when is_binary(RestData) -> + {error, {Reason, RestData}} when is_binary(RestData) orelse + is_list(RestData) -> call(Server, {send_error, Reason}); {error, Reason} -> call(Server, {send_error, Reason}); @@ -837,7 +841,7 @@ fdopen(Fd, Opts) when is_integer(Fd), 0 =< Fd, is_list(Opts) -> %%% Socket glue code %%% --compile({inline, [socket_send/3, socket_send_error/1]}). +-compile({inline, [socket_send/3]}). socket_send(Socket, Data, Timeout) -> Result = socket:send(Socket, Data, [], Timeout), case Result of @@ -850,6 +854,20 @@ socket_send(Socket, Data, Timeout) -> Result end. +-compile({inline, [socket_sendv/3]}). +socket_sendv(Socket, Data, Timeout) -> + Result = socket:sendv(Socket, Data, Timeout), + case Result of + {error, {Reason, RestData}} when is_list(RestData) -> + {error, NewReason} = socket_send_error({error, Reason}), + {error, {NewReason, RestData}}; + {error, _} -> + socket_send_error(Result); + _ -> + Result +end. + +-compile({inline, [socket_send_error/1]}). socket_send_error(Result) -> case Result of {error, epipe} -> {error, econnreset}; diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index 52235c7d1b..bbbf317490 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -258,6 +258,7 @@ server(Addr, Port) -> send/2, send/3, send/4, sendto/3, sendto/4, sendto/5, sendmsg/2, sendmsg/3, sendmsg/4, + sendv/2, sendv/3, sendv/4, sendfile/2, sendfile/3, sendfile/4, sendfile/5, @@ -362,7 +363,6 @@ server(Addr, Port) -> %% We need #file_descriptor{} for sendfile/2,3,4,5 -include("file_int.hrl"). -%% -include("socket_int.hrl"). %% -define(DBG(T), %% erlang:display({{self(), ?MODULE, ?LINE, ?FUNCTION_NAME}, T})). @@ -1773,6 +1773,7 @@ the `CompletionStatus`. -define(ESOCK_SENDTO_TIMEOUT_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT). -define(ESOCK_SENDMSG_FLAGS_DEFAULT, []). -define(ESOCK_SENDMSG_TIMEOUT_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT). +-define(ESOCK_SENDV_TIMEOUT_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT). -define(ESOCK_RECV_FLAGS_DEFAULT, []). -define(ESOCK_RECV_TIMEOUT_DEFAULT, infinity). @@ -3585,6 +3586,19 @@ send_common_deadline_result( Op, Fun, SendResult) -> %% case SendResult of + select -> + %% Would block, wait for continuation + Timeout = timeout(Deadline), + receive + ?socket_msg(_Socket, select, Handle) -> + Fun(SockRef, Data, undefined, Deadline, HasWritten); + ?socket_msg(_Socket, abort, {Handle, Reason}) -> + send_common_error(Reason, Data, HasWritten) + after Timeout -> + _ = cancel(SockRef, Op, Handle), + send_common_error(timeout, Data, HasWritten) + end; + {select, Cont} -> %% Would block, wait for continuation Timeout = timeout(Deadline), @@ -3629,7 +3643,9 @@ send_common_deadline_result( Error; {error, Reason} -> send_common_error(Reason, Data, HasWritten); + Result -> + %% ?DBG([{deadline, Deadline}, {op, Op}, {result, Result}]), Result end. @@ -4172,6 +4187,213 @@ sendmsg_deadline_cont(SockRef, Data, Cont, Deadline, HasWritten) -> prim_socket:sendmsg(SockRef, Data, Cont, SelectHandle)). +%% --------------------------------------------------------------------------- +%% +%% + +-spec sendv(Socket, IOV) -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(). + +sendv(Socket, IOV) -> + sendv(Socket, IOV, ?ESOCK_SENDMSG_TIMEOUT_DEFAULT). + + +-spec sendv(Socket, IOV, Cont) -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + Cont :: select_info(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(); + + (Socket, IOV, Timeout :: 'nowait') -> + 'ok' | + {'ok', RestIOV} | + {'select', SelectInfo} | + {'select', {SelectInfo, RestIOV}} | + {'completion', CompletionInfo} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + RestIOV :: erlang:iovec(), + SelectInfo :: select_info(), + CompletionInfo :: completion_info(), + Reason :: posix() | 'closed' | invalid(); + + (Socket, IOV, Handle :: select_handle() | completion_handle()) -> + 'ok' | + {'ok', RestIOV} | + {'select', SelectInfo} | + {'select', {SelectInfo, RestIOV}} | + {'completion', CompletionInfo} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + RestIOV :: erlang:iovec(), + SelectInfo :: select_info(), + CompletionInfo :: completion_info(), + Reason :: posix() | 'closed' | invalid(); + + (Socket, IOV, Timeout :: 'infinity') -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(); + + (Socket, IOV, Timeout :: non_neg_integer()) -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason | 'timeout'} | + {'error', {Reason | 'timeout', RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(). + +sendv(?socket(SockRef) = Socket, IOV, + ?SELECT_INFO(SelectTag, _) = Cont) + when is_reference(SockRef) -> + case SelectTag of + {sendv, _} -> % We do not use ContData here + sendv_timeout_cont(SockRef, IOV, ?ESOCK_SENDV_TIMEOUT_DEFAULT); + _ -> + erlang:error(badarg, [Socket, IOV, Cont]) + end; +sendv(?socket(SockRef), IOV, Timeout) + when is_reference(SockRef) -> + case deadline(Timeout) of + invalid -> + erlang:error({invalid, {timeout, Timeout}}); + nowait -> + Handle = make_ref(), + sendv_nowait(SockRef, IOV, Handle); + handle -> + Handle = Timeout, + sendv_nowait(SockRef, IOV, Handle); + Deadline -> + sendv_deadline(SockRef, IOV, Deadline) + end; +sendv(Socket, IOV, Timeout) -> + erlang:error(badarg, [Socket, IOV, Timeout]). + +-spec sendv(Socket, IOV, Cont, Timeout :: 'nowait') -> + 'ok' | + {'ok', RestIOV} | + {'select', SelectInfo} | + {'select', {SelectInfo, RestIOV}} | + {'completion', CompletionInfo} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + Cont :: select_info(), + RestIOV :: erlang:iovec(), + SelectInfo :: select_info(), + CompletionInfo :: completion_info(), + Reason :: posix() | 'closed' | invalid(); + (Socket, IOV, Cont, Timeout :: 'infinity') -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason} | + {'error', {Reason, RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + Cont :: select_info(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(); + + (Socket, IOV, Cont, Timeout :: non_neg_integer()) -> + 'ok' | + {'ok', RestIOV} | + {'error', Reason | 'timeout'} | + {'error', {Reason | 'timeout', RestIOV}} + when + Socket :: socket(), + IOV :: erlang:iovec(), + Cont :: select_info(), + RestIOV :: erlang:iovec(), + Reason :: posix() | 'closed' | invalid(). + +sendv(?socket(SockRef) = _Socket, IOV, + ?SELECT_INFO(SelectTag, _) = Cont, Timeout) + when is_reference(SockRef) andalso is_list(IOV) -> + %% + case SelectTag of + {sendv, _} -> % We do not use ContData here + sendv_timeout_cont(SockRef, IOV, Timeout); + _ -> + {error, {invalid, Cont}} + end; +sendv(Socket, IOV, Cont, Timeout) -> + erlang:error(badarg, [Socket, IOV, Cont, Timeout]). + + +sendv_timeout_cont(SockRef, RestIOV, Timeout) -> + case deadline(Timeout) of + invalid -> + erlang:error({invalid, {timeout, Timeout}}); + nowait -> + SelectHandle = make_ref(), + sendv_nowait_cont(SockRef, RestIOV, SelectHandle); + handle -> + SelectHandle = Timeout, + sendv_nowait_cont(SockRef, RestIOV, SelectHandle); + Deadline -> + HasWritten = false, + sendv_deadline_cont( + SockRef, RestIOV, undefined, Deadline, HasWritten) + end. + +sendv_nowait(SockRef, IOV, Handle) -> + send_common_nowait_result( + Handle, sendv, + prim_socket:sendv(SockRef, IOV, Handle)). + +sendv_nowait_cont(SockRef, RestIOV, SelectHandle) -> + send_common_nowait_result( + SelectHandle, sendv, + prim_socket:sendv(SockRef, RestIOV, SelectHandle)). + +sendv_deadline(SockRef, IOV, Deadline) -> + Handle = make_ref(), + HasWritten = false, + send_common_deadline_result( + SockRef, IOV, Handle, Deadline, HasWritten, + sendv, fun sendv_deadline_cont/5, + prim_socket:sendv(SockRef, IOV, Handle)). + +sendv_deadline_cont(SockRef, IOV, _, Deadline, HasWritten) -> + SelectHandle = make_ref(), + send_common_deadline_result( + SockRef, IOV, SelectHandle, Deadline, HasWritten, + sendv, fun sendv_deadline_cont/5, + prim_socket:sendv(SockRef, IOV, SelectHandle)). + + %% =========================================================================== %% %% sendfile - send a file on a socket -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor