summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaimo Niskanen <raimo@erlang.org>2020-11-30 12:25:01 +0100
committerRaimo Niskanen <raimo@erlang.org>2020-12-04 10:21:23 +0100
commit5dbd5c5af324926b93b6f3265213e0cb3911f69d (patch)
tree3048c539b4179a1bdc8d5796f6c5e9cc5e2298c7
parent6f3ebb6c8a6c120f2349777cdb04106081759cb5 (diff)
downloaderlang-5dbd5c5af324926b93b6f3265213e0cb3911f69d.tar.gz
Optimize recv timeout 0
-rw-r--r--erts/emulator/nifs/common/prim_socket_nif.c245
-rw-r--r--erts/emulator/nifs/common/socket_util.c2
-rw-r--r--erts/emulator/nifs/common/socket_util.h2
-rw-r--r--erts/preloaded/ebin/prim_socket.beambin27116 -> 27116 bytes
-rw-r--r--erts/preloaded/src/prim_socket.erl18
-rw-r--r--lib/kernel/doc/src/socket.xml174
-rw-r--r--lib/kernel/src/socket.erl397
-rw-r--r--lib/kernel/test/socket_SUITE.erl101
8 files changed, 587 insertions, 352 deletions
diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c
index 905dff630a..3390f61e41 100644
--- a/erts/emulator/nifs/common/prim_socket_nif.c
+++ b/erts/emulator/nifs/common/prim_socket_nif.c
@@ -3679,6 +3679,7 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(write_pkg_max); \
LOCAL_ATOM_DECL(write_tries); \
LOCAL_ATOM_DECL(write_waits); \
+ LOCAL_ATOM_DECL(zero); \
LOCAL_ATOM_DECL(zerocopy)
/* Local error reason atoms */
@@ -3750,7 +3751,7 @@ static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan)
* nif_send(Sock, SendRef, Data, Flags)
* nif_sendto(Sock, SendRef, Data, Dest, Flags)
* nif_sendmsg(Sock, SendRef, Msg, Flags)
- * nif_recv(Sock, RecvRef, Length, Flags)
+ * nif_recv(Sock, Length, Flags, RecvRef)
* nif_recvfrom(Sock, RecvRef, BufSz, Flags)
* nif_recvmsg(Sock, RecvRef, BufSz, CtrlSz, Flags)
* nif_close(Sock)
@@ -4665,7 +4666,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
if (! GET_INT(env, argv[0], &fd)) {
if (IS_INTEGER(env, argv[0]))
- return esock_make_error_invalid_integer(env, argv[0]);
+ return esock_make_error_integer_range(env, argv[0]);
else
return enif_make_badarg(env);
}
@@ -4693,7 +4694,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
if (! GET_INT(env, argv[2], &proto)) {
if (IS_INTEGER(env, argv[2]))
- return esock_make_error_invalid_integer(env, argv[2]);
+ return esock_make_error_integer_range(env, argv[2]);
else
return enif_make_badarg(env);
}
@@ -5640,7 +5641,7 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env,
}
if (! GET_INT(env, argv[1], &backlog)) {
if (IS_INTEGER(env, argv[1]))
- return esock_make_error_invalid_integer(env, argv[1]);
+ return esock_make_error_integer_range(env, argv[1]);
else
return enif_make_badarg(env);
}
@@ -6272,7 +6273,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
if (! GET_INT(env, argv[2], &flags)) {
SGDBG( ("SOCKET", "nif_send -> argv decode failed\r\n") );
if (IS_INTEGER(env, argv[2]))
- return esock_make_error_invalid_integer(env, argv[2]);
+ return esock_make_error_integer_range(env, argv[2]);
else
return enif_make_badarg(env);
}
@@ -6423,7 +6424,7 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
if (! GET_INT(env, argv[3], &flags)) {
SGDBG( ("SOCKET", "nif_sendto -> argv decode failed\r\n") );
if (IS_INTEGER(env, argv[3]))
- return esock_make_error_invalid_integer(env, argv[3]);
+ return esock_make_error_integer_range(env, argv[3]);
else
return enif_make_badarg(env);
}
@@ -6573,7 +6574,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
}
if (! GET_INT(env, argv[2], &flags)) {
if (IS_INTEGER(env, argv[2]))
- return esock_make_error_invalid_integer(env, argv[2]);
+ return esock_make_error_integer_range(env, argv[2]);
else
return enif_make_badarg(env);
}
@@ -6908,10 +6909,10 @@ ERL_NIF_TERM nwritev(ErlNifEnv* env,
* whatever is in the buffers (everything it got).
*
* Arguments:
- * Socket (ref) - Points to the socket descriptor.
- * RecvRef - A unique id for this (send) request.
- * Length - The number of bytes to receive.
- * Flags - Receive flags.
+ * Socket (ref) - NIF resource reference() to the socket descriptor.
+ * Length - The number of bytes to receive; integer().
+ * Flags - Receive flags; integer().
+ * RecvRef - A unique reference() id for this (send) request | 'poll'
*/
static
@@ -6932,31 +6933,32 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
ESOCK_ASSERT( argc == 4 );
sockRef = argv[0]; // We need this in case we send abort (to the caller)
- recvRef = argv[1];
+ recvRef = argv[3];
if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
- if (! enif_is_ref(env, recvRef)) {
+ if ((! enif_is_ref(env, recvRef)) &&
+ (COMPARE(recvRef, atom_zero) != 0)) {
return enif_make_badarg(env);
}
- if ((! GET_UINT64(env, argv[2], &elen)) ||
- (! GET_INT(env, argv[3], &flags))) {
- BOOLEAN_T argv2_is_integer = IS_INTEGER(env, argv[2]);
+ if ((! GET_UINT64(env, argv[1], &elen)) ||
+ (! GET_INT(env, argv[2], &flags))) {
+ BOOLEAN_T argv1_is_integer = IS_INTEGER(env, argv[1]);
- if ((! argv2_is_integer) ||
- (! IS_INTEGER(env, argv[3])))
+ if ((! argv1_is_integer) ||
+ (! IS_INTEGER(env, argv[2])))
return enif_make_badarg(env);
- if (argv2_is_integer)
- return esock_make_error_invalid_integer(env, argv[2]);
+ if (argv1_is_integer)
+ return esock_make_error_integer_range(env, argv[1]);
return
- esock_make_error_invalid_integer(env, argv[3]);
+ esock_make_error_integer_range(env, argv[2]);
}
len = (ssize_t) elen;
if (elen != (ErlNifUInt64) len)
- return esock_make_error_invalid_integer(env, elen);
+ return esock_make_error_integer_range(env, elen);
MLOCK(descP->readMtx);
@@ -7056,12 +7058,8 @@ ERL_NIF_TERM esock_recv(ErlNifEnv* env,
"esock_recv {%d} -> read: %ld (%d)\r\n",
descP->sock, (long) read, save_errno) );
- return recv_check_result(env, descP,
- read, len,
- save_errno,
- &buf,
- sockRef,
- recvRef);
+ return recv_check_result(env, descP, read, len, save_errno,
+ &buf, sockRef, recvRef);
}
#endif // #ifndef __WIN32__
@@ -7077,10 +7075,11 @@ ERL_NIF_TERM esock_recv(ErlNifEnv* env,
* buffer size for this socket (whatever has been configured).
*
* Arguments:
- * Socket (ref) - Points to the socket descriptor.
- * RecvRef - A unique id for this (send) request.
- * BufSz - Size of the buffer into which we put the received message.
- * Flags - Receive flags.
+ * Socket (ref) - NIF resource reference() to the socket descriptor.
+ * BufSz - integer() ize of the buffer
+ * into which we put the received message.
+ * Flags - Receive flags; integer().
+ * RecvRef - A unique reference() id for this recv request.
*
* <KOLLA>
*
@@ -7111,7 +7110,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
SGDBG( ("SOCKET", "nif_recvfrom -> entry with argc: %d\r\n", argc) );
sockRef = argv[0]; // We need this in case we send abort (to the caller)
- recvRef = argv[1];
+ recvRef = argv[3];
if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
@@ -7119,25 +7118,27 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
- if (! enif_is_ref(env, recvRef))
+ if ((! enif_is_ref(env, recvRef)) &&
+ (COMPARE(recvRef, atom_zero) != 0)) {
return enif_make_badarg(env);
+ }
- if ((! GET_UINT64(env, argv[2], &elen)) ||
- (! GET_INT(env, argv[3], &flags))) {
- BOOLEAN_T argv2_is_integer = IS_INTEGER(env, argv[2]);
+ if ((! GET_UINT64(env, argv[1], &elen)) ||
+ (! GET_INT(env, argv[2], &flags))) {
+ BOOLEAN_T argv1_is_integer = IS_INTEGER(env, argv[1]);
- if ((! argv2_is_integer) ||
- (! IS_INTEGER(env, argv[3])))
+ if ((! argv1_is_integer) ||
+ (! IS_INTEGER(env, argv[2])))
return enif_make_badarg(env);
- if (argv2_is_integer)
- return esock_make_error_invalid_integer(env, argv[2]);
+ if (argv1_is_integer)
+ return esock_make_error_integer_range(env, argv[1]);
return
- esock_make_error_invalid_integer(env, argv[3]);
+ esock_make_error_integer_range(env, argv[2]);
}
len = (ssize_t) elen;
if (elen != (ErlNifUInt64) len)
- return esock_make_error_invalid_integer(env, elen);
+ return esock_make_error_integer_range(env, elen);
MLOCK(descP->readMtx);
@@ -7197,7 +7198,7 @@ ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
int save_errno;
ErlNifBinary buf;
ERL_NIF_TERM readerCheck;
- size_t bufSz = (len ? len : descP->rBufSz);
+ size_t bufSz = (len != 0 ? len : descP->rBufSz);
SSDBG( descP, ("SOCKET", "esock_recvfrom {%d} -> entry with"
"\r\n bufSz: %d"
@@ -7239,13 +7240,9 @@ ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
else
save_errno = 0; // The value does not actually matter in this case
- return recvfrom_check_result(env, descP,
- read,
- save_errno,
- &buf,
- &fromAddr, addrLen,
- sockRef,
- recvRef);
+ return recvfrom_check_result(env, descP, read, save_errno,
+ &buf, &fromAddr, addrLen,
+ sockRef, recvRef);
}
#endif // #ifndef __WIN32__
@@ -7263,12 +7260,13 @@ ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
* (buffer) size is used (1024).
*
* Arguments:
- * Socket (ref) - Points to the socket descriptor.
- * RecvRef - A unique id for this (send) request.
- * BufSz - Size of the buffer into which we put the received message.
+ * Socket (ref) - NIF resource reference() to the socket descriptor.
+ * BufSz - Size of the buffer into which we put the received message;
+ * integer().
* CtrlSz - Size of the ctrl (buffer) into which we put the received
- * ancillary data.
- * Flags - Receive flags.
+ * ancillary data; integer().
+ * Flags - Receive flags; integer().
+ * RecvRef - A unique reference() id for this (send) request.
*
* <KOLLA>
*
@@ -7299,7 +7297,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
SGDBG( ("SOCKET", "nif_recvmsg -> entry with argc: %d\r\n", argc) );
sockRef = argv[0]; // We need this in case we send abort (to the caller)
- recvRef = argv[1];
+ recvRef = argv[4];
if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
@@ -7307,36 +7305,38 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
- if (! enif_is_ref(env, recvRef))
+ if ((! enif_is_ref(env, recvRef)) &&
+ (COMPARE(recvRef, atom_zero) != 0)) {
return enif_make_badarg(env);
+ }
- if ((! GET_UINT64(env, argv[2], &eBufSz)) ||
- (! GET_UINT64(env, argv[3], &eCtrlSz)) ||
- (! GET_INT(env, argv[4], &flags))) {
+ if ((! GET_UINT64(env, argv[1], &eBufSz)) ||
+ (! GET_UINT64(env, argv[2], &eCtrlSz)) ||
+ (! GET_INT(env, argv[3], &flags))) {
BOOLEAN_T
- argv2_is_integer = IS_INTEGER(env, argv[2]),
- argv3_is_integer;
+ argv1_is_integer = IS_INTEGER(env, argv[1]),
+ argv2_is_integer;
- if ((! argv2_is_integer) ||
- (! (argv3_is_integer = IS_INTEGER(env, argv[3]))) ||
- (! IS_INTEGER(env, argv[4])))
+ if ((! argv1_is_integer) ||
+ (! (argv2_is_integer = IS_INTEGER(env, argv[2]))) ||
+ (! IS_INTEGER(env, argv[3])))
return enif_make_badarg(env);
+ if (argv1_is_integer)
+ return esock_make_error_integer_range(env, argv[1]);
if (argv2_is_integer)
- return esock_make_error_invalid_integer(env, argv[2]);
- if (argv3_is_integer)
- return esock_make_error_invalid_integer(env, argv[3]);
+ return esock_make_error_integer_range(env, argv[2]);
return
- esock_make_error_invalid_integer(env, argv[4]);
+ esock_make_error_integer_range(env, argv[3]);
}
bufSz = (ssize_t) eBufSz;
if (eBufSz != (ErlNifUInt64) bufSz)
- return esock_make_error_invalid_integer(env, eBufSz);
+ return esock_make_error_integer_range(env, eBufSz);
ctrlSz = (ssize_t) eCtrlSz;
if (eCtrlSz != (ErlNifUInt64) ctrlSz)
- return esock_make_error_invalid_integer(env, eCtrlSz);
+ return esock_make_error_integer_range(env, eCtrlSz);
MLOCK(descP->readMtx);
@@ -7397,8 +7397,8 @@ ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
SOCKLEN_T addrLen;
ssize_t read;
int save_errno;
- size_t bufSz = (bufLen ? bufLen : descP->rBufSz);
- size_t ctrlSz = (ctrlLen ? ctrlLen : descP->rCtrlSz);
+ size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz);
+ size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz);
struct msghdr msgHdr;
struct iovec iov[1]; // Shall we always use 1?
ErlNifBinary data[1]; // Shall we always use 1?
@@ -7469,14 +7469,11 @@ ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
else
save_errno = 0; // The value does not actually matter in this case
- return recvmsg_check_result(env, descP,
- read,
- save_errno,
+ return recvmsg_check_result(env, descP, read, save_errno,
&msgHdr,
data, // Needed for iov encode
&ctrl, // Needed for ctrl header encode
- sockRef,
- recvRef);
+ sockRef, recvRef);
}
#endif // #ifndef __WIN32__
@@ -8047,7 +8044,7 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
if (! IS_INTEGER(env, argv[2]))
return enif_make_badarg(env);
else
- return esock_make_error_invalid_integer(env, argv[2]);
+ return esock_make_error_integer_range(env, argv[2]);
}
eVal = argv[3];
@@ -8069,7 +8066,7 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
SGDBG( ("SOCKET", "nif_setopt -> failed arg check\r\n") );
if (IS_INTEGER(env, argv[1]))
- return esock_make_error_invalid_integer(env, argv[1]);
+ return esock_make_error_integer_range(env, argv[1]);
else
return enif_make_badarg(env);
#endif // #ifdef __WIN32__ #else
@@ -9731,7 +9728,7 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
if (! IS_INTEGER(env, argv[2]))
return enif_make_badarg(env);
else
- return esock_make_error_invalid_integer(env, argv[2]);
+ return esock_make_error_integer_range(env, argv[2]);
}
if (esock_decode_level(env, argv[1], &level)) {
@@ -9750,7 +9747,7 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
SGDBG( ("SOCKET", "nif_getopt -> failed args check\r\n") );
if (IS_INTEGER(env, argv[1]))
- return esock_make_error_invalid_integer(env, argv[1]);
+ return esock_make_error_integer_range(env, argv[1]);
else
return enif_make_badarg(env);
@@ -11692,7 +11689,7 @@ ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
("SOCKET", "esock_cancel_recv_current(%T) {%d} -> cancel res: %T"
"\r\n", sockRef, descP->sock, res) );
- if (!activate_next_reader(env, descP, sockRef)) {
+ if (! activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET",
"esock_cancel_recv_current(%T) {%d} -> no more readers"
@@ -12220,7 +12217,9 @@ BOOLEAN_T recv_check_reader(ErlNifEnv* env,
"\r\n ref: %T"
"\r\n", descP->sock, ref) );
- if (!reader_search4pid(env, descP, &caller)) {
+ if (! reader_search4pid(env, descP, &caller)) {
+ if (COMPARE(ref, atom_zero) == 0)
+ goto done_ok;
reader_push(env, descP, caller, ref);
*checkResult = atom_select;
} else {
@@ -12237,9 +12236,9 @@ BOOLEAN_T recv_check_reader(ErlNifEnv* env,
}
}
+ done_ok:
// Does not actually matter in this case, but ...
*checkResult = esock_atom_ok;
-
return TRUE;
}
#endif // #ifndef __WIN32__
@@ -12306,7 +12305,7 @@ ERL_NIF_TERM recv_update_current_reader(ErlNifEnv* env,
DEMONP("recv_update_current_reader",
env, descP, &descP->currentReader.mon);
- if (!activate_next_reader(env, descP, sockRef)) {
+ if (! activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET",
@@ -12411,7 +12410,7 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
* When a stream socket peer has performed an orderly shutdown,
* the return value will be 0 (the traditional "end-of-file" return).
*
- * *We* do never actually try to read 0 bytes from a stream socket!
+ * *We* do never actually try to read 0 bytes!
*
* We must also notify any waiting readers!
*/
@@ -12488,14 +12487,15 @@ ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
{
ERL_NIF_TERM res;
- if (toRead == 0) {
+ if ((toRead == 0) &&
+ (descP->type == SOCK_STREAM)) {
/* +++ Give us everything you have got => *
* (maybe) needs to continue +++ */
/* Send up each chunk of data for each of the read
- * and let the erlang code assemble it: {ok, false, Bin}
- * (when complete it should return {ok, true, Bin}).
+ * and let the erlang code assemble it: {more, Bin}
+ * (when complete it should return {ok, Bin}).
* We need to read atleast one more time to be sure if its
* done...
*
@@ -12537,9 +12537,9 @@ ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
/* *** recv_check_full_maybe_done ***
*
* Send up each chunk of data for each of the read
- * and let the erlang code assemble it: {ok, false, Bin}
- * (when complete it should return {ok, true, Bin}).
- * We need to read atleast one more time to be sure if its
+ * and let the erlang code assemble it: {more, Bin}
+ * (when complete it should return {ok, Bin}).
+ * We need to read at least one more time to be sure if its
* done...
*
* Also, we need to check if the rNumCnt has reached its max (rNum),
@@ -12649,11 +12649,12 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
{
ERL_NIF_TERM res;
- FREE_BIN(buf1P); if (buf2P != NULL) FREE_BIN(buf2P);
+ FREE_BIN(buf1P);
+ if (buf2P != NULL) FREE_BIN(buf2P);
if (saveErrno == ECONNRESET) {
- /* +++ Oups - closed +++ */
+ /* +++ Oops - closed +++ */
SSDBG( descP,
("SOCKET",
@@ -12676,7 +12677,10 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
"\r\n recvRef: %T"
"\r\n", sockRef, descP->sock, recvRef) );
- res = recv_check_retry(env, descP, sockRef, recvRef);
+ if (COMPARE(recvRef, atom_zero) == 0)
+ res = esock_atom_ok;
+ else
+ res = recv_check_retry(env, descP, sockRef, recvRef);
} else {
@@ -12812,7 +12816,9 @@ ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
{
ERL_NIF_TERM res;
- if (toRead == 0) {
+ if ((toRead == 0) ||
+ (descP->type != SOCK_STREAM) ||
+ (COMPARE(recvRef, atom_zero) == 0)) {
/* +++ We got it all, but since we +++
* +++ did not fill the buffer, we +++
@@ -12829,6 +12835,10 @@ ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
res = recv_check_partial_done(env, descP, read, bufP, sockRef);
} else {
+ /* A stream socket with specified read size
+ * and not a polling read, we got a partial read
+ * - return a select result to initiate a retry
+ */
SSDBG( descP,
("SOCKET",
@@ -12967,6 +12977,31 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
"\r\n", sockRef, descP->sock,
(long) read, saveErrno, recvRef) );
+ /* <KOLLA>
+ *
+ * We need to handle read = 0 for non_stream socket type(s) when
+ * its actually valid to read 0 bytes.
+ *
+ * </KOLLA>
+ */
+
+ if ((read == 0) && (descP->type == SOCK_STREAM)) {
+
+ /*
+ * When a stream socket peer has performed an orderly shutdown,
+ * the return value will be 0 (the traditional "end-of-file" return).
+ *
+ * *We* do never actually try to read 0 bytes!
+ */
+
+ ESOCK_CNT_INC(env, descP, sockRef,
+ atom_read_fails, &descP->readFails, 1);
+
+ FREE_BIN(bufP);
+
+ return esock_make_error(env, atom_closed);
+ }
+
if (read < 0) {
/* +++ Error handling +++ */
@@ -13050,19 +13085,19 @@ ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
/* <KOLLA>
*
- * We need to handle read = 0 for other type(s) (DGRAM) when
+ * We need to handle read = 0 for non_stream socket type(s) when
* its actually valid to read 0 bytes.
*
* </KOLLA>
*/
-
+
if ((read == 0) && (descP->type == SOCK_STREAM)) {
/*
* When a stream socket peer has performed an orderly shutdown,
* the return value will be 0 (the traditional "end-of-file" return).
*
- * *We* do never actually try to read 0 bytes from a stream socket!
+ * *We* do never actually try to read 0 bytes!
*/
ESOCK_CNT_INC(env, descP, sockRef,
@@ -13071,15 +13106,9 @@ ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
FREE_BIN(dataBufP); FREE_BIN(ctrlBufP);
return esock_make_error(env, atom_closed);
-
}
- /* There is a special case: If the provided 'to read' value is
- * zero (0). That means that we reads as much as we can, using
- * the default read buffer size.
- */
-
if (read < 0) {
/* +++ Error handling +++ */
@@ -16849,7 +16878,7 @@ void esock_down_reader(ErlNifEnv* env,
"current reader - try activate next\r\n",
sockRef, descP->sock) );
- if (!activate_next_reader(env, descP, sockRef)) {
+ if (! activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET",
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c
index 6c196ef6f7..ce879dbfb3 100644
--- a/erts/emulator/nifs/common/socket_util.c
+++ b/erts/emulator/nifs/common/socket_util.c
@@ -1774,7 +1774,7 @@ ERL_NIF_TERM esock_make_error_invalid(ErlNifEnv* env, ERL_NIF_TERM what)
* ERL_NIF_TERM so all we have to do is create the tuple.
*/
extern
-ERL_NIF_TERM esock_make_error_invalid_integer(ErlNifEnv* env, ERL_NIF_TERM i)
+ERL_NIF_TERM esock_make_error_integer_range(ErlNifEnv* env, ERL_NIF_TERM i)
{
return
esock_make_invalid(env, MKT2(env, esock_atom_integer_range, i));
diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h
index f20b33fe7b..3a0a84a8d8 100644
--- a/erts/emulator/nifs/common/socket_util.h
+++ b/erts/emulator/nifs/common/socket_util.h
@@ -241,7 +241,7 @@ ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err);
extern
ERL_NIF_TERM esock_make_error_invalid(ErlNifEnv* env, ERL_NIF_TERM what);
extern
-ERL_NIF_TERM esock_make_error_invalid_integer(ErlNifEnv* env, ERL_NIF_TERM i);
+ERL_NIF_TERM esock_make_error_integer_range(ErlNifEnv* env, ERL_NIF_TERM i);
extern
ERL_NIF_TERM esock_make_invalid(ErlNifEnv* env, ERL_NIF_TERM reason);
extern
diff --git a/erts/preloaded/ebin/prim_socket.beam b/erts/preloaded/ebin/prim_socket.beam
index c616a36d62..ecaca5322d 100644
--- a/erts/preloaded/ebin/prim_socket.beam
+++ b/erts/preloaded/ebin/prim_socket.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_socket.erl b/erts/preloaded/src/prim_socket.erl
index f3204d09ad..7efba71fe9 100644
--- a/erts/preloaded/src/prim_socket.erl
+++ b/erts/preloaded/src/prim_socket.erl
@@ -633,26 +633,26 @@ invalid_iov(_, N) ->
%% ----------------------------------
-recv(SockRef, RecvRef, Length, Flags) ->
+recv(SockRef, Length, Flags, RecvRef) ->
try enc_msg_flags(Flags) of
EFlags ->
- nif_recv(SockRef, RecvRef, Length, EFlags)
+ nif_recv(SockRef, Length, EFlags, RecvRef)
catch throw : Reason ->
{error, Reason}
end.
-recvfrom(SockRef, RecvRef, Length, Flags) ->
+recvfrom(SockRef, Length, Flags, RecvRef) ->
try enc_msg_flags(Flags) of
EFlags ->
- nif_recvfrom(SockRef, RecvRef, Length, EFlags)
+ nif_recvfrom(SockRef, Length, EFlags, RecvRef)
catch throw : Reason ->
{error, Reason}
end.
-recvmsg(SockRef, RecvRef, BufSz, CtrlSz, Flags) ->
+recvmsg(SockRef, BufSz, CtrlSz, Flags, RecvRef) ->
try enc_msg_flags(Flags) of
EFlags ->
- case nif_recvmsg(SockRef, RecvRef, BufSz, CtrlSz, EFlags) of
+ case nif_recvmsg(SockRef, BufSz, CtrlSz, EFlags, RecvRef) of
{ok, #{ctrl := []}} = Result ->
Result;
{ok, #{ctrl := Cmsgs} = Msg} ->
@@ -995,9 +995,9 @@ nif_send(_SockRef, _Bin, _Flags, _SendRef) -> erlang:nif_error(undef).
nif_sendto(_SRef, _Bin, _Dest, _Flags, _SendRef) -> erlang:nif_error(undef).
nif_sendmsg(_SRef, _Msg, _Flags, _SendRef, _IOV) -> erlang:nif_error(undef).
-nif_recv(_SRef, _RecvRef, _Length, _Flags) -> erlang:nif_error(undef).
-nif_recvfrom(_SRef, _RecvRef, _Length, _Flags) -> erlang:nif_error(undef).
-nif_recvmsg(_SRef, _RecvRef, _BufSz, _CtrlSz, _Flags) -> erlang:nif_error(undef).
+nif_recv(_SRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(undef).
+nif_recvfrom(_SRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(undef).
+nif_recvmsg(_SRef, _BufSz, _CtrlSz, _Flags, _RecvRef) -> erlang:nif_error(undef).
nif_close(_SRef) -> erlang:nif_error(undef).
nif_finalize_close(_SRef) -> erlang:nif_error(undef).
diff --git a/lib/kernel/doc/src/socket.xml b/lib/kernel/doc/src/socket.xml
index b8f699e047..49d043f403 100644
--- a/lib/kernel/doc/src/socket.xml
+++ b/lib/kernel/doc/src/socket.xml
@@ -1885,23 +1885,30 @@
<func>
<name name="recv" arity="1" since="OTP 22.0"
anchor="recv-infinity"/>
- <name name="recv" arity="2" since="OTP 22.0"/>
- <name name="recv" arity="3" clause_i="1" since="OTP 22.0"/>
- <name name="recv" arity="3" clause_i="4" since="OTP 22.0"/>
+ <name name="recv" arity="2" clause_i="1" since="OTP @OTP-16749@"/>
+ <name name="recv" arity="2" clause_i="2" since="OTP 22.0"/>
+ <name name="recv" arity="3" clause_i="3" since="OTP @OTP-16749@"/>
+ <name name="recv" arity="3" clause_i="5" since="OTP 22.0"/>
+ <name name="recv" arity="3" clause_i="8" since="OTP 22.0"/>
<name name="recv" arity="4" clause_i="3" since="OTP 22.0"/>
- <fsummary>Receive data from a socket.</fsummary>
+ <fsummary>
+ Receive data from a socket, with "infinite" time-out.
+ </fsummary>
<desc>
- <p>Receive data from a socket.</p>
+ <p>
+ Receives data from a socket, waiting for it to arrive.
+ </p>
<p>
The argument <c><anno>Length</anno></c>
specifies how many bytes to receive,
with the special case <c>0</c> meaning "all available".
</p>
<p>
- This call will not return until all requested
- data can be delivered.
- For "all available" this means the first data
- chunk that arrives.
+ For a socket of
+ <seetype marker="#type">type <c>stream</c></seetype>
+ this call will not return until all requested
+ data can be delivered, or if "all available" data
+ was requested when the first data chunk arrives.
</p>
<p>
The message <c>Flags</c> may be symbolic
@@ -1919,39 +1926,55 @@
</func>
<func>
- <name name="recv" arity="3" clause_i="5" since="OTP 22.0"
+ <name name="recv" arity="3" clause_i="4" since="OTP @OTP-16749@"
anchor="recv-timeout"/>
+ <name name="recv" arity="3" clause_i="9" since="OTP 22.0"/>
<name name="recv" arity="4" clause_i="4" since="OTP 22.0"/>
- <fsummary>Receive data from a socket.</fsummary>
+ <fsummary>Receive data from a socket, with time-out.</fsummary>
<desc>
+ <p>
+ Receives data from a socket, waiting at most
+ <c><anno>Timeout</anno></c> milliseconds for it to arrive.
+ </p>
<p>
The same as
- <seemfa marker="#recv/1">recv/1,2,3</seemfa>
+ <seeerl marker="#recv-infinity">
+ infinite time-out <c>recv/1,2,3,4</c>
+ </seeerl>
but returns <c>{error,&nbsp;timeout}</c> or
<c>{error,&nbsp;{timeout,&nbsp;<anno>Data</anno>}}</c>
after <c><anno>Timeout</anno></c> milliseconds,
- if the requested data could not be delivered.
+ if the requested data has not been delivered.
</p>
</desc>
</func>
<func>
- <name name="recv" arity="3" clause_i="2" since="OTP 22.1"
+ <name name="recv" arity="3" clause_i="1" since="OTP @OTP-16749@"
anchor="recv-nowait"/>
- <name name="recv" arity="3" clause_i="3" since="OTP @OTP-16749@"/>
+ <name name="recv" arity="3" clause_i="2" since="OTP @OTP-16749@"/>
+ <name name="recv" arity="3" clause_i="6" since="OTP 22.1"/>
+ <name name="recv" arity="3" clause_i="7" since="OTP @OTP-16749@"/>
<name name="recv" arity="4" clause_i="1" since="OTP 22.1"/>
<name name="recv" arity="4" clause_i="2" since="OTP @OTP-16749@"/>
- <fsummary>Receive data from a socket.</fsummary>
+ <fsummary>Receive data from a socket, but do not wait.</fsummary>
<desc>
+ <p>
+ Receives data from a socket,
+ but returns a select continuation if the data
+ could not be returned immediately.
+ </p>
<p>
The same as
- <seemfa marker="#recv/1">recv/1,2,3</seemfa>
- but if the data can not be immediately delivered,
+ <seeerl marker="#recv-infinity">
+ infinite time-out <c>recv/1,2,3,4</c>
+ </seeerl>
+ but if the data can not be delivered immediately,
the function returns
- <seetype marker="#select_info"><c>{select, <anno>SelectInfo</anno>}</c></seetype>,
+ <seetype marker="#select_info"><c>{select,&nbsp;<anno>SelectInfo</anno>}</c></seetype>,
and the caller will then receive a select message,
- <c>{'$socket', Socket, select, SelectHandle}</c> (
- with the
+ <c>{'$socket',&nbsp;Socket,&nbsp;select,&nbsp;SelectHandle}</c>
+ ( with the
<seetype marker="socket#select_handle"><c>SelectHandle</c></seetype>
contained in the
<seetype marker="#select_info">
@@ -1978,7 +2001,8 @@
</seetype> generated by the call.
</p>
<p>
- Note that if a <c><anno>Length</anno>&nbsp;&gt;&nbsp;0</c>
+ Note that for a socket of type <c>stream</c>,
+ if <c><anno>Length</anno>&nbsp;&gt;&nbsp;0</c>
and only part of that amount of data is available,
the function will return
<seetype marker="#select_info">
@@ -1986,7 +2010,8 @@
</seetype>
with partial data. If the caller doesn't want to wait
for more data, it must call
- <seemfa marker="#cancel/2"><c>cancel/2</c></seemfa>.
+ <seemfa marker="#cancel/2"><c>cancel/2</c></seemfa>
+ to cancel the operation.
</p>
</desc>
</func>
@@ -1994,20 +2019,26 @@
<func>
<name name="recvfrom" arity="1" since="OTP 22.0"
anchor="recvfrom-infinity"/>
- <name name="recvfrom" arity="2" since="OTP 22.0"/>
+ <name name="recvfrom" arity="2" clause_i="1" since="OTP @OTP-16749@"/>
+ <name name="recvfrom" arity="2" clause_i="2" since="OTP 22.0"/>
<name name="recvfrom" arity="3" clause_i="3" since="OTP 22.0"/>
<name name="recvfrom" arity="3" clause_i="5" since="OTP 22.0"/>
<name name="recvfrom" arity="3" clause_i="8" since="OTP 22.0"/>
<name name="recvfrom" arity="4" clause_i="3" since="OTP 22.0"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>
+ Receive a message from a socket, with "infinite" time-out.
+ </fsummary>
<desc>
- <p>Receive a message from a socket.</p>
+ <p>
+ Receive a message from a socket, waiting for it to arrive.
+ </p>
<p>
- The function returns when a message is received.
+ The function returns when a message is received,
+ or when there is a socket error.
Argument <c><anno>BufSz</anno></c> specifies the
number of bytes for the receive buffer.
If the buffer size is too small,
- the message will be truncated...
+ the message will be truncated.
</p>
<p>
If <c><anno>BufSz</anno></c> is not specified or <c>0</c>,
@@ -2022,8 +2053,7 @@
<seetype marker="#msg_flag">message flag</seetype>
<c>peek</c>. When this flag is used, the message is
<em>not</em> "consumed" from the underlying buffers,
- so another
- <seemfa marker="#recvfrom/1"><c>recvfrom/1,2,3</c></seemfa>
+ so another <c>recvfrom/1,2,3,4</c>
call is needed, possibly with an adjusted buffer size.
</p>
<p>
@@ -2040,14 +2070,20 @@
anchor="recvfrom-timeout"/>
<name name="recvfrom" arity="3" clause_i="9" since="OTP 22.0"/>
<name name="recvfrom" arity="4" clause_i="4" since="OTP 22.0"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>Receive a message from a socket, with time-out.</fsummary>
<desc>
+ <p>
+ Receives a message from a socket, waiting at most
+ <c><anno>Timeout</anno></c> milliseconds for it to arrive.
+ </p>
<p>
The same as
- <seemfa marker="#recvfrom/1">recvfrom/1,2,3</seemfa>
+ <seeerl marker="#recvfrom-infinity">
+ infinite time-out <c>recvfrom/1,2,3,4</c>
+ </seeerl>
but returns <c>{error,&nbsp;timeout}</c>
after <c><anno>Timeout</anno></c> milliseconds,
- if the requested data could not be delivered.
+ if no message has been delivered.
</p>
</desc>
</func>
@@ -2060,17 +2096,24 @@
<name name="recvfrom" arity="3" clause_i="7" since="OTP @OTP-16749@"/>
<name name="recvfrom" arity="4" clause_i="1" since="OTP 22.1"/>
<name name="recvfrom" arity="4" clause_i="2" since="OTP @OTP-16749@"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>Receive a message from a socket, but do not wait.</fsummary>
<desc>
+ <p>
+ Receives a message from a socket,
+ but returns a select continuation if no message
+ could be returned immediately.
+ </p>
<p>
The same as
- <seemfa marker="#recvfrom/1">recvfrom/1,2,3</seemfa>
- but if the data can not be immediately delivered,
+ <seeerl marker="#recvfrom-infinity">
+ infinite time-out <c>recvfrom/1,2,3,4</c>
+ </seeerl>
+ but if no message can not delivered immediately,
the function returns
- <seetype marker="#select_info"><c>{select, <anno>SelectInfo</anno>}</c></seetype>,
+ <seetype marker="#select_info"><c>{select,&nbsp;<anno>SelectInfo</anno>}</c></seetype>,
and the caller will then receive a select message,
- <c>{'$socket', Socket, select, SelectHandle}</c> (
- with the
+ <c>{'$socket',&nbsp;Socket,&nbsp;select,&nbsp;SelectHandle}</c>
+ ( with the
<seetype marker="socket#select_handle"><c>SelectHandle</c></seetype>
contained in the
<seetype marker="#select_info">
@@ -2078,7 +2121,7 @@
</seetype>
) when data has arrived.
A subsequent call to <c>recvfrom/1,2,3,4</c>
- will then return the data.
+ will then return the message.
</p>
<p>
If the time-out argument is <c>SelectHandle</c>,
@@ -2106,18 +2149,24 @@
<name name="recvmsg" arity="2" clause_i="4" since="OTP 22.0"/>
<name name="recvmsg" arity="3" clause_i="3" since="OTP 22.0"/>
<name name="recvmsg" arity="3" clause_i="5" since="OTP 22.0"/>
+ <name name="recvmsg" arity="4" clause_i="3" since="OTP @OTP-16749@"/>
<name name="recvmsg" arity="5" clause_i="3" since="OTP 22.0"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>
+ Receive a message from a socket, with "infinite" time-out.
+ </fsummary>
<desc>
- <p>Receive a message from a socket.</p>
+ <p>
+ Receive a message from a socket, waiting for it to arrive.
+ </p>
<p>
- The function returns when a message is received.
+ The function returns when a message is received,
+ or when there is a socket error.
Arguments <c><anno>BufSz</anno></c>
and <c><anno>CtrlSz</anno></c> specifies the
number of bytes for the receive buffer
and the control message buffer.
If the buffer size(s) is(are) too small,
- the message and/or control message list will be truncated...
+ the message and/or control message list will be truncated.
</p>
<p>
If <c><anno>BufSz</anno></c> is not specified or <c>0</c>,
@@ -2137,8 +2186,7 @@
<seetype marker="#msg_flag">message flag</seetype>
<c>peek</c>. When this flag is used, the message is
<em>not</em> "consumed" from the underlying buffers,
- so another
- <seemfa marker="#recvmsg/1"><c>recvfrom/1,2,3,5</c></seemfa>
+ so another <c>recvfrom/1,2,3,4,5</c>
call is needed, possibly with an adjusted buffer size.
</p>
<p>
@@ -2154,15 +2202,20 @@
<name name="recvmsg" arity="2" clause_i="5" since="OTP 22.0"
anchor="recvmsg-timeout"/>
<name name="recvmsg" arity="3" clause_i="4" since="OTP 22.0"/>
+ <name name="recvmsg" arity="4" clause_i="4" since="OTP @OTP-16749@"/>
<name name="recvmsg" arity="5" clause_i="4" since="OTP 22.0"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>Receive a message from a socket, with time-out.</fsummary>
<desc>
+ <p>
+ Receives a message from a socket, waiting at most
+ <c><anno>Timeout</anno></c> milliseconds for it to arrive.
+ </p>
<p>
The same as
- <seemfa marker="#recvmsg/1">recvmsg/1,2,3</seemfa>
+ <seeerl marker="#recvmsg-infinity">recvmsg/1,2,3,4,5</seeerl>
but returns <c>{error,&nbsp;timeout}</c>
after <c><anno>Timeout</anno></c> milliseconds,
- if the requested data could not be delivered.
+ if no message has been delivered.
</p>
</desc>
</func>
@@ -2173,26 +2226,35 @@
<name name="recvmsg" arity="2" clause_i="3" since="OTP @OTP-16749@"/>
<name name="recvmsg" arity="3" clause_i="1" since="OTP 22.1"/>
<name name="recvmsg" arity="3" clause_i="2" since="OTP @OTP-16749@"/>
+ <name name="recvmsg" arity="4" clause_i="1" since="OTP @OTP-16749@"/>
+ <name name="recvmsg" arity="4" clause_i="2" since="OTP @OTP-16749@"/>
<name name="recvmsg" arity="5" clause_i="1" since="OTP 22.1"/>
<name name="recvmsg" arity="5" clause_i="2" since="OTP @OTP-16749@"/>
- <fsummary>Receive a message from a socket.</fsummary>
+ <fsummary>Receive a message from a socket, but do not wait.</fsummary>
<desc>
+ <p>
+ Receives a message from a socket,
+ but returns a select continuation if no message
+ could be returned immediately.
+ </p>
<p>
The same as
- <seemfa marker="#recvmsg/1">recvmsg/1,2,3</seemfa>
- but if the data can not be immediately delivered,
+ <seeerl marker="#recvfrom-infinity">
+ infinite time-out <c>recvfrom/1,2,3,4</c>
+ </seeerl>
+ but if no message can not delivered immediately,
the function returns
- <seetype marker="#select_info"><c>{select, <anno>SelectInfo</anno>}</c></seetype>,
+ <seetype marker="#select_info"><c>{select,&nbsp;<anno>SelectInfo</anno>}</c></seetype>,
and the caller will then receive a select message,
- <c>{'$socket', Socket, select, SelectHandle}</c> (
- with the
+ <c>{'$socket',&nbsp;Socket,&nbsp;select,&nbsp;SelectHandle}</c>
+ ( with the
<seetype marker="socket#select_handle"><c>SelectHandle</c></seetype>
contained in the
<seetype marker="#select_info">
<c><anno>SelectInfo</anno></c>
</seetype>
) when data has arrived.
- A subsequent call to <c>recvmsg/1,2,3,5</c>
+ A subsequent call to <c>recvmsg/1,2,3,4,5</c>
will then return the data.
</p>
<p>
diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl
index 0788af62f5..489b1578cd 100644
--- a/lib/kernel/src/socket.erl
+++ b/lib/kernel/src/socket.erl
@@ -46,7 +46,7 @@
recv/1, recv/2, recv/3, recv/4,
recvfrom/1, recvfrom/2, recvfrom/3, recvfrom/4,
- recvmsg/1, recvmsg/2, recvmsg/3, recvmsg/5,
+ recvmsg/1, recvmsg/2, recvmsg/3, recvmsg/4, recvmsg/5,
close/1,
shutdown/2,
@@ -2223,148 +2223,186 @@ sendmsg_deadline_cont(SockRef, Data, Cont, Deadline, HasWritten) ->
-spec recv(Socket) ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()}.
+ Reason :: posix() | 'closed' | invalid().
recv(Socket) ->
- recv(Socket, 0).
+ recv(Socket, 0, ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recv(Socket, Length) ->
+-spec recv(Socket, Flags) ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Length) ->
+ {'ok', Data} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()}.
+ Reason :: posix() | 'closed' | invalid().
+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,
+ ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
+
+-spec recv(Socket, Flags, SelectHandle :: 'nowait') ->
+ {'ok', Data} |
+ {'ok', {Data, SelectInfo}} |
+ {'select', SelectInfo} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: posix() | 'closed' | invalid();
--spec recv(Socket, Length, Flags) ->
+ (Socket, Flags, SelectHandle :: select_handle()) ->
{'ok', Data} |
- {'error', Reason} when
+ {'ok', {Data, SelectInfo}} |
+ {'select', SelectInfo} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Flags, Timeout :: 'infinity') ->
+ {'ok', Data} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, Flags, Timeout :: non_neg_integer()) ->
+ {'ok', Data} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid() | 'timeout';
+
+ (Socket, Length, Flags) ->
+ {'ok', Data} |
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, 'nowait') ->
+ (Socket, Length, SelectHandle :: 'nowait') ->
{'ok', Data} |
{'ok', {Data, SelectInfo}} |
{'select', SelectInfo} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Data :: binary(),
SelectInfo :: select_info(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, SelectHandle) ->
+ (Socket, Length, SelectHandle :: select_handle()) ->
{'ok', Data} |
{'ok', {Data, SelectInfo}} |
{'select', SelectInfo} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Data :: binary(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, Timeout) ->
+ (Socket, Length, Timeout :: 'infinity') ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
- Timeout :: 'infinity',
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, Timeout) ->
+ (Socket, Length, Timeout :: non_neg_integer()) ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
- Timeout :: non_neg_integer(),
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() | 'timeout' |
- {posix() | 'closed' | invalid() | 'timeout', Data :: binary()}.
+ Reason :: posix() | 'closed' | invalid() | 'timeout'.
+recv(Socket, Flags, Timeout) when is_list(Flags) ->
+ recv(Socket, 0, Flags, Timeout);
recv(Socket, Length, Flags) when is_list(Flags) ->
recv(Socket, Length, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
recv(Socket, Length, Timeout) ->
recv(Socket, Length, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
--spec recv(Socket, Length, Flags, 'nowait') ->
+-spec recv(Socket, Length, Flags, SelectHandle :: 'nowait') ->
{'ok', Data} |
{'ok', {Data, SelectInfo}} |
{'select', SelectInfo} |
- {'error', Reason} when
+ {'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() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, Flags, SelectHandle) ->
+ (Socket, Length, Flags, SelectHandle :: select_handle()) ->
{'ok', Data} |
{'ok', {Data, SelectInfo}} |
{'select', SelectInfo} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
Data :: binary(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, Flags, Timeout) ->
+ (Socket, Length, Flags, Timeout :: 'infinity') ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: 'infinity',
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() |
- {posix() | 'closed' | invalid(), Data :: binary()};
+ Reason :: posix() | 'closed' | invalid();
- (Socket, Length, Flags, Timeout) ->
+ (Socket, Length, Flags, Timeout :: non_neg_integer()) ->
{'ok', Data} |
- {'error', Reason} when
+ {'error', Reason} |
+ {'error', {Reason, Data}} when
Socket :: socket(),
Length :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: non_neg_integer(),
Data :: binary(),
- Reason ::
- posix() | 'closed' | invalid() | 'timeout' |
- {posix() | 'closed' | invalid() | 'timeout', Data :: binary()}.
+ Reason :: posix() | 'closed' | invalid() | 'timeout'.
recv(?socket(SockRef), Length, Flags, Timeout)
when is_reference(SockRef),
@@ -2379,6 +2417,13 @@ recv(?socket(SockRef), Length, Flags, Timeout)
select_handle ->
SelectHandle = Timeout,
recv_nowait(SockRef, Length, Flags, SelectHandle, <<>>);
+ zero ->
+ case prim_socket:recv(SockRef, Length, Flags, zero) of
+ ok ->
+ {error, timeout};
+ Result ->
+ Result
+ end;
Deadline ->
recv_deadline(SockRef, Length, Flags, Deadline, <<>>)
end;
@@ -2389,7 +2434,7 @@ recv(Socket, Length, Flags, Timeout) ->
%% so Length == 0 means to return all available data also when recursing
recv_nowait(SockRef, Length, Flags, SelectHandle, Acc) ->
- case prim_socket:recv(SockRef, SelectHandle, Length, Flags) of
+ case prim_socket:recv(SockRef, Length, Flags, SelectHandle) of
{more, Bin} ->
%% We got what we requested but will not waste more time
%% although there might be more data available
@@ -2400,7 +2445,7 @@ recv_nowait(SockRef, Length, Flags, SelectHandle, Acc) ->
{ok, {bincat(Acc, Bin), ?SELECT_INFO(recv, SelectHandle)}};
select ->
%% The caller will get a select message when there
- %% might me data to read
+ %% might be data to read
if
byte_size(Acc) =:= 0 ->
{select, ?SELECT_INFO(recv, SelectHandle)};
@@ -2413,7 +2458,7 @@ recv_nowait(SockRef, Length, Flags, SelectHandle, Acc) ->
recv_deadline(SockRef, Length, Flags, Deadline, Acc) ->
SelectHandle = make_ref(),
- case prim_socket:recv(SockRef, SelectHandle, Length, Flags) of
+ case prim_socket:recv(SockRef, Length, Flags, SelectHandle) of
{more, Bin} ->
%% There is more data readily available
%% - repeat unless time's up
@@ -2510,7 +2555,9 @@ recv_error(Acc, Reason) ->
%% is needed, possibly with a then adjusted buffer size.
%%
--spec recvfrom(Socket) -> {'ok', {Source, Data}} | {'error', Reason} when
+-spec recvfrom(Socket) ->
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
Socket :: socket(),
Source :: sockaddr_recv(),
Data :: binary(),
@@ -2519,19 +2566,32 @@ recv_error(Acc, Reason) ->
recvfrom(Socket) ->
recvfrom(Socket, 0).
--spec recvfrom(Socket, BufSz) -> {'ok', {Source, Data}} | {'error', Reason} when
+-spec recvfrom(Socket, Flags) ->
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
+ Socket :: socket(),
+ Flags :: [msg_flag() | integer()],
+ Source :: sockaddr_recv(),
+ Data :: binary(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz) ->
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid().
+recvfrom(Socket, Flags) when is_list(Flags) ->
+ recvfrom(Socket, 0, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
recvfrom(Socket, BufSz) ->
recvfrom(Socket, BufSz,
?ESOCK_RECV_FLAGS_DEFAULT,
?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recvfrom(Socket, Flags, 'nowait') ->
+-spec recvfrom(Socket, Flags, SelectHandle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2542,7 +2602,7 @@ recvfrom(Socket, BufSz) ->
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, SelectHandle) ->
+ (Socket, Flags, SelectHandle :: select_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2551,31 +2611,29 @@ recvfrom(Socket, BufSz) ->
Source :: sockaddr_recv(),
Data :: binary(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, Timeout) ->
+ (Socket, Flags, Timeout :: 'infinity') ->
{'ok', {Source, Data}} |
{'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Timeout :: 'infinity',
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, Timeout) ->
+ (Socket, Flags, Timeout :: non_neg_integer()) ->
{'ok', {Source, Data}} |
{'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Timeout :: non_neg_integer(),
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid() | 'timeout';
(Socket, BufSz, Flags) ->
- {'ok', {Source, Data}} | {'error', Reason} when
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
@@ -2583,7 +2641,7 @@ recvfrom(Socket, BufSz) ->
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, 'nowait') ->
+ (Socket, BufSz, SelectHandle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2594,7 +2652,7 @@ recvfrom(Socket, BufSz) ->
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, SelectHandle) ->
+ (Socket, BufSz, SelectHandle :: select_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2603,23 +2661,22 @@ recvfrom(Socket, BufSz) ->
Source :: sockaddr_recv(),
Data :: binary(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, Timeout) ->
- {'ok', {Source, Data}} | {'error', Reason} when
+ (Socket, BufSz, Timeout :: 'infinity') ->
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
- Timeout :: 'infinity',
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, Timeout) ->
- {'ok', {Source, Data}} | {'error', Reason} when
+ (Socket, BufSz, Timeout :: non_neg_integer()) ->
+ {'ok', {Source, Data}} |
+ {'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
- Timeout :: non_neg_integer(),
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid() | 'timeout'.
@@ -2631,7 +2688,7 @@ 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, 'nowait') ->
+-spec recvfrom(Socket, BufSz, Flags, SelectHandle :: 'nowait') ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2643,7 +2700,7 @@ recvfrom(Socket, BufSz, Timeout) ->
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, Flags, SelectHandle) ->
+ (Socket, BufSz, Flags, SelectHandle :: select_handle()) ->
{'ok', {Source, Data}} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2653,27 +2710,24 @@ recvfrom(Socket, BufSz, Timeout) ->
Source :: sockaddr_recv(),
Data :: binary(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, Flags, Timeout) ->
+ (Socket, BufSz, Flags, Timeout :: 'infinity') ->
{'ok', {Source, Data}} |
{'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: 'infinity',
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, Flags, Timeout) ->
+ (Socket, BufSz, Flags, Timeout :: non_neg_integer()) ->
{'ok', {Source, Data}} |
{'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: non_neg_integer(),
Source :: sockaddr_recv(),
Data :: binary(),
Reason :: posix() | 'closed' | invalid() | 'timeout'.
@@ -2691,6 +2745,13 @@ recvfrom(?socket(SockRef), BufSz, Flags, Timeout)
select_handle ->
SelectHandle = Timeout,
recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags);
+ zero ->
+ case prim_socket:recvfrom(SockRef, BufSz, Flags, zero) of
+ ok ->
+ {error, timeout};
+ Result ->
+ recvfrom_result(Result)
+ end;
Deadline ->
recvfrom_deadline(SockRef, BufSz, Flags, Deadline)
end;
@@ -2698,7 +2759,7 @@ recvfrom(Socket, BufSz, Flags, Timeout) ->
erlang:error(badarg, [Socket, BufSz, Flags, Timeout]).
recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags) ->
- case prim_socket:recvfrom(SockRef, SelectHandle, BufSz, Flags) of
+ case prim_socket:recvfrom(SockRef, BufSz, Flags, SelectHandle) of
select ->
{select, ?SELECT_INFO(recvfrom, SelectHandle)};
Result ->
@@ -2707,7 +2768,7 @@ recvfrom_nowait(SockRef, BufSz, SelectHandle, Flags) ->
recvfrom_deadline(SockRef, BufSz, Flags, Deadline) ->
SelectHandle = make_ref(),
- case prim_socket:recvfrom(SockRef, SelectHandle, BufSz, Flags) of
+ case prim_socket:recvfrom(SockRef, BufSz, Flags, SelectHandle) of
select ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
@@ -2737,7 +2798,9 @@ recvfrom_result(Result) ->
%% ---------------------------------------------------------------------------
%%
--spec recvmsg(Socket) -> {'ok', Msg} | {'error', Reason} when
+-spec recvmsg(Socket) ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid().
@@ -2746,40 +2809,44 @@ recvmsg(Socket) ->
recvmsg(Socket, 0, 0,
?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
--spec recvmsg(Socket, Flags) -> {'ok', Msg} | {'error', Reason} when
+
+-spec recvmsg(Socket, Flags) ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Timeout :: 'nowait')
- -> {'ok', Msg} |
- {'select', SelectInfo} |
- {'error', Reason} when
+ (Socket, Timeout :: 'nowait') ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'error', Reason} when
Socket :: socket(),
Msg :: msg_recv(),
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, SelectHandle)
- -> {'ok', Msg} |
- {'select', SelectInfo} |
- {'error', Reason} when
+ (Socket, SelectHandle :: select_handle()) ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'error', Reason} when
Socket :: socket(),
Msg :: msg_recv(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Timeout) -> {'ok', Msg} | {'error', Reason} when
+ (Socket, Timeout :: 'infinity') ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
- Timeout :: 'infinity',
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Timeout) -> {'ok', Msg} | {'error', Reason} when
+ (Socket, Timeout :: non_neg_integer()) ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
- Timeout :: non_neg_integer(),
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid() | 'timeout'.
@@ -2788,42 +2855,90 @@ recvmsg(Socket, Flags) when is_list(Flags) ->
recvmsg(Socket, Timeout) ->
recvmsg(Socket, 0, 0, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
--spec recvmsg(Socket, Flags, Timeout :: 'nowait')
- -> {'ok', Msg} |
- {'select', SelectInfo} |
- {'error', Reason} when
+
+-spec recvmsg(Socket, BufSz, CtrlSz, SelectHandle :: 'nowait') ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'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()) ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'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, Timeout :: 'infinity') ->
+ {'ok', Msg} |
+ {'error', Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Msg :: msg_recv(),
+ Reason :: posix() | 'closed' | invalid();
+
+ (Socket, BufSz, CtrlSz, Timeout :: non_neg_integer()) ->
+ {'ok', Msg} |
+ {'error', Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Msg :: msg_recv(),
+ Reason :: posix() | 'closed' | invalid() | 'timeout'.
+
+recvmsg(Socket, BufSz, CtrlSz, Timeout) ->
+ recvmsg(Socket, BufSz, CtrlSz, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
+
+
+-spec recvmsg(Socket, Flags, Timeout :: 'nowait') ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
Msg :: msg_recv(),
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, SelectHandle)
- -> {'ok', Msg} |
- {'select', SelectInfo} |
- {'error', Reason} when
+ (Socket, Flags, SelectHandle :: select_handle()) ->
+ {'ok', Msg} |
+ {'select', SelectInfo} |
+ {'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
Msg :: msg_recv(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, Timeout) -> {'ok', Msg} | {'error', Reason} when
+ (Socket, Flags, Timeout :: 'infinity') ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Timeout :: 'infinity',
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid();
- (Socket, Flags, Timeout) -> {'ok', Msg} | {'error', Reason} when
+ (Socket, Flags, Timeout :: non_neg_integer()) ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
Flags :: [msg_flag() | integer()],
- Timeout :: non_neg_integer(),
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid() | 'timeout';
- (Socket, BufSz, CtrlSz) -> {'ok', Msg} | {'error', Reason} when
+ (Socket, BufSz, CtrlSz) ->
+ {'ok', Msg} |
+ {'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
CtrlSz :: non_neg_integer(),
@@ -2837,7 +2952,7 @@ 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, 'nowait') ->
+-spec recvmsg(Socket, BufSz, CtrlSz, Flags, SelectHandle :: 'nowait') ->
{'ok', Msg} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2849,7 +2964,7 @@ recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz), is_integer(CtrlSz) ->
SelectInfo :: select_info(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, CtrlSz, Flags, SelectHandle) ->
+ (Socket, BufSz, CtrlSz, Flags, SelectHandle :: select_handle()) ->
{'ok', Msg} |
{'select', SelectInfo} |
{'error', Reason} when
@@ -2859,28 +2974,25 @@ recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz), is_integer(CtrlSz) ->
Flags :: [msg_flag() | integer()],
Msg :: msg_recv(),
SelectInfo :: select_info(),
- SelectHandle :: select_handle(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, CtrlSz, Flags, Timeout) ->
+ (Socket, BufSz, CtrlSz, Flags, Timeout :: 'infinity') ->
{'ok', Msg} |
{'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
CtrlSz :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: 'infinity',
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid();
- (Socket, BufSz, CtrlSz, Flags, Timeout) ->
+ (Socket, BufSz, CtrlSz, Flags, Timeout :: non_neg_integer()) ->
{'ok', Msg} |
{'error', Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
CtrlSz :: non_neg_integer(),
Flags :: [msg_flag() | integer()],
- Timeout :: non_neg_integer(),
Msg :: msg_recv(),
Reason :: posix() | 'closed' | invalid() | 'timeout'.
@@ -2898,6 +3010,13 @@ recvmsg(?socket(SockRef), BufSz, CtrlSz, Flags, Timeout)
select_handle ->
SelectHandle = Timeout,
recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, SelectHandle);
+ zero ->
+ case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, zero) of
+ ok ->
+ {error, timeout};
+ Result ->
+ recvmsg_result(Result)
+ end;
Deadline ->
recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline)
end;
@@ -2905,7 +3024,7 @@ 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, SelectHandle, BufSz, CtrlSz, Flags) of
+ case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, SelectHandle) of
select ->
{select, ?SELECT_INFO(recvmsg, SelectHandle)};
Result ->
@@ -2914,7 +3033,7 @@ recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, SelectHandle) ->
recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline) ->
SelectHandle = make_ref(),
- case prim_socket:recvmsg(SockRef, SelectHandle, BufSz, CtrlSz, Flags) of
+ case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, SelectHandle) of
select ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
@@ -2929,12 +3048,6 @@ recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline) ->
cancel(SockRef, recvmsg, SelectHandle),
{error, timeout}
end;
- %%
- {error, ealready = Reason} ->
- %% Internal error:
- %% we called recvmsg, got eagain, and called recvmsg again
- %% - without waiting for select message
- erlang:error(Reason);
Result ->
recvmsg_result(Result)
end.
@@ -3270,12 +3383,12 @@ deadline(Timeout) ->
Timeout;
infinity ->
Timeout;
+ SelectHandle when is_reference(SelectHandle) ->
+ select_handle;
0 ->
zero;
_ when is_integer(Timeout), 0 < Timeout ->
timestamp() + Timeout;
- _ when is_reference(Timeout) ->
- select_handle;
_ ->
invalid
end.
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index c55f120d93..139a886aa5 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -20701,8 +20701,6 @@ api_opt_ip_recverr_udp4(doc) ->
[];
api_opt_ip_recverr_udp4(Config) when is_list(Config) ->
?TT(?SECS(5)),
- SendRef = nowait(Config),
- RecvRef = nowait(Config),
tc_try(api_opt_ip_recverr_udp4,
fun() ->
has_support_ip_recverr()
@@ -20714,21 +20712,19 @@ api_opt_ip_recverr_udp4(Config) when is_list(Config) ->
Get = fun(Sock, Key) ->
socket:getopt(Sock, ip, Key)
end,
- Send = fun(Sock, Data, Dest) ->
- socket:sendto(Sock, Data, Dest, [], SendRef)
+ Send = fun(Sock, Data, Dest, Tmo) ->
+ socket:sendto(Sock, Data, Dest, [], Tmo)
end,
- Recv = fun(Sock) ->
- socket:recvfrom(Sock, 0, [], RecvRef)
+ Recv = fun(Sock, Tmo) ->
+ socket:recvfrom(Sock, 0, [], Tmo)
end,
InitState = #{domain => inet,
proto => udp,
send => Send,
recv => Recv,
- send_sref => SendRef,
- recv_sref => RecvRef,
set => Set,
get => Get},
- ok = api_opt_recverr_udp(InitState)
+ ok = api_opt_recverr_udp(Config, InitState)
end).
@@ -20744,8 +20740,6 @@ api_opt_ipv6_recverr_udp6(doc) ->
[];
api_opt_ipv6_recverr_udp6(Config) when is_list(Config) ->
?TT(?SECS(5)),
- SendRef = nowait(Config),
- RecvRef = nowait(Config),
tc_try(api_opt_ipv6_recverr_udp6,
fun() ->
has_support_ipv6(),
@@ -20758,27 +20752,25 @@ api_opt_ipv6_recverr_udp6(Config) when is_list(Config) ->
Get = fun(Sock, Key) ->
socket:getopt(Sock, ipv6, Key)
end,
- Send = fun(Sock, Data, Dest) ->
- socket:sendto(Sock, Data, Dest, [], SendRef)
+ Send = fun(Sock, Data, Dest, Tmo) ->
+ socket:sendto(Sock, Data, Dest, [], Tmo)
end,
- Recv = fun(Sock) ->
- socket:recvfrom(Sock, 0, [], SendRef)
+ Recv = fun(Sock, Tmo) ->
+ socket:recvfrom(Sock, 0, [], Tmo)
end,
InitState = #{domain => inet6,
proto => udp,
send => Send,
recv => Recv,
- send_sref => SendRef,
- recv_sref => RecvRef,
set => Set,
get => Get},
- ok = api_opt_recverr_udp(InitState)
+ ok = api_opt_recverr_udp(Config, InitState)
end).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-api_opt_recverr_udp(InitState) ->
+api_opt_recverr_udp(Config, InitState) ->
Seq =
[
#{desc => "create socket",
@@ -20792,13 +20784,19 @@ api_opt_recverr_udp(InitState) ->
end
end},
#{desc => "bind (to loopback)",
- cmd => fun(#{sock := Sock} = _State) ->
+ cmd => fun(#{sock := Sock} = State) ->
case socket:bind(Sock, loopback) of
ok ->
- ?SEV_IPRINT("bound"),
- ok;
- {error, _} = ERROR ->
- ERROR
+ case socket:sockname(Sock) of
+ {ok, Addr} ->
+ ?SEV_IPRINT(
+ "bound to ~p", [Addr]),
+ {ok, State#{addr => Addr}};
+ {error, _} = ERROR_1 ->
+ ERROR_1
+ end;
+ {error, _} = ERROR_2 ->
+ ERROR_2
end
end},
@@ -20814,9 +20812,9 @@ api_opt_recverr_udp(InitState) ->
#{desc => "try (async) read (=> select)",
cmd => fun(#{sock := Sock,
- recv := Recv,
- recv_sref := RecvRef} = State) ->
- case Recv(Sock) of
+ recv := Recv} = State) ->
+ RecvRef = nowait(Config),
+ case Recv(Sock, RecvRef) of
{select, SelectInfo} when RecvRef =:= nowait ->
?SEV_IPRINT("expected select nowait: "
"~n ~p", [SelectInfo]),
@@ -20836,11 +20834,11 @@ api_opt_recverr_udp(InitState) ->
end
end},
- #{desc => "try (dummy) send",
+ #{desc => "try send to nowhere",
cmd => fun(#{domain := Domain,
sock := Sock,
- send := Send,
- send_sref := SendRef} = State) ->
+ send := Send} = State) ->
+ SendRef = nowait(Config),
Dest = #{family => Domain,
addr => if
(Domain =:= inet) ->
@@ -20848,8 +20846,8 @@ api_opt_recverr_udp(InitState) ->
(Domain =:= inet6) ->
{0,0,0,0,0,0,0,1}
end,
- port => 1234},
- case Send(Sock, <<"ping">>, Dest) of
+ port => 44444},
+ case Send(Sock, <<"ping">>, Dest, SendRef) of
ok ->
?SEV_IPRINT("sent"),
ok;
@@ -20871,7 +20869,7 @@ api_opt_recverr_udp(InitState) ->
end
end},
- #{desc => "await select message",
+ #{desc => "await receive select message",
cmd => fun(#{sock := Sock,
rselect := {select_info, _, Ref}} = _State) ->
receive
@@ -20884,7 +20882,7 @@ api_opt_recverr_udp(InitState) ->
#{desc => "try recv - expect econnrefused",
cmd => fun(#{sock := Sock, recv := Recv} = _State) ->
- case Recv(Sock) of
+ case Recv(Sock, infinity) of
{error, econnrefused = Reason} ->
?SEV_IPRINT("expected failure: ~p", [Reason]),
ok;
@@ -20902,6 +20900,39 @@ api_opt_recverr_udp(InitState) ->
end
end},
+ #{desc => "send to self",
+ cmd =>
+ fun(#{sock := Sock,
+ send := Send,
+ addr := Addr} = _State) ->
+ case Send(Sock, <<"ring">>, Addr, infinity) of
+ ok ->
+ ?SEV_IPRINT("sent to self"),
+ ok;
+ {error, _} = Error ->
+ Error
+ end
+ end},
+
+ #{desc => "try recv - expect data sent to self",
+ cmd => fun(#{sock := Sock,
+ addr := Addr,
+ recv := Recv} = _State) ->
+ case Recv(Sock, infinity) of
+ {ok, {Addr, <<"ring">>}} ->
+ ?SEV_IPRINT("receive expected"),
+ ok;
+ {select, SelectInfo} ->
+ ?SEV_EPRINT("unexpected select: ~p",
+ [SelectInfo]),
+ {error, unexpected_success};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("unexpected error: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
#{desc => "try recv error queue",
cmd => fun(#{domain := Domain, sock := Sock}) ->
%% Note that not all platforms that support
@@ -20915,7 +20946,7 @@ api_opt_recverr_udp(InitState) ->
if (Domain =:= inet) -> ip;
(Domain =:= inet6) -> ipv6
end,
- case socket:recvmsg(Sock, [errqueue]) of
+ case socket:recvmsg(Sock, [errqueue], 0) of
{ok, #{addr := #{family := Domain,
addr := Addr},
flags := [errqueue],