summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorMicael Karlberg <bmk@erlang.org>2023-04-04 13:27:39 +0200
committerMicael Karlberg <bmk@erlang.org>2023-04-05 17:56:36 +0200
commit958832b8ccf72166c50d251d0450b1a53ef8c4d7 (patch)
treea81627b47c5a4cafc0e6e8840540530e4996d40f /erts
parent29c8e6e3067d5578245b155f1dbeb57a277278d0 (diff)
downloaderlang-958832b8ccf72166c50d251d0450b1a53ef8c4d7.tar.gz
[erts|esock] Term construction and select reset for connect
OTP-18029
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/nifs/common/socket_int.h5
-rw-r--r--erts/emulator/nifs/win32/win_socket_asyncio.c233
2 files changed, 149 insertions, 89 deletions
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h
index ab5837a9ed..2613fe5a1e 100644
--- a/erts/emulator/nifs/common/socket_int.h
+++ b/erts/emulator/nifs/common/socket_int.h
@@ -642,7 +642,10 @@ GLOBAL_ERROR_REASON_ATOM_DEFS;
#define FREE_IOVEC(IV) enif_free_iovec((IV))
/* Copy term T into environment E */
-#define CP_TERM(E, T) enif_make_copy((E), (T))
+#define CP_TERM(E, T) enif_make_copy((E), (T))
+
+#define CLEAR_ENV(E) esock_clear_env(__FUNCTION__, (E))
+#define FREE_ENV(E) esock_free_env(__FUNCTION__, (E))
#define TCREATE(NAME, TID, FUNC, ARGS, OPTS) \
enif_thread_create((NAME), (TID), (FUNC), (ARGS), (OPTS))
diff --git a/erts/emulator/nifs/win32/win_socket_asyncio.c b/erts/emulator/nifs/win32/win_socket_asyncio.c
index cfc051c06d..c9689944ca 100644
--- a/erts/emulator/nifs/win32/win_socket_asyncio.c
+++ b/erts/emulator/nifs/win32/win_socket_asyncio.c
@@ -660,6 +660,16 @@ static BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP,
ErlNifPid* opCaller,
ESAIOOpDataConnect* opDataP,
int error);
+static void esaio_completion_connect_success(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP);
+static void esaio_completion_connect_aborted(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP);
+static void esaio_completion_connect_failure(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP,
+ int error);
static void esaio_completion_connect_completed(ErlNifEnv* env,
ESockDescriptor* descP,
ESAIOOpDataConnect* opDataPP);
@@ -1803,7 +1813,6 @@ ERL_NIF_TERM connect_stream_check_result(ErlNifEnv* env,
} else {
save_errno = sock_errno();
-
tag = esock_atom_update_connect_context;
reason = ENO2T(env, save_errno);
@@ -1828,19 +1837,20 @@ ERL_NIF_TERM connect_stream_check_result(ErlNifEnv* env,
if (save_errno == WSA_IO_PENDING) {
- SSDBG( descP, ("WIN-ESAIO",
- "esaio_connect {%d} -> connect scheduled\r\n",
- descP->sock) );
+ SSDBG( descP,
+ ("WIN-ESAIO",
+ "connect_stream_check_result(%d) -> connect scheduled\r\n",
+ descP->sock) );
eres = esock_atom_completion;
} else {
- ERL_NIF_TERM ereason = MKA(env, erl_errno_id(save_errno));
+ ERL_NIF_TERM ereason = ENO2T(env, save_errno);
SSDBG( descP, ("WIN-ESAIO",
- "connect_stream_check_result {%d} -> "
- "connect attempt failed: %T (%d)\r\n",
- descP->sock, ereason, save_errno) );
+ "connect_stream_check_result(%d) -> "
+ "connect attempt failed: %T\r\n",
+ descP->sock, ereason) );
/* Clean up the connector stuff, no need for that anymore */
esock_requestor_release("connect_stream_check_result -> failure",
@@ -5539,38 +5549,17 @@ BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP,
("WIN-ESAIO", "esaio_completion_connect(%d) -> entry\r\n",
descP->sock, error) );
+ (void) opCaller;
+
switch (error) {
case NO_ERROR:
SSDBG( descP,
- ("WIN-ESAIO", "esaio_completion_connect(%d) -> no error"
+ ("WIN-ESAIO", "esaio_completion_connect(%d) -> success"
"\r\n", descP->sock) );
MLOCK(descP->writeMtx);
- if (descP->connectorP != NULL) {
- if (IS_OPEN(descP->writeState)) {
- esaio_completion_connect_completed(env, descP, opDataP);
- } else {
- /* A completed (active) request for a socket that is not open.
- * Is this even possible?
- * A race (completed just as the socket was closed).
- */
-
- /* Clean up the connector stuff, no need for that anymore */
- esock_requestor_release("esaio_completion_connect -> "
- "not active",
- env, descP, &descP->connector);
- descP->connectorP = NULL;
- descP->writeState &=
- ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+ esaio_completion_connect_success(env, descP, opDataP);
- esaio_completion_connect_not_active(descP);
- }
- } else {
- /* Connect was actually completed directly
- * (and 'connector' was therefor not initiated)
- * => Nothing to do here, other than cleanup (see below).
- */
- }
MUNLOCK(descP->writeMtx);
break;
@@ -5582,75 +5571,28 @@ BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP,
/* *** SAME MTX LOCK ORDER FOR ALL OPs *** */
MLOCK(descP->readMtx);
MLOCK(descP->writeMtx);
- /* The only thing *we* do that could cause an abort is the
- * 'CancelIoEx' call, which we do when closing the socket
- * (or cancel a request).
- * But if we have done that;
- * - Socket state will not be 'open' and
- * - we have also set closer (pid and ref).
- */
-
- if (descP->connectorP != NULL) {
-
- reason = esock_atom_closed,
-
- /* Inform the user waiting for a reply */
- esock_send_abort_msg(env, descP, opDataP->sockRef,
- descP->connectorP, reason);
- /* Clean up the connector stuff, no need for that anymore */
- esock_requestor_release("connect_stream_check_result -> abort",
- env, descP, &descP->connector);
- descP->connectorP = NULL;
- descP->writeState &=
- ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+ esaio_completion_connect_aborted(env, descP, opDataP);
- /* The socket not being open (assumed closing),
- * means we are in the closing phase...
- */
- if (! IS_OPEN(descP->writeState)) {
-
- esaio_stop(env, descP);
-
- }
- }
MUNLOCK(descP->writeMtx);
MUNLOCK(descP->readMtx);
break;
default:
- SSDBG( descP,
- ("WIN-ESAIO",
- "esaio_completion_connect(%d) -> operation unknown failure:"
- "\r\n %T"
- "\r\n", descP->sock, ENO2T(env, error)) );
- MLOCK(descP->writeMtx);
/* We do not know what this is
* but we can "assume" that the request failed so we need to
* remove it from the "queue" if its still there...
* And cleanup...
*/
- if (descP->connectorP != NULL) {
- /* Figure out the reason */
- reason = MKT2(env,
- esock_atom_get_overlapped_result,
- ENO2T(env, error));
-
- /* Inform the user waiting for a reply */
- esock_send_abort_msg(env, descP, opDataP->sockRef,
- descP->connectorP, reason);
- esaio_completion_connect_fail(env, descP, error, FALSE);
+ SSDBG( descP,
+ ("WIN-ESAIO",
+ "esaio_completion_connect(%d) -> unknown failure:"
+ "\r\n %T"
+ "\r\n", descP->sock, ENO2T(env, error)) );
+ MLOCK(descP->writeMtx);
- /* Clean up the connector stuff, no need for that anymore */
- esock_requestor_release("connect_stream_check_result -> failure",
- env, descP, &descP->connector);
- descP->connectorP = NULL;
- descP->writeState &=
- ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+ esaio_completion_connect_failure(env, descP, opDataP, error);
- } else {
- esaio_completion_connect_fail(env, descP, error, TRUE);
- }
MUNLOCK(descP->writeMtx);
break;
}
@@ -5669,6 +5611,120 @@ BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP,
+/* *** esaio_completion_connect_success ***
+ * The 'connect' operation was successful.
+ */
+static
+void esaio_completion_connect_success(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP)
+{
+ if (descP->connectorP != NULL) {
+ if (IS_OPEN(descP->writeState)) {
+ esaio_completion_connect_completed(env, descP, opDataP);
+ } else {
+ /* A completed (active) request for a socket that is not open.
+ * Is this even possible?
+ * A race (completed just as the socket was closed).
+ */
+
+ /* Clean up the connector stuff, no need for that anymore */
+ esock_requestor_release("esaio_completion_connect_success -> "
+ "not active",
+ env, descP, &descP->connector);
+ descP->connectorP = NULL;
+
+ descP->writeState &=
+ ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+
+ esaio_completion_connect_not_active(descP);
+ }
+ } else {
+ /* Connect was actually completed directly
+ * (and 'connector' was therefor not initiated)
+ * => Nothing to do here, other than cleanup.
+ */
+ descP->writeState &= ~ESOCK_STATE_SELECTED;
+ }
+}
+
+
+
+/* *** esaio_completion_connect_aborted ***
+ * The 'connect' operation was aborted.
+ * The only thing *we* do that could cause an abort is the
+ * 'CancelIoEx' call, which we do when closing the socket
+ * (or cancel a request).
+ * But if we have done that;
+ * - Socket state will not be 'open' and
+ * - we have also set closer (pid and ref).
+ */
+
+static
+void esaio_completion_connect_aborted(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP)
+{
+ if (descP->connectorP != NULL) {
+
+ ERL_NIF_TERM reason = esock_atom_closed;
+
+ /* Inform the user waiting for a reply */
+ esock_send_abort_msg(env, descP, opDataP->sockRef,
+ descP->connectorP, reason);
+
+ /* Clean up the connector stuff, no need for that anymore */
+ esock_requestor_release("connect_stream_check_result -> abort",
+ env, descP, &descP->connector);
+ descP->connectorP = NULL;
+ descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+
+ /* The socket not being open (assumed closing),
+ * means we are in the closing phase...
+ */
+ if (! IS_OPEN(descP->writeState)) {
+
+ esaio_stop(env, descP);
+
+ }
+ } else {
+ descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+ }
+}
+
+
+/* *** esaio_completion_connect_failure *
+ * A "general" failure happened while performing the 'connect' operation.
+ */
+static
+void esaio_completion_connect_failure(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESAIOOpDataConnect* opDataP,
+ int error)
+{
+ if (descP->connectorP != NULL) {
+ /* Figure out the reason */
+ ERL_NIF_TERM reason = MKT2(env,
+ esock_atom_get_overlapped_result,
+ ENO2T(env, error));
+
+ /* Inform the user waiting for a reply */
+ esock_send_abort_msg(env, descP, opDataP->sockRef,
+ descP->connectorP, reason);
+ esaio_completion_connect_fail(env, descP, error, FALSE);
+
+ /* Clean up the connector stuff, no need for that anymore */
+ esock_requestor_release("connect_stream_check_result -> failure",
+ env, descP, &descP->connector);
+ descP->connectorP = NULL;
+ descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
+
+ } else {
+ esaio_completion_connect_fail(env, descP, error, TRUE);
+ }
+}
+
+
/* *** esaio_completion_connect_completed ***
* The connect request has completed.
*/
@@ -5788,6 +5844,7 @@ void esaio_completion_connect_fail(ErlNifEnv* env,
int error,
BOOLEAN_T inform)
{
+ descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED);
esaio_completion_fail(env, descP, "connect", error, inform);
}