Skip to content

Commit

Permalink
Merge branch 'maint'
Browse files Browse the repository at this point in the history
  • Loading branch information
bmk committed Oct 7, 2024
2 parents 4a5ac69 + bcf5cba commit fa80932
Show file tree
Hide file tree
Showing 7 changed files with 469 additions and 20 deletions.
159 changes: 150 additions & 9 deletions erts/emulator/drivers/common/inet_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#define INET_OPT_RECVTTL 47 /* IP_RECVTTL ancillary data */
#define TCP_OPT_NOPUSH 48 /* super-Nagle, aka TCP_CORK */
#define INET_LOPT_TCP_READ_AHEAD 49 /* Read ahead of packet data */
#define INET_LOPT_NON_BLOCK_SEND 50 /* Non-blocking send, only SCTP */
#define INET_LOPT_DEBUG 99 /* Enable/disable DEBUG for a socket */

/* SCTP options: a separate range, from 100: */
Expand Down Expand Up @@ -988,6 +989,7 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#define INET_FLG_IS_IGNORED_RD (1 << 2)
#define INET_FLG_IS_IGNORED_WR (1 << 3)
#define INET_FLG_IS_IGNORED_PASS (1 << 4)
#define INET_FLG_NON_BLOCK_SEND (1 << 5) /* Currently only SCTP */

/*
** End of interface constants.
Expand Down Expand Up @@ -1039,6 +1041,9 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#define INET_IGNORE_READ (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_RD)
#define INET_IGNORE_WRITE (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_WR)
#define INET_IGNORE_PASSIVE (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_PASS)
#define IS_NON_BLOCK_SEND(desc) ((desc)->flags & INET_FLG_NON_BLOCK_SEND)
#define SET_NON_BLOCK_SEND(desc) ((desc)->flags & INET_FLG_NON_BLOCK_SEND)
#define CLEAR_NON_BLOCK_SEND(desc) ((desc)->flags & ~(INET_FLG_NON_BLOCK_SEND))

/* Max length of Erlang Term Buffer (for outputting structured terms): */
#ifdef HAVE_SCTP
Expand Down Expand Up @@ -1256,6 +1261,7 @@ typedef struct {
#endif
int recv_cmsgflags; /* Which ancillary data to expect */
int debug; /* debug enabled or not */

} inet_descriptor;


Expand Down Expand Up @@ -7681,6 +7687,37 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
break;
#endif

case INET_LOPT_NON_BLOCK_SEND:
#ifdef HAVE_SCTP
if (IS_SCTP(desc)) {
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"inet_set_opts(non-block-send) -> %s\r\n",
__LINE__, desc->s,
driver_caller(desc->port), B2S(ival)) );
if (ival) {
desc->flags |= INET_FLG_NON_BLOCK_SEND;
} else {
desc->flags = (desc->flags) & ~(INET_FLG_NON_BLOCK_SEND);
}
} else {
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"inet_set_opts(non-block-send) -> IGNORE\r\n",
__LINE__, desc->s,
driver_caller(desc->port)) );
}
#else
{
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"inet_set_opts(non-block-send) -> IGNORE\r\n",
__LINE__, desc->s,
driver_caller(desc->port)) );
}
#endif
continue; /* take care of next option */

case INET_LOPT_DEBUG:
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
Expand Down Expand Up @@ -8719,6 +8756,33 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
}
#endif

case INET_LOPT_NON_BLOCK_SEND:
if (IS_SCTP(desc))
{
int ival = get_int32(curr); curr += 4;

DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"sctp_set_opts(non-block-send) -> %s\r\n",
__LINE__, desc->s, driver_caller(desc->port),
B2S(ival)) );
if (ival) {
desc->flags |= INET_FLG_NON_BLOCK_SEND;
} else {
desc->flags = (desc->flags) & ~(INET_FLG_NON_BLOCK_SEND);
}

res = 0;
}
else {
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"sctp_set_opts(non-block-send) -> IGNORE\r\n",
__LINE__, desc->s,
driver_caller(desc->port)) );
}
continue; /* take care of next option */

