aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-10-04 15:33:23 +0200
committerMicael Karlberg <[email protected]>2018-10-04 15:33:23 +0200
commit4e3f42da1dae7166faeb9f9e07adc40bc3b22d75 (patch)
treead10b8bdb3fa4ac76a6d6e485bfb7873083eae15
parent8daa980d92a17e7bb948971b2048c7758e5dd2e6 (diff)
parente698436942c7aaf4f2872c19df2555275be169d1 (diff)
downloadotp-4e3f42da1dae7166faeb9f9e07adc40bc3b22d75.tar.gz
otp-4e3f42da1dae7166faeb9f9e07adc40bc3b22d75.tar.bz2
otp-4e3f42da1dae7166faeb9f9e07adc40bc3b22d75.zip
Merge branch 'bmk/20181004/nififying_inet_freebsd_fixes/OTP-14831' into bmk/20180918/nififying_inet/OTP-14831
-rw-r--r--erts/doc/src/socket_usage.xml2
-rw-r--r--erts/emulator/nifs/common/socket_nif.c199
-rw-r--r--erts/preloaded/ebin/socket.beambin66584 -> 66596 bytes
-rw-r--r--erts/preloaded/src/socket.erl13
-rw-r--r--lib/kernel/test/socket_SUITE.erl18
5 files changed, 210 insertions, 22 deletions
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 23d0f319f1..1ea29097c3 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -146,7 +146,7 @@
<cell>domain()</cell>
<cell>no</cell>
<cell>yes</cell>
- <cell>none</cell>
+ <cell><em>Not</em> on FreeBSD (for instance)</cell>
</row>
<row>
<cell>dontroute</cell>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index a762742cd7..0ef88162bc 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -319,8 +319,8 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
/* Debug stuff... */
-#define SOCKET_NIF_DEBUG_DEFAULT FALSE
-#define SOCKET_DEBUG_DEFAULT FALSE
+#define SOCKET_GLOBAL_DEBUG_DEFAULT FALSE
+#define SOCKET_DEBUG_DEFAULT FALSE
/* Counters and stuff (Don't know where to sent this stuff anyway) */
#define SOCKET_NIF_IOW_DEFAULT FALSE
@@ -504,6 +504,9 @@ typedef union {
#define SOCKET_OPT_OTP_RCVBUF 4
#define SOCKET_OPT_OTP_RCVCTRLBUF 6
#define SOCKET_OPT_OTP_SNDCTRLBUF 7
+#define SOCKET_OPT_OTP_DOMAIN 0xFF01 // INTERNAL AND ONLY GET
+#define SOCKET_OPT_OTP_TYPE 0xFF02 // INTERNAL AND ONLY GET
+#define SOCKET_OPT_OTP_PROTOCOL 0xFF03 // INTERNAL AND ONLY GET
#define SOCKET_OPT_SOCK_ACCEPTCONN 1
#define SOCKET_OPT_SOCK_BINDTODEVICE 3
@@ -1510,6 +1513,12 @@ static ERL_NIF_TERM ngetopt_otp_rcvctrlbuf(ErlNifEnv* env,
SocketDescriptor* descP);
static ERL_NIF_TERM ngetopt_otp_sndctrlbuf(ErlNifEnv* env,
SocketDescriptor* descP);
+static ERL_NIF_TERM ngetopt_otp_domain(ErlNifEnv* env,
+ SocketDescriptor* descP);
+static ERL_NIF_TERM ngetopt_otp_type(ErlNifEnv* env,
+ SocketDescriptor* descP);
+static ERL_NIF_TERM ngetopt_otp_protocol(ErlNifEnv* env,
+ SocketDescriptor* descP);
static ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
SocketDescriptor* descP,
int level,
@@ -3044,26 +3053,36 @@ static
ERL_NIF_TERM nconnect(ErlNifEnv* env,
SocketDescriptor* descP)
{
- int code;
+ int code, save_errno = 0;
/* Verify that we are where in the proper state */
- if (!IS_OPEN(descP))
+ if (!IS_OPEN(descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> not open\r\n") );
return esock_make_error(env, atom_exbadstate);
+ }
- if (IS_CONNECTED(descP))
+ if (IS_CONNECTED(descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> already connected\r\n") );
return esock_make_error(env, atom_eisconn);
+ }
- if (IS_CONNECTING(descP))
+ if (IS_CONNECTING(descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> already connecting\r\n") );
return esock_make_error(env, esock_atom_einval);
-
+ }
+
code = sock_connect(descP->sock,
(struct sockaddr*) &descP->remote,
descP->addrLen);
+ save_errno = sock_errno();
+
+ SSDBG( descP, ("SOCKET", "nif_sendto -> connect result: %d, %d\r\n",
+ code, save_errno) );
if (IS_SOCKET_ERROR(code) &&
- ((sock_errno() == ERRNO_BLOCK) || /* Winsock2 */
- (sock_errno() == EINPROGRESS))) { /* Unix & OSE!! */
+ ((save_errno == ERRNO_BLOCK) || /* Winsock2 */
+ (save_errno == EINPROGRESS))) { /* Unix & OSE!! */
ERL_NIF_TERM ref = MKREF(env);
descP->state = SOCKET_STATE_CONNECTING;
SELECT(env,
@@ -3078,7 +3097,7 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env,
*/
return esock_atom_ok;
} else {
- return esock_make_error_errno(env, sock_errno());
+ return esock_make_error_errno(env, save_errno);
}
}
@@ -3792,16 +3811,22 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
descP->sock, argv[0], sendRef, sndData.size, eSockAddr, eflags) );
/* THIS TEST IS NOT CORRECT!!! */
- if (!IS_OPEN(descP))
+ if (!IS_OPEN(descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> not open (%u)\r\n", descP->state) );
return esock_make_error(env, esock_atom_einval);
+ }
- if (!esendflags2sendflags(eflags, &flags))
+ if (!esendflags2sendflags(eflags, &flags)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> sendflags decode failed\r\n") );
return esock_make_error(env, esock_atom_einval);
+ }
if ((xres = esock_decode_sockaddr(env, eSockAddr,
&remoteAddr,
- &remoteAddrLen)) != NULL)
+ &remoteAddrLen)) != NULL) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> sockaddr decode: %s\r\n", xres) );
return esock_make_error_str(env, xres);
+ }
MLOCK(descP->writeMtx);
@@ -4337,8 +4362,10 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
/* if (IS_OPEN(descP)) */
/* return esock_make_error(env, atom_enotconn); */
- if (!erecvflags2recvflags(eflags, &flags))
+ if (!erecvflags2recvflags(eflags, &flags)) {
+ SSDBG( descP, ("SOCKET", "nif_recvfrom -> recvflags decode failed\r\n") );
return enif_make_badarg(env);
+ }
MLOCK(descP->readMtx);
@@ -8290,6 +8317,19 @@ ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env,
result = ngetopt_otp_sndctrlbuf(env, descP);
break;
+ /* *** INTERNAL *** */
+ case SOCKET_OPT_OTP_DOMAIN:
+ result = ngetopt_otp_domain(env, descP);
+ break;
+
+ case SOCKET_OPT_OTP_TYPE:
+ result = ngetopt_otp_type(env, descP);
+ break;
+
+ case SOCKET_OPT_OTP_PROTOCOL:
+ result = ngetopt_otp_protocol(env, descP);
+ break;
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
@@ -8377,6 +8417,124 @@ ERL_NIF_TERM ngetopt_otp_sndctrlbuf(ErlNifEnv* env,
}
+/* ngetopt_otp_domain - Handle the OTP (level) domain options.
+ */
+static
+ERL_NIF_TERM ngetopt_otp_domain(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ int val = descP->domain;
+
+ switch (val) {
+ case AF_INET:
+ result = esock_make_ok2(env, esock_atom_inet);
+ break;
+
+#if defined(HAVE_IN6) && defined(AF_INET6)
+ case AF_INET6:
+ result = esock_make_ok2(env, esock_atom_inet6);
+ break;
+#endif
+
+#if defined(HAVE_SYS_UN_H)
+ case AF_UNIX:
+ result = esock_make_ok2(env, esock_atom_local);
+ break;
+#endif
+
+ default:
+ result = esock_make_error(env,
+ MKT2(env,
+ esock_atom_unknown,
+ MKI(env, val)));
+ break;
+ }
+
+ return result;
+}
+
+
+/* ngetopt_otp_type - Handle the OTP (level) type options.
+ */
+static
+ERL_NIF_TERM ngetopt_otp_type(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ int val = descP->type;
+
+ switch (val) {
+ case SOCK_STREAM:
+ result = esock_make_ok2(env, esock_atom_stream);
+ break;
+
+ case SOCK_DGRAM:
+ result = esock_make_ok2(env, esock_atom_dgram);
+ break;
+
+#ifdef HAVE_SCTP
+ case SOCK_SEQPACKET:
+ result = esock_make_ok2(env, esock_atom_seqpacket);
+ break;
+#endif
+ case SOCK_RAW:
+ result = esock_make_ok2(env, esock_atom_raw);
+ break;
+
+ case SOCK_RDM:
+ result = esock_make_ok2(env, esock_atom_rdm);
+ break;
+
+ default:
+ result = esock_make_error(env,
+ MKT2(env, esock_atom_unknown, MKI(env, val)));
+ break;
+ }
+
+ return result;
+}
+
+
+/* ngetopt_otp_protocol - Handle the OTP (level) protocol options.
+ */
+static
+ERL_NIF_TERM ngetopt_otp_protocol(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ int val = descP->protocol;
+
+ switch (val) {
+ case IPPROTO_IP:
+ result = esock_make_ok2(env, esock_atom_ip);
+ break;
+
+ case IPPROTO_TCP:
+ result = esock_make_ok2(env, esock_atom_tcp);
+ break;
+
+ case IPPROTO_UDP:
+ result = esock_make_ok2(env, esock_atom_udp);
+ break;
+
+#if defined(HAVE_SCTP)
+ case IPPROTO_SCTP:
+ result = esock_make_ok2(env, esock_atom_sctp);
+ break;
+#endif
+
+ default:
+ result = esock_make_error(env,
+ MKT2(env, esock_atom_unknown, MKI(env, val)));
+ break;
+ }
+
+ return result;
+}
+
+
+
/* The option has *not* been encoded. Instead it has been provided
* in "native mode" (option is provided as is). In this case it will have the
* format: {NativeOpt :: integer(), ValueSize :: non_neg_integer()}
@@ -14069,6 +14227,12 @@ BOOLEAN_T esendflags2sendflags(unsigned int eflags, int* flags)
unsigned int ef;
int tmp = 0;
+ /* First, check if we have any flags at all */
+ if (eflags == 0) {
+ *flags = 0;
+ return TRUE;
+ }
+
for (ef = SOCKET_SEND_FLAG_LOW; ef <= SOCKET_SEND_FLAG_HIGH; ef++) {
switch (ef) {
@@ -14140,6 +14304,11 @@ BOOLEAN_T erecvflags2recvflags(unsigned int eflags, int* flags)
"\r\n eflags: %d"
"\r\n", eflags) );
+ if (eflags == 0) {
+ *flags = 0;
+ return TRUE;
+ }
+
for (ef = SOCKET_RECV_FLAG_LOW; ef <= SOCKET_RECV_FLAG_HIGH; ef++) {
SGDBG( ("SOCKET", "erecvflags2recvflags -> iteration"
@@ -15290,7 +15459,7 @@ BOOLEAN_T extract_debug(ErlNifEnv* env,
*/
ERL_NIF_TERM debug = MKA(env, "debug");
- return esock_extract_bool_from_map(env, map, debug, SOCKET_NIF_DEBUG_DEFAULT);
+ return esock_extract_bool_from_map(env, map, debug, SOCKET_GLOBAL_DEBUG_DEFAULT);
}
static
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index a0550990e3..9c7bcf89b5 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 8093bad885..c388fc2849 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -652,6 +652,9 @@
%%-define(SOCKET_OPT_OTP_SNDBUF, 5).
-define(SOCKET_OPT_OTP_RCVCTRLBUF, 6).
-define(SOCKET_OPT_OTP_SNDCTRLBUF, 7).
+-define(SOCKET_OPT_OTP_DOMAIN, 16#FF01). % INTERNAL
+-define(SOCKET_OPT_OTP_TYPE, 16#FF02). % INTERNAL
+-define(SOCKET_OPT_OTP_PROTOCOL, 16#FF03). % INTERNAL
%% *** SOCKET (socket) options
-define(SOCKET_OPT_SOCK_ACCEPTCONN, 1).
@@ -2159,7 +2162,7 @@ getopt(#socket{ref = SockRef}, Level, Key) ->
which_domain(SockRef) ->
case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_DOMAIN) of
+ ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_DOMAIN) of
{ok, Domain} ->
Domain;
{error, _} = ERROR ->
@@ -2173,7 +2176,7 @@ which_domain(SockRef) ->
which_type(SockRef) ->
case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_TYPE) of
+ ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_TYPE) of
{ok, Type} ->
Type;
{error, _} = ERROR ->
@@ -2186,9 +2189,9 @@ which_type(SockRef) ->
which_protocol(SockRef) ->
case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_PROTOCOL) of
- {ok, Type} ->
- Type;
+ ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_PROTOCOL) of
+ {ok, Proto} ->
+ Proto;
{error, _} = ERROR ->
throw(ERROR)
end.
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index 95b58892c1..1fff17cf8c 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -205,7 +205,15 @@ api_b_open_and_close(Domain, Type, Proto) ->
{error, Reason} ->
?FAIL({open, Reason})
end,
- {ok, Domain} = socket:getopt(Socket, socket, domain),
+ %% Domain is not available on all platforms:
+ case socket:getopt(Socket, socket, domain) of
+ {ok, Domain} ->
+ ok;
+ {error, einval} ->
+ ok;
+ Else ->
+ ?FAIL({getopt, domain, Else})
+ end,
{ok, Type} = socket:getopt(Socket, socket, type),
{ok, Proto} = socket:getopt(Socket, socket, protocol),
Self = self(),
@@ -691,6 +699,11 @@ api_to_connect_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% We use the backlog (listen) argument to test this.
+%% Note that the behaviour of the TCP "server side" can vary when
+%% a client connect to a "busy" server (full backlog).
+%% For instance, on FreeBSD (11.2) the reponse when the backlog is full
+%% is a econreset.
api_to_connect_tcp(Domain) ->
process_flag(trap_exit, true),
@@ -754,6 +767,9 @@ api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) ->
{error, timeout} ->
p("expected timeout (~w)", [ID]),
ok;
+ {error, econnreset = Reason} ->
+ p("failed connecting: ~p - giving up", [Reason]),
+ ok;
{error, Reason} ->
p("failed connecting: ~p", [Reason]),
?FAIL({recv, Reason});