aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2019-05-07 10:36:56 +0200
committerMicael Karlberg <[email protected]>2019-05-29 18:50:03 +0200
commit51a0daaec83e7e5794d74b7276b2d13f98ba48df (patch)
tree831a4441090fe92115188272e68be81cd7108132 /erts
parent6ede678f9e7a2ba1b15c276e0e401d7990e88c51 (diff)
downloadotp-51a0daaec83e7e5794d74b7276b2d13f98ba48df.tar.gz
otp-51a0daaec83e7e5794d74b7276b2d13f98ba48df.tar.bz2
otp-51a0daaec83e7e5794d74b7276b2d13f98ba48df.zip
[esock] Found and fixed some weirdness on darwin
Tests on Darwin Kernel Version 18.2.0 reveled some problems handling connect (on that platform). It seems that calling connect the second time is not needed (it results in eisconn), so we needed to handle that case, which we now do.
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/nifs/common/socket_nif.c104
-rw-r--r--erts/emulator/test/socket_SUITE.erl128
2 files changed, 198 insertions, 34 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 4394e7bc7c..d24edde1e0 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -4901,17 +4901,17 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env,
return esock_make_error(env, atom_closed);
if (!IS_OPEN(descP)) {
- SSDBG( descP, ("SOCKET", "nif_connect -> not open\r\n") );
+ SSDBG( descP, ("SOCKET", "nconnect -> not open\r\n") );
return esock_make_error(env, atom_exbadstate);
}
if (IS_CONNECTED(descP)) {
- SSDBG( descP, ("SOCKET", "nif_connect -> already connected\r\n") );
+ SSDBG( descP, ("SOCKET", "nconnect -> already connected\r\n") );
return esock_make_error(env, atom_eisconn);
}
if (IS_CONNECTING(descP) && !is_connector(env, descP)) {
- SSDBG( descP, ("SOCKET", "nif_connect -> already connecting\r\n") );
+ SSDBG( descP, ("SOCKET", "nconnect -> already connecting\r\n") );
return esock_make_error(env, esock_atom_einval);
}
@@ -4925,45 +4925,79 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env,
descP->addrLen);
save_errno = sock_errno();
- SSDBG( descP, ("SOCKET", "nif_connect -> connect result: %d, %d\r\n",
+ SSDBG( descP, ("SOCKET", "nconnect -> connect result: %d, %d\r\n",
code, save_errno) );
- if (IS_SOCKET_ERROR(code) &&
- ((save_errno == ERRNO_BLOCK) || /* Winsock2 */
- (save_errno == EINPROGRESS))) { /* Unix & OSE!! */
- ref = MKREF(env);
+ if (IS_SOCKET_ERROR(code)) {
+ switch (save_errno) {
+ case ERRNO_BLOCK: /* Winsock2 */
+ case EINPROGRESS: /* Unix & OSE!! */
+ SSDBG( descP, ("SOCKET", "nconnect -> would block => select\r\n") );
- if (IS_CONNECTING(descP)) {
- /* Glitch */
- res = esock_make_ok2(env, ref);
- } else {
+ ref = MKREF(env);
- /* First time here */
+ if (IS_CONNECTING(descP)) {
+ /* Glitch */
+ res = esock_make_ok2(env, ref);
+ } else {
- if (enif_self(env, &descP->connPid) == NULL)
- return esock_make_error(env, atom_exself);
+ /* First time here */
- if (MONP("nconnect -> conn",
- env, descP,
- &descP->connPid,
- &descP->connMon) != 0)
- return esock_make_error(env, atom_exmon);
-
- descP->state = SOCKET_STATE_CONNECTING;
-
- if ((sres = esock_select_write(env, descP->sock, descP, NULL,
- sockRef, ref)) < 0) {
- res = esock_make_error(env,
- MKT2(env,
- esock_atom_select_failed,
- MKI(env, sres)));
- } else {
- res = esock_make_ok2(env, ref);
+ if (enif_self(env, &descP->connPid) == NULL)
+ return esock_make_error(env, atom_exself);
+
+ if (MONP("nconnect -> conn",
+ env, descP,
+ &descP->connPid,
+ &descP->connMon) != 0)
+ return esock_make_error(env, atom_exmon);
+
+ descP->state = SOCKET_STATE_CONNECTING;
+
+ if ((sres = esock_select_write(env, descP->sock, descP, NULL,
+ sockRef, ref)) < 0) {
+ res = esock_make_error(env,
+ MKT2(env,
+ esock_atom_select_failed,
+ MKI(env, sres)));
+ } else {
+ res = esock_make_ok2(env, ref);
+ }
}
+ break;
+
+ case EISCONN:
+ SSDBG( descP, ("SOCKET", "nconnect -> *already* connected\r\n") );
+ {
+ /* This is ***strange*** so make sure */
+ int err = 0;
+ if (!verify_is_connected(descP, &err)) {
+ descP->state = SOCKET_STATE_OPEN; /* restore state */
+ res = esock_make_error_errno(env, err);
+ } else {
+ descP->state = SOCKET_STATE_CONNECTED;
+ /* And just to be on the safe side, reset these */
+ enif_set_pid_undefined(&descP->connPid);
+ DEMONP("nconnect -> connected",
+ env, descP, &descP->connMon);
+ descP->isReadable = TRUE;
+ descP->isWritable = TRUE;
+ res = esock_atom_ok;
+ }
+ }
+ break;
+
+ default:
+ SSDBG( descP, ("SOCKET", "nconnect -> other error(1): %d\r\n",
+ save_errno) );
+ res = esock_make_error_errno(env, save_errno);
+ break;
}
} else if (code == 0) { /* ok we are connected */
+ SSDBG( descP, ("SOCKET", "nconnect -> connected\r\n") );
+
descP->state = SOCKET_STATE_CONNECTED;
enif_set_pid_undefined(&descP->connPid);
DEMONP("nconnect -> connected", env, descP, &descP->connMon);
@@ -4971,7 +5005,13 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env,
descP->isWritable = TRUE;
res = esock_atom_ok;
+
} else {
+ /* Do we really need this case? */
+
+ SSDBG( descP, ("SOCKET", "nconnect -> other error(2): %d\r\n",
+ save_errno) );
+
res = esock_make_error_errno(env, save_errno);
}
@@ -16412,6 +16452,8 @@ char* encode_cmsghdr_data_ipv6(ErlNifEnv* env,
#if defined(IPV6_PKTINFO)
case IPV6_PKTINFO:
{
+ char* xres;
+
struct in6_pktinfo* pktInfoP = (struct in6_pktinfo*) dataP;
ERL_NIF_TERM ifIndex = MKI(env, pktInfoP->ipi6_ifindex);
ERL_NIF_TERM addr;
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 0c29e3288c..d3ea02f166 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -2668,8 +2668,16 @@ api_a_connect_tcp4(_Config) when is_list(_Config) ->
Connect = fun(Sock, SockAddr) ->
socket:connect(Sock, SockAddr, nowait)
end,
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
InitState = #{domain => inet,
- connect => Connect},
+ connect => Connect,
+ send => Send,
+ recv => Recv},
ok = api_a_connect_tcp(InitState)
end).
@@ -2748,6 +2756,43 @@ api_a_connect_tcp(InitState) ->
ok
end},
+ #{desc => "await continue (recv_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_req)
+ end},
+ #{desc => "recv req",
+ cmd => fun(#{csock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REQ} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+ #{desc => "await continue (send_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_rep)
+ end},
+ #{desc => "send rep",
+ cmd => fun(#{csock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REP)
+ end},
+ #{desc => "announce ready (send_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_rep),
+ ok
+ end},
+
+
%% *** Termination ***
#{desc => "await terminate",
cmd => fun(#{tester := Tester} = State) ->
@@ -2831,7 +2876,10 @@ api_a_connect_tcp(InitState) ->
connect := Connect} = State) ->
case Connect(Sock, SSA) of
ok ->
- {error, unexpected_success};
+ ?SEV_IPRINT("ok -> "
+ "unexpected success => SKIP",
+ []),
+ {skip, unexpected_success};
{select, {select_info, ST, SR}} ->
?SEV_IPRINT("select ->"
"~n tag: ~p"
@@ -2870,7 +2918,6 @@ api_a_connect_tcp(InitState) ->
cmd => fun(#{sock := Sock, server_sa := SSA, connect := Connect}) ->
case Connect(Sock, SSA) of
ok ->
- ok = socket:setopt(Sock, otp, debug, false),
ok;
{select, SelectInfo} ->
{error, {unexpected_select, SelectInfo}};
@@ -2894,6 +2941,42 @@ api_a_connect_tcp(InitState) ->
end
end},
+ #{desc => "await continue (send_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send req",
+ cmd => fun(#{sock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REQ)
+ end},
+ #{desc => "announce ready (send_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+ #{desc => "await continue (recv_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_rep)
+ end},
+ #{desc => "recv rep",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REP} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
%% *** Termination ***
#{desc => "await terminate",
cmd => fun(#{tester := Tester} = State) ->
@@ -2986,6 +3069,45 @@ api_a_connect_tcp(InitState) ->
?SEV_AWAIT_READY(Server, server, accept)
end},
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to recv test req (recv req)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_req),
+ ok
+ end},
+ #{desc => "order client to send test req (send req)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send_req)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_req)
+ end},
+ #{desc => "await server ready (recv_req)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_req)
+ end},
+ #{desc => "order client to recv test rep (send rep)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_rep),
+ ok
+ end},
+ #{desc => "order server to send test rep (send rep)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_rep),
+ ok
+ end},
+ #{desc => "await server ready (send_rep)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_rep)
+ end},
+ #{desc => "await client ready (recv_rep)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_rep)
+ end},
+
%% *** Termination ***
#{desc => "order client to terminate",