case INET_LOPT_DEBUG:
{
int ival = get_int32(curr); curr += 4;
Expand Down Expand Up @@ -9423,6 +9487,15 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
#endif /* #ifdef __WIN32__ */

case INET_LOPT_NON_BLOCK_SEND:
*ptr++ = opt;
if (IS_NON_BLOCK_SEND(desc))
ival = TRUE;
else
ival = FALSE;
put_int32(ival, ptr);
continue;

case INET_LOPT_DEBUG:
*ptr++ = opt;
ival = desc->debug;
Expand Down Expand Up @@ -9558,13 +9631,48 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
int eopt = *buf; /* "eopt" is 1-byte encoded */
buf ++; buflen --;

DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"sctp_fill_opts -> opt: %d\r\n",
__LINE__, desc->s, driver_caller(desc->port), eopt) );

switch(eopt)
{
/* Local options allowed for SCTP. For TCP and UDP, the values of
these options are returned via "res" using integer encoding,
but here, we encode them as proper terms the same way as we do
it for all other SCTP options:
*/
case INET_LOPT_NON_BLOCK_SEND:
{
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"sctp_fill_opts -> NON_BLOCK_SEND: %s\r\n",
__LINE__, desc->s, driver_caller(desc->port),
B2S(IS_NON_BLOCK_SEND(desc))) );

if (IS_NON_BLOCK_SEND(desc))
i = LOAD_ATOM (spec, i, am_true);
else
i = LOAD_ATOM (spec, i, am_false);
break;
}

case INET_LOPT_DEBUG:
{
DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"sctp_fill_opts -> DEBUG: %s\r\n",
__LINE__, desc->s, driver_caller(desc->port),
B2S(desc->debug)) );

if (desc->debug)
i = LOAD_ATOM (spec, i, am_true);
else
i = LOAD_ATOM (spec, i, am_false);
break;
}

case INET_LOPT_BUFFER:
{
PLACE_FOR(spec, i, LOAD_ATOM_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT);
Expand Down Expand Up @@ -14014,15 +14122,17 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s,
}

/* Some flags must be inherited at this point */
copy_desc->inet.mode = desc->inet.mode;
copy_desc->inet.exitf = desc->inet.exitf;
copy_desc->inet.deliver = desc->inet.deliver;
copy_desc->inet.htype = desc->inet.htype;
copy_desc->inet.psize = desc->inet.psize;
copy_desc->inet.stype = desc->inet.stype;
copy_desc->inet.sfamily = desc->inet.sfamily;
copy_desc->inet.hsz = desc->inet.hsz;
copy_desc->inet.bufsz = desc->inet.bufsz;
copy_desc->inet.mode = desc->inet.mode;
copy_desc->inet.exitf = desc->inet.exitf;
copy_desc->inet.deliver = desc->inet.deliver;
copy_desc->inet.htype = desc->inet.htype;
copy_desc->inet.psize = desc->inet.psize;
copy_desc->inet.stype = desc->inet.stype;
copy_desc->inet.sfamily = desc->inet.sfamily;
copy_desc->inet.hsz = desc->inet.hsz;
copy_desc->inet.bufsz = desc->inet.bufsz;
// Only inherit the NON-BLOCK-SEND flag
copy_desc->inet.flags = desc->inet.flags & INET_FLG_NON_BLOCK_SEND;

/* The new port will be linked and connected to the owner */
port = driver_create_port(port, owner, "sctp_inet",
Expand Down Expand Up @@ -14744,11 +14854,42 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
#endif
if (IS_SOCKET_ERROR(code)) {
int err = sock_errno();

DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"packet_inet_command -> send failed"
"\r\n error: %d (%T)"
"\r\n",
__LINE__,
desc->s, driver_caller(desc->port),
err, error_atom(err)) );

if ((err != ERRNO_BLOCK) && (err != EINTR)) {
inet_reply_error(desc, err);
return;
}
// else if (desc->nonBlockSend) {
else if (IS_NON_BLOCK_SEND(desc)) {

DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"packet_inet_command -> block|intr when non-block send"
"\r\n",
__LINE__,
desc->s, driver_caller(desc->port)) );

