diff options
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/nifs/common/socket_nif.c | 104 | ||||
-rw-r--r-- | erts/emulator/test/socket_SUITE.erl | 128 |
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", |