aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded/src/socket.erl
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-11-05 14:43:07 +0100
committerMicael Karlberg <[email protected]>2018-11-05 14:43:07 +0100
commitf18bd2a88d7bc8519cf5db611c4c530eedecba2a (patch)
tree184d55f6629706a478b78d17120ff5f6e29cc543 /erts/preloaded/src/socket.erl
parent868950ba50185d68075e0eb14708beb5a7a5a63f (diff)
downloadotp-f18bd2a88d7bc8519cf5db611c4c530eedecba2a.tar.gz
otp-f18bd2a88d7bc8519cf5db611c4c530eedecba2a.tar.bz2
otp-f18bd2a88d7bc8519cf5db611c4c530eedecba2a.zip
[socket-nif] Add "partial success" to sendmsg
The sendmsg function attempts to send *one message*. But its possible for the underlying software to fail to send the *entire* message. So, instead of retrying itself, as send does, the sendmsg function will now instead return with {ok, Remaining}, leaving it to the caller to decide what to do. OTP-14831
Diffstat (limited to 'erts/preloaded/src/socket.erl')
-rw-r--r--erts/preloaded/src/socket.erl47
1 files changed, 39 insertions, 8 deletions
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 5ebc2074e0..dd10aac3ff 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -1573,12 +1573,13 @@ sendmsg(Socket, MsgHdr, Timeout)
sendmsg(Socket, MsgHdr, ?SOCKET_SENDMSG_FLAGS_DEFAULT, Timeout).
--spec sendmsg(Socket, MsgHdr, Flags, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- MsgHdr :: msghdr(),
- Flags :: send_flags(),
- Timeout :: timeout(),
- Reason :: term().
+-spec sendmsg(Socket, MsgHdr, Flags, Timeout) -> ok | {ok, Remaining} | {error, Reason} when
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ Flags :: send_flags(),
+ Timeout :: timeout(),
+ Remaining :: erlang:iovec(),
+ Reason :: term().
sendmsg(#socket{ref = SockRef}, #{iov := IOV} = MsgHdr, Flags, Timeout)
when is_list(IOV) andalso
@@ -1603,6 +1604,18 @@ do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
%% We are done
ok;
+ {ok, Written} when is_integer(Written) andalso (Written > 0) ->
+
+ %% We should not retry here since the protocol may not
+ %% be able to handle a message being split. Leave it to
+ %% the caller to figure out (call again with the rest).
+ %%
+ %% We should really not need to cancel, since this is
+ %% accepted for sendmsg!
+ %%
+ cancel(SockRef, sendmsg, SendRef),
+ {ok, do_sendmsg_rest(maps:get(iov, MsgHdr), Written)};
+
{error, eagain} ->
receive
{select, SockRef, SendRef, ready_output} ->
@@ -1617,6 +1630,12 @@ do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
ERROR
end.
+do_sendmsg_rest([B|IOVec], Written) when (Written >= size(B)) ->
+ do_sendmsg_rest(IOVec, Written - size(B));
+do_sendmsg_rest([B|IOVec], Written) ->
+ <<_:Written/binary, Rest/binary>> = B,
+ [Rest|IOVec].
+
ensure_msghdr(#{ctrl := []} = M) ->
ensure_msghdr(maps:remove(ctrl, M));
ensure_msghdr(#{iov := IOV} = M) when is_list(IOV) andalso (IOV =/= []) ->
@@ -1625,6 +1644,8 @@ ensure_msghdr(_) ->
einval().
+
+
%% ===========================================================================
%%
%% writev - write data into multiple buffers
@@ -1983,10 +2004,20 @@ recvmsg(Socket, Timeout) ->
Flags :: recv_flags(),
Timeout :: timeout(),
MsgHdr :: msghdr(),
+ Reason :: term()
+ ; (Socket, BufSz, CtrlSz) -> {ok, MsgHdr} | {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ MsgHdr :: msghdr(),
Reason :: term().
-recvmsg(Socket, Flags, Timeout) ->
- recvmsg(Socket, 0, 0, Flags, Timeout).
+recvmsg(Socket, Flags, Timeout) when is_list(Flags) ->
+ recvmsg(Socket, 0, 0, Flags, Timeout);
+recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz) andalso is_integer(CtrlSz) ->
+ recvmsg(Socket, BufSz, CtrlSz,
+ ?SOCKET_RECV_FLAGS_DEFAULT, ?SOCKET_RECV_TIMEOUT_DEFAULT).
+
-spec recvmsg(Socket,
BufSz, CtrlSz,