inet_reply_error(desc, err);
return;
}
else {

DDBG(desc,
("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
"packet_inet_command -> block|intr send"
"\r\n",
__LINE__,
desc->s, driver_caller(desc->port)) );

/* XXX if(! INET_IGNORED(INETP(desc))) */
sock_select(desc, (FD_WRITE|FD_CLOSE), 1);
set_busy_port(desc->port, 1);
Expand Down
Binary file modified erts/preloaded/ebin/prim_inet.beam
Binary file not shown.
5 changes: 4 additions & 1 deletion erts/preloaded/src/prim_inet.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM;
enc_opt(raw) -> ?INET_OPT_RAW;
enc_opt(bind_to_device) -> ?INET_OPT_BIND_TO_DEVICE;
enc_opt(read_ahead) -> ?INET_LOPT_TCP_READ_AHEAD;
enc_opt(non_block_send) -> ?INET_OPT_NON_BLOCK_SEND;
enc_opt(debug) -> ?INET_OPT_DEBUG;
% Names of SCTP opts:
enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO;
Expand Down Expand Up @@ -1646,6 +1647,7 @@ dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter;
dec_opt(?INET_OPT_RAW) -> raw;
dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device;
dec_opt(?INET_LOPT_TCP_READ_AHEAD) -> read_ahead;
dec_opt(?INET_OPT_NON_BLOCK_SEND) -> non_block_send;
dec_opt(?INET_OPT_DEBUG) -> debug;
dec_opt(I) when is_integer(I) -> undefined.

Expand Down Expand Up @@ -1759,6 +1761,7 @@ type_opt_1(netns) -> binary;
type_opt_1(show_econnreset) -> bool;
type_opt_1(bind_to_device) -> binary;
type_opt_1(read_ahead) -> bool;
type_opt_1(non_block_send) -> bool;
type_opt_1(debug) -> bool;
%%
%% SCTP options (to be set). If the type is a record type, the corresponding
Expand Down Expand Up @@ -2070,7 +2073,7 @@ type_value_2(binary_or_uint,Int)
%% Type-checking of SCTP options
type_value_2(sctp_assoc_id, X)
when X band 16#ffffffff =:= X -> true;
type_value_2(_, _) -> false.
type_value_2(_T, _V) -> false.



Expand Down
27 changes: 26 additions & 1 deletion lib/kernel/src/gen_sctp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,15 @@ by calling `inet:setopts/2`. They can be retrieved using `inet:getopts/2`.
larger than `val(recbuf)`. Setting this option also adjusts the size
of the driver buffer (see `buffer` above).
### [](){: #option_non_block_send }
- **`{non_block_send, boolean()}`** - A send call that would otherwise block (hang),
will instead immediately return with e.g. `{error, eagain}`
*if* this option has been set to `true`.
Defaults to `false`.
- **`{sctp_module, module()}`** - Overrides which callback module is used.
Defaults to `inet_sctp` for IPv4 and `inet6_sctp` for IPv6.
Defaults to `inet_sctp` for IPv4 and `inet6_sctp` for IPv6.
- **`{sctp_rtoinfo, #sctp_rtoinfo{}}`**
Expand Down Expand Up @@ -683,6 +690,7 @@ future associations".
-type elementary_option() ::
{active, true | false | once | -32768..32767} |
{buffer, non_neg_integer()} |
{non_block_send, boolean()} |
{debug, boolean()} |
{dontroute, boolean()} |
{exclusiveaddruse, boolean()} |
Expand Down Expand Up @@ -713,6 +721,7 @@ future associations".
-type elementary_option_name() ::
active |
buffer |
non_block_send |
debug |
dontroute |
exclusiveaddruse |
Expand Down Expand Up @@ -1502,6 +1511,14 @@ and context (passed to the local SCTP layer), which can be used,
for example, for error identification. However, such a fine grained
user control is rarely required. The function [`send/4`](`send/4`)
is sufficient for most applications.
> #### Note {: .info }
>
> Send is normally blocking, but if the socket option
> [`non_block_send`](#option_non_block_send) is set to true,
> the function will return with e.g. {error, eagain}
> in the case when the function would otherwise block.
> It is then up to the user to try again later.
""".
-spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when
Socket :: sctp_socket(),
Expand All @@ -1528,6 +1545,14 @@ Sends a `Data` message on the association `Assoc` and `Stream`.
[`#sctp_assoc_change{}`](#record-sctp_assoc_change) record
from an association establishment, or as the `t:assoc_id/0`
`t:integer/0` field value.
> #### Note {: .info }
>
> Send is normally blocking, but if the socket option
> [`non_block_send`](#option_non_block_send) is set to true,
> the function will return with e.g. {error, eagain}
> in the case when the function would otherwise block.
> It is then up to the user to try again later.
""".
-spec send(Socket, Assoc, Stream, Data) -> ok | {error, Reason} when
Socket :: sctp_socket(),
Expand Down
Loading

0 comments on commit fa80932

Please sign in to comment.