aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in9
-rw-r--r--erts/doc/src/Makefile40
-rw-r--r--erts/doc/src/alt_dist.xml5
-rw-r--r--erts/doc/src/crash_dump.xml2
-rw-r--r--erts/doc/src/driver.xml2
-rw-r--r--erts/doc/src/erl_ext_dist.xml4
-rw-r--r--erts/doc/src/erl_nif.xml7
-rw-r--r--erts/doc/src/erlang.xml19
-rw-r--r--erts/doc/src/net.xml129
-rw-r--r--erts/doc/src/notes.xml289
-rw-r--r--erts/doc/src/part.xml.src (renamed from erts/doc/src/part.xml)4
-rw-r--r--erts/doc/src/ref_man.xml.src (renamed from erts/doc/src/ref_man.xml)5
-rw-r--r--erts/doc/src/socket.xml362
-rw-r--r--erts/doc/src/socket_usage.xml82
-rw-r--r--erts/doc/src/specs.xml.src (renamed from erts/doc/src/specs.xml)3
-rw-r--r--erts/doc/src/zlib.xml2
-rw-r--r--erts/emulator/Makefile.in7
-rw-r--r--erts/emulator/beam/atom.c77
-rw-r--r--erts/emulator/beam/atom.h8
-rw-r--r--erts/emulator/beam/beam_bif_load.c72
-rw-r--r--erts/emulator/beam/beam_emu.c20
-rw-r--r--erts/emulator/beam/beam_load.c10
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/binary.c80
-rw-r--r--erts/emulator/beam/break.c5
-rw-r--r--erts/emulator/beam/bs_instrs.tab23
-rw-r--r--erts/emulator/beam/copy.c49
-rw-r--r--erts/emulator/beam/dist.c78
-rw-r--r--erts/emulator/beam/dist.h16
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_alloc_util.c69
-rw-r--r--erts/emulator/beam/erl_bif_binary.c184
-rw-r--r--erts/emulator/beam/erl_bif_info.c28
-rw-r--r--erts/emulator/beam/erl_bif_lists.c15
-rw-r--r--erts/emulator/beam/erl_bif_persistent.c99
-rw-r--r--erts/emulator/beam/erl_bif_re.c30
-rw-r--r--erts/emulator/beam/erl_bif_trace.c29
-rw-r--r--erts/emulator/beam/erl_binary.h118
-rw-r--r--erts/emulator/beam/erl_bits.c95
-rw-r--r--erts/emulator/beam/erl_bits.h18
-rw-r--r--erts/emulator/beam/erl_db.c15
-rw-r--r--erts/emulator/beam/erl_db.h4
-rw-r--r--erts/emulator/beam/erl_db_catree.c169
-rw-r--r--erts/emulator/beam/erl_db_catree.h5
-rw-r--r--erts/emulator/beam/erl_db_hash.c6
-rw-r--r--erts/emulator/beam/erl_db_hash.h3
-rw-r--r--erts/emulator/beam/erl_db_tree.c6
-rw-r--r--erts/emulator/beam/erl_db_tree.h4
-rw-r--r--erts/emulator/beam/erl_gc.c55
-rw-r--r--erts/emulator/beam/erl_message.c2
-rw-r--r--erts/emulator/beam/erl_monitor_link.c49
-rw-r--r--erts/emulator/beam/erl_monitor_link.h17
-rw-r--r--erts/emulator/beam/erl_node_tables.c247
-rw-r--r--erts/emulator/beam/erl_node_tables.h39
-rw-r--r--erts/emulator/beam/erl_printf_term.c29
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c11
-rw-r--r--erts/emulator/beam/erl_process.c143
-rw-r--r--erts/emulator/beam/erl_process.h50
-rw-r--r--erts/emulator/beam/erl_sched_spec_pre_alloc.h2
-rw-r--r--erts/emulator/beam/erl_trace.c70
-rw-r--r--erts/emulator/beam/erl_trace.h8
-rw-r--r--erts/emulator/beam/external.c59
-rw-r--r--erts/emulator/beam/external.h2
-rw-r--r--erts/emulator/beam/global.h42
-rw-r--r--erts/emulator/beam/instrs.tab17
-rw-r--r--erts/emulator/beam/ops.tab18
-rw-r--r--erts/emulator/drivers/common/inet_drv.c231
-rw-r--r--erts/emulator/hipe/hipe_arm.c26
-rw-r--r--erts/emulator/hipe/hipe_x86.h25
-rw-r--r--erts/emulator/nifs/common/prim_net_nif.c (renamed from erts/emulator/nifs/common/net_nif.c)2
-rw-r--r--erts/emulator/nifs/common/socket_dbg.c73
-rw-r--r--erts/emulator/nifs/common/socket_dbg.h4
-rw-r--r--erts/emulator/nifs/common/socket_int.h5
-rw-r--r--erts/emulator/nifs/common/socket_nif.c6907
-rw-r--r--erts/emulator/nifs/common/socket_util.c129
-rw-r--r--erts/emulator/nifs/common/socket_util.h3
-rw-r--r--erts/emulator/pcre/LICENCE10
-rw-r--r--erts/emulator/pcre/pcre-8.42.tar.bz2bin1570171 -> 0 bytes
-rw-r--r--erts/emulator/pcre/pcre-8.43.tar.bz2bin0 -> 1576584 bytes
-rw-r--r--erts/emulator/pcre/pcre.h7
-rw-r--r--erts/emulator/pcre/pcre_compile.c18
-rw-r--r--erts/emulator/pcre/pcre_exec.c115
-rw-r--r--erts/emulator/pcre/pcre_internal.h11
-rw-r--r--erts/emulator/pcre/pcre_jit_compile.c2
-rw-r--r--erts/emulator/pcre/pcre_valid_utf8.c73
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c26
-rw-r--r--erts/emulator/test/bif_SUITE.erl10
-rw-r--r--erts/emulator/test/binary_SUITE.erl17
-rw-r--r--erts/emulator/test/distribution_SUITE.erl29
-rw-r--r--erts/emulator/test/dump_SUITE.erl47
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest130
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest-client72
-rwxr-xr-xerts/emulator/test/esock_ttest/esock-ttest-server-sock30
-rw-r--r--erts/emulator/test/exception_SUITE.erl34
-rw-r--r--erts/emulator/test/fun_SUITE.erl10
-rw-r--r--erts/emulator/test/multi_load_SUITE.erl10
-rw-r--r--erts/emulator/test/net_SUITE.erl3
-rw-r--r--erts/emulator/test/node_container_SUITE.erl73
-rw-r--r--erts/emulator/test/process_SUITE.erl111
-rw-r--r--erts/emulator/test/socket_SUITE.erl12095
-rw-r--r--erts/emulator/test/socket_test_lib.erl201
-rw-r--r--erts/emulator/test/socket_test_logger.erl2
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_client.erl101
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_client_gen.erl18
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_client_socket.erl89
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_gen.erl43
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_server.erl274
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_server_gen.erl16
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_server_socket.erl15
-rw-r--r--erts/emulator/test/socket_test_ttest_tcp_socket.erl454
-rw-r--r--erts/emulator/test/system_info_SUITE.erl53
-rw-r--r--erts/etc/common/erlexec.c66
-rw-r--r--erts/etc/unix/cerl.src25
-rw-r--r--erts/etc/unix/etp-commands.in322
-rwxr-xr-xerts/etc/unix/gcov-gen-html62
-rw-r--r--erts/etc/win32/msys_tools/vc/cc.sh33
-rw-r--r--erts/lib_src/pthread/ethread.c4
-rw-r--r--erts/preloaded/ebin/atomics.beambin3292 -> 3292 bytes
-rw-r--r--erts/preloaded/ebin/counters.beambin3092 -> 3092 bytes
-rw-r--r--erts/preloaded/ebin/erl_init.beambin2312 -> 2336 bytes
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin52636 -> 52540 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2200 -> 2200 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin100196 -> 100200 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin11204 -> 10976 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_signal_handler.beambin2764 -> 2760 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin17788 -> 17760 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3268 -> 3248 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50304 -> 50208 bytes
-rw-r--r--erts/preloaded/ebin/net.beambin6140 -> 0 bytes
-rw-r--r--erts/preloaded/ebin/persistent_term.beambin1836 -> 1844 bytes
-rw-r--r--erts/preloaded/ebin/prim_buffer.beambin3596 -> 3592 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1496 -> 1496 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin28084 -> 27984 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin81012 -> 81508 bytes
-rw-r--r--erts/preloaded/ebin/prim_net.beambin0 -> 4700 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22644 -> 22436 bytes
-rw-r--r--erts/preloaded/ebin/socket.beambin70300 -> 75892 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin19716 -> 19700 bytes
-rw-r--r--erts/preloaded/src/Makefile19
-rw-r--r--erts/preloaded/src/erl_init.erl7
-rw-r--r--erts/preloaded/src/erlang.erl2
-rw-r--r--erts/preloaded/src/prim_inet.erl99
-rw-r--r--erts/preloaded/src/prim_net.erl (renamed from erts/preloaded/src/net.erl)74
-rw-r--r--erts/preloaded/src/socket.erl758
-rw-r--r--erts/test/erlexec_SUITE.erl32
-rw-r--r--erts/vsn.mk2
146 files changed, 20822 insertions, 5455 deletions
diff --git a/erts/configure.in b/erts/configure.in
index 506ce0d0fb..3a043c940d 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -676,7 +676,7 @@ elif test "X$PROFILE_INSTR_GENERATE" = "Xtrue" -a "X$PROFILE_INSTR_USE" = "Xtrue
PROFILE_COMPILER=clang
AC_MSG_RESULT([yes, using -fprofile-instr-generate])
else
- if $enable_pgo = yes; then
+ if test $enable_pgo = yes; then
AC_MSG_ERROR(cannot use PGO with this compiler)
else
AC_MSG_RESULT([no])
@@ -1362,6 +1362,13 @@ else
USE_ESOCK=no
fi
fi
+
+if test "x$USE_ESOCK" = "xyes"; then
+ if test "x$USE_ESOCK" = "xyes"; then
+ AC_CHECK_FUNCS([localtime_r strftime])
+ fi
+fi
+
AC_SUBST(USE_ESOCK)
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index bc01919da1..bb96293947 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+# Copyright Ericsson AB 1997-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -47,6 +47,20 @@ XML_REF1_FILES = epmd.xml \
run_erl.xml \
start.xml
+ifeq ($(USE_ESOCK), yes)
+XML_REF3_ESOCK_EFILES = socket.xml
+XML_CHAPTER_ESOCK_EFILES = socket_usage.xml
+ESOCK_USE_SOCKET_XML=<xi:include href="socket.xml"\/>
+ESOCK_USE_SOCKET_SPECS_XML=<xi:include href="../specs/specs_socket.xml"/>
+ESOCK_USE_SOCKET_USAGE_XML=<xi:include href="socket_usage.xml"/>
+else
+XML_REF3_ESOCK_EFILES =
+XML_CHAPTER_ESOCK_EFILES =
+ESOCK_USE_SOCKET_XML =
+ESOCK_USE_SOCKET_SPECS_XML =
+ESOCK_USE_SOCKET_USAGE_XML =
+endif
+
XML_REF3_EFILES = \
erl_prim_loader.xml \
erlang.xml \
@@ -56,8 +70,7 @@ XML_REF3_EFILES = \
atomics.xml \
counters.xml \
zlib.xml \
- socket.xml \
- net.xml
+ $(XML_REF3_ESOCK_EFILES)
XML_REF3_FILES = \
$(XML_REF3_EFILES) \
@@ -94,7 +107,7 @@ XML_CHAPTER_FILES = \
driver.xml \
absform.xml \
inet_cfg.xml \
- socket_usage.xml \
+ $(XML_CHAPTER_ESOCK_EFILES) \
erl_ext_dist.xml \
erl_dist_protocol.xml \
communication.xml \
@@ -159,7 +172,7 @@ $(HTMLDIR)/%.gif: %.gif
$(XML_FIGURE_DIR)/%.png: ../../emulator/internal_doc/figures/%.png
$(INSTALL_DATA) $< $@
-docs: figures man pdf html $(INFO_FILE)
+docs: part ref_man specs figures man pdf html $(INFO_FILE)
$(TOP_PDF_FILE): $(XML_FILES)
@@ -169,6 +182,10 @@ html: gifs $(HTML_REF_MAN_FILE)
man: $(MAN1_FILES) $(MAN3_FILES)
+ref_man: ref_man.xml
+part: part.xml
+specs: specs.xml
+
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
$(INFO_FILE): $(INFO_FILE_SRC) $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -196,6 +213,19 @@ $(SPECDIR)/specs_%.xml:
$(XMLDIR)/%.xml: ../../emulator/internal_doc/%.md $(ERL_TOP)/make/emd2exml
$(ERL_TOP)/make/emd2exml $< $@
+ref_man.xml: ref_man.xml.src
+ ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_XML%?$(ESOCK_USE_SOCKET_XML)?' \
+ $<) > $@
+
+part.xml: part.xml.src
+ ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_USAGE_XML%?$(ESOCK_USE_SOCKET_USAGE_XML)?' \
+ $<) > $@
+
+specs.xml: specs.xml.src
+ ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_SPECS_XML%?$(ESOCK_USE_SOCKET_SPECS_XML)?' \
+ $<) > $@
+
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/erts/doc/src/alt_dist.xml b/erts/doc/src/alt_dist.xml
index 7c997cae20..f72e8acd2c 100644
--- a/erts/doc/src/alt_dist.xml
+++ b/erts/doc/src/alt_dist.xml
@@ -680,7 +680,10 @@
of the distribution controller, <c>Received</c>
is received packets, <c>Sent</c> is
sent packets, and <c>PendSend</c> is
- amount of packets in queue to be sent
+ amount of data in queue to be sent
+ (typically in bytes, but <c>dist_util</c>
+ only checks whether the value is non-zero
+ to know there is data in queue)
or a <c>boolean()</c> indicating whether
there are packets in queue to be sent.
</p>
diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml
index 33d0903622..876834307a 100644
--- a/erts/doc/src/crash_dump.xml
+++ b/erts/doc/src/crash_dump.xml
@@ -289,7 +289,7 @@ Slogan: &lt;reason&gt;</pre>
<marker id="memory"></marker>
<title>Memory Information</title>
<p>Under the tag <em>=memory</em> is shown information similar
- to what can be obtainted on a living node with
+ to what can be obtained on a living node with
<seealso marker="erts:erlang#memory/0">
<c>erlang:memory()</c></seealso>.</p>
</section>
diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml
index 8f31df4cad..a873bf9931 100644
--- a/erts/doc/src/driver.xml
+++ b/erts/doc/src/driver.xml
@@ -391,7 +391,7 @@ void encode_result(ei_x_buff* x, PGresult* res, PGconn* conn)
<p>Before a driver can be called from Erlang, it must be
loaded and opened. Loading is done using the <c><![CDATA[erl_ddll]]></c>
module (the <c><![CDATA[erl_ddll]]></c> driver that loads dynamic
- driver is actually a driver itself). If loading is successfull,
+ driver is actually a driver itself). If loading is successful,
the port can be opened with <c><![CDATA[open_port/2]]></c>. The port
name must match the name of the shared library and
the name in the driver entry structure.</p>
diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml
index 3730f0e8ac..2ba5994557 100644
--- a/erts/doc/src/erl_ext_dist.xml
+++ b/erts/doc/src/erl_ext_dist.xml
@@ -128,7 +128,7 @@
are deprecated and are only kept for backward
compatibility when decoding terms encoded by older nodes.</p>
<p>Support for UTF-8 encoded atoms in the external format has been
- available since ERTS 5.10 (OTP R16). This abillity allows such old nodes
+ available since ERTS 5.10 (OTP R16). This ability allows such old nodes
to decode, store and encode any Unicode atoms received from a new OTP 20
node.</p>
<p>The maximum number of allowed characters in an atom is 255. In the
@@ -913,7 +913,7 @@
<tcaption>SMALL_BIG_EXT</tcaption></table>
<p>
Bignums are stored in unary form with a <c>Sign</c> byte,
- that is, 0 if the binum is positive and 1 if it is negative. The
+ that is, 0 if the bignum is positive and 1 if it is negative. The
digits are stored with the least significant byte stored first. To
calculate the integer, the following formula can be used:
</p>
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index f88d255296..d74ae23a93 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1495,6 +1495,9 @@ enif_free_iovec(iovec);]]></code>
<c>term</c>.</p>
<p>Returns <c>true</c> on success, or <c>false</c> if <c>term</c> is
not a handle to a resource object of type <c>type</c>.</p>
+ <p><c>enif_get_resource</c> does not add a reference to the resource
+ object. However, the pointer received in <c>*objp</c> is guaranteed to
+ be valid at least as long as the resource handle <c>term</c> is valid.</p>
</desc>
</func>
@@ -2947,6 +2950,10 @@ enif_map_iterator_destroy(env, &amp;iter);</code>
References made by <seealso marker="#enif_make_resource">
<c>enif_make_resource</c></seealso>
can only be removed by the garbage collector.</p>
+ <p>There are no guarantees exactly when the destructor of an
+ unreferenced resource is called. It could be called directly by
+ <c>enif_release_resource</c> but it could also be scheduled to be
+ called at a later time possibly by another thread.</p>
</desc>
</func>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index a879cce840..2183f75487 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -2553,6 +2553,7 @@ os_prompt%</pre>
true
> is_map_key(value,Map).
false</code>
+ <p>Allowed in guard tests.</p>
</desc>
</func>
@@ -3105,6 +3106,7 @@ false</code>
Map = #{42 => value_two,1337 => "value one","a" => 1},
map_get(Key,Map).
"value one"</code>
+ <p>Allowed in guard tests.</p>
</desc>
</func>
@@ -9412,6 +9414,18 @@ Metadata = #{ pid => pid(),
<p>Returns the previous system monitor settings just like
<seealso marker="#system_monitor/0">
<c>erlang:system_monitor/0</c></seealso>.</p>
+ <p>The arguments to <c>system_monitor/2</c> specifies how all
+ system monitoring on the node should be done, not how it should be
+ changed. This means only one process at a time
+ (<c><anno>MonitorPid</anno></c>) can be the receiver of system monitor
+ messages. Also, the way to clear a specific monitor option
+ is to not include it in the list <c><anno>Options</anno></c>. All
+ system monitoring will, however, be cleared if the process identified by
+ <c><anno>MonitorPid</anno></c> terminates.</p>
+ <p>There are no special option values (like zero) to clear an option.
+ Some of the options have a unspecified minimum value. Lower values
+ will be adjusted to the minimum value. For example, it is currently not
+ possible to monitor all garbage collections with <c>{long_gc, 0}</c>.</p>
<note>
<p>If a monitoring process gets so large that it itself
starts to cause system monitor messages when garbage
@@ -10116,6 +10130,11 @@ timestamp() ->
time stamp flags are remembered, so if two are passed
and the one with highest precedence later is disabled,
the other one becomes active.</p>
+ <p>If a match specification (applicable only for <c>call</c>, <c>send</c>
+ and <c>'receive'</c> tracing) contains a <c>{message}</c> action
+ function with a non-boolean value, that value is added as an extra
+ element to the message tuple either in the last position or before
+ the timestamp (if it is present).</p>
<p>Trace messages:</p>
<marker id="trace_3_trace_messages"></marker>
<taglist>
diff --git a/erts/doc/src/net.xml b/erts/doc/src/net.xml
deleted file mode 100644
index 6fbc37076c..0000000000
--- a/erts/doc/src/net.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2018</year><year>2018</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>net</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- <file>net.xml</file>
- </header>
- <module since="OTP 22.0">net</module>
- <modulesummary>Network interface.</modulesummary>
- <description>
- <p>This module provides an API for the network interface.</p>
- <note>
- <p>There is currently <em>no</em> support for Windows. </p>
- </note>
- </description>
-
- <datatypes>
- <datatype>
- <name name="address_info"/>
- </datatype>
- <datatype>
- <name name="name_info"/>
- </datatype>
- <datatype>
- <name name="name_info_flags"/>
- </datatype>
- <datatype>
- <name name="name_info_flag"/>
- </datatype>
- <datatype>
- <name name="name_info_flag_ext"/>
- </datatype>
- <datatype>
- <name name="network_interface_name"/>
- </datatype>
- <datatype>
- <name name="network_interface_index"/>
- </datatype>
- </datatypes>
-
- <funcs>
- <func>
- <name name="gethostname" arity="0"/>
- <fsummary>Get hostname.</fsummary>
- <desc>
- <p>Returns the name of the current host.</p>
- </desc>
- </func>
-
- <func>
- <name name="getnameinfo" arity="1" since="OTP 22.0"/>
- <name name="getnameinfo" arity="2" since="OTP 22.0"/>
- <fsummary>Address-to-name transaltion.</fsummary>
- <desc>
- <p>Address-to-name translation in a protocol-independant manner.</p>
- <p>This function is the inverse of
- <seealso marker="#getaddrinfo/1"><c>getaddrinfo</c></seealso>.
- It converts a socket address to a corresponding host and service.</p>
- </desc>
- </func>
-
- <func>
- <name name="getaddrinfo" arity="1" since="OTP 22.0"/>
- <name name="getaddrinfo" arity="2" clause_i="1" since="OTP 22.0"/>
- <name name="getaddrinfo" arity="2" clause_i="2" since="OTP 22.0"/>
- <name name="getaddrinfo" arity="2" clause_i="3" since="OTP 22.0"/>
- <fsummary>Network address and service transation.</fsummary>
- <desc>
- <p>Network address and service translation.</p>
- <p>This function is the inverse of
- <seealso marker="#getnameinfo/1"><c>getnameinfo</c></seealso>.
- It converts host and service to a corresponding socket address.</p>
- <p>One of the <c>Host</c> and <c>Service</c> may be <c>undefined</c>
- but <em>not</em> both.</p>
- </desc>
- </func>
-
- <func>
- <name name="if_name2index" arity="1" since="OTP 22.0"/>
- <fsummary>Mappings between network interface names and indexes.</fsummary>
- <desc>
- <p>Mappings between network interface names and indexes.</p>
- </desc>
- </func>
-
- <func>
- <name name="if_index2name" arity="1" since="OTP 22.0"/>
- <fsummary>Mappings between network interface index and names.</fsummary>
- <desc>
- <p>Mappings between network interface index and names.</p>
- </desc>
- </func>
-
- <func>
- <name name="if_names" arity="0" since="OTP 22.0"/>
- <fsummary>Get network interface names and indexes.</fsummary>
- <desc>
- <p>Get network interface names and indexes.</p>
- </desc>
- </func>
-
- </funcs>
-
-</erlref>
-
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index aad7e27f80..5ca387ffd8 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,132 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.4.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An invalid value test caused the socket:setopt(Socket,
+ ip, add_membership, ip_mreq()) to fail with badarg. The
+ same for drop_membership.</p>
+ <p>
+ Own Id: OTP-15908 Aux Id: ERL-980 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug causing VM crash when doing textual dump of a
+ process containing an unhandled monitor down signal.
+ Textual process dumps can be done with
+ <c>erlang:system_info(procs)</c>, trace feature
+ <c>process_dump</c>, Erlang shell break menu and a
+ crashdump. Bug exist since OTP 21.0.</p>
+ <p>
+ Own Id: OTP-15909 Aux Id: ERL-979 </p>
+ </item>
+ <item>
+ <p><c>lists:subtract/2</c> would produce incorrect
+ results for some inputs on 64-bit platforms.</p>
+ <p>
+ Own Id: OTP-15938 Aux Id: ERL-986 </p>
+ </item>
+ <item>
+ <p>Fixed a bug in the loader that was similar to
+ <c>OTP-15938</c>, yielding incorrect code for some inputs
+ on 64-bit platforms.</p>
+ <p>
+ Own Id: OTP-15939</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug causing scheduler threads in rare cases to
+ block spinnning indefinitely. Bug exists since OTP 21.0.</p>
+ <p>
+ Own Id: OTP-15941 Aux Id: PR-2313 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.4.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a buffer overflow when
+ <c>binary_to_existing_atom/2</c> and
+ <c>list_to_existing_atom/2</c> was used with the
+ <c>latin1</c> encoding.</p>
+ <p>
+ Own Id: OTP-15819 Aux Id: ERL-944 </p>
+ </item>
+ <item>
+ <p>
+ The runtime system disconnected a connection if it
+ received an <c>exit/2</c> signal where the recipient was
+ a process on an old incarnation of the current node. That
+ is, the receiving node had the same node name, but
+ another "creation" number. The signal will now just be
+ dropped since the receiving process no longer exists.</p>
+ <p>
+ Own Id: OTP-15867 Aux Id: ERIERL-373 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed <c>process_info(Pid,reductions)</c> to not
+ categorically increase reduction count of the measured
+ process <c>Pid</c>. Repeated reduction measure of an idle
+ process will most often (but not guaranteed) return the
+ same value, like it behaved before OTP 21.3.8.</p>
+ <p>
+ Own Id: OTP-15865 Aux Id: ERL-964 </p>
+ </item>
+ <item>
+ <p>Fixed an incorrect load-time optimization that could
+ cause a crash when extracting deeply nested tuple
+ elements.</p>
+ <p>
+ Own Id: OTP-15871 Aux Id: ERIERL-374 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug causing VM crash when pressing P for "proc info"
+ in Erlang shell break menu. Bug exists since OTP 22.0.</p>
+ <p>
+ Own Id: OTP-15873 Aux Id: ERL-965 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In nested use of <c>try</c>/<c>catch</c>, rethrowing
+ an exception using <c>erlang:raise/3</c> with a different
+ class would not always be able to change the class of the
+ exception.</p>
+ <p>
+ Own Id: OTP-15834 Aux Id: ERIERL-367 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -514,6 +640,152 @@
</section>
+<section><title>Erts 10.3.5.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug causing VM crash when doing textual dump of a
+ process containing an unhandled monitor down signal.
+ Textual process dumps can be done with
+ <c>erlang:system_info(procs)</c>, trace feature
+ <c>process_dump</c>, Erlang shell break menu and a
+ crashdump. Bug exist since OTP 21.0.</p>
+ <p>
+ Own Id: OTP-15909 Aux Id: ERL-979 </p>
+ </item>
+ <item>
+ <p><c>lists:subtract/2</c> would produce incorrect
+ results for some inputs on 64-bit platforms.</p>
+ <p>
+ Own Id: OTP-15938 Aux Id: ERL-986 </p>
+ </item>
+ <item>
+ <p>Fixed a bug in the loader that was similar to
+ <c>OTP-15938</c>, yielding incorrect code for some inputs
+ on 64-bit platforms.</p>
+ <p>
+ Own Id: OTP-15939</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug causing scheduler threads in rare cases to
+ block spinnning indefinitely. Bug exists since OTP 21.0.</p>
+ <p>
+ Own Id: OTP-15941 Aux Id: PR-2313 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.5.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If you set <c>{linger,{true,0}}</c> on a <c>gen_tcp</c>
+ listen socket, accept a connection on that socket, and
+ then close the accepted socket, now the linger zero
+ setting is transferred to the accepted socket. Before
+ this correction that information was lost and the close
+ behaviour on the accepted socket incorrect.</p>
+ <p>
+ Own Id: OTP-15370 Aux Id: ERIERL-353 </p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>process_info(Pid,reductions)</c> to not
+ categorically increase reduction count of the measured
+ process <c>Pid</c>. Repeated reduction measure of an idle
+ process will most often (but not guaranteed) return the
+ same value, like it behaved before OTP 21.3.8.</p>
+ <p>
+ Own Id: OTP-15865 Aux Id: ERL-964 </p>
+ </item>
+ <item>
+ <p>
+ The runtime system disconnected a connection if it
+ received an <c>exit/2</c> signal where the recipient was
+ a process on an old incarnation of the current node. That
+ is, the receiving node had the same node name, but
+ another "creation" number. The signal will now just be
+ dropped since the receiving process no longer exists.</p>
+ <p>
+ Own Id: OTP-15867 Aux Id: ERIERL-373 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The possibility to send ancillary data, in particular the
+ TOS field, has been added to <c>gen_udp:send/4,5</c>.</p>
+ <p>
+ Own Id: OTP-15747 Aux Id: ERIERL-294 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In nested use of <c>try</c>/<c>catch</c>, rethrowing
+ an exception using <c>erlang:raise/3</c> with a different
+ class would not always be able to change the class of the
+ exception.</p>
+ <p>
+ Own Id: OTP-15834 Aux Id: ERIERL-367 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>seq_trace:set_token(label,Term)</c> which
+ could cause VM crash if <c>Term</c> was heap allocated
+ (not an atom, small integer, local pid or port). Bug
+ exists since OTP 21.0 when terms other than small
+ integers were first allowed as labels.</p>
+ <p>
+ Own Id: OTP-15849 Aux Id: ERL-700 </p>
+ </item>
+ <item>
+ <p>
+ Fix <c>seq_trace:print/2</c> not to raise <c>badarg</c>
+ exception if label is not a small integer. Bug exists
+ since OTP 21.0.</p>
+ <p>
+ Own Id: OTP-15859 Aux Id: ERL-700 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a buffer overflow when
+ <c>binary_to_existing_atom/2</c> and
+ <c>list_to_existing_atom/2</c> was used with the
+ <c>latin1</c> encoding.</p>
+ <p>
+ Own Id: OTP-15819 Aux Id: ERL-944 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2523,6 +2795,23 @@
</section>
+<section><title>Erts 9.3.3.11</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a buffer overflow when
+ <c>binary_to_existing_atom/2</c> and
+ <c>list_to_existing_atom/2</c> was used with the
+ <c>latin1</c> encoding.</p>
+ <p>
+ Own Id: OTP-15819 Aux Id: ERL-944 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 9.3.3.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/doc/src/part.xml b/erts/doc/src/part.xml.src
index f0b8a00b90..9b20beffad 100644
--- a/erts/doc/src/part.xml
+++ b/erts/doc/src/part.xml.src
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2018</year>
+ <year>1996</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,7 +42,7 @@
<xi:include href="tty.xml"/>
<xi:include href="driver.xml"/>
<xi:include href="inet_cfg.xml"/>
- <xi:include href="socket_usage.xml"/>
+ %ESOCK_USE_SOCKET_USAGE_XML%
<xi:include href="erl_ext_dist.xml"/>
<xi:include href="erl_dist_protocol.xml"/>
</part>
diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml.src
index 80cdcf9145..7dd003763c 100644
--- a/erts/doc/src/ref_man.xml
+++ b/erts/doc/src/ref_man.xml.src
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2018</year>
+ <year>1996</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,10 +46,9 @@
<xi:include href="erts_alloc.xml"/>
<xi:include href="escript.xml"/>
<xi:include href="init.xml"/>
- <xi:include href="net.xml"/>
<xi:include href="persistent_term.xml"/>
<xi:include href="run_erl.xml"/>
- <xi:include href="socket.xml"/>
+ %ESOCK_USE_SOCKET_XML%
<xi:include href="start.xml"/>
<xi:include href="start_erl.xml"/>
<xi:include href="werl.xml"/>
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index 343b61d4aa..2f7ff2fc07 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -41,6 +41,40 @@
e.g. <seealso marker="#recv/3"><c>recv/3</c></seealso>,
has a timeout argument. </p>
<note>
+ <p>Some functions allow for an <i>asynchronous</i> call.
+ This is achieved by setting the <c>Timeout</c> argument to
+ <c>nowait</c>. For instance, if calling the
+ <seealso marker="#recv_async"><c>recv/3</c></seealso>
+ function with Timeout set to <c>nowait</c> (<c>recv(Sock, 0, nowait)</c>)
+ when there is actually nothing to read, it will return with
+ <c>{select, </c>
+ <seealso marker="#type-select_info"><c>SelectInfo</c></seealso><c>}</c>
+ (<c>SelectInfo</c> contains the
+ <seealso marker="socket#type-select_ref">SelectRef</seealso>).
+ When data eventually arrives a 'select' message
+ will be sent to the caller: </p>
+ <taglist>
+ <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
+ <tag></tag>
+ <item><c>{'$socket', socket(), select, SelectRef}</c></item>
+ </taglist>
+ <p>The caller can now make another
+ call to the recv function and now expect data.</p>
+ <p>Note that all other users are <em>locked out</em> until the
+ 'current user' has called the function (recv in this case).</p>
+ <p>Another message the user must be prepared for (when making asynchronous
+ calls) is the <c>abort</c> message:</p>
+ <taglist>
+ <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
+ <tag></tag>
+ <item><c>{'$socket', socket(), abort, Info}</c></item>
+ </taglist>
+ <p>This message indicates
+ that the (asynchronous) operation has been aborted.
+ If, for instance, the socket has been closed (by another process),
+ <c>Info</c> will be <c>{SelectRef, closed}</c>. </p>
+ </note>
+ <note>
<p>There is currently <em>no</em> support for Windows. </p>
<p>Support for IPv6 has been implemented but <em>not</em> tested. </p>
<p>SCTP has only been partly implemented (and not tested). </p>
@@ -65,6 +99,30 @@
</desc>
</datatype>
<datatype>
+ <name name="select_tag"/>
+ <desc>
+ <p>A tag that describes the (select) operation.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="select_ref"/>
+ <desc>
+ <p>A reference that uniquely identifies the (select) operation.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="select_info"/>
+ </datatype>
+ <datatype>
+ <name name="socket_counters"/>
+ </datatype>
+ <datatype>
+ <name name="socket_counter"/>
+ </datatype>
+ <datatype>
+ <name name="socket_info"/>
+ </datatype>
+ <datatype>
<name name="ip4_address"/>
</datatype>
<datatype>
@@ -257,7 +315,7 @@
<funcs>
<func>
<name name="accept" arity="1" since="OTP 22.0"/>
- <name name="accept" arity="2" since="OTP 22.0"/>
+ <name name="accept" arity="2" clause_i="2" since="OTP 22.0"/>
<fsummary>Accept a connection on a socket.</fsummary>
<desc>
<p>Accept a connection on a socket.</p>
@@ -269,6 +327,28 @@
</func>
<func>
+ <name name="accept" arity="2" clause_i="1" anchor="accept_async" since="OTP @OTP-15731@"/>
+ <fsummary>Accept a connection on a socket.</fsummary>
+ <desc>
+ <p>Accept a connection on a socket.</p>
+
+ <p>This call is used with connection-based socket types
+ (<c>stream</c> or <c>seqpacket</c>). It extracs the first pending
+ connection request for the listen socket and returns the (newly)
+ connected socket.</p>
+
+ <p>In the case when there is no connections waiting, the function
+ will return with the <c>SelectInfo</c>. The caller can then await a
+ select message, <c>{'$socket', Socket, select, Info}</c> (where
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
+ when a client connects (a subsequent call to accept will then return
+ the socket). </p>
+ </desc>
+ </func>
+
+ <func>
<name name="bind" arity="2" since="OTP 22.0"/>
<fsummary>Bind a name to a socket.</fsummary>
<desc>
@@ -282,6 +362,18 @@
</func>
<func>
+ <name name="cancel" arity="2" since="OTP @OTP-15731@"/>
+ <fsummary>Cancel an asynchronous request.</fsummary>
+ <desc>
+ <p>Cancel an asynchronous request.</p>
+
+ <p>Call this function in order to cancel a previous
+ asynchronous call to, e.g.
+ <seealso marker="#recv/3"><c>recv/3</c></seealso>. </p>
+ </desc>
+ </func>
+
+ <func>
<name name="close" arity="1" since="OTP 22.0"/>
<fsummary>Close a socket.</fsummary>
<desc>
@@ -302,7 +394,7 @@
<func>
<name name="connect" arity="2" since="OTP 22.0"/>
- <name name="connect" arity="3" since="OTP 22.0"/>
+ <name name="connect" arity="3" clause_i="2" since="OTP 22.0"/>
<fsummary>Initiate a connection on a socket.</fsummary>
<desc>
<p>This function connects the socket to the address
@@ -311,6 +403,26 @@
</func>
<func>
+ <name name="connect" arity="3" clause_i="1" anchor="connect_async" since="OTP @OTP-15731@"/>
+ <fsummary>Initiate a connection on a socket.</fsummary>
+ <desc>
+ <p>This function connects the socket to the address
+ specied by the <c>SockAddr</c> argument.</p>
+
+ <p>In the case when its not possible to immediately establish a
+ connection, the function will return with the
+ <seealso marker="#type-select_info"><c>SelectInfo</c></seealso>.
+ The caller can then await a
+ select message, <c>{'$socket', Socket, select, Info}</c> (where
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>,
+ a subsequent call to connect will then
+ establish the connection). </p>
+ </desc>
+ </func>
+
+ <func>
<name name="getopt" arity="3" clause_i="1" since="OTP 22.0"/>
<name name="getopt" arity="3" clause_i="2" since="OTP 22.0"/>
<name name="getopt" arity="3" clause_i="3" since="OTP 22.0"/>
@@ -359,6 +471,20 @@
</func>
<func>
+ <name name="info" arity="1" since="OTP @OTP-15818@"/>
+ <fsummary>Get miscellaneous socket info.</fsummary>
+ <desc>
+ <p>Get miscellaneous info about the socket.</p>
+ <p>The function returns a map with each info item as a key-value
+ binding. It reflects the "current" state of the socket. </p>
+ <note>
+ <p>In order to ensure data integrity, mutex'es are taken when
+ needed. So, do not call this function often. </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
<name name="listen" arity="1" since="OTP 22.0"/>
<name name="listen" arity="2" since="OTP 22.0"/>
<fsummary>Listen for connections on a socket.</fsummary>
@@ -373,19 +499,24 @@
<name name="open" arity="4" since="OTP 22.0"/>
<fsummary>Create an endpoint for communication.</fsummary>
<desc>
- <p>Creates an endpoint (socket) for communication.</p>
- <p>For some <c>types</c> there is a default protocol, which will
- be used if no protocol is specified: </p>
+ <p>Creates an endpoint (socket) for communication.</p>
- <list>
- <item><p><c>stream</c>: <c>tcp</c></p></item>
- <item><p><c>dgram</c>: <c>udp</c></p></item>
- <item><p><c>seqpacket</c>: <c>sctp</c></p></item>
- </list>
+ <p>For some <c>types</c> there is a default protocol,
+ indicated by <c>default</c>, which it <em>may</em> be
+ possible to specify.
+ And for <c>Domain = local</c>, if a protocol <em>is</em> pecified,
+ it <em>must</em> be <c>default</c>. </p>
<p>The <c>Extra</c> argument is intended for "obscure" options.
Currently the only supported option is <c>netns</c>, which
is only supported on the linux platform.</p>
+
+ <note>
+ <p>It may not be possible to specify the default protocol (except
+ when <c>Domain = local</c>). We need to be able to retreive
+ the resulting protocol, which is <em>not</em> possble on all
+ platforms. </p>
+ </note>
</desc>
</func>
@@ -401,8 +532,8 @@
<name name="recv" arity="1" since="OTP 22.0"/>
<name name="recv" arity="2" since="OTP 22.0"/>
<name name="recv" arity="3" clause_i="1" since="OTP 22.0"/>
- <name name="recv" arity="3" clause_i="2" since="OTP 22.0"/>
- <name name="recv" arity="4" since="OTP 22.0"/>
+ <name name="recv" arity="3" clause_i="3" since="OTP 22.0"/>
+ <name name="recv" arity="4" clause_i="2" since="OTP 22.0"/>
<fsummary>Receive a message from a socket.</fsummary>
<desc>
<p>Receive a message from a socket.</p>
@@ -413,36 +544,128 @@
</func>
<func>
+ <name name="recv" arity="3" clause_i="2" anchor="recv_async" since="OTP @OTP-15731@"/>
+ <name name="recv" arity="4" clause_i="1" since="OTP @OTP-15731@"/>
+ <fsummary>Receive a message from a socket.</fsummary>
+ <desc>
+ <p>Receive a message from a socket.</p>
+
+ <p>There is a special case for the argument <c>Length</c>.
+ If it is set to zero (0), it means "give me everything you
+ currently have".</p>
+
+ <p>In the case when there is no data waiting, the function
+ will return with the <c>SelectInfo</c>. The caller can then await a
+ select message, <c>{'$socket', Socket, select, Info}</c> (where
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
+ when data has arrived (a subsequent call to recv will then return
+ the data). </p>
+ <p>Note that if a length (<c>> 0</c>) is specified, and only part
+ of that amount of data is available, the function will return with
+ that data <em>and</em> the <c>SelectInfo</c> (if the caller don't
+ want to wait for the remaining data, it must immediately call
+ the <seealso marker="#cancel/2"><c>cancel/2</c></seealso> function.)</p>
+ </desc>
+ </func>
+
+ <func>
<name name="recvfrom" arity="1" since="OTP 22.0"/>
<name name="recvfrom" arity="2" since="OTP 22.0"/>
- <name name="recvfrom" arity="3" clause_i="1" since="OTP 22.0"/>
<name name="recvfrom" arity="3" clause_i="2" since="OTP 22.0"/>
<name name="recvfrom" arity="3" clause_i="3" since="OTP 22.0"/>
- <name name="recvfrom" arity="4" since="OTP 22.0"/>
+ <name name="recvfrom" arity="3" clause_i="5" since="OTP 22.0"/>
+ <name name="recvfrom" arity="4" clause_i="2" since="OTP 22.0"/>
<fsummary>Receive a message from a socket.</fsummary>
<desc>
<p>Receive a message from a socket.</p>
<p>This function reads "messages", which means that regardless of
- how much we want to read, it returns when we get a message.</p>
+ how much we want to read, it returns when we get a message
+ (if the buffer size is to small, the message will be truncated).</p>
+ <p>The <c>BufSz</c> argument basically defines the size of the
+ receive buffer. By setting the value to zero (0), the configured
+ size (setopt with <c>Level</c> = <c>otp</c> and
+ <c>Key</c> = <c>rcvbuf</c>) is used.</p>
+ <p>It may be impossible to know what (buffer) size is appropriate
+ "in advance", and in those cases it may be convenient to use the
+ (recv) 'peek' flag. When this flag is provided, the message is *not*
+ "consumed" from the underlying buffers, so another recvfrom call
+ is needed, possibly with a then adjusted buffer size.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="recvfrom" arity="3" clause_i="1" anchor="recvfrom_async" since="OTP @OTP-15731@"/>
+ <name name="recvfrom" arity="3" clause_i="4" since="OTP @OTP-15731@"/>
+ <name name="recvfrom" arity="4" clause_i="1" since="OTP @OTP-15731@"/>
+ <fsummary>Receive a message from a socket.</fsummary>
+ <desc>
+ <p>Receive a message from a socket.</p>
+ <p>This function reads "messages", which means that regardless of
+ how much we want to read, it returns when we get a message
+ (if the buffer size is to small, the message will be truncated).</p>
<p>The <c>BufSz</c> argument basically defines the size of the
receive buffer. By setting the value to zero (0), the configured
- size (setopt with <c>Level</c> = <c>otp</c> and <c>Key</c> = <c>rcvbuf</c>)
- is used.</p>
+ size (setopt with <c>Level</c> = <c>otp</c> and
+ <c>Key</c> = <c>rcvbuf</c>) is used.</p>
<p>It may be impossible to know what (buffer) size is appropriate
"in advance", and in those cases it may be convenient to use the
(recv) 'peek' flag. When this flag is provided, the message is *not*
"consumed" from the underlying buffers, so another recvfrom call
is needed, possibly with a then adjusted buffer size.</p>
+
+ <p>In the case when there is no data waiting, the function
+ will return with the <c>SelectInfo</c>. The caller can then await a
+ select message, <c>{'$socket', Socket, select, Info}</c> (where
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
+ when data has arrived (a subsequent call to recvfrom will then return
+ the data). </p>
</desc>
</func>
<func>
<name name="recvmsg" arity="1" since="OTP 22.0"/>
<name name="recvmsg" arity="2" clause_i="1" since="OTP 22.0"/>
- <name name="recvmsg" arity="2" clause_i="2" since="OTP 22.0"/>
- <name name="recvmsg" arity="3" clause_i="1" since="OTP 22.0"/>
+ <name name="recvmsg" arity="2" clause_i="3" since="OTP 22.0"/>
<name name="recvmsg" arity="3" clause_i="2" since="OTP 22.0"/>
- <name name="recvmsg" arity="5" since="OTP 22.0"/>
+ <name name="recvmsg" arity="3" clause_i="3" since="OTP 22.0"/>
+ <name name="recvmsg" arity="5" clause_i="2" since="OTP 22.0"/>
+ <fsummary>Receive a message from a socket.</fsummary>
+ <desc>
+ <p>Receive a message from a socket.</p>
+ <p>This function reads "messages", which means that regardless of
+ how much we want to read, it returns when we get a message.</p>
+ <p>The message will be delivered in the form of a <c>msghdr()</c>,
+ which may contain the source address (if socket not connected),
+ a list of <c>cmsghdr_recv()</c> (depends on what socket options have
+ been set and what the protocol and platform supports) and
+ also a set of flags, providing further info about the read. </p>
+
+ <p>The <c>BufSz</c> argument basically defines the size of the
+ receive buffer. By setting the value to zero (0), the configured
+ size (setopt with <c>Level</c> = <c>otp</c> and
+ <c>Key</c> = <c>rcvbuf</c>) is used.</p>
+
+ <p>The <c>CtrlSz</c> argument basically defines the size of the
+ receive buffer for the control messages.
+ By setting the value to zero (0), the configured size (setopt
+ with <c>Level</c> = <c>otp</c>) is used.</p>
+
+ <p>It may be impossible to know what (buffer) size is appropriate
+ "in advance", and in those cases it may be convenient to use the
+ (recv) 'peek' flag. When this flag is provided, the message is *not*
+ "consumed" from the underlying buffers, so another recvmsg call
+ is needed, possibly with a then adjusted buffer size.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="recvmsg" arity="2" clause_i="2" anchor="recvmsg_async" since="OTP @OTP-15731@"/>
+ <name name="recvmsg" arity="3" clause_i="1" since="OTP @OTP-15731@"/>
+ <name name="recvmsg" arity="5" clause_i="1" since="OTP @OTP-15731@"/>
<fsummary>Receive a message from a socket.</fsummary>
<desc>
<p>Receive a message from a socket.</p>
@@ -456,8 +679,8 @@
<p>The <c>BufSz</c> argument basically defines the size of the
receive buffer. By setting the value to zero (0), the configured
- size (setopt with <c>Level</c> = <c>otp</c> and <c>Key</c> = <c>rcvbuf</c>)
- is used.</p>
+ size (setopt with <c>Level</c> = <c>otp</c> and
+ <c>Key</c> = <c>rcvbuf</c>) is used.</p>
<p>The <c>CtrlSz</c> argument basically defines the size of the
receive buffer for the control messages.
@@ -469,25 +692,58 @@
(recv) 'peek' flag. When this flag is provided, the message is *not*
"consumed" from the underlying buffers, so another recvmsg call
is needed, possibly with a then adjusted buffer size.</p>
+
+ <p>In the case when there is no data waiting, the function
+ will return with the <c>SelectInfo</c>. The caller can then await a
+ select message, <c>{'$socket', Socket, select, Info}</c> (where
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
+ when data has arrived (a subsequent call to recvmsg will then return
+ the data). </p>
</desc>
</func>
<func>
<name name="send" arity="2" since="OTP 22.0"/>
<name name="send" arity="3" clause_i="1" since="OTP 22.0"/>
- <name name="send" arity="3" clause_i="2" since="OTP 22.0"/>
- <name name="send" arity="4" since="OTP 22.0"/>
+ <name name="send" arity="3" clause_i="3" since="OTP 22.0"/>
+ <name name="send" arity="4" clause_i="2" since="OTP 22.0"/>
+ <fsummary>Send a message on a socket.</fsummary>
+ <desc>
+ <p>Send a message on a connected socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="3" clause_i="2" anchor="send_async" since="OTP @OTP-15731@"/>
+ <name name="send" arity="4" clause_i="1" since="OTP @OTP-15731@"/>
<fsummary>Send a message on a socket.</fsummary>
<desc>
<p>Send a message on a connected socket.</p>
+
+ <p>In the case when there is no room in the (system-) buffers,
+ the function will return with the <c>SelectInfo</c>. The caller
+ can then await a select message,
+ <c>{'$socket', Socket, select, Info}</c>
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
+ <c>SelectInfo</c>), when there is room for more data (a subsequent
+ call to send will then send the data). </p>
+ <p>Note that if not all the data was sent, the function will return
+ with the remaining data <em>and</em> the <c>SelectInfo</c>
+ (if the caller don't
+ want to wait to be able to send the rest, it should immediately call
+ the <seealso marker="#cancel/2"><c>cancel/2</c></seealso> function.)</p>
</desc>
</func>
<func>
<name name="sendmsg" arity="2" since="OTP 22.0"/>
<name name="sendmsg" arity="3" clause_i="1" since="OTP 22.0"/>
- <name name="sendmsg" arity="3" clause_i="2" since="OTP 22.0"/>
- <name name="sendmsg" arity="4" since="OTP 22.0"/>
+ <name name="sendmsg" arity="3" clause_i="3" since="OTP 22.0"/>
+ <name name="sendmsg" arity="4" clause_i="2" since="OTP 22.0"/>
<fsummary>Send a message on a socket.</fsummary>
<desc>
<p>Send a message on a socket. The destination, if needed
@@ -508,10 +764,41 @@
</func>
<func>
+ <name name="sendmsg" arity="3" clause_i="2" anchor="sendmsg_async" since="OTP @OTP-15731@"/>
+ <name name="sendmsg" arity="4" clause_i="1" since="OTP @OTP-15731@"/>
+ <fsummary>Send a message on a socket.</fsummary>
+ <desc>
+ <p>Send a message on a socket. The destination, if needed
+ (socket <em>not</em> connected) is provided in the <c>MsgHdr</c>,
+ which also contains the message to send,
+ The <c>MsgHdr</c> may also contain an list of optional <c>cmsghdr_send()</c>
+ (depends on what the protocol and platform supports).</p>
+
+ <p>Unlike the <seealso marker="#send/2"><c>send</c></seealso> function,
+ this one sends <em>one message</em>.
+ This means that if, for whatever reason, its not possible to send the
+ message in one go, the function will instead return with the
+ <em>remaining</em> data (<c>{ok, Remaining}</c>). Thereby leaving it
+ up to the caller to decide what to do (retry with the remaining data
+ of give up). </p>
+
+ <p>In the case when there is no room in the (system-) buffers,
+ the function will return with the <c>SelectInfo</c>. The caller
+ can then await a select message,
+ <c>{'$socket', Socket, select, Info}</c>
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
+ <c>SelectInfo</c>), when there is room for more data (a subsequent
+ call to sendmsg will then send the data). </p>
+ </desc>
+ </func>
+
+ <func>
<name name="sendto" arity="3" since="OTP 22.0"/>
<name name="sendto" arity="4" clause_i="1" since="OTP 22.0"/>
- <name name="sendto" arity="4" clause_i="2" since="OTP 22.0"/>
- <name name="sendto" arity="5" since="OTP 22.0"/>
+ <name name="sendto" arity="4" clause_i="3" since="OTP 22.0"/>
+ <name name="sendto" arity="5" clause_i="2" since="OTP 22.0"/>
<fsummary>Send a message on a socket.</fsummary>
<desc>
<p>Send a message on a socket, to the specified destination.</p>
@@ -519,6 +806,25 @@
</func>
<func>
+ <name name="sendto" arity="4" clause_i="2" anchor="sendto_async" since="OTP @OTP-15731@"/>
+ <name name="sendto" arity="5" clause_i="1" since="OTP @OTP-15731@"/>
+ <fsummary>Send a message on a socket.</fsummary>
+ <desc>
+ <p>Send a message on a socket, to the specified destination.</p>
+
+ <p>In the case when there is no room in the (system-) buffers,
+ the function will return with the <c>SelectInfo</c>. The caller
+ can then await a select message,
+ <c>{'$socket', Socket, select, Info}</c>
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
+ <c>SelectInfo</c>), when there is room for more data (a subsequent
+ call to sendto will then send the data). </p>
+ </desc>
+ </func>
+
+ <func>
<name name="setopt" arity="4" clause_i="1" since="OTP 22.0"/>
<name name="setopt" arity="4" clause_i="2" since="OTP 22.0"/>
<name name="setopt" arity="4" clause_i="3" since="OTP 22.0"/>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index e0f006e618..c3cda9a615 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -34,11 +34,81 @@
<title>Introduction</title>
<p>The socket interface (module) is basically an "thin" layer on top of
the OS socket interface. It is assumed that, unless you have special needs,
- gen_[tcp|udp|sctp] should be sufficent. </p>
+ gen_[tcp|udp|sctp] should be sufficent (when they become available). </p>
<p>Note that just because we have a documented and described option,
it does <em>not</em> mean that the OS supports it. So its recommended
that the user reads the platform specific documentation for the
option used. </p>
+ <section>
+ <title>Asynchronous calls</title>
+ <p>Some functions allow for an <i>asynchronous</i> call
+ (<seealso marker="socket#accept_async"><c>accept/2</c></seealso>,
+ <seealso marker="socket#connect_async"><c>connect/3</c></seealso>,
+ <seealso marker="socket#recv_async"><c>recv/3,4</c></seealso>,
+ <seealso marker="socket#recvfrom_async"><c>recvfrom/3,4</c></seealso>,
+ <seealso marker="socket#recvmsg_async"><c>recvmsg/2,3,5</c></seealso>,
+ <seealso marker="socket#send_async"><c>send/3,4</c></seealso>,
+ <seealso marker="socket#sendmsg_async"><c>sendmsg/3,4</c></seealso> and
+ <seealso marker="socket#sendto_async"><c>sendto/4,5</c></seealso>).
+ This is achieved by setting the <c>Timeout</c> argument to
+ <c>nowait</c>. For instance, if calling the
+ <seealso marker="socket#recv_async"><c>recv/3</c></seealso>
+ function with Timeout set to <c>nowait</c> (i.e.
+ <c>recv(Sock, 0, nowait)</c>)
+ when there is actually nothing to read, it will return with
+ <c>{select, </c>
+ <seealso marker="socket#type-select_info"><c>SelectInfo</c></seealso><c>}</c>
+ (<c>SelectInfo</c> contains the
+ <seealso marker="socket#type-select_ref">SelectRef</seealso>).
+ When data eventually arrives a 'select message'
+ will be sent to the caller:</p>
+ <taglist>
+ <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
+ <tag></tag>
+ <item><c>{'$socket', socket(), select, SelectRef}</c></item>
+ </taglist>
+ <p>The caller can then make another
+ call to the recv function and now expect data.</p>
+ <p>The user must also be prepared to receive an abort message: </p>
+ <taglist>
+ <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
+ <tag></tag>
+ <item><c>{'$socket', socket(), abort, Info}</c></item>
+ </taglist>
+ <p>If the operation is aborted
+ for whatever reason (e.g. if the socket is closed "by someone else").
+ The <c>Info</c> part contains the abort reason (in this case that
+ the socket has been closed <c>Info = {SelectRef, closed}</c>). </p>
+ <p>Note that all other users are <em>locked out</em> until the
+ 'current user' has called the function (recv in this case). So either
+ immediately call the function or
+ <seealso marker="socket#cancel/2"><c>cancel</c></seealso>. </p>
+
+ <p>The general form of the 'socket' message is: </p>
+ <taglist>
+ <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
+ <tag></tag>
+ <item><c>{'$socket', Sock :: socket(), Tag :: atom(), Info :: term()}</c></item>
+ </taglist>
+ <p>Where the format of <c>Info</c> is a function of <c>Tag</c>:</p>
+ <table>
+ <row>
+ <cell><em>Tag</em></cell>
+ <cell><em>Info value type</em></cell>
+ </row>
+ <row>
+ <cell>select</cell>
+ <cell>select_ref()</cell>
+ </row>
+ <row>
+ <cell>abort</cell>
+ <cell>{select_ref(), Reason :: term()}</cell>
+ </row>
+ <tcaption>socket message info value type</tcaption>
+ </table>
+ <p>The <c>select_ref()</c> is the same as was received in the
+ <seealso marker="socket#type-select_info"><c>SelectInfo</c></seealso>. </p>
+ </section>
</section>
<section>
@@ -124,7 +194,7 @@
<cell><em>Other Requirements and comments</em></cell>
</row>
<row>
- <cell>acceptcon</cell>
+ <cell>acceptconn</cell>
<cell>boolean()</cell>
<cell>no</cell>
<cell>yes</cell>
@@ -135,7 +205,9 @@
<cell>string()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>none</cell>
+ <cell>Before Linux 3.8, this socket option could be set, but not get.
+ Only works for some socket types (e.g. <c>inet</c>).
+ If empty value is set, the binding is removed.</cell>
</row>
<row>
<cell>broadcast</cell>
@@ -149,7 +221,7 @@
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>requires admin capability</cell>
+ <cell>may require admin capability</cell>
</row>
<row>
<cell>domain</cell>
@@ -205,7 +277,7 @@
<cell>protocol()</cell>
<cell>no</cell>
<cell>yes</cell>
- <cell>none</cell>
+ <cell><em>Not</em> on (some) Darwin (for instance)</cell>
</row>
<row>
<cell>rcvbuf</cell>
diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml.src
index 68fab5edf1..54224c15f5 100644
--- a/erts/doc/src/specs.xml
+++ b/erts/doc/src/specs.xml.src
@@ -5,8 +5,7 @@
<xi:include href="../specs/specs_erl_tracer.xml"/>
<xi:include href="../specs/specs_init.xml"/>
<xi:include href="../specs/specs_persistent_term.xml"/>
- <xi:include href="../specs/specs_socket.xml"/>
- <xi:include href="../specs/specs_net.xml"/>
+ %ESOCK_USE_SOCKET_SPECS_XML%
<xi:include href="../specs/specs_zlib.xml"/>
<xi:include href="../specs/specs_atomics.xml"/>
<xi:include href="../specs/specs_counters.xml"/>
diff --git a/erts/doc/src/zlib.xml b/erts/doc/src/zlib.xml
index 38229456c9..8a580c8d7b 100644
--- a/erts/doc/src/zlib.xml
+++ b/erts/doc/src/zlib.xml
@@ -411,7 +411,7 @@ list_to_binary([B1,B2])</pre>
<func>
<name name="deflateParams" arity="3" since=""/>
- <fsummary>Dynamicly update deflate parameters.</fsummary>
+ <fsummary>Dynamically update deflate parameters.</fsummary>
<desc>
<p>Dynamically updates the compression level and compression
strategy. The interpretation of <c><anno>Level</anno></c> and
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index a9f3bb8e89..ba5ba8abef 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -636,10 +636,9 @@ GENERATE += $(TTF_DIR)/driver_tab.c
ifeq ($(USE_ESOCK), yes)
ESOCK_PRELOAD_BEAM = \
$(ERL_TOP)/erts/preloaded/ebin/socket.beam \
- $(ERL_TOP)/erts/preloaded/ebin/net.beam
+ $(ERL_TOP)/erts/preloaded/ebin/prim_net.beam
else
-ESOCK_PRELOAD_BEAM = \
- $(ERL_TOP)/erts/preloaded/ebin/net.beam
+ESOCK_PRELOAD_BEAM =
endif
PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \
@@ -850,7 +849,7 @@ ifeq ($(USE_ESOCK), yes)
ESOCK_NIF_OBJS = \
$(OBJDIR)/socket_nif.o \
- $(OBJDIR)/net_nif.o
+ $(OBJDIR)/prim_net_nif.o
ifneq ($(TARGET), win32)
# These are *currently* only needed for non-win32,
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index 59b51fd15e..5a70509ffd 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -200,11 +200,15 @@ atom_free(Atom* obj)
ASSERT(obj->slot.index == atom_val(am_ErtsSecretAtom));
}
-static void latin1_to_utf8(byte* conv_buf, const byte** srcp, int* lenp)
+static void latin1_to_utf8(byte* conv_buf, Uint buf_sz,
+ const byte** srcp, Uint* lenp)
{
byte* dst;
const byte* src = *srcp;
- int i, len = *lenp;
+ Uint i, len = *lenp;
+
+ ASSERT(len <= MAX_ATOM_CHARACTERS);
+ ASSERT(buf_sz >= MAX_ATOM_SZ_FROM_LATIN1);
for (i=0 ; i < len; ++i) {
if (src[i] & 0x80) {
@@ -234,11 +238,11 @@ need_convertion:
* erts_atom_put_index() may fail. Returns negative indexes for errors.
*/
int
-erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
+erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc)
{
byte utf8_copy[MAX_ATOM_SZ_FROM_LATIN1];
const byte *text = name;
- int tlen = len;
+ Uint tlen;
Sint no_latin1_chars;
Atom a;
int aix;
@@ -247,13 +251,16 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
erts_atomic_inc_nob(&atom_put_ops);
#endif
- if (tlen < 0) {
- if (trunc)
- tlen = 0;
- else
- return ATOM_MAX_CHARS_ERROR;
+ if (len < 0) {
+ if (trunc) {
+ len = 0;
+ } else {
+ return ATOM_MAX_CHARS_ERROR;
+ }
}
+ tlen = len;
+
switch (enc) {
case ERTS_ATOM_ENC_7BIT_ASCII:
if (tlen > MAX_ATOM_CHARACTERS) {
@@ -277,7 +284,7 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
return ATOM_MAX_CHARS_ERROR;
}
no_latin1_chars = tlen;
- latin1_to_utf8(utf8_copy, &text, &tlen);
+ latin1_to_utf8(utf8_copy, sizeof(utf8_copy), &text, &tlen);
break;
case ERTS_ATOM_ENC_UTF8:
/* First sanity check; need to verify later */
@@ -338,7 +345,7 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
* erts_atom_put() may fail. If it fails THE_NON_VALUE is returned!
*/
Eterm
-erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
+erts_atom_put(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc)
{
int aix = erts_atom_put_index(name, len, enc, trunc);
if (aix >= 0)
@@ -348,7 +355,7 @@ erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
}
Eterm
-am_atom_put(const char* name, int len)
+am_atom_put(const char* name, Sint len)
{
/* Assumes 7-bit ascii; use erts_atom_put() for other encodings... */
return erts_atom_put((byte *) name, len, ERTS_ATOM_ENC_7BIT_ASCII, 1);
@@ -379,23 +386,57 @@ int atom_table_sz(void)
}
int
-erts_atom_get(const char *name, int len, Eterm* ap, ErtsAtomEncoding enc)
+erts_atom_get(const char *name, Uint len, Eterm* ap, ErtsAtomEncoding enc)
{
byte utf8_copy[MAX_ATOM_SZ_FROM_LATIN1];
Atom a;
int i;
int res;
- a.len = (Sint16) len;
- a.name = (byte *)name;
- if (enc == ERTS_ATOM_ENC_LATIN1) {
- latin1_to_utf8(utf8_copy, (const byte**)&a.name, &len);
- a.len = (Sint16) len;
+ switch (enc) {
+ case ERTS_ATOM_ENC_LATIN1:
+ if (len > MAX_ATOM_CHARACTERS) {
+ return 0;
+ }
+
+ latin1_to_utf8(utf8_copy, sizeof(utf8_copy), (const byte**)&name, &len);
+
+ a.name = (byte*)name;
+ a.len = (Sint16)len;
+ break;
+ case ERTS_ATOM_ENC_7BIT_ASCII:
+ if (len > MAX_ATOM_CHARACTERS) {
+ return 0;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (name[i] & 0x80) {
+ return 0;
+ }
+ }
+
+ a.len = (Sint16)len;
+ a.name = (byte*)name;
+ break;
+ case ERTS_ATOM_ENC_UTF8:
+ if (len > MAX_ATOM_SZ_LIMIT) {
+ return 0;
+ }
+
+ /* We don't need to check whether the encoding is legal as all atom
+ * names are stored as UTF-8 and we know a lookup with a badly encoded
+ * name will fail. */
+
+ a.len = (Sint16)len;
+ a.name = (byte*)name;
+ break;
}
+
atom_read_lock();
i = index_get(&erts_atom_table, (void*) &a);
res = i < 0 ? 0 : (*ap = make_atom(i), 1);
atom_read_unlock();
+
return res;
}
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index ca920679c6..f51c5a8c62 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -133,14 +133,14 @@ typedef enum {
int atom_table_size(void); /* number of elements */
int atom_table_sz(void); /* table size in bytes, excluding stored objects */
-Eterm am_atom_put(const char*, int); /* ONLY 7-bit ascii! */
-Eterm erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc);
-int erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc);
+Eterm am_atom_put(const char*, Sint); /* ONLY 7-bit ascii! */
+Eterm erts_atom_put(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc);
+int erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc);
void init_atom_table(void);
void atom_info(fmtfn_t, void *);
void dump_atoms(fmtfn_t, void *);
Uint erts_get_atom_limit(void);
-int erts_atom_get(const char* name, int len, Eterm* ap, ErtsAtomEncoding enc);
+int erts_atom_get(const char* name, Uint len, Eterm* ap, ErtsAtomEncoding enc);
void erts_atom_get_text_space_sizes(Uint *reserved, Uint *used);
#endif
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index bb1b2e5b27..4c8ee5178a 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1799,6 +1799,78 @@ erts_queue_release_literals(Process* c_p, ErtsLiteralArea* literals)
}
}
+struct debug_la_oh {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_later_cleanup_literal_area_off_heap(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vlrlap)
+{
+ struct debug_la_oh *fap = vfap;
+ ErtsLaterReleasLiteralArea *lrlap = vlrlap;
+ ErtsLiteralArea *lap = lrlap->la;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*fap->func)(&oh, fap->arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+}
+
+static void debug_later_complete_literal_area_switch_off_heap(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vlap)
+{
+ struct debug_la_oh *fap = vfap;
+ ErtsLiteralArea *lap = vlap;
+ if (lap && !erts_debug_have_accessed_literal_area(lap)) {
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*fap->func)(&oh, fap->arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+}
+
+
+void
+erts_debug_foreach_release_literal_area_off_heap(void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ ErtsLiteralArea *lap;
+ ErlOffHeap oh;
+ ErtsLiteralAreaRef *ref;
+ struct debug_la_oh fa;
+ erts_mtx_lock(&release_literal_areas.mtx);
+ for (ref = release_literal_areas.first; ref; ref = ref->next) {
+ lap = ref->literal_area;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ }
+ erts_mtx_unlock(&release_literal_areas.mtx);
+ lap = ERTS_COPY_LITERAL_AREA();
+ if (lap && !erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(later_release_literal_area,
+ debug_later_cleanup_literal_area_off_heap,
+ (void *) &fa);
+ erts_debug_later_op_foreach(complete_literal_area_switch,
+ debug_later_complete_literal_area_switch_off_heap,
+ (void *) &fa);
+}
+
/*
* Move code from current to old and null all export entries for the module
*/
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index bae64afb97..07c16e3415 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -414,6 +414,7 @@ static Eterm add_stacktrace(Process* c_p, Eterm Value, Eterm exc);
static void save_stacktrace(Process* c_p, BeamInstr* pc, Eterm* reg,
ErtsCodeMFA *bif_mfa, Eterm args);
static struct StackTrace * get_trace_from_exc(Eterm exc);
+static Eterm *get_freason_ptr_from_exc(Eterm exc);
static Eterm make_arglist(Process* c_p, Eterm* reg, int a);
void
@@ -1902,6 +1903,25 @@ static int is_raised_exc(Eterm exc) {
}
}
+static Eterm *get_freason_ptr_from_exc(Eterm exc) {
+ static Eterm dummy_freason;
+ struct StackTrace* s;
+
+ if (exc == NIL) {
+ /*
+ * Is is not exactly clear when exc can be NIL. Probably only
+ * when the exception has been generated from native code.
+ * Return a pointer to an Eterm that can be safely written and
+ * ignored.
+ */
+ return &dummy_freason;
+ } else {
+ ASSERT(is_list(exc));
+ s = (struct StackTrace *) big_val(CDR(list_val(exc)));
+ return &s->freason;
+ }
+}
+
/*
* Creating a list with the argument registers
*/
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 941c3ebbbe..35f2ea6688 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -4612,7 +4612,15 @@ typedef struct SortGenOpArg {
static int
genopargtermcompare(SortGenOpArg* a, SortGenOpArg* b)
{
- return CMP_TERM(a->term, b->term);
+ Sint res = CMP_TERM(a->term, b->term);
+
+ if (res < 0) {
+ return -1;
+ } else if (res > 0) {
+ return 1;
+ }
+
+ return 0;
}
static int
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index db9c258cb7..602db106b1 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -413,6 +413,7 @@ bif re:compile/1
bif re:compile/2
bif re:run/2
bif re:run/3
+bif re:internal_run/4
#
# Bifs in lists module.
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index a18228b84a..4ddf59092a 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -1153,51 +1153,47 @@ BIF_RETTYPE list_to_bitstring_1(BIF_ALIST_1)
BIF_RETTYPE split_binary_2(BIF_ALIST_2)
{
- Uint pos;
- ErlSubBin* sb1;
- ErlSubBin* sb2;
- size_t orig_size;
- Eterm orig;
- Uint offset;
- Uint bit_offset;
- Uint bit_size;
- Eterm* hp;
+ size_t orig_size, left_size, right_size;
+ Uint byte_offset, bit_offset, bit_size;
+ Uint split_at;
+
+ Eterm *hp, *hp_end;
+ Eterm left, right;
+ Eterm real_bin;
+ Eterm result;
+ byte *bptr;
if (is_not_binary(BIF_ARG_1)) {
- goto error;
- }
- if (!term_to_Uint(BIF_ARG_2, &pos)) {
- goto error;
- }
- if ((orig_size = binary_size(BIF_ARG_1)) < pos) {
- goto error;
+ BIF_ERROR(BIF_P, BADARG);
+ } else if (!term_to_Uint(BIF_ARG_2, &split_at)) {
+ BIF_ERROR(BIF_P, BADARG);
+ } else if ((orig_size = binary_size(BIF_ARG_1)) < split_at) {
+ BIF_ERROR(BIF_P, BADARG);
}
- hp = HAlloc(BIF_P, 2*ERL_SUB_BIN_SIZE+3);
- ERTS_GET_REAL_BIN(BIF_ARG_1, orig, offset, bit_offset, bit_size);
- sb1 = (ErlSubBin *) hp;
- sb1->thing_word = HEADER_SUB_BIN;
- sb1->size = pos;
- sb1->offs = offset;
- sb1->orig = orig;
- sb1->bitoffs = bit_offset;
- sb1->bitsize = 0;
- sb1->is_writable = 0;
- hp += ERL_SUB_BIN_SIZE;
-
- sb2 = (ErlSubBin *) hp;
- sb2->thing_word = HEADER_SUB_BIN;
- sb2->size = orig_size - pos;
- sb2->offs = offset + pos;
- sb2->orig = orig;
- sb2->bitoffs = bit_offset;
- sb2->bitsize = bit_size; /* The extra bits go into the second binary. */
- sb2->is_writable = 0;
- hp += ERL_SUB_BIN_SIZE;
-
- return TUPLE2(hp, make_binary(sb1), make_binary(sb2));
-
- error:
- BIF_ERROR(BIF_P, BADARG);
+
+ left_size = split_at;
+ right_size = orig_size - split_at;
+
+ ERTS_GET_REAL_BIN(BIF_ARG_1, real_bin, byte_offset, bit_offset, bit_size);
+ bptr = binary_bytes(real_bin);
+
+ hp = HAlloc(BIF_P, EXTRACT_SUB_BIN_HEAP_NEED * 2 + 3);
+ hp_end = hp + (EXTRACT_SUB_BIN_HEAP_NEED * 2 + 3);
+
+ left = erts_extract_sub_binary(&hp, real_bin, bptr,
+ byte_offset * 8 + bit_offset,
+ left_size * 8);
+
+ right = erts_extract_sub_binary(&hp, real_bin, bptr,
+ (byte_offset + split_at) * 8 + bit_offset,
+ right_size * 8 + bit_size);
+
+ result = TUPLE2(hp, left, right);
+ hp += 3;
+
+ HRelease(BIF_P, hp_end, hp);
+
+ return result;
}
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 80e871aaf6..6379e4e04d 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -84,8 +84,9 @@ process_info(fmtfn_t to, void *to_arg)
* they are most likely just created and has invalid data
*/
if (p->heap != NULL) {
- ErtsProcLocks locks = (p == esdp->current_process ||
- p == esdp->free_process) ? ERTS_PROC_LOCK_MAIN : 0;
+ ErtsProcLocks locks = ((esdp && (p == esdp->current_process ||
+ p == esdp->free_process))
+ ? ERTS_PROC_LOCK_MAIN : 0);
print_process_info(to, to_arg, p, locks);
}
}
diff --git a/erts/emulator/beam/bs_instrs.tab b/erts/emulator/beam/bs_instrs.tab
index bd1ad91e45..5f25bc2ad3 100644
--- a/erts/emulator/beam/bs_instrs.tab
+++ b/erts/emulator/beam/bs_instrs.tab
@@ -149,7 +149,7 @@ i_bs_get_binary_all2.execute(Fail, Live, Unit, Dst) {
ErlBinMatchBuffer *_mb;
Eterm _result;
- $GC_TEST_PRESERVE(ERL_SUB_BIN_SIZE, $Live, context);
+ $GC_TEST_PRESERVE(EXTRACT_SUB_BIN_HEAP_NEED, $Live, context);
_mb = ms_matchbuffer(context);
if (((_mb->size - _mb->offset) % $Unit) == 0) {
LIGHT_SWAPOUT;
@@ -179,7 +179,7 @@ i_bs_get_binary2.execute(Fail, Live, Sz, Flags, Dst) {
Eterm _result;
Uint _size;
$BS_GET_FIELD_SIZE($Sz, (($Flags) >> 3), $FAIL($Fail), _size);
- $GC_TEST_PRESERVE(ERL_SUB_BIN_SIZE, $Live, context);
+ $GC_TEST_PRESERVE(EXTRACT_SUB_BIN_HEAP_NEED, $Live, context);
_mb = ms_matchbuffer(context);
LIGHT_SWAPOUT;
_result = erts_bs_get_binary_2(c_p, _size, $Flags, _mb);
@@ -206,8 +206,7 @@ i_bs_get_binary_imm2.fetch(Ctx) {
i_bs_get_binary_imm2.execute(Fail, Live, Sz, Flags, Dst) {
ErlBinMatchBuffer *_mb;
Eterm _result;
- $GC_TEST_PRESERVE(heap_bin_size(ERL_ONHEAP_BIN_LIMIT),
- $Live, context);
+ $GC_TEST_PRESERVE(EXTRACT_SUB_BIN_HEAP_NEED, $Live, context);
_mb = ms_matchbuffer(context);
LIGHT_SWAPOUT;
_result = erts_bs_get_binary_2(c_p, $Sz, $Flags, _mb);
@@ -876,9 +875,7 @@ bs_start_match.execute(Fail, Live, Slots, Dst) {
result = erts_bs_start_match_2(c_p, context, slots);
HTOP = HEAP_TOP(c_p);
HEAP_SPACE_VERIFIED(0);
- if (is_non_value(result)) {
- $FAIL($Fail);
- }
+
$REFRESH_GEN_DEST();
$Dst = result;
} else {
@@ -1296,10 +1293,6 @@ i_bs_start_match3_gp.execute(Live, Fail, Dst, Pos) {
HTOP = HEAP_TOP(c_p);
HEAP_SPACE_VERIFIED(0);
- if (ms == NULL) {
- $FAIL($Fail);
- }
-
$REFRESH_GEN_DEST();
$Dst = make_matchstate(ms);
position = ms->mb.offset;
@@ -1348,10 +1341,6 @@ i_bs_start_match3.execute(Live, Fail, Dst) {
HTOP = HEAP_TOP(c_p);
HEAP_SPACE_VERIFIED(0);
- if (ms == NULL) {
- $FAIL($Fail);
- }
-
$REFRESH_GEN_DEST();
$Dst = make_matchstate(ms);
} else {
@@ -1523,10 +1512,6 @@ i_bs_start_match3.execute(Live, Fail, Dst) {
HTOP = HEAP_TOP(c_p);
HEAP_SPACE_VERIFIED(0);
- if (is_non_value(result)) {
- $FAIL($Fail);
- }
-
$REFRESH_GEN_DEST();
$Dst = result;
} else {
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index db74b06cc5..9bbcba6f3b 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -604,7 +604,12 @@ cleanup:
/*
* Copy a structure to a heap.
*/
-Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint *bsz, erts_literal_area_t *litopt)
+Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap,
+ Uint *bsz, erts_literal_area_t *litopt
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
{
char* hstart;
Uint hsize;
@@ -854,7 +859,11 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint
case EXTERNAL_REF_SUBTAG:
{
ExternalThing *etp = (ExternalThing *) objp;
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(htop), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(htop));
+#endif
}
L_off_heap_node_container_common:
{
@@ -1326,8 +1335,13 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info)
* Copy object "obj" preserving sharing.
* Second half: copy and restore the object.
*/
-Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
- Eterm** hpp, ErlOffHeap* off_heap) {
+Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info,
+ Eterm** hpp, ErlOffHeap* off_heap
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
+{
Uint e;
unsigned sz;
Eterm* ptr;
@@ -1393,7 +1407,11 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
*resp = obj;
} else {
Uint bsz = 0;
- *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL); /* copy literal */
+ *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , file, line
+#endif
+ ); /* copy literal */
hbot -= bsz;
}
goto cleanup_next;
@@ -1461,7 +1479,11 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
*resp = obj;
} else {
Uint bsz = 0;
- *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL); /* copy literal */
+ *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , file, line
+#endif
+ ); /* copy literal */
hbot -= bsz;
}
goto cleanup_next;
@@ -1660,7 +1682,12 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
case EXTERNAL_REF_SUBTAG:
{
ExternalThing *etp = (ExternalThing *) ptr;
+
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(hp), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(hp));
+#endif
}
off_heap_node_container_common:
{
@@ -1823,8 +1850,12 @@ all_clean:
*
* NOTE: Assumes that term is a tuple (ptr is an untagged tuple ptr).
*/
-Eterm copy_shallow(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp,
- ErlOffHeap* off_heap)
+Eterm
+copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
{
Eterm* tp = ptr;
Eterm* hp = *hpp;
@@ -1866,7 +1897,11 @@ Eterm copy_shallow(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp,
case EXTERNAL_REF_SUBTAG:
{
ExternalThing* etp = (ExternalThing *) (tp-1);
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(hp-1), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(hp-1));
+#endif
}
off_heap_common:
{
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index ff19ef018e..eb9e749a08 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -80,7 +80,7 @@ dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz)
byte *extp = edep->data->extp;
Eterm msg;
Sint ctl_len;
- Sint size = ctl_len = erts_decode_dist_ext_size(edep, 0);
+ Sint size = ctl_len = erts_decode_dist_ext_size(edep, 0, 0);
if (size < 0) {
erts_fprintf(dbg_file,
"DIST MSG DEBUG: erts_decode_dist_ext_size(%s) failed:\n",
@@ -1266,18 +1266,6 @@ erts_dsig_send_group_leader(ErtsDSigSendContext *ctx, Eterm leader, Eterm remote
return dsig_send_ctl(ctx, ctl);
}
-struct dist_sequences {
- ErlHeapFragment hfrag;
- struct dist_sequences *parent;
- struct dist_sequences *left;
- struct dist_sequences *right;
- char is_red;
-
- Uint64 seq_id;
- int cnt;
- Sint ctl_len;
-};
-
#define ERTS_RBT_PREFIX dist_seq
#define ERTS_RBT_T DistSeqNode
#define ERTS_RBT_KEY_T Uint
@@ -1312,25 +1300,25 @@ struct dist_sequences {
#include "erl_rbtree.h"
-struct erts_dist_seq_tree_foreach_iter_arg {
- int (*func)(ErtsDistExternal *, void *, Sint);
+struct erts_debug_dist_seq_tree_foreach_iter_arg {
+ int (*func)(DistSeqNode *, void *, Sint);
void *arg;
};
static int
-erts_dist_seq_tree_foreach_iter(DistSeqNode *seq, void *arg, Sint reds)
+erts_debug_dist_seq_tree_foreach_iter(DistSeqNode *seq, void *arg, Sint reds)
{
- struct erts_dist_seq_tree_foreach_iter_arg *state = arg;
- return state->func(erts_get_dist_ext(&seq->hfrag), state->arg, reds);
+ struct erts_debug_dist_seq_tree_foreach_iter_arg *state = arg;
+ return state->func(seq, state->arg, reds);
}
void
-erts_dist_seq_tree_foreach(DistEntry *dep, int (*func)(ErtsDistExternal *, void *, Sint), void *arg)
+erts_debug_dist_seq_tree_foreach(DistEntry *dep, int (*func)(DistSeqNode *, void *, Sint), void *arg)
{
- struct erts_dist_seq_tree_foreach_iter_arg state;
+ struct erts_debug_dist_seq_tree_foreach_iter_arg state;
state.func = func;
state.arg = arg;
- dist_seq_rbt_foreach(dep->sequences, erts_dist_seq_tree_foreach_iter, &state);
+ dist_seq_rbt_foreach(dep->sequences, erts_debug_dist_seq_tree_foreach_iter, &state);
}
static int dist_seq_cleanup(DistSeqNode *seq, void *unused, Sint reds)
@@ -1462,7 +1450,7 @@ int erts_net_message(Port *prt,
#endif
goto data_error;
case ERTS_PREP_DIST_EXT_SUCCESS:
- ctl_len = erts_decode_dist_ext_size(&ede, 1);
+ ctl_len = erts_decode_dist_ext_size(&ede, 1, 0);
if (ctl_len < 0) {
#ifdef ERTS_DIST_MSG_DBG
erts_fprintf(dbg_file, "DIST MSG DEBUG: erts_decode_dist_ext_size(CTL) failed:\n");
@@ -1543,39 +1531,6 @@ int erts_net_message(Port *prt,
edep = erts_get_dist_ext(&seq->hfrag);
ede_hfrag = &seq->hfrag;
- /* If the sequence consisted of more than 1 fragment we create one large
- binary out of all of the fragments. This because erts_decode_ext
- cannot handle a segmented buffer.
- TODO: Move this copy to as late as possible, preferably in in the
- erts_decode_dist_ext in the receiving process.
- */
- if (edep->data->frag_id > 1) {
- Uint sz = 0;
- Binary *bin;
- int i;
- byte *ep;
-
- for (i = 0; i < edep->data->frag_id; i++)
- sz += edep->data[i].ext_endp - edep->data[i].extp;
-
- bin = erts_bin_nrml_alloc(sz);
- ep = (byte*)bin->orig_bytes;
-
- for (i = 0; i < edep->data->frag_id; i++) {
- sys_memcpy(ep, edep->data[i].extp, edep->data[i].ext_endp - edep->data[i].extp);
- ep += edep->data[i].ext_endp - edep->data[i].extp;
- erts_bin_release(edep->data[i].binp);
- edep->data[i].binp = NULL;
- edep->data[i].extp = NULL;
- edep->data[i].ext_endp = NULL;
- }
-
- edep->data->frag_id = 1;
- edep->data->extp = (byte*)bin->orig_bytes;
- edep->data->ext_endp = ep;
- edep->data->binp = bin;
- }
-
break;
}
default:
@@ -2055,10 +2010,17 @@ int erts_net_message(Port *prt,
token = tuple[4];
}
if (is_not_pid(from)
- || dep != external_pid_dist_entry(from)
- || is_not_internal_pid(to)) {
+ || dep != external_pid_dist_entry(from)) {
goto invalid_message;
}
+ if (is_not_internal_pid(to)) {
+ if (is_external_pid(to)) {
+ DistEntry *dep = external_pid_dist_entry(to);
+ if (dep == erts_this_dist_entry)
+ break; /* Old incarnation of this node... */
+ }
+ goto invalid_message;
+ }
if (!erts_proc_lookup(to)) {
if (ede_hfrag != NULL) {
@@ -3368,7 +3330,7 @@ dist_get_stat_1(BIF_ALIST_1)
am_ok,
erts_bld_sint64(hpp, szp, read),
erts_bld_sint64(hpp, szp, write),
- pend ? am_true : am_false);
+ erts_bld_sint64(hpp, szp, pend));
if (hpp)
break;
hp = HAlloc(BIF_P, sz);
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 067028634b..a33fb7efcf 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -274,6 +274,18 @@ typedef struct erts_dsig_send_context {
typedef struct dist_sequences DistSeqNode;
+struct dist_sequences {
+ ErlHeapFragment hfrag;
+ struct dist_sequences *parent;
+ struct dist_sequences *left;
+ struct dist_sequences *right;
+ char is_red;
+
+ Uint64 seq_id;
+ int cnt;
+ Sint ctl_len;
+};
+
/*
* erts_dsig_send_* return values.
*/
@@ -306,9 +318,9 @@ extern Uint erts_dist_cache_size(void);
extern Sint erts_abort_connection_rwunlock(DistEntry *dep);
-extern void erts_dist_seq_tree_foreach(
+extern void erts_debug_dist_seq_tree_foreach(
DistEntry *dep,
- int (*func)(ErtsDistExternal *, void*, Sint), void *args);
+ int (*func)(DistSeqNode *, void*, Sint), void *args);
extern int erts_dsig_prepare(ErtsDSigSendContext *,
DistEntry*,
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 92e5069c71..21941ba96e 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -149,6 +149,7 @@ type MODULE_TABLE LONG_LIVED CODE module_tab
type TAINT LONG_LIVED CODE taint_list
type MODULE_REFS STANDARD CODE module_refs
type NC_TMP TEMPORARY SYSTEM nc_tmp
+type NC_STD STANDARD SYSTEM nc_std
type TMP TEMPORARY SYSTEM tmp
type UNDEF SYSTEM SYSTEM undefined
type DCACHE STANDARD SYSTEM dcache
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 25ac3bc5af..bfc2f5992c 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -7112,12 +7112,21 @@ static int blockscan_cpool_yielding(blockscan_t *state)
return 0;
}
-static int blockscan_yield_helper(blockscan_t *state,
- int (*yielding_op)(blockscan_t*))
+/* */
+
+static int blockscan_finish(blockscan_t *state)
{
- /* Note that we don't check whether to abort here; only yielding_op knows
- * whether the carrier is still in the list/pool. */
+ if (ERTS_PROC_IS_EXITING(state->process)) {
+ state->abort(state->user_data);
+ return 0;
+ }
+ state->current_op = blockscan_finish;
+
+ return state->finish(state->user_data);
+}
+
+static void blockscan_lock_helper(blockscan_t *state) {
if ((state->allocator)->thread_safe) {
/* Locked scans have to be as short as possible. */
state->reductions = 1;
@@ -7126,34 +7135,18 @@ static int blockscan_yield_helper(blockscan_t *state,
} else {
state->reductions = BLOCKSCAN_REDUCTIONS;
}
+}
- if (yielding_op(state)) {
- state->next_op = state->current_op;
- }
-
+static void blockscan_unlock_helper(blockscan_t *state) {
if ((state->allocator)->thread_safe) {
erts_mtx_unlock(&(state->allocator)->mutex);
}
-
- return 1;
-}
-
-/* */
-
-static int blockscan_finish(blockscan_t *state)
-{
- if (ERTS_PROC_IS_EXITING(state->process)) {
- state->abort(state->user_data);
- return 0;
- }
-
- state->current_op = blockscan_finish;
-
- return state->finish(state->user_data);
}
static int blockscan_sweep_sbcs(blockscan_t *state)
{
+ blockscan_lock_helper(state);
+
if (state->current_op != blockscan_sweep_sbcs) {
SET_CARRIER_HDR(&state->dummy_carrier, 0, SCH_SBC, state->allocator);
state->current_clist = &(state->allocator)->sbc_list;
@@ -7163,11 +7156,19 @@ static int blockscan_sweep_sbcs(blockscan_t *state)
state->current_op = blockscan_sweep_sbcs;
state->next_op = blockscan_finish;
- return blockscan_yield_helper(state, blockscan_clist_yielding);
+ if (blockscan_clist_yielding(state)) {
+ state->next_op = state->current_op;
+ }
+
+ blockscan_unlock_helper(state);
+
+ return 1;
}
static int blockscan_sweep_mbcs(blockscan_t *state)
{
+ blockscan_lock_helper(state);
+
if (state->current_op != blockscan_sweep_mbcs) {
SET_CARRIER_HDR(&state->dummy_carrier, 0, SCH_MBC, state->allocator);
state->current_clist = &(state->allocator)->mbc_list;
@@ -7177,11 +7178,19 @@ static int blockscan_sweep_mbcs(blockscan_t *state)
state->current_op = blockscan_sweep_mbcs;
state->next_op = blockscan_sweep_sbcs;
- return blockscan_yield_helper(state, blockscan_clist_yielding);
+ if (blockscan_clist_yielding(state)) {
+ state->next_op = state->current_op;
+ }
+
+ blockscan_unlock_helper(state);
+
+ return 1;
}
static int blockscan_sweep_cpool(blockscan_t *state)
{
+ blockscan_lock_helper(state);
+
if (state->current_op != blockscan_sweep_cpool) {
SET_CARRIER_HDR(&state->dummy_carrier, 0, SCH_MBC, state->allocator);
state->cpool_cursor = (state->allocator)->cpool.sentinel;
@@ -7190,7 +7199,13 @@ static int blockscan_sweep_cpool(blockscan_t *state)
state->current_op = blockscan_sweep_cpool;
state->next_op = blockscan_sweep_mbcs;
- return blockscan_yield_helper(state, blockscan_cpool_yielding);
+ if (blockscan_cpool_yielding(state)) {
+ state->next_op = state->current_op;
+ }
+
+ blockscan_unlock_helper(state);
+
+ return 1;
}
static int blockscan_get_specific_allocator(int allocator_num,
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index 4d6d31cd76..b8e56390c1 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -1750,9 +1750,8 @@ static Eterm do_split_single_result(Process *p, Eterm subject, BinaryFindContext
Uint offset;
Uint bit_offset;
Uint bit_size;
- ErlSubBin *sb1;
- ErlSubBin *sb2;
- Eterm *hp;
+ Uint hp_need;
+ Eterm *hp, *hp_end;
Eterm ret;
pos = ff->pos;
@@ -1765,57 +1764,58 @@ static Eterm do_split_single_result(Process *p, Eterm subject, BinaryFindContext
if (pos == 0) {
ret = NIL;
} else {
- hp = HAlloc(p, (ERL_SUB_BIN_SIZE + 2));
+ Eterm extracted;
+
+ hp_need = EXTRACT_SUB_BIN_HEAP_NEED + 2;
+
+ hp = HAlloc(p, hp_need);
+ hp_end = hp + hp_need;
+
ERTS_GET_REAL_BIN(subject, orig, offset, bit_offset, bit_size);
- sb1 = (ErlSubBin *) hp;
- sb1->thing_word = HEADER_SUB_BIN;
- sb1->size = pos;
- sb1->offs = offset;
- sb1->orig = orig;
- sb1->bitoffs = bit_offset;
- sb1->bitsize = bit_size;
- sb1->is_writable = 0;
- hp += ERL_SUB_BIN_SIZE;
-
- ret = CONS(hp, make_binary(sb1), NIL);
+ extracted = erts_extract_sub_binary(&hp, orig, binary_bytes(orig),
+ offset * 8 + bit_offset,
+ pos * 8 + bit_size);
+
+ ret = CONS(hp, extracted, NIL);
hp += 2;
+
+ HRelease(p, hp_end, hp);
+
+ return ret;
}
} else {
- if ((ctx->flags & BF_FLAG_SPLIT_TRIM_ALL) && (pos == 0)) {
- hp = HAlloc(p, 1 * (ERL_SUB_BIN_SIZE + 2));
- ERTS_GET_REAL_BIN(subject, orig, offset, bit_offset, bit_size);
- sb1 = NULL;
- } else {
- hp = HAlloc(p, 2 * (ERL_SUB_BIN_SIZE + 2));
- ERTS_GET_REAL_BIN(subject, orig, offset, bit_offset, bit_size);
- sb1 = (ErlSubBin *) hp;
- sb1->thing_word = HEADER_SUB_BIN;
- sb1->size = pos;
- sb1->offs = offset;
- sb1->orig = orig;
- sb1->bitoffs = bit_offset;
- sb1->bitsize = 0;
- sb1->is_writable = 0;
- hp += ERL_SUB_BIN_SIZE;
- }
-
- sb2 = (ErlSubBin *) hp;
- sb2->thing_word = HEADER_SUB_BIN;
- sb2->size = orig_size - pos - len;
- sb2->offs = offset + pos + len;
- sb2->orig = orig;
- sb2->bitoffs = bit_offset;
- sb2->bitsize = bit_size;
- sb2->is_writable = 0;
- hp += ERL_SUB_BIN_SIZE;
-
- ret = CONS(hp, make_binary(sb2), NIL);
- hp += 2;
- if (sb1 != NULL) {
- ret = CONS(hp, make_binary(sb1), ret);
- hp += 2;
- }
+ Eterm first, rest;
+
+ hp_need = (EXTRACT_SUB_BIN_HEAP_NEED + 2) * 2;
+
+ hp = HAlloc(p, hp_need);
+ hp_end = hp + hp_need;
+
+ ERTS_GET_REAL_BIN(subject, orig, offset, bit_offset, bit_size);
+
+ if ((ctx->flags & BF_FLAG_SPLIT_TRIM_ALL) && (pos == 0)) {
+ first = NIL;
+ } else {
+ first = erts_extract_sub_binary(&hp, orig, binary_bytes(orig),
+ offset * 8 + bit_offset,
+ pos * 8);
+ }
+
+ rest = erts_extract_sub_binary(&hp, orig, binary_bytes(orig),
+ (offset + pos + len) * 8 + bit_offset,
+ (orig_size - pos - len) * 8 + bit_size);
+
+ ret = CONS(hp, rest, NIL);
+ hp += 2;
+
+ if (first != NIL) {
+ ret = CONS(hp, first, ret);
+ hp += 2;
+ }
+
+ HRelease(p, hp_end, hp);
}
+
return ret;
}
@@ -1829,7 +1829,9 @@ static Eterm do_split_global_result(Process *p, Eterm subject, BinaryFindContext
Uint offset;
Uint bit_offset;
Uint bit_size;
- ErlSubBin *sb;
+ Uint extracted_offset;
+ Uint extracted_size;
+ Eterm extracted;
Uint do_trim;
Sint i;
register Uint reds = ctx->reds;
@@ -1852,7 +1854,8 @@ static Eterm do_split_global_result(Process *p, Eterm subject, BinaryFindContext
*ctxp = ctx;
fa = &(ctx->u.fa);
}
- erts_factory_proc_prealloc_init(&(fa->factory), p, (fa->size + 1) * (ERL_SUB_BIN_SIZE + 2));
+ erts_factory_proc_prealloc_init(&(fa->factory), p, (fa->size + 1) *
+ (EXTRACT_SUB_BIN_HEAP_NEED + 2));
ctx->state = BFResult;
}
@@ -1871,39 +1874,39 @@ static Eterm do_split_global_result(Process *p, Eterm subject, BinaryFindContext
}
return THE_NON_VALUE;
}
- sb = (ErlSubBin *)(fa->factory.hp);
- sb->size = fa->end_pos - (fad[i].pos + fad[i].len);
- if (!(sb->size == 0 && do_trim)) {
- sb->thing_word = HEADER_SUB_BIN;
- sb->offs = offset + fad[i].pos + fad[i].len;
- sb->orig = orig;
- sb->bitoffs = bit_offset;
- sb->bitsize = 0;
- sb->is_writable = 0;
- fa->factory.hp += ERL_SUB_BIN_SIZE;
- fa->term = CONS(fa->factory.hp, make_binary(sb), fa->term);
- fa->factory.hp += 2;
- do_trim &= ~BF_FLAG_SPLIT_TRIM;
- }
- fa->end_pos = fad[i].pos;
+
+ extracted_offset = (offset + fad[i].pos + fad[i].len) * 8 + bit_offset;
+ extracted_size = (fa->end_pos - (fad[i].pos + fad[i].len)) * 8;
+
+ if (!(extracted_size == 0 && do_trim)) {
+ extracted = erts_extract_sub_binary(&fa->factory.hp, orig,
+ binary_bytes(orig),
+ extracted_offset,
+ extracted_size);
+ fa->term = CONS(fa->factory.hp, extracted, fa->term);
+ fa->factory.hp += 2;
+
+ do_trim &= ~BF_FLAG_SPLIT_TRIM;
+ }
+
+ fa->end_pos = fad[i].pos;
}
fa->head = i;
ctx->reds = reds;
- sb = (ErlSubBin *)(fa->factory.hp);
- sb->size = fad[0].pos;
- if (!(sb->size == 0 && do_trim)) {
- sb->thing_word = HEADER_SUB_BIN;
- sb->offs = offset;
- sb->orig = orig;
- sb->bitoffs = bit_offset;
- sb->bitsize = 0;
- sb->is_writable = 0;
- fa->factory.hp += ERL_SUB_BIN_SIZE;
- fa->term = CONS(fa->factory.hp, make_binary(sb), fa->term);
- fa->factory.hp += 2;
+ extracted_offset = offset * 8 + bit_offset;
+ extracted_size = fad[0].pos * 8;
+
+ if (!(extracted_size == 0 && do_trim)) {
+ extracted = erts_extract_sub_binary(&fa->factory.hp, orig,
+ binary_bytes(orig),
+ extracted_offset,
+ extracted_size);
+ fa->term = CONS(fa->factory.hp, extracted, fa->term);
+ fa->factory.hp += 2;
}
+
erts_factory_close(&(fa->factory));
return fa->term;
@@ -1937,8 +1940,8 @@ BIF_RETTYPE erts_binary_part(Process *p, Eterm binary, Eterm epos, Eterm elen)
Uint offset;
Uint bit_offset;
Uint bit_size;
- Eterm* hp;
- ErlSubBin* sb;
+ Eterm *hp, *hp_end;
+ Eterm result;
if (is_not_binary(binary)) {
goto badarg;
@@ -1970,19 +1973,18 @@ BIF_RETTYPE erts_binary_part(Process *p, Eterm binary, Eterm epos, Eterm elen)
goto badarg;
}
- hp = HeapFragOnlyAlloc(p, ERL_SUB_BIN_SIZE);
+ hp = HeapFragOnlyAlloc(p, EXTRACT_SUB_BIN_HEAP_NEED);
+ hp_end = hp + EXTRACT_SUB_BIN_HEAP_NEED;
ERTS_GET_REAL_BIN(binary, orig, offset, bit_offset, bit_size);
- sb = (ErlSubBin *) hp;
- sb->thing_word = HEADER_SUB_BIN;
- sb->size = len;
- sb->offs = offset + pos;
- sb->orig = orig;
- sb->bitoffs = bit_offset;
- sb->bitsize = 0;
- sb->is_writable = 0;
-
- BIF_RET(make_binary(sb));
+
+ result = erts_extract_sub_binary(&hp, orig, binary_bytes(orig),
+ (offset + pos) * 8 + bit_offset,
+ len * 8);
+
+ HRelease(p, hp_end, hp);
+
+ BIF_RET(result);
badarg:
BIF_ERROR(p, BADARG);
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 2704b99aa4..4d8c3eb9dd 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -162,10 +162,10 @@ static Eterm current_stacktrace(ErtsHeapFactory *hfact, Process* rp,
Uint reserve_size);
static Eterm
-bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
+bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh, Eterm tail)
{
struct erl_off_heap_header* ohh;
- Eterm res = NIL;
+ Eterm res = tail;
Eterm tuple;
for (ohh = oh->first; ohh; ohh = ohh->next) {
@@ -768,7 +768,7 @@ static ErtsProcessInfoArgs pi_args[] = {
{am_memory, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
{am_garbage_collection, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + ERTS_MAX_HEAP_SIZE_MAP_SZ, 0, ERTS_PROC_LOCK_MAIN},
{am_group_leader, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_reductions, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
+ {am_reductions, 0, 0, ERTS_PROC_LOCK_MAIN},
{am_priority, 0, 0, 0},
{am_trace, 0, 0, ERTS_PROC_LOCK_MAIN},
{am_binary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
@@ -1864,11 +1864,25 @@ process_info_aux(Process *c_p,
break;
case ERTS_PI_IX_BINARY: {
- Uint sz = 0;
- (void) bld_bin_list(NULL, &sz, &MSO(rp));
+ ErlHeapFragment *hfrag;
+ Uint sz;
+
+ res = NIL;
+ sz = 0;
+
+ (void)bld_bin_list(NULL, &sz, &MSO(rp), NIL);
+ for (hfrag = rp->mbuf; hfrag != NULL; hfrag = hfrag->next) {
+ (void)bld_bin_list(NULL, &sz, &hfrag->off_heap, NIL);
+ }
+
hp = erts_produce_heap(hfact, sz, reserve_size);
- res = bld_bin_list(&hp, NULL, &MSO(rp));
- break;
+
+ res = bld_bin_list(&hp, NULL, &MSO(rp), NIL);
+ for (hfrag = rp->mbuf; hfrag != NULL; hfrag = hfrag->next) {
+ res = bld_bin_list(&hp, NULL, &hfrag->off_heap, res);
+ }
+
+ break;
}
case ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN: {
diff --git a/erts/emulator/beam/erl_bif_lists.c b/erts/emulator/beam/erl_bif_lists.c
index b23fa77f5f..fa2edfef1e 100644
--- a/erts/emulator/beam/erl_bif_lists.c
+++ b/erts/emulator/beam/erl_bif_lists.c
@@ -413,12 +413,25 @@ typedef struct {
#define ERTS_RBT_GET_LEFT(T) ((T)->left)
#define ERTS_RBT_SET_LEFT(T, L) ((T)->left = (L))
#define ERTS_RBT_GET_KEY(T) ((T)->key)
-#define ERTS_RBT_CMP_KEYS(KX, KY) CMP_TERM(KX, KY)
+#define ERTS_RBT_CMP_KEYS(KX, KY) subtract_term_cmp((KX), (KY))
#define ERTS_RBT_WANT_LOOKUP_INSERT
#define ERTS_RBT_WANT_LOOKUP
#define ERTS_RBT_WANT_DELETE
#define ERTS_RBT_UNDEF
+/* erl_rbtree expects comparisons to return an int */
+static int subtract_term_cmp(Eterm a, Eterm b) {
+ Sint res = CMP_TERM(a, b);
+
+ if (res < 0) {
+ return -1;
+ } else if (res > 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
#include "erl_rbtree.h"
static int subtract_continue(Process *p, ErtsSubtractContext *context);
diff --git a/erts/emulator/beam/erl_bif_persistent.c b/erts/emulator/beam/erl_bif_persistent.c
index f38e0cc5cb..8662a9e33a 100644
--- a/erts/emulator/beam/erl_bif_persistent.c
+++ b/erts/emulator/beam/erl_bif_persistent.c
@@ -1234,3 +1234,102 @@ next_to_delete(void)
erts_mtx_unlock(&delete_queue_mtx);
return table;
}
+
+/*
+ * test/debug functionality follow...
+ */
+
+static Uint accessed_literal_areas_size;
+static Uint accessed_no_literal_areas;
+static ErtsLiteralArea **accessed_literal_areas;
+
+int
+erts_debug_have_accessed_literal_area(ErtsLiteralArea *lap)
+{
+ Uint i;
+ for (i = 0; i < accessed_no_literal_areas; i++) {
+ if (accessed_literal_areas[i] == lap)
+ return !0;
+ }
+ return 0;
+}
+
+void
+erts_debug_save_accessed_literal_area(ErtsLiteralArea *lap)
+{
+ if (accessed_no_literal_areas == accessed_literal_areas_size) {
+ accessed_literal_areas_size += 10;
+ accessed_literal_areas = erts_realloc(ERTS_ALC_T_TMP,
+ accessed_literal_areas,
+ (sizeof(ErtsLiteralArea *)
+ *accessed_literal_areas_size));
+ }
+ accessed_literal_areas[accessed_no_literal_areas++] = lap;
+}
+
+static void debug_foreach_off_heap(HashTable *tbl, void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ int i;
+
+ for (i = 0; i < tbl->allocated; i++) {
+ Eterm term = tbl->term[i];
+ if (is_tuple_arity(term, 2)) {
+ ErtsLiteralArea *lap = term_to_area(term);
+ ErlOffHeap oh;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ }
+ }
+}
+
+struct debug_la_oh {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_handle_table(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vtbl)
+{
+ struct debug_la_oh *fap = vfap;
+ HashTable *tbl = vtbl;
+ debug_foreach_off_heap(tbl, fap->func, fap->arg);
+}
+
+void
+erts_debug_foreach_persistent_term_off_heap(void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ HashTable *tbl;
+ struct debug_la_oh fa;
+ accessed_no_literal_areas = 0;
+ accessed_literal_areas_size = 10;
+ accessed_literal_areas = erts_alloc(ERTS_ALC_T_TMP,
+ (sizeof(ErtsLiteralArea *)
+ * accessed_literal_areas_size));
+
+ tbl = (HashTable *) erts_atomic_read_nob(&the_hash_table);
+ debug_foreach_off_heap(tbl, func, arg);
+ erts_mtx_lock(&delete_queue_mtx);
+ for (tbl = delete_queue_head; tbl; tbl = tbl->delete_next)
+ debug_foreach_off_heap(tbl, func, arg);
+ erts_mtx_unlock(&delete_queue_mtx);
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(table_updater,
+ debug_handle_table,
+ (void *) &fa);
+ erts_debug_later_op_foreach(table_deleter,
+ debug_handle_table,
+ (void *) &fa);
+ erts_debug_foreach_release_literal_area_off_heap(func, arg);
+
+ erts_free(ERTS_ALC_T_TMP, accessed_literal_areas);
+ accessed_no_literal_areas = 0;
+ accessed_literal_areas_size = 0;
+ accessed_literal_areas = NULL;
+}
+
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index e0b9202fe7..b3bf1c7ee3 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -46,7 +46,7 @@ static Export *urun_trap_exportp = NULL;
static Export *ucompile_trap_exportp = NULL;
static BIF_RETTYPE re_exec_trap(BIF_ALIST_3);
-static BIF_RETTYPE re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3);
+static BIF_RETTYPE re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3, int first);
static void *erts_erts_pcre_malloc(size_t size) {
return erts_alloc(ERTS_ALC_T_RE_HEAP,size);
@@ -1094,7 +1094,7 @@ build_capture(Eterm capture_spec[CAPSPEC_SIZE], const pcre *code)
* The actual re:run/2,3 BIFs
*/
static BIF_RETTYPE
-re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
+re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3, int first)
{
const pcre *code_tmp;
RestartContext restart;
@@ -1120,6 +1120,14 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
< 0) {
BIF_ERROR(p,BADARG);
}
+ if (!first) {
+ /*
+ * 'first' is false when re:grun() previously has called re:internal_run()
+ * with the same subject; i.e., no need to do yet another validation of
+ * the subject regarding utf8 encoding...
+ */
+ options |= PCRE_NO_UTF8_CHECK;
+ }
is_list_cap = ((pflags & PARSE_FLAG_CAPTURE_OPT) &&
(capture[CAPSPEC_TYPE] == am_list));
@@ -1360,15 +1368,28 @@ handle_iolist:
}
BIF_RETTYPE
+re_internal_run_4(BIF_ALIST_4)
+{
+ int first;
+ if (BIF_ARG_4 == am_false)
+ first = 0;
+ else if (BIF_ARG_4 == am_true)
+ first = !0;
+ else
+ BIF_ERROR(BIF_P,BADARG);
+ return re_run(BIF_P,BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, first);
+}
+
+BIF_RETTYPE
re_run_3(BIF_ALIST_3)
{
- return re_run(BIF_P,BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+ return re_run(BIF_P,BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, !0);
}
BIF_RETTYPE
re_run_2(BIF_ALIST_2)
{
- return re_run(BIF_P,BIF_ARG_1, BIF_ARG_2, NIL);
+ return re_run(BIF_P,BIF_ARG_1, BIF_ARG_2, NIL, !0);
}
/*
@@ -1407,6 +1428,7 @@ static BIF_RETTYPE re_exec_trap(BIF_ALIST_3)
loop_count = 0xFFFFFFFF;
#endif
rc = erts_pcre_exec(NULL, &(restartp->extra), NULL, 0, 0, 0, NULL, 0);
+
ASSERT(loop_count != 0xFFFFFFFF);
BUMP_REDS(BIF_P, loop_count / LOOP_FACTOR);
if (rc == PCRE_ERROR_LOOP_LIMIT) {
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 711e62c795..b31d5b86cb 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -74,7 +74,7 @@ static void smp_bp_finisher(void* arg);
static BIF_RETTYPE
system_monitor(Process *p, Eterm monitor_pid, Eterm list);
-static void new_seq_trace_token(Process* p); /* help func for seq_trace_2*/
+static void new_seq_trace_token(Process* p, int); /* help func for seq_trace_2*/
static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key);
static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key);
static Eterm trace_info_on_load(Process* p, Eterm key);
@@ -1874,7 +1874,7 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2,
if (current_flag && ( (arg2 == am_true) || (arg2 == am_false)) ) {
/* Flags */
- new_seq_trace_token(p);
+ new_seq_trace_token(p, 0);
flags = unsigned_val(SEQ_TRACE_TOKEN_FLAGS(p));
if (build_result) {
old_value = flags & current_flag ? am_true : am_false;
@@ -1889,11 +1889,11 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2,
return old_value;
}
else if (arg1 == am_label) {
- new_seq_trace_token(p);
+ new_seq_trace_token(p, is_not_immed(arg2));
if (build_result) {
old_value = SEQ_TRACE_TOKEN_LABEL(p);
}
- SEQ_TRACE_TOKEN_LABEL(p) = arg2;
+ SEQ_TRACE_TOKEN_LABEL(p) = arg2;
return old_value;
}
else if (arg1 == am_serial) {
@@ -1905,7 +1905,7 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2,
if ((*tp != make_arityval(2)) || is_not_small(*(tp+1)) || is_not_small(*(tp+2))) {
return THE_NON_VALUE;
}
- new_seq_trace_token(p);
+ new_seq_trace_token(p, 0);
if (build_result) {
hp = HAlloc(p,3);
old_value = TUPLE2(hp, SEQ_TRACE_TOKEN_LASTCNT(p),
@@ -1940,8 +1940,8 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2,
}
}
-void
-new_seq_trace_token(Process* p)
+static void
+new_seq_trace_token(Process* p, int ensure_new_heap)
{
Eterm* hp;
@@ -1953,6 +1953,16 @@ new_seq_trace_token(Process* p)
p->common.id, /* Internal pid */ /* From */
make_small(p->seq_trace_lastcnt));
}
+ else if (ensure_new_heap) {
+ Eterm* tpl = tuple_val(SEQ_TRACE_TOKEN(p));
+ ASSERT(arityval(tpl[0]) == 5);
+ if (ErtsInArea(tpl, OLD_HEAP(p),
+ (OLD_HEND(p) - OLD_HEAP(p))*sizeof(Eterm))) {
+ hp = HAlloc(p, 6);
+ sys_memcpy(hp, tpl, 6*sizeof(Eterm));
+ SEQ_TRACE_TOKEN(p) = make_tuple(hp);
+ }
+ }
}
BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item)
@@ -2050,10 +2060,7 @@ BIF_RETTYPE seq_trace_print_2(BIF_ALIST_2)
if (have_no_seqtrace(SEQ_TRACE_TOKEN(BIF_P))) {
BIF_RET(am_false);
}
- if (!(is_atom(BIF_ARG_1) || is_small(BIF_ARG_1))) {
- BIF_ERROR(BIF_P, BADARG);
- }
- if (SEQ_TRACE_TOKEN_LABEL(BIF_P) != BIF_ARG_1)
+ if (!EQ(BIF_ARG_1, SEQ_TRACE_TOKEN_LABEL(BIF_P)))
BIF_RET(am_false);
seq_trace_update_send(BIF_P);
seq_trace_output(SEQ_TRACE_TOKEN(BIF_P), BIF_ARG_2,
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index c9c047255a..66b59ef1a3 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -351,6 +351,19 @@ erts_free_aligned_binary_bytes(byte* buf)
erts_free_aligned_binary_bytes_extra(buf,ERTS_ALC_T_TMP);
}
+/* A binary's size in bits must fit into a word for matching to work. We used
+ * to allow creating larger binaries than this, but they acted really strangely
+ * in Erlang code and were pretty much only usable in drivers and NIFs.
+ *
+ * This check also ensures, indirectly, that there won't be an overflow when
+ * the size is bumped by CHICKEN_PAD and the binary struct itself. */
+#define BINARY_OVERFLOW_CHECK(BYTE_SIZE) \
+ do { \
+ if (ERTS_UNLIKELY(BYTE_SIZE > ERTS_UWORD_MAX / CHAR_BIT)) { \
+ return NULL; \
+ } \
+ } while(0)
+
/* Explicit extra bytes allocated to counter buggy drivers.
** These extra bytes where earlier (< R13B04) added by an alignment-bug
** in this code. Do we dare remove this in some major release (R14?) maybe?
@@ -364,86 +377,107 @@ erts_free_aligned_binary_bytes(byte* buf)
ERTS_GLB_INLINE Binary *
erts_bin_drv_alloc_fnf(Uint size)
{
- Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
Binary *res;
+ Uint bsize;
+
+ BINARY_OVERFLOW_CHECK(size);
+ bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- if (bsize < size) /* overflow */
- return NULL;
res = erts_alloc_fnf(ERTS_ALC_T_DRV_BINARY, bsize);
ERTS_CHK_BIN_ALIGNMENT(res);
+
if (res) {
- res->orig_size = size;
- res->intern.flags = BIN_FLAG_DRV;
+ res->orig_size = size;
+ res->intern.flags = BIN_FLAG_DRV;
erts_refc_init(&res->intern.refc, 1);
}
+
return res;
}
ERTS_GLB_INLINE Binary *
erts_bin_drv_alloc(Uint size)
{
- Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
+ Binary *res = erts_bin_drv_alloc_fnf(size);
+
+ if (res) {
+ return res;
+ }
+
+ erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, size);
+}
+
+ERTS_GLB_INLINE Binary *
+erts_bin_nrml_alloc_fnf(Uint size)
+{
Binary *res;
+ Uint bsize;
- if (bsize < size) /* overflow */
- erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, size);
- res = erts_alloc(ERTS_ALC_T_DRV_BINARY, bsize);
+ BINARY_OVERFLOW_CHECK(size);
+ bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
+
+ res = erts_alloc_fnf(ERTS_ALC_T_BINARY, bsize);
ERTS_CHK_BIN_ALIGNMENT(res);
- res->orig_size = size;
- res->intern.flags = BIN_FLAG_DRV;
- erts_refc_init(&res->intern.refc, 1);
+
+ if (res) {
+ res->orig_size = size;
+ res->intern.flags = 0;
+ erts_refc_init(&res->intern.refc, 1);
+ }
+
return res;
}
ERTS_GLB_INLINE Binary *
erts_bin_nrml_alloc(Uint size)
{
- Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- Binary *res;
+ Binary *res = erts_bin_drv_alloc_fnf(size);
- if (bsize < size) /* overflow */
- erts_alloc_enomem(ERTS_ALC_T_BINARY, size);
- res = erts_alloc(ERTS_ALC_T_BINARY, bsize);
- ERTS_CHK_BIN_ALIGNMENT(res);
- res->orig_size = size;
- res->intern.flags = 0;
- erts_refc_init(&res->intern.refc, 1);
- return res;
+ if (res) {
+ return res;
+ }
+
+ erts_alloc_enomem(ERTS_ALC_T_BINARY, size);
}
ERTS_GLB_INLINE Binary *
erts_bin_realloc_fnf(Binary *bp, Uint size)
{
+ ErtsAlcType_t type;
Binary *nbp;
- Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- ErtsAlcType_t type = (bp->intern.flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
- : ERTS_ALC_T_BINARY;
+ Uint bsize;
+
+ type = (bp->intern.flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
+ : ERTS_ALC_T_BINARY;
ASSERT((bp->intern.flags & BIN_FLAG_MAGIC) == 0);
- if (bsize < size) /* overflow */
- return NULL;
+
+ BINARY_OVERFLOW_CHECK(size);
+ bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
+
nbp = erts_realloc_fnf(type, (void *) bp, bsize);
ERTS_CHK_BIN_ALIGNMENT(nbp);
- if (nbp)
- nbp->orig_size = size;
+
+ if (nbp) {
+ nbp->orig_size = size;
+ }
+
return nbp;
}
ERTS_GLB_INLINE Binary *
erts_bin_realloc(Binary *bp, Uint size)
{
- Binary *nbp;
- Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- ErtsAlcType_t type = (bp->intern.flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
- : ERTS_ALC_T_BINARY;
- ASSERT((bp->intern.flags & BIN_FLAG_MAGIC) == 0);
- if (bsize < size) /* overflow */
- erts_realloc_enomem(type, bp, size);
- nbp = erts_realloc_fnf(type, (void *) bp, bsize);
- if (!nbp)
- erts_realloc_enomem(type, bp, bsize);
- ERTS_CHK_BIN_ALIGNMENT(nbp);
- nbp->orig_size = size;
- return nbp;
+ Binary *nbp = erts_bin_realloc_fnf(bp, size);
+
+ if (nbp) {
+ return nbp;
+ }
+
+ if (bp->intern.flags & BIN_FLAG_DRV) {
+ erts_realloc_enomem(ERTS_ALC_T_DRV_BINARY, bp, size);
+ } else {
+ erts_realloc_enomem(ERTS_ALC_T_BINARY, bp, size);
+ }
}
ERTS_GLB_INLINE void
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index f5807d25d7..a0edbc81a4 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -124,10 +124,10 @@ erts_bs_start_match_2(Process *p, Eterm Binary, Uint Max)
ProcBin* pb;
ASSERT(is_binary(Binary));
+
total_bin_size = binary_size(Binary);
- if ((total_bin_size >> (8*sizeof(Uint)-3)) != 0) {
- return THE_NON_VALUE;
- }
+ ASSERT(total_bin_size <= ERTS_UWORD_MAX / CHAR_BIT);
+
NeededSize = ERL_BIN_MATCHSTATE_SIZE(Max);
hp = HeapOnlyAlloc(p, NeededSize);
ms = (ErlBinMatchState *) hp;
@@ -157,10 +157,9 @@ ErlBinMatchState *erts_bs_start_match_3(Process *p, Eterm Binary)
ProcBin* pb;
ASSERT(is_binary(Binary));
+
total_bin_size = binary_size(Binary);
- if ((total_bin_size >> (8*sizeof(Uint)-3)) != 0) {
- return NULL;
- }
+ ASSERT(total_bin_size <= ERTS_UWORD_MAX / CHAR_BIT);
NeededSize = ERL_BIN_MATCHSTATE_SIZE(0);
hp = HeapOnlyAlloc(p, NeededSize);
@@ -459,29 +458,25 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff
Eterm
erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb)
{
- ErlSubBin* sb;
+ Eterm result;
CHECK_MATCH_BUFFER(mb);
- if (mb->size - mb->offset < num_bits) { /* Asked for too many bits. */
- return THE_NON_VALUE;
+ if (mb->size - mb->offset < num_bits) {
+ /* Asked for too many bits. */
+ return THE_NON_VALUE;
}
/*
* From now on, we can't fail.
*/
- sb = (ErlSubBin *) HeapOnlyAlloc(p, ERL_SUB_BIN_SIZE);
-
- sb->thing_word = HEADER_SUB_BIN;
- sb->orig = mb->orig;
- sb->size = BYTE_OFFSET(num_bits);
- sb->bitsize = BIT_OFFSET(num_bits);
- sb->offs = BYTE_OFFSET(mb->offset);
- sb->bitoffs = BIT_OFFSET(mb->offset);
- sb->is_writable = 0;
+ result = erts_extract_sub_binary(&HEAP_TOP(p),
+ mb->orig, mb->base,
+ mb->offset, num_bits);
+
mb->offset += num_bits;
-
- return make_binary(sb);
+
+ return result;
}
Eterm
@@ -545,21 +540,19 @@ erts_bs_get_float_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer
Eterm
erts_bs_get_binary_all_2(Process *p, ErlBinMatchBuffer* mb)
{
- ErlSubBin* sb;
- Uint size;
+ Uint bit_size;
+ Eterm result;
CHECK_MATCH_BUFFER(mb);
- size = mb->size-mb->offset;
- sb = (ErlSubBin *) HeapOnlyAlloc(p, ERL_SUB_BIN_SIZE);
- sb->thing_word = HEADER_SUB_BIN;
- sb->size = BYTE_OFFSET(size);
- sb->bitsize = BIT_OFFSET(size);
- sb->offs = BYTE_OFFSET(mb->offset);
- sb->bitoffs = BIT_OFFSET(mb->offset);
- sb->is_writable = 0;
- sb->orig = mb->orig;
- mb->offset = mb->size;
- return make_binary(sb);
+ bit_size = mb->size - mb->offset;
+
+ result = erts_extract_sub_binary(&HEAP_TOP(p),
+ mb->orig, mb->base,
+ mb->offset, bit_size);
+
+ mb->offset = mb->size;
+
+ return result;
}
/****************************************************************
@@ -2097,3 +2090,39 @@ erts_copy_bits(byte* src, /* Base pointer to source. */
}
}
+Eterm erts_extract_sub_binary(Eterm **hp, Eterm base_bin, byte *base_data,
+ Uint bit_offset, Uint bit_size)
+{
+ Uint byte_offset, byte_size;
+
+ ERTS_CT_ASSERT(ERL_SUB_BIN_SIZE <= ERL_ONHEAP_BIN_LIMIT);
+
+ byte_offset = BYTE_OFFSET(bit_offset);
+ byte_size = BYTE_OFFSET(bit_size);
+
+ if (BIT_OFFSET(bit_size) == 0 && byte_size <= ERL_ONHEAP_BIN_LIMIT) {
+ ErlHeapBin *hb = (ErlHeapBin*)*hp;
+ *hp += heap_bin_size(byte_size);
+
+ hb->thing_word = header_heap_bin(byte_size);
+ hb->size = byte_size;
+
+ copy_binary_to_buffer(hb->data, 0, base_data, bit_offset, bit_size);
+
+ return make_binary(hb);
+ } else {
+ ErlSubBin *sb = (ErlSubBin*)*hp;
+ *hp += ERL_SUB_BIN_SIZE;
+
+ sb->thing_word = HEADER_SUB_BIN;
+ sb->size = byte_size;
+ sb->offs = byte_offset;
+ sb->orig = base_bin;
+ sb->bitoffs = BIT_OFFSET(bit_offset);
+ sb->bitsize = BIT_OFFSET(bit_size);
+ sb->is_writable = 0;
+
+ return make_binary(sb);
+ }
+}
+
diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h
index 50d353e1fa..0b2a6f3760 100644
--- a/erts/emulator/beam/erl_bits.h
+++ b/erts/emulator/beam/erl_bits.h
@@ -116,7 +116,7 @@ typedef struct erl_bin_match_struct{
do { \
if (BIT_OFFSET(DstBufOffset) == 0 && (SrcBufferOffset == 0) && \
(BIT_OFFSET(NumBits)==0) && (NumBits != 0)) { \
- sys_memcpy(DstBuffer+BYTE_OFFSET(DstBufOffset), \
+ sys_memcpy(((byte*)DstBuffer)+BYTE_OFFSET(DstBufOffset), \
SrcBuffer, NBYTES(NumBits)); \
} else { \
erts_copy_bits(SrcBuffer, SrcBufferOffset, 1, \
@@ -150,8 +150,11 @@ void erts_bits_destroy_state(ERL_BITS_PROTO_0);
Eterm erts_bs_start_match_2(Process *p, Eterm Bin, Uint Max);
ErlBinMatchState *erts_bs_start_match_3(Process *p, Eterm Bin);
Eterm erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
-Eterm erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
Eterm erts_bs_get_float_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
+
+/* These will create heap binaries when appropriate, so they require free space
+ * up to EXTRACT_SUB_BIN_HEAP_NEED. */
+Eterm erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
Eterm erts_bs_get_binary_all_2(Process *p, ErlBinMatchBuffer* mb);
/*
@@ -182,6 +185,17 @@ void erts_copy_bits(byte* src, size_t soffs, int sdir,
byte* dst, size_t doffs,int ddir, size_t n);
int erts_cmp_bits(byte* a_ptr, size_t a_offs, byte* b_ptr, size_t b_offs, size_t size);
+
+/* Extracts a region from base_bin as a sub-binary or heap binary, whichever
+ * is the most appropriate.
+ *
+ * The caller must ensure that there's enough free space at *hp */
+Eterm erts_extract_sub_binary(Eterm **hp, Eterm base_bin, byte *base_data,
+ Uint bit_offset, Uint num_bits);
+
+/* Pessimistic estimate of the words required for erts_extract_sub_binary */
+#define EXTRACT_SUB_BIN_HEAP_NEED (heap_bin_size(ERL_ONHEAP_BIN_LIMIT))
+
/*
* Flags for bs_get_* / bs_put_* / bs_init* instructions.
*/
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index d24f30f126..3c74ef493b 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -4415,7 +4415,7 @@ void db_info(fmtfn_t to, void *to_arg, int show) /* Called by break handler *
pdbi.to_arg = to_arg;
pdbi.show = show;
- erts_db_foreach_table(db_info_print, &pdbi);
+ erts_db_foreach_table(db_info_print, &pdbi, !0);
}
Uint
@@ -4428,7 +4428,7 @@ erts_get_ets_misc_mem_size(void)
/* SMP Note: May only be used when system is locked */
void
-erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg)
+erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg, int alive_only)
{
int ix;
@@ -4440,7 +4440,7 @@ erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg)
if (first) {
DbTable *tb = first;
do {
- if (is_table_alive(tb))
+ if (!alive_only || is_table_alive(tb))
(*func)(tb, arg);
tb = tb->common.all.next;
} while (tb != first);
@@ -4457,6 +4457,15 @@ erts_db_foreach_offheap(DbTable *tb,
tb->common.meth->db_foreach_offheap(tb, func, arg);
}
+void
+erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+ erts_db_foreach_thr_prgr_offheap_hash(func, arg);
+ erts_db_foreach_thr_prgr_offheap_tree(func, arg);
+ erts_db_foreach_thr_prgr_offheap_catree(func, arg);
+}
+
/* retrieve max number of ets tables */
Uint
erts_db_get_max_tabs()
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index b3dc1b9ba3..c604744687 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -114,10 +114,12 @@ void init_db(ErtsDbSpinCount);
int erts_db_process_exiting(Process *, ErtsProcLocks, void **);
int erts_db_execute_free_fixation(Process*, DbFixation*);
void db_info(fmtfn_t, void *, int);
-void erts_db_foreach_table(void (*)(DbTable *, void *), void *);
+void erts_db_foreach_table(void (*)(DbTable *, void *), void *, int);
void erts_db_foreach_offheap(DbTable *,
void (*func)(ErlOffHeap *, void *),
void *);
+void erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *),
+ void *);
extern int erts_ets_rwmtx_spin_count;
extern int user_requested_db_max_tabs; /* set in erl_init */
diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c
index e0d5e44f58..8a89eb72df 100644
--- a/erts/emulator/beam/erl_db_catree.c
+++ b/erts/emulator/beam/erl_db_catree.c
@@ -166,8 +166,17 @@ static void split_catree(DbTableCATree *tb,
static void join_catree(DbTableCATree *tb,
DbTableCATreeNode *thiz,
DbTableCATreeNode *parent);
-
-
+static ERTS_INLINE
+int try_wlock_base_node(DbTableCATreeBaseNode *base_node);
+static ERTS_INLINE
+void wunlock_base_node(DbTableCATreeNode *base_node);
+static ERTS_INLINE
+void wlock_base_node_no_stats(DbTableCATreeNode *base_node);
+static ERTS_INLINE
+void wunlock_adapt_base_node(DbTableCATree* tb,
+ DbTableCATreeNode* node,
+ DbTableCATreeNode* parent,
+ int current_level);
/*
** External interface
*/
@@ -210,12 +219,16 @@ DbTableMethod db_catree =
* Constants
*/
-#define ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION 200
+#define ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION 250
#define ERL_DB_CATREE_LOCK_SUCCESS_CONTRIBUTION (-1)
+#define ERL_DB_CATREE_LOCK_GRAVITY_CONTRIBUTION (-500)
+#define ERL_DB_CATREE_LOCK_GRAVITY_PATTERN (0xFF800000)
#define ERL_DB_CATREE_LOCK_MORE_THAN_ONE_CONTRIBUTION (-10)
#define ERL_DB_CATREE_HIGH_CONTENTION_LIMIT 1000
#define ERL_DB_CATREE_LOW_CONTENTION_LIMIT (-1000)
-#define ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT 14
+#define ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT 16
+#define ERL_DB_CATREE_LOCK_LOW_NO_CONTRIBUTION_LIMIT (-20000)
+#define ERL_DB_CATREE_LOCK_HIGH_NO_CONTRIBUTION_LIMIT (20000)
/*
* Internal CA tree related helper functions and macros
@@ -245,6 +258,27 @@ DbTableMethod db_catree =
#define SET_LEFT_RELB(ca_tree_route_node, v) erts_atomic_set_relb(&(ca_tree_route_node->u.route.left), (erts_aint_t)(v));
#define SET_RIGHT_RELB(ca_tree_route_node, v) erts_atomic_set_relb(&(ca_tree_route_node->u.route.right), (erts_aint_t)(v));
+/* Change base node lock statistics */
+#define BASE_NODE_STAT_SET(NODE, VALUE) erts_atomic_set_nob(&(NODE)->u.base.lock_statistics, VALUE)
+#define BASE_NODE_STAT_READ(NODE) erts_atomic_read_nob(&(NODE)->u.base.lock_statistics)
+#define BASE_NODE_STAT_ADD(NODE, VALUE) \
+ do { \
+ Sint v = erts_atomic_read_nob(&((NODE)->u.base.lock_statistics)); \
+ ASSERT(VALUE > 0); \
+ if(v < ERL_DB_CATREE_LOCK_HIGH_NO_CONTRIBUTION_LIMIT) { \
+ erts_atomic_set_nob(&(NODE->u.base.lock_statistics), v + VALUE); \
+ } \
+ }while(0);
+#define BASE_NODE_STAT_SUB(NODE, VALUE) \
+ do { \
+ Sint v = erts_atomic_read_nob(&((NODE)->u.base.lock_statistics)); \
+ ASSERT(VALUE < 0); \
+ if(v > ERL_DB_CATREE_LOCK_LOW_NO_CONTRIBUTION_LIMIT) { \
+ erts_atomic_set_nob(&(NODE->u.base.lock_statistics), v + VALUE); \
+ } \
+ }while(0);
+
+
/* Compares a key to the key in a route node */
static ERTS_INLINE Sint cmp_key_route(Eterm key,
DbTableCATreeNode *obj)
@@ -653,10 +687,10 @@ static void dbg_provoke_random_splitjoin(DbTableCATree* tb,
switch (dbg_fastrand() % 8) {
case 1:
- base_node->u.base.lock_statistics = 1+ERL_DB_CATREE_HIGH_CONTENTION_LIMIT;
+ BASE_NODE_STAT_ADD(base_node, 1+ERL_DB_CATREE_HIGH_CONTENTION_LIMIT);
break;
case 2:
- base_node->u.base.lock_statistics = -1+ERL_DB_CATREE_LOW_CONTENTION_LIMIT;
+ BASE_NODE_STAT_SUB(base_node, -1+ERL_DB_CATREE_LOW_CONTENTION_LIMIT);
break;
}
}
@@ -664,6 +698,48 @@ static void dbg_provoke_random_splitjoin(DbTableCATree* tb,
# define dbg_provoke_random_splitjoin(T,N)
#endif /* PROVOKE_RANDOM_SPLIT_JOIN */
+static ERTS_NOINLINE
+void do_random_join(DbTableCATree* tb, Uint rand)
+{
+ DbTableCATreeNode* node = GET_ROOT_ACQB(tb);
+ DbTableCATreeNode* parent = NULL;
+ int level = 0;
+ Sint stat;
+ while (!node->is_base_node) {
+ parent = node;
+ if ((rand & (1 << level)) == 0) {
+ node = GET_LEFT_ACQB(node);
+ } else {
+ node = GET_RIGHT_ACQB(node);
+ }
+ level++;
+ }
+ BASE_NODE_STAT_SUB(node, ERL_DB_CATREE_LOCK_GRAVITY_CONTRIBUTION);
+ stat = BASE_NODE_STAT_READ(node);
+ if (stat >= ERL_DB_CATREE_LOW_CONTENTION_LIMIT &&
+ stat <= ERL_DB_CATREE_HIGH_CONTENTION_LIMIT) {
+ return; /* No adaptation */
+ }
+ if (parent != NULL && !try_wlock_base_node(&node->u.base)) {
+ if (!node->u.base.is_valid) {
+ wunlock_base_node(node);
+ return;
+ }
+ wunlock_adapt_base_node(tb, node, parent, level);
+ }
+}
+
+static ERTS_INLINE
+void do_random_join_with_low_probability(DbTableCATree* tb, Uint seed)
+{
+#ifndef ERTS_DB_CA_TREE_NO_RANDOM_JOIN_WITH_LOW_PROBABILITY
+ Uint32 rand = erts_sched_local_random(seed);
+ if (((rand & ERL_DB_CATREE_LOCK_GRAVITY_PATTERN)) == 0) {
+ do_random_join(tb, rand);
+ }
+#endif
+}
+
static ERTS_INLINE
int try_wlock_base_node(DbTableCATreeBaseNode *base_node)
{
@@ -691,9 +767,9 @@ void wlock_base_node(DbTableCATreeNode *base_node)
if (try_wlock_base_node(&base_node->u.base)) {
/* The lock is contended */
wlock_base_node_no_stats(base_node);
- base_node->u.base.lock_statistics += ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION;
+ BASE_NODE_STAT_ADD(base_node, ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION);
} else {
- base_node->u.base.lock_statistics += ERL_DB_CATREE_LOCK_SUCCESS_CONTRIBUTION;
+ BASE_NODE_STAT_SUB(base_node, ERL_DB_CATREE_LOCK_SUCCESS_CONTRIBUTION);
}
}
@@ -709,13 +785,14 @@ void wunlock_adapt_base_node(DbTableCATree* tb,
DbTableCATreeNode* parent,
int current_level)
{
+ Sint base_node_lock_stat = BASE_NODE_STAT_READ(node);
dbg_provoke_random_splitjoin(tb,node);
if ((!node->u.base.root && parent && !(tb->common.status
& DB_CATREE_FORCE_SPLIT))
- || node->u.base.lock_statistics < ERL_DB_CATREE_LOW_CONTENTION_LIMIT) {
+ || base_node_lock_stat < ERL_DB_CATREE_LOW_CONTENTION_LIMIT) {
join_catree(tb, node, parent);
}
- else if (node->u.base.lock_statistics > ERL_DB_CATREE_HIGH_CONTENTION_LIMIT
+ else if (base_node_lock_stat > ERL_DB_CATREE_HIGH_CONTENTION_LIMIT
&& current_level < ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT) {
split_catree(tb, node, parent);
}
@@ -728,11 +805,23 @@ static ERTS_INLINE
void rlock_base_node(DbTableCATreeNode *base_node)
{
ASSERT(base_node->is_base_node);
- erts_rwmtx_rlock(&base_node->u.base.lock);
+ if (EBUSY == erts_rwmtx_tryrlock(&base_node->u.base.lock)) {
+ /* The lock is contended */
+ BASE_NODE_STAT_ADD(base_node, ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION);
+ erts_rwmtx_rlock(&base_node->u.base.lock);
+ }
+}
+
+static ERTS_INLINE
+void runlock_base_node(DbTableCATreeNode *base_node, DbTableCATree* tb)
+{
+ ASSERT(base_node->is_base_node);
+ erts_rwmtx_runlock(&base_node->u.base.lock);
+ do_random_join_with_low_probability(tb, (Uint)base_node);
}
static ERTS_INLINE
-void runlock_base_node(DbTableCATreeNode *base_node)
+void runlock_base_node_no_rand(DbTableCATreeNode *base_node)
{
ASSERT(base_node->is_base_node);
erts_rwmtx_runlock(&base_node->u.base.lock);
@@ -814,7 +903,7 @@ void unlock_iter_base_node(CATreeRootIterator* iter)
{
ASSERT(iter->locked_bnode);
if (iter->read_only)
- runlock_base_node(iter->locked_bnode);
+ runlock_base_node(iter->locked_bnode, iter->tb);
else if (iter->locked_bnode->u.base.is_valid) {
wunlock_adapt_base_node(iter->tb, iter->locked_bnode,
iter->bnode_parent, iter->bnode_level);
@@ -874,7 +963,7 @@ DbTableCATreeNode* find_rlock_valid_base_node(DbTableCATree* tb, Eterm key)
rlock_base_node(base_node);
if (base_node->u.base.is_valid)
break;
- runlock_base_node(base_node);
+ runlock_base_node_no_rand(base_node);
}
return base_node;
}
@@ -923,8 +1012,8 @@ static DbTableCATreeNode *create_base_node(DbTableCATree *tb,
"erl_db_catree_base_node",
NIL,
ERTS_LOCK_FLAGS_CATEGORY_DB);
- p->u.base.lock_statistics = ((tb->common.status & DB_CATREE_FORCE_SPLIT)
- ? INT_MAX : 0);
+ BASE_NODE_STAT_SET(p, ((tb->common.status & DB_CATREE_FORCE_SPLIT)
+ ? INT_MAX : 0));
p->u.base.is_valid = 1;
return p;
}
@@ -1094,7 +1183,7 @@ static void join_catree(DbTableCATree *tb,
ASSERT(thiz->is_base_node);
if (parent == NULL) {
- thiz->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(thiz, 0);
wunlock_base_node(thiz);
return;
}
@@ -1103,11 +1192,11 @@ static void join_catree(DbTableCATree *tb,
neighbor = leftmost_base_node(GET_RIGHT_ACQB(parent));
if (try_wlock_base_node(&neighbor->u.base)) {
/* Failed to acquire lock */
- thiz->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(thiz, 0);
wunlock_base_node(thiz);
return;
} else if (!neighbor->u.base.is_valid) {
- thiz->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(thiz, 0);
wunlock_base_node(thiz);
wunlock_base_node(neighbor);
return;
@@ -1153,11 +1242,11 @@ static void join_catree(DbTableCATree *tb,
neighbor = rightmost_base_node(GET_LEFT_ACQB(parent));
if (try_wlock_base_node(&neighbor->u.base)) {
/* Failed to acquire lock */
- thiz->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(thiz, 0);
wunlock_base_node(thiz);
return;
} else if (!neighbor->u.base.is_valid) {
- thiz->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(thiz, 0);
wunlock_base_node(thiz);
wunlock_base_node(neighbor);
return;
@@ -1241,7 +1330,7 @@ static void split_catree(DbTableCATree *tb,
if (less_than_two_elements(base->u.base.root)) {
if (!(tb->common.status & DB_CATREE_FORCE_SPLIT))
- base->u.base.lock_statistics = 0;
+ BASE_NODE_STAT_SET(base, 0);
wunlock_base_node(base);
return;
} else {
@@ -1521,7 +1610,7 @@ static int db_get_catree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
int result = db_get_tree_common(p, &tb->common,
node->u.base.root,
key, ret, NULL);
- runlock_base_node(node);
+ runlock_base_node(node, tb);
return result;
}
@@ -1804,7 +1893,7 @@ static int db_member_catree(DbTable *tbl, Eterm key, Eterm *ret)
int result = db_member_tree_common(&tb->common,
node->u.base.root,
key, ret, NULL);
- runlock_base_node(node);
+ runlock_base_node(node, tb);
return result;
}
@@ -1816,7 +1905,7 @@ static int db_get_element_catree(Process *p, DbTable *tbl,
int result = db_get_element_tree_common(p, &tb->common,
node->u.base.root,
key, ndex, ret, NULL);
- runlock_base_node(node);
+ runlock_base_node(node, tb);
return result;
}
@@ -2250,7 +2339,7 @@ void db_catree_force_split(DbTableCATree* tb, int on)
init_root_iterator(tb, &iter, 1);
root = catree_find_first_root(&iter);
do {
- iter.locked_bnode->u.base.lock_statistics = (on ? INT_MAX : 0);
+ BASE_NODE_STAT_SET(iter.locked_bnode, (on ? INT_MAX : 0));
root = catree_find_next_root(&iter, NULL);
} while (root);
destroy_root_iterator(&iter);
@@ -2306,6 +2395,34 @@ void db_calc_stats_catree(DbTableCATree* tb, DbCATreeStats* stats)
} while (depth > 0);
}
+struct debug_catree_fa {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_free_route_node(void *vfap, ErtsThrPrgrVal val, void *vnp)
+{
+ DbTableCATreeNode *np = vnp;
+ if (np->u.route.key.oh) {
+ struct debug_catree_fa *fap = vfap;
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = np->u.route.key.oh;
+ (*fap->func)(&oh, fap->arg);
+ }
+}
+
+void
+erts_db_foreach_thr_prgr_offheap_catree(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+ struct debug_catree_fa fa;
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(do_free_route_node, debug_free_route_node, &fa);
+}
+
+
#ifdef HARDDEBUG
/*
diff --git a/erts/emulator/beam/erl_db_catree.h b/erts/emulator/beam/erl_db_catree.h
index cf3498dabb..2ede85e04e 100644
--- a/erts/emulator/beam/erl_db_catree.h
+++ b/erts/emulator/beam/erl_db_catree.h
@@ -42,7 +42,7 @@ typedef struct {
typedef struct {
erts_rwmtx_t lock; /* The lock for this base node */
- Sint lock_statistics;
+ erts_atomic_t lock_statistics;
int is_valid; /* If this base node is still valid */
TreeDbTerm *root; /* The root of the sequential tree */
ErtsThrPrgrLaterOp free_item; /* Used when freeing using thread progress */
@@ -132,6 +132,9 @@ typedef struct {
Uint max_depth;
} DbCATreeStats;
void db_calc_stats_catree(DbTableCATree*, DbCATreeStats*);
+void
+erts_db_foreach_thr_prgr_offheap_catree(void (*func)(ErlOffHeap *, void *),
+ void *arg);
#endif /* _DB_CATREE_H */
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index ceaccf7e44..4904d3fa42 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -3262,6 +3262,12 @@ Eterm erts_ets_hash_sizeof_ext_segtab(void)
return make_small(((SIZEOF_EXT_SEGTAB(0)-1) / sizeof(UWord)) + 1);
}
+void
+erts_db_foreach_thr_prgr_offheap_hash(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+}
+
#ifdef ERTS_ENABLE_LOCK_COUNT
void erts_lcnt_enable_db_hash_lock_count(DbTableHash *tb, int enable) {
int i;
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index eae5537ba4..9759d8b466 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -110,6 +110,9 @@ typedef struct {
void db_calc_stats_hash(DbTableHash* tb, DbHashStats*);
Eterm erts_ets_hash_sizeof_ext_segtab(void);
+void
+erts_db_foreach_thr_prgr_offheap_hash(void (*func)(ErlOffHeap *, void *),
+ void *arg);
#ifdef ERTS_ENABLE_LOCK_COUNT
void erts_lcnt_enable_db_hash_lock_count(DbTableHash *tb, int enable);
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 492ea81b63..19b94b0634 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -3936,6 +3936,12 @@ static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
return 1;
}
+void
+erts_db_foreach_thr_prgr_offheap_tree(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+}
+
#ifdef TREE_DEBUG
static void do_dump_tree2(DbTableCommon* tb, int to, void *to_arg, int show,
TreeDbTerm *t, int offset)
diff --git a/erts/emulator/beam/erl_db_tree.h b/erts/emulator/beam/erl_db_tree.h
index 54da2a6bc1..06e0005801 100644
--- a/erts/emulator/beam/erl_db_tree.h
+++ b/erts/emulator/beam/erl_db_tree.h
@@ -53,4 +53,8 @@ void db_initialize_tree(void);
int db_create_tree(Process *p, DbTable *tbl);
+void
+erts_db_foreach_thr_prgr_offheap_tree(void (*func)(ErlOffHeap *, void *),
+ void *arg);
+
#endif /* _DB_TREE_H */
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 67a73e4d57..13b1f8ab4d 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -151,6 +151,7 @@ static void grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj);
static void sweep_off_heap(Process *p, int fullsweep);
static void offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
static void offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
+static void offset_heap_ptr_nstack(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
Eterm* objv, int nobj);
static void offset_off_heap(Process* p, Sint offs, char* area, Uint area_size);
@@ -1054,9 +1055,10 @@ erts_garbage_collect_hibernate(Process* p)
n_htop = tmp_n_htop; \
} while(0)
+
/*
* offset_nstack() can ignore the descriptor-based traversal the other
- * nstack procedures use and simply call offset_heap_ptr() instead.
+ * nstack procedures use and do a simpler word by word traversal instead.
* This relies on two facts:
* 1. The only live non-Erlang terms on an nstack are return addresses,
* and they will be skipped thanks to the low/high range check.
@@ -1071,14 +1073,51 @@ static ERTS_INLINE void offset_nstack(Process* p, Sint offs,
{
if (p->hipe.nstack) {
ASSERT(p->hipe.nsp && p->hipe.nstend);
- offset_heap_ptr(hipe_nstack_start(p), hipe_nstack_used(p),
- offs, area, area_size);
+ offset_heap_ptr_nstack(hipe_nstack_start(p), hipe_nstack_used(p),
+ offs, area, area_size);
}
else {
ASSERT(!p->hipe.nsp && !p->hipe.nstend);
}
}
+/*
+ * This is the same as offset_heap_ptr()
+ *
+ * Except for VALGRIND. It allows benign offsetting of undefined (dead) words
+ * on the nstack while also retaining them as undefined. This suppresses
+ * valgrinds "Conditional jump or move depends on uninitialised value(s)".
+ */
+static void
+offset_heap_ptr_nstack(Eterm* hp, Uint sz, Sint offs,
+ char* area, Uint area_size)
+{
+ while (sz--) {
+ Eterm val = *hp;
+#ifdef VALGRIND
+ Eterm val_vbits;
+ VALGRIND_GET_VBITS(&val, &val_vbits, sizeof(val));
+ VALGRIND_MAKE_MEM_DEFINED(&val, sizeof(val));
+#endif
+ switch (primary_tag(val)) {
+ case TAG_PRIMARY_LIST:
+ case TAG_PRIMARY_BOXED:
+ if (ErtsInArea(ptr_val(val), area, area_size)) {
+#ifdef VALGRIND
+ VALGRIND_SET_VBITS(&val, val_vbits, sizeof(val));
+#endif
+ *hp = offset_ptr(val, offs);
+ }
+ hp++;
+ break;
+ default:
+ hp++;
+ break;
+ }
+ }
+}
+
+
#else /* !HIPE */
#define fullsweep_nstack(p,n_htop) (n_htop)
@@ -2848,7 +2887,7 @@ sweep_off_heap(Process *p, int fullsweep)
if (is_external_header(((struct erl_off_heap_header*) boxed_val(ptr->thing_word))->thing_word))
erts_node_bookkeep(((ExternalThing*)ptr)->node,
make_boxed(&ptr->thing_word),
- ERL_NODE_DEC);
+ ERL_NODE_DEC, __FILE__, __LINE__);
*prev = ptr = (struct erl_off_heap_header*) boxed_val(ptr->thing_word);
ASSERT(!IS_MOVED_BOXED(ptr->thing_word));
switch (ptr->thing_word) {
@@ -2879,7 +2918,7 @@ sweep_off_heap(Process *p, int fullsweep)
if (is_external_header(ptr->thing_word)) {
erts_node_bookkeep(((ExternalThing*)ptr)->node,
make_boxed(&ptr->thing_word),
- ERL_NODE_INC);
+ ERL_NODE_INC, __FILE__, __LINE__);
}
prev = &ptr->next;
ptr = ptr->next;
@@ -3050,9 +3089,11 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
if (is_external_header(oh->thing_word)) {
erts_node_bookkeep(((ExternalThing*)oh)->node,
- make_boxed(((Eterm*)oh)-offs), ERL_NODE_DEC);
+ make_boxed(((Eterm*)oh)-offs),
+ ERL_NODE_DEC, __FILE__, __LINE__);
erts_node_bookkeep(((ExternalThing*)oh)->node,
- make_boxed((Eterm*)oh), ERL_NODE_INC);
+ make_boxed((Eterm*)oh), ERL_NODE_INC,
+ __FILE__, __LINE__);
}
if (ErtsInArea(oh->next, area, area_size)) {
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 6645341512..1bebf6efe2 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -527,7 +527,7 @@ erts_msg_attached_data_size_aux(ErtsMessage *msg)
if (edep->heap_size < 0) {
- sz = erts_decode_dist_ext_size(edep, 1);
+ sz = erts_decode_dist_ext_size(edep, 1, 1);
if (sz < 0) {
/* Bad external
* We leave the message intact in this case as it's not worth the trouble
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c
index 1c6b4afaa3..43028be39d 100644
--- a/erts/emulator/beam/erl_monitor_link.c
+++ b/erts/emulator/beam/erl_monitor_link.c
@@ -671,6 +671,24 @@ erts_monitor_tree_foreach(ErtsMonitor *root,
arg);
}
+void
+erts_debug_monitor_tree_destroying_foreach(ErtsMonitor *root,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE,
+ sizeof(ErtsMonLnkYieldState));
+ Sint reds;
+ sys_memcpy(tmp_vysp, tmp_vysp, sizeof(ErtsMonLnkYieldState));
+ do {
+ reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root,
+ (ErtsMonLnkNodeFunc) func,
+ arg, &tmp_vysp, (Sint) INT_MAX);
+ } while (reds <= 0);
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_monitor_tree_foreach_yielding(ErtsMonitor *root,
ErtsMonitorFunc func,
@@ -716,6 +734,19 @@ erts_monitor_list_foreach(ErtsMonitor *list,
arg, &ystate, (Sint) INT_MAX));
}
+void
+erts_debug_monitor_list_destroying_foreach(ErtsMonitor *list,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = vysp;
+ while (!ml_dl_list_foreach_yielding((ErtsMonLnkNode *) list,
+ (int (*)(ErtsMonLnkNode *, void *, Sint)) func,
+ arg, &tmp_vysp, (Sint) INT_MAX));
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_monitor_list_foreach_yielding(ErtsMonitor *list,
ErtsMonitorFunc func,
@@ -1080,6 +1111,24 @@ erts_link_tree_foreach(ErtsLink *root,
}
+void
+erts_debug_link_tree_destroying_foreach(ErtsLink *root,
+ ErtsLinkFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE,
+ sizeof(ErtsMonLnkYieldState));
+ Sint reds;
+ sys_memcpy(tmp_vysp, vysp, sizeof(ErtsMonLnkYieldState));
+ do {
+ reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root,
+ (ErtsMonLnkNodeFunc) func,
+ arg, &tmp_vysp, (Sint) INT_MAX);
+ } while (reds <= 0);
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_link_tree_foreach_yielding(ErtsLink *root,
ErtsLinkFunc func,
diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h
index eff861fce8..86be400c09 100644
--- a/erts/emulator/beam/erl_monitor_link.h
+++ b/erts/emulator/beam/erl_monitor_link.h
@@ -1509,6 +1509,17 @@ ERTS_GLB_INLINE ErtsMonitorSuspend *erts_monitor_suspend(ErtsMonitor *mon)
#endif
+void
+erts_debug_monitor_tree_destroying_foreach(ErtsMonitor *root,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp);
+void
+erts_debug_monitor_list_destroying_foreach(ErtsMonitor *list,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp);
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Link Operations *
\* */
@@ -2365,4 +2376,10 @@ erts_link_dist_delete(ErtsLink *lnk)
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
+void
+erts_debug_link_tree_destroying_foreach(ErtsLink *root,
+ ErtsLinkFunc func,
+ void *arg,
+ void *vysp);
+
#endif /* ERL_MONITOR_LINK_H__ */
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 4eb6c3e214..50e9812534 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -932,7 +932,8 @@ static void try_delete_node(void *venp)
*
* If refc > 0, the entry is in use. Keep the entry.
*/
- erts_node_bookkeep(enp, THE_NON_VALUE, ERL_NODE_DEC);
+ erts_node_bookkeep(enp, THE_NON_VALUE, ERL_NODE_DEC,
+ __FILE__, __LINE__);
refc = erts_refc_dectest(&enp->refc, -1);
if (refc == -1)
(void) hash_erase(&erts_node_table, (void *) enp);
@@ -1164,6 +1165,12 @@ void erts_lcnt_update_distribution_locks(int enable) {
* can damage the real-time properties of the system. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#ifdef ERL_NODE_BOOKKEEP
+#define ERTS_DBG_NC_ALLOC_TYPE ERTS_ALC_T_NC_STD
+#else
+#define ERTS_DBG_NC_ALLOC_TYPE ERTS_ALC_T_NC_TMP
+#endif
+
#include "erl_db.h"
#undef INIT_AM
@@ -1188,10 +1195,12 @@ static Eterm AM_delayed_delete_timer;
static Eterm AM_thread_progress_delete_timer;
static Eterm AM_sequence;
static Eterm AM_signal;
+static Eterm AM_persistent_term;
static void setup_reference_table(void);
static Eterm reference_table_term(Uint **hpp, ErlOffHeap *ohp, Uint *szp);
static void delete_reference_table(void);
+static void clear_system(void);
#undef ERTS_MAX__
#define ERTS_MAX__(A, B) ((A) > (B) ? (A) : (B))
@@ -1244,11 +1253,11 @@ typedef struct inserted_bin_ {
Binary *bin_val;
} InsertedBin;
-static ReferredNode *referred_nodes;
+static ReferredNode *referred_nodes = NULL;
static int no_referred_nodes;
-static ReferredDist *referred_dists;
+static ReferredDist *referred_dists = NULL;
static int no_referred_dists;
-static InsertedBin *inserted_bins;
+static InsertedBin *inserted_bins = NULL;
Eterm
erts_get_node_and_dist_references(struct process *proc)
@@ -1284,9 +1293,15 @@ erts_get_node_and_dist_references(struct process *proc)
INIT_AM(thread_progress_delete_timer);
INIT_AM(signal);
INIT_AM(sequence);
+ INIT_AM(persistent_term);
references_atoms_need_init = 0;
}
+#ifdef ERL_NODE_BOOKKEEP
+ if (referred_nodes || referred_dists || inserted_bins)
+ delete_reference_table();
+#endif
+
setup_reference_table();
/* Get term size */
@@ -1304,7 +1319,11 @@ erts_get_node_and_dist_references(struct process *proc)
ASSERT(endp == hp);
+#ifndef ERL_NODE_BOOKKEEP
delete_reference_table();
+#endif
+
+ clear_system();
erts_thr_progress_unblock();
erts_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
@@ -1339,7 +1358,7 @@ insert_dist_referrer(ReferredDist *referred_dist,
break;
if(!drp) {
- drp = (DistReferrer *) erts_alloc(ERTS_ALC_T_NC_TMP,
+ drp = (DistReferrer *) erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
sizeof(DistReferrer));
drp->next = referred_dist->referrers;
referred_dist->referrers = drp;
@@ -1402,7 +1421,7 @@ insert_node_referrer(ReferredNode *referred_node, int type, Eterm id)
break;
if(!nrp) {
- nrp = (NodeReferrer *) erts_alloc(ERTS_ALC_T_NC_TMP,
+ nrp = (NodeReferrer *) erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
sizeof(NodeReferrer));
nrp->next = referred_node->referrers;
ERTS_INIT_OFF_HEAP(&nrp->off_heap);
@@ -1516,7 +1535,8 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id)
erts_match_prog_foreach_offheap((Binary *) u.mref->mb,
insert_offheap2,
(void *) &a);
- nib = erts_alloc(ERTS_ALC_T_NC_TMP, sizeof(InsertedBin));
+ nib = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
+ sizeof(InsertedBin));
nib->bin_val = (Binary *) u.mref->mb;
nib->next = inserted_bins;
inserted_bins = nib;
@@ -1574,18 +1594,6 @@ static int clear_visited_monitor(ErtsMonitor *mon, void *p, Sint reds)
}
static void
-insert_p_monitors(ErtsPTabElementCommon *p)
-{
- Eterm id = p->id;
- erts_monitor_tree_foreach(p->u.alive.monitors,
- insert_monitor,
- (void *) &id);
- erts_monitor_list_foreach(p->u.alive.lt_monitors,
- insert_monitor,
- (void *) &id);
-}
-
-static void
insert_dist_monitors(DistEntry *dep)
{
if (dep->mld) {
@@ -1600,8 +1608,10 @@ insert_dist_monitors(DistEntry *dep)
static int
-insert_sequence(ErtsDistExternal *edep, void *arg, Sint reds)
+insert_sequence(DistSeqNode *seq, void *arg, Sint reds)
{
+ ErtsDistExternal *edep = erts_get_dist_ext(&seq->hfrag);
+ insert_offheap(&seq->hfrag.off_heap, SEQUENCE_REF, *(Eterm*)arg);
insert_dist_entry(edep->dep, SEQUENCE_REF, *(Eterm*)arg, 0);
return 1;
}
@@ -1609,18 +1619,7 @@ insert_sequence(ErtsDistExternal *edep, void *arg, Sint reds)
static void
insert_dist_sequences(DistEntry *dep)
{
- erts_dist_seq_tree_foreach(dep, insert_sequence, (void *) &dep->sysname);
-}
-
-static void
-clear_visited_p_monitors(ErtsPTabElementCommon *p)
-{
- erts_monitor_tree_foreach(p->u.alive.monitors,
- clear_visited_monitor,
- NULL);
- erts_monitor_list_foreach(p->u.alive.lt_monitors,
- clear_visited_monitor,
- NULL);
+ erts_debug_dist_seq_tree_foreach(dep, insert_sequence, (void *) &dep->sysname);
}
static void
@@ -1667,13 +1666,6 @@ static int clear_visited_link(ErtsLink *lnk, void *p, Sint reds)
}
static void
-insert_p_links(ErtsPTabElementCommon *p)
-{
- Eterm id = p->id;
- erts_link_tree_foreach(p->u.alive.links, insert_link, (void *) &id);
-}
-
-static void
insert_dist_links(DistEntry *dep)
{
if (dep->mld)
@@ -1683,14 +1675,6 @@ insert_dist_links(DistEntry *dep)
}
static void
-clear_visited_p_links(ErtsPTabElementCommon *p)
-{
- erts_link_tree_foreach(p->u.alive.links,
- clear_visited_link,
- NULL);
-}
-
-static void
clear_visited_dist_links(DistEntry *dep)
{
if (dep->mld)
@@ -1885,15 +1869,11 @@ insert_process(Process *proc)
insert_sig_ext,
(void *) proc);
- /* If the process is FREE, the proc->common field has been
- re-used by the ptab delete, so we cannot trust it. */
- if (!(erts_atomic32_read_nob(&proc->state) & ERTS_PSFLG_FREE)) {
- /* Insert links */
- insert_p_links(&proc->common);
-
- /* Insert monitors */
- insert_p_monitors(&proc->common);
- }
+ /* Insert monitors and links... */
+ erts_debug_proc_monitor_link_foreach(proc,
+ insert_monitor,
+ insert_link,
+ (void *) &proc->common.id);
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc);
@@ -1906,6 +1886,12 @@ insert_process(Process *proc)
}
static void
+insert_process2(Process *proc, void *arg)
+{
+ insert_process(proc);
+}
+
+static void
insert_dist_suspended_procs(DistEntry *dep)
{
ErtsProcList *plist = erts_proclist_peek_first(dep->suspended);
@@ -1916,16 +1902,47 @@ insert_dist_suspended_procs(DistEntry *dep)
}
}
+static void clear_process(Process *proc);
+
+static void
+clear_dist_suspended_procs(DistEntry *dep)
+{
+ ErtsProcList *plist = erts_proclist_peek_first(dep->suspended);
+ while (plist) {
+ if (is_not_immed(plist->u.pid))
+ clear_process(plist->u.p);
+ plist = erts_proclist_peek_next(dep->suspended, plist);
+ }
+}
+
+static void
+insert_persistent_term(ErlOffHeap *ohp, void *arg)
+{
+ Eterm heap[3];
+ insert_offheap(ohp, SYSTEM_REF,
+ TUPLE2(&heap[0], AM_system, AM_persistent_term));
+}
+
+static void
+insert_ets_offheap_thr_prgr(ErlOffHeap *ohp, void *arg)
+{
+ Eterm heap[3];
+ insert_offheap(ohp, ETS_REF,
+ TUPLE2(&heap[0], AM_system, AM_ets));
+}
+
#ifdef ERL_NODE_BOOKKEEP
void
-erts_node_bookkeep(ErlNode *np, Eterm term, int what)
+erts_node_bookkeep(ErlNode *np, Eterm term, int what, char *f, int l)
{
- erts_aint_t slot = (erts_atomic_inc_read_nob(&np->slot) - 1) % 1024;
+ erts_aint_t slot = (erts_atomic_inc_read_nob(&np->slot) - 1) % ERTS_BOOKKEEP_SIZE;
ErtsSchedulerData *esdp = erts_get_scheduler_data();
Eterm who = THE_NON_VALUE;
ASSERT(np);
np->books[slot].what = what;
np->books[slot].term = term;
+ np->books[slot].file = f;
+ np->books[slot].line = l;
if (esdp->current_process) {
who = esdp->current_process->common.id;
} else if (esdp->current_port) {
@@ -1946,14 +1963,14 @@ setup_reference_table(void)
inserted_bins = NULL;
hash_get_info(&hi, &erts_node_table);
- referred_nodes = erts_alloc(ERTS_ALC_T_NC_TMP,
+ referred_nodes = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
hi.objs*sizeof(ReferredNode));
no_referred_nodes = 0;
hash_foreach(&erts_node_table, init_referred_node, NULL);
ASSERT(no_referred_nodes == hi.objs);
hash_get_info(&hi, &erts_dist_table);
- referred_dists = erts_alloc(ERTS_ALC_T_NC_TMP,
+ referred_dists = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
hi.objs*sizeof(ReferredDist));
no_referred_dists = 0;
hash_foreach(&erts_dist_table, init_referred_dist, NULL);
@@ -1990,8 +2007,9 @@ setup_reference_table(void)
if (proc)
insert_process(proc);
}
+ erts_debug_free_process_foreach(insert_process2, NULL);
- erts_foreach_sys_msg_in_q(insert_sys_msg);
+ erts_debug_foreach_sys_msg_in_q(insert_sys_msg);
/* Insert all ports */
max = erts_ptab_max(&erts_port);
@@ -2008,10 +2026,18 @@ setup_reference_table(void)
if (state & ERTS_PORT_SFLGS_DEAD)
continue;
- /* Insert links */
- insert_p_links(&prt->common);
- /* Insert monitors */
- insert_p_monitors(&prt->common);
+ /* Insert links */
+ erts_link_tree_foreach(ERTS_P_LINKS(prt),
+ insert_link,
+ (void *) &prt->common.id);
+ /* Insert monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(prt),
+ insert_monitor,
+ (void *) &prt->common.id);
+ /* Insert local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(prt),
+ insert_monitor,
+ (void *) &prt->common.id);
/* Insert port data */
ohp = erts_port_data_offheap(prt);
if (ohp)
@@ -2091,11 +2117,16 @@ setup_reference_table(void)
}
/* Insert all ets tables */
- erts_db_foreach_table(insert_ets_table, NULL);
+ erts_db_foreach_table(insert_ets_table, NULL, 0);
+ erts_db_foreach_thr_prgr_offheap(insert_ets_offheap_thr_prgr, NULL);
/* Insert all bif timers */
erts_debug_bif_timer_foreach(insert_bif_timer, NULL);
+ /* Insert persistent term storage */
+ erts_debug_foreach_persistent_term_off_heap(insert_persistent_term,
+ NULL);
+
/* Insert node table (references to dist) */
hash_foreach(&erts_node_table, insert_erl_node, NULL);
}
@@ -2348,8 +2379,7 @@ static void noop_sig_ext(ErtsDistExternal *ext, void *arg)
static void
delete_reference_table(void)
{
- DistEntry *dep;
- int i, max;
+ int i;
for(i = 0; i < no_referred_nodes; i++) {
NodeReferrer *nrp;
NodeReferrer *tnrp;
@@ -2358,11 +2388,13 @@ delete_reference_table(void)
erts_cleanup_offheap(&nrp->off_heap);
tnrp = nrp;
nrp = nrp->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *) tnrp);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) tnrp);
}
}
- if (referred_nodes)
- erts_free(ERTS_ALC_T_NC_TMP, (void *) referred_nodes);
+ if (referred_nodes) {
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) referred_nodes);
+ referred_nodes = NULL;
+ }
for(i = 0; i < no_referred_dists; i++) {
DistReferrer *drp;
@@ -2371,34 +2403,57 @@ delete_reference_table(void)
while(drp) {
tdrp = drp;
drp = drp->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *) tdrp);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) tdrp);
}
}
- if (referred_dists)
- erts_free(ERTS_ALC_T_NC_TMP, (void *) referred_dists);
+ if (referred_dists) {
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) referred_dists);
+ referred_dists = NULL;
+ }
while(inserted_bins) {
InsertedBin *ib = inserted_bins;
inserted_bins = inserted_bins->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *)ib);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *)ib);
}
+}
+
+static void clear_process(Process *proc)
+{
+ erts_proc_sig_debug_foreach_sig(proc,
+ noop_sig_msg,
+ noop_sig_offheap,
+ clear_visited_monitor,
+ clear_visited_link,
+ noop_sig_ext,
+ (void *) proc);
+
+
+ /* Clear monitors and links... */
+ erts_debug_proc_monitor_link_foreach(proc,
+ clear_visited_monitor,
+ clear_visited_link,
+ (void *) &proc->common.id);
+}
+
+static void clear_process2(Process *proc, void *arg)
+{
+ clear_process(proc);
+}
- /* Cleanup... */
+static void
+clear_system(void)
+{
+ DistEntry *dep;
+ int i, max;
+ /* Clear... */
max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
Process *proc = erts_pix2proc(i);
- if (proc) {
- clear_visited_p_links(&proc->common);
- clear_visited_p_monitors(&proc->common);
- erts_proc_sig_debug_foreach_sig(proc,
- noop_sig_msg,
- noop_sig_offheap,
- clear_visited_monitor,
- clear_visited_link,
- noop_sig_ext,
- (void *) proc);
- }
+ if (proc)
+ clear_process(proc);
}
+ erts_debug_free_process_foreach(clear_process2, NULL);
max = erts_ptab_max(&erts_port);
for (i = 0; i < max; i++) {
@@ -2413,28 +2468,42 @@ delete_reference_table(void)
if (state & ERTS_PORT_SFLGS_DEAD)
continue;
- clear_visited_p_links(&prt->common);
- clear_visited_p_monitors(&prt->common);
+ /* Clear links */
+ erts_link_tree_foreach(ERTS_P_LINKS(prt),
+ clear_visited_link,
+ (void *) &prt->common.id);
+ /* Clear monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(prt),
+ clear_visited_monitor,
+ (void *) &prt->common.id);
+ /* Clear local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(prt),
+ clear_visited_monitor,
+ (void *) &prt->common.id);
}
for(dep = erts_visible_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_hidden_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_pending_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_not_connected_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
}
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index aa8af12555..ffaafbbbea 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -187,6 +187,7 @@ set pagination off
set $i = 0
set $node = referred_nodes[$node_ix].node
while $i < $node->slot.counter
+ printf "%s:%d ", $node->books[$i].file, $node->books[$i].line
printf "%p: ", $node->books[$i].term
etp-1 $node->books[$i].who
printf " "
@@ -211,8 +212,12 @@ lists:usort(lists:filter(fun({V,N}) -> N /= 0 end, maps:to_list(Accs))).
struct erl_node_bookkeeping {
Eterm who;
Eterm term;
+ char *file;
+ int line;
enum { ERL_NODE_INC, ERL_NODE_DEC } what;
};
+
+#define ERTS_BOOKKEEP_SIZE (1024)
#endif
typedef struct erl_node_ {
@@ -222,7 +227,7 @@ typedef struct erl_node_ {
Uint32 creation; /* Creation */
DistEntry *dist_entry; /* Corresponding dist entry */
#ifdef ERL_NODE_BOOKKEEP
- struct erl_node_bookkeeping books[1024];
+ struct erl_node_bookkeeping books[ERTS_BOOKKEEP_SIZE];
erts_atomic_t slot;
#endif
} ErlNode;
@@ -276,14 +281,21 @@ Eterm erts_build_dhandle(Eterm **hpp, ErlOffHeap*, DistEntry*, Uint32 conn_id);
Eterm erts_make_dhandle(Process *c_p, DistEntry*, Uint32 conn_id);
ERTS_GLB_INLINE void erts_init_node_entry(ErlNode *np, erts_aint_t val);
+#ifdef ERL_NODE_BOOKKEEP
+#define erts_ref_node_entry(NP, MIN, T) erts_ref_node_entry__((NP), (MIN), (T), __FILE__, __LINE__)
+#define erts_deref_node_entry(NP, T) erts_deref_node_entry__((NP), (T), __FILE__, __LINE__)
+ERTS_GLB_INLINE erts_aint_t erts_ref_node_entry__(ErlNode *np, int min_val, Eterm term, char *file, int line);
+ERTS_GLB_INLINE void erts_deref_node_entry__(ErlNode *np, Eterm term, char *file, int line);
+#else
ERTS_GLB_INLINE erts_aint_t erts_ref_node_entry(ErlNode *np, int min_val, Eterm term);
ERTS_GLB_INLINE void erts_deref_node_entry(ErlNode *np, Eterm term);
+#endif
ERTS_GLB_INLINE void erts_de_rlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_runlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_rwlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_rwunlock(DistEntry *dep);
#ifdef ERL_NODE_BOOKKEEP
-void erts_node_bookkeep(ErlNode *, Eterm , int);
+void erts_node_bookkeep(ErlNode *, Eterm , int, char *file, int line);
#else
#define erts_node_bookkeep(...)
#endif
@@ -296,21 +308,40 @@ erts_init_node_entry(ErlNode *np, erts_aint_t val)
erts_refc_init(&np->refc, val);
}
+#ifdef ERL_NODE_BOOKKEEP
+
+ERTS_GLB_INLINE erts_aint_t
+erts_ref_node_entry__(ErlNode *np, int min_val, Eterm term, char *file, int line)
+{
+ erts_node_bookkeep(np, term, ERL_NODE_INC, file, line);
+ return erts_refc_inctest(&np->refc, min_val);
+}
+
+ERTS_GLB_INLINE void
+erts_deref_node_entry__(ErlNode *np, Eterm term, char *file, int line)
+{
+ erts_node_bookkeep(np, term, ERL_NODE_DEC, file, line);
+ if (erts_refc_dectest(&np->refc, 0) == 0)
+ erts_schedule_delete_node(np);
+}
+
+#else
+
ERTS_GLB_INLINE erts_aint_t
erts_ref_node_entry(ErlNode *np, int min_val, Eterm term)
{
- erts_node_bookkeep(np, term, ERL_NODE_INC);
return erts_refc_inctest(&np->refc, min_val);
}
ERTS_GLB_INLINE void
erts_deref_node_entry(ErlNode *np, Eterm term)
{
- erts_node_bookkeep(np, term, ERL_NODE_DEC);
if (erts_refc_dectest(&np->refc, 0) == 0)
erts_schedule_delete_node(np);
}
+#endif
+
ERTS_GLB_INLINE void
erts_de_rlock(DistEntry *dep)
{
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 2e33a8a782..67c486a0db 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -533,13 +533,34 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) {
case EXPORT_DEF:
{
Export* ep = *((Export **) (export_val(wobj) + 1));
- Atom* module = atom_tab(atom_val(ep->info.mfa.module));
- Atom* name = atom_tab(atom_val(ep->info.mfa.function));
+ long tdcount;
+ int tres;
PRINT_STRING(res, fn, arg, "fun ");
- PRINT_BUF(res, fn, arg, module->name, module->len);
+
+ /* We pass a temporary 'dcount' and adjust the real one later to ensure
+ * that the fun doesn't get split up between the module and function
+ * name. */
+ tdcount = MAX_ATOM_SZ_LIMIT;
+ tres = print_atom_name(fn, arg, ep->info.mfa.module, &tdcount);
+ if (tres < 0) {
+ res = tres;
+ goto L_done;
+ }
+ *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount);
+ res += tres;
+
PRINT_CHAR(res, fn, arg, ':');
- PRINT_BUF(res, fn, arg, name->name, name->len);
+
+ tdcount = MAX_ATOM_SZ_LIMIT;
+ tres = print_atom_name(fn, arg, ep->info.mfa.function, &tdcount);
+ if (tres < 0) {
+ res = tres;
+ goto L_done;
+ }
+ *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount);
+ res += tres;
+
PRINT_CHAR(res, fn, arg, '/');
PRINT_SWORD(res, fn, arg, 'd', 0, 1,
(ErlPfSWord) ep->info.mfa.arity);
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index f58a606d57..d5e0e3b218 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3028,7 +3028,7 @@ erts_proc_sig_decode_dist(Process *proc, ErtsProcLocks proc_locks,
if (edep->heap_size >= 0)
need = edep->heap_size;
else {
- need = erts_decode_dist_ext_size(edep, 1);
+ need = erts_decode_dist_ext_size(edep, 1, 1);
if (need < 0) {
/* bad signal; remove it... */
return 0;
@@ -4051,6 +4051,7 @@ erts_proc_sig_signal_size(ErtsSignal *sig)
case ERTS_MON_TYPE_DIST_PROC:
case ERTS_MON_TYPE_NODE:
size = erts_monitor_size((ErtsMonitor *) sig);
+ break;
default:
ERTS_INTERNAL_ERROR("Unexpected sig type");
break;
@@ -4688,10 +4689,12 @@ erts_proc_sig_debug_foreach_sig(Process *c_p,
case ERTS_SIG_Q_OP_MONITOR_DOWN:
switch (type) {
case ERTS_SIG_Q_TYPE_GEN_EXIT:
- if (ERTS_SIG_IS_GEN_EXIT_EXTERNAL(sig))
- debug_foreach_sig_external(sig, ext_func, arg);
- else
+ if (!ERTS_SIG_IS_GEN_EXIT_EXTERNAL(sig))
debug_foreach_sig_heap_frags(&sig->hfrag, oh_func, arg);
+ else {
+ oh_func(&sig->hfrag.off_heap, arg);
+ debug_foreach_sig_external(sig, ext_func, arg);
+ }
break;
case ERTS_LNK_TYPE_PORT:
case ERTS_LNK_TYPE_PROC:
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 1f6adb98ef..1c1ef1db84 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -8568,9 +8568,6 @@ erts_start_schedulers(void)
{
ethr_tid tid;
int res = 0;
- Uint actual;
- Uint wanted = erts_no_schedulers;
- Uint wanted_no_schedulers = erts_no_schedulers;
char name[16];
ethr_thr_opts opts = ETHR_THR_OPTS_DEFAULT_INITER;
int ix;
@@ -8584,40 +8581,34 @@ erts_start_schedulers(void)
erts_snprintf(opts.name, 16, "runq_supervisor");
erts_atomic_init_nob(&runq_supervisor_sleeping, 0);
if (0 != ethr_event_init(&runq_supervision_event))
- erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision event\n");
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create run-queue supervision event\n");
res = ethr_thr_create(&runq_supervisor_tid,
runq_supervisor,
NULL,
&opts);
if (0 != res)
- erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision thread, "
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create run-queue supervision thread, "
"error = %d\n", res);
}
opts.suggested_stack_size = erts_sched_thread_suggested_stack_size;
- if (wanted < 1)
- wanted = 1;
- if (wanted > ERTS_MAX_NO_OF_SCHEDULERS) {
- wanted = ERTS_MAX_NO_OF_SCHEDULERS;
- res = ENOTSUP;
- }
-
- for (actual = 0; actual < wanted; actual++) {
- ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(actual);
-
- ASSERT(actual == esdp->no - 1);
-
- erts_snprintf(opts.name, 16, "%lu_scheduler", actual + 1);
+ ASSERT(erts_no_schedulers > 0 && erts_no_schedulers <= ERTS_MAX_NO_OF_SCHEDULERS);
+ for (ix = 0; ix < erts_no_schedulers; ix++) {
+ ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix);
+ ASSERT(ix == esdp->no - 1);
+ erts_snprintf(opts.name, 16, "%lu_scheduler", ix + 1);
res = ethr_thr_create(&esdp->tid, sched_thread_func, (void*)esdp, &opts);
-
if (res != 0) {
- break;
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create scheduler thread %d, error = %d\n", ix, res);
}
}
- erts_no_schedulers = actual;
+
+ /* Probably not needed as thread create will imply a memory barrier,
+ but we do one just to be safe. */
+ ERTS_THR_MEMORY_BARRIER;
{
for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++) {
@@ -8626,7 +8617,7 @@ erts_start_schedulers(void)
opts.suggested_stack_size = erts_dcpu_sched_thread_suggested_stack_size;
res = ethr_thr_create(&esdp->tid,sched_dirty_cpu_thread_func,(void*)esdp,&opts);
if (res != 0)
- erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty cpu scheduler thread %d, error = %d\n", ix, res);
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create dirty cpu scheduler thread %d, error = %d\n", ix, res);
}
for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) {
ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix);
@@ -8634,40 +8625,22 @@ erts_start_schedulers(void)
opts.suggested_stack_size = erts_dio_sched_thread_suggested_stack_size;
res = ethr_thr_create(&esdp->tid,sched_dirty_io_thread_func,(void*)esdp,&opts);
if (res != 0)
- erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty io scheduler thread %d, error = %d\n", ix, res);
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create dirty io scheduler thread %d, error = %d\n", ix, res);
}
}
- ERTS_THR_MEMORY_BARRIER;
-
erts_snprintf(opts.name, 16, "aux");
res = ethr_thr_create(&tid, aux_thread, NULL, &opts);
if (res != 0)
- erts_exit(ERTS_ERROR_EXIT, "Failed to create aux thread, error = %d\n", res);
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create aux thread, error = %d\n", res);
for (ix = 0; ix < erts_no_poll_threads; ix++) {
erts_snprintf(opts.name, 16, "%d_poller", ix);
res = ethr_thr_create(&tid, poll_thread, (void*)(UWord)ix, &opts);
if (res != 0)
- erts_exit(ERTS_ERROR_EXIT, "Failed to create poll thread\n");
- }
-
- if (actual < 1)
- erts_exit(ERTS_ERROR_EXIT,
- "Failed to create any scheduler-threads: %s (%d)\n",
- erl_errno_id(res),
- res);
- if (res != 0) {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- ASSERT(actual != wanted_no_schedulers);
- erts_dsprintf(dsbufp,
- "Failed to create %beu scheduler-threads (%s:%d); "
- "only %beu scheduler-thread%s created.\n",
- wanted_no_schedulers, erl_errno_id(res), res,
- actual, actual == 1 ? " was" : "s were");
- erts_send_error_to_logger_nogl(dsbufp);
+ erts_exit(ERTS_ABORT_EXIT, "Failed to create poll thread\n");
}
}
@@ -12097,6 +12070,7 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
ErtsHeapFactory factory;
Sint reds_consumed = 0;
+ ASSERT(c_p->flags & F_DISABLE_GC);
ASSERT(erts_monitor_is_target(mon) && mon->type == ERTS_MON_TYPE_DIST_PROC);
mdp = erts_monitor_to_data(mon);
@@ -12144,7 +12118,6 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
switch (code) {
case ERTS_DSIG_SEND_CONTINUE:
case ERTS_DSIG_SEND_YIELD:
- erts_set_gc_state(c_p, 0);
ctxt->dist_state = erts_dsend_export_trap_context(c_p, &ctx);
reds_consumed = reds; /* force yield */
break;
@@ -12152,7 +12125,6 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
break;
case ERTS_DSIG_SEND_TOO_LRG:
erts_kill_dist_connection(dep, dist->connection_id);
- erts_set_gc_state(c_p, 1);
break;
default:
ASSERT(! "Invalid dsig send exit monitor result");
@@ -12356,6 +12328,7 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
ErtsHeapFactory factory;
Sint reds_consumed = 0;
+ ASSERT(c_p->flags & F_DISABLE_GC);
ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC);
dlnk = erts_link_to_other(lnk, &ldp);
dist = ((ErtsLinkDataExtended *) ldp)->dist;
@@ -12395,7 +12368,6 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
switch (code) {
case ERTS_DSIG_SEND_YIELD:
case ERTS_DSIG_SEND_CONTINUE:
- erts_set_gc_state(c_p, 0);
ctxt->dist_state = erts_dsend_export_trap_context(c_p, &ctx);
reds_consumed = reds; /* force yield */
break;
@@ -12403,7 +12375,6 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
break;
case ERTS_DSIG_SEND_TOO_LRG:
erts_kill_dist_connection(dep, dist->connection_id);
- erts_set_gc_state(c_p, 1);
break;
default:
ASSERT(! "Invalid dsig send exit monitor result");
@@ -12951,6 +12922,8 @@ restart:
yield_allowed = 0;
#endif
+ /* Enable GC again, through strictly not needed it puts
+ the process in a consistent state. */
erts_set_gc_state(p, 1);
/* Set state to not active as we don't want this process
@@ -13495,3 +13468,79 @@ erts_debug_later_op_foreach(void (*callback)(void*),
}
}
}
+
+void
+erts_debug_free_process_foreach(void (*func)(Process *, void *), void *arg)
+{
+ ErtsRunQueue *rq;
+ int ix, prio;
+ for (ix = 0; ix < erts_no_run_queues; ix++) {
+ rq = ERTS_RUNQ_IX(ix);
+ for (prio = PRIORITY_MAX; prio < PRIORITY_LOW; prio++) {
+ Process *p = rq->procs.prio[prio].first;
+ for (; p; p = p->next) {
+ if (ERTS_PSFLG_FREE & erts_atomic32_read_nob(&p->state))
+ (*func)(p, arg);
+ }
+ }
+ }
+}
+
+void
+erts_debug_proc_monitor_link_foreach(Process *proc,
+ int (*monitor_func)(ErtsMonitor *, void *, Sint ),
+ int (*link_func)(ErtsLink *, void *, Sint ),
+ void *arg)
+{
+ if (!(erts_atomic32_read_nob(&proc->state) & ERTS_PSFLG_FREE)) {
+ /* For all links */
+ erts_link_tree_foreach(ERTS_P_LINKS(proc),
+ link_func,
+ arg);
+ /* For all monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(proc),
+ monitor_func,
+ arg);
+ /* For all local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(proc),
+ monitor_func,
+ arg);
+ }
+ else {
+ struct continue_exit_state *ce_state = proc->u.terminate;
+
+ /* For all links */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_LINKS)
+ erts_debug_link_tree_destroying_foreach(ce_state->links,
+ link_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_link_tree_foreach(ce_state->links,
+ link_func,
+ arg);
+
+ /* For all monitors */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_MONITORS)
+ erts_debug_monitor_tree_destroying_foreach(ce_state->monitors,
+ monitor_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_monitor_tree_foreach(ce_state->monitors,
+ monitor_func,
+ arg);
+
+ /* For all local target monitors */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_LT_MONITORS)
+ erts_debug_monitor_list_destroying_foreach(ce_state->lt_monitors,
+ monitor_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_monitor_list_foreach(ce_state->lt_monitors,
+ monitor_func,
+ arg);
+
+ }
+}
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 6118c671ee..c0d7cfd13d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -701,6 +701,13 @@ void
erts_debug_later_op_foreach(void (*callback)(void*),
void (*func)(void *, ErtsThrPrgrVal, void *),
void *arg);
+void
+erts_debug_free_process_foreach(void (*func)(Process *, void *), void *arg);
+void
+erts_debug_proc_monitor_link_foreach(Process *proc,
+ int (*monitor_func)(ErtsMonitor *, void *, Sint ),
+ int (*link_func)(ErtsLink *, void *, Sint ),
+ void *arg);
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
@@ -1230,9 +1237,10 @@ void erts_check_for_holes(Process* p);
/* The sequential tracing token is a tuple of size 5:
*
- * {Flags, Label, Serial, Sender}
+ * {Flags, Label, Serial, Sender, LastCnt}
+ *
+ * WARNING: The top 5-tuple is *MUTABLE* and thus INTERNAL ONLY.
*/
-
#define SEQ_TRACE_TOKEN_ARITY(p) (arityval(*(tuple_val(SEQ_TRACE_TOKEN(p)))))
#define SEQ_TRACE_TOKEN_FLAGS(p) (*(tuple_val(SEQ_TRACE_TOKEN(p)) + 1))
#define SEQ_TRACE_TOKEN_LABEL(p) (*(tuple_val(SEQ_TRACE_TOKEN(p)) + 2))
@@ -2352,6 +2360,8 @@ erts_try_change_runq_proc(Process *p, ErtsRunQueue *rq)
old_rqint);
if (act_rqint == old_rqint)
return !0;
+
+ old_rqint = act_rqint;
}
}
@@ -2631,6 +2641,9 @@ void erts_notify_inc_runq(ErtsRunQueue *runq);
void erts_sched_finish_poke(ErtsSchedulerSleepInfo *, erts_aint32_t);
ERTS_GLB_INLINE void erts_sched_poke(ErtsSchedulerSleepInfo *ssi);
void erts_aux_thread_poke(void);
+ERTS_GLB_INLINE Uint32 erts_sched_local_random_hash_64_to_32_shift(Uint64 key);
+ERTS_GLB_INLINE Uint32 erts_sched_local_random(Uint additional_seed);
+
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
@@ -2647,6 +2660,39 @@ erts_sched_poke(ErtsSchedulerSleepInfo *ssi)
}
+/*
+ * Source: https://gist.github.com/badboy/6267743
+ * http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+ */
+ERTS_GLB_INLINE
+Uint32 erts_sched_local_random_hash_64_to_32_shift(Uint64 key)
+{
+ key = (~key) + (key << 18); /* key = (key << 18) - key - 1; */
+ key = key ^ (key >> 31);
+ key = (key + (key << 2)) + (key << 4);
+ key = key ^ (key >> 11);
+ key = key + (key << 6);
+ key = key ^ (key >> 22);
+ return (Uint32) key;
+}
+
+/*
+ * This function attempts to return a random number based on the state
+ * of the scheduler, the current process and the additional_seed
+ * parameter.
+ */
+ERTS_GLB_INLINE
+Uint32 erts_sched_local_random(Uint additional_seed)
+{
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ Uint64 seed =
+ additional_seed +
+ esdp->reductions +
+ esdp->current_process->fcalls +
+ (((Uint64)esdp->no) << 32);
+ return erts_sched_local_random_hash_64_to_32_shift(seed);
+}
+
#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.h b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
index 74cc966cbe..6f715ae80d 100644
--- a/erts/emulator/beam/erl_sched_spec_pre_alloc.h
+++ b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
@@ -49,7 +49,7 @@ do { \
#endif
#ifdef DEBUG
-extern Uint erts_no_schedulers;
+extern Uint ERTS_WRITE_UNLIKELY(erts_no_schedulers);
#endif
#define ERTS_SSPA_FORCE_THR_CHECK_PROGRESS 10
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index c85a7df5ec..f6f177887c 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -713,7 +713,9 @@ trace_sched(Process *p, ErtsProcLocks locks, Eterm what)
trace_sched_aux(p, locks, what);
}
-/* Send {trace_ts, Pid, Send, Msg, DestPid, Timestamp}
+/* Send {trace_ts, Pid, Send, Msg, DestPid, PamResult, Timestamp}
+ * or {trace_ts, Pid, Send, Msg, DestPid, Timestamp}
+ * or {trace, Pid, Send, Msg, DestPid, PamResult}
* or {trace, Pid, Send, Msg, DestPid}
*
* where 'Send' is 'send' or 'send_to_non_existing_process'.
@@ -773,7 +775,9 @@ trace_send(Process *p, Eterm to, Eterm msg)
erts_match_set_release_result_trace(p, pam_result);
}
-/* Send {trace_ts, Pid, receive, Msg, Timestamp}
+/* Send {trace_ts, Pid, receive, Msg, PamResult, Timestamp}
+ * or {trace_ts, Pid, receive, Msg, Timestamp}
+ * or {trace, Pid, receive, Msg, PamResult}
* or {trace, Pid, receive, Msg}
*/
void
@@ -2190,11 +2194,12 @@ sys_msg_dispatcher_wait(void *vwait_p)
erts_mtx_unlock(&smq_mtx);
}
+static ErtsSysMsgQ *local_sys_message_queue = NULL;
+
static void *
sys_msg_dispatcher_func(void *unused)
{
ErtsThrPrgrCallbacks callbacks;
- ErtsSysMsgQ *local_sys_message_queue = NULL;
ErtsThrPrgrData *tpd;
int wait = 0;
@@ -2202,6 +2207,8 @@ sys_msg_dispatcher_func(void *unused)
erts_lc_set_thread_name("system message dispatcher");
#endif
+ local_sys_message_queue = NULL;
+
callbacks.arg = (void *) &wait;
callbacks.wakeup = sys_msg_dispatcher_wakeup;
callbacks.prepare_wait = sys_msg_dispatcher_prep_wait;
@@ -2258,6 +2265,8 @@ sys_msg_dispatcher_func(void *unused)
Process *proc = NULL;
Port *port = NULL;
+ ASSERT(is_value(smqp->msg));
+
if (erts_thr_progress_update(tpd))
erts_thr_progress_leader_update(tpd);
@@ -2370,6 +2379,7 @@ sys_msg_dispatcher_func(void *unused)
erts_fprintf(stderr, "dropped\n");
#endif
}
+ smqp->msg = THE_NON_VALUE;
}
}
@@ -2377,32 +2387,38 @@ sys_msg_dispatcher_func(void *unused)
}
void
-erts_foreach_sys_msg_in_q(void (*func)(Eterm,
- Eterm,
- Eterm,
- ErlHeapFragment *))
+erts_debug_foreach_sys_msg_in_q(void (*func)(Eterm,
+ Eterm,
+ Eterm,
+ ErlHeapFragment *))
{
- ErtsSysMsgQ *sm;
- erts_mtx_lock(&smq_mtx);
- for (sm = sys_message_queue; sm; sm = sm->next) {
- Eterm to;
- switch (sm->type) {
- case SYS_MSG_TYPE_SYSMON:
- to = erts_get_system_monitor();
- break;
- case SYS_MSG_TYPE_SYSPROF:
- to = erts_get_system_profile();
- break;
- case SYS_MSG_TYPE_ERRLGR:
- to = erts_get_system_logger();
- break;
- default:
- to = NIL;
- break;
- }
- (*func)(sm->from, to, sm->msg, sm->bp);
+ ErtsSysMsgQ *smq[] = {sys_message_queue, local_sys_message_queue};
+ int i;
+
+ ERTS_LC_ASSERT(erts_thr_progress_is_blocking());
+
+ for (i = 0; i < sizeof(smq)/sizeof(smq[0]); i++) {
+ ErtsSysMsgQ *sm;
+ for (sm = smq[i]; sm; sm = sm->next) {
+ Eterm to;
+ switch (sm->type) {
+ case SYS_MSG_TYPE_SYSMON:
+ to = erts_get_system_monitor();
+ break;
+ case SYS_MSG_TYPE_SYSPROF:
+ to = erts_get_system_profile();
+ break;
+ case SYS_MSG_TYPE_ERRLGR:
+ to = erts_get_system_logger();
+ break;
+ default:
+ to = NIL;
+ break;
+ }
+ if (is_value(sm->msg))
+ (*func)(sm->from, to, sm->msg, sm->bp);
+ }
}
- erts_mtx_unlock(&smq_mtx);
}
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index b7844d1cb0..af38ef52db 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -90,10 +90,10 @@ int erts_is_tracer_valid(Process* p);
void erts_check_my_tracer_proc(Process *);
void erts_block_sys_msg_dispatcher(void);
void erts_release_sys_msg_dispatcher(void);
-void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
- Eterm,
- Eterm,
- ErlHeapFragment *));
+void erts_debug_foreach_sys_msg_in_q(void (*func)(Eterm,
+ Eterm,
+ Eterm,
+ ErlHeapFragment *));
Eterm erts_set_system_logger(Eterm);
Eterm erts_get_system_logger(void);
void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index ec67ab2aed..ce61cdf040 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -1062,11 +1062,38 @@ bad_dist_ext(ErtsDistExternal *edep)
}
Sint
-erts_decode_dist_ext_size(ErtsDistExternal *edep, int kill_connection)
+erts_decode_dist_ext_size(ErtsDistExternal *edep, int kill_connection, int payload)
{
Sint res;
byte *ep;
+ if (edep->data->frag_id > 1 && payload) {
+ Uint sz = 0;
+ Binary *bin;
+ int i;
+ byte *ep;
+
+ for (i = 0; i < edep->data->frag_id; i++)
+ sz += edep->data[i].ext_endp - edep->data[i].extp;
+
+ bin = erts_bin_nrml_alloc(sz);
+ ep = (byte*)bin->orig_bytes;
+
+ for (i = 0; i < edep->data->frag_id; i++) {
+ sys_memcpy(ep, edep->data[i].extp, edep->data[i].ext_endp - edep->data[i].extp);
+ ep += edep->data[i].ext_endp - edep->data[i].extp;
+ erts_bin_release(edep->data[i].binp);
+ edep->data[i].binp = NULL;
+ edep->data[i].extp = NULL;
+ edep->data[i].ext_endp = NULL;
+ }
+
+ edep->data->frag_id = 1;
+ edep->data->extp = (byte*)bin->orig_bytes;
+ edep->data->ext_endp = ep;
+ edep->data->binp = bin;
+ }
+
if (edep->data->extp >= edep->data->ext_endp)
goto fail;
#ifndef ERTS_DEBUG_USE_DIST_SEP
@@ -1164,6 +1191,7 @@ Eterm erts_decode_ext(ErtsHeapFactory* factory, byte **ext, Uint32 flags)
if (flags) {
ASSERT(flags == ERTS_DIST_EXT_BTT_SAFE);
ede.flags = flags; /* a dummy struct just for the flags */
+ ede.data = NULL;
edep = &ede;
} else {
edep = NULL;
@@ -1233,8 +1261,10 @@ BIF_RETTYPE erts_debug_dist_ext_to_term_2(BIF_ALIST_2)
ede.data->extp = binary_bytes(real_bin)+offset;
ede.data->ext_endp = ede.data->extp + size;
+ ede.data->frag_id = 1;
+ ede.data->binp = NULL;
- hsz = erts_decode_dist_ext_size(&ede, 1);
+ hsz = erts_decode_dist_ext_size(&ede, 1, 1);
if (hsz < 0)
goto badarg;
@@ -1765,6 +1795,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Eterm bin, B2TContext *ctx)
case B2TDecodeBinary: {
ErtsDistExternal fakedep;
fakedep.flags = ctx->flags;
+ fakedep.data = NULL;
dec_term(&fakedep, NULL, NULL, NULL, ctx);
break;
}
@@ -3762,6 +3793,30 @@ dec_term_atom_common:
hp += heap_bin_size(n);
sys_memcpy(hb->data, ep, n);
*objp = make_binary(hb);
+ } else if (edep && edep->data && edep->data->binp &&
+ n > (edep->data->binp->orig_size / 4)) {
+ /* If we decode a refc binary from a distribution data
+ entry we know that it is a refc binary to begin with
+ so we just increment it and use the reference. This
+ means that the entire distribution data entry will
+ remain until this binary is de-allocated so we only
+ do it if a substantial part (> 25%) of the data
+ is a binary. */
+ ProcBin* pb = (ProcBin *) hp;
+ Binary* bptr = edep->data->binp;
+ erts_refc_inc(&bptr->intern.refc, 1);
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = n;
+ pb->next = factory->off_heap->first;
+ factory->off_heap->first = (struct erl_off_heap_header*)pb;
+ pb->val = bptr;
+ pb->bytes = (byte*) ep;
+ ERTS_ASSERT((byte*)(bptr->orig_bytes) < ep &&
+ ep+n <= (byte*)(bptr->orig_bytes+bptr->orig_size));
+ pb->flags = 0;
+ OH_OVERHEAD(factory->off_heap, pb->size / sizeof(Eterm));
+ hp += PROC_BIN_SIZE;
+ *objp = make_binary(pb);
} else {
Binary* dbin = erts_bin_nrml_alloc(n);
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index b556c9076c..e362a6c81f 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -199,7 +199,7 @@ typedef enum {
ErtsPrepDistExtRes erts_prepare_dist_ext(ErtsDistExternal *, byte *, Uint, struct binary *,
DistEntry *, Uint32, ErtsAtomCache *);
-Sint erts_decode_dist_ext_size(ErtsDistExternal *, int);
+Sint erts_decode_dist_ext_size(ErtsDistExternal *, int, int);
Eterm erts_decode_dist_ext(ErtsHeapFactory*, ErtsDistExternal *, int);
Sint erts_decode_ext_size(byte*, Uint);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 4c8d3d3dbe..0c2cf98033 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -907,7 +907,8 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
/* beam_bif_load.c */
Eterm erts_check_process_code(Process *c_p, Eterm module, int *redsp, int fcalls);
Eterm erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed);
-
+void erts_debug_foreach_release_literal_area_off_heap(void (*func)(ErlOffHeap *, void *),
+ void *arg);
typedef struct ErtsLiteralArea_ {
struct erl_off_heap_header *off_heap;
Eterm *end;
@@ -1072,17 +1073,46 @@ Uint size_object_x(Eterm, erts_literal_area_t*);
#define size_object_litopt(Term,LitArea) size_object_x(Term,LitArea)
Uint copy_shared_calculate(Eterm, erts_shcopy_t*);
-Eterm copy_shared_perform(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*);
-
Uint size_shared(Eterm);
+/* #define ERTS_COPY_REGISTER_LOCATION */
+
+#ifdef ERTS_COPY_REGISTER_LOCATION
+
+#define copy_shared_perform(U, V, X, Y, Z) \
+ copy_shared_perform_x((U), (V), (X), (Y), (Z), __FILE__, __LINE__)
+Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*,
+ char *file, int line);
+
+Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*,
+ char *file, int line);
+#define copy_struct(Obj,Sz,HPP,OH) \
+ copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL,__FILE__,__LINE__)
+#define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
+ copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea,__FILE__,__LINE__)
+
+#define copy_shallow(R, SZ, HPP, OH) \
+ copy_shallow_x((R), (SZ), (HPP), (OH), __FILE__, __LINE__)
+Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*,
+ char *file, int line);
+
+#else
+
+#define copy_shared_perform(U, V, X, Y, Z) \
+ copy_shared_perform_x((U), (V), (X), (Y), (Z))
+Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*);
+
Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*);
#define copy_struct(Obj,Sz,HPP,OH) \
copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL)
#define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea)
-Eterm copy_shallow(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*);
+#define copy_shallow(R, SZ, HPP, OH) \
+ copy_shallow_x((R), (SZ), (HPP), (OH))
+Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*);
+
+#endif
void erts_move_multi_frags(Eterm** hpp, ErlOffHeap*, ErlHeapFragment* first,
Eterm* refs, unsigned nrefs, int literals);
@@ -1257,6 +1287,10 @@ Uint erts_persistent_term_count(void);
void erts_init_persistent_dumping(void);
extern ErtsLiteralArea** erts_persistent_areas;
extern Uint erts_num_persistent_areas;
+void erts_debug_foreach_persistent_term_off_heap(void (*func)(ErlOffHeap *, void *),
+ void *arg);
+int erts_debug_have_accessed_literal_area(ErtsLiteralArea *lap);
+void erts_debug_save_accessed_literal_area(ErtsLiteralArea *lap);
/* external.c */
void erts_init_external(void);
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 462ee77e6f..7cffe7fb5c 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -1064,19 +1064,30 @@ raw_raise() {
Eterm class = x(0);
Eterm value = x(1);
Eterm stacktrace = x(2);
+ Eterm* freason_ptr;
+
+ /*
+ * Note that the i_raise instruction will override c_p->freason
+ * with the freason field stored inside the StackTrace struct in
+ * ftrace. Therefore, we must take care to store the class both
+ * inside the StackTrace struct and in c_p->freason (important if
+ * the class is different from the class of the original
+ * exception).
+ */
+ freason_ptr = get_freason_ptr_from_exc(stacktrace);
if (class == am_error) {
- c_p->freason = EXC_ERROR & ~EXF_SAVETRACE;
+ *freason_ptr = c_p->freason = EXC_ERROR & ~EXF_SAVETRACE;
c_p->fvalue = value;
c_p->ftrace = stacktrace;
goto find_func_info;
} else if (class == am_exit) {
- c_p->freason = EXC_EXIT & ~EXF_SAVETRACE;
+ *freason_ptr = c_p->freason = EXC_EXIT & ~EXF_SAVETRACE;
c_p->fvalue = value;
c_p->ftrace = stacktrace;
goto find_func_info;
} else if (class == am_throw) {
- c_p->freason = EXC_THROWN & ~EXF_SAVETRACE;
+ *freason_ptr = c_p->freason = EXC_THROWN & ~EXF_SAVETRACE;
c_p->fvalue = value;
c_p->ftrace = stacktrace;
goto find_func_info;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 10ca74cd60..b9d4f6afcc 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+# Copyright Ericsson AB 1997-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -699,13 +699,18 @@ is_tuple NotTupleFail Tuple=x | is_tagged_tuple WrongRecordFail Tuple Arity Atom
is_tagged_tuple_ff f? f? rx A a
-get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
+get_tuple_element Reg=x P1 D1=x | \
+ get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P3 D3=x | \
- succ(P1, P2) | succ(P2, P3) | \
- succ(D1, D2) | succ(D2, D3) => i_get_tuple_element3 Reg P1 D1
+ succ(P1, P2) | succ(P2, P3) | succ(D1, D2) | succ(D2, D3) | \
+ distinct(D1, Reg) | distinct(D2, Reg) => \
+ i_get_tuple_element3 Reg P1 D1
-get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
- succ(P1, P2) | succ(D1, D2) => i_get_tuple_element2 Reg P1 D1
+get_tuple_element Reg=x P1 D1=x | \
+ get_tuple_element Reg=x P2 D2=x | \
+ succ(P1, P2) | succ(D1, D2) | \
+ distinct(D1, Reg) => \
+ i_get_tuple_element2 Reg P1 D1
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
succ(P1, P2) | distinct(D1, Reg) => i_get_tuple_element2_dst Reg P1 D1 D2
@@ -1687,6 +1692,7 @@ i_increment rxy W d
# Handle unoptimized code.
i_plus S1=c S2=c Fail Dst => move S1 x | i_plus x S2 Fail Dst
+i_plus S1=c S2=xy Fail Dst => i_plus S2 S1 Fail Dst
i_plus xy xyc j? d
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index c93966d24f..66ff8d8450 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2018. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2019. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1077,6 +1077,7 @@ typedef struct {
long forced_events; /* Mask of events that are forcefully signalled
on windows see winsock_event_select
for details */
+ int err; /* Keeps error code for closed socket */
int send_would_block; /* Last send attempt failed with "WOULDBLOCK" */
#endif
ErlDrvPort port; /* the port identifier */
@@ -3379,6 +3380,71 @@ static int udp_parse_ancillary_data(ErlDrvTermData *spec, int i,
i = LOAD_NIL(spec, i);
return LOAD_LIST(spec, i, n+1);
}
+
+static int compile_ancillary_data(struct msghdr *mhdr,
+ char *ptr, ErlDrvSizeT anc_len) {
+ struct cmsghdr *cmsg;
+ size_t controllen = 0;
+ cmsg = CMSG_FIRSTHDR(mhdr);
+ for (;;) {
+ if (anc_len == 0) {
+ /* End of options to compile */
+ mhdr->msg_controllen = controllen;
+ return 0;
+ }
+ if (cmsg == NULL) {
+ /* End of destination before end of options */
+ return 1;
+ }
+
+#define COMPILE_ANCILLARY_DATA_ITEM(Level, Opt, Type, Get, Size) \
+ do { \
+ if (anc_len < (Size)) return 1; \
+ sys_memset(cmsg, '\0', CMSG_SPACE(sizeof(Type))); \
+ cmsg->cmsg_level = Level; \
+ cmsg->cmsg_type = Opt; \
+ cmsg->cmsg_len = CMSG_LEN(sizeof(Type)); \
+ *((Type *) CMSG_DATA(cmsg)) = Get(ptr); \
+ controllen += CMSG_SPACE(sizeof(Type)); \
+ cmsg = CMSG_NXTHDR(mhdr, cmsg); \
+ ptr += 4; \
+ anc_len -= 4; \
+ } while (0)
+#define SIZEOF_ANCILLARY_DATA (2 * CMSG_SPACE(sizeof(int)))
+ /* (IP_TOS | IPV6_TCLASS) + IP_TTL */
+
+ switch (anc_len--, *ptr++) {
+ case INET_OPT_TOS: {
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IP, IP_TOS, int, get_int32, 4);
+#else
+ return 1; /* Socket option not implemented */
+#endif
+ break;
+ }
+ case INET_OPT_TTL: {
+#if defined(IPPROTO_IP) && defined(IP_TTL)
+ COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IP, IP_TTL, int, get_int32, 4);
+#else
+ return 1; /* Socket option not implemented */
+#endif
+ break;
+ }
+ case INET_OPT_TCLASS: {
+#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
+ COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IPV6, IPV6_TCLASS, int, get_int32, 4);
+#else
+ return 1; /* Socket option not implemented */
+#endif
+ break;
+ }
+ default:
+ /* Unknow socket option */
+ return 1;
+ }
+#undef COMPILE_ANCILLARY_DATA_ITEM
+ }
+}
#endif /* ifndef __WIN32__ */
/*
@@ -9063,6 +9129,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
desc->event_mask = 0;
#ifdef __WIN32__
desc->forced_events = 0;
+ desc->err = 0;
desc->send_would_block = 0;
#endif
desc->port = port;
@@ -9846,10 +9913,8 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
copy_desc->send_timeout = desc->send_timeout;
copy_desc->send_timeout_close = desc->send_timeout_close;
- if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET)
- copy_desc->tcp_add_flags |= TCP_ADDF_SHOW_ECONNRESET;
- else
- copy_desc->tcp_add_flags &= ~TCP_ADDF_SHOW_ECONNRESET;
+ copy_desc->tcp_add_flags = desc->tcp_add_flags
+ & (TCP_ADDF_SHOW_ECONNRESET | TCP_ADDF_LINGER_ZERO);
/* The new port will be linked and connected to the original caller */
port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc);
@@ -10914,7 +10979,7 @@ static int winsock_event_select(inet_descriptor *desc, int flags, int on)
{
int save_event_mask = desc->event_mask;
- desc->forced_events = 0;
+ desc->forced_events &= FD_CLOSE;
if (on)
desc->event_mask |= flags;
else
@@ -10966,7 +11031,7 @@ static int winsock_event_select(inet_descriptor *desc, int flags, int on)
TIMEVAL tmo = {0,0};
FD_SET fds;
int ret;
-
+
FD_ZERO(&fds);
FD_SET(desc->s,&fds);
do_force = (select(desc->s+1,0,&fds,0,&tmo) > 0);
@@ -10983,7 +11048,7 @@ static int winsock_event_select(inet_descriptor *desc, int flags, int on)
FD_SET fds;
int ret;
unsigned long arg;
-
+
FD_ZERO(&fds);
FD_SET(desc->s,&fds);
ret = select(desc->s+1,&fds,0,0,&tmo);
@@ -11022,13 +11087,16 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event)
goto error;
}
- DEBUGF((" => event=%02X, mask=%02X\r\n",
- netEv.lNetworkEvents, desc->inet.event_mask));
+ DEBUGF((" => event=%02X, mask=%02X, forced=%02X\r\n",
+ netEv.lNetworkEvents, desc->inet.event_mask,
+ desc->inet.forced_events));
/* Add the forced events. */
-
netEv.lNetworkEvents |= desc->inet.forced_events;
+ if (desc->inet.forced_events & FD_CLOSE)
+ netEv.iErrorCode[FD_CLOSE_BIT] = desc->inet.err;
+
/*
* Calling WSAEventSelect() with a mask of 0 doesn't always turn off
* all events. To avoid acting on events we don't want, we mask
@@ -11048,16 +11116,29 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event)
goto error;
}
if (netEv.lNetworkEvents & FD_CLOSE) {
- /*
+
+ /* We may not get any more FD_CLOSE events so we
+ keep this event and always signal it from
+ this moment on. */
+ if ((desc->inet.forced_events & FD_CLOSE) == 0) {
+ desc->inet.forced_events |= FD_CLOSE;
+ desc->inet.err = netEv.iErrorCode[FD_CLOSE_BIT];
+ }
+
+ /*
* We must loop to read out the remaining packets (if any).
*/
for (;;) {
- DEBUGF(("Retrying read due to closed port\r\n"));
- /* XXX The buffer will be thrown away on error (empty que).
- Possible SMP FIXME. */
- if (!desc->inet.active && (desc->inet.opt) == NULL) {
- goto error;
- }
+
+ /* if passive and no subscribers, break loop */
+ if (!desc->inet.active && desc->inet.opt == NULL) {
+ /* do not trigger close event when socket is
+ transitioned to passive */
+ netEv.lNetworkEvents &= ~FD_CLOSE;
+ break;
+ }
+
+ DEBUGF(("Retrying read due to FD_CLOSE\r\n"));
if (tcp_inet_input(desc, event) < 0) {
goto error;
}
@@ -11386,7 +11467,7 @@ static int tcp_shutdown_error(tcp_descriptor* desc, int err)
static void tcp_inet_delay_send(ErlDrvData data, ErlDrvTermData dummy)
{
tcp_descriptor *desc = (tcp_descriptor*)data;
- (void)tcp_inet_output(desc, INETP(desc)->s);
+ (void)tcp_inet_output(desc, (HANDLE) INETP(desc)->s);
}
/*
@@ -12553,7 +12634,7 @@ static void packet_inet_timeout(ErlDrvData e)
sock_select(desc, FD_READ, 0);
async_error_am (desc, am_timeout);
} else {
- (void)packet_inet_input(udesc, desc->s);
+ (void)packet_inet_input(udesc, (HANDLE) desc->s);
}
}
@@ -12597,11 +12678,8 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
char ancd[CMSG_SPACE(sizeof(*sri))];
} cmsg;
- if (len < SCTP_GET_SENDPARAMS_LEN) {
- inet_reply_error(desc, EINVAL);
- return;
- }
-
+ if (len < SCTP_GET_SENDPARAMS_LEN) goto return_einval;
+
/* The ancillary data */
sri = (struct sctp_sndrcvinfo *) (CMSG_DATA(&cmsg.hdr));
/* Get the "sndrcvinfo" from the buffer, advancing the "ptr": */
@@ -12634,28 +12712,82 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
goto check_result_code;
}
#endif
- /* UDP socket. Even if it is connected, there is an address prefix
- here -- ignored for connected sockets: */
- sz = len;
- qtr = ptr;
- xerror = inet_set_faddress(desc->sfamily, &other, &qtr, &sz);
- if (xerror != NULL) {
- inet_reply_error_am(desc, driver_mk_atom(xerror));
- return;
- }
- len -= (qtr - ptr);
- ptr = qtr;
- /* Now "ptr" is the user data ptr, "len" is data length: */
- inet_output_count(desc, len);
-
- if (desc->state & INET_F_ACTIVE) { /* connected (ignore address) */
- code = sock_send(desc->s, ptr, len, 0);
- }
- else {
- code = sock_sendto(desc->s, ptr, len, 0, &other.sa, sz);
+ {
+ ErlDrvSizeT anc_len;
+
+ /* UDP socket. Even if it is connected, there is an address prefix
+ here -- ignored for connected sockets: */
+ sz = len;
+ qtr = ptr;
+ xerror = inet_set_faddress(desc->sfamily, &other, &qtr, &sz);
+ if (xerror != NULL) {
+ inet_reply_error_am(desc, driver_mk_atom(xerror));
+ return;
+ }
+ len -= (qtr - ptr);
+ ptr = qtr;
+
+ /* Here comes ancillary data */
+ if (len < 4) goto return_einval;
+ anc_len = get_int32(ptr);
+ len -= 4; ptr += 4;
+ if (len < anc_len) goto return_einval;
+
+ if (anc_len == 0) {
+ /* Empty ancillary data */
+ /* Now "ptr" is the user data ptr, "len" is data length: */
+ inet_output_count(desc, len);
+ if (desc->state & INET_F_ACTIVE) {
+ /* connected (ignore address) */
+ code = sock_send(desc->s, ptr, len, 0);
+ }
+ else {
+ code = sock_sendto(desc->s, ptr, len, 0, &other.sa, sz);
+ }
+ }
+ else {
+#ifdef __WIN32__
+ goto return_einval; /* Can not send ancillary data on Windows */
+#else
+ struct iovec iov[1];
+ struct msghdr mhdr;
+ union { /* For ancillary data */
+ struct cmsghdr hdr;
+ char ancd[SIZEOF_ANCILLARY_DATA];
+ } cmsg;
+ sys_memset(&iov, '\0', sizeof(iov));
+ sys_memset(&mhdr, '\0', sizeof(mhdr));
+ sys_memset(&cmsg, '\0', sizeof(cmsg));
+ if (desc->state & INET_F_ACTIVE) {
+ /* connected (ignore address) */
+ mhdr.msg_name = NULL;
+ mhdr.msg_namelen = 0;
+ }
+ else {
+ mhdr.msg_name = &other;
+ mhdr.msg_namelen = sz;
+ }
+ mhdr.msg_control = cmsg.ancd;
+ mhdr.msg_controllen = sizeof(cmsg.ancd);
+ if (compile_ancillary_data(&mhdr, ptr, anc_len) != 0) {
+ goto return_einval;
+ }
+ ASSERT(mhdr.msg_controllen != 0);
+ len -= anc_len;
+ ptr += anc_len;
+ /* Now "ptr" is the user data ptr, "len" is data length: */
+ iov[0].iov_len = len;
+ iov[0].iov_base = ptr;
+ mhdr.msg_iov = iov;
+ mhdr.msg_iovlen = 1;
+ mhdr.msg_flags = 0;
+ inet_output_count(desc, len);
+ code = sock_sendmsg(desc->s, &mhdr, 0);
+#endif
+ }
}
-#ifdef HAVE_SCTP
+#ifdef HAVE_SCTP
check_result_code:
/* "code" analysis is the same for both SCTP and UDP cases above: */
#endif
@@ -12665,8 +12797,15 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
}
else
inet_reply_ok(desc);
+ return;
+
+ return_einval:
+ inet_reply_error(desc, EINVAL);
+ return;
}
-#endif
+
+#endif /* HAVE_UDP */
+
#ifdef __WIN32__
static void packet_inet_event(ErlDrvData e, ErlDrvEvent event)
diff --git a/erts/emulator/hipe/hipe_arm.c b/erts/emulator/hipe/hipe_arm.c
index b61939724c..3e1d7e4d5e 100644
--- a/erts/emulator/hipe/hipe_arm.c
+++ b/erts/emulator/hipe/hipe_arm.c
@@ -18,6 +18,7 @@
* %CopyrightEnd%
*/
+#ifdef __arm__
#include <stddef.h> /* offsetof() */
#ifdef HAVE_CONFIG_H
@@ -30,24 +31,39 @@
#include "hipe_native_bif.h" /* nbif_callemu() */
#include "hipe_bif0.h"
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
/* Flush dcache and invalidate icache for a range of addresses. */
void hipe_flush_icache_range(void *address, unsigned int nbytes)
{
-#if defined(__ARM_EABI__)
+ void* end = (char*)address + nbytes;
+
+#if ERTS_AT_LEAST_GCC_VSN__(4, 3, 0) || __has_builtin(__builtin___clear_cache)
+ __builtin___clear_cache(address, end);
+#elif defined(__clang__)
+ void __clear_cache(void *start, void *end);
+ __clear_cache(address, end);
+#elif defined(__linux__)
+# if defined(__ARM_EABI__)
register unsigned long beg __asm__("r0") = (unsigned long)address;
- register unsigned long end __asm__("r1") = (unsigned long)address + nbytes;
+ register unsigned long end __asm__("r1") = (unsigned long)end;
register unsigned long flg __asm__("r2") = 0;
register unsigned long scno __asm__("r7") = 0xf0002;
__asm__ __volatile__("swi 0" /* sys_cacheflush() */
: "=r"(beg)
: "0"(beg), "r"(end), "r"(flg), "r"(scno));
-#else
+# else
register unsigned long beg __asm__("r0") = (unsigned long)address;
- register unsigned long end __asm__("r1") = (unsigned long)address + nbytes;
+ register unsigned long end __asm__("r1") = (unsigned long)end;
register unsigned long flg __asm__("r2") = 0;
__asm__ __volatile__("swi 0x9f0002" /* sys_cacheflush() */
: "=r"(beg)
: "0"(beg), "r"(end), "r"(flg));
+# endif
+#else
+# error "Don't know how to flush instruction cache"
#endif
}
@@ -270,3 +286,5 @@ void hipe_arch_print_pcb(struct hipe_process_state *p)
U("narity ", narity);
#undef U
}
+
+#endif /*__arm__*/
diff --git a/erts/emulator/hipe/hipe_x86.h b/erts/emulator/hipe/hipe_x86.h
index 8967793171..a1fe75e792 100644
--- a/erts/emulator/hipe/hipe_x86.h
+++ b/erts/emulator/hipe/hipe_x86.h
@@ -22,17 +22,28 @@
#ifndef HIPE_X86_H
#define HIPE_X86_H
-static __inline__ void hipe_flush_icache_word(void *address)
-{
- /* Do nothing. This works as long as compiled code is
- executed by a single CPU thread. */
-}
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
static __inline__ void
hipe_flush_icache_range(void *address, unsigned int nbytes)
{
- /* Do nothing. This works as long as compiled code is
- executed by a single CPU thread. */
+ void* end = (char*)address + nbytes;
+
+#if ERTS_AT_LEAST_GCC_VSN__(4, 3, 0) || __has_builtin(__builtin___clear_cache)
+ __builtin___clear_cache(address, end);
+#elif defined(__clang__)
+ void __clear_cache(void *start, void *end);
+ __clear_cache(address, end);
+#else
+# warning "Don't know how to flush instruction cache"
+#endif
+}
+
+static __inline__ void hipe_flush_icache_word(void *address)
+{
+ hipe_flush_icache_range(address, sizeof(void*));
}
/* for stack descriptor hash lookup */
diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c
index 8a69052935..11a8ff724e 100644
--- a/erts/emulator/nifs/common/net_nif.c
+++ b/erts/emulator/nifs/common/prim_net_nif.c
@@ -1653,4 +1653,4 @@ LOCAL_ERROR_REASON_ATOMS
return !net;
}
-ERL_NIF_INIT(net, net_funcs, on_load, NULL, NULL, NULL)
+ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL)
diff --git a/erts/emulator/nifs/common/socket_dbg.c b/erts/emulator/nifs/common/socket_dbg.c
index 96f75a328f..0005575017 100644
--- a/erts/emulator/nifs/common/socket_dbg.c
+++ b/erts/emulator/nifs/common/socket_dbg.c
@@ -30,35 +30,30 @@
#include <time.h>
#include <erl_nif.h>
+#include "socket_util.h"
#include "socket_dbg.h"
#define TSELF() enif_thread_self()
#define TNAME(__T__) enif_thread_name( __T__ )
#define TSNAME() TNAME(TSELF())
-static FILE* dbgout = NULL;
-
-#if defined(CLOCK_REALTIME)
-static int realtime(struct timespec* tsP);
-static int timespec2str(char *buf, unsigned int len, struct timespec *ts);
-#endif
-
+FILE* esock_dbgout = NULL;
extern
void esock_dbg_init(char* filename)
{
if (filename != NULL) {
if (strcmp(filename, ESOCK_DBGOUT_DEFAULT) == 0) {
- dbgout = stdout;
+ esock_dbgout = stdout;
} else if (strcmp(filename, ESOCK_DBGOUT_UNIQUE) == 0) {
- char template[] = "/tmp/esock-dbg-XXXXXX";
- dbgout = fdopen(mkstemp(template), "w+");
+ char template[] = "/tmp/esock-dbg-XXXXXX";
+ esock_dbgout = fdopen(mkstemp(template), "w+");
} else {
- dbgout = fopen(filename, "w+");
+ esock_dbgout = fopen(filename, "w+");
}
} else {
char template[] = "/tmp/esock-dbg-XXXXXX";
- dbgout = fdopen(mkstemp(template), "w+");
+ esock_dbgout = fdopen(mkstemp(template), "w+");
}
}
@@ -72,11 +67,8 @@ extern
void esock_dbg_printf( const char* prefix, const char* format, ... )
{
va_list args;
- char f[512 + sizeof(format)]; // This has to suffice...
-#if defined(CLOCK_REALTIME)
+ char f[512 + strlen(format)]; // This has to suffice...
char stamp[30];
- struct timespec ts;
-#endif
int res;
/*
@@ -85,64 +77,21 @@ void esock_dbg_printf( const char* prefix, const char* format, ... )
* But then I must change the API....something for later.
*/
-#if defined(CLOCK_REALTIME)
- if (!realtime(&ts) &&
- (timespec2str(stamp, sizeof(stamp), &ts) == 0)) {
+ if (esock_timestamp(stamp, sizeof(stamp))) {
res = enif_snprintf(f, sizeof(f), "%s [%s] [%s] %s",
prefix, stamp, TSNAME(), format);
} else {
res = enif_snprintf(f, sizeof(f), "%s [%s] %s",
prefix, TSNAME(), format);
}
-#else
- res = enif_snprintf(f, sizeof(f), "%s [%s] %s",
- prefix, TSNAME(), format);
-#endif
if (res > 0) {
va_start (args, format);
- enif_vfprintf (dbgout, f, args);
+ enif_vfprintf (esock_dbgout, f, args);
va_end (args);
- fflush(stdout);
+ fflush(esock_dbgout);
}
return;
}
-
-#if defined(CLOCK_REALTIME)
-static
-int realtime(struct timespec* tsP)
-{
- return clock_gettime(CLOCK_REALTIME, tsP);
-}
-
-
-
-
-/*
- * Convert a timespec struct into a readable/printable string
- */
-static
-int timespec2str(char *buf, unsigned int len, struct timespec *ts)
-{
- int ret, buflen;
- struct tm t;
-
- tzset();
- if (localtime_r(&(ts->tv_sec), &t) == NULL)
- return 1;
-
- ret = strftime(buf, len, "%F %T", &t);
- if (ret == 0)
- return 2;
- len -= ret - 1;
- buflen = strlen(buf);
-
- ret = snprintf(&buf[buflen], len, ".%06ld", ts->tv_nsec/1000);
- if (ret >= len)
- return 3;
-
- return 0;
-}
-#endif
diff --git a/erts/emulator/nifs/common/socket_dbg.h b/erts/emulator/nifs/common/socket_dbg.h
index 47739b46da..8fce211a8a 100644
--- a/erts/emulator/nifs/common/socket_dbg.h
+++ b/erts/emulator/nifs/common/socket_dbg.h
@@ -40,12 +40,12 @@
#endif
typedef unsigned long long llu_t;
-
+extern FILE* esock_dbgout; // Initiated by the 'init' function
#define ESOCK_DBG_PRINTF( ___COND___ , proto ) \
if ( ___COND___ ) { \
esock_dbg_printf proto; \
- fflush(stdout); \
+ fflush(esock_dbgout); \
}
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h
index 38c28a6de5..4161775a04 100644
--- a/erts/emulator/nifs/common/socket_int.h
+++ b/erts/emulator/nifs/common/socket_int.h
@@ -102,6 +102,9 @@ typedef unsigned int BOOLEAN_T;
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* "Global" atoms
+ *
+ * Note that when an (global) atom is added here, it must also be added
+ * in the socket_nif.c file!
*/
#define GLOBAL_ATOM_DEFS \
@@ -130,6 +133,7 @@ typedef unsigned int BOOLEAN_T;
GLOBAL_ATOM_DEF(busy_poll); \
GLOBAL_ATOM_DEF(checksum); \
GLOBAL_ATOM_DEF(close); \
+ GLOBAL_ATOM_DEF(command); \
GLOBAL_ATOM_DEF(connect); \
GLOBAL_ATOM_DEF(congestion); \
GLOBAL_ATOM_DEF(context); \
@@ -139,6 +143,7 @@ typedef unsigned int BOOLEAN_T;
GLOBAL_ATOM_DEF(ctrunc); \
GLOBAL_ATOM_DEF(data); \
GLOBAL_ATOM_DEF(debug); \
+ GLOBAL_ATOM_DEF(default); \
GLOBAL_ATOM_DEF(default_send_params); \
GLOBAL_ATOM_DEF(delayed_ack_time); \
GLOBAL_ATOM_DEF(dgram); \
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index ee3b9f2a98..bbeb8b6cdd 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -24,7 +24,7 @@
* The first function is called 'nif_<something>', e.g. nif_open.
* This does the initial validation and argument processing and then
* calls the function that does the actual work. This is called
- * 'n<something>'.
+ * 'esock_<something>'.
* ----------------------------------------------------------------------
*
*
@@ -354,11 +354,11 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
/* Debug stuff... */
-#define SOCKET_GLOBAL_DEBUG_DEFAULT FALSE
-#define SOCKET_DEBUG_DEFAULT FALSE
+#define ESOCK_GLOBAL_DEBUG_DEFAULT FALSE
+#define ESOCK_DEBUG_DEFAULT FALSE
/* Counters and stuff (Don't know where to sent this stuff anyway) */
-#define SOCKET_NIF_IOW_DEFAULT FALSE
+#define ESOCK_NIF_IOW_DEFAULT FALSE
@@ -398,10 +398,10 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
#if defined(TCP_CA_NAME_MAX)
-#define SOCKET_OPT_TCP_CONGESTION_NAME_MAX TCP_CA_NAME_MAX
+#define ESOCK_OPT_TCP_CONGESTION_NAME_MAX TCP_CA_NAME_MAX
#else
/* This is really excessive, but just in case... */
-#define SOCKET_OPT_TCP_CONGESTION_NAME_MAX 256
+#define ESOCK_OPT_TCP_CONGESTION_NAME_MAX 256
#endif
@@ -414,24 +414,25 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
/* *** Socket state defs *** */
-#define SOCKET_FLAG_OPEN 0x0001
-#define SOCKET_FLAG_ACTIVE 0x0004
-#define SOCKET_FLAG_LISTEN 0x0008
-#define SOCKET_FLAG_CON 0x0010
-#define SOCKET_FLAG_ACC 0x0020
-#define SOCKET_FLAG_BUSY 0x0040
-#define SOCKET_FLAG_CLOSE 0x0080
-
-#define SOCKET_STATE_CLOSED (0)
-#define SOCKET_STATE_OPEN (SOCKET_FLAG_OPEN)
-#define SOCKET_STATE_CONNECTED (SOCKET_STATE_OPEN | SOCKET_FLAG_ACTIVE)
-#define SOCKET_STATE_LISTENING (SOCKET_STATE_OPEN | SOCKET_FLAG_LISTEN)
-#define SOCKET_STATE_CONNECTING (SOCKET_STATE_OPEN | SOCKET_FLAG_CON)
-#define SOCKET_STATE_ACCEPTING (SOCKET_STATE_LISTENING | SOCKET_FLAG_ACC)
-#define SOCKET_STATE_CLOSING (SOCKET_FLAG_CLOSE)
+#define ESOCK_FLAG_OPEN 0x0001
+#define ESOCK_FLAG_ACTIVE 0x0004
+#define ESOCK_FLAG_LISTEN 0x0008
+#define ESOCK_FLAG_CON 0x0010
+#define ESOCK_FLAG_ACC 0x0020
+#define ESOCK_FLAG_BUSY 0x0040
+#define ESOCK_FLAG_CLOSE 0x0080
+
+#define ESOCK_STATE_CLOSED (0)
+#define ESOCK_STATE_OPEN (ESOCK_FLAG_OPEN)
+#define ESOCK_STATE_CONNECTED (ESOCK_STATE_OPEN | ESOCK_FLAG_ACTIVE)
+#define ESOCK_STATE_LISTENING (ESOCK_STATE_OPEN | ESOCK_FLAG_LISTEN)
+#define ESOCK_STATE_CONNECTING (ESOCK_STATE_OPEN | ESOCK_FLAG_CON)
+#define ESOCK_STATE_ACCEPTING (ESOCK_STATE_LISTENING | ESOCK_FLAG_ACC)
+#define ESOCK_STATE_CLOSING (ESOCK_FLAG_CLOSE)
+#define ESOCK_STATE_DTOR (0xFFFF)
#define IS_CLOSED(d) \
- ((d)->state == SOCKET_STATE_CLOSED)
+ ((d)->state == ESOCK_STATE_CLOSED)
/*
#define IS_STATE(d, f) \
@@ -439,52 +440,59 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
*/
#define IS_CLOSING(d) \
- (((d)->state & SOCKET_STATE_CLOSING) == SOCKET_STATE_CLOSING)
+ (((d)->state & ESOCK_STATE_CLOSING) == ESOCK_STATE_CLOSING)
#define IS_OPEN(d) \
- (((d)->state & SOCKET_FLAG_OPEN) == SOCKET_FLAG_OPEN)
+ (((d)->state & ESOCK_FLAG_OPEN) == ESOCK_FLAG_OPEN)
#define IS_CONNECTED(d) \
- (((d)->state & SOCKET_STATE_CONNECTED) == SOCKET_STATE_CONNECTED)
+ (((d)->state & ESOCK_STATE_CONNECTED) == ESOCK_STATE_CONNECTED)
#define IS_CONNECTING(d) \
- (((d)->state & SOCKET_FLAG_CON) == SOCKET_FLAG_CON)
+ (((d)->state & ESOCK_FLAG_CON) == ESOCK_FLAG_CON)
/*
#define IS_BUSY(d) \
- (((d)->state & SOCKET_FLAG_BUSY) == SOCKET_FLAG_BUSY)
+ (((d)->state & ESOCK_FLAG_BUSY) == ESOCK_FLAG_BUSY)
*/
-#define SOCKET_SEND_FLAG_CONFIRM 0
-#define SOCKET_SEND_FLAG_DONTROUTE 1
-#define SOCKET_SEND_FLAG_EOR 2
-#define SOCKET_SEND_FLAG_MORE 3
-#define SOCKET_SEND_FLAG_NOSIGNAL 4
-#define SOCKET_SEND_FLAG_OOB 5
-#define SOCKET_SEND_FLAG_LOW SOCKET_SEND_FLAG_CONFIRM
-#define SOCKET_SEND_FLAG_HIGH SOCKET_SEND_FLAG_OOB
-
-#define SOCKET_RECV_FLAG_CMSG_CLOEXEC 0
-#define SOCKET_RECV_FLAG_ERRQUEUE 1
-#define SOCKET_RECV_FLAG_OOB 2
-#define SOCKET_RECV_FLAG_PEEK 3
-#define SOCKET_RECV_FLAG_TRUNC 4
-#define SOCKET_RECV_FLAG_LOW SOCKET_RECV_FLAG_CMSG_CLOEXEC
-#define SOCKET_RECV_FLAG_HIGH SOCKET_RECV_FLAG_TRUNC
-
-#define SOCKET_RECV_BUFFER_SIZE_DEFAULT 8192
-#define SOCKET_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024
-#define SOCKET_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024
-
-#define VT2S(__VT__) (((__VT__) == SOCKET_OPT_VALUE_TYPE_UNSPEC) ? "unspec" : \
- (((__VT__) == SOCKET_OPT_VALUE_TYPE_INT) ? "int" : \
- ((__VT__) == SOCKET_OPT_VALUE_TYPE_BOOL) ? "bool" : \
+#define ESOCK_GET_RESOURCE(ENV, REF, RES) \
+ enif_get_resource((ENV), (REF), esocks, (RES))
+
+#define ESOCK_SEND_FLAG_CONFIRM 0
+#define ESOCK_SEND_FLAG_DONTROUTE 1
+#define ESOCK_SEND_FLAG_EOR 2
+#define ESOCK_SEND_FLAG_MORE 3
+#define ESOCK_SEND_FLAG_NOSIGNAL 4
+#define ESOCK_SEND_FLAG_OOB 5
+#define ESOCK_SEND_FLAG_LOW ESOCK_SEND_FLAG_CONFIRM
+#define ESOCK_SEND_FLAG_HIGH ESOCK_SEND_FLAG_OOB
+
+#define ESOCK_RECV_FLAG_CMSG_CLOEXEC 0
+#define ESOCK_RECV_FLAG_ERRQUEUE 1
+#define ESOCK_RECV_FLAG_OOB 2
+#define ESOCK_RECV_FLAG_PEEK 3
+#define ESOCK_RECV_FLAG_TRUNC 4
+#define ESOCK_RECV_FLAG_LOW ESOCK_RECV_FLAG_CMSG_CLOEXEC
+#define ESOCK_RECV_FLAG_HIGH ESOCK_RECV_FLAG_TRUNC
+
+#define ESOCK_RECV_BUFFER_SIZE_DEFAULT 8192
+#define ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024
+#define ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024
+
+#define VT2S(__VT__) (((__VT__) == ESOCK_OPT_VALUE_TYPE_UNSPEC) ? "unspec" : \
+ (((__VT__) == ESOCK_OPT_VALUE_TYPE_INT) ? "int" : \
+ ((__VT__) == ESOCK_OPT_VALUE_TYPE_BOOL) ? "bool" : \
"undef"))
-#define SOCKET_OPT_VALUE_TYPE_UNSPEC 0
-#define SOCKET_OPT_VALUE_TYPE_INT 1
-#define SOCKET_OPT_VALUE_TYPE_BOOL 2
+#define ESOCK_OPT_VALUE_TYPE_UNSPEC 0
+#define ESOCK_OPT_VALUE_TYPE_INT 1
+#define ESOCK_OPT_VALUE_TYPE_BOOL 2
+#define ESOCK_DESC_PATTERN_CREATED 0x03030303
+#define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0
+
+/*
typedef union {
struct {
// 0 = not open, 1 = open
@@ -497,15 +505,16 @@ typedef union {
unsigned int listen:2;
// unsigned int listening:1;
// unsigned int accepting:1;
- /* Room for more... */
+ / * Room for more... * /
} flags;
unsigned int field; // Make it easy to reset all flags...
} SocketState;
+*/
/*
#define IS_OPEN(d) ((d)->state.flags.open)
-#define IS_CONNECTED(d) ((d)->state.flags.connect == SOCKET_STATE_CONNECTED)
-#define IS_CONNECTING(d) ((d)->state.flags.connect == SOCKET_STATE_CONNECTING)
+#define IS_CONNECTED(d) ((d)->state.flags.connect == ESOCK_STATE_CONNECTED)
+#define IS_CONNECTING(d) ((d)->state.flags.connect == ESOCK_STATE_CONNECTING)
*/
@@ -516,154 +525,160 @@ typedef union {
*/
/* domain */
-#define SOCKET_DOMAIN_LOCAL 1
-#define SOCKET_DOMAIN_INET 2
-#define SOCKET_DOMAIN_INET6 3
+#define ESOCK_DOMAIN_LOCAL 1
+#define ESOCK_DOMAIN_INET 2
+#define ESOCK_DOMAIN_INET6 3
/* type */
-#define SOCKET_TYPE_STREAM 1
-#define SOCKET_TYPE_DGRAM 2
-#define SOCKET_TYPE_RAW 3
-// #define SOCKET_TYPE_RDM 4
-#define SOCKET_TYPE_SEQPACKET 5
+#define ESOCK_TYPE_STREAM 1
+#define ESOCK_TYPE_DGRAM 2
+#define ESOCK_TYPE_RAW 3
+// #define ESOCK_TYPE_RDM 4
+#define ESOCK_TYPE_SEQPACKET 5
/* protocol */
-#define SOCKET_PROTOCOL_IP 1
-#define SOCKET_PROTOCOL_TCP 2
-#define SOCKET_PROTOCOL_UDP 3
-#define SOCKET_PROTOCOL_SCTP 4
-#define SOCKET_PROTOCOL_ICMP 5
-#define SOCKET_PROTOCOL_IGMP 6
+#define ESOCK_PROTOCOL_DEFAULT 0
+#define ESOCK_PROTOCOL_IP 1
+#define ESOCK_PROTOCOL_TCP 2
+#define ESOCK_PROTOCOL_UDP 3
+#define ESOCK_PROTOCOL_SCTP 4
+#define ESOCK_PROTOCOL_ICMP 5
+#define ESOCK_PROTOCOL_IGMP 6
/* shutdown how */
-#define SOCKET_SHUTDOWN_HOW_RD 0
-#define SOCKET_SHUTDOWN_HOW_WR 1
-#define SOCKET_SHUTDOWN_HOW_RDWR 2
-
-
-#define SOCKET_OPT_LEVEL_OTP 0
-#define SOCKET_OPT_LEVEL_SOCKET 1
-#define SOCKET_OPT_LEVEL_IP 2
-#define SOCKET_OPT_LEVEL_IPV6 3
-#define SOCKET_OPT_LEVEL_TCP 4
-#define SOCKET_OPT_LEVEL_UDP 5
-#define SOCKET_OPT_LEVEL_SCTP 6
-
-#define SOCKET_OPT_OTP_DEBUG 1
-#define SOCKET_OPT_OTP_IOW 2
-#define SOCKET_OPT_OTP_CTRL_PROC 3
-#define SOCKET_OPT_OTP_RCVBUF 4
-#define SOCKET_OPT_OTP_RCVCTRLBUF 6
-#define SOCKET_OPT_OTP_SNDCTRLBUF 7
-#define SOCKET_OPT_OTP_FD 8
-#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
-#define SOCKET_OPT_SOCK_BROADCAST 4
-#define SOCKET_OPT_SOCK_DEBUG 6
-#define SOCKET_OPT_SOCK_DOMAIN 7
-#define SOCKET_OPT_SOCK_DONTROUTE 8
-#define SOCKET_OPT_SOCK_KEEPALIVE 10
-#define SOCKET_OPT_SOCK_LINGER 11
-#define SOCKET_OPT_SOCK_OOBINLINE 13
-#define SOCKET_OPT_SOCK_PEEK_OFF 15
-#define SOCKET_OPT_SOCK_PRIORITY 17
-#define SOCKET_OPT_SOCK_PROTOCOL 18
-#define SOCKET_OPT_SOCK_RCVBUF 19
-#define SOCKET_OPT_SOCK_RCVLOWAT 21
-#define SOCKET_OPT_SOCK_RCVTIMEO 22
-#define SOCKET_OPT_SOCK_REUSEADDR 23
-#define SOCKET_OPT_SOCK_REUSEPORT 24
-#define SOCKET_OPT_SOCK_SNDBUF 27
-#define SOCKET_OPT_SOCK_SNDLOWAT 29
-#define SOCKET_OPT_SOCK_SNDTIMEO 30
-#define SOCKET_OPT_SOCK_TIMESTAMP 31
-#define SOCKET_OPT_SOCK_TYPE 32
-
-#define SOCKET_OPT_IP_ADD_MEMBERSHIP 1
-#define SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP 2
-#define SOCKET_OPT_IP_BLOCK_SOURCE 3
-#define SOCKET_OPT_IP_DROP_MEMBERSHIP 5
-#define SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP 6
-#define SOCKET_OPT_IP_FREEBIND 7
-#define SOCKET_OPT_IP_HDRINCL 8
-#define SOCKET_OPT_IP_MINTTL 9
-#define SOCKET_OPT_IP_MSFILTER 10
-#define SOCKET_OPT_IP_MTU 11
-#define SOCKET_OPT_IP_MTU_DISCOVER 12
-#define SOCKET_OPT_IP_MULTICAST_ALL 13
-#define SOCKET_OPT_IP_MULTICAST_IF 14
-#define SOCKET_OPT_IP_MULTICAST_LOOP 15
-#define SOCKET_OPT_IP_MULTICAST_TTL 16
-#define SOCKET_OPT_IP_NODEFRAG 17
-#define SOCKET_OPT_IP_PKTINFO 19
-#define SOCKET_OPT_IP_RECVDSTADDR 20
-#define SOCKET_OPT_IP_RECVERR 21
-#define SOCKET_OPT_IP_RECVIF 22
-#define SOCKET_OPT_IP_RECVOPTS 23
-#define SOCKET_OPT_IP_RECVORIGDSTADDR 24
-#define SOCKET_OPT_IP_RECVTOS 25
-#define SOCKET_OPT_IP_RECVTTL 26
-#define SOCKET_OPT_IP_RETOPTS 27
-#define SOCKET_OPT_IP_ROUTER_ALERT 28
-#define SOCKET_OPT_IP_SENDSRCADDR 29 // Same as IP_RECVDSTADDR?
-#define SOCKET_OPT_IP_TOS 30
-#define SOCKET_OPT_IP_TRANSPARENT 31
-#define SOCKET_OPT_IP_TTL 32
-#define SOCKET_OPT_IP_UNBLOCK_SOURCE 33
-
-#define SOCKET_OPT_IPV6_ADDRFORM 1
-#define SOCKET_OPT_IPV6_ADD_MEMBERSHIP 2
-#define SOCKET_OPT_IPV6_AUTHHDR 3
-#define SOCKET_OPT_IPV6_DROP_MEMBERSHIP 6
-#define SOCKET_OPT_IPV6_DSTOPTS 7
-#define SOCKET_OPT_IPV6_FLOWINFO 11
-#define SOCKET_OPT_IPV6_HOPLIMIT 12
-#define SOCKET_OPT_IPV6_HOPOPTS 13
-#define SOCKET_OPT_IPV6_MTU 17
-#define SOCKET_OPT_IPV6_MTU_DISCOVER 18
-#define SOCKET_OPT_IPV6_MULTICAST_HOPS 19
-#define SOCKET_OPT_IPV6_MULTICAST_IF 20
-#define SOCKET_OPT_IPV6_MULTICAST_LOOP 21
-#define SOCKET_OPT_IPV6_RECVERR 24
-#define SOCKET_OPT_IPV6_RECVPKTINFO 25 // PKTINFO on FreeBSD
-#define SOCKET_OPT_IPV6_ROUTER_ALERT 27
-#define SOCKET_OPT_IPV6_RTHDR 28
-#define SOCKET_OPT_IPV6_UNICAST_HOPS 30
-#define SOCKET_OPT_IPV6_V6ONLY 32
-
-#define SOCKET_OPT_TCP_CONGESTION 1
-#define SOCKET_OPT_TCP_CORK 2
-#define SOCKET_OPT_TCP_MAXSEG 7
-#define SOCKET_OPT_TCP_NODELAY 9
-
-#define SOCKET_OPT_UDP_CORK 1
-
-#define SOCKET_OPT_SCTP_ASSOCINFO 2
-#define SOCKET_OPT_SCTP_AUTOCLOSE 8
-#define SOCKET_OPT_SCTP_DISABLE_FRAGMENTS 12
-#define SOCKET_OPT_SCTP_EVENTS 14
-#define SOCKET_OPT_SCTP_INITMSG 18
-#define SOCKET_OPT_SCTP_MAXSEG 21
-#define SOCKET_OPT_SCTP_NODELAY 23
-#define SOCKET_OPT_SCTP_RTOINFO 29
+#define ESOCK_SHUTDOWN_HOW_RD 0
+#define ESOCK_SHUTDOWN_HOW_WR 1
+#define ESOCK_SHUTDOWN_HOW_RDWR 2
+
+
+#define ESOCK_OPT_LEVEL_OTP 0
+#define ESOCK_OPT_LEVEL_SOCKET 1
+#define ESOCK_OPT_LEVEL_IP 2
+#define ESOCK_OPT_LEVEL_IPV6 3
+#define ESOCK_OPT_LEVEL_TCP 4
+#define ESOCK_OPT_LEVEL_UDP 5
+#define ESOCK_OPT_LEVEL_SCTP 6
+
+#define ESOCK_OPT_OTP_DEBUG 1
+#define ESOCK_OPT_OTP_IOW 2
+#define ESOCK_OPT_OTP_CTRL_PROC 3
+#define ESOCK_OPT_OTP_RCVBUF 4
+#define ESOCK_OPT_OTP_RCVCTRLBUF 6
+#define ESOCK_OPT_OTP_SNDCTRLBUF 7
+#define ESOCK_OPT_OTP_FD 8
+#define ESOCK_OPT_OTP_DOMAIN 0xFF01 // INTERNAL AND ONLY GET
+#define ESOCK_OPT_OTP_TYPE 0xFF02 // INTERNAL AND ONLY GET
+#define ESOCK_OPT_OTP_PROTOCOL 0xFF03 // INTERNAL AND ONLY GET
+
+#define ESOCK_OPT_SOCK_ACCEPTCONN 1
+#define ESOCK_OPT_SOCK_BINDTODEVICE 3
+#define ESOCK_OPT_SOCK_BROADCAST 4
+#define ESOCK_OPT_SOCK_DEBUG 6
+#define ESOCK_OPT_SOCK_DOMAIN 7
+#define ESOCK_OPT_SOCK_DONTROUTE 8
+#define ESOCK_OPT_SOCK_KEEPALIVE 10
+#define ESOCK_OPT_SOCK_LINGER 11
+#define ESOCK_OPT_SOCK_OOBINLINE 13
+#define ESOCK_OPT_SOCK_PEEK_OFF 15
+#define ESOCK_OPT_SOCK_PRIORITY 17
+#define ESOCK_OPT_SOCK_PROTOCOL 18
+#define ESOCK_OPT_SOCK_RCVBUF 19
+#define ESOCK_OPT_SOCK_RCVLOWAT 21
+#define ESOCK_OPT_SOCK_RCVTIMEO 22
+#define ESOCK_OPT_SOCK_REUSEADDR 23
+#define ESOCK_OPT_SOCK_REUSEPORT 24
+#define ESOCK_OPT_SOCK_SNDBUF 27
+#define ESOCK_OPT_SOCK_SNDLOWAT 29
+#define ESOCK_OPT_SOCK_SNDTIMEO 30
+#define ESOCK_OPT_SOCK_TIMESTAMP 31
+#define ESOCK_OPT_SOCK_TYPE 32
+
+#define ESOCK_OPT_IP_ADD_MEMBERSHIP 1
+#define ESOCK_OPT_IP_ADD_SOURCE_MEMBERSHIP 2
+#define ESOCK_OPT_IP_BLOCK_SOURCE 3
+#define ESOCK_OPT_IP_DROP_MEMBERSHIP 5
+#define ESOCK_OPT_IP_DROP_SOURCE_MEMBERSHIP 6
+#define ESOCK_OPT_IP_FREEBIND 7
+#define ESOCK_OPT_IP_HDRINCL 8
+#define ESOCK_OPT_IP_MINTTL 9
+#define ESOCK_OPT_IP_MSFILTER 10
+#define ESOCK_OPT_IP_MTU 11
+#define ESOCK_OPT_IP_MTU_DISCOVER 12
+#define ESOCK_OPT_IP_MULTICAST_ALL 13
+#define ESOCK_OPT_IP_MULTICAST_IF 14
+#define ESOCK_OPT_IP_MULTICAST_LOOP 15
+#define ESOCK_OPT_IP_MULTICAST_TTL 16
+#define ESOCK_OPT_IP_NODEFRAG 17
+#define ESOCK_OPT_IP_PKTINFO 19
+#define ESOCK_OPT_IP_RECVDSTADDR 20
+#define ESOCK_OPT_IP_RECVERR 21
+#define ESOCK_OPT_IP_RECVIF 22
+#define ESOCK_OPT_IP_RECVOPTS 23
+#define ESOCK_OPT_IP_RECVORIGDSTADDR 24
+#define ESOCK_OPT_IP_RECVTOS 25
+#define ESOCK_OPT_IP_RECVTTL 26
+#define ESOCK_OPT_IP_RETOPTS 27
+#define ESOCK_OPT_IP_ROUTER_ALERT 28
+#define ESOCK_OPT_IP_SENDSRCADDR 29 // Same as IP_RECVDSTADDR?
+#define ESOCK_OPT_IP_TOS 30
+#define ESOCK_OPT_IP_TRANSPARENT 31
+#define ESOCK_OPT_IP_TTL 32
+#define ESOCK_OPT_IP_UNBLOCK_SOURCE 33
+
+#define ESOCK_OPT_IPV6_ADDRFORM 1
+#define ESOCK_OPT_IPV6_ADD_MEMBERSHIP 2
+#define ESOCK_OPT_IPV6_AUTHHDR 3
+#define ESOCK_OPT_IPV6_DROP_MEMBERSHIP 6
+#define ESOCK_OPT_IPV6_DSTOPTS 7
+#define ESOCK_OPT_IPV6_FLOWINFO 11
+#define ESOCK_OPT_IPV6_HOPLIMIT 12
+#define ESOCK_OPT_IPV6_HOPOPTS 13
+#define ESOCK_OPT_IPV6_MTU 17
+#define ESOCK_OPT_IPV6_MTU_DISCOVER 18
+#define ESOCK_OPT_IPV6_MULTICAST_HOPS 19
+#define ESOCK_OPT_IPV6_MULTICAST_IF 20
+#define ESOCK_OPT_IPV6_MULTICAST_LOOP 21
+#define ESOCK_OPT_IPV6_RECVERR 24
+#define ESOCK_OPT_IPV6_RECVPKTINFO 25 // PKTINFO on FreeBSD
+#define ESOCK_OPT_IPV6_ROUTER_ALERT 27
+#define ESOCK_OPT_IPV6_RTHDR 28
+#define ESOCK_OPT_IPV6_UNICAST_HOPS 30
+#define ESOCK_OPT_IPV6_V6ONLY 32
+
+#define ESOCK_OPT_TCP_CONGESTION 1
+#define ESOCK_OPT_TCP_CORK 2
+#define ESOCK_OPT_TCP_MAXSEG 7
+#define ESOCK_OPT_TCP_NODELAY 9
+
+#define ESOCK_OPT_UDP_CORK 1
+
+#define ESOCK_OPT_SCTP_ASSOCINFO 2
+#define ESOCK_OPT_SCTP_AUTOCLOSE 8
+#define ESOCK_OPT_SCTP_DISABLE_FRAGMENTS 12
+#define ESOCK_OPT_SCTP_EVENTS 14
+#define ESOCK_OPT_SCTP_INITMSG 18
+#define ESOCK_OPT_SCTP_MAXSEG 21
+#define ESOCK_OPT_SCTP_NODELAY 23
+#define ESOCK_OPT_SCTP_RTOINFO 29
/* We should *eventually* use this instead of hard-coding the size (to 1) */
#define ESOCK_RECVMSG_IOVEC_SZ 1
+#define ESOCK_CMD_DEBUG 0x0001
+
+#define ESOCK_SUPPORTS_OPTIONS 0x0001
+#define ESOCK_SUPPORTS_SCTP 0x0002
+#define ESOCK_SUPPORTS_IPV6 0x0003
+#define ESOCK_SUPPORTS_LOCAL 0x0004
-#define SOCKET_SUPPORTS_OPTIONS 0x0001
-#define SOCKET_SUPPORTS_SCTP 0x0002
-#define SOCKET_SUPPORTS_IPV6 0x0003
+#define ESOCK_WHICH_PROTO_ERROR -1
+#define ESOCK_WHICH_PROTO_UNSUP -2
/* =================================================================== *
* *
- * Various enif macros *
+ * Various esockmacros *
* *
* =================================================================== */
@@ -672,6 +687,12 @@ typedef union {
/* Socket specific debug */
#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto )
+#define SOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \
+ { \
+ if (cnt_inc(CNT, INC) && (__D__)->iow) { \
+ esock_send_wrap_msg(__E__, __D__, SF, ACNT); \
+ } \
+ }
/* =================================================================== *
@@ -803,6 +824,14 @@ typedef struct {
typedef struct {
+ /*
+ * +++ This is a way to, possibly, detect memory overrides "and stuff" +++
+ *
+ * We have two patterns. One is set when the descriptor is created (allocated)
+ * and one is set when the descriptor is dtor'ed.
+ */
+ Uint32 pattern;
+
/* +++ The actual socket +++ */
SOCKET sock;
HANDLE event;
@@ -820,6 +849,10 @@ typedef struct {
ErlNifPid ctrlPid;
ESockMonitor ctrlMon;
+ /* +++ Connector process +++ */
+ ErlNifPid connPid;
+ ESockMonitor connMon;
+
/* +++ Write stuff +++ */
ErlNifMutex* writeMtx;
ESockRequestor currentWriter;
@@ -844,6 +877,7 @@ typedef struct {
Uint32 readByteCnt;
Uint32 readTries;
Uint32 readWaits;
+ Uint32 readFails;
/* +++ Accept stuff +++ */
ErlNifMutex* accMtx;
@@ -927,6 +961,7 @@ extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */
* does the actual work. Except for the info function.
*
* nif_info
+ * nif_command
* nif_supports
* nif_open
* nif_bind
@@ -952,6 +987,7 @@ extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */
#define ESOCK_NIF_FUNCS \
ESOCK_NIF_FUNC_DEF(info); \
+ ESOCK_NIF_FUNC_DEF(command); \
ESOCK_NIF_FUNC_DEF(supports); \
ESOCK_NIF_FUNC_DEF(open); \
ESOCK_NIF_FUNC_DEF(bind); \
@@ -983,1107 +1019,1143 @@ ESOCK_NIF_FUNCS
#if !defined(__WIN32__)
+
/* And here comes the functions that does the actual work (for the most part) */
-static ERL_NIF_TERM nsupports(ErlNifEnv* env, int key);
-static ERL_NIF_TERM nsupports_options(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_udp(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_sctp(ErlNifEnv* env);
-static ERL_NIF_TERM nsupports_ipv6(ErlNifEnv* env);
-
-static ERL_NIF_TERM nopen(ErlNifEnv* env,
+
+static BOOLEAN_T ecommand2command(ErlNifEnv* env,
+ ERL_NIF_TERM ecommand,
+ Uint16* command,
+ ERL_NIF_TERM* edata);
+static ERL_NIF_TERM esock_command(ErlNifEnv* env,
+ Uint16 cmd,
+ ERL_NIF_TERM ecdata);
+static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM ecdata);
+
+static ERL_NIF_TERM esock_global_info(ErlNifEnv* env);
+static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
+ ESockDescriptor* descP);
+#define ESOCK_SOCKET_INFO_REQ_FUNCS \
+ ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \
+ ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \
+ ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors);
+
+#define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \
+ static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \
+ ESockDescriptor* descP);
+ESOCK_SOCKET_INFO_REQ_FUNCS
+#undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF
+
+static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ErlNifMutex* mtx,
+ ESockRequestor* crp,
+ ESockRequestQueue* q);
+
+static ERL_NIF_TERM esock_supports(ErlNifEnv* env, int key);
+static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_socket(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_ip(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_ipv6(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_tcp(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_udp(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_options_sctp(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_sctp(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_ipv6(ErlNifEnv* env);
+static ERL_NIF_TERM esock_supports_local(ErlNifEnv* env);
+
+static ERL_NIF_TERM esock_open(ErlNifEnv* env,
int domain,
int type,
int protocol,
char* netns);
-static ERL_NIF_TERM nbind(ErlNifEnv* env,
- ESockDescriptor* descP,
- ESockAddress* sockAddrP,
- unsigned int addrLen);
-static ERL_NIF_TERM nconnect(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef);
-static ERL_NIF_TERM nlisten(ErlNifEnv* env,
- ESockDescriptor* descP,
- int backlog);
-static ERL_NIF_TERM naccept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref);
-static ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref);
-static ERL_NIF_TERM naccept_listening_error(ErlNifEnv* env,
+static BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto);
+
+static ERL_NIF_TERM esock_bind(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESockAddress* sockAddrP,
+ unsigned int addrLen);
+static ERL_NIF_TERM esock_connect(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM esock_listen(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int backlog);
+static ERL_NIF_TERM esock_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref);
+static ERL_NIF_TERM esock_accept_listening(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref);
+static ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM accRef,
+ ErlNifPid caller,
+ int save_errno);
+static ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ SOCKET accSock,
+ ErlNifPid caller,
+ ESockAddress* remote);
+static ERL_NIF_TERM esock_accept_accepting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref);
+static ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref);
+static ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ SOCKET accSock,
+ ESockAddress* remote);
+static ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef,
+ int save_errno);
+static ERL_NIF_TERM esock_accept_accepting_other(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM ref,
+ ErlNifPid caller);
+static ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM accRef,
- ErlNifPid caller,
- int save_errno);
-static ERL_NIF_TERM naccept_listening_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- SOCKET accSock,
- ErlNifPid caller,
- ESockAddress* remote);
-static ERL_NIF_TERM naccept_accepting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref);
-static ERL_NIF_TERM naccept_accepting_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref);
-static ERL_NIF_TERM naccept_accepting_current_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- SOCKET accSock,
- ESockAddress* remote);
-static ERL_NIF_TERM naccept_accepting_current_error(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef,
- int save_errno);
-static ERL_NIF_TERM naccept_accepting_other(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM ref,
- ErlNifPid caller);
-static ERL_NIF_TERM naccept_busy_retry(ErlNifEnv* env,
+ ErlNifPid* pid,
+ unsigned int nextState);
+static BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM accRef,
- ErlNifPid* pid,
- unsigned int nextState);
-static BOOLEAN_T naccept_accepted(ErlNifEnv* env,
+ SOCKET accSock,
+ ErlNifPid pid,
+ ESockAddress* remote,
+ ERL_NIF_TERM* result);
+static ERL_NIF_TERM esock_send(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ErlNifBinary* dataP,
+ int flags);
+static ERL_NIF_TERM esock_sendto(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ErlNifBinary* dataP,
+ int flags,
+ ESockAddress* toAddrP,
+ unsigned int toAddrLen);
+static ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
ESockDescriptor* descP,
- SOCKET accSock,
- ErlNifPid pid,
- ESockAddress* remote,
- ERL_NIF_TERM* result);
-static ERL_NIF_TERM nsend(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ErlNifBinary* dataP,
- int flags);
-static ERL_NIF_TERM nsendto(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ErlNifBinary* dataP,
- int flags,
- ESockAddress* toAddrP,
- unsigned int toAddrLen);
-static ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ERL_NIF_TERM eMsgHdr,
- int flags);
-static ERL_NIF_TERM nrecv(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sendRef,
- ERL_NIF_TERM recvRef,
- int len,
- int flags);
-static ERL_NIF_TERM nrecvfrom(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef,
- Uint16 bufSz,
- int flags);
-static ERL_NIF_TERM nrecvmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef,
- Uint16 bufLen,
- Uint16 ctrlLen,
- int flags);
-static ERL_NIF_TERM nclose(ErlNifEnv* env,
- ESockDescriptor* descP);
-static BOOLEAN_T nclose_check(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM* reason);
-static ERL_NIF_TERM nclose_do(ErlNifEnv* env,
- ESockDescriptor* descP);
-static ERL_NIF_TERM nshutdown(ErlNifEnv* env,
- ESockDescriptor* descP,
- int how);
-static ERL_NIF_TERM nsetopt(ErlNifEnv* env,
- ESockDescriptor* descP,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal);
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ERL_NIF_TERM eMsgHdr,
+ int flags);
+static ERL_NIF_TERM esock_recv(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sendRef,
+ ERL_NIF_TERM recvRef,
+ int len,
+ int flags);
+static ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef,
+ Uint16 bufSz,
+ int flags);
+static ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef,
+ Uint16 bufLen,
+ Uint16 ctrlLen,
+ int flags);
+static ERL_NIF_TERM esock_close(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static BOOLEAN_T esock_close_check(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM* reason);
+static ERL_NIF_TERM esock_close_do(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int how);
+static ERL_NIF_TERM esock_setopt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ BOOLEAN_T isEncoded,
+ BOOLEAN_T isOTP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal);
/* Set OTP level options */
-static ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
-/* *** nsetopt_otp_debug ***
- * *** nsetopt_otp_iow ***
- * *** nsetopt_otp_ctrl_proc ***
- * *** nsetopt_otp_rcvbuf ***
- * *** nsetopt_otp_rcvctrlbuf ***
- * *** nsetopt_otp_sndctrlbuf ***
- */
-#define NSETOPT_OTP_FUNCS \
- NSETOPT_OTP_FUNC_DEF(debug); \
- NSETOPT_OTP_FUNC_DEF(iow); \
- NSETOPT_OTP_FUNC_DEF(ctrl_proc); \
- NSETOPT_OTP_FUNC_DEF(rcvbuf); \
- NSETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
- NSETOPT_OTP_FUNC_DEF(sndctrlbuf);
-#define NSETOPT_OTP_FUNC_DEF(F) \
- static ERL_NIF_TERM nsetopt_otp_##F(ErlNifEnv* env, \
- ESockDescriptor* descP, \
- ERL_NIF_TERM eVal)
-NSETOPT_OTP_FUNCS
-#undef NSETOPT_OTP_FUNC_DEF
+static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+/* *** esock_setopt_otp_debug ***
+ * *** esock_setopt_otp_iow ***
+ * *** esock_setopt_otp_ctrl_proc ***
+ * *** esock_setopt_otp_rcvbuf ***
+ * *** esock_setopt_otp_rcvctrlbuf ***
+ * *** esock_setopt_otp_sndctrlbuf ***
+ */
+#define ESOCK_SETOPT_OTP_FUNCS \
+ ESOCK_SETOPT_OTP_FUNC_DEF(debug); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(iow); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf);
+#define ESOCK_SETOPT_OTP_FUNC_DEF(F) \
+ static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \
+ ESockDescriptor* descP, \
+ ERL_NIF_TERM eVal)
+ESOCK_SETOPT_OTP_FUNCS
+#undef ESOCK_SETOPT_OTP_FUNC_DEF
/* Set native options */
-static ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal);
-static ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal);
-static ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
+static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_level(ErlNifEnv* env,
ESockDescriptor* descP,
+ int level,
int eOpt,
ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_socket(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
/* *** Handling set of socket options for level = socket *** */
#if defined(SO_BINDTODEVICE)
-static ERL_NIF_TERM nsetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_BROADCAST)
-static ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_broadcast(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_DEBUG)
-static ERL_NIF_TERM nsetopt_lvl_sock_debug(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_debug(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_DONTROUTE)
-static ERL_NIF_TERM nsetopt_lvl_sock_dontroute(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_dontroute(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_KEEPALIVE)
-static ERL_NIF_TERM nsetopt_lvl_sock_keepalive(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_keepalive(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_LINGER)
-static ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_linger(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_OOBINLINE)
-static ERL_NIF_TERM nsetopt_lvl_sock_oobinline(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_oobinline(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_PEEK_OFF)
-static ERL_NIF_TERM nsetopt_lvl_sock_peek_off(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_peek_off(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_PRIORITY)
-static ERL_NIF_TERM nsetopt_lvl_sock_priority(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_priority(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_RCVBUF)
-static ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_RCVLOWAT)
-static ERL_NIF_TERM nsetopt_lvl_sock_rcvlowat(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_rcvlowat(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_RCVTIMEO)
-static ERL_NIF_TERM nsetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_REUSEADDR)
-static ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_REUSEPORT)
-static ERL_NIF_TERM nsetopt_lvl_sock_reuseport(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_reuseport(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_SNDBUF)
-static ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_SNDLOWAT)
-static ERL_NIF_TERM nsetopt_lvl_sock_sndlowat(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_sndlowat(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_SNDTIMEO)
-static ERL_NIF_TERM nsetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SO_TIMESTAMP)
-static ERL_NIF_TERM nsetopt_lvl_sock_timestamp(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sock_timestamp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
-static ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
/* *** Handling set of socket options for level = ip *** */
#if defined(IP_ADD_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ip_add_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_add_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_ADD_SOURCE_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ip_add_source_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_add_source_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_BLOCK_SOURCE)
-static ERL_NIF_TERM nsetopt_lvl_ip_block_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_block_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_DROP_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ip_drop_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_drop_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_DROP_SOURCE_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ip_drop_source_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_drop_source_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_FREEBIND)
-static ERL_NIF_TERM nsetopt_lvl_ip_freebind(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_freebind(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_HDRINCL)
-static ERL_NIF_TERM nsetopt_lvl_ip_hdrincl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_hdrincl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MINTTL)
-static ERL_NIF_TERM nsetopt_lvl_ip_minttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_minttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
-static ERL_NIF_TERM nsetopt_lvl_ip_msfilter(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_msfilter(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
static BOOLEAN_T decode_ip_msfilter_mode(ErlNifEnv* env,
ERL_NIF_TERM eVal,
Uint32* mode);
-static ERL_NIF_TERM nsetopt_lvl_ip_msfilter_set(ErlNifEnv* env,
- SOCKET sock,
- struct ip_msfilter* msfP,
- SOCKLEN_T optLen);
+static ERL_NIF_TERM esock_setopt_lvl_ip_msfilter_set(ErlNifEnv* env,
+ SOCKET sock,
+ struct ip_msfilter* msfP,
+ SOCKLEN_T optLen);
#endif
#if defined(IP_MTU_DISCOVER)
-static ERL_NIF_TERM nsetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MULTICAST_ALL)
-static ERL_NIF_TERM nsetopt_lvl_ip_multicast_all(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_multicast_all(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MULTICAST_IF)
-static ERL_NIF_TERM nsetopt_lvl_ip_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MULTICAST_LOOP)
-static ERL_NIF_TERM nsetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_MULTICAST_TTL)
-static ERL_NIF_TERM nsetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_NODEFRAG)
-static ERL_NIF_TERM nsetopt_lvl_ip_nodefrag(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_nodefrag(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_PKTINFO)
-static ERL_NIF_TERM nsetopt_lvl_ip_pktinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_pktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVDSTADDR)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVERR)
-static ERL_NIF_TERM nsetopt_lvl_ip_recverr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVIF)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvif(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvif(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVOPTS)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVORIGDSTADDR)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVTOS)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvtos(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RECVTTL)
-static ERL_NIF_TERM nsetopt_lvl_ip_recvttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_recvttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_RETOPTS)
-static ERL_NIF_TERM nsetopt_lvl_ip_retopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
-#endif
-#if defined(IP_ROUTER_ALERT)
-static ERL_NIF_TERM nsetopt_lvl_ip_router_alert(ErlNifEnv* env,
+static ERL_NIF_TERM esock_setopt_lvl_ip_retopts(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(IP_ROUTER_ALERT)
+static ERL_NIF_TERM esock_setopt_lvl_ip_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IP_SENDSRCADDR)
-static ERL_NIF_TERM nsetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_TOS)
-static ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_tos(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_TRANSPARENT)
-static ERL_NIF_TERM nsetopt_lvl_ip_transparent(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_transparent(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_TTL)
-static ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_UNBLOCK_SOURCE)
-static ERL_NIF_TERM nsetopt_lvl_ip_unblock_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ip_unblock_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IP_DROP_MEMBERSHIP) || defined(IP_ADD_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_update_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt);
+ERL_NIF_TERM esock_setopt_lvl_ip_update_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt);
#endif
#if defined(IP_ADD_SOURCE_MEMBERSHIP) || defined(IP_DROP_SOURCE_MEMBERSHIP) || defined(IP_BLOCK_SOURCE) || defined(IP_UNBLOCK_SOURCE)
static
-ERL_NIF_TERM nsetopt_lvl_ip_update_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt);
+ERL_NIF_TERM esock_setopt_lvl_ip_update_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt);
#endif
/* *** Handling set of socket options for level = ipv6 *** */
#if defined(HAVE_IPV6)
-static ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
#if defined(IPV6_ADDRFORM)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_addrform(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_ADD_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_add_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_AUTHHDR)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_authhdr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_authhdr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_DROP_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_DSTOPTS)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_dstopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_dstopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_FLOWINFO)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_HOPLIMIT)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_HOPOPTS)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_hopopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_MTU)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_mtu(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_MTU_DISCOVER)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_MULTICAST_HOPS)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_MULTICAST_IF)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_MULTICAST_LOOP)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_RECVERR)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_recverr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_ROUTER_ALERT)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_RTHDR)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_UNICAST_HOPS)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_V6ONLY)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_v6only(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
-static ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt);
+static ERL_NIF_TERM esock_setopt_lvl_ipv6_update_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt);
#endif
#endif // defined(HAVE_IPV6)
-static ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_tcp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
#if defined(TCP_CONGESTION)
-static ERL_NIF_TERM nsetopt_lvl_tcp_congestion(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_tcp_congestion(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(TCP_MAXSEG)
-static ERL_NIF_TERM nsetopt_lvl_tcp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(TCP_NODELAY)
-static ERL_NIF_TERM nsetopt_lvl_tcp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
-static ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
-#if defined(UDP_CORK)
-static ERL_NIF_TERM nsetopt_lvl_udp_cork(ErlNifEnv* env,
+static ERL_NIF_TERM esock_setopt_lvl_udp(ErlNifEnv* env,
ESockDescriptor* descP,
+ int eOpt,
ERL_NIF_TERM eVal);
+#if defined(UDP_CORK)
+static ERL_NIF_TERM esock_setopt_lvl_udp_cork(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(HAVE_SCTP)
-static ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal);
#if defined(SCTP_ASSOCINFO)
-static ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_AUTOCLOSE)
-static ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_DISABLE_FRAGMENTS)
-static ERL_NIF_TERM nsetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_EVENTS)
-static ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_events(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_INITMSG)
-static ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_MAXSEG)
-static ERL_NIF_TERM nsetopt_lvl_sctp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_NODELAY)
-static ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#if defined(SCTP_RTOINFO)
-static ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal);
#endif
#endif // defined(HAVE_SCTP)
-static ERL_NIF_TERM ngetopt(ErlNifEnv* env,
- ESockDescriptor* descP,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- ERL_NIF_TERM eOpt);
+static ERL_NIF_TERM esock_getopt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ BOOLEAN_T isEncoded,
+ BOOLEAN_T isOTP,
+ int level,
+ ERL_NIF_TERM eOpt);
-static ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
-/* *** ngetopt_otp_debug ***
- * *** ngetopt_otp_iow ***
- * *** ngetopt_otp_ctrl_proc ***
- * *** ngetopt_otp_rcvbuf ***
- * *** ngetopt_otp_rcvctrlbuf ***
- * *** ngetopt_otp_sndctrlbuf ***
- * *** ngetopt_otp_fd ***
- * *** ngetopt_otp_domain ***
- * *** ngetopt_otp_type ***
- * *** ngetopt_otp_protocol ***
- */
-#define NGETOPT_OTP_FUNCS \
- NGETOPT_OTP_FUNC_DEF(debug); \
- NGETOPT_OTP_FUNC_DEF(iow); \
- NGETOPT_OTP_FUNC_DEF(ctrl_proc); \
- NGETOPT_OTP_FUNC_DEF(rcvbuf); \
- NGETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
- NGETOPT_OTP_FUNC_DEF(sndctrlbuf); \
- NGETOPT_OTP_FUNC_DEF(fd); \
- NGETOPT_OTP_FUNC_DEF(domain); \
- NGETOPT_OTP_FUNC_DEF(type); \
- NGETOPT_OTP_FUNC_DEF(protocol);
-#define NGETOPT_OTP_FUNC_DEF(F) \
- static ERL_NIF_TERM ngetopt_otp_##F(ErlNifEnv* env, \
- ESockDescriptor* descP)
-NGETOPT_OTP_FUNCS
-#undef NGETOPT_OTP_FUNC_DEF
+static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
+/* *** esock_getopt_otp_debug ***
+ * *** esock_getopt_otp_iow ***
+ * *** esock_getopt_otp_ctrl_proc ***
+ * *** esock_getopt_otp_rcvbuf ***
+ * *** esock_getopt_otp_rcvctrlbuf ***
+ * *** esock_getopt_otp_sndctrlbuf ***
+ * *** esock_getopt_otp_fd ***
+ * *** esock_getopt_otp_domain ***
+ * *** esock_getopt_otp_type ***
+ * *** esock_getopt_otp_protocol ***
+ */
+#define ESOCK_GETOPT_OTP_FUNCS \
+ ESOCK_GETOPT_OTP_FUNC_DEF(debug); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(iow); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(fd); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(domain); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(type); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(protocol);
+#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \
+ static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \
+ ESockDescriptor* descP)
+ESOCK_GETOPT_OTP_FUNCS
+#undef ESOCK_GETOPT_OTP_FUNC_DEF
-static ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- ERL_NIF_TERM eOpt);
-static ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- SOCKOPTLEN_T valueSz);
-static ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int eOpt);
-static ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
+static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ ERL_NIF_TERM eOpt);
+static ERL_NIF_TERM esock_getopt_native_unspec(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ SOCKOPTLEN_T valueSz);
+static ERL_NIF_TERM esock_getopt_level(ErlNifEnv* env,
ESockDescriptor* descP,
+ int level,
int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_socket(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(SO_ACCEPTCONN)
-static ERL_NIF_TERM ngetopt_lvl_sock_acceptconn(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_acceptconn(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_BINDTODEVICE)
-static ERL_NIF_TERM ngetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_BROADCAST)
-static ERL_NIF_TERM ngetopt_lvl_sock_broadcast(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_broadcast(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_DEBUG)
-static ERL_NIF_TERM ngetopt_lvl_sock_debug(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_debug(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_DOMAIN)
-static ERL_NIF_TERM ngetopt_lvl_sock_domain(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_domain(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_DONTROUTE)
-static ERL_NIF_TERM ngetopt_lvl_sock_dontroute(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_dontroute(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_KEEPALIVE)
-static ERL_NIF_TERM ngetopt_lvl_sock_keepalive(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_keepalive(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_LINGER)
-static ERL_NIF_TERM ngetopt_lvl_sock_linger(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_linger(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_OOBINLINE)
-static ERL_NIF_TERM ngetopt_lvl_sock_oobinline(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_oobinline(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_PEEK_OFF)
-static ERL_NIF_TERM ngetopt_lvl_sock_peek_off(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_peek_off(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_PRIORITY)
-static ERL_NIF_TERM ngetopt_lvl_sock_priority(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_priority(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_PROTOCOL)
-static ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_protocol(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_RCVBUF)
-static ERL_NIF_TERM ngetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_RCVLOWAT)
-static ERL_NIF_TERM ngetopt_lvl_sock_rcvlowat(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_rcvlowat(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_RCVTIMEO)
-static ERL_NIF_TERM ngetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_REUSEADDR)
-static ERL_NIF_TERM ngetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_REUSEPORT)
-static ERL_NIF_TERM ngetopt_lvl_sock_reuseport(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_reuseport(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_SNDBUF)
-static ERL_NIF_TERM ngetopt_lvl_sock_sndbuf(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_SNDLOWAT)
-static ERL_NIF_TERM ngetopt_lvl_sock_sndlowat(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_sndlowat(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_SNDTIMEO)
-static ERL_NIF_TERM ngetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_TIMESTAMP)
-static ERL_NIF_TERM ngetopt_lvl_sock_timestamp(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_timestamp(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SO_TYPE)
-static ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sock_type(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
-static ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_ip(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(IP_FREEBIND)
-static ERL_NIF_TERM ngetopt_lvl_ip_freebind(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_freebind(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_HDRINCL)
-static ERL_NIF_TERM ngetopt_lvl_ip_hdrincl(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_hdrincl(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MINTTL)
-static ERL_NIF_TERM ngetopt_lvl_ip_minttl(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_minttl(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MTU)
-static ERL_NIF_TERM ngetopt_lvl_ip_mtu(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_mtu(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MTU_DISCOVER)
-static ERL_NIF_TERM ngetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MULTICAST_ALL)
-static ERL_NIF_TERM ngetopt_lvl_ip_multicast_all(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_multicast_all(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MULTICAST_IF)
-static ERL_NIF_TERM ngetopt_lvl_ip_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MULTICAST_LOOP)
-static ERL_NIF_TERM ngetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_MULTICAST_TTL)
-static ERL_NIF_TERM ngetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_NODEFRAG)
-static ERL_NIF_TERM ngetopt_lvl_ip_nodefrag(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_nodefrag(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_PKTINFO)
-static ERL_NIF_TERM ngetopt_lvl_ip_pktinfo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_pktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVDSTADDR)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVERR)
-static ERL_NIF_TERM ngetopt_lvl_ip_recverr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVIF)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvif(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvif(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVOPTS)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvopts(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvopts(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVORIGDSTADDR)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVTOS)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvtos(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvtos(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RECVTTL)
-static ERL_NIF_TERM ngetopt_lvl_ip_recvttl(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_recvttl(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_RETOPTS)
-static ERL_NIF_TERM ngetopt_lvl_ip_retopts(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_retopts(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_ROUTER_ALERT)
-static ERL_NIF_TERM ngetopt_lvl_ip_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_SENDSRCADDR)
-static ERL_NIF_TERM ngetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_TOS)
-static ERL_NIF_TERM ngetopt_lvl_ip_tos(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_tos(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_TRANSPARENT)
-static ERL_NIF_TERM ngetopt_lvl_ip_transparent(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_transparent(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IP_TTL)
-static ERL_NIF_TERM ngetopt_lvl_ip_ttl(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ip_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(HAVE_IPV6)
-static ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(IPV6_AUTHHDR)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_authhdr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_authhdr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_DSTOPTS)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_dstopts(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_dstopts(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_FLOWINFO)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_HOPLIMIT)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_HOPOPTS)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_hopopts(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_MTU)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_mtu(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_MTU_DISCOVER)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_MULTICAST_HOPS)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_MULTICAST_IF)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_MULTICAST_LOOP)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_RECVERR)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_recverr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_ROUTER_ALERT)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_RTHDR)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_UNICAST_HOPS)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(IPV6_V6ONLY)
-static ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_ipv6_v6only(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#endif // defined(HAVE_IPV6)
-static ERL_NIF_TERM ngetopt_lvl_tcp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_tcp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(TCP_CONGESTION)
-static ERL_NIF_TERM ngetopt_lvl_tcp_congestion(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_tcp_congestion(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(TCP_MAXSEG)
-static ERL_NIF_TERM ngetopt_lvl_tcp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(TCP_NODELAY)
-static ERL_NIF_TERM ngetopt_lvl_tcp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
-static ERL_NIF_TERM ngetopt_lvl_udp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_udp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(UDP_CORK)
-static ERL_NIF_TERM ngetopt_lvl_udp_cork(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_udp_cork(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(HAVE_SCTP)
-static ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt);
+static ERL_NIF_TERM esock_getopt_lvl_sctp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt);
#if defined(SCTP_ASSOCINFO)
-static ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_AUTOCLOSE)
-static ERL_NIF_TERM ngetopt_lvl_sctp_autoclose(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_DISABLE_FRAGMENTS)
-static ERL_NIF_TERM ngetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_MAXSEG)
-static ERL_NIF_TERM ngetopt_lvl_sctp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_INITMSG)
-static ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_NODELAY)
-static ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#if defined(SCTP_RTOINFO)
-static ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
- ESockDescriptor* descP);
+static ERL_NIF_TERM esock_getopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ ESockDescriptor* descP);
#endif
#endif // defined(HAVE_SCTP)
-static ERL_NIF_TERM nsockname(ErlNifEnv* env,
- ESockDescriptor* descP);
-static ERL_NIF_TERM npeername(ErlNifEnv* env,
- ESockDescriptor* descP);
-static ERL_NIF_TERM ncancel(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM op,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_connect(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_accept_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef);
-static ERL_NIF_TERM ncancel_accept_waiting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_send(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_send_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef);
-static ERL_NIF_TERM ncancel_send_waiting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_recv(ErlNifEnv* env,
+static ERL_NIF_TERM esock_sockname(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static ERL_NIF_TERM esock_peername(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static ERL_NIF_TERM esock_cancel(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM op,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_recv_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef);
-static ERL_NIF_TERM ncancel_recv_waiting(ErlNifEnv* env,
+static ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_read_select(ErlNifEnv* env,
+static ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_write_select(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef);
-static ERL_NIF_TERM ncancel_mode_select(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef,
- int smode,
- int rmode);
+static ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef);
+static ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef,
+ int smode,
+ int rmode);
#if defined(USE_SETOPT_STR_OPT)
-static ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- int max,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ int max,
+ ERL_NIF_TERM eVal);
#endif
-static ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal);
-static ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal);
-static ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
+static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
#if defined(USE_GETOPT_STR_OPT)
-static ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- int max);
+static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ int max);
#endif
-static ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt);
-static ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt);
-static ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt);
+static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt);
+static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt);
+static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt);
static BOOLEAN_T send_check_writer(ErlNifEnv* env,
ESockDescriptor* descP,
@@ -2214,10 +2286,10 @@ static ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
ErlNifBinary* ctrlBufP,
ERL_NIF_TERM sockRef);
-static ERL_NIF_TERM nfinalize_connection(ErlNifEnv* env,
+static ERL_NIF_TERM esock_finalize_connection(ErlNifEnv* env,
+ ESockDescriptor* descP);
+static ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env,
ESockDescriptor* descP);
-static ERL_NIF_TERM nfinalize_close(ErlNifEnv* env,
- ESockDescriptor* descP);
extern char* encode_msghdr(ErlNifEnv* env,
ESockDescriptor* descP,
@@ -2350,11 +2422,11 @@ static BOOLEAN_T decode_native_get_opt(ErlNifEnv* env,
// static void encode_bool(BOOLEAN_T val, ERL_NIF_TERM* eVal);
static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val);
-static void socket_stop_handle_current(ErlNifEnv* env,
- const char* role,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ESockRequestor* reqP);
+static void esock_stop_handle_current(ErlNifEnv* env,
+ const char* role,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ESockRequestor* reqP);
static void inform_waiting_procs(ErlNifEnv* env,
const char* role,
ESockDescriptor* descP,
@@ -2369,6 +2441,8 @@ static int socket_setopt(int sock,
const void* optVal,
const socklen_t optLen);
+static BOOLEAN_T is_connector(ErlNifEnv* env,
+ ESockDescriptor* descP);
static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err);
static ESockDescriptor* alloc_descriptor(SOCKET sock, HANDLE event);
@@ -2491,31 +2565,35 @@ static size_t my_strnlen(const char *s, size_t maxlen);
#endif
*/
-static void socket_dtor(ErlNifEnv* env, void* obj);
-static void socket_stop(ErlNifEnv* env,
- void* obj,
- int fd,
- int is_direct_call);
-static void socket_down(ErlNifEnv* env,
- void* obj,
- const ErlNifPid* pid,
- const ErlNifMonitor* mon);
+static void esock_dtor(ErlNifEnv* env, void* obj);
+static void esock_stop(ErlNifEnv* env,
+ void* obj,
+ int fd,
+ int is_direct_call);
+static void esock_down(ErlNifEnv* env,
+ void* obj,
+ const ErlNifPid* pid,
+ const ErlNifMonitor* mon);
#if !defined(__WIN32__)
-static void socket_down_acceptor(ErlNifEnv* env,
+static void esock_down_acceptor(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ const ErlNifPid* pid);
+static void esock_down_writer(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ const ErlNifPid* pid);
+static void esock_down_reader(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ const ErlNifPid* pid);
+
+static char* esock_send_wrap_msg(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
- const ErlNifPid* pid);
-static void socket_down_writer(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- const ErlNifPid* pid);
-static void socket_down_reader(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- const ErlNifPid* pid);
-
+ ERL_NIF_TERM cnt);
static char* esock_send_close_msg(ErlNifEnv* env,
ESockDescriptor* descP,
ErlNifPid* pid);
@@ -2534,6 +2612,9 @@ static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM opRef,
ERL_NIF_TERM reason);
+static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM cnt);
static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM closeRef);
@@ -2608,7 +2689,10 @@ static char str_exsend[] = "exsend"; // failed send
-/* *** Global atoms *** */
+/* *** Global atoms ***
+ * Note that when an (global) atom is added here, it must also be added
+ * in the socket_int.h file!
+ */
#define GLOBAL_ATOMS \
GLOBAL_ATOM_DECL(abort); \
GLOBAL_ATOM_DECL(accept); \
@@ -2635,6 +2719,7 @@ static char str_exsend[] = "exsend"; // failed send
GLOBAL_ATOM_DECL(busy_poll); \
GLOBAL_ATOM_DECL(checksum); \
GLOBAL_ATOM_DECL(close); \
+ GLOBAL_ATOM_DECL(command); \
GLOBAL_ATOM_DECL(connect); \
GLOBAL_ATOM_DECL(congestion); \
GLOBAL_ATOM_DECL(context); \
@@ -2644,6 +2729,7 @@ static char str_exsend[] = "exsend"; // failed send
GLOBAL_ATOM_DECL(ctrunc); \
GLOBAL_ATOM_DECL(data); \
GLOBAL_ATOM_DECL(debug); \
+ GLOBAL_ATOM_DECL(default); \
GLOBAL_ATOM_DECL(default_send_params); \
GLOBAL_ATOM_DECL(delayed_ack_time); \
GLOBAL_ATOM_DECL(dgram); \
@@ -2830,6 +2916,8 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(closed); \
LOCAL_ATOM_DECL(closing); \
LOCAL_ATOM_DECL(cookie_life); \
+ LOCAL_ATOM_DECL(counter_wrap); \
+ LOCAL_ATOM_DECL(counters); \
LOCAL_ATOM_DECL(data_in); \
LOCAL_ATOM_DECL(do); \
LOCAL_ATOM_DECL(dont); \
@@ -2853,6 +2941,7 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(mode); \
LOCAL_ATOM_DECL(multiaddr); \
LOCAL_ATOM_DECL(null); \
+ LOCAL_ATOM_DECL(num_acceptors); \
LOCAL_ATOM_DECL(num_dinet); \
LOCAL_ATOM_DECL(num_dinet6); \
LOCAL_ATOM_DECL(num_dlocal); \
@@ -2862,14 +2951,21 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(num_psctp); \
LOCAL_ATOM_DECL(num_ptcp); \
LOCAL_ATOM_DECL(num_pudp); \
+ LOCAL_ATOM_DECL(num_readers); \
LOCAL_ATOM_DECL(num_sockets); \
LOCAL_ATOM_DECL(num_tdgrams); \
LOCAL_ATOM_DECL(num_tseqpkgs); \
LOCAL_ATOM_DECL(num_tstreams); \
+ LOCAL_ATOM_DECL(num_writers); \
LOCAL_ATOM_DECL(partial_delivery); \
LOCAL_ATOM_DECL(peer_error); \
LOCAL_ATOM_DECL(peer_rwnd); \
LOCAL_ATOM_DECL(probe); \
+ LOCAL_ATOM_DECL(read_byte); \
+ LOCAL_ATOM_DECL(read_fails); \
+ LOCAL_ATOM_DECL(read_pkg); \
+ LOCAL_ATOM_DECL(read_tries); \
+ LOCAL_ATOM_DECL(read_waits); \
LOCAL_ATOM_DECL(select); \
LOCAL_ATOM_DECL(sender_dry); \
LOCAL_ATOM_DECL(send_failure); \
@@ -2878,7 +2974,12 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(sourceaddr); \
LOCAL_ATOM_DECL(timeout); \
LOCAL_ATOM_DECL(true); \
- LOCAL_ATOM_DECL(want);
+ LOCAL_ATOM_DECL(want); \
+ LOCAL_ATOM_DECL(write_byte); \
+ LOCAL_ATOM_DECL(write_fails); \
+ LOCAL_ATOM_DECL(write_pkg); \
+ LOCAL_ATOM_DECL(write_tries); \
+ LOCAL_ATOM_DECL(write_waits);
/* Local error reason atoms */
#define LOCAL_ERROR_REASON_ATOMS \
@@ -2899,11 +3000,11 @@ LOCAL_ERROR_REASON_ATOMS
/* *** Sockets *** */
-static ErlNifResourceType* sockets;
-static ErlNifResourceTypeInit socketInit = {
- socket_dtor,
- socket_stop,
- (ErlNifResourceDown*) socket_down
+static ErlNifResourceType* esocks;
+static ErlNifResourceTypeInit esockInit = {
+ esock_dtor,
+ esock_stop,
+ (ErlNifResourceDown*) esock_down
};
// Initiated when the nif is loaded
@@ -2940,8 +3041,8 @@ static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan)
* Utility and admin functions:
* ----------------------------
* nif_info/0
+ * nif_command/1
* nif_supports/1
- * (nif_debug/1)
*
* The "proper" socket functions:
* ------------------------------
@@ -2981,7 +3082,7 @@ static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan)
* Description:
* This is currently just a placeholder...
*/
-#define MKCT(E, T, C) MKT2((E), (T), MKI((E), (C)))
+#define MKCT(E, T, C) MKT2((E), (T), MKUI((E), (C)))
static
ERL_NIF_TERM nif_info(ErlNifEnv* env,
@@ -2991,43 +3092,338 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env,
#if defined(__WIN32__)
return enif_raise_exception(env, MKA(env, "notsup"));
#else
- if (argc != 0) {
+ ERL_NIF_TERM info;
+
+ SGDBG( ("SOCKET", "nif_info -> entry with %d args\r\n", argc) );
+
+ switch (argc) {
+ case 0:
+ info = esock_global_info(env);
+ break;
+
+ case 1:
+ {
+ ESockDescriptor* descP;
+
+ if (!ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
+ return enif_make_badarg(env);
+ }
+ SSDBG( descP, ("SOCKET", "nif_info -> get socket info\r\n") );
+ info = esock_socket_info(env, descP);
+ }
+ break;
+
+ default:
return enif_make_badarg(env);
- } else {
- ERL_NIF_TERM numSockets = MKCT(env, atom_num_sockets, data.numSockets);
- ERL_NIF_TERM numTypeDGrams = MKCT(env, atom_num_tdgrams, data.numTypeDGrams);
- ERL_NIF_TERM numTypeStreams = MKCT(env, atom_num_tstreams, data.numTypeStreams);
- ERL_NIF_TERM numTypeSeqPkgs = MKCT(env, atom_num_tseqpkgs, data.numTypeSeqPkgs);
- ERL_NIF_TERM numDomLocal = MKCT(env, atom_num_dlocal, data.numDomainLocal);
- ERL_NIF_TERM numDomInet = MKCT(env, atom_num_dinet, data.numDomainInet);
- ERL_NIF_TERM numDomInet6 = MKCT(env, atom_num_dinet6, data.numDomainInet6);
- ERL_NIF_TERM numProtoIP = MKCT(env, atom_num_pip, data.numProtoIP);
- ERL_NIF_TERM numProtoTCP = MKCT(env, atom_num_ptcp, data.numProtoTCP);
- ERL_NIF_TERM numProtoUDP = MKCT(env, atom_num_pudp, data.numProtoUDP);
- ERL_NIF_TERM numProtoSCTP = MKCT(env, atom_num_psctp, data.numProtoSCTP);
- ERL_NIF_TERM gcnt[] = {numSockets,
- numTypeDGrams, numTypeStreams, numTypeSeqPkgs,
- numDomLocal, numDomInet, numDomInet6,
- numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP};
- unsigned int lenGCnt = sizeof(gcnt) / sizeof(ERL_NIF_TERM);
- ERL_NIF_TERM lgcnt = MKLA(env, gcnt, lenGCnt);
- ERL_NIF_TERM keys[] = {esock_atom_debug, atom_iow, atom_global_counters};
- ERL_NIF_TERM vals[] = {BOOL2ATOM(data.dbg), BOOL2ATOM(data.iow), lgcnt};
- ERL_NIF_TERM info;
- unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
- unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+ }
- ESOCK_ASSERT( (numKeys == numVals) );
+ return info;
+
+#endif
+}
+
+
+/*
+ * This function return a property list containing "global" info.
+ */
+#if !defined(__WIN32__)
+static
+ERL_NIF_TERM esock_global_info(ErlNifEnv* env)
+{
+ ERL_NIF_TERM numSockets = MKCT(env, atom_num_sockets, data.numSockets);
+ ERL_NIF_TERM numTypeDGrams = MKCT(env, atom_num_tdgrams, data.numTypeDGrams);
+ ERL_NIF_TERM numTypeStreams = MKCT(env, atom_num_tstreams, data.numTypeStreams);
+ ERL_NIF_TERM numTypeSeqPkgs = MKCT(env, atom_num_tseqpkgs, data.numTypeSeqPkgs);
+ ERL_NIF_TERM numDomLocal = MKCT(env, atom_num_dlocal, data.numDomainLocal);
+ ERL_NIF_TERM numDomInet = MKCT(env, atom_num_dinet, data.numDomainInet);
+ ERL_NIF_TERM numDomInet6 = MKCT(env, atom_num_dinet6, data.numDomainInet6);
+ ERL_NIF_TERM numProtoIP = MKCT(env, atom_num_pip, data.numProtoIP);
+ ERL_NIF_TERM numProtoTCP = MKCT(env, atom_num_ptcp, data.numProtoTCP);
+ ERL_NIF_TERM numProtoUDP = MKCT(env, atom_num_pudp, data.numProtoUDP);
+ ERL_NIF_TERM numProtoSCTP = MKCT(env, atom_num_psctp, data.numProtoSCTP);
+ ERL_NIF_TERM gcnt[] = {numSockets,
+ numTypeDGrams, numTypeStreams, numTypeSeqPkgs,
+ numDomLocal, numDomInet, numDomInet6,
+ numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP};
+ unsigned int lenGCnt = sizeof(gcnt) / sizeof(ERL_NIF_TERM);
+ ERL_NIF_TERM lgcnt = MKLA(env, gcnt, lenGCnt);
+ ERL_NIF_TERM keys[] = {esock_atom_debug, atom_iow, atom_global_counters};
+ ERL_NIF_TERM vals[] = {BOOL2ATOM(data.dbg), BOOL2ATOM(data.iow), lgcnt};
+ ERL_NIF_TERM info;
+ unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+
+ ESOCK_ASSERT( (numKeys == numVals) );
+
+ if (!MKMA(env, keys, vals, numKeys, &info))
+ return enif_make_badarg(env);
+
+ return info;
+}
- if (!MKMA(env, keys, vals, numKeys, &info))
- return enif_make_badarg(env);
+
+
+/*
+ * This function return a property *map*. The properties are:
+ * counters: A list of each socket counter and there current values
+ * readers: The number of current and waiting readers
+ * writers: The number of current and waiting writers
+ * acceptors: The number of current and waiting acceptors
+ */
+static
+ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM counters = esock_socket_info_counters(env, descP);
+ ERL_NIF_TERM readers = esock_socket_info_readers(env, descP);
+ ERL_NIF_TERM writers = esock_socket_info_writers(env, descP);
+ ERL_NIF_TERM acceptors = esock_socket_info_acceptors(env, descP);
+ ERL_NIF_TERM keys[] = {atom_counters, atom_num_readers,
+ atom_num_writers, atom_num_acceptors};
+ ERL_NIF_TERM vals[] = {counters, readers, writers, acceptors};
+ ERL_NIF_TERM info;
+ unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+
+ SSDBG( descP, ("SOCKET", "esock_socket_info -> "
+ "\r\n numKeys: %d"
+ "\r\n numVals: %d"
+ "\r\n", numKeys, numVals) );
+
+ ESOCK_ASSERT( (numKeys == numVals) );
+
+ if (!MKMA(env, keys, vals, numKeys, &info))
+ return enif_make_badarg(env);
+
+ SSDBG( descP, ("SOCKET", "esock_socket_info -> done with"
+ "\r\n info: %T"
+ "\r\n", info) );
+
+ return info;
- return info;
+}
+
+
+/*
+ * Collect all counters for a socket.
+ */
+static
+ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM info;
+
+ MLOCK(descP->writeMtx);
+ MLOCK(descP->readMtx);
+
+ {
+ ERL_NIF_TERM readByteCnt = MKCT(env, atom_read_byte, descP->readByteCnt);
+ ERL_NIF_TERM readFails = MKCT(env, atom_read_fails, descP->readFails);
+ ERL_NIF_TERM readPkgCnt = MKCT(env, atom_read_pkg, descP->readPkgCnt);
+ ERL_NIF_TERM readTries = MKCT(env, atom_read_tries, descP->readTries);
+ ERL_NIF_TERM readWaits = MKCT(env, atom_read_waits, descP->readWaits);
+ ERL_NIF_TERM writeByteCnt = MKCT(env, atom_write_byte, descP->writeByteCnt);
+ ERL_NIF_TERM writeFails = MKCT(env, atom_write_fails, descP->writeFails);
+ ERL_NIF_TERM writePkgCnt = MKCT(env, atom_write_pkg, descP->writePkgCnt);
+ ERL_NIF_TERM writeTries = MKCT(env, atom_write_tries, descP->writeTries);
+ ERL_NIF_TERM writeWaits = MKCT(env, atom_write_waits, descP->writeWaits);
+ ERL_NIF_TERM acnt[] = {readByteCnt, readFails, readPkgCnt,
+ readTries, readWaits,
+ writeByteCnt, writeFails, writePkgCnt,
+ writeTries, writeWaits};
+ unsigned int lenACnt = sizeof(acnt) / sizeof(ERL_NIF_TERM);
+
+ info = MKLA(env, acnt, lenACnt);
+
+ SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> "
+ "\r\n lenACnt: %d"
+ "\r\n info: %T"
+ "\r\n", lenACnt, info) );
+
+ }
+
+ MUNLOCK(descP->readMtx);
+ MUNLOCK(descP->writeMtx);
+
+ SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> done with"
+ "\r\n info: %T"
+ "\r\n", info) );
+
+ return info;
+}
+#endif
+
+
+/* ----------------------------------------------------------------------
+ * nif_command
+ *
+ * Description:
+ * This function is intended to handle "various" commands. That is,
+ * commands and operations that are not part of the socket API proper.
+ * Currently it handles setting the global debug. Its a map with two
+ * attributes command and (command) data:
+ * #{command :: atom(), data :: term()}
+ *
+ * Command Data
+ * debug boolean()
+ *
+ */
+
+static
+ERL_NIF_TERM nif_command(ErlNifEnv* env,
+ int argc,
+ const ERL_NIF_TERM argv[])
+{
+#if defined(__WIN32__)
+ return enif_raise_exception(env, MKA(env, "notsup"));
+#else
+ ERL_NIF_TERM ecmd, ecdata, result;
+ Uint16 cmd;
+
+ SGDBG( ("SOCKET", "nif_command -> entry with %d args\r\n", argc) );
+
+ if ((argc != 1) ||
+ !IS_MAP(env, argv[0])) {
+ return enif_make_badarg(env);
+ }
+ ecmd = argv[0];
+
+ SGDBG( ("SOCKET", "nif_command -> "
+ "\r\n (e) command: %T"
+ "\r\n", ecmd) );
+
+ if (!ecommand2command(env, ecmd, &cmd, &ecdata)) {
+ SGDBG( ("SOCKET", "nif_command -> invalid command\r\n") );
+ return esock_make_error(env, esock_atom_einval);
}
+
+ SGDBG( ("SOCKET", "nif_command -> "
+ "\r\n command: %d"
+ "\r\n (e) command data: %T"
+ "\r\n", cmd, ecdata) );
+
+ result = esock_command(env, cmd, ecdata);
+
+ SGDBG( ("SOCKET", "nif_command -> done with result: "
+ "\r\n %T"
+ "\r\n", result) );
+
+ return result;
+
#endif
}
+#if !defined(__WIN32__)
+static
+ERL_NIF_TERM esock_command(ErlNifEnv* env, Uint16 cmd, ERL_NIF_TERM ecdata)
+{
+ ERL_NIF_TERM result;
+
+ SGDBG( ("SOCKET", "esock_command -> entry with 0x%lX\r\n", cmd) );
+
+ switch (cmd) {
+ case ESOCK_CMD_DEBUG:
+ result = esock_command_debug(env, ecdata);
+ break;
+
+ default:
+ result = esock_make_error(env, esock_atom_einval);
+ break;
+ }
+
+ return result;
+}
+
+
+
+static
+ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM ecdata)
+{
+ ERL_NIF_TERM result;
+
+ /* The data *should* be a boolean() */
+
+ if (COMPARE(ecdata, esock_atom_true) == 0) {
+ data.dbg = TRUE;
+ result = esock_atom_ok;
+ } else if (COMPARE(ecdata, esock_atom_false) == 0) {
+ data.dbg = FALSE;
+ result = esock_atom_ok;
+ } else {
+ SGDBG( ("SOCKET", "esock_command_debug -> invalid debug value: %T\r\n",
+ ecdata) );
+ result = esock_make_error(env, esock_atom_einval);
+ }
+
+ return result;
+}
+#endif
+
+
+/* *** esock_socket_info_readers ***
+ * *** esock_socket_info_writers ***
+ * *** esock_socket_info_acceptors ***
+ *
+ * Calculate how many readers | writers | acceptors we have for this socket.
+ * Current requestor + any waiting requestors (of the type).
+ *
+ */
+
+#if !defined(__WIN32__)
+#define ESOCK_INFO_REQ_FUNCS \
+ ESOCK_INFO_REQ_FUNC_DECL(readers, readMtx, currentReaderP, readersQ) \
+ ESOCK_INFO_REQ_FUNC_DECL(writers, writeMtx, currentWriterP, writersQ) \
+ ESOCK_INFO_REQ_FUNC_DECL(acceptors, accMtx, currentAcceptorP, acceptorsQ)
+
+#define ESOCK_INFO_REQ_FUNC_DECL(F, MTX, CRP, Q) \
+ static \
+ ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \
+ ESockDescriptor* descP) \
+ { \
+ return socket_info_reqs(env, descP, descP->MTX, descP->CRP, &descP->Q); \
+ }
+ESOCK_INFO_REQ_FUNCS
+#undef ESOCK_INFO_REQ_FUNC_DECL
+
+
+static
+ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ErlNifMutex* mtx,
+ ESockRequestor* crp,
+ ESockRequestQueue* q)
+{
+ ESockRequestQueueElement* tmp;
+ ERL_NIF_TERM info;
+ unsigned int cnt = 0;
+
+ MLOCK(mtx);
+
+ if (crp != NULL) {
+ // We have an active requestor!
+ cnt++;
+
+ // And add all the waiting requestors
+ tmp = q->first;
+ while (tmp != NULL) {
+ cnt++;
+ tmp = tmp->nextP;
+ }
+ }
+
+ MUNLOCK(mtx);
+
+ info = MKUI(env, cnt);
+
+ SSDBG( descP, ("SOCKET", "socket_info_reqs -> done with"
+ "\r\n info: %T"
+ "\r\n", info) );
+
+ return info;
+}
+#endif
+
/* ----------------------------------------------------------------------
* nif_supports
@@ -3046,6 +3442,9 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env,
* {tcp, [{Opt, boolean()}]},
* {udp, [{Opt, boolean()}]},
* {sctp, [{Opt, boolean()}]}]
+ * sctp boolean()
+ * ipv6 boolean()
+ * local boolean()
*/
static
@@ -3067,39 +3466,40 @@ ERL_NIF_TERM nif_supports(ErlNifEnv* env,
return enif_make_badarg(env);
}
- return nsupports(env, key);
+ return esock_supports(env, key);
#endif
}
-/* nopen - create an endpoint for communication
+/* esock_supports - what features do we support
*
- * Assumes the input has been validated.
- *
- * Normally we want debugging on (individual) sockets to be controlled
- * by the sockets own debug flag. But since we don't even have a socket
- * yet, we must use the global debug flag.
+ * This is to prove information about what features actually
+ * work on the current platform.
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports(ErlNifEnv* env, int key)
+ERL_NIF_TERM esock_supports(ErlNifEnv* env, int key)
{
ERL_NIF_TERM result;
- SGDBG( ("SOCKET", "nsupports -> entry with 0x%lX\r\n", key) );
+ SGDBG( ("SOCKET", "esock_supports -> entry with 0x%lX\r\n", key) );
switch (key) {
- case SOCKET_SUPPORTS_OPTIONS:
- result = nsupports_options(env);
+ case ESOCK_SUPPORTS_OPTIONS:
+ result = esock_supports_options(env);
+ break;
+
+ case ESOCK_SUPPORTS_SCTP:
+ result = esock_supports_sctp(env);
break;
- case SOCKET_SUPPORTS_SCTP:
- result = nsupports_sctp(env);
+ case ESOCK_SUPPORTS_IPV6:
+ result = esock_supports_ipv6(env);
break;
- case SOCKET_SUPPORTS_IPV6:
- result = nsupports_ipv6(env);
+ case ESOCK_SUPPORTS_LOCAL:
+ result = esock_supports_local(env);
break;
default:
@@ -3114,19 +3514,19 @@ ERL_NIF_TERM nsupports(ErlNifEnv* env, int key)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options(ErlNifEnv* env)
{
- ERL_NIF_TERM sockOpts = nsupports_options_socket(env);
+ ERL_NIF_TERM sockOpts = esock_supports_options_socket(env);
ERL_NIF_TERM sockOptsT = MKT2(env, esock_atom_socket, sockOpts);
- ERL_NIF_TERM ipOpts = nsupports_options_ip(env);
+ ERL_NIF_TERM ipOpts = esock_supports_options_ip(env);
ERL_NIF_TERM ipOptsT = MKT2(env, esock_atom_ip, ipOpts);
- ERL_NIF_TERM ipv6Opts = nsupports_options_ipv6(env);
+ ERL_NIF_TERM ipv6Opts = esock_supports_options_ipv6(env);
ERL_NIF_TERM ipv6OptsT = MKT2(env, esock_atom_ipv6, ipv6Opts);
- ERL_NIF_TERM tcpOpts = nsupports_options_tcp(env);
+ ERL_NIF_TERM tcpOpts = esock_supports_options_tcp(env);
ERL_NIF_TERM tcpOptsT = MKT2(env, esock_atom_tcp, tcpOpts);
- ERL_NIF_TERM udpOpts = nsupports_options_udp(env);
+ ERL_NIF_TERM udpOpts = esock_supports_options_udp(env);
ERL_NIF_TERM udpOptsT = MKT2(env, esock_atom_udp, udpOpts);
- ERL_NIF_TERM sctpOpts = nsupports_options_sctp(env);
+ ERL_NIF_TERM sctpOpts = esock_supports_options_sctp(env);
ERL_NIF_TERM sctpOptsT = MKT2(env, esock_atom_sctp, sctpOpts);
ERL_NIF_TERM optsA[] = {sockOptsT,
ipOptsT, ipv6OptsT,
@@ -3142,13 +3542,13 @@ ERL_NIF_TERM nsupports_options(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_socket(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(128);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_SOCK_ACCEPTCONN => SO_ACCEPTCONN *** */
+ /* *** ESOCK_OPT_SOCK_ACCEPTCONN => SO_ACCEPTCONN *** */
#if defined(SO_ACCEPTCONN)
tmp = MKT2(env, esock_atom_acceptconn, esock_atom_true);
#else
@@ -3157,12 +3557,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_ACCEPTFILTER => SO_ACCEPTFILTER *** */
+ /* *** ESOCK_OPT_SOCK_ACCEPTFILTER => SO_ACCEPTFILTER *** */
tmp = MKT2(env, esock_atom_acceptfilter, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_BINDTODEVICE => SO_BINDTODEVICE *** */
+ /* *** ESOCK_OPT_SOCK_BINDTODEVICE => SO_BINDTODEVICE *** */
#if defined(SO_BINDTODEVICE)
tmp = MKT2(env, esock_atom_bindtodevice, esock_atom_true);
#else
@@ -3171,7 +3571,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_BROADCAST => SO_BROADCAST *** */
+ /* *** ESOCK_OPT_SOCK_BROADCAST => SO_BROADCAST *** */
#if defined(SO_BROADCAST)
tmp = MKT2(env, esock_atom_broadcast, esock_atom_true);
#else
@@ -3180,12 +3580,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_BUSY_POLL => SO_BUSY_POLL *** */
+ /* *** ESOCK_OPT_SOCK_BUSY_POLL => SO_BUSY_POLL *** */
tmp = MKT2(env, esock_atom_busy_poll, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_DEBUG => SO_DEBUG *** */
+ /* *** ESOCK_OPT_SOCK_DEBUG => SO_DEBUG *** */
#if defined(SO_DEBUG)
tmp = MKT2(env, esock_atom_debug, esock_atom_true);
#else
@@ -3194,7 +3594,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_DOMAIN => SO_DOMAIN *** */
+ /* *** ESOCK_OPT_SOCK_DOMAIN => SO_DOMAIN *** */
#if defined(SO_DOMAIN)
tmp = MKT2(env, esock_atom_domain, esock_atom_true);
#else
@@ -3203,7 +3603,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_DONTROUTE => SO_DONTROUTE *** */
+ /* *** ESOCK_OPT_SOCK_DONTROUTE => SO_DONTROUTE *** */
#if defined(SO_DONTROUTE)
tmp = MKT2(env, esock_atom_dontroute, esock_atom_true);
#else
@@ -3212,12 +3612,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_ERROR => SO_ERROR *** */
+ /* *** ESOCK_OPT_SOCK_ERROR => SO_ERROR *** */
tmp = MKT2(env, esock_atom_error, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_KEEPALIVE => SO_KEEPALIVE *** */
+ /* *** ESOCK_OPT_SOCK_KEEPALIVE => SO_KEEPALIVE *** */
#if defined(SO_KEEPALIVE)
tmp = MKT2(env, esock_atom_keepalive, esock_atom_true);
#else
@@ -3226,7 +3626,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_LINGER => SO_LINGER *** */
+ /* *** ESOCK_OPT_SOCK_LINGER => SO_LINGER *** */
#if defined(SO_LINGER)
tmp = MKT2(env, esock_atom_linger, esock_atom_true);
#else
@@ -3235,12 +3635,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_MARK => SO_MARK *** */
+ /* *** ESOCK_OPT_SOCK_MARK => SO_MARK *** */
tmp = MKT2(env, esock_atom_mark, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_OOBINLINE => SO_OOBINLINE *** */
+ /* *** ESOCK_OPT_SOCK_OOBINLINE => SO_OOBINLINE *** */
#if defined(SO_OOBINLINE)
tmp = MKT2(env, esock_atom_oobinline, esock_atom_true);
#else
@@ -3249,12 +3649,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_PASSCRED => SO_PASSCRED *** */
+ /* *** ESOCK_OPT_PASSCRED => SO_PASSCRED *** */
tmp = MKT2(env, esock_atom_passcred, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_PEEK_OFF => SO_PEEK_OFF *** */
+ /* *** ESOCK_OPT_SOCK_PEEK_OFF => SO_PEEK_OFF *** */
#if defined(SO_PEEK_OFF)
tmp = MKT2(env, esock_atom_peek_off, esock_atom_true);
#else
@@ -3263,12 +3663,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_PEEKCRED => SO_PEEKCRED *** */
+ /* *** ESOCK_OPT_SOCK_PEEKCRED => SO_PEEKCRED *** */
tmp = MKT2(env, esock_atom_peekcred, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_PRIORITY => SO_PRIORITY *** */
+ /* *** ESOCK_OPT_SOCK_PRIORITY => SO_PRIORITY *** */
#if defined(SO_PRIORITY)
tmp = MKT2(env, esock_atom_priority, esock_atom_true);
#else
@@ -3277,7 +3677,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_PROTOCOL => SO_PROTOCOL *** */
+ /* *** ESOCK_OPT_SOCK_PROTOCOL => SO_PROTOCOL *** */
#if defined(SO_PROTOCOL)
tmp = MKT2(env, esock_atom_protocol, esock_atom_true);
#else
@@ -3286,7 +3686,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_RCVBUF => SO_RCVBUF *** */
+ /* *** ESOCK_OPT_SOCK_RCVBUF => SO_RCVBUF *** */
#if defined(SO_RCVBUF)
tmp = MKT2(env, esock_atom_rcvbuf, esock_atom_true);
#else
@@ -3295,12 +3695,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_RCVBUFFORCE => SO_RCVBUFFORCE *** */
+ /* *** ESOCK_OPT_SOCK_RCVBUFFORCE => SO_RCVBUFFORCE *** */
tmp = MKT2(env, esock_atom_rcvbufforce, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_RCVLOWAT => SO_RCVLOWAT *** */
+ /* *** ESOCK_OPT_SOCK_RCVLOWAT => SO_RCVLOWAT *** */
#if defined(SO_RCVLOWAT)
tmp = MKT2(env, esock_atom_rcvlowat, esock_atom_true);
#else
@@ -3309,7 +3709,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_RCVTIMEO => SO_RCVTIMEO *** */
+ /* *** ESOCK_OPT_SOCK_RCVTIMEO => SO_RCVTIMEO *** */
#if defined(SO_RCVTIMEO)
tmp = MKT2(env, esock_atom_rcvtimeo, esock_atom_true);
#else
@@ -3318,7 +3718,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_REUSEADDR => SO_REUSEADDR *** */
+ /* *** ESOCK_OPT_SOCK_REUSEADDR => SO_REUSEADDR *** */
#if defined(SO_REUSEADDR)
tmp = MKT2(env, esock_atom_reuseaddr, esock_atom_true);
#else
@@ -3327,7 +3727,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_REUSEPORT => SO_REUSEPORT *** */
+ /* *** ESOCK_OPT_SOCK_REUSEPORT => SO_REUSEPORT *** */
#if defined(SO_REUSEPORT)
tmp = MKT2(env, esock_atom_reuseport, esock_atom_true);
#else
@@ -3336,17 +3736,17 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_RXQ_OVFL => SO_RXQ_OVFL *** */
+ /* *** ESOCK_OPT_SOCK_RXQ_OVFL => SO_RXQ_OVFL *** */
tmp = MKT2(env, esock_atom_rxq_ovfl, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_SETFIB => SO_SETFIB *** */
+ /* *** ESOCK_OPT_SOCK_SETFIB => SO_SETFIB *** */
tmp = MKT2(env, esock_atom_setfib, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_SNDBUF => SO_SNDBUF *** */
+ /* *** ESOCK_OPT_SOCK_SNDBUF => SO_SNDBUF *** */
#if defined(SO_SNDBUF)
tmp = MKT2(env, esock_atom_sndbuf, esock_atom_true);
#else
@@ -3355,12 +3755,12 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_SNDBUFFORCE => SO_SNDBUFFORCE *** */
+ /* *** ESOCK_OPT_SOCK_SNDBUFFORCE => SO_SNDBUFFORCE *** */
tmp = MKT2(env, esock_atom_sndbufforce, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_SNDLOWAT => SO_SNDLOWAT *** */
+ /* *** ESOCK_OPT_SOCK_SNDLOWAT => SO_SNDLOWAT *** */
#if defined(SO_SNDLOWAT)
tmp = MKT2(env, esock_atom_sndlowat, esock_atom_true);
#else
@@ -3369,7 +3769,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_SNDTIMEO => SO_SNDTIMEO *** */
+ /* *** ESOCK_OPT_SOCK_SNDTIMEO => SO_SNDTIMEO *** */
#if defined(SO_SNDTIMEO)
tmp = MKT2(env, esock_atom_sndtimeo, esock_atom_true);
#else
@@ -3378,7 +3778,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_TIMESTAMP => SO_TIMESTAMP *** */
+ /* *** ESOCK_OPT_SOCK_TIMESTAMP => SO_TIMESTAMP *** */
#if defined(SO_TIMESTAMP)
tmp = MKT2(env, esock_atom_timestamp, esock_atom_true);
#else
@@ -3387,7 +3787,7 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SOCK_TYPE => SO_TYPE *** */
+ /* *** ESOCK_OPT_SOCK_TYPE => SO_TYPE *** */
#if defined(SO_TYPE)
tmp = MKT2(env, esock_atom_type, esock_atom_true);
#else
@@ -3406,13 +3806,13 @@ ERL_NIF_TERM nsupports_options_socket(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_ip(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(128);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_IP_ADD_MEMBERSHIP => IP_ADD_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IP_ADD_MEMBERSHIP => IP_ADD_MEMBERSHIP *** */
#if defined(IP_ADD_MEMBERSHIP)
tmp = MKT2(env, esock_atom_add_membership, esock_atom_true);
#else
@@ -3421,7 +3821,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP => IP_ADD_SOURCE_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IP_ADD_SOURCE_MEMBERSHIP => IP_ADD_SOURCE_MEMBERSHIP *** */
#if defined(IP_ADD_SOURCE_MEMBERSHIP)
tmp = MKT2(env, esock_atom_add_source_membership, esock_atom_true);
#else
@@ -3430,7 +3830,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_BLOCK_SOURCE => IP_BLOCK_SOURCE *** */
+ /* *** ESOCK_OPT_IP_BLOCK_SOURCE => IP_BLOCK_SOURCE *** */
#if defined(IP_BLOCK_SOURCE)
tmp = MKT2(env, esock_atom_block_source, esock_atom_true);
#else
@@ -3439,12 +3839,12 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_DONTFRAG => IP_DONTFRAG *** */
+ /* *** ESOCK_OPT_IP_DONTFRAG => IP_DONTFRAG *** */
tmp = MKT2(env, esock_atom_dontfrag, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_DROP_MEMBERSHIP => IP_DROP_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IP_DROP_MEMBERSHIP => IP_DROP_MEMBERSHIP *** */
#if defined(IP_DROP_MEMBERSHIP)
tmp = MKT2(env, esock_atom_drop_membership, esock_atom_true);
#else
@@ -3453,7 +3853,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP => IP_DROP_SOURCE_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IP_DROP_SOURCE_MEMBERSHIP => IP_DROP_SOURCE_MEMBERSHIP *** */
#if defined(IP_DROP_SOURCE_MEMBERSHIP)
tmp = MKT2(env, esock_atom_drop_source_membership, esock_atom_true);
#else
@@ -3462,7 +3862,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_FREEBIND => IP_FREEBIND *** */
+ /* *** ESOCK_OPT_IP_FREEBIND => IP_FREEBIND *** */
#if defined(IP_FREEBIND)
tmp = MKT2(env, esock_atom_freebind, esock_atom_true);
#else
@@ -3471,7 +3871,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_HDRINCL => IP_HDRINCL *** */
+ /* *** ESOCK_OPT_IP_HDRINCL => IP_HDRINCL *** */
#if defined(IP_HDRINCL)
tmp = MKT2(env, esock_atom_hdrincl, esock_atom_true);
#else
@@ -3480,7 +3880,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MINTTL => IP_MINTTL *** */
+ /* *** ESOCK_OPT_IP_MINTTL => IP_MINTTL *** */
#if defined(IP_MINTTL)
tmp = MKT2(env, esock_atom_minttl, esock_atom_true);
#else
@@ -3489,7 +3889,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MSFILTER => IP_MSFILTER / IP_MSFILTER_SIZE *** */
+ /* *** ESOCK_OPT_IP_MSFILTER => IP_MSFILTER / IP_MSFILTER_SIZE *** */
#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
tmp = MKT2(env, esock_atom_msfilter, esock_atom_true);
#else
@@ -3498,12 +3898,12 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MTU => IP_MTU *** */
+ /* *** ESOCK_OPT_IP_MTU => IP_MTU *** */
tmp = MKT2(env, esock_atom_mtu, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MTU_DISCOVER => IP_MTU_DISCOVER *** */
+ /* *** ESOCK_OPT_IP_MTU_DISCOVER => IP_MTU_DISCOVER *** */
#if defined(IP_MTU_DISCOVER)
tmp = MKT2(env, esock_atom_mtu_discover, esock_atom_true);
#else
@@ -3512,7 +3912,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MULTICAST_ALL => IP_MULTICAST_ALL *** */
+ /* *** ESOCK_OPT_IP_MULTICAST_ALL => IP_MULTICAST_ALL *** */
#if defined(IP_MULTICAST_ALL)
tmp = MKT2(env, esock_atom_multicast_all, esock_atom_true);
#else
@@ -3521,7 +3921,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MULTICAST_IF => IP_MULTICAST_IF *** */
+ /* *** ESOCK_OPT_IP_MULTICAST_IF => IP_MULTICAST_IF *** */
#if defined(IP_MULTICAST_IF)
tmp = MKT2(env, esock_atom_multicast_if, esock_atom_true);
#else
@@ -3530,7 +3930,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MULTICAST_LOOP => IP_MULTICAST_LOOP *** */
+ /* *** ESOCK_OPT_IP_MULTICAST_LOOP => IP_MULTICAST_LOOP *** */
#if defined(IP_MULTICAST_LOOP)
tmp = MKT2(env, esock_atom_multicast_loop, esock_atom_true);
#else
@@ -3539,7 +3939,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_MULTICAST_TTL => IP_MULTICAST_TTL *** */
+ /* *** ESOCK_OPT_IP_MULTICAST_TTL => IP_MULTICAST_TTL *** */
#if defined(IP_MULTICAST_TTL)
tmp = MKT2(env, esock_atom_multicast_ttl, esock_atom_true);
#else
@@ -3548,7 +3948,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_NODEFRAG => IP_NODEFRAG *** */
+ /* *** ESOCK_OPT_IP_NODEFRAG => IP_NODEFRAG *** */
#if defined(IP_NODEFRAG)
tmp = MKT2(env, esock_atom_nodefrag, esock_atom_true);
#else
@@ -3557,12 +3957,12 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_OPTIONS => IP_OPTIONS *** */
+ /* *** ESOCK_OPT_IP_OPTIONS => IP_OPTIONS *** */
tmp = MKT2(env, esock_atom_options, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_PKTINFO => IP_PKTINFO *** */
+ /* *** ESOCK_OPT_IP_PKTINFO => IP_PKTINFO *** */
#if defined(IP_PKTINFO)
tmp = MKT2(env, esock_atom_pktinfo, esock_atom_true);
#else
@@ -3571,7 +3971,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVDSTADDR => IP_RECVDSTADDR *** */
+ /* *** ESOCK_OPT_IP_RECVDSTADDR => IP_RECVDSTADDR *** */
#if defined(IP_RECVDSTADDR)
tmp = MKT2(env, esock_atom_recvdstaddr, esock_atom_true);
#else
@@ -3580,7 +3980,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVERR => IP_RECVERR *** */
+ /* *** ESOCK_OPT_IP_RECVERR => IP_RECVERR *** */
#if defined(IP_RECVERR)
tmp = MKT2(env, esock_atom_recverr, esock_atom_true);
#else
@@ -3589,7 +3989,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVIF => IP_RECVIF *** */
+ /* *** ESOCK_OPT_IP_RECVIF => IP_RECVIF *** */
#if defined(IP_RECVIF)
tmp = MKT2(env, esock_atom_recvif, esock_atom_true);
#else
@@ -3598,7 +3998,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVOPTS => IP_RECVOPTS *** */
+ /* *** ESOCK_OPT_IP_RECVOPTS => IP_RECVOPTS *** */
#if defined(IP_RECVOPTS)
tmp = MKT2(env, esock_atom_recvopts, esock_atom_true);
#else
@@ -3607,7 +4007,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVORIGDSTADDR => IP_RECVORIGDSTADDR *** */
+ /* *** ESOCK_OPT_IP_RECVORIGDSTADDR => IP_RECVORIGDSTADDR *** */
#if defined(IP_RECVORIGDSTADDR)
tmp = MKT2(env, esock_atom_recvorigdstaddr, esock_atom_true);
#else
@@ -3616,7 +4016,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVTOS => IP_RECVTOS *** */
+ /* *** ESOCK_OPT_IP_RECVTOS => IP_RECVTOS *** */
#if defined(IP_RECVTOS)
tmp = MKT2(env, esock_atom_recvtos, esock_atom_true);
#else
@@ -3625,7 +4025,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RECVTTL => IP_RECVTTL *** */
+ /* *** ESOCK_OPT_IP_RECVTTL => IP_RECVTTL *** */
#if defined(IP_RECVTTL)
tmp = MKT2(env, esock_atom_recvttl, esock_atom_true);
#else
@@ -3634,7 +4034,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_RETOPTS => IP_RETOPTS *** */
+ /* *** ESOCK_OPT_IP_RETOPTS => IP_RETOPTS *** */
#if defined(IP_RETOPTS)
tmp = MKT2(env, esock_atom_retopts, esock_atom_true);
#else
@@ -3643,7 +4043,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_ROUTER_ALERT => IP_ROUTER_ALERT *** */
+ /* *** ESOCK_OPT_IP_ROUTER_ALERT => IP_ROUTER_ALERT *** */
#if defined(IP_ROUTER_ALERT)
tmp = MKT2(env, esock_atom_router_alert, esock_atom_true);
#else
@@ -3652,7 +4052,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_SENDSRCADDR => IP_SENDSRCADDR *** */
+ /* *** ESOCK_OPT_IP_SENDSRCADDR => IP_SENDSRCADDR *** */
#if defined(IP_SENDSRCADDR)
tmp = MKT2(env, esock_atom_sendsrcaddr, esock_atom_true);
#else
@@ -3661,7 +4061,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_TOS => IP_TOS *** */
+ /* *** ESOCK_OPT_IP_TOS => IP_TOS *** */
#if defined(IP_TOS)
tmp = MKT2(env, esock_atom_tos, esock_atom_true);
#else
@@ -3670,7 +4070,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_TRANSPARENT => IP_TRANSPARENT *** */
+ /* *** ESOCK_OPT_IP_TRANSPARENT => IP_TRANSPARENT *** */
#if defined(IP_TRANSPARENT)
tmp = MKT2(env, esock_atom_transparent, esock_atom_true);
#else
@@ -3679,7 +4079,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_TTL => IP_TTL *** */
+ /* *** ESOCK_OPT_IP_TTL => IP_TTL *** */
#if defined(IP_TTL)
tmp = MKT2(env, esock_atom_ttl, esock_atom_true);
#else
@@ -3688,7 +4088,7 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IP_UNBLOCK_SOURCE => IP_UNBLOCK_SOURCE *** */
+ /* *** ESOCK_OPT_IP_UNBLOCK_SOURCE => IP_UNBLOCK_SOURCE *** */
#if defined(IP_UNBLOCK_SOURCE)
tmp = MKT2(env, esock_atom_unblock_source, esock_atom_true);
#else
@@ -3707,13 +4107,13 @@ ERL_NIF_TERM nsupports_options_ip(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_ipv6(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(128);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_IPV6_ADDRFORM => IPV6_ADDRFORM *** */
+ /* *** ESOCK_OPT_IPV6_ADDRFORM => IPV6_ADDRFORM *** */
#if defined(IPV6_ADDRFORM)
tmp = MKT2(env, esock_atom_addrform, esock_atom_true);
#else
@@ -3722,7 +4122,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_ADD_MEMBERSHIP => IPV6_ADD_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IPV6_ADD_MEMBERSHIP => IPV6_ADD_MEMBERSHIP *** */
#if defined(IPV6_ADD_MEMBERSHIP)
tmp = MKT2(env, esock_atom_add_membership, esock_atom_true);
#else
@@ -3731,7 +4131,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_AUTHHDR => IPV6_AUTHHDR *** */
+ /* *** ESOCK_OPT_IPV6_AUTHHDR => IPV6_AUTHHDR *** */
#if defined(IPV6_AUTHHDR)
tmp = MKT2(env, esock_atom_authhdr, esock_atom_true);
#else
@@ -3740,17 +4140,17 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_AUTH_LEVEL => IPV6_AUTH_LEVEL *** */
+ /* *** ESOCK_OPT_IPV6_AUTH_LEVEL => IPV6_AUTH_LEVEL *** */
tmp = MKT2(env, esock_atom_auth_level, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_CHECKSUM => IPV6_CHECKSUM *** */
+ /* *** ESOCK_OPT_IPV6_CHECKSUM => IPV6_CHECKSUM *** */
tmp = MKT2(env, esock_atom_checksum, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_DROP_MEMBERSHIP => IPV6_DROP_MEMBERSHIP *** */
+ /* *** ESOCK_OPT_IPV6_DROP_MEMBERSHIP => IPV6_DROP_MEMBERSHIP *** */
#if defined(IPV6_DROP_MEMBERSHIP)
tmp = MKT2(env, esock_atom_drop_membership, esock_atom_true);
#else
@@ -3759,7 +4159,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_DSTOPTS => IPV6_DSTOPTS *** */
+ /* *** ESOCK_OPT_IPV6_DSTOPTS => IPV6_DSTOPTS *** */
#if defined(IPV6_DSTOPTS)
tmp = MKT2(env, esock_atom_dstopts, esock_atom_true);
#else
@@ -3768,22 +4168,22 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_ESP_NETWORK_LEVEL => IPV6_ESP_NETWORK_LEVEL *** */
+ /* *** ESOCK_OPT_IPV6_ESP_NETWORK_LEVEL => IPV6_ESP_NETWORK_LEVEL *** */
tmp = MKT2(env, esock_atom_esp_network_level, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_ESP_TRANS_LEVEL => IPV6_ESP_TRANS_LEVEL *** */
+ /* *** ESOCK_OPT_IPV6_ESP_TRANS_LEVEL => IPV6_ESP_TRANS_LEVEL *** */
tmp = MKT2(env, esock_atom_esp_trans_level, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_FAITH => IPV6_FAITH *** */
+ /* *** ESOCK_OPT_IPV6_FAITH => IPV6_FAITH *** */
tmp = MKT2(env, esock_atom_faith, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_FLOWINFO => IPV6_FLOWINFO *** */
+ /* *** ESOCK_OPT_IPV6_FLOWINFO => IPV6_FLOWINFO *** */
#if defined(IPV6_FLOWINFO)
tmp = MKT2(env, esock_atom_flowinfo, esock_atom_true);
#else
@@ -3792,7 +4192,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_HOPLIMIT => IPV6_HOPLIMIT *** */
+ /* *** ESOCK_OPT_IPV6_HOPLIMIT => IPV6_HOPLIMIT *** */
#if defined(IPV6_HOPLIMIT)
tmp = MKT2(env, esock_atom_hoplimit, esock_atom_true);
#else
@@ -3801,7 +4201,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_HOPOPTS => IPV6_HOPOPTS *** */
+ /* *** ESOCK_OPT_IPV6_HOPOPTS => IPV6_HOPOPTS *** */
#if defined(IPV6_HOPOPTS)
tmp = MKT2(env, esock_atom_hopopts, esock_atom_true);
#else
@@ -3810,22 +4210,22 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_IPCOMP_LEVEL => IPV6_IPCOMP_LEVEL *** */
+ /* *** ESOCK_OPT_IPV6_IPCOMP_LEVEL => IPV6_IPCOMP_LEVEL *** */
tmp = MKT2(env, esock_atom_ipcomp_level, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_JOIN_GROUP => IPV6_JOIN_GROUP *** */
+ /* *** ESOCK_OPT_IPV6_JOIN_GROUP => IPV6_JOIN_GROUP *** */
tmp = MKT2(env, esock_atom_join_group, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_LEAVE_GROUP => IPV6_LEAVE_GROUP *** */
+ /* *** ESOCK_OPT_IPV6_LEAVE_GROUP => IPV6_LEAVE_GROUP *** */
tmp = MKT2(env, esock_atom_leave_group, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_MTU => IPV6_MTU *** */
+ /* *** ESOCK_OPT_IPV6_MTU => IPV6_MTU *** */
#if defined(IPV6_MTU)
tmp = MKT2(env, esock_atom_mtu, esock_atom_true);
#else
@@ -3834,7 +4234,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_MTU_DISCOVER => IPV6_MTU_DISCOVER *** */
+ /* *** ESOCK_OPT_IPV6_MTU_DISCOVER => IPV6_MTU_DISCOVER *** */
#if defined(IPV6_MTU_DISCOVER)
tmp = MKT2(env, esock_atom_mtu_discover, esock_atom_true);
#else
@@ -3843,7 +4243,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_MULTICAST_HOPS => IPV6_MULTICAST_HOPS *** */
+ /* *** ESOCK_OPT_IPV6_MULTICAST_HOPS => IPV6_MULTICAST_HOPS *** */
#if defined(IPV6_MULTICAST_HOPS)
tmp = MKT2(env, esock_atom_multicast_hops, esock_atom_true);
#else
@@ -3852,7 +4252,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_MULTICAST_IF => IPV6_MULTICAST_IF *** */
+ /* *** ESOCK_OPT_IPV6_MULTICAST_IF => IPV6_MULTICAST_IF *** */
#if defined(IPV6_MULTICAST_IF)
tmp = MKT2(env, esock_atom_multicast_if, esock_atom_true);
#else
@@ -3861,7 +4261,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_MULTICAST_LOOP => IPV6_MULTICAST_LOOP *** */
+ /* *** ESOCK_OPT_IPV6_MULTICAST_LOOP => IPV6_MULTICAST_LOOP *** */
#if defined(IPV6_MULTICAST_LOOP)
tmp = MKT2(env, esock_atom_multicast_loop, esock_atom_true);
#else
@@ -3870,17 +4270,17 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_PORTRANGE => IPV6_PORTRANGE *** */
+ /* *** ESOCK_OPT_IPV6_PORTRANGE => IPV6_PORTRANGE *** */
tmp = MKT2(env, esock_atom_portrange, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_PKTOPTIONS => IPV6_PKTOPTIONS *** */
+ /* *** ESOCK_OPT_IPV6_PKTOPTIONS => IPV6_PKTOPTIONS *** */
tmp = MKT2(env, esock_atom_pktoptions, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_RECVERR => IPV6_RECVERR *** */
+ /* *** ESOCK_OPT_IPV6_RECVERR => IPV6_RECVERR *** */
#if defined(IPV6_RECVERR)
tmp = MKT2(env, esock_atom_recverr, esock_atom_true);
#else
@@ -3889,7 +4289,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_RECVPKTINFO => IPV6_RECVPKTINFO *** */
+ /* *** ESOCK_OPT_IPV6_RECVPKTINFO => IPV6_RECVPKTINFO *** */
#if defined(IPV6_RECVPKTINFO)
tmp = MKT2(env, esock_atom_recvpktinfo, esock_atom_true);
#else
@@ -3898,12 +4298,12 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_RECVTCLASS => IPV6_RECVTCLASS *** */
+ /* *** ESOCK_OPT_IPV6_RECVTCLASS => IPV6_RECVTCLASS *** */
tmp = MKT2(env, esock_atom_recvtclass, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_ROUTER_ALERT => IPV6_ROUTER_ALERT *** */
+ /* *** ESOCK_OPT_IPV6_ROUTER_ALERT => IPV6_ROUTER_ALERT *** */
#if defined(IPV6_ROUTER_ALERT)
tmp = MKT2(env, esock_atom_router_alert, esock_atom_true);
#else
@@ -3912,7 +4312,7 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_RTHDR => IPV6_RTHDR *** */
+ /* *** ESOCK_OPT_IPV6_RTHDR => IPV6_RTHDR *** */
#if defined(IPV6_RTHDR)
tmp = MKT2(env, esock_atom_rthdr, esock_atom_true);
#else
@@ -3921,12 +4321,12 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_TCLASS => IPV6_TCLASS *** */
+ /* *** ESOCK_OPT_IPV6_TCLASS => IPV6_TCLASS *** */
tmp = MKT2(env, esock_atom_tclass, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_UNICAST_HOPS => IPV6_UNICAST_HOPS *** */
+ /* *** ESOCK_OPT_IPV6_UNICAST_HOPS => IPV6_UNICAST_HOPS *** */
#if defined(IPV6_UNICAST_HOPS)
tmp = MKT2(env, esock_atom_unicast_hops, esock_atom_true);
#else
@@ -3935,12 +4335,12 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_USE_MIN_MTU => IPV6_USE_MIN_MTU *** */
+ /* *** ESOCK_OPT_IPV6_USE_MIN_MTU => IPV6_USE_MIN_MTU *** */
tmp = MKT2(env, esock_atom_use_min_mtu, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_IPV6_V6ONLY => IPV6_V6ONLY *** */
+ /* *** ESOCK_OPT_IPV6_V6ONLY => IPV6_V6ONLY *** */
#if defined(IPV6_V6ONLY)
tmp = MKT2(env, esock_atom_v6only, esock_atom_true);
#else
@@ -3959,13 +4359,13 @@ ERL_NIF_TERM nsupports_options_ipv6(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_tcp(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(32);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_TCP_CONGESTION => TCP_CONGESTION *** */
+ /* *** ESOCK_OPT_TCP_CONGESTION => TCP_CONGESTION *** */
#if defined(TCP_CONGESTION)
tmp = MKT2(env, esock_atom_congestion, esock_atom_true);
#else
@@ -3974,7 +4374,7 @@ ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_CORK => TCP_CORK *** */
+ /* *** ESOCK_OPT_TCP_CORK => TCP_CORK *** */
#if defined(TCP_CORK)
tmp = MKT2(env, esock_atom_cork, esock_atom_true);
#else
@@ -3983,28 +4383,28 @@ ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_INFO => TCP_INFO *** */
+ /* *** ESOCK_OPT_TCP_INFO => TCP_INFO *** */
tmp = MKT2(env, esock_atom_info, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_KEEPCNT => TCP_KEEPCNT *** */
+ /* *** ESOCK_OPT_TCP_KEEPCNT => TCP_KEEPCNT *** */
tmp = MKT2(env, esock_atom_keepcnt, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_KEEPIDLE => TCP_KEEPIDLE *** */
+ /* *** ESOCK_OPT_TCP_KEEPIDLE => TCP_KEEPIDLE *** */
tmp = MKT2(env, esock_atom_keepidle, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_KEEPINTVL => TCP_KEEPINTVL *** */
+ /* *** ESOCK_OPT_TCP_KEEPINTVL => TCP_KEEPINTVL *** */
tmp = MKT2(env, esock_atom_keepintvl, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_MAXSEG => TCP_MAXSEG *** */
-#if defined(TCP_)
+ /* *** ESOCK_OPT_TCP_MAXSEG => TCP_MAXSEG *** */
+#if defined(TCP_MAXSEG)
tmp = MKT2(env, esock_atom_maxseg, esock_atom_true);
#else
tmp = MKT2(env, esock_atom_maxseg, esock_atom_false);
@@ -4012,13 +4412,13 @@ ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_MD5SIG => TCP_MD5SIG *** */
+ /* *** ESOCK_OPT_TCP_MD5SIG => TCP_MD5SIG *** */
tmp = MKT2(env, esock_atom_md5sig, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_NODELAY => TCP_NODELAY *** */
-#if defined(TCP_)
+ /* *** ESOCK_OPT_TCP_NODELAY => TCP_NODELAY *** */
+#if defined(TCP_NODELAY)
tmp = MKT2(env, esock_atom_nodelay, esock_atom_true);
#else
tmp = MKT2(env, esock_atom_nodelay, esock_atom_false);
@@ -4026,22 +4426,22 @@ ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_NOOPT => TCP_NOOPT *** */
+ /* *** ESOCK_OPT_TCP_NOOPT => TCP_NOOPT *** */
tmp = MKT2(env, esock_atom_noopt, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_NOPUSH => TCP_NOPUSH *** */
+ /* *** ESOCK_OPT_TCP_NOPUSH => TCP_NOPUSH *** */
tmp = MKT2(env, esock_atom_nopush, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_SYNCNT => TCP_SYNCNT *** */
+ /* *** ESOCK_OPT_TCP_SYNCNT => TCP_SYNCNT *** */
tmp = MKT2(env, esock_atom_syncnt, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_TCP_USER_TIMEOUT => TCP_USER_TIMEOUT *** */
+ /* *** ESOCK_OPT_TCP_USER_TIMEOUT => TCP_USER_TIMEOUT *** */
tmp = MKT2(env, esock_atom_user_timeout, esock_atom_false);
TARRAY_ADD(opts, tmp);
@@ -4056,13 +4456,13 @@ ERL_NIF_TERM nsupports_options_tcp(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_udp(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_udp(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(8);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_UDP_CORK => UDP_CORK *** */
+ /* *** ESOCK_OPT_UDP_CORK => UDP_CORK *** */
#if defined(UDP_CORK)
tmp = MKT2(env, esock_atom_cork, esock_atom_true);
#else
@@ -4081,18 +4481,18 @@ ERL_NIF_TERM nsupports_options_udp(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_options_sctp(ErlNifEnv* env)
{
SocketTArray opts = TARRAY_CREATE(64);
ERL_NIF_TERM tmp, optsL;
- /* *** SOCKET_OPT_SCTP_ADAPTION_LAYER => SCTP_ADAPTION_LAYER *** */
+ /* *** ESOCK_OPT_SCTP_ADAPTION_LAYER => SCTP_ADAPTION_LAYER *** */
tmp = MKT2(env, esock_atom_adaption_layer, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_ASSOCINFO => SCTP_ASSOCINFO *** */
+ /* *** ESOCK_OPT_SCTP_ASSOCINFO => SCTP_ASSOCINFO *** */
#if defined(SCTP_ASSOCINFO)
tmp = MKT2(env, esock_atom_associnfo, esock_atom_true);
#else
@@ -4101,32 +4501,32 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTH_ACTIVE_KEY => SCTP_AUTH_ACTIVE_KEY *** */
+ /* *** ESOCK_OPT_SCTP_AUTH_ACTIVE_KEY => SCTP_AUTH_ACTIVE_KEY *** */
tmp = MKT2(env, esock_atom_auth_active_key, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTH_ASCONF => SCTP_AUTH_ASCONF *** */
+ /* *** ESOCK_OPT_SCTP_AUTH_ASCONF => SCTP_AUTH_ASCONF *** */
tmp = MKT2(env, esock_atom_auth_asconf, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTH_CHUNK => SCTP_AUTH_CHUNK *** */
+ /* *** ESOCK_OPT_SCTP_AUTH_CHUNK => SCTP_AUTH_CHUNK *** */
tmp = MKT2(env, esock_atom_auth_chunk, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTH_DELETE_KEY => SCTP_AUTH_DELETE_KEY *** */
+ /* *** ESOCK_OPT_SCTP_AUTH_DELETE_KEY => SCTP_AUTH_DELETE_KEY *** */
tmp = MKT2(env, esock_atom_auth_delete_key, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTH_KEY => SCTP_AUTH_KEY *** */
+ /* *** ESOCK_OPT_SCTP_AUTH_KEY => SCTP_AUTH_KEY *** */
tmp = MKT2(env, esock_atom_auth_key, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_AUTOCLOSE => SCTP_AUTOCLOSE *** */
+ /* *** ESOCK_OPT_SCTP_AUTOCLOSE => SCTP_AUTOCLOSE *** */
#if defined(SCTP_AUTOCLOSE)
tmp = MKT2(env, esock_atom_autoclose, esock_atom_true);
#else
@@ -4135,22 +4535,22 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_CONTEXT => SCTP_CONTEXT *** */
+ /* *** ESOCK_OPT_SCTP_CONTEXT => SCTP_CONTEXT *** */
tmp = MKT2(env, esock_atom_context, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_DEFAULT_SEND_PARAMS => SCTP_DEFAULT_SEND_PARAMS *** */
+ /* *** ESOCK_OPT_SCTP_DEFAULT_SEND_PARAMS => SCTP_DEFAULT_SEND_PARAMS *** */
tmp = MKT2(env, esock_atom_default_send_params, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_DELAYED_ACK_TIME => SCTP_DELAYED_ACK_TIME *** */
+ /* *** ESOCK_OPT_SCTP_DELAYED_ACK_TIME => SCTP_DELAYED_ACK_TIME *** */
tmp = MKT2(env, esock_atom_delayed_ack_time, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_DISABLE_FRAGMENTS => SCTP_DISABLE_FRAGMENTS *** */
+ /* *** ESOCK_OPT_SCTP_DISABLE_FRAGMENTS => SCTP_DISABLE_FRAGMENTS *** */
#if defined(SCTP_DISABLE_FRAGMENTS)
tmp = MKT2(env, esock_atom_disable_fragments, esock_atom_true);
#else
@@ -4159,12 +4559,12 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_HMAC_IDENT => SCTP_HMAC_IDENT *** */
+ /* *** ESOCK_OPT_SCTP_HMAC_IDENT => SCTP_HMAC_IDENT *** */
tmp = MKT2(env, esock_atom_hmac_ident, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_EVENTS => SCTP_EVENTS *** */
+ /* *** ESOCK_OPT_SCTP_EVENTS => SCTP_EVENTS *** */
#if defined(SCTP_EVENTS)
tmp = MKT2(env, esock_atom_events, esock_atom_true);
#else
@@ -4173,22 +4573,22 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_EXPLICIT_EOR => SCTP_EXPLICIT_EOR *** */
+ /* *** ESOCK_OPT_SCTP_EXPLICIT_EOR => SCTP_EXPLICIT_EOR *** */
tmp = MKT2(env, esock_atom_explicit_eor, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_FRAGMENT_INTERLEAVE => SCTP_FRAGMENT_INTERLEAVE *** */
+ /* *** ESOCK_OPT_SCTP_FRAGMENT_INTERLEAVE => SCTP_FRAGMENT_INTERLEAVE *** */
tmp = MKT2(env, esock_atom_fragment_interleave, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_GET_PEER_ADDR_INFO => SCTP_GET_PEER_ADDR_INFO *** */
+ /* *** ESOCK_OPT_SCTP_GET_PEER_ADDR_INFO => SCTP_GET_PEER_ADDR_INFO *** */
tmp = MKT2(env, esock_atom_get_peer_addr_info, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_INITMSG => SCTP_INITMSG *** */
+ /* *** ESOCK_OPT_SCTP_INITMSG => SCTP_INITMSG *** */
#if defined(SCTP_INITMSG)
tmp = MKT2(env, esock_atom_initmsg, esock_atom_true);
#else
@@ -4197,17 +4597,17 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_I_WANT_MAPPED_V4_ADDR => SCTP_I_WANT_MAPPED_V4_ADDR *** */
+ /* *** ESOCK_OPT_SCTP_I_WANT_MAPPED_V4_ADDR => SCTP_I_WANT_MAPPED_V4_ADDR *** */
tmp = MKT2(env, esock_atom_i_want_mapped_v4_addr, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_LOCAL_AUTH_CHUNKS => SCTP_LOCAL_AUTH_CHUNKS *** */
+ /* *** ESOCK_OPT_SCTP_LOCAL_AUTH_CHUNKS => SCTP_LOCAL_AUTH_CHUNKS *** */
tmp = MKT2(env, esock_atom_local_auth_chunks, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_MAXSEG => SCTP_MAXSEG *** */
+ /* *** ESOCK_OPT_SCTP_MAXSEG => SCTP_MAXSEG *** */
#if defined(SCTP_MAXSEG)
tmp = MKT2(env, esock_atom_maxseg, esock_atom_true);
#else
@@ -4216,12 +4616,12 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_MAXBURST => SCTP_MAXBURST *** */
+ /* *** ESOCK_OPT_SCTP_MAXBURST => SCTP_MAXBURST *** */
tmp = MKT2(env, esock_atom_maxburst, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_NODELAY => SCTP_NODELAY *** */
+ /* *** ESOCK_OPT_SCTP_NODELAY => SCTP_NODELAY *** */
#if defined(SCTP_NODELAY)
tmp = MKT2(env, esock_atom_nodelay, esock_atom_true);
#else
@@ -4230,32 +4630,32 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_PARTIAL_DELIVERY_POINT => SCTP_PARTIAL_DELIVERY_POINT *** */
+ /* *** ESOCK_OPT_SCTP_PARTIAL_DELIVERY_POINT => SCTP_PARTIAL_DELIVERY_POINT *** */
tmp = MKT2(env, esock_atom_partial_delivery_point, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_PEER_ADDR_PARAMS => SCTP_PEER_ADDR_PARAMS *** */
+ /* *** ESOCK_OPT_SCTP_PEER_ADDR_PARAMS => SCTP_PEER_ADDR_PARAMS *** */
tmp = MKT2(env, esock_atom_peer_addr_params, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_PEER_AUTH_CHUNKS => SCTP_PEER_AUTH_CHUNKS *** */
+ /* *** ESOCK_OPT_SCTP_PEER_AUTH_CHUNKS => SCTP_PEER_AUTH_CHUNKS *** */
tmp = MKT2(env, esock_atom_peer_auth_chunks, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_PRIMARY_ADDR => SCTP_PRIMARY_ADDR *** */
+ /* *** ESOCK_OPT_SCTP_PRIMARY_ADDR => SCTP_PRIMARY_ADDR *** */
tmp = MKT2(env, esock_atom_primary_addr, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_RESET_STREAMS => SCTP_RESET_STREAMS *** */
+ /* *** ESOCK_OPT_SCTP_RESET_STREAMS => SCTP_RESET_STREAMS *** */
tmp = MKT2(env, esock_atom_reset_streams, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_RTOINFO => SCTP_RTOINFO *** */
+ /* *** ESOCK_OPT_SCTP_RTOINFO => SCTP_RTOINFO *** */
#if defined(SCTP_RTOINFO)
tmp = MKT2(env, esock_atom_rtoinfo, esock_atom_true);
#else
@@ -4264,17 +4664,17 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_SET_PEER_PRIMARY_ADDR => SCTP_SET_PEER_PRIMARY_ADDR *** */
+ /* *** ESOCK_OPT_SCTP_SET_PEER_PRIMARY_ADDR => SCTP_SET_PEER_PRIMARY_ADDR *** */
tmp = MKT2(env, esock_atom_set_peer_primary_addr, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_STATUS => SCTP_STATUS *** */
+ /* *** ESOCK_OPT_SCTP_STATUS => SCTP_STATUS *** */
tmp = MKT2(env, esock_atom_status, esock_atom_false);
TARRAY_ADD(opts, tmp);
- /* *** SOCKET_OPT_SCTP_USE_EXT_RECVINFO => SCTP_USE_EXT_RECVINFO *** */
+ /* *** ESOCK_OPT_SCTP_USE_EXT_RECVINFO => SCTP_USE_EXT_RECVINFO *** */
tmp = MKT2(env, esock_atom_use_ext_recvinfo, esock_atom_false);
TARRAY_ADD(opts, tmp);
@@ -4289,7 +4689,7 @@ ERL_NIF_TERM nsupports_options_sctp(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_sctp(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_sctp(ErlNifEnv* env)
{
ERL_NIF_TERM supports;
@@ -4307,7 +4707,7 @@ ERL_NIF_TERM nsupports_sctp(ErlNifEnv* env)
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsupports_ipv6(ErlNifEnv* env)
+ERL_NIF_TERM esock_supports_ipv6(ErlNifEnv* env)
{
ERL_NIF_TERM supports;
@@ -4324,6 +4724,24 @@ ERL_NIF_TERM nsupports_ipv6(ErlNifEnv* env)
+#if !defined(__WIN32__)
+static
+ERL_NIF_TERM esock_supports_local(ErlNifEnv* env)
+{
+ ERL_NIF_TERM supports;
+
+#if defined(AF_LOCAL)
+ supports = esock_atom_true;
+#else
+ supports = esock_atom_false;
+#endif
+
+ return supports;
+}
+#endif
+
+
+
/* ----------------------------------------------------------------------
* nif_open
*
@@ -4400,7 +4818,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
#endif
- result = nopen(env, domain, type, proto, netns);
+ result = esock_open(env, domain, type, proto, netns);
SGDBG( ("SOCKET", "nif_open -> done with result: "
"\r\n %T"
@@ -4412,7 +4830,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
}
-/* nopen - create an endpoint for communication
+/* esock_open - create an endpoint for communication
*
* Assumes the input has been validated.
*
@@ -4421,21 +4839,22 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
* yet, we must use the global debug flag.
*/
#if !defined(__WIN32__)
+
static
-ERL_NIF_TERM nopen(ErlNifEnv* env,
- int domain, int type, int protocol,
- char* netns)
+ERL_NIF_TERM esock_open(ErlNifEnv* env,
+ int domain, int type, int protocol,
+ char* netns)
{
ESockDescriptor* descP;
ERL_NIF_TERM res;
- int save_errno = 0;
+ int proto = protocol, save_errno = 0;
SOCKET sock;
HANDLE event;
#ifdef HAVE_SETNS
int current_ns = 0;
#endif
- SGDBG( ("SOCKET", "nopen -> entry with"
+ SGDBG( ("SOCKET", "esock_open -> entry with"
"\r\n domain: %d"
"\r\n type: %d"
"\r\n protocol: %d"
@@ -4448,10 +4867,34 @@ ERL_NIF_TERM nopen(ErlNifEnv* env,
return esock_make_error_errno(env, save_errno);
#endif
- if ((sock = sock_open(domain, type, protocol)) == INVALID_SOCKET)
+ if ((sock = sock_open(domain, type, proto)) == INVALID_SOCKET)
return esock_make_error_errno(env, sock_errno());
- SGDBG( ("SOCKET", "nopen -> open success: %d\r\n", sock) );
+ SGDBG( ("SOCKET", "esock_open -> open success: %d\r\n", sock) );
+
+
+ /* NOTE that if the protocol = 0 (default) and the domain is not
+ * local (AF_LOCAL) we need to explicitly get the protocol here!
+ */
+
+ if ((proto == 0)
+#if defined(AF_LOCAL)
+ && (domain != AF_LOCAL)
+#endif
+ )
+ if (!esock_open_which_protocol(sock, &proto)) {
+ if (proto == ESOCK_WHICH_PROTO_ERROR) {
+ save_errno = sock_errno();
+ while ((sock_close(sock) == INVALID_SOCKET) &&
+ (sock_errno() == EINTR));
+ return esock_make_error_errno(env, save_errno);
+ } else {
+ while ((sock_close(sock) == INVALID_SOCKET) &&
+ (sock_errno() == EINTR));
+ return esock_make_error(env, esock_atom_eafnosupport);
+ }
+ }
+
#ifdef HAVE_SETNS
if ((netns != NULL) &&
@@ -4469,7 +4912,7 @@ ERL_NIF_TERM nopen(ErlNifEnv* env,
return esock_make_error_errno(env, save_errno);
}
- SGDBG( ("SOCKET", "nopen -> event success: %d\r\n", event) );
+ SGDBG( ("SOCKET", "esock_open -> event success: %d\r\n", event) );
SET_NONBLOCKING(sock);
@@ -4481,10 +4924,10 @@ ERL_NIF_TERM nopen(ErlNifEnv* env,
return enif_make_badarg(env);
}
- descP->state = SOCKET_STATE_OPEN;
+ descP->state = ESOCK_STATE_OPEN;
descP->domain = domain;
descP->type = type;
- descP->protocol = protocol;
+ descP->protocol = proto;
/* Does this apply to other types? Such as RAW?
* Also, is this really correct? Should we not wait for bind?
@@ -4510,7 +4953,7 @@ ERL_NIF_TERM nopen(ErlNifEnv* env,
if (enif_self(env, &descP->ctrlPid) == NULL)
return esock_make_error(env, atom_exself);
- if (MONP("nopen -> ctrl",
+ if (MONP("esock_open -> ctrl",
env, descP,
&descP->ctrlPid,
&descP->ctrlMon) != 0)
@@ -4521,6 +4964,32 @@ ERL_NIF_TERM nopen(ErlNifEnv* env,
return esock_make_ok2(env, res);
}
+
+
+static
+BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto)
+{
+#if defined(SO_PROTOCOL)
+ int val;
+ SOCKOPTLEN_T valSz = sizeof(val);
+ int res;
+
+ res = sock_getopt(sock, SOL_SOCKET, SO_PROTOCOL, &val, &valSz);
+
+ if (res != 0) {
+ *proto = ESOCK_WHICH_PROTO_ERROR;
+ return FALSE;
+ } else {
+ *proto = val;
+ return TRUE;
+ }
+#else
+ *proto = ESOCK_WHICH_PROTO_UNSUP;
+ return FALSE;
+#endif
+}
+
+
#endif // if !defined(__WIN32__)
@@ -4657,7 +5126,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 2) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
eSockAddr = argv[1];
@@ -4674,13 +5143,13 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env,
/* Make sure we are ready
* Not sure how this would even happen, but...
*/
- if (descP->state != SOCKET_STATE_OPEN)
+ if (descP->state != ESOCK_STATE_OPEN)
return esock_make_error(env, atom_exbadstate);
if ((xres = esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) != NULL)
return esock_make_error_str(env, xres);
- return nbind(env, descP, &sockAddr, addrLen);
+ return esock_bind(env, descP, &sockAddr, addrLen);
#endif // if defined(__WIN32__)
}
@@ -4688,24 +5157,24 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nbind(ErlNifEnv* env,
- ESockDescriptor* descP,
- ESockAddress* sockAddrP,
- unsigned int addrLen)
+ERL_NIF_TERM esock_bind(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESockAddress* sockAddrP,
+ unsigned int addrLen)
{
int port, ntohs_port;
- SSDBG( descP, ("SOCKET", "nbind -> try bind\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_bind -> try bind\r\n") );
if (IS_SOCKET_ERROR(sock_bind(descP->sock,
(struct sockaddr*) sockAddrP, addrLen))) {
return esock_make_error_errno(env, sock_errno());
}
- SSDBG( descP, ("SOCKET", "nbind -> bound - get port\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_bind -> bound - get port\r\n") );
port = which_address_port(sockAddrP);
- SSDBG( descP, ("SOCKET", "nbind -> port: %d\r\n", port) );
+ SSDBG( descP, ("SOCKET", "esock_bind -> port: %d\r\n", port) );
if (port == 0) {
SOCKLEN_T len = sizeof(ESockAddress);
sys_memzero((char *) sockAddrP, len);
@@ -4717,7 +5186,8 @@ ERL_NIF_TERM nbind(ErlNifEnv* env,
ntohs_port = sock_ntohs(port);
- SSDBG( descP, ("SOCKET", "nbind -> done with port = %d\r\n", ntohs_port) );
+ SSDBG( descP, ("SOCKET",
+ "esock_bind -> done with port = %d\r\n", ntohs_port) );
return esock_make_ok2(env, MKI(env, ntohs_port));
@@ -4757,7 +5227,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env,
sockRef = argv[0];
if ((argc != 2) ||
- !enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
eSockAddr = argv[1];
@@ -4784,7 +5254,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env,
MLOCK(descP->writeMtx);
MLOCK(descP->cfgMtx);
- res = nconnect(env, descP, sockRef);
+ res = esock_connect(env, descP, sockRef);
MUNLOCK(descP->cfgMtx);
MUNLOCK(descP->writeMtx);
@@ -4798,9 +5268,9 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nconnect(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef)
+ERL_NIF_TERM esock_connect(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM res, ref;
int code, sres, save_errno = 0;
@@ -4813,17 +5283,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", "esock_connect -> 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", "esock_connect -> already connected\r\n") );
return esock_make_error(env, atom_eisconn);
}
- if (IS_CONNECTING(descP)) {
- SSDBG( descP, ("SOCKET", "nif_connect -> already connecting\r\n") );
+ if (IS_CONNECTING(descP) && !is_connector(env, descP)) {
+ SSDBG( descP, ("SOCKET", "esock_connect -> already connecting\r\n") );
return esock_make_error(env, esock_atom_einval);
}
@@ -4837,31 +5307,95 @@ 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", "esock_connect -> 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);
- 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 (IS_SOCKET_ERROR(code)) {
+ switch (save_errno) {
+ case ERRNO_BLOCK: /* Winsock2 */
+ case EINPROGRESS: /* Unix & OSE!! */
+ SSDBG( descP, ("SOCKET",
+ "esock_connect -> would block => select\r\n") );
+
+ ref = MKREF(env);
+
+ if (IS_CONNECTING(descP)) {
+ /* Glitch */
+ res = esock_make_ok2(env, ref);
+ } else {
+
+ /* First time here */
+
+ if (enif_self(env, &descP->connPid) == NULL)
+ return esock_make_error(env, atom_exself);
+
+ if (MONP("esock_connect -> conn",
+ env, descP,
+ &descP->connPid,
+ &descP->connMon) != 0)
+ return esock_make_error(env, atom_exmon);
+
+ descP->state = ESOCK_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",
+ "esock_connect -> *already* connected\r\n") );
+ {
+ /* This is ***strange*** so make sure */
+ int err = 0;
+ if (!verify_is_connected(descP, &err)) {
+ descP->state = ESOCK_STATE_OPEN; /* restore state */
+ res = esock_make_error_errno(env, err);
+ } else {
+ descP->state = ESOCK_STATE_CONNECTED;
+ /* And just to be on the safe side, reset these */
+ enif_set_pid_undefined(&descP->connPid);
+ DEMONP("esock_connect -> connected",
+ env, descP, &descP->connMon);
+ descP->isReadable = TRUE;
+ descP->isWritable = TRUE;
+ res = esock_atom_ok;
+ }
+ }
+ break;
+
+ default:
+ SSDBG( descP, ("SOCKET", "esock_connect -> 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 */
- descP->state = SOCKET_STATE_CONNECTED;
+ SSDBG( descP, ("SOCKET", "esock_connect -> connected\r\n") );
+
+ descP->state = ESOCK_STATE_CONNECTED;
+ enif_set_pid_undefined(&descP->connPid);
+ DEMONP("esock_connect -> connected", env, descP, &descP->connMon);
descP->isReadable = TRUE;
descP->isWritable = TRUE;
res = esock_atom_ok;
+
} else {
+ /* Do we really need this case? */
+
+ SSDBG( descP, ("SOCKET", "esock_connect -> other error(2): %d\r\n",
+ save_errno) );
+
res = esock_make_error_errno(env, save_errno);
}
@@ -4896,35 +5430,38 @@ ERL_NIF_TERM nif_finalize_connection(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 1) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
- return nfinalize_connection(env, descP);
+ return esock_finalize_connection(env, descP);
#endif
}
-/* *** nfinalize_connection ***
+/* *** esock_finalize_connection ***
* Perform the final check to verify a connection.
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nfinalize_connection(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_finalize_connection(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
int error;
- if (descP->state != SOCKET_STATE_CONNECTING)
+ if (!IS_CONNECTING(descP))
return esock_make_error(env, atom_enotconn);
if (!verify_is_connected(descP, &error)) {
- descP->state = SOCKET_STATE_OPEN; /* restore state */
+ descP->state = ESOCK_STATE_OPEN; /* restore state */
return esock_make_error_errno(env, error);
}
- descP->state = SOCKET_STATE_CONNECTED;
+ descP->state = ESOCK_STATE_CONNECTED;
+ enif_set_pid_undefined(&descP->connPid);
+ DEMONP("esock_finalize_connection -> connected",
+ env, descP, &descP->connMon);
descP->isReadable = TRUE;
descP->isWritable = TRUE;
@@ -4987,6 +5524,29 @@ BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err)
+/* *** is_connector ***
+ * Check if the current process is the connector process.
+ */
+#if !defined(__WIN32__)
+static
+BOOLEAN_T is_connector(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ErlNifPid caller;
+
+ if (enif_self(env, &caller) == NULL)
+ return FALSE;
+
+ if (COMPARE_PIDS(&descP->connPid, &caller) == 0)
+ return TRUE;
+ else
+ return FALSE;
+
+}
+#endif
+
+
+
/* ----------------------------------------------------------------------
* nif_listen
*
@@ -5014,7 +5574,7 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 2) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP) ||
!GET_INT(env, argv[1], &backlog)) {
return enif_make_badarg(env);
}
@@ -5025,7 +5585,7 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env,
"\r\n backlog: %d"
"\r\n", descP->sock, argv[0], backlog) );
- return nlisten(env, descP, backlog);
+ return esock_listen(env, descP, backlog);
#endif // if defined(__WIN32__)
}
@@ -5034,9 +5594,9 @@ ERL_NIF_TERM nif_listen(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nlisten(ErlNifEnv* env,
- ESockDescriptor* descP,
- int backlog)
+ERL_NIF_TERM esock_listen(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int backlog)
{
/*
@@ -5046,7 +5606,7 @@ ERL_NIF_TERM nlisten(ErlNifEnv* env,
if (IS_CLOSED(descP) || IS_CLOSING(descP))
return esock_make_error(env, atom_closed);
- if (descP->state == SOCKET_STATE_CLOSED)
+ if (descP->state == ESOCK_STATE_CLOSED)
return esock_make_error(env, atom_exbadstate);
if (!IS_OPEN(descP))
@@ -5060,7 +5620,7 @@ ERL_NIF_TERM nlisten(ErlNifEnv* env,
if (IS_SOCKET_ERROR(sock_listen(descP->sock, backlog)))
return esock_make_error_errno(env, sock_errno());
- descP->state = SOCKET_STATE_LISTENING;
+ descP->state = ESOCK_STATE_LISTENING;
return esock_atom_ok;
@@ -5097,7 +5657,7 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env,
sockRef = argv[0];
if ((argc != 2) ||
- !enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
ref = argv[1];
@@ -5118,15 +5678,15 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env,
"\r\n",
descP->sock,
sockRef, ref,
- ((descP->state == SOCKET_STATE_LISTENING) ? "listening" :
- ((descP->state == SOCKET_STATE_ACCEPTING) ? "accepting" : "other")),
+ ((descP->state == ESOCK_STATE_LISTENING) ? "listening" :
+ ((descP->state == ESOCK_STATE_ACCEPTING) ? "accepting" : "other")),
descP->currentAcceptorP,
descP->currentAcceptor.pid,
esock_make_monitor_term(env, &descP->currentAcceptor.mon),
descP->currentAcceptor.env,
descP->currentAcceptor.ref) );
- res = naccept(env, descP, sockRef, ref);
+ res = esock_accept(env, descP, sockRef, ref);
MUNLOCK(descP->accMtx);
@@ -5138,10 +5698,10 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM naccept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref)
+ERL_NIF_TERM esock_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref)
{
ERL_NIF_TERM res;
@@ -5149,12 +5709,12 @@ ERL_NIF_TERM naccept(ErlNifEnv* env,
return esock_make_error(env, atom_closed);
switch (descP->state) {
- case SOCKET_STATE_LISTENING:
- res = naccept_listening(env, descP, sockRef, ref);
+ case ESOCK_STATE_LISTENING:
+ res = esock_accept_listening(env, descP, sockRef, ref);
break;
- case SOCKET_STATE_ACCEPTING:
- res = naccept_accepting(env, descP, sockRef, ref);
+ case ESOCK_STATE_ACCEPTING:
+ res = esock_accept_accepting(env, descP, sockRef, ref);
break;
default:
@@ -5167,16 +5727,16 @@ ERL_NIF_TERM naccept(ErlNifEnv* env,
#endif // if !defined(__WIN32__)
-/* *** naccept_listening ***
+/* *** esock_accept_listening ***
*
* We have no active acceptor (and therefor no acceptors in queue).
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM accRef)
+ERL_NIF_TERM esock_accept_listening(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM accRef)
{
ESockAddress remote;
unsigned int n;
@@ -5185,14 +5745,14 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
ErlNifPid caller;
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "naccept_listening -> get caller\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_accept_listening -> get caller\r\n") );
if (enif_self(env, &caller) == NULL)
return esock_make_error(env, atom_exself);
n = sizeof(remote);
sys_memzero((char *) &remote, n);
- SSDBG( descP, ("SOCKET", "naccept_listening -> try accept\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_accept_listening -> try accept\r\n") );
accSock = sock_accept(descP->sock, (struct sockaddr*) &remote, &n);
if (accSock == INVALID_SOCKET) {
@@ -5200,10 +5760,11 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "naccept_listening -> accept failed (%d)\r\n", save_errno) );
+ "esock_accept_listening -> accept failed (%d)\r\n",
+ save_errno) );
- res = naccept_listening_error(env, descP, sockRef, accRef,
- caller, save_errno);
+ res = esock_accept_listening_error(env, descP, sockRef, accRef,
+ caller, save_errno);
} else {
@@ -5211,9 +5772,9 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
* We got one
*/
- SSDBG( descP, ("SOCKET", "naccept_listening -> success\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_accept_listening -> success\r\n") );
- res = naccept_listening_accept(env, descP, accSock, caller, &remote);
+ res = esock_accept_listening_accept(env, descP, accSock, caller, &remote);
}
@@ -5221,7 +5782,7 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
}
-/* *** naccept_listening_error ***
+/* *** esock_accept_listening_error ***
*
* The accept call resultet in an error - handle it.
* There are only two cases:
@@ -5229,12 +5790,12 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env,
* 2) Other => Return the value (converted to an atom)
*/
static
-ERL_NIF_TERM naccept_listening_error(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM accRef,
- ErlNifPid caller,
- int save_errno)
+ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM accRef,
+ ErlNifPid caller,
+ int save_errno)
{
ERL_NIF_TERM res;
@@ -5243,28 +5804,29 @@ ERL_NIF_TERM naccept_listening_error(ErlNifEnv* env,
/* *** Try again later *** */
SSDBG( descP,
- ("SOCKET", "naccept_listening_error -> would block\r\n") );
+ ("SOCKET", "esock_accept_listening_error -> would block\r\n") );
descP->currentAcceptor.pid = caller;
- if (MONP("naccept_listening -> current acceptor",
+ if (MONP("esock_accept_listening -> current acceptor",
env, descP,
&descP->currentAcceptor.pid,
&descP->currentAcceptor.mon) != 0) {
enif_set_pid_undefined(&descP->currentAcceptor.pid);
res = esock_make_error(env, atom_exmon);
} else {
+ ESOCK_ASSERT(!descP->currentAcceptor.env);
descP->currentAcceptor.env = esock_alloc_env("current acceptor");
descP->currentAcceptor.ref = CP_TERM(descP->currentAcceptor.env,
accRef);
descP->currentAcceptorP = &descP->currentAcceptor;
- res = naccept_busy_retry(env, descP,
- sockRef, accRef,
- NULL, SOCKET_STATE_ACCEPTING);
+ res = esock_accept_busy_retry(env, descP,
+ sockRef, accRef,
+ NULL, ESOCK_STATE_ACCEPTING);
}
} else {
SSDBG( descP,
("SOCKET",
- "naccept_listening -> errno: %d\r\n", save_errno) );
+ "esock_accept_listening -> errno: %d\r\n", save_errno) );
res = esock_make_error_errno(env, save_errno);
}
@@ -5272,20 +5834,20 @@ ERL_NIF_TERM naccept_listening_error(ErlNifEnv* env,
}
-/* *** naccept_listening_accept ***
+/* *** esock_accept_listening_accept ***
*
* The accept call was successful (accepted) - handle the new connection.
*/
static
-ERL_NIF_TERM naccept_listening_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- SOCKET accSock,
- ErlNifPid caller,
- ESockAddress* remote)
+ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ SOCKET accSock,
+ ErlNifPid caller,
+ ESockAddress* remote)
{
ERL_NIF_TERM res;
- naccept_accepted(env, descP, accSock, caller, remote, &res);
+ esock_accept_accepted(env, descP, accSock, caller, remote, &res);
return res;
}
@@ -5293,7 +5855,7 @@ ERL_NIF_TERM naccept_listening_accept(ErlNifEnv* env,
-/* *** naccept_accepting ***
+/* *** esock_accept_accepting ***
*
* We have an active acceptor and possibly acceptors waiting in queue.
* If the pid of the calling process is not the pid of the "current process",
@@ -5301,20 +5863,20 @@ ERL_NIF_TERM naccept_listening_accept(ErlNifEnv* env,
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM naccept_accepting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM ref)
+ERL_NIF_TERM esock_accept_accepting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM ref)
{
ErlNifPid caller;
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "naccept_accepting -> get caller\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_accept_accepting -> get caller\r\n") );
if (enif_self(env, &caller) == NULL)
return esock_make_error(env, atom_exself);
- SSDBG( descP, ("SOCKET", "naccept_accepting -> check: "
+ SSDBG( descP, ("SOCKET", "esock_accept_accepting -> check: "
"are caller current acceptor:"
"\r\n Caller: %T"
"\r\n Current: %T"
@@ -5323,18 +5885,19 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env,
if (COMPARE_PIDS(&descP->currentAcceptor.pid, &caller) == 0) {
SSDBG( descP,
- ("SOCKET", "naccept_accepting -> current acceptor\r\n") );
+ ("SOCKET", "esock_accept_accepting -> current acceptor\r\n") );
- res = naccept_accepting_current(env, descP, sockRef, ref);
+ res = esock_accept_accepting_current(env, descP, sockRef, ref);
} else {
/* Not the "current acceptor", so (maybe) push onto queue */
SSDBG( descP,
- ("SOCKET", "naccept_accepting -> *not* current acceptor\r\n") );
+ ("SOCKET",
+ "esock_accept_accepting -> *not* current acceptor\r\n") );
- res = naccept_accepting_other(env, descP, ref, caller);
+ res = esock_accept_accepting_other(env, descP, ref, caller);
}
@@ -5344,14 +5907,14 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env,
-/* *** naccept_accepting_current ***
+/* *** esock_accept_accepting_current ***
* Handles when the current acceptor makes another attempt.
*/
static
-ERL_NIF_TERM naccept_accepting_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM accRef)
+ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM accRef)
{
ESockAddress remote;
unsigned int n;
@@ -5359,7 +5922,8 @@ ERL_NIF_TERM naccept_accepting_current(ErlNifEnv* env,
int save_errno;
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "naccept_accepting_current -> try accept\r\n") );
+ SSDBG( descP, ("SOCKET",
+ "esock_accept_accepting_current -> try accept\r\n") );
n = sizeof(descP->remote);
sys_memzero((char *) &remote, n);
accSock = sock_accept(descP->sock, (struct sockaddr*) &remote, &n);
@@ -5369,18 +5933,19 @@ ERL_NIF_TERM naccept_accepting_current(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "naccept_accepting_current -> accept failed: %d\r\n",
+ "esock_accept_accepting_current -> accept failed: %d\r\n",
save_errno) );
- res = naccept_accepting_current_error(env, descP, sockRef,
- accRef, save_errno);
+ res = esock_accept_accepting_current_error(env, descP, sockRef,
+ accRef, save_errno);
} else {
- SSDBG( descP, ("SOCKET", "naccept_accepting_current -> accepted\r\n") );
+ SSDBG( descP, ("SOCKET",
+ "esock_accept_accepting_current -> accepted\r\n") );
- res = naccept_accepting_current_accept(env, descP, sockRef,
- accSock, &remote);
+ res = esock_accept_accepting_current_accept(env, descP, sockRef,
+ accSock, &remote);
}
@@ -5388,40 +5953,42 @@ ERL_NIF_TERM naccept_accepting_current(ErlNifEnv* env,
}
-/* *** naccept_accepting_current_accept ***
+/* *** esock_accept_accepting_current_accept ***
* Handles when the current acceptor succeeded in its accept call -
* handle the new connection.
*/
static
-ERL_NIF_TERM naccept_accepting_current_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- SOCKET accSock,
- ESockAddress* remote)
+ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ SOCKET accSock,
+ ESockAddress* remote)
{
ERL_NIF_TERM res;
- if (naccept_accepted(env, descP, accSock,
- descP->currentAcceptor.pid, remote, &res)) {
+ if (esock_accept_accepted(env, descP, accSock,
+ descP->currentAcceptor.pid, remote, &res)) {
/* Clean out the old cobweb's before trying to invite a new spider */
descP->currentAcceptor.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentAcceptor.pid);
- esock_free_env("naccept_accepting_current_accept - "
+ esock_free_env("esock_accept_accepting_current_accept - "
"current-accept-env",
descP->currentAcceptor.env);
+ descP->currentAcceptor.env = NULL;
if (!activate_next_acceptor(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET",
- "naccept_accepting_current_accept -> "
+ "esock_accept_accepting_current_accept -> "
"no more writers\r\n") );
- descP->state = SOCKET_STATE_LISTENING;
+ descP->state = ESOCK_STATE_LISTENING;
descP->currentAcceptorP = NULL;
+ ESOCK_ASSERT(!descP->currentAcceptor.env);
descP->currentAcceptor.env = NULL;
MON_INIT(&descP->currentAcceptor.mon);
}
@@ -5432,22 +5999,23 @@ ERL_NIF_TERM naccept_accepting_current_accept(ErlNifEnv* env,
}
-/* *** naccept_accepting_current_error ***
+/* *** esock_accept_accepting_current_error ***
* The accept call of current acceptor resultet in an error - handle it.
* There are only two cases:
* 1) BLOCK => Attempt a "retry"
* 2) Other => Return the value (converted to an atom)
*/
static
-ERL_NIF_TERM naccept_accepting_current_error(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef,
- int save_errno)
+ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef,
+ int save_errno)
{
ESockRequestor req;
ERL_NIF_TERM res, reason;
+ req.env = NULL;
if (save_errno == ERRNO_BLOCK) {
/*
@@ -5456,13 +6024,13 @@ ERL_NIF_TERM naccept_accepting_current_error(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "naccept_accepting_current_error -> "
+ "esock_accept_accepting_current_error -> "
"would block: try again\r\n") );
- res = naccept_busy_retry(env, descP, sockRef, opRef,
- &descP->currentAcceptor.pid,
- /* No state change */
- descP->state);
+ res = esock_accept_busy_retry(env, descP, sockRef, opRef,
+ &descP->currentAcceptor.pid,
+ /* No state change */
+ descP->state);
} else {
@@ -5471,11 +6039,13 @@ ERL_NIF_TERM naccept_accepting_current_error(ErlNifEnv* env,
while (acceptor_pop(env, descP, &req)) {
SSDBG( descP,
- ("SOCKET", "naccept_accepting_current_error -> abort %T\r\n",
+ ("SOCKET",
+ "esock_accept_accepting_current_error -> abort %T\r\n",
req.pid) );
esock_send_abort_msg(env, sockRef, req.ref, req.env,
reason, &req.pid);
- DEMONP("naccept_accepting_current_error -> pop'ed writer",
+ req.env = NULL;
+ DEMONP("esock_accept_accepting_current_error -> pop'ed writer",
env, descP, &req.mon);
}
@@ -5485,16 +6055,16 @@ ERL_NIF_TERM naccept_accepting_current_error(ErlNifEnv* env,
}
-/* *** naccept_accepting_other ***
+/* *** esock_accept_accepting_other ***
* Handles when the another acceptor makes an attempt, which
* results (maybe) in the request beeing pushed onto the
* acceptor queue.
*/
static
-ERL_NIF_TERM naccept_accepting_other(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM ref,
- ErlNifPid caller)
+ERL_NIF_TERM esock_accept_accepting_other(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM ref,
+ ErlNifPid caller)
{
ERL_NIF_TERM result;
@@ -5509,18 +6079,18 @@ ERL_NIF_TERM naccept_accepting_other(ErlNifEnv* env,
-/* *** naccept_busy_retry ***
+/* *** esock_accept_busy_retry ***
*
* Perform a retry select. If successful, set nextState.
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM naccept_busy_retry(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM accRef,
- ErlNifPid* pid,
- unsigned int nextState)
+ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM accRef,
+ ErlNifPid* pid,
+ unsigned int nextState)
{
int sres;
ERL_NIF_TERM res, reason;
@@ -5539,17 +6109,17 @@ ERL_NIF_TERM naccept_busy_retry(ErlNifEnv* env,
-/* *** naccept_accepted ***
+/* *** esock_accept_accepted ***
*
* Generic function handling a successful accept.
*/
static
-BOOLEAN_T naccept_accepted(ErlNifEnv* env,
- ESockDescriptor* descP,
- SOCKET accSock,
- ErlNifPid pid,
- ESockAddress* remote,
- ERL_NIF_TERM* result)
+BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ SOCKET accSock,
+ ErlNifPid pid,
+ ESockAddress* remote,
+ ERL_NIF_TERM* result)
{
ESockDescriptor* accDescP;
HANDLE accEvent;
@@ -5587,7 +6157,7 @@ BOOLEAN_T naccept_accepted(ErlNifEnv* env,
enif_release_resource(accDescP);
accDescP->ctrlPid = pid;
- if (MONP("naccept_accepted -> ctrl",
+ if (MONP("esock_accept_accepted -> ctrl",
env, accDescP,
&accDescP->ctrlPid,
&accDescP->ctrlMon) != 0) {
@@ -5600,7 +6170,7 @@ BOOLEAN_T naccept_accepted(ErlNifEnv* env,
accDescP->remote = *remote;
SET_NONBLOCKING(accDescP->sock);
- accDescP->state = SOCKET_STATE_CONNECTED;
+ accDescP->state = ESOCK_STATE_CONNECTED;
accDescP->isReadable = TRUE;
accDescP->isWritable = TRUE;
@@ -5653,7 +6223,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
sockRef = argv[0]; // We need this in case we send in case we send abort
sendRef = argv[1];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -5678,7 +6248,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
* is done!
*/
- res = nsend(env, descP, sockRef, sendRef, &sndData, flags);
+ res = esock_send(env, descP, sockRef, sendRef, &sndData, flags);
MUNLOCK(descP->writeMtx);
@@ -5689,7 +6259,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
-/* *** nsend ***
+/* *** esock_send ***
*
* Do the actual send.
* Do some initial writer checks, do the actual send and then
@@ -5698,12 +6268,12 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsend(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ErlNifBinary* sndDataP,
- int flags)
+ERL_NIF_TERM esock_send(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ErlNifBinary* sndDataP,
+ int flags)
{
int save_errno;
ssize_t written;
@@ -5719,7 +6289,8 @@ ERL_NIF_TERM nsend(ErlNifEnv* env,
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- cnt_inc(&descP->writeTries, 1);
+ // cnt_inc(&descP->writeTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
written = sock_send(descP->sock, sndDataP->data, sndDataP->size, flags);
if (IS_SOCKET_ERROR(written))
@@ -5774,16 +6345,15 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 5) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
!GET_BIN(env, argv[2], &sndData) ||
!GET_UINT(env, argv[4], &eflags)) {
return enif_make_badarg(env);
}
- sockRef = argv[0]; // We need this in case we send in case we send abort
+ sockRef = argv[0]; // We need this in case we send abort (to the caller)
sendRef = argv[1];
eSockAddr = argv[3];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -5812,8 +6382,8 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
MLOCK(descP->writeMtx);
- res = nsendto(env, descP, sockRef, sendRef, &sndData, flags,
- &remoteAddr, remoteAddrLen);
+ res = esock_sendto(env, descP, sockRef, sendRef, &sndData, flags,
+ &remoteAddr, remoteAddrLen);
MUNLOCK(descP->writeMtx);
@@ -5829,14 +6399,14 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsendto(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ErlNifBinary* dataP,
- int flags,
- ESockAddress* toAddrP,
- unsigned int toAddrLen)
+ERL_NIF_TERM esock_sendto(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ErlNifBinary* dataP,
+ int flags,
+ ESockAddress* toAddrP,
+ unsigned int toAddrLen)
{
int save_errno;
ssize_t written;
@@ -5852,7 +6422,8 @@ ERL_NIF_TERM nsendto(ErlNifEnv* env,
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- cnt_inc(&descP->writeTries, 1);
+ // cnt_inc(&descP->writeTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
if (toAddrP != NULL) {
written = sock_sendto(descP->sock,
@@ -5910,11 +6481,11 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
!GET_UINT(env, argv[3], &eflags)) {
return enif_make_badarg(env);
}
- sockRef = argv[0]; // We need this in case we send in case we send abort
+ sockRef = argv[0]; // We need this in case we send abort (to the caller)
sendRef = argv[1];
eMsgHdr = argv[2];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -5931,7 +6502,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
MLOCK(descP->writeMtx);
- res = nsendmsg(env, descP, sockRef, sendRef, eMsgHdr, flags);
+ res = esock_sendmsg(env, descP, sockRef, sendRef, eMsgHdr, flags);
MUNLOCK(descP->writeMtx);
@@ -5948,12 +6519,12 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM sendRef,
- ERL_NIF_TERM eMsgHdr,
- int flags)
+ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM sendRef,
+ ERL_NIF_TERM eMsgHdr,
+ int flags)
{
ERL_NIF_TERM res, eAddr, eIOV, eCtrl;
ESockAddress addr;
@@ -5982,7 +6553,8 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
/* We don't need the address */
- SSDBG( descP, ("SOCKET", "nsendmsg -> connected: no address\r\n") );
+ SSDBG( descP, ("SOCKET",
+ "esock_sendmsg -> connected: no address\r\n") );
msgHdr.msg_name = NULL;
msgHdr.msg_namelen = 0;
@@ -5997,7 +6569,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
if (!GET_MAP_VAL(env, eMsgHdr, esock_atom_addr, &eAddr))
return esock_make_error(env, esock_atom_einval);
- SSDBG( descP, ("SOCKET", "nsendmsg -> not connected: "
+ SSDBG( descP, ("SOCKET", "esock_sendmsg -> not connected: "
"\r\n address: %T"
"\r\n", eAddr) );
@@ -6017,7 +6589,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
if (!GET_LIST_LEN(env, eIOV, &iovLen) && (iovLen > 0))
return esock_make_error(env, esock_atom_einval);
- SSDBG( descP, ("SOCKET", "nsendmsg -> iov length: %d\r\n", iovLen) );
+ SSDBG( descP, ("SOCKET", "esock_sendmsg -> iov length: %d\r\n", iovLen) );
iovBins = MALLOC(iovLen * sizeof(ErlNifBinary));
ESOCK_ASSERT( (iovBins != NULL) );
@@ -6035,7 +6607,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
ctrlBufLen = 0;
ctrlBuf = NULL;
}
- SSDBG( descP, ("SOCKET", "nsendmsg -> optional ctrl: "
+ SSDBG( descP, ("SOCKET", "esock_sendmsg -> optional ctrl: "
"\r\n ctrlBuf: 0x%lX"
"\r\n ctrlBufLen: %d"
"\r\n eCtrl: %T\r\n", ctrlBuf, ctrlBufLen, eCtrl) );
@@ -6053,7 +6625,8 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
SSDBG( descP, ("SOCKET",
- "nsendmsg -> total (iov) data size: %d\r\n", dataSize) );
+ "esock_sendmsg -> "
+ "total (iov) data size: %d\r\n", dataSize) );
/* Decode the ctrl and initiate that part of the msghdr.
@@ -6081,7 +6654,8 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env,
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- cnt_inc(&descP->writeTries, 1);
+ // cnt_inc(&descP->writeTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
/* And now, finally, try to send the message */
written = sock_sendmsg(descP->sock, &msgHdr, flags);
@@ -6210,10 +6784,10 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
!GET_UINT(env, argv[3], &eflags)) {
return enif_make_badarg(env);
}
- sockRef = argv[0]; // We need this in case we case we send abort
+ sockRef = argv[0]; // We need this in case we send abort (to the caller)
recvRef = argv[1];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -6230,7 +6804,7 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
* is done!
*/
- res = nrecv(env, descP, sockRef, recvRef, len, flags);
+ res = esock_recv(env, descP, sockRef, recvRef, len, flags);
MUNLOCK(descP->readMtx);
@@ -6247,12 +6821,12 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nrecv(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef,
- int len,
- int flags)
+ERL_NIF_TERM esock_recv(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef,
+ int len,
+ int flags)
{
ssize_t read;
ErlNifBinary buf;
@@ -6260,7 +6834,7 @@ ERL_NIF_TERM nrecv(ErlNifEnv* env,
int save_errno;
int bufSz = (len ? len : descP->rBufSz);
- SSDBG( descP, ("SOCKET", "nrecv -> entry with"
+ SSDBG( descP, ("SOCKET", "esock_recv -> entry with"
"\r\n len: %d (%d:%d)"
"\r\n flags: %d"
"\r\n", len, descP->rNumCnt, bufSz, flags) );
@@ -6279,13 +6853,11 @@ ERL_NIF_TERM nrecv(ErlNifEnv* env,
if (!ALLOC_BIN(bufSz, &buf))
return esock_make_error(env, atom_exalloc);
- /* We ignore the wrap for the moment.
- * Maybe we should issue a wrap-message to controlling process...
- */
- cnt_inc(&descP->readTries, 1);
+ // cnt_inc(&descP->readTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
// If it fails (read = -1), we need errno...
- SSDBG( descP, ("SOCKET", "nrecv -> try read (%d)\r\n", buf.size) );
+ SSDBG( descP, ("SOCKET", "esock_recv -> try read (%d)\r\n", buf.size) );
read = sock_recv(descP->sock, buf.data, buf.size, flags);
if (IS_SOCKET_ERROR(read)) {
save_errno = sock_errno();
@@ -6293,7 +6865,8 @@ ERL_NIF_TERM nrecv(ErlNifEnv* env,
save_errno = -1; // The value does not actually matter in this case
}
- SSDBG( descP, ("SOCKET", "nrecv -> read: %d (%d)\r\n", read, save_errno) );
+ SSDBG( descP, ("SOCKET",
+ "esock_recv -> read: %d (%d)\r\n", read, save_errno) );
return recv_check_result(env, descP,
read, len,
@@ -6354,10 +6927,10 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
!GET_UINT(env, argv[3], &eflags)) {
return enif_make_badarg(env);
}
- sockRef = argv[0]; // We need this in case we send in case we send abort
+ sockRef = argv[0]; // We need this in case we send abort (to the caller)
recvRef = argv[1];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -6394,7 +6967,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
* </KOLLA>
*/
- res = nrecvfrom(env, descP, sockRef, recvRef, bufSz, flags);
+ res = esock_recvfrom(env, descP, sockRef, recvRef, bufSz, flags);
MUNLOCK(descP->readMtx);
@@ -6410,12 +6983,12 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env,
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nrecvfrom(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef,
- Uint16 len,
- int flags)
+ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef,
+ Uint16 len,
+ int flags)
{
ESockAddress fromAddr;
unsigned int addrLen;
@@ -6425,7 +6998,7 @@ ERL_NIF_TERM nrecvfrom(ErlNifEnv* env,
ERL_NIF_TERM readerCheck;
int bufSz = (len ? len : descP->rBufSz);
- SSDBG( descP, ("SOCKET", "nrecvfrom -> entry with"
+ SSDBG( descP, ("SOCKET", "esock_recvfrom -> entry with"
"\r\n len: %d (%d)"
"\r\n flags: %d"
"\r\n", len, bufSz, flags) );
@@ -6444,10 +7017,8 @@ ERL_NIF_TERM nrecvfrom(ErlNifEnv* env,
if (!ALLOC_BIN(bufSz, &buf))
return esock_make_error(env, atom_exalloc);
- /* We ignore the wrap for the moment.
- * Maybe we should issue a wrap-message to controlling process...
- */
- cnt_inc(&descP->readTries, 1);
+ // cnt_inc(&descP->readTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
addrLen = sizeof(fromAddr);
sys_memzero((char*) &fromAddr, addrLen);
@@ -6525,10 +7096,10 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
!GET_UINT(env, argv[4], &eflags)) {
return enif_make_badarg(env);
}
- sockRef = argv[0]; // We need this in case we send in case we send abort
+ sockRef = argv[0]; // We need this in case we send abort (to the caller)
recvRef = argv[1];
- if (!enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -6566,7 +7137,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
* </KOLLA>
*/
- res = nrecvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags);
+ res = esock_recvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags);
MUNLOCK(descP->readMtx);
@@ -6582,13 +7153,13 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env,
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nrecvmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef,
- Uint16 bufLen,
- Uint16 ctrlLen,
- int flags)
+ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef,
+ Uint16 bufLen,
+ Uint16 ctrlLen,
+ int flags)
{
unsigned int addrLen;
ssize_t read;
@@ -6602,7 +7173,7 @@ ERL_NIF_TERM nrecvmsg(ErlNifEnv* env,
ERL_NIF_TERM readerCheck;
ESockAddress addr;
- SSDBG( descP, ("SOCKET", "nrecvmsg -> entry with"
+ SSDBG( descP, ("SOCKET", "esock_recvmsg -> entry with"
"\r\n bufSz: %d (%d)"
"\r\n ctrlSz: %d (%d)"
"\r\n flags: %d"
@@ -6634,10 +7205,8 @@ ERL_NIF_TERM nrecvmsg(ErlNifEnv* env,
if (!ALLOC_BIN(ctrlSz, &ctrl))
return esock_make_error(env, atom_exalloc);
- /* We ignore the wrap for the moment.
- * Maybe we should issue a wrap-message to controlling process...
- */
- cnt_inc(&descP->readTries, 1);
+ // cnt_inc(&descP->readTries, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
addrLen = sizeof(addr);
sys_memzero((char*) &addr, addrLen);
@@ -6693,28 +7262,28 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env,
ESockDescriptor* descP;
if ((argc != 1) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
if (IS_CLOSED(descP) || IS_CLOSING(descP))
return esock_make_error(env, atom_closed);
- return nclose(env, descP);
+ return esock_close(env, descP);
#endif // if defined(__WIN32__)
}
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nclose(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_close(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM reply, reason;
BOOLEAN_T doClose;
SSDBG( descP, ("SOCKET",
- "nclose -> [%d] entry (0x%lX, 0x%lX, 0x%lX, 0x%lX)\r\n",
+ "esock_close -> [%d] entry (0x%lX, 0x%lX, 0x%lX, 0x%lX)\r\n",
descP->sock,
descP->state,
descP->currentWriterP,
@@ -6723,10 +7292,10 @@ ERL_NIF_TERM nclose(ErlNifEnv* env,
MLOCK(descP->closeMtx);
- doClose = nclose_check(env, descP, &reason);
+ doClose = esock_close_check(env, descP, &reason);
if (doClose) {
- reply = nclose_do(env, descP);
+ reply = esock_close_do(env, descP);
} else {
reply = esock_make_error(env, reason);
}
@@ -6734,7 +7303,7 @@ ERL_NIF_TERM nclose(ErlNifEnv* env,
MUNLOCK(descP->closeMtx);
SSDBG( descP,
- ("SOCKET", "nclose -> [%d] done when: "
+ ("SOCKET", "esock_close -> [%d] done when: "
"\r\n state: 0x%lX"
"\r\n reply: %T"
"\r\n", descP->sock, descP->state, reply) );
@@ -6744,23 +7313,23 @@ ERL_NIF_TERM nclose(ErlNifEnv* env,
-/* *** nclose_check ***
+/* *** esock_close_check ***
*
* Check if we should try to perform the first stage close.
*/
static
-BOOLEAN_T nclose_check(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM* reason)
+BOOLEAN_T esock_close_check(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM* reason)
{
BOOLEAN_T doClose;
- if (descP->state == SOCKET_STATE_CLOSED) {
+ if (descP->state == ESOCK_STATE_CLOSED) {
doClose = FALSE;
*reason = atom_closed;
- } else if (descP->state == SOCKET_STATE_CLOSING) {
+ } else if (descP->state == ESOCK_STATE_CLOSING) {
doClose = FALSE;
*reason = atom_closing;
@@ -6790,7 +7359,7 @@ BOOLEAN_T nclose_check(ErlNifEnv* env,
* </KOLLA>
*/
- if (MONP("nclose_check -> closer",
+ if (MONP("esock_close_check -> closer",
env, descP,
&descP->closerPid,
&descP->closerMon) != 0) {
@@ -6801,7 +7370,7 @@ BOOLEAN_T nclose_check(ErlNifEnv* env,
} else {
descP->closeLocal = TRUE;
- descP->state = SOCKET_STATE_CLOSING;
+ descP->state = ESOCK_STATE_CLOSING;
descP->isReadable = FALSE;
descP->isWritable = FALSE;
doClose = TRUE;
@@ -6817,13 +7386,13 @@ BOOLEAN_T nclose_check(ErlNifEnv* env,
-/* *** nclose_do ***
+/* *** esock_close_do ***
*
* Perform (do) the first stage close.
*/
static
-ERL_NIF_TERM nclose_do(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_close_do(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
int domain = descP->domain;
int type = descP->type;
@@ -6831,7 +7400,7 @@ ERL_NIF_TERM nclose_do(ErlNifEnv* env,
int sres;
ERL_NIF_TERM reply, reason;
- descP->closeEnv = esock_alloc_env("nclose-do - close-env");
+ descP->closeEnv = esock_alloc_env("esock_close_do - close-env");
descP->closeRef = MKREF(descP->closeEnv);
sres = esock_select_stop(env, descP->sock, descP);
@@ -6840,7 +7409,8 @@ ERL_NIF_TERM nclose_do(ErlNifEnv* env,
/* Prep done - inform the caller it can finalize (close) directly */
SSDBG( descP,
- ("SOCKET", "nclose -> [%d] stop was called\r\n", descP->sock) );
+ ("SOCKET",
+ "esock_close -> [%d] stop was called\r\n", descP->sock) );
dec_socket(domain, type, protocol);
reply = esock_atom_ok;
@@ -6850,7 +7420,7 @@ ERL_NIF_TERM nclose_do(ErlNifEnv* env,
/* The stop callback function has been *scheduled* which means that we
* have to wait for it to complete. */
SSDBG( descP,
- ("SOCKET", "nclose -> [%d] stop was scheduled\r\n",
+ ("SOCKET", "esock_close -> [%d] stop was scheduled\r\n",
descP->sock) );
dec_socket(domain, type, protocol); // SHALL WE DO THIS AT finalize?
@@ -6859,7 +7429,7 @@ ERL_NIF_TERM nclose_do(ErlNifEnv* env,
} else {
SSDBG( descP,
- ("SOCKET", "nclose -> [%d] stop failed: %d\r\n",
+ ("SOCKET", "esock_close -> [%d] stop failed: %d\r\n",
descP->sock, sres) );
/* <KOLLA>
@@ -6873,7 +7443,7 @@ ERL_NIF_TERM nclose_do(ErlNifEnv* env,
*/
// Do we need this?
- DEMONP("nclose_do -> closer", env, descP, &descP->closerMon);
+ DEMONP("esock_close_do -> closer", env, descP, &descP->closerMon);
reason = MKT2(env, esock_atom_select_failed, MKI(env, sres));
reply = esock_make_error(env, reason);
@@ -6911,22 +7481,22 @@ ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 1) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
- return nfinalize_close(env, descP);
+ return esock_finalize_close(env, descP);
#endif // if defined(__WIN32__)
}
-/* *** nfinalize_close ***
+/* *** esock_finalize_close ***
* Perform the final step in the socket close.
*/
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nfinalize_close(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM reply;
@@ -6963,7 +7533,7 @@ ERL_NIF_TERM nfinalize_close(ErlNifEnv* env,
descP->sock = INVALID_SOCKET;
descP->event = INVALID_EVENT;
- descP->state = SOCKET_STATE_CLOSED;
+ descP->state = ESOCK_STATE_CLOSED;
return reply;
}
@@ -6995,7 +7565,7 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env,
int how;
if ((argc != 2) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP) ||
!GET_UINT(env, argv[1], &ehow)) {
return enif_make_badarg(env);
}
@@ -7006,7 +7576,7 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env,
if (!ehow2how(ehow, &how))
return enif_make_badarg(env);
- return nshutdown(env, descP, how);
+ return esock_shutdown(env, descP, how);
#endif // if defined(__WIN32__)
}
@@ -7014,9 +7584,9 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nshutdown(ErlNifEnv* env,
- ESockDescriptor* descP,
- int how)
+ERL_NIF_TERM esock_shutdown(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int how)
{
ERL_NIF_TERM reply;
@@ -7084,7 +7654,7 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 5) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP) ||
!GET_INT(env, argv[2], &eLevel) ||
!GET_INT(env, argv[3], &eOpt)) {
SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") );
@@ -7121,7 +7691,7 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
MLOCK(descP->cfgMtx);
- result = nsetopt(env, descP, isEncoded, isOTP, level, eOpt, eVal);
+ result = esock_setopt(env, descP, isEncoded, isOTP, level, eOpt, eVal);
MUNLOCK(descP->cfgMtx);
@@ -7138,13 +7708,13 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsetopt(ErlNifEnv* env,
- ESockDescriptor* descP,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ BOOLEAN_T isEncoded,
+ BOOLEAN_T isOTP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
@@ -7152,11 +7722,11 @@ ERL_NIF_TERM nsetopt(ErlNifEnv* env,
/* These are not actual socket options,
* but options for our implementation.
*/
- result = nsetopt_otp(env, descP, eOpt, eVal);
+ result = esock_setopt_otp(env, descP, eOpt, eVal);
} else if (!isEncoded) {
- result = nsetopt_native(env, descP, level, eOpt, eVal);
+ result = esock_setopt_native(env, descP, level, eOpt, eVal);
} else {
- result = nsetopt_level(env, descP, level, eOpt, eVal);
+ result = esock_setopt_level(env, descP, level, eOpt, eVal);
}
return result;
@@ -7164,45 +7734,45 @@ ERL_NIF_TERM nsetopt(ErlNifEnv* env,
-/* nsetopt_otp - Handle OTP (level) options
+/* esock_setopt_otp - Handle OTP (level) options
*/
static
-ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_otp -> entry with"
+ ("SOCKET", "esock_setopt_otp -> entry with"
"\r\n eOpt: %d"
"\r\n eVal: %T"
"\r\n", eOpt, eVal) );
switch (eOpt) {
- case SOCKET_OPT_OTP_DEBUG:
- result = nsetopt_otp_debug(env, descP, eVal);
+ case ESOCK_OPT_OTP_DEBUG:
+ result = esock_setopt_otp_debug(env, descP, eVal);
break;
- case SOCKET_OPT_OTP_IOW:
- result = nsetopt_otp_iow(env, descP, eVal);
+ case ESOCK_OPT_OTP_IOW:
+ result = esock_setopt_otp_iow(env, descP, eVal);
break;
- case SOCKET_OPT_OTP_CTRL_PROC:
- result = nsetopt_otp_ctrl_proc(env, descP, eVal);
+ case ESOCK_OPT_OTP_CTRL_PROC:
+ result = esock_setopt_otp_ctrl_proc(env, descP, eVal);
break;
- case SOCKET_OPT_OTP_RCVBUF:
- result = nsetopt_otp_rcvbuf(env, descP, eVal);
+ case ESOCK_OPT_OTP_RCVBUF:
+ result = esock_setopt_otp_rcvbuf(env, descP, eVal);
break;
- case SOCKET_OPT_OTP_RCVCTRLBUF:
- result = nsetopt_otp_rcvctrlbuf(env, descP, eVal);
+ case ESOCK_OPT_OTP_RCVCTRLBUF:
+ result = esock_setopt_otp_rcvctrlbuf(env, descP, eVal);
break;
- case SOCKET_OPT_OTP_SNDCTRLBUF:
- result = nsetopt_otp_sndctrlbuf(env, descP, eVal);
+ case ESOCK_OPT_OTP_SNDCTRLBUF:
+ result = esock_setopt_otp_sndctrlbuf(env, descP, eVal);
break;
default:
@@ -7214,12 +7784,12 @@ ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env,
}
-/* nsetopt_otp_debug - Handle the OTP (level) debug options
+/* esock_setopt_otp_debug - Handle the OTP (level) debug options
*/
static
-ERL_NIF_TERM nsetopt_otp_debug(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
descP->dbg = esock_decode_bool(eVal);
@@ -7227,12 +7797,12 @@ ERL_NIF_TERM nsetopt_otp_debug(ErlNifEnv* env,
}
-/* nsetopt_otp_iow - Handle the OTP (level) iow options
+/* esock_setopt_otp_iow - Handle the OTP (level) iow options
*/
static
-ERL_NIF_TERM nsetopt_otp_iow(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
descP->iow = esock_decode_bool(eVal);
@@ -7241,19 +7811,20 @@ ERL_NIF_TERM nsetopt_otp_iow(ErlNifEnv* env,
-/* nsetopt_otp_ctrl_proc - Handle the OTP (level) controlling_process options
+/* esock_setopt_otp_ctrl_proc - Handle the OTP (level)
+ * controlling_process options
*/
static
-ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ErlNifPid caller, newCtrlPid;
ESockMonitor newCtrlMon;
int xres;
SSDBG( descP,
- ("SOCKET", "nsetopt_otp_ctrl_proc -> entry with"
+ ("SOCKET", "esock_setopt_otp_ctrl_proc -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -7262,7 +7833,8 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env,
return esock_make_error(env, atom_exself);
if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) {
- SSDBG( descP, ("SOCKET", "nsetopt_otp_ctrl_proc -> not owner (%T)\r\n",
+ SSDBG( descP, ("SOCKET",
+ "esock_setopt_otp_ctrl_proc -> not owner (%T)\r\n",
descP->ctrlPid) );
return esock_make_error(env, esock_atom_not_owner);
}
@@ -7272,13 +7844,14 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
}
- if ((xres = MONP("nsetopt_otp_ctrl_proc -> (new) ctrl",
+ if ((xres = MONP("esock_setopt_otp_ctrl_proc -> (new) ctrl",
env, descP, &newCtrlPid, &newCtrlMon)) != 0) {
- esock_warning_msg("Failed monitor %d) (new) controlling process\r\n", xres);
+ esock_warning_msg("Failed monitor (%d) (new) controlling process\r\n",
+ xres);
return esock_make_error(env, esock_atom_einval);
}
- if ((xres = DEMONP("nsetopt_otp_ctrl_proc -> (old) ctrl",
+ if ((xres = DEMONP("esock_setopt_otp_ctrl_proc -> (old) ctrl",
env, descP, &descP->ctrlMon)) != 0) {
esock_warning_msg("Failed demonitor (%d) "
"old controlling process %T (%T)\r\n",
@@ -7288,14 +7861,14 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env,
descP->ctrlPid = newCtrlPid;
descP->ctrlMon = newCtrlMon;
- SSDBG( descP, ("SOCKET", "nsetopt_otp_ctrl_proc -> done\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_setopt_otp_ctrl_proc -> done\r\n") );
return esock_atom_ok;
}
-/* nsetopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
+/* esock_setopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
* The (otp) rcvbuf option is provided as:
*
* BufSz :: integer() | {N :: pos_integer(), BufSz :: pod_integer()}
@@ -7303,9 +7876,9 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env,
* Where N is the max number of reads.
*/
static
-ERL_NIF_TERM nsetopt_otp_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
const ERL_NIF_TERM* t; // The array of the elements of the tuple
int tsz; // The size of the tuple - should be 2
@@ -7322,7 +7895,7 @@ ERL_NIF_TERM nsetopt_otp_rcvbuf(ErlNifEnv* env,
if ((xres = esock_decode_bufsz(env,
eVal,
- SOCKET_RECV_BUFFER_SIZE_DEFAULT,
+ ESOCK_RECV_BUFFER_SIZE_DEFAULT,
&bufSz)) != NULL)
return esock_make_error_str(env, xres);
@@ -7339,7 +7912,7 @@ ERL_NIF_TERM nsetopt_otp_rcvbuf(ErlNifEnv* env,
if ((xres = esock_decode_bufsz(env,
t[1],
- SOCKET_RECV_BUFFER_SIZE_DEFAULT,
+ ESOCK_RECV_BUFFER_SIZE_DEFAULT,
&bufSz)) != NULL)
return esock_make_error_str(env, xres);
@@ -7355,19 +7928,19 @@ ERL_NIF_TERM nsetopt_otp_rcvbuf(ErlNifEnv* env,
-/* nsetopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
+/* esock_setopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
*/
static
-ERL_NIF_TERM nsetopt_otp_rcvctrlbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
size_t val;
char* xres;
if ((xres = esock_decode_bufsz(env,
eVal,
- SOCKET_RECV_CTRL_BUFFER_SIZE_DEFAULT,
+ ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT,
&val)) != NULL)
return esock_make_error_str(env, xres);
@@ -7378,19 +7951,19 @@ ERL_NIF_TERM nsetopt_otp_rcvctrlbuf(ErlNifEnv* env,
-/* nsetopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
+/* esock_setopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
*/
static
-ERL_NIF_TERM nsetopt_otp_sndctrlbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
size_t val;
char* xres;
if ((xres = esock_decode_bufsz(env,
eVal,
- SOCKET_SEND_CTRL_BUFFER_SIZE_DEFAULT,
+ ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT,
&val)) != NULL)
return esock_make_error_str(env, xres);
@@ -7405,17 +7978,17 @@ ERL_NIF_TERM nsetopt_otp_sndctrlbuf(ErlNifEnv* env,
* in "native mode" (option is provided as is and value as a binary).
*/
static
-ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
{
ErlNifBinary val;
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_native -> entry with"
+ ("SOCKET", "esock_setopt_native -> entry with"
"\r\n level: %d"
"\r\n opt: %d"
"\r\n eVal: %T"
@@ -7433,7 +8006,7 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "nsetopt_native -> done when"
+ ("SOCKET", "esock_setopt_native -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -7442,25 +8015,25 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
-/* nsetopt_level - A "proper" level (option) has been specified
+/* esock_setopt_level - A "proper" level (option) has been specified
*/
static
-ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_level(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_level -> entry with"
+ ("SOCKET", "esock_setopt_level -> entry with"
"\r\n level: %d"
"\r\n", level) );
switch (level) {
case SOL_SOCKET:
- result = nsetopt_lvl_socket(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_socket(env, descP, eOpt, eVal);
break;
#if defined(SOL_IP)
@@ -7468,7 +8041,7 @@ ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
#else
case IPPROTO_IP:
#endif
- result = nsetopt_lvl_ip(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_ip(env, descP, eOpt, eVal);
break;
#if defined(HAVE_IPV6)
@@ -7477,33 +8050,34 @@ ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
#else
case IPPROTO_IPV6:
#endif
- result = nsetopt_lvl_ipv6(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_ipv6(env, descP, eOpt, eVal);
break;
#endif
case IPPROTO_TCP:
- result = nsetopt_lvl_tcp(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_tcp(env, descP, eOpt, eVal);
break;
case IPPROTO_UDP:
- result = nsetopt_lvl_udp(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_udp(env, descP, eOpt, eVal);
break;
#if defined(HAVE_SCTP)
case IPPROTO_SCTP:
- result = nsetopt_lvl_sctp(env, descP, eOpt, eVal);
+ result = esock_setopt_lvl_sctp(env, descP, eOpt, eVal);
break;
#endif
default:
SSDBG( descP,
- ("SOCKET", "nsetopt_level -> unknown level (%d)\r\n", level) );
+ ("SOCKET",
+ "esock_setopt_level -> unknown level (%d)\r\n", level) );
result = esock_make_error(env, esock_atom_einval);
break;
}
SSDBG( descP,
- ("SOCKET", "nsetopt_level -> done when"
+ ("SOCKET", "esock_setopt_level -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -7512,139 +8086,140 @@ ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
-/* nsetopt_lvl_socket - Level *SOCKET* option
+/* esock_setopt_lvl_socket - Level *SOCKET* option
*/
static
-ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_socket(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_socket -> entry with"
+ ("SOCKET", "esock_setopt_lvl_socket -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(SO_BINDTODEVICE)
- case SOCKET_OPT_SOCK_BINDTODEVICE:
- result = nsetopt_lvl_sock_bindtodevice(env, descP, eVal);
+ case ESOCK_OPT_SOCK_BINDTODEVICE:
+ result = esock_setopt_lvl_sock_bindtodevice(env, descP, eVal);
break;
#endif
#if defined(SO_BROADCAST)
- case SOCKET_OPT_SOCK_BROADCAST:
- result = nsetopt_lvl_sock_broadcast(env, descP, eVal);
+ case ESOCK_OPT_SOCK_BROADCAST:
+ result = esock_setopt_lvl_sock_broadcast(env, descP, eVal);
break;
#endif
#if defined(SO_DEBUG)
- case SOCKET_OPT_SOCK_DEBUG:
- result = nsetopt_lvl_sock_debug(env, descP, eVal);
+ case ESOCK_OPT_SOCK_DEBUG:
+ result = esock_setopt_lvl_sock_debug(env, descP, eVal);
break;
#endif
#if defined(SO_DONTROUTE)
- case SOCKET_OPT_SOCK_DONTROUTE:
- result = nsetopt_lvl_sock_dontroute(env, descP, eVal);
+ case ESOCK_OPT_SOCK_DONTROUTE:
+ result = esock_setopt_lvl_sock_dontroute(env, descP, eVal);
break;
#endif
#if defined(SO_KEEPALIVE)
- case SOCKET_OPT_SOCK_KEEPALIVE:
- result = nsetopt_lvl_sock_keepalive(env, descP, eVal);
+ case ESOCK_OPT_SOCK_KEEPALIVE:
+ result = esock_setopt_lvl_sock_keepalive(env, descP, eVal);
break;
#endif
#if defined(SO_LINGER)
- case SOCKET_OPT_SOCK_LINGER:
- result = nsetopt_lvl_sock_linger(env, descP, eVal);
+ case ESOCK_OPT_SOCK_LINGER:
+ result = esock_setopt_lvl_sock_linger(env, descP, eVal);
break;
#endif
#if defined(SO_PEEK_OFF)
- case SOCKET_OPT_SOCK_PEEK_OFF:
- result = nsetopt_lvl_sock_peek_off(env, descP, eVal);
+ case ESOCK_OPT_SOCK_PEEK_OFF:
+ result = esock_setopt_lvl_sock_peek_off(env, descP, eVal);
break;
#endif
#if defined(SO_OOBINLINE)
- case SOCKET_OPT_SOCK_OOBINLINE:
- result = nsetopt_lvl_sock_oobinline(env, descP, eVal);
+ case ESOCK_OPT_SOCK_OOBINLINE:
+ result = esock_setopt_lvl_sock_oobinline(env, descP, eVal);
break;
#endif
#if defined(SO_PRIORITY)
- case SOCKET_OPT_SOCK_PRIORITY:
- result = nsetopt_lvl_sock_priority(env, descP, eVal);
+ case ESOCK_OPT_SOCK_PRIORITY:
+ result = esock_setopt_lvl_sock_priority(env, descP, eVal);
break;
#endif
#if defined(SO_RCVBUF)
- case SOCKET_OPT_SOCK_RCVBUF:
- result = nsetopt_lvl_sock_rcvbuf(env, descP, eVal);
+ case ESOCK_OPT_SOCK_RCVBUF:
+ result = esock_setopt_lvl_sock_rcvbuf(env, descP, eVal);
break;
#endif
#if defined(SO_RCVLOWAT)
- case SOCKET_OPT_SOCK_RCVLOWAT:
- result = nsetopt_lvl_sock_rcvlowat(env, descP, eVal);
+ case ESOCK_OPT_SOCK_RCVLOWAT:
+ result = esock_setopt_lvl_sock_rcvlowat(env, descP, eVal);
break;
#endif
#if defined(SO_RCVTIMEO)
- case SOCKET_OPT_SOCK_RCVTIMEO:
- result = nsetopt_lvl_sock_rcvtimeo(env, descP, eVal);
+ case ESOCK_OPT_SOCK_RCVTIMEO:
+ result = esock_setopt_lvl_sock_rcvtimeo(env, descP, eVal);
break;
#endif
#if defined(SO_REUSEADDR)
- case SOCKET_OPT_SOCK_REUSEADDR:
- result = nsetopt_lvl_sock_reuseaddr(env, descP, eVal);
+ case ESOCK_OPT_SOCK_REUSEADDR:
+ result = esock_setopt_lvl_sock_reuseaddr(env, descP, eVal);
break;
#endif
#if defined(SO_REUSEPORT)
- case SOCKET_OPT_SOCK_REUSEPORT:
- result = nsetopt_lvl_sock_reuseport(env, descP, eVal);
+ case ESOCK_OPT_SOCK_REUSEPORT:
+ result = esock_setopt_lvl_sock_reuseport(env, descP, eVal);
break;
#endif
#if defined(SO_SNDBUF)
- case SOCKET_OPT_SOCK_SNDBUF:
- result = nsetopt_lvl_sock_sndbuf(env, descP, eVal);
+ case ESOCK_OPT_SOCK_SNDBUF:
+ result = esock_setopt_lvl_sock_sndbuf(env, descP, eVal);
break;
#endif
#if defined(SO_SNDLOWAT)
- case SOCKET_OPT_SOCK_SNDLOWAT:
- result = nsetopt_lvl_sock_sndlowat(env, descP, eVal);
+ case ESOCK_OPT_SOCK_SNDLOWAT:
+ result = esock_setopt_lvl_sock_sndlowat(env, descP, eVal);
break;
#endif
#if defined(SO_SNDTIMEO)
- case SOCKET_OPT_SOCK_SNDTIMEO:
- result = nsetopt_lvl_sock_sndtimeo(env, descP, eVal);
+ case ESOCK_OPT_SOCK_SNDTIMEO:
+ result = esock_setopt_lvl_sock_sndtimeo(env, descP, eVal);
break;
#endif
#if defined(SO_TIMESTAMP)
- case SOCKET_OPT_SOCK_TIMESTAMP:
- result = nsetopt_lvl_sock_timestamp(env, descP, eVal);
+ case ESOCK_OPT_SOCK_TIMESTAMP:
+ result = esock_setopt_lvl_sock_timestamp(env, descP, eVal);
break;
#endif
default:
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_socket -> unknown opt (%d)\r\n", eOpt) );
+ ("SOCKET",
+ "esock_setopt_lvl_socket -> unknown opt (%d)\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_socket -> done when"
+ ("SOCKET", "esock_setopt_lvl_socket -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -7654,66 +8229,66 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
#if defined(SO_BINDTODEVICE)
static
-ERL_NIF_TERM nsetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_str_opt(env, descP,
- SOL_SOCKET, SO_BROADCAST,
- IFNAMSIZ, eVal);
+ return esock_setopt_str_opt(env, descP,
+ SOL_SOCKET, SO_BINDTODEVICE,
+ IFNAMSIZ, eVal);
}
#endif
#if defined(SO_BROADCAST)
static
-ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_broadcast(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_BROADCAST, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_BROADCAST, eVal);
}
#endif
#if defined(SO_DEBUG)
static
-ERL_NIF_TERM nsetopt_lvl_sock_debug(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_debug(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_DEBUG, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_DEBUG, eVal);
}
#endif
#if defined(SO_DONTROUTE)
static
-ERL_NIF_TERM nsetopt_lvl_sock_dontroute(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_dontroute(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_DONTROUTE, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_DONTROUTE, eVal);
}
#endif
#if defined(SO_KEEPALIVE)
static
-ERL_NIF_TERM nsetopt_lvl_sock_keepalive(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_keepalive(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_KEEPALIVE, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_KEEPALIVE, eVal);
}
#endif
#if defined(SO_LINGER)
static
-ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_linger(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
struct linger val;
@@ -7737,346 +8312,347 @@ ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
#if defined(SO_OOBINLINE)
static
-ERL_NIF_TERM nsetopt_lvl_sock_oobinline(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_oobinline(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_OOBINLINE, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_OOBINLINE, eVal);
}
#endif
#if defined(SO_PEEK_OFF)
static
-ERL_NIF_TERM nsetopt_lvl_sock_peek_off(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_peek_off(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_PEEK_OFF, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_PEEK_OFF, eVal);
}
#endif
#if defined(SO_PRIORITY)
static
-ERL_NIF_TERM nsetopt_lvl_sock_priority(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_priority(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_PRIORITY, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_PRIORITY, eVal);
}
#endif
#if defined(SO_RCVBUF)
static
-ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_RCVBUF, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_RCVBUF, eVal);
}
#endif
#if defined(SO_RCVLOWAT)
static
-ERL_NIF_TERM nsetopt_lvl_sock_rcvlowat(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_rcvlowat(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_RCVLOWAT, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_RCVLOWAT, eVal);
}
#endif
#if defined(SO_RCVTIMEO)
static
-ERL_NIF_TERM nsetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO, eVal);
+ return esock_setopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO, eVal);
}
#endif
#if defined(SO_REUSEADDR)
static
-ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEADDR, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEADDR, eVal);
}
#endif
#if defined(SO_REUSEPORT)
static
-ERL_NIF_TERM nsetopt_lvl_sock_reuseport(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_reuseport(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEPORT, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEPORT, eVal);
}
#endif
#if defined(SO_SNDBUF)
static
-ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_SNDBUF, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_SNDBUF, eVal);
}
#endif
#if defined(SO_SNDLOWAT)
static
-ERL_NIF_TERM nsetopt_lvl_sock_sndlowat(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_sndlowat(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, SOL_SOCKET, SO_SNDLOWAT, eVal);
+ return esock_setopt_int_opt(env, descP, SOL_SOCKET, SO_SNDLOWAT, eVal);
}
#endif
#if defined(SO_SNDTIMEO)
static
-ERL_NIF_TERM nsetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sock_sndtimeo -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sock_sndtimeo -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
- return nsetopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO, eVal);
+ return esock_setopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO, eVal);
}
#endif
#if defined(SO_TIMESTAMP)
static
-ERL_NIF_TERM nsetopt_lvl_sock_timestamp(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sock_timestamp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_SOCKET, SO_TIMESTAMP, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_SOCKET, SO_TIMESTAMP, eVal);
}
#endif
-/* nsetopt_lvl_ip - Level *IP* option(s)
+/* esock_setopt_lvl_ip - Level *IP* option(s)
*/
static
-ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ip -> entry with"
+ ("SOCKET", "esock_setopt_lvl_ip -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(IP_ADD_MEMBERSHIP)
- case SOCKET_OPT_IP_ADD_MEMBERSHIP:
- result = nsetopt_lvl_ip_add_membership(env, descP, eVal);
+ case ESOCK_OPT_IP_ADD_MEMBERSHIP:
+ result = esock_setopt_lvl_ip_add_membership(env, descP, eVal);
break;
#endif
#if defined(IP_ADD_SOURCE_MEMBERSHIP)
- case SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP:
- result = nsetopt_lvl_ip_add_source_membership(env, descP, eVal);
+ case ESOCK_OPT_IP_ADD_SOURCE_MEMBERSHIP:
+ result = esock_setopt_lvl_ip_add_source_membership(env, descP, eVal);
break;
#endif
#if defined(IP_BLOCK_SOURCE)
- case SOCKET_OPT_IP_BLOCK_SOURCE:
- result = nsetopt_lvl_ip_block_source(env, descP, eVal);
+ case ESOCK_OPT_IP_BLOCK_SOURCE:
+ result = esock_setopt_lvl_ip_block_source(env, descP, eVal);
break;
#endif
#if defined(IP_DROP_MEMBERSHIP)
- case SOCKET_OPT_IP_DROP_MEMBERSHIP:
- result = nsetopt_lvl_ip_drop_membership(env, descP, eVal);
+ case ESOCK_OPT_IP_DROP_MEMBERSHIP:
+ result = esock_setopt_lvl_ip_drop_membership(env, descP, eVal);
break;
#endif
#if defined(IP_DROP_SOURCE_MEMBERSHIP)
- case SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP:
- result = nsetopt_lvl_ip_drop_source_membership(env, descP, eVal);
+ case ESOCK_OPT_IP_DROP_SOURCE_MEMBERSHIP:
+ result = esock_setopt_lvl_ip_drop_source_membership(env, descP, eVal);
break;
#endif
#if defined(IP_FREEBIND)
- case SOCKET_OPT_IP_FREEBIND:
- result = nsetopt_lvl_ip_freebind(env, descP, eVal);
+ case ESOCK_OPT_IP_FREEBIND:
+ result = esock_setopt_lvl_ip_freebind(env, descP, eVal);
break;
#endif
#if defined(IP_HDRINCL)
- case SOCKET_OPT_IP_HDRINCL:
- result = nsetopt_lvl_ip_hdrincl(env, descP, eVal);
+ case ESOCK_OPT_IP_HDRINCL:
+ result = esock_setopt_lvl_ip_hdrincl(env, descP, eVal);
break;
#endif
#if defined(IP_MINTTL)
- case SOCKET_OPT_IP_MINTTL:
- result = nsetopt_lvl_ip_minttl(env, descP, eVal);
+ case ESOCK_OPT_IP_MINTTL:
+ result = esock_setopt_lvl_ip_minttl(env, descP, eVal);
break;
#endif
#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
- case SOCKET_OPT_IP_MSFILTER:
- result = nsetopt_lvl_ip_msfilter(env, descP, eVal);
+ case ESOCK_OPT_IP_MSFILTER:
+ result = esock_setopt_lvl_ip_msfilter(env, descP, eVal);
break;
#endif
#if defined(IP_MTU_DISCOVER)
- case SOCKET_OPT_IP_MTU_DISCOVER:
- result = nsetopt_lvl_ip_mtu_discover(env, descP, eVal);
+ case ESOCK_OPT_IP_MTU_DISCOVER:
+ result = esock_setopt_lvl_ip_mtu_discover(env, descP, eVal);
break;
#endif
#if defined(IP_MULTICAST_ALL)
- case SOCKET_OPT_IP_MULTICAST_ALL:
- result = nsetopt_lvl_ip_multicast_all(env, descP, eVal);
+ case ESOCK_OPT_IP_MULTICAST_ALL:
+ result = esock_setopt_lvl_ip_multicast_all(env, descP, eVal);
break;
#endif
#if defined(IP_MULTICAST_IF)
- case SOCKET_OPT_IP_MULTICAST_IF:
- result = nsetopt_lvl_ip_multicast_if(env, descP, eVal);
+ case ESOCK_OPT_IP_MULTICAST_IF:
+ result = esock_setopt_lvl_ip_multicast_if(env, descP, eVal);
break;
#endif
#if defined(IP_MULTICAST_LOOP)
- case SOCKET_OPT_IP_MULTICAST_LOOP:
- result = nsetopt_lvl_ip_multicast_loop(env, descP, eVal);
+ case ESOCK_OPT_IP_MULTICAST_LOOP:
+ result = esock_setopt_lvl_ip_multicast_loop(env, descP, eVal);
break;
#endif
#if defined(IP_MULTICAST_TTL)
- case SOCKET_OPT_IP_MULTICAST_TTL:
- result = nsetopt_lvl_ip_multicast_ttl(env, descP, eVal);
+ case ESOCK_OPT_IP_MULTICAST_TTL:
+ result = esock_setopt_lvl_ip_multicast_ttl(env, descP, eVal);
break;
#endif
#if defined(IP_NODEFRAG)
- case SOCKET_OPT_IP_NODEFRAG:
- result = nsetopt_lvl_ip_nodefrag(env, descP, eVal);
+ case ESOCK_OPT_IP_NODEFRAG:
+ result = esock_setopt_lvl_ip_nodefrag(env, descP, eVal);
break;
#endif
#if defined(IP_PKTINFO)
- case SOCKET_OPT_IP_PKTINFO:
- result = nsetopt_lvl_ip_pktinfo(env, descP, eVal);
+ case ESOCK_OPT_IP_PKTINFO:
+ result = esock_setopt_lvl_ip_pktinfo(env, descP, eVal);
break;
#endif
#if defined(IP_RECVDSTADDR)
- case SOCKET_OPT_IP_RECVDSTADDR:
- result = nsetopt_lvl_ip_recvdstaddr(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVDSTADDR:
+ result = esock_setopt_lvl_ip_recvdstaddr(env, descP, eVal);
break;
#endif
#if defined(IP_RECVERR)
- case SOCKET_OPT_IP_RECVERR:
- result = nsetopt_lvl_ip_recverr(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVERR:
+ result = esock_setopt_lvl_ip_recverr(env, descP, eVal);
break;
#endif
#if defined(IP_RECVIF)
- case SOCKET_OPT_IP_RECVIF:
- result = nsetopt_lvl_ip_recvif(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVIF:
+ result = esock_setopt_lvl_ip_recvif(env, descP, eVal);
break;
#endif
#if defined(IP_RECVOPTS)
- case SOCKET_OPT_IP_RECVOPTS:
- result = nsetopt_lvl_ip_recvopts(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVOPTS:
+ result = esock_setopt_lvl_ip_recvopts(env, descP, eVal);
break;
#endif
#if defined(IP_RECVORIGDSTADDR)
- case SOCKET_OPT_IP_RECVORIGDSTADDR:
- result = nsetopt_lvl_ip_recvorigdstaddr(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVORIGDSTADDR:
+ result = esock_setopt_lvl_ip_recvorigdstaddr(env, descP, eVal);
break;
#endif
#if defined(IP_RECVTOS)
- case SOCKET_OPT_IP_RECVTOS:
- result = nsetopt_lvl_ip_recvtos(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVTOS:
+ result = esock_setopt_lvl_ip_recvtos(env, descP, eVal);
break;
#endif
#if defined(IP_RECVTTL)
- case SOCKET_OPT_IP_RECVTTL:
- result = nsetopt_lvl_ip_recvttl(env, descP, eVal);
+ case ESOCK_OPT_IP_RECVTTL:
+ result = esock_setopt_lvl_ip_recvttl(env, descP, eVal);
break;
#endif
#if defined(IP_RETOPTS)
- case SOCKET_OPT_IP_RETOPTS:
- result = nsetopt_lvl_ip_retopts(env, descP, eVal);
+ case ESOCK_OPT_IP_RETOPTS:
+ result = esock_setopt_lvl_ip_retopts(env, descP, eVal);
break;
#endif
#if defined(IP_ROUTER_ALERT)
- case SOCKET_OPT_IP_ROUTER_ALERT:
- result = nsetopt_lvl_ip_router_alert(env, descP, eVal);
+ case ESOCK_OPT_IP_ROUTER_ALERT:
+ result = esock_setopt_lvl_ip_router_alert(env, descP, eVal);
break;
#endif
#if defined(IP_SENDSRCADDR)
- case SOCKET_OPT_IP_SENDSRCADDR:
- result = nsetopt_lvl_ip_sendsrcaddr(env, descP, eVal);
+ case ESOCK_OPT_IP_SENDSRCADDR:
+ result = esock_setopt_lvl_ip_sendsrcaddr(env, descP, eVal);
break;
#endif
#if defined(IP_TOS)
- case SOCKET_OPT_IP_TOS:
- result = nsetopt_lvl_ip_tos(env, descP, eVal);
+ case ESOCK_OPT_IP_TOS:
+ result = esock_setopt_lvl_ip_tos(env, descP, eVal);
break;
#endif
#if defined(IP_TRANSPARENT)
- case SOCKET_OPT_IP_TRANSPARENT:
- result = nsetopt_lvl_ip_transparent(env, descP, eVal);
+ case ESOCK_OPT_IP_TRANSPARENT:
+ result = esock_setopt_lvl_ip_transparent(env, descP, eVal);
break;
#endif
#if defined(IP_TTL)
- case SOCKET_OPT_IP_TTL:
- result = nsetopt_lvl_ip_ttl(env, descP, eVal);
+ case ESOCK_OPT_IP_TTL:
+ result = esock_setopt_lvl_ip_ttl(env, descP, eVal);
break;
#endif
#if defined(IP_UNBLOCK_SOURCE)
- case SOCKET_OPT_IP_UNBLOCK_SOURCE:
- result = nsetopt_lvl_ip_unblock_source(env, descP, eVal);
+ case ESOCK_OPT_IP_UNBLOCK_SOURCE:
+ result = esock_setopt_lvl_ip_unblock_source(env, descP, eVal);
break;
#endif
default:
- SSDBG( descP, ("SOCKET", "nsetopt_lvl_ip -> unknown opt (%d)\r\n", eOpt) );
+ SSDBG( descP, ("SOCKET",
+ "esock_setopt_lvl_ip -> unknown opt (%d)\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ip -> done when"
+ ("SOCKET", "esock_setopt_lvl_ip -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -8084,7 +8660,7 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
}
-/* nsetopt_lvl_ip_add_membership - Level IP ADD_MEMBERSHIP option
+/* esock_setopt_lvl_ip_add_membership - Level IP ADD_MEMBERSHIP option
*
* The value is a map with two attributes: multiaddr and interface.
* The attribute 'multiaddr' is always a 4-tuple (IPv4 address).
@@ -8093,16 +8669,18 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
*/
#if defined(IP_ADD_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_add_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_add_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_membership(env, descP, eVal, IP_ADD_MEMBERSHIP);
+ return esock_setopt_lvl_ip_update_membership(env, descP, eVal,
+ IP_ADD_MEMBERSHIP);
}
#endif
-/* nsetopt_lvl_ip_add_source_membership - Level IP ADD_SOURCE_MEMBERSHIP option
+/* esock_setopt_lvl_ip_add_source_membership -
+ * Level IP ADD_SOURCE_MEMBERSHIP option
*
* The value is a map with three attributes: multiaddr, interface and
* sourceaddr.
@@ -8113,17 +8691,17 @@ ERL_NIF_TERM nsetopt_lvl_ip_add_membership(ErlNifEnv* env,
*/
#if defined(IP_ADD_SOURCE_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_add_source_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_add_source_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_source(env, descP, eVal,
- IP_ADD_SOURCE_MEMBERSHIP);
+ return esock_setopt_lvl_ip_update_source(env, descP, eVal,
+ IP_ADD_SOURCE_MEMBERSHIP);
}
#endif
-/* nsetopt_lvl_ip_block_source - Level IP BLOCK_SOURCE option
+/* esock_setopt_lvl_ip_block_source - Level IP BLOCK_SOURCE option
*
* The value is a map with three attributes: multiaddr, interface and
* sourceaddr.
@@ -8134,16 +8712,16 @@ ERL_NIF_TERM nsetopt_lvl_ip_add_source_membership(ErlNifEnv* env,
*/
#if defined(IP_BLOCK_SOURCE)
static
-ERL_NIF_TERM nsetopt_lvl_ip_block_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_block_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_source(env, descP, eVal, IP_BLOCK_SOURCE);
+ return esock_setopt_lvl_ip_update_source(env, descP, eVal, IP_BLOCK_SOURCE);
}
#endif
-/* nsetopt_lvl_ip_drop_membership - Level IP DROP_MEMBERSHIP option
+/* esock_setopt_lvl_ip_drop_membership - Level IP DROP_MEMBERSHIP option
*
* The value is a map with two attributes: multiaddr and interface.
* The attribute 'multiaddr' is always a 4-tuple (IPv4 address).
@@ -8156,18 +8734,19 @@ ERL_NIF_TERM nsetopt_lvl_ip_block_source(ErlNifEnv* env,
*/
#if defined(IP_DROP_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_drop_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_drop_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_membership(env, descP, eVal,
- IP_DROP_MEMBERSHIP);
+ return esock_setopt_lvl_ip_update_membership(env, descP, eVal,
+ IP_DROP_MEMBERSHIP);
}
#endif
-/* nsetopt_lvl_ip_drop_source_membership - Level IP DROP_SOURCE_MEMBERSHIP option
+/* esock_setopt_lvl_ip_drop_source_membership -
+ * Level IP DROP_SOURCE_MEMBERSHIP option
*
* The value is a map with three attributes: multiaddr, interface and
* sourceaddr.
@@ -8178,24 +8757,24 @@ ERL_NIF_TERM nsetopt_lvl_ip_drop_membership(ErlNifEnv* env,
*/
#if defined(IP_DROP_SOURCE_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_drop_source_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_drop_source_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_source(env, descP, eVal,
- IP_DROP_SOURCE_MEMBERSHIP);
+ return esock_setopt_lvl_ip_update_source(env, descP, eVal,
+ IP_DROP_SOURCE_MEMBERSHIP);
}
#endif
-/* nsetopt_lvl_ip_freebind - Level IP FREEBIND option
+/* esock_setopt_lvl_ip_freebind - Level IP FREEBIND option
*/
#if defined(IP_FREEBIND)
static
-ERL_NIF_TERM nsetopt_lvl_ip_freebind(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_freebind(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8203,19 +8782,19 @@ ERL_NIF_TERM nsetopt_lvl_ip_freebind(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_FREEBIND, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_FREEBIND, eVal);
}
#endif
-/* nsetopt_lvl_ip_hdrincl - Level IP HDRINCL option
+/* esock_setopt_lvl_ip_hdrincl - Level IP HDRINCL option
*/
#if defined(IP_HDRINCL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_hdrincl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_hdrincl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8223,19 +8802,19 @@ ERL_NIF_TERM nsetopt_lvl_ip_hdrincl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_HDRINCL, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_HDRINCL, eVal);
}
#endif
-/* nsetopt_lvl_ip_minttl - Level IP MINTTL option
+/* esock_setopt_lvl_ip_minttl - Level IP MINTTL option
*/
#if defined(IP_MINTTL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_minttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_minttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8243,26 +8822,26 @@ ERL_NIF_TERM nsetopt_lvl_ip_minttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_int_opt(env, descP, level, IP_MINTTL, eVal);
+ return esock_setopt_int_opt(env, descP, level, IP_MINTTL, eVal);
}
#endif
-/* nsetopt_lvl_ip_msfilter - Level IP MSFILTER option
+/* esock_setopt_lvl_ip_msfilter - Level IP MSFILTER option
*
* The value can be *either* the atom 'null' or a map of type ip_msfilter().
*/
#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE)
static
-ERL_NIF_TERM nsetopt_lvl_ip_msfilter(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_msfilter(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
if (COMPARE(eVal, atom_null) == 0) {
- return nsetopt_lvl_ip_msfilter_set(env, descP->sock, NULL, 0);
+ return esock_setopt_lvl_ip_msfilter_set(env, descP->sock, NULL, 0);
} else {
struct ip_msfilter* msfP;
Uint32 msfSz;
@@ -8327,7 +8906,8 @@ ERL_NIF_TERM nsetopt_lvl_ip_msfilter(ErlNifEnv* env,
}
/* And now, finally, set the option */
- result = nsetopt_lvl_ip_msfilter_set(env, descP->sock, msfP, msfSz);
+ result = esock_setopt_lvl_ip_msfilter_set(env, descP->sock,
+ msfP, msfSz);
FREE(msfP);
return result;
}
@@ -8357,10 +8937,10 @@ BOOLEAN_T decode_ip_msfilter_mode(ErlNifEnv* env,
static
-ERL_NIF_TERM nsetopt_lvl_ip_msfilter_set(ErlNifEnv* env,
- SOCKET sock,
- struct ip_msfilter* msfP,
- SOCKLEN_T optLen)
+ERL_NIF_TERM esock_setopt_lvl_ip_msfilter_set(ErlNifEnv* env,
+ SOCKET sock,
+ struct ip_msfilter* msfP,
+ SOCKLEN_T optLen)
{
ERL_NIF_TERM result;
int res;
@@ -8382,15 +8962,15 @@ ERL_NIF_TERM nsetopt_lvl_ip_msfilter_set(ErlNifEnv* env,
-/* nsetopt_lvl_ip_mtu_discover - Level IP MTU_DISCOVER option
+/* esock_setopt_lvl_ip_mtu_discover - Level IP MTU_DISCOVER option
*
* The value is an atom of the type ip_pmtudisc().
*/
#if defined(IP_MTU_DISCOVER)
static
-ERL_NIF_TERM nsetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
int val;
@@ -8423,13 +9003,13 @@ ERL_NIF_TERM nsetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_ip_multicast_all - Level IP MULTICAST_ALL option
+/* esock_setopt_lvl_ip_multicast_all - Level IP MULTICAST_ALL option
*/
#if defined(IP_MULTICAST_ALL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_multicast_all(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_multicast_all(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8437,20 +9017,20 @@ ERL_NIF_TERM nsetopt_lvl_ip_multicast_all(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_MULTICAST_ALL, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_MULTICAST_ALL, eVal);
}
#endif
-/* nsetopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
+/* esock_setopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
*
* The value is either the atom 'any' or a 4-tuple.
*/
#if defined(IP_MULTICAST_IF)
static
-ERL_NIF_TERM nsetopt_lvl_ip_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
struct in_addr ifAddr;
@@ -8481,13 +9061,13 @@ ERL_NIF_TERM nsetopt_lvl_ip_multicast_if(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
+/* esock_setopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
*/
#if defined(IP_MULTICAST_LOOP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8495,18 +9075,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_MULTICAST_LOOP, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_MULTICAST_LOOP, eVal);
}
#endif
-/* nsetopt_lvl_ip_multicast_ttl - Level IP MULTICAST_TTL option
+/* esock_setopt_lvl_ip_multicast_ttl - Level IP MULTICAST_TTL option
*/
#if defined(IP_MULTICAST_TTL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8514,18 +9094,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_int_opt(env, descP, level, IP_MULTICAST_TTL, eVal);
+ return esock_setopt_int_opt(env, descP, level, IP_MULTICAST_TTL, eVal);
}
#endif
-/* nsetopt_lvl_ip_nodefrag - Level IP NODEFRAG option
+/* esock_setopt_lvl_ip_nodefrag - Level IP NODEFRAG option
*/
#if defined(IP_NODEFRAG)
static
-ERL_NIF_TERM nsetopt_lvl_ip_nodefrag(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_nodefrag(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8533,18 +9113,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_nodefrag(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_NODEFRAG, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_NODEFRAG, eVal);
}
#endif
-/* nsetopt_lvl_ip_pktinfo - Level IP PKTINFO option
+/* esock_setopt_lvl_ip_pktinfo - Level IP PKTINFO option
*/
#if defined(IP_PKTINFO)
static
-ERL_NIF_TERM nsetopt_lvl_ip_pktinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_pktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8552,18 +9132,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_pktinfo(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_PKTINFO, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_PKTINFO, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvdstaddr - Level IP RECVDSTADDR option
+/* esock_setopt_lvl_ip_recvdstaddr - Level IP RECVDSTADDR option
*/
#if defined(IP_RECVDSTADDR)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8571,18 +9151,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVDSTADDR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVDSTADDR, eVal);
}
#endif
-/* nsetopt_lvl_ip_recverr - Level IP RECVERR option
+/* esock_setopt_lvl_ip_recverr - Level IP RECVERR option
*/
#if defined(IP_RECVERR)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recverr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8590,18 +9170,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recverr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVERR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVERR, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvif - Level IP RECVIF option
+/* esock_setopt_lvl_ip_recvif - Level IP RECVIF option
*/
#if defined(IP_RECVIF)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvif(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvif(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8609,18 +9189,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvif(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVIF, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVIF, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvopts - Level IP RECVOPTS option
+/* esock_setopt_lvl_ip_recvopts - Level IP RECVOPTS option
*/
#if defined(IP_RECVOPTS)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8628,18 +9208,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvopts(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVOPTS, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVOPTS, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvorigdstaddr - Level IP RECVORIGDSTADDR option
+/* esock_setopt_lvl_ip_recvorigdstaddr - Level IP RECVORIGDSTADDR option
*/
#if defined(IP_RECVORIGDSTADDR)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8647,18 +9227,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVORIGDSTADDR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVORIGDSTADDR, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvtos - Level IP RECVTOS option
+/* esock_setopt_lvl_ip_recvtos - Level IP RECVTOS option
*/
#if defined(IP_RECVTOS)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvtos(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8666,18 +9246,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVTOS, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVTOS, eVal);
}
#endif
-/* nsetopt_lvl_ip_recvttl - Level IP RECVTTL option
+/* esock_setopt_lvl_ip_recvttl - Level IP RECVTTL option
*/
#if defined(IP_RECVTTL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_recvttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_recvttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8685,18 +9265,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_recvttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RECVTTL, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RECVTTL, eVal);
}
#endif
-/* nsetopt_lvl_ip_retopts - Level IP RETOPTS option
+/* esock_setopt_lvl_ip_retopts - Level IP RETOPTS option
*/
#if defined(IP_RETOPTS)
static
-ERL_NIF_TERM nsetopt_lvl_ip_retopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_retopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8704,18 +9284,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_retopts(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_RETOPTS, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_RETOPTS, eVal);
}
#endif
-/* nsetopt_lvl_ip_router_alert - Level IP ROUTER_ALERT option
+/* esock_setopt_lvl_ip_router_alert - Level IP ROUTER_ALERT option
*/
#if defined(IP_ROUTER_ALERT)
static
-ERL_NIF_TERM nsetopt_lvl_ip_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8723,18 +9303,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_router_alert(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_int_opt(env, descP, level, IP_ROUTER_ALERT, eVal);
+ return esock_setopt_int_opt(env, descP, level, IP_ROUTER_ALERT, eVal);
}
#endif
-/* nsetopt_lvl_ip_sendsrcaddr - Level IP SENDSRCADDR option
+/* esock_setopt_lvl_ip_sendsrcaddr - Level IP SENDSRCADDR option
*/
#if defined(IP_SENDSRCADDR)
static
-ERL_NIF_TERM nsetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8742,18 +9322,18 @@ ERL_NIF_TERM nsetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_SENDSRCADDR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_SENDSRCADDR, eVal);
}
#endif
-/* nsetopt_lvl_ip_tos - Level IP TOS option
+/* esock_setopt_lvl_ip_tos - Level IP TOS option
*/
#if defined(IP_TOS)
static
-ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_tos(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8780,13 +9360,13 @@ ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_ip_transparent - Level IP TRANSPARENT option
+/* esock_setopt_lvl_ip_transparent - Level IP TRANSPARENT option
*/
#if defined(IP_TRANSPARENT)
static
-ERL_NIF_TERM nsetopt_lvl_ip_transparent(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_transparent(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8794,19 +9374,19 @@ ERL_NIF_TERM nsetopt_lvl_ip_transparent(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_bool_opt(env, descP, level, IP_TRANSPARENT, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IP_TRANSPARENT, eVal);
}
#endif
-/* nsetopt_lvl_ip_ttl - Level IP TTL option
+/* esock_setopt_lvl_ip_ttl - Level IP TTL option
*/
#if defined(IP_TTL)
static
-ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -8814,13 +9394,13 @@ ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return nsetopt_int_opt(env, descP, level, IP_TTL, eVal);
+ return esock_setopt_int_opt(env, descP, level, IP_TTL, eVal);
}
#endif
-/* nsetopt_lvl_ip_unblock_source - Level IP UNBLOCK_SOURCE option
+/* esock_setopt_lvl_ip_unblock_source - Level IP UNBLOCK_SOURCE option
*
* The value is a map with three attributes: multiaddr, interface and
* sourceaddr.
@@ -8831,11 +9411,12 @@ ERL_NIF_TERM nsetopt_lvl_ip_ttl(ErlNifEnv* env,
*/
#if defined(IP_UNBLOCK_SOURCE)
static
-ERL_NIF_TERM nsetopt_lvl_ip_unblock_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ip_unblock_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ip_update_source(env, descP, eVal, IP_UNBLOCK_SOURCE);
+ return esock_setopt_lvl_ip_update_source(env, descP, eVal,
+ IP_UNBLOCK_SOURCE);
}
#endif
@@ -8843,10 +9424,10 @@ ERL_NIF_TERM nsetopt_lvl_ip_unblock_source(ErlNifEnv* env,
#if defined(IP_ADD_MEMBERSHIP) || defined(IP_DROP_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ip_update_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt)
+ERL_NIF_TERM esock_setopt_lvl_ip_update_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt)
{
ERL_NIF_TERM result, eMultiAddr, eInterface;
struct ip_mreq mreq;
@@ -8860,35 +9441,67 @@ ERL_NIF_TERM nsetopt_lvl_ip_update_membership(ErlNifEnv* env,
#endif
// It must be a map
- if (!IS_MAP(env, eVal))
+ if (!IS_MAP(env, eVal)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "value *not* a map\r\n") );
return enif_make_badarg(env);
+ }
// It must have atleast two attributes
- if (!enif_get_map_size(env, eVal, &sz) || (sz >= 2))
+ if (!enif_get_map_size(env, eVal, &sz) || (sz < 2)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "invalid map value: %T\r\n", eVal) );
return enif_make_badarg(env);
+ }
- if (!GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr))
+ if (!GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed get multiaddr (map) attribute\r\n") );
return enif_make_badarg(env);
+ }
- if (!GET_MAP_VAL(env, eVal, atom_interface, &eInterface))
+ if (!GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed get interface (map) attribute\r\n") );
return enif_make_badarg(env);
+ }
if ((xres = esock_decode_ip4_address(env,
eMultiAddr,
- &mreq.imr_multiaddr)) != NULL)
+ &mreq.imr_multiaddr)) != NULL) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed decode multiaddr %T: %s\r\n", eMultiAddr, xres) );
return esock_make_error_str(env, xres);
+ }
if ((xres = esock_decode_ip4_address(env,
eInterface,
- &mreq.imr_interface)) != NULL)
+ &mreq.imr_interface)) != NULL) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed decode interface %T: %s\r\n", eInterface, xres) );
return esock_make_error_str(env, xres);
+ }
res = socket_setopt(descP->sock, level, opt, &mreq, sizeof(mreq));
- if (res != 0)
- result = esock_make_error_errno(env, sock_errno());
- else
+ if (res != 0) {
+ int save_errno = sock_errno();
+
+ result = esock_make_error_errno(env, save_errno);
+
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed setopt: %T (%d)\r\n", result, save_errno) );
+
+ } else {
result = esock_atom_ok;
+ }
return result;
}
@@ -8897,10 +9510,10 @@ ERL_NIF_TERM nsetopt_lvl_ip_update_membership(ErlNifEnv* env,
#if defined(IP_ADD_SOURCE_MEMBERSHIP) || defined(IP_DROP_SOURCE_MEMBERSHIP) || defined(IP_BLOCK_SOURCE) || defined(IP_UNBLOCK_SOURCE)
static
-ERL_NIF_TERM nsetopt_lvl_ip_update_source(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt)
+ERL_NIF_TERM esock_setopt_lvl_ip_update_source(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt)
{
ERL_NIF_TERM result, eMultiAddr, eInterface, eSourceAddr;
struct ip_mreq_source mreq;
@@ -8960,146 +9573,147 @@ ERL_NIF_TERM nsetopt_lvl_ip_update_source(ErlNifEnv* env,
/* *** Handling set of socket options for level = ipv6 *** */
-/* nsetopt_lvl_ipv6 - Level *IPv6* option(s)
+/* esock_setopt_lvl_ipv6 - Level *IPv6* option(s)
*/
#if defined(HAVE_IPV6)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ipv6 -> entry with"
+ ("SOCKET", "esock_setopt_lvl_ipv6 -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(IPV6_ADDRFORM)
- case SOCKET_OPT_IPV6_ADDRFORM:
- result = nsetopt_lvl_ipv6_addrform(env, descP, eVal);
+ case ESOCK_OPT_IPV6_ADDRFORM:
+ result = esock_setopt_lvl_ipv6_addrform(env, descP, eVal);
break;
#endif
#if defined(IPV6_ADD_MEMBERSHIP)
- case SOCKET_OPT_IPV6_ADD_MEMBERSHIP:
- result = nsetopt_lvl_ipv6_add_membership(env, descP, eVal);
+ case ESOCK_OPT_IPV6_ADD_MEMBERSHIP:
+ result = esock_setopt_lvl_ipv6_add_membership(env, descP, eVal);
break;
#endif
#if defined(IPV6_AUTHHDR)
- case SOCKET_OPT_IPV6_AUTHHDR:
- result = nsetopt_lvl_ipv6_authhdr(env, descP, eVal);
+ case ESOCK_OPT_IPV6_AUTHHDR:
+ result = esock_setopt_lvl_ipv6_authhdr(env, descP, eVal);
break;
#endif
#if defined(IPV6_DROP_MEMBERSHIP)
- case SOCKET_OPT_IPV6_DROP_MEMBERSHIP:
- result = nsetopt_lvl_ipv6_drop_membership(env, descP, eVal);
+ case ESOCK_OPT_IPV6_DROP_MEMBERSHIP:
+ result = esock_setopt_lvl_ipv6_drop_membership(env, descP, eVal);
break;
#endif
#if defined(IPV6_DSTOPTS)
- case SOCKET_OPT_IPV6_DSTOPTS:
- result = nsetopt_lvl_ipv6_dstopts(env, descP, eVal);
+ case ESOCK_OPT_IPV6_DSTOPTS:
+ result = esock_setopt_lvl_ipv6_dstopts(env, descP, eVal);
break;
#endif
#if defined(IPV6_FLOWINFO)
- case SOCKET_OPT_IPV6_FLOWINFO:
- result = nsetopt_lvl_ipv6_flowinfo(env, descP, eVal);
+ case ESOCK_OPT_IPV6_FLOWINFO:
+ result = esock_setopt_lvl_ipv6_flowinfo(env, descP, eVal);
break;
#endif
#if defined(IPV6_HOPLIMIT)
- case SOCKET_OPT_IPV6_HOPLIMIT:
- result = nsetopt_lvl_ipv6_hoplimit(env, descP, eVal);
+ case ESOCK_OPT_IPV6_HOPLIMIT:
+ result = esock_setopt_lvl_ipv6_hoplimit(env, descP, eVal);
break;
#endif
#if defined(IPV6_HOPOPTS)
- case SOCKET_OPT_IPV6_HOPOPTS:
- result = nsetopt_lvl_ipv6_hopopts(env, descP, eVal);
+ case ESOCK_OPT_IPV6_HOPOPTS:
+ result = esock_setopt_lvl_ipv6_hopopts(env, descP, eVal);
break;
#endif
#if defined(IPV6_MTU)
- case SOCKET_OPT_IPV6_MTU:
- result = nsetopt_lvl_ipv6_mtu(env, descP, eVal);
+ case ESOCK_OPT_IPV6_MTU:
+ result = esock_setopt_lvl_ipv6_mtu(env, descP, eVal);
break;
#endif
#if defined(IPV6_MTU_DISCOVER)
- case SOCKET_OPT_IPV6_MTU_DISCOVER:
- result = nsetopt_lvl_ipv6_mtu_discover(env, descP, eVal);
+ case ESOCK_OPT_IPV6_MTU_DISCOVER:
+ result = esock_setopt_lvl_ipv6_mtu_discover(env, descP, eVal);
break;
#endif
#if defined(IPV6_MULTICAST_HOPS)
- case SOCKET_OPT_IPV6_MULTICAST_HOPS:
- result = nsetopt_lvl_ipv6_multicast_hops(env, descP, eVal);
+ case ESOCK_OPT_IPV6_MULTICAST_HOPS:
+ result = esock_setopt_lvl_ipv6_multicast_hops(env, descP, eVal);
break;
#endif
#if defined(IPV6_MULTICAST_IF)
- case SOCKET_OPT_IPV6_MULTICAST_IF:
- result = nsetopt_lvl_ipv6_multicast_if(env, descP, eVal);
+ case ESOCK_OPT_IPV6_MULTICAST_IF:
+ result = esock_setopt_lvl_ipv6_multicast_if(env, descP, eVal);
break;
#endif
#if defined(IPV6_MULTICAST_LOOP)
- case SOCKET_OPT_IPV6_MULTICAST_LOOP:
- result = nsetopt_lvl_ipv6_multicast_loop(env, descP, eVal);
+ case ESOCK_OPT_IPV6_MULTICAST_LOOP:
+ result = esock_setopt_lvl_ipv6_multicast_loop(env, descP, eVal);
break;
#endif
#if defined(IPV6_RECVERR)
- case SOCKET_OPT_IPV6_RECVERR:
- result = nsetopt_lvl_ipv6_recverr(env, descP, eVal);
+ case ESOCK_OPT_IPV6_RECVERR:
+ result = esock_setopt_lvl_ipv6_recverr(env, descP, eVal);
break;
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
- case SOCKET_OPT_IPV6_RECVPKTINFO:
- result = nsetopt_lvl_ipv6_recvpktinfo(env, descP, eVal);
+ case ESOCK_OPT_IPV6_RECVPKTINFO:
+ result = esock_setopt_lvl_ipv6_recvpktinfo(env, descP, eVal);
break;
#endif
#if defined(IPV6_ROUTER_ALERT)
- case SOCKET_OPT_IPV6_ROUTER_ALERT:
- result = nsetopt_lvl_ipv6_router_alert(env, descP, eVal);
+ case ESOCK_OPT_IPV6_ROUTER_ALERT:
+ result = esock_setopt_lvl_ipv6_router_alert(env, descP, eVal);
break;
#endif
#if defined(IPV6_RTHDR)
- case SOCKET_OPT_IPV6_RTHDR:
- result = nsetopt_lvl_ipv6_rthdr(env, descP, eVal);
+ case ESOCK_OPT_IPV6_RTHDR:
+ result = esock_setopt_lvl_ipv6_rthdr(env, descP, eVal);
break;
#endif
#if defined(IPV6_UNICAST_HOPS)
- case SOCKET_OPT_IPV6_UNICAST_HOPS:
- result = nsetopt_lvl_ipv6_unicast_hops(env, descP, eVal);
+ case ESOCK_OPT_IPV6_UNICAST_HOPS:
+ result = esock_setopt_lvl_ipv6_unicast_hops(env, descP, eVal);
break;
#endif
#if defined(IPV6_V6ONLY)
- case SOCKET_OPT_IPV6_V6ONLY:
- result = nsetopt_lvl_ipv6_v6only(env, descP, eVal);
+ case ESOCK_OPT_IPV6_V6ONLY:
+ result = esock_setopt_lvl_ipv6_v6only(env, descP, eVal);
break;
#endif
default:
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ipv6 -> unknown opt (%d)\r\n", eOpt) );
+ ("SOCKET",
+ "esock_setopt_lvl_ipv6 -> unknown opt (%d)\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ipv6 -> done when"
+ ("SOCKET", "esock_setopt_lvl_ipv6 -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -9109,15 +9723,15 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
#if defined(IPV6_ADDRFORM)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_addrform(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
int res, edomain, domain;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ipv6_addrform -> entry with"
+ ("SOCKET", "esock_setopt_lvl_ipv6_addrform -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -9125,14 +9739,15 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_ipv6_addrform -> decode"
+ ("SOCKET", "esock_setopt_lvl_ipv6_addrform -> decode"
"\r\n edomain: %d"
"\r\n", edomain) );
if (!edomain2domain(edomain, &domain))
return esock_make_error(env, esock_atom_einval);
- SSDBG( descP, ("SOCKET", "nsetopt_lvl_ipv6_addrform -> try set opt to %d\r\n",
+ SSDBG( descP, ("SOCKET",
+ "esock_setopt_lvl_ipv6_addrform -> try set opt to %d\r\n",
domain) );
res = socket_setopt(descP->sock,
@@ -9151,11 +9766,11 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
#if defined(IPV6_ADD_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_add_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ipv6_update_membership(env, descP, eVal,
+ return esock_setopt_lvl_ipv6_update_membership(env, descP, eVal,
IPV6_ADD_MEMBERSHIP);
}
#endif
@@ -9163,22 +9778,22 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
#if defined(IPV6_AUTHHDR)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_authhdr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_authhdr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, SOL_IPV6, IPV6_AUTHHDR, eVal);
+ return esock_setopt_bool_opt(env, descP, SOL_IPV6, IPV6_AUTHHDR, eVal);
}
#endif
#if defined(IPV6_DROP_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_lvl_ipv6_update_membership(env, descP, eVal,
+ return esock_setopt_lvl_ipv6_update_membership(env, descP, eVal,
IPV6_DROP_MEMBERSHIP);
}
#endif
@@ -9186,9 +9801,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
#if defined(IPV6_DSTOPTS)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_dstopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_dstopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9196,16 +9811,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_dstopts(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_DSTOPTS, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_DSTOPTS, eVal);
}
#endif
#if defined(IPV6_FLOWINFO)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9213,16 +9828,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_FLOWINFO, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_FLOWINFO, eVal);
}
#endif
#if defined(IPV6_HOPLIMIT)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9230,16 +9845,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_HOPLIMIT, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_HOPLIMIT, eVal);
}
#endif
#if defined(IPV6_HOPOPTS)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_hopopts(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9247,14 +9862,14 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_HOPOPTS, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_HOPOPTS, eVal);
}
#endif
#if defined(IPV6_MTU)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env,
+ERL_NIF_TERM esock_setopt_lvl_ipv6_mtu(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM eVal)
{
@@ -9264,20 +9879,20 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_int_opt(env, descP, level, IPV6_MTU, eVal);
+ return esock_setopt_int_opt(env, descP, level, IPV6_MTU, eVal);
}
#endif
-/* nsetopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
+/* esock_setopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
*
* The value is an atom of the type ipv6_pmtudisc().
*/
#if defined(IPV6_MTU_DISCOVER)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
int val;
@@ -9313,9 +9928,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
#if defined(IPV6_MULTICAST_HOPS)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9323,7 +9938,7 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_int_opt(env, descP, level, IPV6_MULTICAST_HOPS, eVal);
+ return esock_setopt_int_opt(env, descP, level, IPV6_MULTICAST_HOPS, eVal);
}
#endif
@@ -9331,9 +9946,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
#if defined(IPV6_MULTICAST_IF)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9341,7 +9956,7 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_int_opt(env, descP, level, IPV6_MULTICAST_IF, eVal);
+ return esock_setopt_int_opt(env, descP, level, IPV6_MULTICAST_IF, eVal);
}
#endif
@@ -9349,9 +9964,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
#if defined(IPV6_MULTICAST_LOOP)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9359,16 +9974,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_MULTICAST_LOOP, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_MULTICAST_LOOP, eVal);
}
#endif
#if defined(IPV6_RECVERR)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_recverr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9376,16 +9991,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_recverr(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_RECVERR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_RECVERR, eVal);
}
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9398,16 +10013,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
int opt = IPV6_PKTINFO;
#endif
- return nsetopt_bool_opt(env, descP, level, opt, eVal);
+ return esock_setopt_bool_opt(env, descP, level, opt, eVal);
}
#endif
#if defined(IPV6_ROUTER_ALERT)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9415,7 +10030,7 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_int_opt(env, descP, level, IPV6_ROUTER_ALERT, eVal);
+ return esock_setopt_int_opt(env, descP, level, IPV6_ROUTER_ALERT, eVal);
}
#endif
@@ -9423,9 +10038,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
#if defined(IPV6_RTHDR)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9433,16 +10048,16 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_RTHDR, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_RTHDR, eVal);
}
#endif
#if defined(IPV6_UNICAST_HOPS)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9450,7 +10065,7 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_int_opt(env, descP, level, IPV6_UNICAST_HOPS, eVal);
+ return esock_setopt_int_opt(env, descP, level, IPV6_UNICAST_HOPS, eVal);
}
#endif
@@ -9458,9 +10073,9 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
#if defined(IPV6_V6ONLY)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_v6only(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -9468,17 +10083,17 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return nsetopt_bool_opt(env, descP, level, IPV6_V6ONLY, eVal);
+ return esock_setopt_bool_opt(env, descP, level, IPV6_V6ONLY, eVal);
}
#endif
#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
static
-ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal,
- int opt)
+ERL_NIF_TERM esock_setopt_lvl_ipv6_update_membership(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt)
{
ERL_NIF_TERM result, eMultiAddr, eInterface;
struct ipv6_mreq mreq;
@@ -9492,33 +10107,65 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
#endif
// It must be a map
- if (!IS_MAP(env, eVal))
+ if (!IS_MAP(env, eVal)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "value *not* a map\r\n") );
return enif_make_badarg(env);
+ }
// It must have atleast two attributes
- if (!enif_get_map_size(env, eVal, &sz) || (sz >= 2))
+ if (!enif_get_map_size(env, eVal, &sz) || (sz < 2)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "invalid map value: %T\r\n", eVal) );
return enif_make_badarg(env);
+ }
- if (!GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr))
+ if (!GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "failed get multiaddr (map) attribute\r\n") );
return enif_make_badarg(env);
+ }
- if (!GET_MAP_VAL(env, eVal, atom_interface, &eInterface))
+ if (!GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "failed get interface (map) attribute\r\n") );
return enif_make_badarg(env);
+ }
if ((xres = esock_decode_ip6_address(env,
eMultiAddr,
- &mreq.ipv6mr_multiaddr)) != NULL)
+ &mreq.ipv6mr_multiaddr)) != NULL) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "failed decode multiaddr %T: %s\r\n", eMultiAddr, xres) );
return esock_make_error_str(env, xres);
+ }
- if (!GET_UINT(env, eInterface, &mreq.ipv6mr_interface))
+ if (!GET_UINT(env, eInterface, &mreq.ipv6mr_interface)) {
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ip_update_membership -> "
+ "failed decode interface %T: %s\r\n", eInterface, xres) );
return esock_make_error(env, esock_atom_einval);
+ }
res = socket_setopt(descP->sock, level, opt, &mreq, sizeof(mreq));
- if (res != 0)
- result = esock_make_error_errno(env, sock_errno());
- else
+ if (res != 0) {
+ int save_errno = sock_errno();
+
+ result = esock_make_error_errno(env, save_errno);
+
+ SSDBG( descP,
+ ("SOCKET", "esock_setopt_lvl_ipv6_update_membership -> "
+ "failed setopt: %T (%d)\r\n", result, save_errno) );
+
+ } else {
result = esock_atom_ok;
+ }
return result;
}
@@ -9530,37 +10177,37 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
-/* nsetopt_lvl_tcp - Level *TCP* option(s)
+/* esock_setopt_lvl_tcp - Level *TCP* option(s)
*/
static
-ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_tcp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_tcp -> entry with"
+ ("SOCKET", "esock_setopt_lvl_tcp -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(TCP_CONGESTION)
- case SOCKET_OPT_TCP_CONGESTION:
- result = nsetopt_lvl_tcp_congestion(env, descP, eVal);
+ case ESOCK_OPT_TCP_CONGESTION:
+ result = esock_setopt_lvl_tcp_congestion(env, descP, eVal);
break;
#endif
#if defined(TCP_MAXSEG)
- case SOCKET_OPT_TCP_MAXSEG:
- result = nsetopt_lvl_tcp_maxseg(env, descP, eVal);
+ case ESOCK_OPT_TCP_MAXSEG:
+ result = esock_setopt_lvl_tcp_maxseg(env, descP, eVal);
break;
#endif
#if defined(TCP_NODELAY)
- case SOCKET_OPT_TCP_NODELAY:
- result = nsetopt_lvl_tcp_nodelay(env, descP, eVal);
+ case ESOCK_OPT_TCP_NODELAY:
+ result = esock_setopt_lvl_tcp_nodelay(env, descP, eVal);
break;
#endif
@@ -9573,67 +10220,68 @@ ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
}
-/* nsetopt_lvl_tcp_congestion - Level TCP CONGESTION option
+/* esock_setopt_lvl_tcp_congestion - Level TCP CONGESTION option
*/
#if defined(TCP_CONGESTION)
static
-ERL_NIF_TERM nsetopt_lvl_tcp_congestion(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_tcp_congestion(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- int max = SOCKET_OPT_TCP_CONGESTION_NAME_MAX+1;
+ int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1;
- return nsetopt_str_opt(env, descP, IPPROTO_TCP, TCP_CONGESTION, max, eVal);
+ return esock_setopt_str_opt(env, descP,
+ IPPROTO_TCP, TCP_CONGESTION, max, eVal);
}
#endif
-/* nsetopt_lvl_tcp_maxseg - Level TCP MAXSEG option
+/* esock_setopt_lvl_tcp_maxseg - Level TCP MAXSEG option
*/
#if defined(TCP_MAXSEG)
static
-ERL_NIF_TERM nsetopt_lvl_tcp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, IPPROTO_TCP, TCP_MAXSEG, eVal);
+ return esock_setopt_int_opt(env, descP, IPPROTO_TCP, TCP_MAXSEG, eVal);
}
#endif
-/* nsetopt_lvl_tcp_nodelay - Level TCP NODELAY option
+/* esock_setopt_lvl_tcp_nodelay - Level TCP NODELAY option
*/
#if defined(TCP_NODELAY)
static
-ERL_NIF_TERM nsetopt_lvl_tcp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, IPPROTO_TCP, TCP_NODELAY, eVal);
+ return esock_setopt_bool_opt(env, descP, IPPROTO_TCP, TCP_NODELAY, eVal);
}
#endif
-/* nsetopt_lvl_udp - Level *UDP* option(s)
+/* esock_setopt_lvl_udp - Level *UDP* option(s)
*/
static
-ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_udp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_udp -> entry with"
+ ("SOCKET", "esock_setopt_lvl_udp -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(UDP_CORK)
- case SOCKET_OPT_UDP_CORK:
- result = nsetopt_lvl_udp_cork(env, descP, eVal);
+ case ESOCK_OPT_UDP_CORK:
+ result = esock_setopt_lvl_udp_cork(env, descP, eVal);
break;
#endif
@@ -9646,83 +10294,83 @@ ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env,
}
-/* nsetopt_lvl_udp_cork - Level UDP CORK option
+/* esock_setopt_lvl_udp_cork - Level UDP CORK option
*/
#if defined(UDP_CORK)
static
-ERL_NIF_TERM nsetopt_lvl_udp_cork(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_udp_cork(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, IPPROTO_UDP, UDP_CORK, eVal);
+ return esock_setopt_bool_opt(env, descP, IPPROTO_UDP, UDP_CORK, eVal);
}
#endif
-/* nsetopt_lvl_sctp - Level *SCTP* option(s)
+/* esock_setopt_lvl_sctp - Level *SCTP* option(s)
*/
#if defined(HAVE_SCTP)
static
-ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sctp -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(SCTP_ASSOCINFO)
- case SOCKET_OPT_SCTP_ASSOCINFO:
- result = nsetopt_lvl_sctp_associnfo(env, descP, eVal);
+ case ESOCK_OPT_SCTP_ASSOCINFO:
+ result = esock_setopt_lvl_sctp_associnfo(env, descP, eVal);
break;
#endif
#if defined(SCTP_AUTOCLOSE)
- case SOCKET_OPT_SCTP_AUTOCLOSE:
- result = nsetopt_lvl_sctp_autoclose(env, descP, eVal);
+ case ESOCK_OPT_SCTP_AUTOCLOSE:
+ result = esock_setopt_lvl_sctp_autoclose(env, descP, eVal);
break;
#endif
#if defined(SCTP_DISABLE_FRAGMENTS)
- case SOCKET_OPT_SCTP_DISABLE_FRAGMENTS:
- result = nsetopt_lvl_sctp_disable_fragments(env, descP, eVal);
+ case ESOCK_OPT_SCTP_DISABLE_FRAGMENTS:
+ result = esock_setopt_lvl_sctp_disable_fragments(env, descP, eVal);
break;
#endif
#if defined(SCTP_EVENTS)
- case SOCKET_OPT_SCTP_EVENTS:
- result = nsetopt_lvl_sctp_events(env, descP, eVal);
+ case ESOCK_OPT_SCTP_EVENTS:
+ result = esock_setopt_lvl_sctp_events(env, descP, eVal);
break;
#endif
#if defined(SCTP_INITMSG)
- case SOCKET_OPT_SCTP_INITMSG:
- result = nsetopt_lvl_sctp_initmsg(env, descP, eVal);
+ case ESOCK_OPT_SCTP_INITMSG:
+ result = esock_setopt_lvl_sctp_initmsg(env, descP, eVal);
break;
#endif
#if defined(SCTP_MAXSEG)
- case SOCKET_OPT_SCTP_MAXSEG:
- result = nsetopt_lvl_sctp_maxseg(env, descP, eVal);
+ case ESOCK_OPT_SCTP_MAXSEG:
+ result = esock_setopt_lvl_sctp_maxseg(env, descP, eVal);
break;
#endif
#if defined(SCTP_NODELAY)
- case SOCKET_OPT_SCTP_NODELAY:
- result = nsetopt_lvl_sctp_nodelay(env, descP, eVal);
+ case ESOCK_OPT_SCTP_NODELAY:
+ result = esock_setopt_lvl_sctp_nodelay(env, descP, eVal);
break;
#endif
#if defined(SCTP_RTOINFO)
- case SOCKET_OPT_SCTP_RTOINFO:
- result = nsetopt_lvl_sctp_rtoinfo(env, descP, eVal);
+ case ESOCK_OPT_SCTP_RTOINFO:
+ result = esock_setopt_lvl_sctp_rtoinfo(env, descP, eVal);
break;
#endif
@@ -9735,13 +10383,13 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
}
-/* nsetopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
+/* esock_setopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
*/
#if defined(SCTP_ASSOCINFO)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eAssocId, eMaxRxt, eNumPeerDests;
@@ -9752,7 +10400,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
unsigned int tmp;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_associnfo -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sctp_associnfo -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -9765,7 +10413,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_associnfo -> extract attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_associnfo -> extract attributes\r\n") );
if (!GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId))
return esock_make_error(env, esock_atom_einval);
@@ -9786,7 +10435,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_associnfo -> decode attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_associnfo -> decode attributes\r\n") );
/* On some platforms the assoc id is typed as an unsigned integer (uint32)
* So, to avoid warnings there, we always make an explicit cast...
@@ -9839,7 +10489,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_associnfo -> set associnfo option\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_associnfo -> set associnfo option\r\n") );
res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_ASSOCINFO,
&assocParams, sizeof(assocParams));
@@ -9850,7 +10501,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
result = esock_atom_ok;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_associnfo -> done with"
+ ("SOCKET", "esock_setopt_lvl_sctp_associnfo -> done with"
"\r\n result: %T"
"\r\n", result) );
@@ -9860,39 +10511,42 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
+/* esock_setopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
*/
#if defined(SCTP_AUTOCLOSE)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_AUTOCLOSE, eVal);
+ return esock_setopt_int_opt(env, descP,
+ IPPROTO_SCTP, SCTP_AUTOCLOSE, eVal);
}
#endif
-/* nsetopt_lvl_sctp_disable_fragments - Level SCTP DISABLE_FRAGMENTS option
+/* esock_setopt_lvl_sctp_disable_fragments -
+ * Level SCTP DISABLE_FRAGMENTS option
*/
#if defined(SCTP_DISABLE_FRAGMENTS)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, eVal);
+ return esock_setopt_bool_opt(env, descP,
+ IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, eVal);
}
#endif
-/* nsetopt_lvl_sctp_events - Level SCTP EVENTS option
+/* esock_setopt_lvl_sctp_events - Level SCTP EVENTS option
*/
#if defined(SCTP_EVENTS)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_events(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eDataIn, eAssoc, eAddr, eSndFailure;
@@ -9909,7 +10563,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
size_t sz;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sctp_events -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -9922,7 +10576,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> extract attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_events -> extract attributes\r\n") );
if (!GET_MAP_VAL(env, eVal, atom_data_in, &eDataIn))
return esock_make_error(env, esock_atom_einval);
@@ -9959,7 +10614,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
#endif
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> decode attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_events -> decode attributes\r\n") );
events.sctp_data_io_event = esock_decode_bool(eDataIn);
events.sctp_association_event = esock_decode_bool(eAssoc);
@@ -9977,7 +10633,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
#endif
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> set events option\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_events -> set events option\r\n") );
res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_EVENTS,
&events, sizeof(events));
@@ -9988,7 +10645,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
result = esock_atom_ok;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> done with"
+ ("SOCKET", "esock_setopt_lvl_sctp_events -> done with"
"\r\n result: %T"
"\r\n", result) );
@@ -9998,13 +10655,13 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_sctp_initmsg - Level SCTP INITMSG option
+/* esock_setopt_lvl_sctp_initmsg - Level SCTP INITMSG option
*/
#if defined(SCTP_INITMSG)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eNumOut, eMaxIn, eMaxAttempts, eMaxInitTO;
@@ -10014,7 +10671,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
unsigned int tmp;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_initmsg -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sctp_initmsg -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -10027,7 +10684,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_initmsg -> extract attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_initmsg -> extract attributes\r\n") );
if (!GET_MAP_VAL(env, eVal, atom_num_outstreams, &eNumOut))
return esock_make_error(env, esock_atom_einval);
@@ -10042,7 +10700,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_initmsg -> decode attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_initmsg -> decode attributes\r\n") );
if (!GET_UINT(env, eNumOut, &tmp))
return esock_make_error(env, esock_atom_einval);
@@ -10061,7 +10720,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
initMsg.sinit_max_init_timeo = (Uint16) tmp;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_initmsg -> set initmsg option\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_initmsg -> set initmsg option\r\n") );
res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_INITMSG,
&initMsg, sizeof(initMsg));
@@ -10072,7 +10732,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
result = esock_atom_ok;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_initmsg -> done with"
+ ("SOCKET", "esock_setopt_lvl_sctp_initmsg -> done with"
"\r\n result: %T"
"\r\n", result) );
@@ -10082,39 +10742,39 @@ ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
#endif
-/* nsetopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
+/* esock_setopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
*/
#if defined(SCTP_MAXSEG)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_MAXSEG, eVal);
+ return esock_setopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_MAXSEG, eVal);
}
#endif
-/* nsetopt_lvl_sctp_nodelay - Level SCTP NODELAY option
+/* esock_setopt_lvl_sctp_nodelay - Level SCTP NODELAY option
*/
#if defined(SCTP_NODELAY)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
- return nsetopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_NODELAY, eVal);
+ return esock_setopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_NODELAY, eVal);
}
#endif
-/* nsetopt_lvl_sctp_rtoinfo - Level SCTP RTOINFO option
+/* esock_setopt_lvl_sctp_rtoinfo - Level SCTP RTOINFO option
*/
#if defined(SCTP_RTOINFO)
static
-ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eAssocId, eInitial, eMax, eMin;
@@ -10123,7 +10783,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
size_t sz;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> entry with"
+ ("SOCKET", "esock_setopt_lvl_sctp_rtoinfo -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -10136,7 +10796,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> extract attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_rtoinfo -> extract attributes\r\n") );
if (!GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId))
return esock_make_error(env, esock_atom_einval);
@@ -10151,7 +10812,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> decode attributes\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_rtoinfo -> decode attributes\r\n") );
/* On some platforms the assoc id is typed as an unsigned integer (uint32)
* So, to avoid warnings there, we always make an explicit cast...
@@ -10186,7 +10848,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> set associnfo option\r\n") );
+ ("SOCKET",
+ "esock_setopt_lvl_sctp_rtoinfo -> set associnfo option\r\n") );
res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_RTOINFO,
&rtoInfo, sizeof(rtoInfo));
@@ -10197,7 +10860,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
result = esock_atom_ok;
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> done with"
+ ("SOCKET", "esock_setopt_lvl_sctp_rtoinfo -> done with"
"\r\n result: %T"
"\r\n", result) );
@@ -10213,14 +10876,14 @@ ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
-/* nsetopt_bool_opt - set an option that has an (integer) bool value
+/* esock_setopt_bool_opt - set an option that has an (integer) bool value
*/
static
-ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
BOOLEAN_T val;
@@ -10240,14 +10903,14 @@ ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
}
-/* nsetopt_int_opt - set an option that has an integer value
+/* esock_setopt_int_opt - set an option that has an integer value
*/
static
-ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
int val;
@@ -10257,7 +10920,7 @@ ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
/*
SSDBG( descP,
- ("SOCKET", "nsetopt_int_opt -> set option"
+ ("SOCKET", "esock_setopt_int_opt -> set option"
"\r\n opt: %d"
"\r\n val: %d"
"\r\n", opt, val) );
@@ -10278,16 +10941,16 @@ ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
}
-/* nsetopt_str_opt - set an option that has an string value
+/* esock_setopt_str_opt - set an option that has an string value
*/
#if defined(USE_SETOPT_STR_OPT)
static
-ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- int max,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ int max,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
char* val = MALLOC(max);
@@ -10312,14 +10975,14 @@ ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
#endif
-/* nsetopt_timeval_opt - set an option that has an (timeval) bool value
+/* esock_setopt_timeval_opt - set an option that has an (timeval) bool value
*/
static
-ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- ERL_NIF_TERM eVal)
+ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
struct timeval timeVal;
@@ -10327,7 +10990,7 @@ ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
char* xres;
SSDBG( descP,
- ("SOCKET", "nsetopt_timeval_opt -> entry with"
+ ("SOCKET", "esock_setopt_timeval_opt -> entry with"
"\r\n eVal: %T"
"\r\n", eVal) );
@@ -10335,7 +10998,7 @@ ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
return esock_make_error_str(env, xres);
SSDBG( descP,
- ("SOCKET", "nsetopt_timeval_opt -> set timeval option\r\n") );
+ ("SOCKET", "esock_setopt_timeval_opt -> set timeval option\r\n") );
res = socket_setopt(descP->sock, level, opt, &timeVal, sizeof(timeVal));
@@ -10345,7 +11008,7 @@ ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
result = esock_atom_ok;
SSDBG( descP,
- ("SOCKET", "nsetopt_timeval_opt -> done with"
+ ("SOCKET", "esock_setopt_timeval_opt -> done with"
"\r\n result: %T"
"\r\n", result) );
@@ -10365,19 +11028,19 @@ BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
if (isEncoded) {
switch (eLevel) {
- case SOCKET_OPT_LEVEL_OTP:
+ case ESOCK_OPT_LEVEL_OTP:
*isOTP = TRUE;
*level = -1;
result = TRUE;
break;
- case SOCKET_OPT_LEVEL_SOCKET:
+ case ESOCK_OPT_LEVEL_SOCKET:
*isOTP = FALSE;
*level = SOL_SOCKET;
result = TRUE;
break;
- case SOCKET_OPT_LEVEL_IP:
+ case ESOCK_OPT_LEVEL_IP:
*isOTP = FALSE;
#if defined(SOL_IP)
*level = SOL_IP;
@@ -10388,7 +11051,7 @@ BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
break;
#if defined(HAVE_IPV6)
- case SOCKET_OPT_LEVEL_IPV6:
+ case ESOCK_OPT_LEVEL_IPV6:
*isOTP = FALSE;
#if defined(SOL_IPV6)
*level = SOL_IPV6;
@@ -10399,20 +11062,20 @@ BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
break;
#endif
- case SOCKET_OPT_LEVEL_TCP:
+ case ESOCK_OPT_LEVEL_TCP:
*isOTP = FALSE;
*level = IPPROTO_TCP;
result = TRUE;
break;
- case SOCKET_OPT_LEVEL_UDP:
+ case ESOCK_OPT_LEVEL_UDP:
*isOTP = FALSE;
*level = IPPROTO_UDP;
result = TRUE;
break;
#ifdef HAVE_SCTP
- case SOCKET_OPT_LEVEL_SCTP:
+ case ESOCK_OPT_LEVEL_SCTP:
*isOTP = FALSE;
*level = IPPROTO_SCTP;
result = TRUE;
@@ -10557,7 +11220,7 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
SGDBG( ("SOCKET", "nif_getopt -> entry with argc: %d\r\n", argc) );
if ((argc != 4) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP) ||
!GET_INT(env, argv[2], &eLevel)) {
SGDBG( ("SOCKET", "nif_getopt -> failed processing args\r\n") );
return enif_make_badarg(env);
@@ -10583,7 +11246,7 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
MLOCK(descP->cfgMtx);
- result = ngetopt(env, descP, isEncoded, isOTP, level, eOpt);
+ result = esock_getopt(env, descP, isEncoded, isOTP, level, eOpt);
MUNLOCK(descP->cfgMtx);
@@ -10596,18 +11259,18 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM ngetopt(ErlNifEnv* env,
- ESockDescriptor* descP,
- BOOLEAN_T isEncoded,
- BOOLEAN_T isOTP,
- int level,
- ERL_NIF_TERM eOpt)
+ERL_NIF_TERM esock_getopt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ BOOLEAN_T isEncoded,
+ BOOLEAN_T isOTP,
+ int level,
+ ERL_NIF_TERM eOpt)
{
ERL_NIF_TERM result;
int opt;
SSDBG( descP,
- ("SOCKET", "ngetopt -> entry with"
+ ("SOCKET", "esock_getopt -> entry with"
"\r\n isEncoded: %s"
"\r\n isOTP: %s"
"\r\n level: %d"
@@ -10619,20 +11282,20 @@ ERL_NIF_TERM ngetopt(ErlNifEnv* env,
* but options for our implementation.
*/
if (GET_INT(env, eOpt, &opt))
- result = ngetopt_otp(env, descP, opt);
+ result = esock_getopt_otp(env, descP, opt);
else
result = esock_make_error(env, esock_atom_einval);
} else if (!isEncoded) {
- result = ngetopt_native(env, descP, level, eOpt);
+ result = esock_getopt_native(env, descP, level, eOpt);
} else {
if (GET_INT(env, eOpt, &opt))
- result = ngetopt_level(env, descP, level, opt);
+ result = esock_getopt_level(env, descP, level, opt);
else
result = esock_make_error(env, esock_atom_einval);
}
SSDBG( descP,
- ("SOCKET", "ngetopt -> done when"
+ ("SOCKET", "esock_getopt -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -10641,60 +11304,60 @@ ERL_NIF_TERM ngetopt(ErlNifEnv* env,
-/* ngetopt_otp - Handle OTP (level) options
+/* esock_getopt_otp - Handle OTP (level) options
*/
static
-ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_otp -> entry with"
+ ("SOCKET", "esock_getopt_otp -> entry with"
"\r\n eOpt: %d"
"\r\n", eOpt) );
switch (eOpt) {
- case SOCKET_OPT_OTP_DEBUG:
- result = ngetopt_otp_debug(env, descP);
+ case ESOCK_OPT_OTP_DEBUG:
+ result = esock_getopt_otp_debug(env, descP);
break;
- case SOCKET_OPT_OTP_IOW:
- result = ngetopt_otp_iow(env, descP);
+ case ESOCK_OPT_OTP_IOW:
+ result = esock_getopt_otp_iow(env, descP);
break;
- case SOCKET_OPT_OTP_CTRL_PROC:
- result = ngetopt_otp_ctrl_proc(env, descP);
+ case ESOCK_OPT_OTP_CTRL_PROC:
+ result = esock_getopt_otp_ctrl_proc(env, descP);
break;
- case SOCKET_OPT_OTP_RCVBUF:
- result = ngetopt_otp_rcvbuf(env, descP);
+ case ESOCK_OPT_OTP_RCVBUF:
+ result = esock_getopt_otp_rcvbuf(env, descP);
break;
- case SOCKET_OPT_OTP_RCVCTRLBUF:
- result = ngetopt_otp_rcvctrlbuf(env, descP);
+ case ESOCK_OPT_OTP_RCVCTRLBUF:
+ result = esock_getopt_otp_rcvctrlbuf(env, descP);
break;
- case SOCKET_OPT_OTP_SNDCTRLBUF:
- result = ngetopt_otp_sndctrlbuf(env, descP);
+ case ESOCK_OPT_OTP_SNDCTRLBUF:
+ result = esock_getopt_otp_sndctrlbuf(env, descP);
break;
- case SOCKET_OPT_OTP_FD:
- result = ngetopt_otp_fd(env, descP);
+ case ESOCK_OPT_OTP_FD:
+ result = esock_getopt_otp_fd(env, descP);
break;
/* *** INTERNAL *** */
- case SOCKET_OPT_OTP_DOMAIN:
- result = ngetopt_otp_domain(env, descP);
+ case ESOCK_OPT_OTP_DOMAIN:
+ result = esock_getopt_otp_domain(env, descP);
break;
- case SOCKET_OPT_OTP_TYPE:
- result = ngetopt_otp_type(env, descP);
+ case ESOCK_OPT_OTP_TYPE:
+ result = esock_getopt_otp_type(env, descP);
break;
- case SOCKET_OPT_OTP_PROTOCOL:
- result = ngetopt_otp_protocol(env, descP);
+ case ESOCK_OPT_OTP_PROTOCOL:
+ result = esock_getopt_otp_protocol(env, descP);
break;
default:
@@ -10703,7 +11366,7 @@ ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_otp -> done when"
+ ("SOCKET", "esock_getopt_otp -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -10711,11 +11374,11 @@ ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env,
}
-/* ngetopt_otp_debug - Handle the OTP (level) debug option
+/* esock_getopt_otp_debug - Handle the OTP (level) debug option
*/
static
-ERL_NIF_TERM ngetopt_otp_debug(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = esock_encode_bool(descP->dbg);
@@ -10723,11 +11386,11 @@ ERL_NIF_TERM ngetopt_otp_debug(ErlNifEnv* env,
}
-/* ngetopt_otp_iow - Handle the OTP (level) iow option
+/* esock_getopt_otp_iow - Handle the OTP (level) iow option
*/
static
-ERL_NIF_TERM ngetopt_otp_iow(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = esock_encode_bool(descP->iow);
@@ -10735,11 +11398,11 @@ ERL_NIF_TERM ngetopt_otp_iow(ErlNifEnv* env,
}
-/* ngetopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option
+/* esock_getopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option
*/
static
-ERL_NIF_TERM ngetopt_otp_ctrl_proc(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = MKPID(env, &descP->ctrlPid);
@@ -10748,11 +11411,11 @@ ERL_NIF_TERM ngetopt_otp_ctrl_proc(ErlNifEnv* env,
-/* ngetopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
+/* esock_getopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option
*/
static
-ERL_NIF_TERM ngetopt_otp_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal;
@@ -10766,11 +11429,11 @@ ERL_NIF_TERM ngetopt_otp_rcvbuf(ErlNifEnv* env,
}
-/* ngetopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
+/* esock_getopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option
*/
static
-ERL_NIF_TERM ngetopt_otp_rcvctrlbuf(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = MKI(env, descP->rCtrlSz);
@@ -10778,11 +11441,11 @@ ERL_NIF_TERM ngetopt_otp_rcvctrlbuf(ErlNifEnv* env,
}
-/* ngetopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
+/* esock_getopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option
*/
static
-ERL_NIF_TERM ngetopt_otp_sndctrlbuf(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = MKI(env, descP->wCtrlSz);
@@ -10790,11 +11453,11 @@ ERL_NIF_TERM ngetopt_otp_sndctrlbuf(ErlNifEnv* env,
}
-/* ngetopt_otp_fd - Handle the OTP (level) fd option
+/* esock_getopt_otp_fd - Handle the OTP (level) fd option
*/
static
-ERL_NIF_TERM ngetopt_otp_fd(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM eVal = MKI(env, descP->sock);
@@ -10802,11 +11465,11 @@ ERL_NIF_TERM ngetopt_otp_fd(ErlNifEnv* env,
}
-/* ngetopt_otp_domain - Handle the OTP (level) domain option
+/* esock_getopt_otp_domain - Handle the OTP (level) domain option
*/
static
-ERL_NIF_TERM ngetopt_otp_domain(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val = descP->domain;
@@ -10838,11 +11501,11 @@ ERL_NIF_TERM ngetopt_otp_domain(ErlNifEnv* env,
}
-/* ngetopt_otp_type - Handle the OTP (level) type options.
+/* esock_getopt_otp_type - Handle the OTP (level) type options.
*/
static
-ERL_NIF_TERM ngetopt_otp_type(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val = descP->type;
@@ -10879,18 +11542,26 @@ ERL_NIF_TERM ngetopt_otp_type(ErlNifEnv* env,
}
-/* ngetopt_otp_protocol - Handle the OTP (level) protocol options.
+/* esock_getopt_otp_protocol - Handle the OTP (level) protocol options.
*/
static
-ERL_NIF_TERM ngetopt_otp_protocol(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val = descP->protocol;
switch (val) {
case IPPROTO_IP:
+#if defined(AF_LOCAL)
+ if (descP->domain == AF_LOCAL) {
+ result = esock_make_ok2(env, esock_atom_default);
+ } else {
+ result = esock_make_ok2(env, esock_atom_ip);
+ }
+#else
result = esock_make_ok2(env, esock_atom_ip);
+#endif
break;
case IPPROTO_TCP:
@@ -10923,10 +11594,10 @@ ERL_NIF_TERM ngetopt_otp_protocol(ErlNifEnv* env,
* format: {NativeOpt :: integer(), ValueSize :: non_neg_integer()}
*/
static
-ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- ERL_NIF_TERM eOpt)
+ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ ERL_NIF_TERM eOpt)
{
ERL_NIF_TERM result = enif_make_badarg(env);
int opt;
@@ -10934,7 +11605,7 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
SOCKOPTLEN_T valueSz;
SSDBG( descP,
- ("SOCKET", "ngetopt_native -> entry with"
+ ("SOCKET", "esock_getopt_native -> entry with"
"\r\n level: %d"
"\r\n eOpt: %T"
"\r\n", level, eOpt) );
@@ -10948,20 +11619,21 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
if (decode_native_get_opt(env, eOpt, &opt, &valueType, (int*) &valueSz)) {
SSDBG( descP,
- ("SOCKET", "ngetopt_native -> decoded opt"
+ ("SOCKET", "esock_getopt_native -> decoded opt"
"\r\n valueType: %d (%s)"
"\r\n ValueSize: %d"
"\r\n", valueType, VT2S(valueType), valueSz) );
switch (valueType) {
- case SOCKET_OPT_VALUE_TYPE_UNSPEC:
- result = ngetopt_native_unspec(env, descP, level, opt, valueSz);
+ case ESOCK_OPT_VALUE_TYPE_UNSPEC:
+ result = esock_getopt_native_unspec(env, descP,
+ level, opt, valueSz);
break;
- case SOCKET_OPT_VALUE_TYPE_INT:
- result = ngetopt_int_opt(env, descP, level, opt);
+ case ESOCK_OPT_VALUE_TYPE_INT:
+ result = esock_getopt_int_opt(env, descP, level, opt);
break;
- case SOCKET_OPT_VALUE_TYPE_BOOL:
- result = ngetopt_bool_opt(env, descP, level, opt);
+ case ESOCK_OPT_VALUE_TYPE_BOOL:
+ result = esock_getopt_bool_opt(env, descP, level, opt);
break;
default:
result = esock_make_error(env, esock_atom_einval);
@@ -10972,7 +11644,7 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_native -> done when"
+ ("SOCKET", "esock_getopt_native -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -10981,17 +11653,17 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env,
static
-ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- SOCKOPTLEN_T valueSz)
+ERL_NIF_TERM esock_getopt_native_unspec(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ SOCKOPTLEN_T valueSz)
{
ERL_NIF_TERM result = esock_make_error(env, esock_atom_einval);
int res;
SSDBG( descP,
- ("SOCKET", "ngetopt_native_unspec -> entry with"
+ ("SOCKET", "esock_getopt_native_unspec -> entry with"
"\r\n level: %d"
"\r\n opt: %d"
"\r\n valueSz: %d"
@@ -11007,7 +11679,8 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
SOCKOPTLEN_T vsz = valueSz;
ErlNifBinary val;
- SSDBG( descP, ("SOCKET", "ngetopt_native_unspec -> try alloc buffer\r\n") );
+ SSDBG( descP, ("SOCKET",
+ "esock_getopt_native_unspec -> try alloc buffer\r\n") );
if (ALLOC_BIN(vsz, &val)) {
int saveErrno;
@@ -11039,7 +11712,7 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_native_unspec -> done when"
+ ("SOCKET", "esock_getopt_native_unspec -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -11048,25 +11721,25 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
-/* ngetopt_level - A "proper" level (option) has been specified
+/* esock_getopt_level - A "proper" level (option) has been specified
*/
static
-ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int eOpt)
+ERL_NIF_TERM esock_getopt_level(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_level -> entry with"
+ ("SOCKET", "esock_getopt_level -> entry with"
"\r\n level: %d"
"\r\n eOpt: %d"
"\r\n", level, eOpt) );
switch (level) {
case SOL_SOCKET:
- result = ngetopt_lvl_socket(env, descP, eOpt);
+ result = esock_getopt_lvl_socket(env, descP, eOpt);
break;
#if defined(SOL_IP)
@@ -11074,7 +11747,7 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
#else
case IPPROTO_IP:
#endif
- result = ngetopt_lvl_ip(env, descP, eOpt);
+ result = esock_getopt_lvl_ip(env, descP, eOpt);
break;
#if defined(HAVE_IPV6)
@@ -11083,21 +11756,21 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
#else
case IPPROTO_IPV6:
#endif
- result = ngetopt_lvl_ipv6(env, descP, eOpt);
+ result = esock_getopt_lvl_ipv6(env, descP, eOpt);
break;
#endif
case IPPROTO_TCP:
- result = ngetopt_lvl_tcp(env, descP, eOpt);
+ result = esock_getopt_lvl_tcp(env, descP, eOpt);
break;
case IPPROTO_UDP:
- result = ngetopt_lvl_udp(env, descP, eOpt);
+ result = esock_getopt_lvl_udp(env, descP, eOpt);
break;
#if defined(HAVE_SCTP)
case IPPROTO_SCTP:
- result = ngetopt_lvl_sctp(env, descP, eOpt);
+ result = esock_getopt_lvl_sctp(env, descP, eOpt);
break;
#endif
@@ -11107,7 +11780,7 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_level -> done when"
+ ("SOCKET", "esock_getopt_level -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -11115,150 +11788,150 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
}
-/* ngetopt_lvl_socket - Level *SOCKET* option
+/* esock_getopt_lvl_socket - Level *SOCKET* option
*/
static
-ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_socket(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_socket -> entry with"
+ ("SOCKET", "esock_getopt_lvl_socket -> entry with"
"\r\n eOpt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(SO_ACCEPTCONN)
- case SOCKET_OPT_SOCK_ACCEPTCONN:
- result = ngetopt_lvl_sock_acceptconn(env, descP);
+ case ESOCK_OPT_SOCK_ACCEPTCONN:
+ result = esock_getopt_lvl_sock_acceptconn(env, descP);
break;
#endif
#if defined(SO_BINDTODEVICE)
- case SOCKET_OPT_SOCK_BINDTODEVICE:
- result = ngetopt_lvl_sock_bindtodevice(env, descP);
+ case ESOCK_OPT_SOCK_BINDTODEVICE:
+ result = esock_getopt_lvl_sock_bindtodevice(env, descP);
break;
#endif
#if defined(SO_BROADCAST)
- case SOCKET_OPT_SOCK_BROADCAST:
- result = ngetopt_lvl_sock_broadcast(env, descP);
+ case ESOCK_OPT_SOCK_BROADCAST:
+ result = esock_getopt_lvl_sock_broadcast(env, descP);
break;
#endif
#if defined(SO_DEBUG)
- case SOCKET_OPT_SOCK_DEBUG:
- result = ngetopt_lvl_sock_debug(env, descP);
+ case ESOCK_OPT_SOCK_DEBUG:
+ result = esock_getopt_lvl_sock_debug(env, descP);
break;
#endif
#if defined(SO_DOMAIN)
- case SOCKET_OPT_SOCK_DOMAIN:
- result = ngetopt_lvl_sock_domain(env, descP);
+ case ESOCK_OPT_SOCK_DOMAIN:
+ result = esock_getopt_lvl_sock_domain(env, descP);
break;
#endif
#if defined(SO_DONTROUTE)
- case SOCKET_OPT_SOCK_DONTROUTE:
- result = ngetopt_lvl_sock_dontroute(env, descP);
+ case ESOCK_OPT_SOCK_DONTROUTE:
+ result = esock_getopt_lvl_sock_dontroute(env, descP);
break;
#endif
#if defined(SO_KEEPALIVE)
- case SOCKET_OPT_SOCK_KEEPALIVE:
- result = ngetopt_lvl_sock_keepalive(env, descP);
+ case ESOCK_OPT_SOCK_KEEPALIVE:
+ result = esock_getopt_lvl_sock_keepalive(env, descP);
break;
#endif
#if defined(SO_LINGER)
- case SOCKET_OPT_SOCK_LINGER:
- result = ngetopt_lvl_sock_linger(env, descP);
+ case ESOCK_OPT_SOCK_LINGER:
+ result = esock_getopt_lvl_sock_linger(env, descP);
break;
#endif
#if defined(SO_OOBINLINE)
- case SOCKET_OPT_SOCK_OOBINLINE:
- result = ngetopt_lvl_sock_oobinline(env, descP);
+ case ESOCK_OPT_SOCK_OOBINLINE:
+ result = esock_getopt_lvl_sock_oobinline(env, descP);
break;
#endif
#if defined(SO_PEEK_OFF)
- case SOCKET_OPT_SOCK_PEEK_OFF:
- result = ngetopt_lvl_sock_peek_off(env, descP);
+ case ESOCK_OPT_SOCK_PEEK_OFF:
+ result = esock_getopt_lvl_sock_peek_off(env, descP);
break;
#endif
#if defined(SO_PRIORITY)
- case SOCKET_OPT_SOCK_PRIORITY:
- result = ngetopt_lvl_sock_priority(env, descP);
+ case ESOCK_OPT_SOCK_PRIORITY:
+ result = esock_getopt_lvl_sock_priority(env, descP);
break;
#endif
#if defined(SO_PROTOCOL)
- case SOCKET_OPT_SOCK_PROTOCOL:
- result = ngetopt_lvl_sock_protocol(env, descP);
+ case ESOCK_OPT_SOCK_PROTOCOL:
+ result = esock_getopt_lvl_sock_protocol(env, descP);
break;
#endif
#if defined(SO_RCVBUF)
- case SOCKET_OPT_SOCK_RCVBUF:
- result = ngetopt_lvl_sock_rcvbuf(env, descP);
+ case ESOCK_OPT_SOCK_RCVBUF:
+ result = esock_getopt_lvl_sock_rcvbuf(env, descP);
break;
#endif
#if defined(SO_RCVLOWAT)
- case SOCKET_OPT_SOCK_RCVLOWAT:
- result = ngetopt_lvl_sock_rcvlowat(env, descP);
+ case ESOCK_OPT_SOCK_RCVLOWAT:
+ result = esock_getopt_lvl_sock_rcvlowat(env, descP);
break;
#endif
#if defined(SO_RCVTIMEO)
- case SOCKET_OPT_SOCK_RCVTIMEO:
- result = ngetopt_lvl_sock_rcvtimeo(env, descP);
+ case ESOCK_OPT_SOCK_RCVTIMEO:
+ result = esock_getopt_lvl_sock_rcvtimeo(env, descP);
break;
#endif
#if defined(SO_REUSEADDR)
- case SOCKET_OPT_SOCK_REUSEADDR:
- result = ngetopt_lvl_sock_reuseaddr(env, descP);
+ case ESOCK_OPT_SOCK_REUSEADDR:
+ result = esock_getopt_lvl_sock_reuseaddr(env, descP);
break;
#endif
#if defined(SO_REUSEPORT)
- case SOCKET_OPT_SOCK_REUSEPORT:
- result = ngetopt_lvl_sock_reuseport(env, descP);
+ case ESOCK_OPT_SOCK_REUSEPORT:
+ result = esock_getopt_lvl_sock_reuseport(env, descP);
break;
#endif
#if defined(SO_SNDBUF)
- case SOCKET_OPT_SOCK_SNDBUF:
- result = ngetopt_lvl_sock_sndbuf(env, descP);
+ case ESOCK_OPT_SOCK_SNDBUF:
+ result = esock_getopt_lvl_sock_sndbuf(env, descP);
break;
#endif
#if defined(SO_SNDLOWAT)
- case SOCKET_OPT_SOCK_SNDLOWAT:
- result = ngetopt_lvl_sock_sndlowat(env, descP);
+ case ESOCK_OPT_SOCK_SNDLOWAT:
+ result = esock_getopt_lvl_sock_sndlowat(env, descP);
break;
#endif
#if defined(SO_SNDTIMEO)
- case SOCKET_OPT_SOCK_SNDTIMEO:
- result = ngetopt_lvl_sock_sndtimeo(env, descP);
+ case ESOCK_OPT_SOCK_SNDTIMEO:
+ result = esock_getopt_lvl_sock_sndtimeo(env, descP);
break;
#endif
#if defined(SO_TIMESTAMP)
- case SOCKET_OPT_SOCK_TIMESTAMP:
- result = ngetopt_lvl_sock_timestamp(env, descP);
+ case ESOCK_OPT_SOCK_TIMESTAMP:
+ result = esock_getopt_lvl_sock_timestamp(env, descP);
break;
#endif
#if defined(SO_TYPE)
- case SOCKET_OPT_SOCK_TYPE:
- result = ngetopt_lvl_sock_type(env, descP);
+ case ESOCK_OPT_SOCK_TYPE:
+ result = esock_getopt_lvl_sock_type(env, descP);
break;
#endif
@@ -11268,7 +11941,7 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_socket -> done when"
+ ("SOCKET", "esock_getopt_lvl_socket -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -11278,51 +11951,52 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
#if defined(SO_ACCEPTCONN)
static
-ERL_NIF_TERM ngetopt_lvl_sock_acceptconn(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_acceptconn(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_ACCEPTCONN);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_ACCEPTCONN);
}
#endif
#if defined(SO_BINDTODEVICE)
static
-ERL_NIF_TERM ngetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sock_bindtodevice -> entry with\r\n") );
+ ("SOCKET", "esock_getopt_lvl_sock_bindtodevice -> entry with\r\n") );
- return ngetopt_str_opt(env, descP, SOL_SOCKET, SO_BROADCAST, IFNAMSIZ+1);
+ return esock_getopt_str_opt(env, descP,
+ SOL_SOCKET, SO_BINDTODEVICE, IFNAMSIZ+1);
}
#endif
#if defined(SO_BROADCAST)
static
-ERL_NIF_TERM ngetopt_lvl_sock_broadcast(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_broadcast(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_BROADCAST);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_BROADCAST);
}
#endif
#if defined(SO_DEBUG)
static
-ERL_NIF_TERM ngetopt_lvl_sock_debug(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_debug(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_DEBUG);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_DEBUG);
}
#endif
#if defined(SO_DOMAIN)
static
-ERL_NIF_TERM ngetopt_lvl_sock_domain(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_domain(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val;
@@ -11366,28 +12040,28 @@ ERL_NIF_TERM ngetopt_lvl_sock_domain(ErlNifEnv* env,
#if defined(SO_DONTROUTE)
static
-ERL_NIF_TERM ngetopt_lvl_sock_dontroute(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_dontroute(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_DONTROUTE);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_DONTROUTE);
}
#endif
#if defined(SO_KEEPALIVE)
static
-ERL_NIF_TERM ngetopt_lvl_sock_keepalive(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_keepalive(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_KEEPALIVE);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_KEEPALIVE);
}
#endif
#if defined(SO_LINGER)
static
-ERL_NIF_TERM ngetopt_lvl_sock_linger(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_linger(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
struct linger val;
@@ -11416,38 +12090,38 @@ ERL_NIF_TERM ngetopt_lvl_sock_linger(ErlNifEnv* env,
#if defined(SO_OOBINLINE)
static
-ERL_NIF_TERM ngetopt_lvl_sock_oobinline(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_oobinline(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_OOBINLINE);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_OOBINLINE);
}
#endif
#if defined(SO_PEEK_OFF)
static
-ERL_NIF_TERM ngetopt_lvl_sock_peek_off(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_peek_off(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_PEEK_OFF);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_PEEK_OFF);
}
#endif
#if defined(SO_PRIORITY)
static
-ERL_NIF_TERM ngetopt_lvl_sock_priority(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_priority(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_PRIORITY);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_PRIORITY);
}
#endif
#if defined(SO_PROTOCOL)
static
-ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_protocol(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val;
@@ -11462,7 +12136,14 @@ ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
} else {
switch (val) {
case IPPROTO_IP:
+#if defined(AF_LOCAL)
+ if (descP->domain == AF_LOCAL)
+ result = esock_make_ok2(env, esock_atom_default);
+ else
+ result = esock_make_ok2(env, esock_atom_ip);
+#else
result = esock_make_ok2(env, esock_atom_ip);
+#endif
break;
case IPPROTO_TCP:
@@ -11493,98 +12174,98 @@ ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
#if defined(SO_RCVBUF)
static
-ERL_NIF_TERM ngetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_rcvbuf(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_RCVBUF);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_RCVBUF);
}
#endif
#if defined(SO_RCVLOWAT)
static
-ERL_NIF_TERM ngetopt_lvl_sock_rcvlowat(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_rcvlowat(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_RCVLOWAT);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_RCVLOWAT);
}
#endif
#if defined(SO_RCVTIMEO)
static
-ERL_NIF_TERM ngetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO);
+ return esock_getopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO);
}
#endif
#if defined(SO_REUSEADDR)
static
-ERL_NIF_TERM ngetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_reuseaddr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEADDR);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEADDR);
}
#endif
#if defined(SO_REUSEPORT)
static
-ERL_NIF_TERM ngetopt_lvl_sock_reuseport(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_reuseport(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEPORT);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_REUSEPORT);
}
#endif
#if defined(SO_SNDBUF)
static
-ERL_NIF_TERM ngetopt_lvl_sock_sndbuf(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_sndbuf(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_SNDBUF);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_SNDBUF);
}
#endif
#if defined(SO_SNDLOWAT)
static
-ERL_NIF_TERM ngetopt_lvl_sock_sndlowat(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_sndlowat(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, SOL_SOCKET, SO_SNDLOWAT);
+ return esock_getopt_int_opt(env, descP, SOL_SOCKET, SO_SNDLOWAT);
}
#endif
#if defined(SO_SNDTIMEO)
static
-ERL_NIF_TERM ngetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO);
+ return esock_getopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO);
}
#endif
#if defined(SO_TIMESTAMP)
static
-ERL_NIF_TERM ngetopt_lvl_sock_timestamp(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_timestamp(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_SOCKET, SO_TIMESTAMP);
+ return esock_getopt_bool_opt(env, descP, SOL_SOCKET, SO_TIMESTAMP);
}
#endif
#if defined(SO_TYPE)
static
-ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sock_type(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result, reason;
int val;
@@ -11626,174 +12307,174 @@ ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_ip - Level *IP* option(s)
+/* esock_getopt_lvl_ip - Level *IP* option(s)
*/
static
-ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_ip(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_ip -> entry with"
+ ("SOCKET", "esock_getopt_lvl_ip -> entry with"
"\r\n eOpt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(IP_FREEBIND)
- case SOCKET_OPT_IP_FREEBIND:
- result = ngetopt_lvl_ip_freebind(env, descP);
+ case ESOCK_OPT_IP_FREEBIND:
+ result = esock_getopt_lvl_ip_freebind(env, descP);
break;
#endif
#if defined(IP_HDRINCL)
- case SOCKET_OPT_IP_HDRINCL:
- result = ngetopt_lvl_ip_hdrincl(env, descP);
+ case ESOCK_OPT_IP_HDRINCL:
+ result = esock_getopt_lvl_ip_hdrincl(env, descP);
break;
#endif
#if defined(IP_MINTTL)
- case SOCKET_OPT_IP_MINTTL:
- result = ngetopt_lvl_ip_minttl(env, descP);
+ case ESOCK_OPT_IP_MINTTL:
+ result = esock_getopt_lvl_ip_minttl(env, descP);
break;
#endif
#if defined(IP_MTU)
- case SOCKET_OPT_IP_MTU:
- result = ngetopt_lvl_ip_mtu(env, descP);
+ case ESOCK_OPT_IP_MTU:
+ result = esock_getopt_lvl_ip_mtu(env, descP);
break;
#endif
#if defined(IP_MTU_DISCOVER)
- case SOCKET_OPT_IP_MTU_DISCOVER:
- result = ngetopt_lvl_ip_mtu_discover(env, descP);
+ case ESOCK_OPT_IP_MTU_DISCOVER:
+ result = esock_getopt_lvl_ip_mtu_discover(env, descP);
break;
#endif
#if defined(IP_MULTICAST_ALL)
- case SOCKET_OPT_IP_MULTICAST_ALL:
- result = ngetopt_lvl_ip_multicast_all(env, descP);
+ case ESOCK_OPT_IP_MULTICAST_ALL:
+ result = esock_getopt_lvl_ip_multicast_all(env, descP);
break;
#endif
#if defined(IP_MULTICAST_IF)
- case SOCKET_OPT_IP_MULTICAST_IF:
- result = ngetopt_lvl_ip_multicast_if(env, descP);
+ case ESOCK_OPT_IP_MULTICAST_IF:
+ result = esock_getopt_lvl_ip_multicast_if(env, descP);
break;
#endif
#if defined(IP_MULTICAST_LOOP)
- case SOCKET_OPT_IP_MULTICAST_LOOP:
- result = ngetopt_lvl_ip_multicast_loop(env, descP);
+ case ESOCK_OPT_IP_MULTICAST_LOOP:
+ result = esock_getopt_lvl_ip_multicast_loop(env, descP);
break;
#endif
#if defined(IP_MULTICAST_TTL)
- case SOCKET_OPT_IP_MULTICAST_TTL:
- result = ngetopt_lvl_ip_multicast_ttl(env, descP);
+ case ESOCK_OPT_IP_MULTICAST_TTL:
+ result = esock_getopt_lvl_ip_multicast_ttl(env, descP);
break;
#endif
#if defined(IP_NODEFRAG)
- case SOCKET_OPT_IP_NODEFRAG:
- result = ngetopt_lvl_ip_nodefrag(env, descP);
+ case ESOCK_OPT_IP_NODEFRAG:
+ result = esock_getopt_lvl_ip_nodefrag(env, descP);
break;
#endif
#if defined(IP_PKTINFO)
- case SOCKET_OPT_IP_PKTINFO:
- result = ngetopt_lvl_ip_pktinfo(env, descP);
+ case ESOCK_OPT_IP_PKTINFO:
+ result = esock_getopt_lvl_ip_pktinfo(env, descP);
break;
#endif
#if defined(IP_RECVDSTADDR)
- case SOCKET_OPT_IP_RECVDSTADDR:
- result = ngetopt_lvl_ip_recvdstaddr(env, descP);
+ case ESOCK_OPT_IP_RECVDSTADDR:
+ result = esock_getopt_lvl_ip_recvdstaddr(env, descP);
break;
#endif
#if defined(IP_RECVERR)
- case SOCKET_OPT_IP_RECVERR:
- result = ngetopt_lvl_ip_recverr(env, descP);
+ case ESOCK_OPT_IP_RECVERR:
+ result = esock_getopt_lvl_ip_recverr(env, descP);
break;
#endif
#if defined(IP_RECVIF)
- case SOCKET_OPT_IP_RECVIF:
- result = ngetopt_lvl_ip_recvif(env, descP);
+ case ESOCK_OPT_IP_RECVIF:
+ result = esock_getopt_lvl_ip_recvif(env, descP);
break;
#endif
#if defined(IP_RECVOPTS)
- case SOCKET_OPT_IP_RECVOPTS:
- result = ngetopt_lvl_ip_recvopts(env, descP);
+ case ESOCK_OPT_IP_RECVOPTS:
+ result = esock_getopt_lvl_ip_recvopts(env, descP);
break;
#endif
#if defined(IP_RECVORIGDSTADDR)
- case SOCKET_OPT_IP_RECVORIGDSTADDR:
- result = ngetopt_lvl_ip_recvorigdstaddr(env, descP);
+ case ESOCK_OPT_IP_RECVORIGDSTADDR:
+ result = esock_getopt_lvl_ip_recvorigdstaddr(env, descP);
break;
#endif
#if defined(IP_RECVTOS)
- case SOCKET_OPT_IP_RECVTOS:
- result = ngetopt_lvl_ip_recvtos(env, descP);
+ case ESOCK_OPT_IP_RECVTOS:
+ result = esock_getopt_lvl_ip_recvtos(env, descP);
break;
#endif
#if defined(IP_RECVTTL)
- case SOCKET_OPT_IP_RECVTTL:
- result = ngetopt_lvl_ip_recvttl(env, descP);
+ case ESOCK_OPT_IP_RECVTTL:
+ result = esock_getopt_lvl_ip_recvttl(env, descP);
break;
#endif
#if defined(IP_RETOPTS)
- case SOCKET_OPT_IP_RETOPTS:
- result = ngetopt_lvl_ip_retopts(env, descP);
+ case ESOCK_OPT_IP_RETOPTS:
+ result = esock_getopt_lvl_ip_retopts(env, descP);
break;
#endif
#if defined(IP_ROUTER_ALERT)
- case SOCKET_OPT_IP_ROUTER_ALERT:
- result = ngetopt_lvl_ip_router_alert(env, descP);
+ case ESOCK_OPT_IP_ROUTER_ALERT:
+ result = esock_getopt_lvl_ip_router_alert(env, descP);
break;
#endif
#if defined(IP_SENDSRCADDR)
- case SOCKET_OPT_IP_SENDSRCADDR:
- result = ngetopt_lvl_ip_sendsrcaddr(env, descP);
+ case ESOCK_OPT_IP_SENDSRCADDR:
+ result = esock_getopt_lvl_ip_sendsrcaddr(env, descP);
break;
#endif
#if defined(IP_TOS)
- case SOCKET_OPT_IP_TOS:
- result = ngetopt_lvl_ip_tos(env, descP);
+ case ESOCK_OPT_IP_TOS:
+ result = esock_getopt_lvl_ip_tos(env, descP);
break;
#endif
#if defined(IP_TRANSPARENT)
- case SOCKET_OPT_IP_TRANSPARENT:
- result = ngetopt_lvl_ip_transparent(env, descP);
+ case ESOCK_OPT_IP_TRANSPARENT:
+ result = esock_getopt_lvl_ip_transparent(env, descP);
break;
#endif
#if defined(IP_TTL)
- case SOCKET_OPT_IP_TTL:
- result = ngetopt_lvl_ip_ttl(env, descP);
+ case ESOCK_OPT_IP_TTL:
+ result = esock_getopt_lvl_ip_ttl(env, descP);
break;
#endif
default:
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_ip -> unknown opt %d\r\n", eOpt) );
+ ("SOCKET", "esock_getopt_lvl_ip -> unknown opt %d\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_ip -> done when"
+ ("SOCKET", "esock_getopt_lvl_ip -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -11801,12 +12482,12 @@ ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
}
-/* ngetopt_lvl_ip_minttl - Level IP MINTTL option
+/* esock_getopt_lvl_ip_minttl - Level IP MINTTL option
*/
#if defined(IP_MINTTL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_minttl(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_minttl(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11814,17 +12495,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_minttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_int_opt(env, descP, level, IP_MINTTL);
+ return esock_getopt_int_opt(env, descP, level, IP_MINTTL);
}
#endif
-/* ngetopt_lvl_ip_freebind - Level IP FREEBIND option
+/* esock_getopt_lvl_ip_freebind - Level IP FREEBIND option
*/
#if defined(IP_FREEBIND)
static
-ERL_NIF_TERM ngetopt_lvl_ip_freebind(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_freebind(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11832,17 +12513,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_freebind(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_FREEBIND);
+ return esock_getopt_bool_opt(env, descP, level, IP_FREEBIND);
}
#endif
-/* ngetopt_lvl_ip_hdrincl - Level IP HDRINCL option
+/* esock_getopt_lvl_ip_hdrincl - Level IP HDRINCL option
*/
#if defined(IP_HDRINCL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_hdrincl(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_hdrincl(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11850,17 +12531,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_hdrincl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_HDRINCL);
+ return esock_getopt_bool_opt(env, descP, level, IP_HDRINCL);
}
#endif
-/* ngetopt_lvl_ip_mtu - Level IP MTU option
+/* esock_getopt_lvl_ip_mtu - Level IP MTU option
*/
#if defined(IP_MTU)
static
-ERL_NIF_TERM ngetopt_lvl_ip_mtu(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_mtu(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11868,17 +12549,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_mtu(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_int_opt(env, descP, level, IP_MTU);
+ return esock_getopt_int_opt(env, descP, level, IP_MTU);
}
#endif
-/* ngetopt_lvl_ip_mtu_discover - Level IP MTU_DISCOVER option
+/* esock_getopt_lvl_ip_mtu_discover - Level IP MTU_DISCOVER option
*/
#if defined(IP_MTU_DISCOVER)
static
-ERL_NIF_TERM ngetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eMtuDisc;
@@ -11907,12 +12588,12 @@ ERL_NIF_TERM ngetopt_lvl_ip_mtu_discover(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_ip_multicast_all - Level IP MULTICAST_ALL option
+/* esock_getopt_lvl_ip_multicast_all - Level IP MULTICAST_ALL option
*/
#if defined(IP_MULTICAST_ALL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_multicast_all(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_multicast_all(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11920,17 +12601,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_multicast_all(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_MULTICAST_ALL);
+ return esock_getopt_bool_opt(env, descP, level, IP_MULTICAST_ALL);
}
#endif
-/* ngetopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
+/* esock_getopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
*/
#if defined(IP_MULTICAST_IF)
static
-ERL_NIF_TERM ngetopt_lvl_ip_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eAddr;
@@ -11962,12 +12643,12 @@ ERL_NIF_TERM ngetopt_lvl_ip_multicast_if(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
+/* esock_getopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
*/
#if defined(IP_MULTICAST_LOOP)
static
-ERL_NIF_TERM ngetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11975,17 +12656,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_MULTICAST_LOOP);
+ return esock_getopt_bool_opt(env, descP, level, IP_MULTICAST_LOOP);
}
#endif
-/* ngetopt_lvl_ip_multicast_ttl - Level IP MULTICAST_TTL option
+/* esock_getopt_lvl_ip_multicast_ttl - Level IP MULTICAST_TTL option
*/
#if defined(IP_MULTICAST_TTL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -11993,17 +12674,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_multicast_ttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_int_opt(env, descP, level, IP_MULTICAST_TTL);
+ return esock_getopt_int_opt(env, descP, level, IP_MULTICAST_TTL);
}
#endif
-/* ngetopt_lvl_ip_nodefrag - Level IP NODEFRAG option
+/* esock_getopt_lvl_ip_nodefrag - Level IP NODEFRAG option
*/
#if defined(IP_NODEFRAG)
static
-ERL_NIF_TERM ngetopt_lvl_ip_nodefrag(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_nodefrag(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12011,17 +12692,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_nodefrag(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_NODEFRAG);
+ return esock_getopt_bool_opt(env, descP, level, IP_NODEFRAG);
}
#endif
-/* ngetopt_lvl_ip_pktinfo - Level IP PKTINFO option
+/* esock_getopt_lvl_ip_pktinfo - Level IP PKTINFO option
*/
#if defined(IP_PKTINFO)
static
-ERL_NIF_TERM ngetopt_lvl_ip_pktinfo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_pktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12029,17 +12710,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_pktinfo(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_PKTINFO);
+ return esock_getopt_bool_opt(env, descP, level, IP_PKTINFO);
}
#endif
-/* ngetopt_lvl_ip_recvtos - Level IP RECVTOS option
+/* esock_getopt_lvl_ip_recvtos - Level IP RECVTOS option
*/
#if defined(IP_RECVTOS)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvtos(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvtos(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12047,17 +12728,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvtos(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVTOS);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVTOS);
}
#endif
-/* ngetopt_lvl_ip_recvdstaddr - Level IP RECVDSTADDR option
+/* esock_getopt_lvl_ip_recvdstaddr - Level IP RECVDSTADDR option
*/
#if defined(IP_RECVDSTADDR)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12065,17 +12746,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvdstaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVDSTADDR);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVDSTADDR);
}
#endif
-/* ngetopt_lvl_ip_recverr - Level IP RECVERR option
+/* esock_getopt_lvl_ip_recverr - Level IP RECVERR option
*/
#if defined(IP_RECVERR)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recverr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12083,17 +12764,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recverr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVERR);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVERR);
}
#endif
-/* ngetopt_lvl_ip_recvif - Level IP RECVIF option
+/* esock_getopt_lvl_ip_recvif - Level IP RECVIF option
*/
#if defined(IP_RECVIF)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvif(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvif(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12101,17 +12782,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvif(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVIF);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVIF);
}
#endif
-/* ngetopt_lvl_ip_recvopt - Level IP RECVOPTS option
+/* esock_getopt_lvl_ip_recvopt - Level IP RECVOPTS option
*/
#if defined(IP_RECVOPTS)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvopts(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvopts(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12119,17 +12800,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvopts(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVOPTS);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVOPTS);
}
#endif
-/* ngetopt_lvl_ip_recvorigdstaddr - Level IP RECVORIGDSTADDR option
+/* esock_getopt_lvl_ip_recvorigdstaddr - Level IP RECVORIGDSTADDR option
*/
#if defined(IP_RECVORIGDSTADDR)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12137,17 +12818,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvorigdstaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVORIGDSTADDR);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVORIGDSTADDR);
}
#endif
-/* ngetopt_lvl_ip_recvttl - Level IP RECVTTL option
+/* esock_getopt_lvl_ip_recvttl - Level IP RECVTTL option
*/
#if defined(IP_RECVTTL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_recvttl(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_recvttl(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12155,17 +12836,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_recvttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RECVTTL);
+ return esock_getopt_bool_opt(env, descP, level, IP_RECVTTL);
}
#endif
-/* ngetopt_lvl_ip_retopts - Level IP RETOPTS option
+/* esock_getopt_lvl_ip_retopts - Level IP RETOPTS option
*/
#if defined(IP_RETOPTS)
static
-ERL_NIF_TERM ngetopt_lvl_ip_retopts(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_retopts(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12173,17 +12854,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_retopts(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_RETOPTS);
+ return esock_getopt_bool_opt(env, descP, level, IP_RETOPTS);
}
#endif
-/* ngetopt_lvl_ip_router_alert - Level IP ROUTER_ALERT option
+/* esock_getopt_lvl_ip_router_alert - Level IP ROUTER_ALERT option
*/
#if defined(IP_ROUTER_ALERT)
static
-ERL_NIF_TERM ngetopt_lvl_ip_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12191,17 +12872,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_router_alert(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_int_opt(env, descP, level, IP_ROUTER_ALERT);
+ return esock_getopt_int_opt(env, descP, level, IP_ROUTER_ALERT);
}
#endif
-/* ngetopt_lvl_ip_sendsrcaddr - Level IP SENDSRCADDR option
+/* esock_getopt_lvl_ip_sendsrcaddr - Level IP SENDSRCADDR option
*/
#if defined(IP_SENDSRCADDR)
static
-ERL_NIF_TERM ngetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12209,17 +12890,17 @@ ERL_NIF_TERM ngetopt_lvl_ip_sendsrcaddr(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_SENDSRCADDR);
+ return esock_getopt_bool_opt(env, descP, level, IP_SENDSRCADDR);
}
#endif
-/* ngetopt_lvl_ip_tos - Level IP TOS option
+/* esock_getopt_lvl_ip_tos - Level IP TOS option
*/
#if defined(IP_TOS)
static
-ERL_NIF_TERM ngetopt_lvl_ip_tos(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_tos(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12244,12 +12925,12 @@ ERL_NIF_TERM ngetopt_lvl_ip_tos(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_ip_transparent - Level IP TRANSPARENT option
+/* esock_getopt_lvl_ip_transparent - Level IP TRANSPARENT option
*/
#if defined(IP_TRANSPARENT)
static
-ERL_NIF_TERM ngetopt_lvl_ip_transparent(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_transparent(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12257,18 +12938,18 @@ ERL_NIF_TERM ngetopt_lvl_ip_transparent(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_bool_opt(env, descP, level, IP_TRANSPARENT);
+ return esock_getopt_bool_opt(env, descP, level, IP_TRANSPARENT);
}
#endif
-/* ngetopt_lvl_ip_ttl - Level IP TTL option
+/* esock_getopt_lvl_ip_ttl - Level IP TTL option
*/
#if defined(IP_TTL)
static
-ERL_NIF_TERM ngetopt_lvl_ip_ttl(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ip_ttl(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IP)
int level = SOL_IP;
@@ -12276,121 +12957,121 @@ ERL_NIF_TERM ngetopt_lvl_ip_ttl(ErlNifEnv* env,
int level = IPPROTO_IP;
#endif
- return ngetopt_int_opt(env, descP, level, IP_TTL);
+ return esock_getopt_int_opt(env, descP, level, IP_TTL);
}
#endif
-/* ngetopt_lvl_ipv6 - Level *IPv6* option(s)
+/* esock_getopt_lvl_ipv6 - Level *IPv6* option(s)
*/
#if defined(HAVE_IPV6)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_ipv6(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_ipv6 -> entry with"
+ ("SOCKET", "esock_getopt_lvl_ipv6 -> entry with"
"\r\n eOpt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(IPV6_AUTHHDR)
- case SOCKET_OPT_IPV6_AUTHHDR:
- result = ngetopt_lvl_ipv6_authhdr(env, descP);
+ case ESOCK_OPT_IPV6_AUTHHDR:
+ result = esock_getopt_lvl_ipv6_authhdr(env, descP);
break;
#endif
#if defined(IPV6_DSTOPTS)
- case SOCKET_OPT_IPV6_DSTOPTS:
- result = ngetopt_lvl_ipv6_dstopts(env, descP);
+ case ESOCK_OPT_IPV6_DSTOPTS:
+ result = esock_getopt_lvl_ipv6_dstopts(env, descP);
break;
#endif
#if defined(IPV6_FLOWINFO)
- case SOCKET_OPT_IPV6_FLOWINFO:
- result = ngetopt_lvl_ipv6_flowinfo(env, descP);
+ case ESOCK_OPT_IPV6_FLOWINFO:
+ result = esock_getopt_lvl_ipv6_flowinfo(env, descP);
break;
#endif
#if defined(IPV6_HOPLIMIT)
- case SOCKET_OPT_IPV6_HOPLIMIT:
- result = ngetopt_lvl_ipv6_hoplimit(env, descP);
+ case ESOCK_OPT_IPV6_HOPLIMIT:
+ result = esock_getopt_lvl_ipv6_hoplimit(env, descP);
break;
#endif
#if defined(IPV6_HOPOPTS)
- case SOCKET_OPT_IPV6_HOPOPTS:
- result = ngetopt_lvl_ipv6_hopopts(env, descP);
+ case ESOCK_OPT_IPV6_HOPOPTS:
+ result = esock_getopt_lvl_ipv6_hopopts(env, descP);
break;
#endif
#if defined(IPV6_MTU)
- case SOCKET_OPT_IPV6_MTU:
- result = ngetopt_lvl_ipv6_mtu(env, descP);
+ case ESOCK_OPT_IPV6_MTU:
+ result = esock_getopt_lvl_ipv6_mtu(env, descP);
break;
#endif
#if defined(IPV6_MTU_DISCOVER)
- case SOCKET_OPT_IPV6_MTU_DISCOVER:
- result = ngetopt_lvl_ipv6_mtu_discover(env, descP);
+ case ESOCK_OPT_IPV6_MTU_DISCOVER:
+ result = esock_getopt_lvl_ipv6_mtu_discover(env, descP);
break;
#endif
#if defined(IPV6_MULTICAST_HOPS)
- case SOCKET_OPT_IPV6_MULTICAST_HOPS:
- result = ngetopt_lvl_ipv6_multicast_hops(env, descP);
+ case ESOCK_OPT_IPV6_MULTICAST_HOPS:
+ result = esock_getopt_lvl_ipv6_multicast_hops(env, descP);
break;
#endif
#if defined(IPV6_MULTICAST_IF)
- case SOCKET_OPT_IPV6_MULTICAST_IF:
- result = ngetopt_lvl_ipv6_multicast_if(env, descP);
+ case ESOCK_OPT_IPV6_MULTICAST_IF:
+ result = esock_getopt_lvl_ipv6_multicast_if(env, descP);
break;
#endif
#if defined(IPV6_MULTICAST_LOOP)
- case SOCKET_OPT_IPV6_MULTICAST_LOOP:
- result = ngetopt_lvl_ipv6_multicast_loop(env, descP);
+ case ESOCK_OPT_IPV6_MULTICAST_LOOP:
+ result = esock_getopt_lvl_ipv6_multicast_loop(env, descP);
break;
#endif
#if defined(IPV6_RECVERR)
- case SOCKET_OPT_IPV6_RECVERR:
- result = ngetopt_lvl_ipv6_recverr(env, descP);
+ case ESOCK_OPT_IPV6_RECVERR:
+ result = esock_getopt_lvl_ipv6_recverr(env, descP);
break;
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
- case SOCKET_OPT_IPV6_RECVPKTINFO:
- result = ngetopt_lvl_ipv6_recvpktinfo(env, descP);
+ case ESOCK_OPT_IPV6_RECVPKTINFO:
+ result = esock_getopt_lvl_ipv6_recvpktinfo(env, descP);
break;
#endif
#if defined(IPV6_ROUTER_ALERT)
- case SOCKET_OPT_IPV6_ROUTER_ALERT:
- result = ngetopt_lvl_ipv6_router_alert(env, descP);
+ case ESOCK_OPT_IPV6_ROUTER_ALERT:
+ result = esock_getopt_lvl_ipv6_router_alert(env, descP);
break;
#endif
#if defined(IPV6_RTHDR)
- case SOCKET_OPT_IPV6_RTHDR:
- result = ngetopt_lvl_ipv6_rthdr(env, descP);
+ case ESOCK_OPT_IPV6_RTHDR:
+ result = esock_getopt_lvl_ipv6_rthdr(env, descP);
break;
#endif
#if defined(IPV6_UNICAST_HOPS)
- case SOCKET_OPT_IPV6_UNICAST_HOPS:
- result = ngetopt_lvl_ipv6_unicast_hops(env, descP);
+ case ESOCK_OPT_IPV6_UNICAST_HOPS:
+ result = esock_getopt_lvl_ipv6_unicast_hops(env, descP);
break;
#endif
#if defined(IPV6_V6ONLY)
- case SOCKET_OPT_IPV6_V6ONLY:
- result = ngetopt_lvl_ipv6_v6only(env, descP);
+ case ESOCK_OPT_IPV6_V6ONLY:
+ result = esock_getopt_lvl_ipv6_v6only(env, descP);
break;
#endif
@@ -12400,7 +13081,7 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_ipv6 -> done when"
+ ("SOCKET", "esock_getopt_lvl_ipv6 -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -12410,33 +13091,33 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
#if defined(IPV6_AUTHHDR)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_authhdr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_authhdr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, SOL_IPV6, IPV6_AUTHHDR);
+ return esock_getopt_bool_opt(env, descP, SOL_IPV6, IPV6_AUTHHDR);
}
#endif
#if defined(IPV6_DSTOPTS)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_dstopts(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_dstopts(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
#else
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_DSTOPTS);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_DSTOPTS);
}
#endif
#if defined(IPV6_FLOWINFO)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12444,15 +13125,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_flowinfo(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_FLOWINFO);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_FLOWINFO);
}
#endif
#if defined(IPV6_HOPLIMIT)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12460,15 +13141,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_HOPLIMIT);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_HOPLIMIT);
}
#endif
#if defined(IPV6_HOPOPTS)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_hopopts(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12476,15 +13157,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_hopopts(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_HOPOPTS);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_HOPOPTS);
}
#endif
#if defined(IPV6_MTU)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_mtu(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12492,17 +13173,17 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_int_opt(env, descP, level, IPV6_MTU);
+ return esock_getopt_int_opt(env, descP, level, IPV6_MTU);
}
#endif
-/* ngetopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
+/* esock_getopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
*/
#if defined(IPV6_MTU_DISCOVER)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eMtuDisc;
@@ -12533,8 +13214,8 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
#if defined(IPV6_MULTICAST_HOPS)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12542,15 +13223,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_hops(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_int_opt(env, descP, level, IPV6_MULTICAST_HOPS);
+ return esock_getopt_int_opt(env, descP, level, IPV6_MULTICAST_HOPS);
}
#endif
#if defined(IPV6_MULTICAST_IF)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12558,15 +13239,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_if(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_int_opt(env, descP, level, IPV6_MULTICAST_IF);
+ return esock_getopt_int_opt(env, descP, level, IPV6_MULTICAST_IF);
}
#endif
#if defined(IPV6_MULTICAST_LOOP)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12574,15 +13255,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_MULTICAST_LOOP);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_MULTICAST_LOOP);
}
#endif
#if defined(IPV6_RECVERR)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_recverr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_recverr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12590,15 +13271,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_recverr(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_RECVERR);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_RECVERR);
}
#endif
#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12611,15 +13292,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
int opt = IPV6_PKTINFO;
#endif
- return ngetopt_bool_opt(env, descP, level, opt);
+ return esock_getopt_bool_opt(env, descP, level, opt);
}
#endif
#if defined(IPV6_ROUTER_ALERT)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12627,15 +13308,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_int_opt(env, descP, level, IPV6_ROUTER_ALERT);
+ return esock_getopt_int_opt(env, descP, level, IPV6_ROUTER_ALERT);
}
#endif
#if defined(IPV6_RTHDR)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12643,15 +13324,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_RTHDR);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_RTHDR);
}
#endif
#if defined(IPV6_UNICAST_HOPS)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12659,15 +13340,15 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_int_opt(env, descP, level, IPV6_UNICAST_HOPS);
+ return esock_getopt_int_opt(env, descP, level, IPV6_UNICAST_HOPS);
}
#endif
#if defined(IPV6_V6ONLY)
static
-ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_ipv6_v6only(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
#if defined(SOL_IPV6)
int level = SOL_IPV6;
@@ -12675,7 +13356,7 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
int level = IPPROTO_IPV6;
#endif
- return ngetopt_bool_opt(env, descP, level, IPV6_V6ONLY);
+ return esock_getopt_bool_opt(env, descP, level, IPV6_V6ONLY);
}
#endif
@@ -12684,31 +13365,31 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
-/* ngetopt_lvl_tcp - Level *TCP* option(s)
+/* esock_getopt_lvl_tcp - Level *TCP* option(s)
*/
static
-ERL_NIF_TERM ngetopt_lvl_tcp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_tcp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
switch (eOpt) {
#if defined(TCP_CONGESTION)
- case SOCKET_OPT_TCP_CONGESTION:
- result = ngetopt_lvl_tcp_congestion(env, descP);
+ case ESOCK_OPT_TCP_CONGESTION:
+ result = esock_getopt_lvl_tcp_congestion(env, descP);
break;
#endif
#if defined(TCP_MAXSEG)
- case SOCKET_OPT_TCP_MAXSEG:
- result = ngetopt_lvl_tcp_maxseg(env, descP);
+ case ESOCK_OPT_TCP_MAXSEG:
+ result = esock_getopt_lvl_tcp_maxseg(env, descP);
break;
#endif
#if defined(TCP_NODELAY)
- case SOCKET_OPT_TCP_NODELAY:
- result = ngetopt_lvl_tcp_nodelay(env, descP);
+ case ESOCK_OPT_TCP_NODELAY:
+ result = esock_getopt_lvl_tcp_nodelay(env, descP);
break;
#endif
@@ -12721,58 +13402,58 @@ ERL_NIF_TERM ngetopt_lvl_tcp(ErlNifEnv* env,
}
-/* ngetopt_lvl_tcp_congestion - Level TCP CONGESTION option
+/* esock_getopt_lvl_tcp_congestion - Level TCP CONGESTION option
*/
#if defined(TCP_CONGESTION)
static
-ERL_NIF_TERM ngetopt_lvl_tcp_congestion(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_tcp_congestion(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- int max = SOCKET_OPT_TCP_CONGESTION_NAME_MAX+1;
+ int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1;
- return ngetopt_str_opt(env, descP, IPPROTO_TCP, TCP_CONGESTION, max);
+ return esock_getopt_str_opt(env, descP, IPPROTO_TCP, TCP_CONGESTION, max);
}
#endif
-/* ngetopt_lvl_tcp_maxseg - Level TCP MAXSEG option
+/* esock_getopt_lvl_tcp_maxseg - Level TCP MAXSEG option
*/
#if defined(TCP_MAXSEG)
static
-ERL_NIF_TERM ngetopt_lvl_tcp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_tcp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, IPPROTO_TCP, TCP_MAXSEG);
+ return esock_getopt_int_opt(env, descP, IPPROTO_TCP, TCP_MAXSEG);
}
#endif
-/* ngetopt_lvl_tcp_nodelay - Level TCP NODELAY option
+/* esock_getopt_lvl_tcp_nodelay - Level TCP NODELAY option
*/
#if defined(TCP_NODELAY)
static
-ERL_NIF_TERM ngetopt_lvl_tcp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_tcp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, IPPROTO_TCP, TCP_NODELAY);
+ return esock_getopt_bool_opt(env, descP, IPPROTO_TCP, TCP_NODELAY);
}
#endif
-/* ngetopt_lvl_udp - Level *UDP* option(s)
+/* esock_getopt_lvl_udp - Level *UDP* option(s)
*/
static
-ERL_NIF_TERM ngetopt_lvl_udp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_udp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
switch (eOpt) {
#if defined(UDP_CORK)
- case SOCKET_OPT_UDP_CORK:
- result = ngetopt_lvl_udp_cork(env, descP);
+ case ESOCK_OPT_UDP_CORK:
+ result = esock_getopt_lvl_udp_cork(env, descP);
break;
#endif
@@ -12785,74 +13466,74 @@ ERL_NIF_TERM ngetopt_lvl_udp(ErlNifEnv* env,
}
-/* ngetopt_lvl_udp_cork - Level UDP CORK option
+/* esock_getopt_lvl_udp_cork - Level UDP CORK option
*/
#if defined(UDP_CORK)
static
-ERL_NIF_TERM ngetopt_lvl_udp_cork(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_udp_cork(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, IPPROTO_UDP, UDP_CORK);
+ return esock_getopt_bool_opt(env, descP, IPPROTO_UDP, UDP_CORK);
}
#endif
-/* ngetopt_lvl_sctp - Level *SCTP* option(s)
+/* esock_getopt_lvl_sctp - Level *SCTP* option(s)
*/
#if defined(HAVE_SCTP)
static
-ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
- ESockDescriptor* descP,
- int eOpt)
+ERL_NIF_TERM esock_getopt_lvl_sctp(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int eOpt)
{
ERL_NIF_TERM result;
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sctp -> entry with"
+ ("SOCKET", "esock_getopt_lvl_sctp -> entry with"
"\r\n opt: %d"
"\r\n", eOpt) );
switch (eOpt) {
#if defined(SCTP_ASSOCINFO)
- case SOCKET_OPT_SCTP_ASSOCINFO:
- result = ngetopt_lvl_sctp_associnfo(env, descP);
+ case ESOCK_OPT_SCTP_ASSOCINFO:
+ result = esock_getopt_lvl_sctp_associnfo(env, descP);
break;
#endif
#if defined(SCTP_AUTOCLOSE)
- case SOCKET_OPT_SCTP_AUTOCLOSE:
- result = ngetopt_lvl_sctp_autoclose(env, descP);
+ case ESOCK_OPT_SCTP_AUTOCLOSE:
+ result = esock_getopt_lvl_sctp_autoclose(env, descP);
break;
#endif
#if defined(SCTP_DISABLE_FRAGMENTS)
- case SOCKET_OPT_SCTP_DISABLE_FRAGMENTS:
- result = ngetopt_lvl_sctp_disable_fragments(env, descP);
+ case ESOCK_OPT_SCTP_DISABLE_FRAGMENTS:
+ result = esock_getopt_lvl_sctp_disable_fragments(env, descP);
break;
#endif
#if defined(SCTP_INITMSG)
- case SOCKET_OPT_SCTP_INITMSG:
- result = ngetopt_lvl_sctp_initmsg(env, descP);
+ case ESOCK_OPT_SCTP_INITMSG:
+ result = esock_getopt_lvl_sctp_initmsg(env, descP);
break;
#endif
#if defined(SCTP_MAXSEG)
- case SOCKET_OPT_SCTP_MAXSEG:
- result = ngetopt_lvl_sctp_maxseg(env, descP);
+ case ESOCK_OPT_SCTP_MAXSEG:
+ result = esock_getopt_lvl_sctp_maxseg(env, descP);
break;
#endif
#if defined(SCTP_NODELAY)
- case SOCKET_OPT_SCTP_NODELAY:
- result = ngetopt_lvl_sctp_nodelay(env, descP);
+ case ESOCK_OPT_SCTP_NODELAY:
+ result = esock_getopt_lvl_sctp_nodelay(env, descP);
break;
#endif
#if defined(SCTP_RTOINFO)
- case SOCKET_OPT_SCTP_RTOINFO:
- result = ngetopt_lvl_sctp_rtoinfo(env, descP);
+ case ESOCK_OPT_SCTP_RTOINFO:
+ result = esock_getopt_lvl_sctp_rtoinfo(env, descP);
break;
#endif
@@ -12862,7 +13543,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sctp -> done when"
+ ("SOCKET", "esock_getopt_lvl_sctp -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -12870,7 +13551,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
}
-/* ngetopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
+/* esock_getopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
*
* <KOLLA>
*
@@ -12885,15 +13566,15 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
*/
#if defined(SCTP_ASSOCINFO)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
struct sctp_assocparams val;
SOCKOPTLEN_T valSz = sizeof(val);
int res;
- SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_associnfo -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_getopt_lvl_sctp_associnfo -> entry\r\n") );
sys_memzero((char*) &val, valSz);
res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_ASSOCINFO, &val, &valSz);
@@ -12922,7 +13603,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sctp_associnfo -> done with"
+ ("SOCKET", "esock_getopt_lvl_sctp_associnfo -> done with"
"\r\n res: %d"
"\r\n result: %T"
"\r\n", res, result) );
@@ -12932,44 +13613,45 @@ ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
+/* esock_getopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
*/
#if defined(SCTP_AUTOCLOSE)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_autoclose(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_autoclose(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_AUTOCLOSE);
+ return esock_getopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_AUTOCLOSE);
}
#endif
-/* ngetopt_lvl_sctp_disable_fragments - Level SCTP DISABLE:FRAGMENTS option
+/* esock_getopt_lvl_sctp_disable_fragments - Level SCTP DISABLE:FRAGMENTS option
*/
#if defined(SCTP_DISABLE_FRAGMENTS)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS);
+ return esock_getopt_bool_opt(env, descP,
+ IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS);
}
#endif
-/* ngetopt_lvl_sctp_initmsg - Level SCTP INITMSG option
+/* esock_getopt_lvl_sctp_initmsg - Level SCTP INITMSG option
*
*/
#if defined(SCTP_INITMSG)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
struct sctp_initmsg val;
SOCKOPTLEN_T valSz = sizeof(val);
int res;
- SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_initmsg -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_getopt_lvl_sctp_initmsg -> entry\r\n") );
sys_memzero((char*) &val, valSz);
res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_INITMSG, &val, &valSz);
@@ -12996,7 +13678,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sctp_initmsg -> done with"
+ ("SOCKET", "esock_getopt_lvl_sctp_initmsg -> done with"
"\r\n res: %d"
"\r\n result: %T"
"\r\n", res, result) );
@@ -13006,31 +13688,31 @@ ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
#endif
-/* ngetopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
+/* esock_getopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
*/
#if defined(SCTP_MAXSEG)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_maxseg(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_maxseg(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_MAXSEG);
+ return esock_getopt_int_opt(env, descP, IPPROTO_SCTP, SCTP_MAXSEG);
}
#endif
-/* ngetopt_lvl_sctp_nodelay - Level SCTP NODELAY option
+/* esock_getopt_lvl_sctp_nodelay - Level SCTP NODELAY option
*/
#if defined(SCTP_NODELAY)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_nodelay(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- return ngetopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_NODELAY);
+ return esock_getopt_bool_opt(env, descP, IPPROTO_SCTP, SCTP_NODELAY);
}
#endif
-/* ngetopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
+/* esock_getopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
*
* <KOLLA>
*
@@ -13045,15 +13727,15 @@ ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
*/
#if defined(SCTP_RTOINFO)
static
-ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ERL_NIF_TERM result;
struct sctp_rtoinfo val;
SOCKOPTLEN_T valSz = sizeof(val);
int res;
- SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_rtoinfo -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_getopt_lvl_sctp_rtoinfo -> entry\r\n") );
sys_memzero((char*) &val, valSz);
res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_RTOINFO, &val, &valSz);
@@ -13079,7 +13761,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_lvl_sctp_rtoinfo -> done with"
+ ("SOCKET", "esock_getopt_lvl_sctp_rtoinfo -> done with"
"\r\n res: %d"
"\r\n result: %T"
"\r\n", res, result) );
@@ -13094,13 +13776,13 @@ ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
-/* ngetopt_bool_opt - get an (integer) bool option
+/* esock_getopt_bool_opt - get an (integer) bool option
*/
static
-ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt)
+ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt)
{
ERL_NIF_TERM result;
int val;
@@ -13108,7 +13790,7 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
int res;
/*
- SSDBG( descP, ("SOCKET", "ngetopt_bool_opt -> entry with"
+ SSDBG( descP, ("SOCKET", "esock_getopt_bool_opt -> entry with"
"\r\n: level: %d"
"\r\n: opt: %d"
"\r\n", level, opt) );
@@ -13125,7 +13807,7 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
}
/*
- SSDBG( descP, ("SOCKET", "ngetopt_bool_opt -> done when"
+ SSDBG( descP, ("SOCKET", "esock_getopt_bool_opt -> done when"
"\r\n: res: %d"
"\r\n: result: %T"
"\r\n", res, result) );
@@ -13135,13 +13817,13 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
}
-/* ngetopt_int_opt - get an integer option
+/* esock_getopt_int_opt - get an integer option
*/
static
-ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt)
+ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt)
{
ERL_NIF_TERM result;
int val;
@@ -13161,13 +13843,13 @@ ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
-/* ngetopt_timeval_opt - get an timeval option
+/* esock_getopt_timeval_opt - get an timeval option
*/
static
-ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt)
+ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt)
{
ERL_NIF_TERM result;
struct timeval val;
@@ -13175,7 +13857,7 @@ ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
int res;
SSDBG( descP,
- ("SOCKET", "ngetopt_timeval_opt -> entry with"
+ ("SOCKET", "esock_getopt_timeval_opt -> entry with"
"\r\n level: %d"
"\r\n opt: %d"
"\r\n", level, opt) );
@@ -13196,7 +13878,7 @@ ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_timeval_opt -> done when"
+ ("SOCKET", "esock_getopt_timeval_opt -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -13205,7 +13887,7 @@ ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
-/* ngetopt_str_opt - get an string option
+/* esock_getopt_str_opt - get an string option
*
* We provide the max size of the string. This is the
* size of the buffer we allocate for the value.
@@ -13214,11 +13896,11 @@ ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
*/
#if defined(USE_GETOPT_STR_OPT)
static
-ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
- ESockDescriptor* descP,
- int level,
- int opt,
- int max)
+ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ int level,
+ int opt,
+ int max)
{
ERL_NIF_TERM result;
char* val = MALLOC(max);
@@ -13226,7 +13908,7 @@ ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
int res;
SSDBG( descP,
- ("SOCKET", "ngetopt_str_opt -> entry with"
+ ("SOCKET", "esock_getopt_str_opt -> entry with"
"\r\n level: %d"
"\r\n opt: %d"
"\r\n max: %d"
@@ -13243,7 +13925,7 @@ ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
}
SSDBG( descP,
- ("SOCKET", "ngetopt_str_opt -> done when"
+ ("SOCKET", "esock_getopt_str_opt -> done when"
"\r\n result: %T"
"\r\n", result) );
@@ -13282,7 +13964,7 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 1) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -13294,7 +13976,7 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env,
"\r\n Socket: %T"
"\r\n", descP->sock, argv[0]) );
- res = nsockname(env, descP);
+ res = esock_sockname(env, descP);
SSDBG( descP, ("SOCKET", "nif_sockname -> done with res = %T\r\n", res) );
@@ -13306,8 +13988,8 @@ ERL_NIF_TERM nif_sockname(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM nsockname(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_sockname(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ESockAddress sa;
ESockAddress* saP = &sa;
@@ -13356,7 +14038,7 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env,
/* Extract arguments and perform preliminary validation */
if ((argc != 1) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
return enif_make_badarg(env);
}
@@ -13368,7 +14050,7 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env,
"\r\n Socket: %T"
"\r\n", descP->sock, argv[0]) );
- res = npeername(env, descP);
+ res = esock_peername(env, descP);
SSDBG( descP, ("SOCKET", "nif_peername -> done with res = %T\r\n", res) );
@@ -13380,8 +14062,8 @@ ERL_NIF_TERM nif_peername(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM npeername(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_peername(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
ESockAddress sa;
ESockAddress* saP = &sa;
@@ -13432,7 +14114,7 @@ ERL_NIF_TERM nif_cancel(ErlNifEnv* env,
sockRef = argv[0];
if ((argc != 3) ||
- !enif_get_resource(env, sockRef, sockets, (void**) &descP)) {
+ !ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
return enif_make_badarg(env);
}
op = argv[1];
@@ -13447,7 +14129,7 @@ ERL_NIF_TERM nif_cancel(ErlNifEnv* env,
"\r\n opRef: %T"
"\r\n", descP->sock, op, opRef) );
- result = ncancel(env, descP, op, sockRef, opRef);
+ result = esock_cancel(env, descP, op, sockRef, opRef);
SSDBG( descP,
("SOCKET", "nif_cancel -> done with result: "
@@ -13461,11 +14143,11 @@ ERL_NIF_TERM nif_cancel(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-ERL_NIF_TERM ncancel(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM op,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM op,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef)
{
/* <KOLLA>
*
@@ -13476,21 +14158,21 @@ ERL_NIF_TERM ncancel(ErlNifEnv* env,
* </KOLLA>
*/
if (COMPARE(op, esock_atom_connect) == 0) {
- return ncancel_connect(env, descP, opRef);
+ return esock_cancel_connect(env, descP, opRef);
} else if (COMPARE(op, esock_atom_accept) == 0) {
- return ncancel_accept(env, descP, sockRef, opRef);
+ return esock_cancel_accept(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_send) == 0) {
- return ncancel_send(env, descP, sockRef, opRef);
+ return esock_cancel_send(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_sendto) == 0) {
- return ncancel_send(env, descP, sockRef, opRef);
+ return esock_cancel_send(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_sendmsg) == 0) {
- return ncancel_send(env, descP, sockRef, opRef);
+ return esock_cancel_send(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_recv) == 0) {
- return ncancel_recv(env, descP, sockRef, opRef);
+ return esock_cancel_recv(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_recvfrom) == 0) {
- return ncancel_recv(env, descP, sockRef, opRef);
+ return esock_cancel_recv(env, descP, sockRef, opRef);
} else if (COMPARE(op, esock_atom_recvmsg) == 0) {
- return ncancel_recv(env, descP, sockRef, opRef);
+ return esock_cancel_recv(env, descP, sockRef, opRef);
} else {
return esock_make_error(env, esock_atom_einval);
}
@@ -13498,20 +14180,20 @@ ERL_NIF_TERM ncancel(ErlNifEnv* env,
-/* *** ncancel_connect ***
+/* *** esock_cancel_connect ***
*
*
*/
static
-ERL_NIF_TERM ncancel_connect(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef)
{
- return ncancel_write_select(env, descP, opRef);
+ return esock_cancel_write_select(env, descP, opRef);
}
-/* *** ncancel_accept ***
+/* *** esock_cancel_accept ***
*
* We have two different cases:
* *) Its the current acceptor
@@ -13522,15 +14204,15 @@ ERL_NIF_TERM ncancel_connect(ErlNifEnv* env,
*
*/
static
-ERL_NIF_TERM ncancel_accept(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef)
{
ERL_NIF_TERM res;
SSDBG( descP,
- ("SOCKET", "ncancel_accept -> entry with"
+ ("SOCKET", "esock_cancel_accept -> entry with"
"\r\n opRef: %T"
"\r\n %s"
"\r\n", opRef,
@@ -13540,9 +14222,9 @@ ERL_NIF_TERM ncancel_accept(ErlNifEnv* env,
if (descP->currentAcceptorP != NULL) {
if (COMPARE(opRef, descP->currentAcceptor.ref) == 0) {
- res = ncancel_accept_current(env, descP, sockRef);
+ res = esock_cancel_accept_current(env, descP, sockRef);
} else {
- res = ncancel_accept_waiting(env, descP, opRef);
+ res = esock_cancel_accept_waiting(env, descP, opRef);
}
} else {
/* Or badarg? */
@@ -13552,7 +14234,7 @@ ERL_NIF_TERM ncancel_accept(ErlNifEnv* env,
MUNLOCK(descP->accMtx);
SSDBG( descP,
- ("SOCKET", "ncancel_accept -> done with result:"
+ ("SOCKET", "esock_cancel_accept -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13565,27 +14247,27 @@ ERL_NIF_TERM ncancel_accept(ErlNifEnv* env,
* in the acceptor queue).
*/
static
-ERL_NIF_TERM ncancel_accept_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef)
+ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "ncancel_accept_current -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_cancel_accept_current -> entry\r\n") );
- DEMONP("ncancel_accept_current -> current acceptor",
+ DEMONP("esock_cancel_accept_current -> current acceptor",
env, descP, &descP->currentAcceptor.mon);
- res = ncancel_read_select(env, descP, descP->currentAcceptor.ref);
+ res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref);
SSDBG( descP, ("SOCKET",
- "ncancel_accept_current -> cancel res: %T\r\n", res) );
+ "esock_cancel_accept_current -> cancel res: %T\r\n", res) );
if (!activate_next_acceptor(env, descP, sockRef)) {
SSDBG( descP,
- ("SOCKET", "ncancel_accept_current -> no more writers\r\n") );
+ ("SOCKET", "esock_cancel_accept_current -> no more writers\r\n") );
- descP->state = SOCKET_STATE_LISTENING;
+ descP->state = ESOCK_STATE_LISTENING;
descP->currentAcceptorP = NULL;
descP->currentAcceptor.ref = esock_atom_undefined;
@@ -13593,7 +14275,7 @@ ERL_NIF_TERM ncancel_accept_current(ErlNifEnv* env,
esock_monitor_init(&descP->currentAcceptor.mon);
}
- SSDBG( descP, ("SOCKET", "ncancel_accept_current -> done with result:"
+ SSDBG( descP, ("SOCKET", "esock_cancel_accept_current -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13605,9 +14287,9 @@ ERL_NIF_TERM ncancel_accept_current(ErlNifEnv* env,
* remove them from the acceptor queue.
*/
static
-ERL_NIF_TERM ncancel_accept_waiting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef)
{
ErlNifPid caller;
@@ -13626,23 +14308,23 @@ ERL_NIF_TERM ncancel_accept_waiting(ErlNifEnv* env,
-/* *** ncancel_send ***
+/* *** esock_cancel_send ***
*
* Cancel a send operation.
* Its either the current writer or one of the waiting writers.
*/
static
-ERL_NIF_TERM ncancel_send(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef)
{
ERL_NIF_TERM res;
MLOCK(descP->writeMtx);
SSDBG( descP,
- ("SOCKET", "ncancel_send -> entry with"
+ ("SOCKET", "esock_cancel_send -> entry with"
"\r\n opRef: %T"
"\r\n %s"
"\r\n", opRef,
@@ -13650,9 +14332,9 @@ ERL_NIF_TERM ncancel_send(ErlNifEnv* env,
if (descP->currentWriterP != NULL) {
if (COMPARE(opRef, descP->currentWriter.ref) == 0) {
- res = ncancel_send_current(env, descP, sockRef);
+ res = esock_cancel_send_current(env, descP, sockRef);
} else {
- res = ncancel_send_waiting(env, descP, opRef);
+ res = esock_cancel_send_waiting(env, descP, opRef);
}
} else {
/* Or badarg? */
@@ -13662,7 +14344,7 @@ ERL_NIF_TERM ncancel_send(ErlNifEnv* env,
MUNLOCK(descP->writeMtx);
SSDBG( descP,
- ("SOCKET", "ncancel_send -> done with result:"
+ ("SOCKET", "esock_cancel_send -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13676,31 +14358,31 @@ ERL_NIF_TERM ncancel_send(ErlNifEnv* env,
* in the writer queue).
*/
static
-ERL_NIF_TERM ncancel_send_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef)
+ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "ncancel_send_current -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_cancel_send_current -> entry\r\n") );
- DEMONP("ncancel_send_current -> current writer",
+ DEMONP("esock_cancel_send_current -> current writer",
env, descP, &descP->currentWriter.mon);
- res = ncancel_write_select(env, descP, descP->currentWriter.ref);
+ res = esock_cancel_write_select(env, descP, descP->currentWriter.ref);
SSDBG( descP,
- ("SOCKET", "ncancel_send_current -> cancel res: %T\r\n", res) );
+ ("SOCKET", "esock_cancel_send_current -> cancel res: %T\r\n", res) );
if (!activate_next_writer(env, descP, sockRef)) {
SSDBG( descP,
- ("SOCKET", "ncancel_send_current -> no more writers\r\n") );
+ ("SOCKET", "esock_cancel_send_current -> no more writers\r\n") );
descP->currentWriterP = NULL;
descP->currentWriter.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentWriter.pid);
esock_monitor_init(&descP->currentWriter.mon);
}
- SSDBG( descP, ("SOCKET", "ncancel_send_current -> done with result:"
+ SSDBG( descP, ("SOCKET", "esock_cancel_send_current -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13712,9 +14394,9 @@ ERL_NIF_TERM ncancel_send_current(ErlNifEnv* env,
* remove them from the writer queue.
*/
static
-ERL_NIF_TERM ncancel_send_waiting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef)
{
ErlNifPid caller;
@@ -13733,23 +14415,23 @@ ERL_NIF_TERM ncancel_send_waiting(ErlNifEnv* env,
-/* *** ncancel_recv ***
+/* *** esock_cancel_recv ***
*
* Cancel a read operation.
* Its either the current reader or one of the waiting readers.
*/
static
-ERL_NIF_TERM ncancel_recv(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM opRef)
{
ERL_NIF_TERM res;
MLOCK(descP->readMtx);
SSDBG( descP,
- ("SOCKET", "ncancel_recv -> entry with"
+ ("SOCKET", "esock_cancel_recv -> entry with"
"\r\n opRef: %T"
"\r\n %s"
"\r\n", opRef,
@@ -13757,9 +14439,9 @@ ERL_NIF_TERM ncancel_recv(ErlNifEnv* env,
if (descP->currentReaderP != NULL) {
if (COMPARE(opRef, descP->currentReader.ref) == 0) {
- res = ncancel_recv_current(env, descP, sockRef);
+ res = esock_cancel_recv_current(env, descP, sockRef);
} else {
- res = ncancel_recv_waiting(env, descP, opRef);
+ res = esock_cancel_recv_waiting(env, descP, opRef);
}
} else {
/* Or badarg? */
@@ -13769,7 +14451,7 @@ ERL_NIF_TERM ncancel_recv(ErlNifEnv* env,
MUNLOCK(descP->readMtx);
SSDBG( descP,
- ("SOCKET", "ncancel_recv -> done with result:"
+ ("SOCKET", "esock_cancel_recv -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13782,31 +14464,31 @@ ERL_NIF_TERM ncancel_recv(ErlNifEnv* env,
* in the reader queue).
*/
static
-ERL_NIF_TERM ncancel_recv_current(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef)
+ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM res;
- SSDBG( descP, ("SOCKET", "ncancel_recv_current -> entry\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_cancel_recv_current -> entry\r\n") );
- DEMONP("ncancel_recv_current -> current reader",
+ DEMONP("esock_cancel_recv_current -> current reader",
env, descP, &descP->currentReader.mon);
- res = ncancel_read_select(env, descP, descP->currentReader.ref);
+ res = esock_cancel_read_select(env, descP, descP->currentReader.ref);
SSDBG( descP,
- ("SOCKET", "ncancel_recv_current -> cancel res: %T\r\n", res) );
+ ("SOCKET", "esock_cancel_recv_current -> cancel res: %T\r\n", res) );
if (!activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
- ("SOCKET", "ncancel_recv_current -> no more readers\r\n") );
+ ("SOCKET", "esock_cancel_recv_current -> no more readers\r\n") );
descP->currentReaderP = NULL;
descP->currentReader.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentReader.pid);
esock_monitor_init(&descP->currentReader.mon);
}
- SSDBG( descP, ("SOCKET", "ncancel_recv_current -> done with result:"
+ SSDBG( descP, ("SOCKET", "esock_cancel_recv_current -> done with result:"
"\r\n %T"
"\r\n", res) );
@@ -13818,9 +14500,9 @@ ERL_NIF_TERM ncancel_recv_current(ErlNifEnv* env,
* remove them from the reader queue.
*/
static
-ERL_NIF_TERM ncancel_recv_waiting(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef)
{
ErlNifPid caller;
@@ -13840,33 +14522,33 @@ ERL_NIF_TERM ncancel_recv_waiting(ErlNifEnv* env,
static
-ERL_NIF_TERM ncancel_read_select(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef)
+ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef)
{
- return ncancel_mode_select(env, descP, opRef,
- ERL_NIF_SELECT_READ,
- ERL_NIF_SELECT_READ_CANCELLED);
+ return esock_cancel_mode_select(env, descP, opRef,
+ ERL_NIF_SELECT_READ,
+ ERL_NIF_SELECT_READ_CANCELLED);
}
static
-ERL_NIF_TERM ncancel_write_select(ErlNifEnv* env,
+ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM opRef)
{
- return ncancel_mode_select(env, descP, opRef,
- ERL_NIF_SELECT_WRITE,
- ERL_NIF_SELECT_WRITE_CANCELLED);
+ return esock_cancel_mode_select(env, descP, opRef,
+ ERL_NIF_SELECT_WRITE,
+ ERL_NIF_SELECT_WRITE_CANCELLED);
}
static
-ERL_NIF_TERM ncancel_mode_select(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM opRef,
- int smode,
- int rmode)
+ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM opRef,
+ int smode,
+ int rmode)
{
int selectRes = esock_select_cancel(env, descP->sock, smode, descP);
@@ -13878,7 +14560,8 @@ ERL_NIF_TERM ncancel_mode_select(ErlNifEnv* env,
return esock_make_error(env, esock_atom_select_sent);
} else {
/* Stopped? */
- SSDBG( descP, ("SOCKET", "ncancel_mode_select -> failed: %d (0x%lX)"
+ SSDBG( descP, ("SOCKET",
+ "esock_cancel_mode_select -> failed: %d (0x%lX)"
"\r\n", selectRes, selectRes) );
return esock_make_error(env, esock_atom_einval);
}
@@ -14030,13 +14713,18 @@ ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
ssize_t dataSize,
ERL_NIF_TERM sockRef)
{
- cnt_inc(&descP->writePkgCnt, 1);
- cnt_inc(&descP->writeByteCnt, written);
+ // cnt_inc(&descP->writePkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef,
+ atom_write_pkg, &descP->writePkgCnt, 1);
+ // cnt_inc(&descP->writeByteCnt, written);
+ SOCK_CNT_INC(env, descP, sockRef,
+ atom_write_byte, &descP->writeByteCnt, written);
if (descP->currentWriterP != NULL) {
DEMONP("send_check_ok -> current writer",
env, descP, &descP->currentWriter.mon);
esock_free_env("send_check_ok", descP->currentWriter.env);
+ descP->currentWriter.env = NULL;
}
SSDBG( descP,
@@ -14049,6 +14737,7 @@ ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
if (!activate_next_writer(env, descP, sockRef)) {
descP->currentWriterP = NULL;
+ ESOCK_ASSERT(!descP->currentWriter.env);
descP->currentWriter.env = NULL;
descP->currentWriter.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentWriter.pid);
@@ -14074,7 +14763,9 @@ ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
ESockRequestor req;
ERL_NIF_TERM reason;
- cnt_inc(&descP->writeFails, 1);
+ req.env = NULL;
+ // cnt_inc(&descP->writeFails, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1);
SSDBG( descP, ("SOCKET", "send_check_fail -> error: %d\r\n", saveErrno) );
@@ -14090,6 +14781,7 @@ ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
("SOCKET", "send_check_fail -> abort %T\r\n", req.pid) );
esock_send_abort_msg(env, sockRef, req.ref, req.env,
reason, &req.pid);
+ req.env = NULL;
DEMONP("send_check_fail -> pop'ed writer", env, descP, &req.mon);
}
}
@@ -14131,13 +14823,15 @@ ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
enif_set_pid_undefined(&descP->currentWriter.pid);
return esock_make_error(env, atom_exmon);
} else {
+ ESOCK_ASSERT(!descP->currentWriter.env);
descP->currentWriter.env = esock_alloc_env("current-writer");
descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef);
descP->currentWriterP = &descP->currentWriter;
}
}
- cnt_inc(&descP->writeWaits, 1);
+ // cnt_inc(&descP->writeWaits, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_write_waits, &descP->writeWaits, 1);
sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef);
@@ -14260,7 +14954,7 @@ char* recv_init_current_reader(ErlNifEnv* env,
enif_set_pid_undefined(&descP->currentReader.pid);
return str_exmon;
} else {
-
+ ESOCK_ASSERT(!descP->currentReader.env);
descP->currentReader.env = esock_alloc_env("current-reader");
descP->currentReader.ref = CP_TERM(descP->currentReader.env,
recvRef);
@@ -14341,6 +15035,7 @@ void recv_error_current_reader(ErlNifEnv* env,
{
ESockRequestor req;
+ req.env = NULL;
if (descP->currentReaderP != NULL) {
DEMONP("recv_error_current_reader -> current reader",
@@ -14352,6 +15047,7 @@ void recv_error_current_reader(ErlNifEnv* env,
req.pid) );
esock_send_abort_msg(env, sockRef, req.ref, req.env,
reason, &req.pid);
+ req.env = NULL;
DEMONP("recv_error_current_reader -> pop'ed reader",
env, descP, &req.mon);
}
@@ -14397,6 +15093,8 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
res = esock_make_error(env, atom_closed);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+
/*
* When a stream socket peer has performed an orderly shutdown,
* the return value will be 0 (the traditional "end-of-file" return).
@@ -14543,7 +15241,8 @@ ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
{
char* xres;
- cnt_inc(&descP->readByteCnt, read);
+ // cnt_inc(&descP->readByteCnt, read);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
if (descP->rNum > 0) {
@@ -14552,7 +15251,8 @@ ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
descP->rNumCnt = 0;
- cnt_inc(&descP->readPkgCnt, 1);
+ // cnt_inc(&descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
recv_update_current_reader(env, descP, sockRef);
@@ -14600,8 +15300,10 @@ ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
{
ERL_NIF_TERM data;
- cnt_inc(&descP->readPkgCnt, 1);
- cnt_inc(&descP->readByteCnt, read);
+ // cnt_inc(&descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ // cnt_inc(&descP->readByteCnt, read);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
recv_update_current_reader(env, descP, sockRef);
@@ -14638,6 +15340,10 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
SSDBG( descP, ("SOCKET", "recv_check_fail -> closed\r\n") );
+ // This is a bit overkill (to count here), but just in case...
+ // cnt_inc(&descP->readFails, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+
res = recv_check_fail_closed(env, descP, sockRef, recvRef);
} else if ((saveErrno == ERRNO_BLOCK) ||
@@ -14652,6 +15358,9 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
SSDBG( descP, ("SOCKET", "recv_check_fail -> errno: %d\r\n",
saveErrno) );
+ // cnt_inc(&descP->readFails, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+
res = recv_check_fail_gen(env, descP, saveErrno, sockRef);
}
@@ -14690,7 +15399,7 @@ ERL_NIF_TERM recv_check_fail_closed(ErlNifEnv* env,
*/
descP->closeLocal = FALSE;
- descP->state = SOCKET_STATE_CLOSING;
+ descP->state = ESOCK_STATE_CLOSING;
recv_error_current_reader(env, descP, sockRef, res);
@@ -14815,8 +15524,10 @@ ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
ERL_NIF_TERM data;
descP->rNumCnt = 0;
- cnt_inc(&descP->readPkgCnt, 1);
- cnt_inc(&descP->readByteCnt, read);
+ // cnt_inc(&descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ // cnt_inc(&descP->readByteCnt, read);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
recv_update_current_reader(env, descP, sockRef);
@@ -14859,7 +15570,8 @@ ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
data = MKBIN(env, bufP);
data = MKSBIN(env, data, 0, read);
- cnt_inc(&descP->readByteCnt, read);
+ // cnt_inc(&descP->readByteCnt, read);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
/* SELECT for more data */
@@ -14946,6 +15658,12 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
data = MKSBIN(env, data, 0, read);
}
+ // cnt_inc(&descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ // cnt_inc(&descP->readByteCnt, read);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
+
recv_update_current_reader(env, descP, sockRef);
res = esock_make_ok2(env, MKT2(env, eSockAddr, data));
@@ -15003,6 +15721,7 @@ ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
* *We* do never actually try to read 0 bytes from a stream socket!
*/
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
FREE_BIN(dataBufP); FREE_BIN(ctrlBufP);
@@ -15073,6 +15792,21 @@ ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
"recvmsg_check_result -> "
"(msghdr) encode failed: %s\r\n", xres) );
+ /* So this is a bit strange. We did "successfully" read 'read' bytes,
+ * but then we fail to process the message header. So what counters
+ * shall we increment?
+ * Only failure?
+ * Or only success (pkg and byte), since the read was "ok" (or was it?)
+ * Or all of them?
+ *
+ * For now, we increment all three...
+ */
+
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
+
recv_update_current_reader(env, descP, sockRef);
FREE_BIN(dataBufP); FREE_BIN(ctrlBufP);
@@ -15084,6 +15818,10 @@ ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "recvmsg_check_result -> (msghdr) encode ok\r\n") );
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
+
recv_update_current_reader(env, descP, sockRef);
res = esock_make_ok2(env, eMsgHdr);
@@ -15123,8 +15861,8 @@ char* encode_msghdr(ErlNifEnv* env,
"\r\n read: %d"
"\r\n", read) );
- /* The address is not used if we are connected,
- * so check (length = 0) before we try to encodel
+ /* The address is not used if we are connected (unless, maybe,
+ * family is 'local'), so check (length = 0) before we try to encodel
*/
if (msgHdrP->msg_namelen != 0) {
if ((xres = esock_encode_sockaddr(env,
@@ -16246,8 +16984,6 @@ char* encode_cmsghdr_data_ipv6(ErlNifEnv* env,
size_t dataLen,
ERL_NIF_TERM* eCMsgHdrData)
{
- char* xres;
-
switch (type) {
#if defined(IPV6_PKTINFO)
case IPV6_PKTINFO:
@@ -16255,6 +16991,7 @@ char* encode_cmsghdr_data_ipv6(ErlNifEnv* env,
struct in6_pktinfo* pktInfoP = (struct in6_pktinfo*) dataP;
ERL_NIF_TERM ifIndex = MKI(env, pktInfoP->ipi6_ifindex);
ERL_NIF_TERM addr;
+ char* xres;
if ((xres = esock_encode_ip6_address(env,
&pktInfoP->ipi6_addr,
@@ -16682,11 +17419,11 @@ BOOLEAN_T decode_native_get_opt(ErlNifEnv* env, ERL_NIF_TERM eVal,
if (COMPARE(nativeOptT[1], atom_int) == 0) {
SGDBG( ("SOCKET", "decode_native_get_opt -> int\r\n") );
- *valueType = SOCKET_OPT_VALUE_TYPE_INT;
+ *valueType = ESOCK_OPT_VALUE_TYPE_INT;
*valueSz = sizeof(int); // Just to be sure
} else if (COMPARE(nativeOptT[1], atom_bool) == 0) {
SGDBG( ("SOCKET", "decode_native_get_opt -> bool\r\n") );
- *valueType = SOCKET_OPT_VALUE_TYPE_BOOL;
+ *valueType = ESOCK_OPT_VALUE_TYPE_BOOL;
*valueSz = sizeof(int); // Just to be sure
} else {
return FALSE;
@@ -16694,7 +17431,7 @@ BOOLEAN_T decode_native_get_opt(ErlNifEnv* env, ERL_NIF_TERM eVal,
} else if (IS_NUM(env, nativeOptT[1])) {
if (GET_INT(env, nativeOptT[1], valueSz)) {
SGDBG( ("SOCKET", "decode_native_get_opt -> unspec\r\n") );
- *valueType = SOCKET_OPT_VALUE_TYPE_UNSPEC;
+ *valueType = ESOCK_OPT_VALUE_TYPE_UNSPEC;
} else {
return FALSE;
}
@@ -16761,11 +17498,13 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, HANDLE event)
{
ESockDescriptor* descP;
- if ((descP = enif_alloc_resource(sockets, sizeof(ESockDescriptor))) != NULL) {
+ if ((descP = enif_alloc_resource(esocks, sizeof(ESockDescriptor))) != NULL) {
char buf[64]; /* Buffer used for building the mutex name */
- // This needs to be released when the socket is closed!
- // descP->env = enif_alloc_env();
+ descP->pattern = ESOCK_DESC_PATTERN_CREATED;
+
+ enif_set_pid_undefined(&descP->connPid);
+ MON_INIT(&descP->connMon);
sprintf(buf, "esock[w,%d]", sock);
descP->writeMtx = MCREATE(buf);
@@ -16797,6 +17536,7 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, HANDLE event)
descP->readByteCnt = 0;
descP->readTries = 0;
descP->readWaits = 0;
+ descP->readFails = 0;
sprintf(buf, "esock[acc,%d]", sock);
descP->accMtx = MCREATE(buf);
@@ -16817,13 +17557,13 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, HANDLE event)
sprintf(buf, "esock[cfg,%d]", sock);
descP->cfgMtx = MCREATE(buf);
- descP->rBufSz = SOCKET_RECV_BUFFER_SIZE_DEFAULT;
+ descP->rBufSz = ESOCK_RECV_BUFFER_SIZE_DEFAULT;
descP->rNum = 0;
descP->rNumCnt = 0;
- descP->rCtrlSz = SOCKET_RECV_CTRL_BUFFER_SIZE_DEFAULT;
- descP->wCtrlSz = SOCKET_SEND_CTRL_BUFFER_SIZE_DEFAULT;
+ descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT;
+ descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT;
descP->iow = FALSE;
- descP->dbg = SOCKET_DEBUG_DEFAULT;
+ descP->dbg = ESOCK_DEBUG_DEFAULT;
descP->sock = sock;
descP->event = event;
@@ -16950,17 +17690,17 @@ static
BOOLEAN_T edomain2domain(int edomain, int* domain)
{
switch (edomain) {
- case SOCKET_DOMAIN_INET:
+ case ESOCK_DOMAIN_INET:
*domain = AF_INET;
break;
#if defined(HAVE_IN6) && defined(AF_INET6)
- case SOCKET_DOMAIN_INET6:
+ case ESOCK_DOMAIN_INET6:
*domain = AF_INET6;
break;
#endif
#ifdef HAVE_SYS_UN_H
- case SOCKET_DOMAIN_LOCAL:
+ case ESOCK_DOMAIN_LOCAL:
*domain = AF_UNIX;
break;
#endif
@@ -16982,20 +17722,20 @@ static
BOOLEAN_T etype2type(int etype, int* type)
{
switch (etype) {
- case SOCKET_TYPE_STREAM:
+ case ESOCK_TYPE_STREAM:
*type = SOCK_STREAM;
break;
- case SOCKET_TYPE_DGRAM:
+ case ESOCK_TYPE_DGRAM:
*type = SOCK_DGRAM;
break;
- case SOCKET_TYPE_RAW:
+ case ESOCK_TYPE_RAW:
*type = SOCK_RAW;
break;
#ifdef HAVE_SCTP
- case SOCKET_TYPE_SEQPACKET:
+ case ESOCK_TYPE_SEQPACKET:
*type = SOCK_SEQPACKET;
break;
#endif
@@ -17027,29 +17767,33 @@ BOOLEAN_T eproto2proto(ErlNifEnv* env,
}
switch (ep) {
- case SOCKET_PROTOCOL_IP:
+ case ESOCK_PROTOCOL_DEFAULT:
+ *proto = 0; // default - note that _IP also has the value 0...
+ break;
+
+ case ESOCK_PROTOCOL_IP:
*proto = IPPROTO_IP;
break;
- case SOCKET_PROTOCOL_TCP:
+ case ESOCK_PROTOCOL_TCP:
*proto = IPPROTO_TCP;
break;
- case SOCKET_PROTOCOL_UDP:
+ case ESOCK_PROTOCOL_UDP:
*proto = IPPROTO_UDP;
break;
#if defined(HAVE_SCTP)
- case SOCKET_PROTOCOL_SCTP:
+ case ESOCK_PROTOCOL_SCTP:
*proto = IPPROTO_SCTP;
break;
#endif
- case SOCKET_PROTOCOL_ICMP:
+ case ESOCK_PROTOCOL_ICMP:
*proto = IPPROTO_ICMP;
break;
- case SOCKET_PROTOCOL_IGMP:
+ case ESOCK_PROTOCOL_IGMP:
*proto = IPPROTO_IGMP;
break;
@@ -17158,47 +17902,47 @@ BOOLEAN_T esendflags2sendflags(unsigned int eflags, int* flags)
return TRUE;
}
- for (ef = SOCKET_SEND_FLAG_LOW; ef <= SOCKET_SEND_FLAG_HIGH; ef++) {
+ for (ef = ESOCK_SEND_FLAG_LOW; ef <= ESOCK_SEND_FLAG_HIGH; ef++) {
switch (ef) {
#if defined(MSG_CONFIRM)
- case SOCKET_SEND_FLAG_CONFIRM:
- if ((1 << SOCKET_SEND_FLAG_CONFIRM) & eflags)
+ case ESOCK_SEND_FLAG_CONFIRM:
+ if ((1 << ESOCK_SEND_FLAG_CONFIRM) & eflags)
tmp |= MSG_CONFIRM;
break;
#endif
#if defined(MSG_DONTROUTE)
- case SOCKET_SEND_FLAG_DONTROUTE:
- if ((1 << SOCKET_SEND_FLAG_DONTROUTE) & eflags)
+ case ESOCK_SEND_FLAG_DONTROUTE:
+ if ((1 << ESOCK_SEND_FLAG_DONTROUTE) & eflags)
tmp |= MSG_DONTROUTE;
break;
#endif
#if defined(MSG_EOR)
- case SOCKET_SEND_FLAG_EOR:
- if ((1 << SOCKET_SEND_FLAG_EOR) & eflags)
+ case ESOCK_SEND_FLAG_EOR:
+ if ((1 << ESOCK_SEND_FLAG_EOR) & eflags)
tmp |= MSG_EOR;
break;
#endif
#if defined(MSG_MORE)
- case SOCKET_SEND_FLAG_MORE:
- if ((1 << SOCKET_SEND_FLAG_MORE) & eflags)
+ case ESOCK_SEND_FLAG_MORE:
+ if ((1 << ESOCK_SEND_FLAG_MORE) & eflags)
tmp |= MSG_MORE;
break;
#endif
#if defined(MSG_NOSIGNAL)
- case SOCKET_SEND_FLAG_NOSIGNAL:
- if ((1 << SOCKET_SEND_FLAG_NOSIGNAL) & eflags)
+ case ESOCK_SEND_FLAG_NOSIGNAL:
+ if ((1 << ESOCK_SEND_FLAG_NOSIGNAL) & eflags)
tmp |= MSG_NOSIGNAL;
break;
#endif
#if defined(MSG_OOB)
- case SOCKET_SEND_FLAG_OOB:
- if ((1 << SOCKET_SEND_FLAG_OOB) & eflags)
+ case ESOCK_SEND_FLAG_OOB:
+ if ((1 << ESOCK_SEND_FLAG_OOB) & eflags)
tmp |= MSG_OOB;
break;
#endif
@@ -17234,7 +17978,7 @@ BOOLEAN_T erecvflags2recvflags(unsigned int eflags, int* flags)
return TRUE;
}
- for (ef = SOCKET_RECV_FLAG_LOW; ef <= SOCKET_RECV_FLAG_HIGH; ef++) {
+ for (ef = ESOCK_RECV_FLAG_LOW; ef <= ESOCK_RECV_FLAG_HIGH; ef++) {
SGDBG( ("SOCKET", "erecvflags2recvflags -> iteration"
"\r\n ef: %d"
@@ -17243,22 +17987,22 @@ BOOLEAN_T erecvflags2recvflags(unsigned int eflags, int* flags)
switch (ef) {
#if defined(MSG_CMSG_CLOEXEC)
- case SOCKET_RECV_FLAG_CMSG_CLOEXEC:
- if ((1 << SOCKET_RECV_FLAG_CMSG_CLOEXEC) & eflags)
+ case ESOCK_RECV_FLAG_CMSG_CLOEXEC:
+ if ((1 << ESOCK_RECV_FLAG_CMSG_CLOEXEC) & eflags)
tmp |= MSG_CMSG_CLOEXEC;
break;
#endif
#if defined(MSG_ERRQUEUE)
- case SOCKET_RECV_FLAG_ERRQUEUE:
- if ((1 << SOCKET_RECV_FLAG_ERRQUEUE) & eflags)
+ case ESOCK_RECV_FLAG_ERRQUEUE:
+ if ((1 << ESOCK_RECV_FLAG_ERRQUEUE) & eflags)
tmp |= MSG_ERRQUEUE;
break;
#endif
#if defined(MSG_OOB)
- case SOCKET_RECV_FLAG_OOB:
- if ((1 << SOCKET_RECV_FLAG_OOB) & eflags)
+ case ESOCK_RECV_FLAG_OOB:
+ if ((1 << ESOCK_RECV_FLAG_OOB) & eflags)
tmp |= MSG_OOB;
break;
#endif
@@ -17271,15 +18015,15 @@ BOOLEAN_T erecvflags2recvflags(unsigned int eflags, int* flags)
* </KOLLA>
*/
#if defined(MSG_PEEK)
- case SOCKET_RECV_FLAG_PEEK:
- if ((1 << SOCKET_RECV_FLAG_PEEK) & eflags)
+ case ESOCK_RECV_FLAG_PEEK:
+ if ((1 << ESOCK_RECV_FLAG_PEEK) & eflags)
tmp |= MSG_PEEK;
break;
#endif
#if defined(MSG_TRUNC)
- case SOCKET_RECV_FLAG_TRUNC:
- if ((1 << SOCKET_RECV_FLAG_TRUNC) & eflags)
+ case ESOCK_RECV_FLAG_TRUNC:
+ if ((1 << ESOCK_RECV_FLAG_TRUNC) & eflags)
tmp |= MSG_TRUNC;
break;
#endif
@@ -17305,15 +18049,15 @@ static
BOOLEAN_T ehow2how(unsigned int ehow, int* how)
{
switch (ehow) {
- case SOCKET_SHUTDOWN_HOW_RD:
+ case ESOCK_SHUTDOWN_HOW_RD:
*how = SHUT_RD;
break;
- case SOCKET_SHUTDOWN_HOW_WR:
+ case ESOCK_SHUTDOWN_HOW_WR:
*how = SHUT_WR;
break;
- case SOCKET_SHUTDOWN_HOW_RDWR:
+ case ESOCK_SHUTDOWN_HOW_RDWR:
*how = SHUT_RDWR;
break;
@@ -17326,6 +18070,59 @@ BOOLEAN_T ehow2how(unsigned int ehow, int* how)
+/* ecommand2command - convert erlang command to "native" command (and data)
+ */
+static
+BOOLEAN_T ecommand2command(ErlNifEnv* env,
+ ERL_NIF_TERM ecommand,
+ Uint16* command,
+ ERL_NIF_TERM* edata)
+{
+ size_t sz;
+ ERL_NIF_TERM ecmd;
+
+ if (!IS_MAP(env, ecommand)) {
+ SGDBG( ("SOCKET", "ecommand2command -> (e)command not a map\r\n") );
+ return FALSE;
+ }
+
+ /* The map shall have exactly two attrbutes:
+ * 'command' and 'data'
+ */
+ if (!enif_get_map_size(env, ecommand, &sz) || (sz != 2)) {
+ SGDBG( ("SOCKET", "ecommand2command -> comamnd map size invalid\r\n") );
+ return FALSE;
+ }
+
+ /* Get the command value, and transform into integer
+ * (might as well do that, since theer is no point in
+ * extracting the data if command is invalid).
+ */
+ if (!GET_MAP_VAL(env, ecommand, esock_atom_command, &ecmd)) {
+ SGDBG( ("SOCKET", "ecommand2command -> command attribute not found\r\n") );
+ return FALSE;
+ }
+ if (COMPARE(ecmd, esock_atom_debug) == 0) {
+ *command = ESOCK_CMD_DEBUG;
+ } else {
+ SGDBG( ("SOCKET", "ecommand2command -> unknown command %T\r\n", ecmd) );
+ return FALSE;
+ }
+
+ /* Get the command data value, we do *not* convert it to
+ * the native form (here) since it may "in theory" be complex.
+ */
+ if (!GET_MAP_VAL(env, ecommand, esock_atom_data, edata)) {
+ SGDBG( ("SOCKET", "ecommand2command -> (command) data not found\r\n") );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE)
/* strnlen doesn't exist everywhere */
/*
@@ -17341,6 +18138,25 @@ size_t my_strnlen(const char *s, size_t maxlen)
#endif
+/* Send an counter wrap message to the controlling process:
+ * A message in the form:
+ *
+ * {'$socket', Socket, counter_wrap, Counter :: atom()}
+ *
+ * This message will only be sent if the iow (Inform On Wrap) is TRUE.
+ */
+static
+char* esock_send_wrap_msg(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM cnt)
+{
+ ERL_NIF_TERM msg = mk_wrap_msg(env, sockRef, cnt);
+
+ return esock_send_msg(env, &descP->ctrlPid, msg, NULL);
+}
+
+
/* Send an close message to the specified process:
* A message in the form:
*
@@ -17438,6 +18254,22 @@ ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env,
}
+/* *** mk_wrap_msg ***
+ *
+ * Construct a counter wrap (socket) message. It has the form:
+ *
+ * {'$socket', Socket, counter_wrap, Counter}
+ *
+ */
+static
+ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM cnt)
+{
+ return mk_socket_msg(env, sockRef, atom_counter_wrap, cnt);
+}
+
+
/* *** mk_close_msg ***
*
* Construct a close (socket) message. It has the form:
@@ -17647,6 +18479,7 @@ int esock_select_cancel(ErlNifEnv* env,
esock_send_abort_msg(env, sockRef, \
reqP->ref, reqP->env, \
reason, &reqP->pid); \
+ reqP->env = NULL; \
\
} else { \
\
@@ -17745,7 +18578,7 @@ REQ_SEARCH4PID_FUNCS
reqP->pid = pid; \
if (MONP("reader_push -> " #F " request", \
env, descP, &pid, &reqP->mon) != 0) { \
- FREE(reqP); \
+ FREE(e); \
return esock_make_error(env, atom_exmon); \
} \
reqP->env = esock_alloc_env(#F "_push"); \
@@ -17822,6 +18655,9 @@ BOOLEAN_T requestor_pop(ESockRequestQueue* q,
{
ESockRequestQueueElement* e = qpop(q);
+ if (reqP->env)
+ esock_free_env("requestor_pop", reqP->env);
+
if (e != NULL) {
reqP->pid = e->data.pid;
reqP->mon = e->data.mon;
@@ -17933,6 +18769,8 @@ BOOLEAN_T qunqueue(ErlNifEnv* env,
}
}
+ if (e->data.env)
+ esock_free_env("qunqueue", e->data.env);
FREE(e);
return TRUE;
@@ -18074,27 +18912,58 @@ ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP)
* ----------------------------------------------------------------------
*/
+
+static void free_request_queue(ESockRequestQueue* q)
+{
+ while (q->first) {
+ ESockRequestQueueElement* free_me = q->first;
+ q->first = free_me->nextP;
+ if (free_me->data.env)
+ esock_free_env("dtor", free_me->data.env);
+ FREE(free_me);
+ }
+}
+
/* =========================================================================
- * socket_dtor - Callback function for resource destructor
+ * esock_dtor - Callback function for resource destructor
*
*/
static
-void socket_dtor(ErlNifEnv* env, void* obj)
+void esock_dtor(ErlNifEnv* env, void* obj)
{
#if !defined(__WIN32__)
ESockDescriptor* descP = (ESockDescriptor*) obj;
- MDESTROY(descP->writeMtx);
- MDESTROY(descP->readMtx);
- MDESTROY(descP->accMtx);
- MDESTROY(descP->closeMtx);
- MDESTROY(descP->cfgMtx);
+ MDESTROY(descP->writeMtx); descP->writeMtx = NULL;
+ MDESTROY(descP->readMtx); descP->readMtx = NULL;
+ MDESTROY(descP->accMtx); descP->accMtx = NULL;
+ MDESTROY(descP->closeMtx); descP->closeMtx = NULL;
+ MDESTROY(descP->cfgMtx); descP->cfgMtx = NULL;
+
+ if (descP->currentReader.env) {
+ esock_free_env("dtor reader", descP->currentReader.env);
+ descP->currentReader.env = NULL;
+ }
+ if (descP->currentWriter.env) {
+ esock_free_env("dtor writer", descP->currentWriter.env);
+ descP->currentWriter.env = NULL;
+ }
+ if (descP->currentAcceptor.env) {
+ esock_free_env("dtor acceptor", descP->currentAcceptor.env);
+ descP->currentAcceptor.env = NULL;
+ }
+ free_request_queue(&descP->readersQ);
+ free_request_queue(&descP->writersQ);
+ free_request_queue(&descP->acceptorsQ);
+
+ descP->state = ESOCK_STATE_DTOR;
+ descP->pattern = ESOCK_DESC_PATTERN_DTOR;
#endif
}
/* =========================================================================
- * socket_stop - Callback function for resource stop
+ * esock_stop - Callback function for resource stop
*
* When the socket is stopped, we need to inform:
*
@@ -18109,14 +18978,14 @@ void socket_dtor(ErlNifEnv* env, void* obj)
*
*/
static
-void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
+void esock_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
{
#if !defined(__WIN32__)
ESockDescriptor* descP = (ESockDescriptor*) obj;
ERL_NIF_TERM sockRef;
SSDBG( descP,
- ("SOCKET", "socket_stop -> entry when %s"
+ ("SOCKET", "esock_stop -> entry when %s"
"\r\n sock: %d (%d)"
"\r\n",
((is_direct_call) ? "called" : "scheduled"), descP->sock, fd) );
@@ -18129,7 +18998,7 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
MLOCK(descP->cfgMtx);
if (!is_direct_call) MLOCK(descP->closeMtx);
- SSDBG( descP, ("SOCKET", "socket_stop -> "
+ SSDBG( descP, ("SOCKET", "esock_stop -> "
"[%d, %T] all mutex(s) locked when counters:"
"\r\n writePkgCnt: %u"
"\r\n writeByteCnt: %u"
@@ -18153,7 +19022,7 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
descP->readWaits) );
sockRef = enif_make_resource(env, descP);
- descP->state = SOCKET_STATE_CLOSING; // Just in case...???
+ descP->state = ESOCK_STATE_CLOSING; // Just in case...???
descP->isReadable = FALSE;
descP->isWritable = FALSE;
@@ -18164,7 +19033,7 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
* there is no point to demonitor. Also, we do not actually
* have a monitor in that case...
*/
- DEMONP("socket_stop -> ctrl", env, descP, &descP->ctrlMon);
+ DEMONP("esock_stop -> ctrl", env, descP, &descP->ctrlMon);
@@ -18181,12 +19050,12 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
* writers waiting.
*/
- socket_stop_handle_current(env,
- "writer",
- descP, sockRef, &descP->currentWriter);
+ esock_stop_handle_current(env,
+ "writer",
+ descP, sockRef, &descP->currentWriter);
/* And also deal with the waiting writers (in the same way) */
- SSDBG( descP, ("SOCKET", "socket_stop -> handle waiting writer(s)\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_stop -> handle waiting writer(s)\r\n") );
inform_waiting_procs(env, "writer",
descP, sockRef, &descP->writersQ, TRUE, atom_closed);
}
@@ -18205,12 +19074,12 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
* readers waiting.
*/
- socket_stop_handle_current(env,
- "reader",
- descP, sockRef, &descP->currentReader);
+ esock_stop_handle_current(env,
+ "reader",
+ descP, sockRef, &descP->currentReader);
/* And also deal with the waiting readers (in the same way) */
- SSDBG( descP, ("SOCKET", "socket_stop -> handle waiting reader(s)\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_stop -> handle waiting reader(s)\r\n") );
inform_waiting_procs(env, "reader",
descP, sockRef, &descP->readersQ, TRUE, atom_closed);
}
@@ -18230,12 +19099,12 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
* acceptors waiting.
*/
- socket_stop_handle_current(env,
- "acceptor",
- descP, sockRef, &descP->currentAcceptor);
-
+ esock_stop_handle_current(env,
+ "acceptor",
+ descP, sockRef, &descP->currentAcceptor);
+
/* And also deal with the waiting acceptors (in the same way) */
- SSDBG( descP, ("SOCKET", "socket_stop -> handle waiting acceptor(s)\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_stop -> handle waiting acceptor(s)\r\n") );
inform_waiting_procs(env, "acceptor",
descP, sockRef, &descP->acceptorsQ, TRUE, atom_closed);
}
@@ -18259,7 +19128,7 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
esock_send_close_msg(env, descP, &descP->closerPid);
- DEMONP("socket_stop -> closer", env, descP, &descP->closerMon);
+ DEMONP("esock_stop -> closer", env, descP, &descP->closerMon);
} else {
@@ -18268,14 +19137,14 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
*/
if (descP->closeEnv != NULL)
- esock_free_env("socket_stop - close-env", descP->closeEnv);
+ esock_free_env("esock_stop - close-env", descP->closeEnv);
}
}
}
- SSDBG( descP, ("SOCKET", "socket_stop -> unlock all mutex(s)\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_stop -> unlock all mutex(s)\r\n") );
if (!is_direct_call) MUNLOCK(descP->closeMtx);
MUNLOCK(descP->cfgMtx);
@@ -18284,33 +19153,33 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
MUNLOCK(descP->writeMtx);
SSDBG( descP,
- ("SOCKET", "socket_stop -> done (%d, %d)\r\n", descP->sock, fd) );
+ ("SOCKET", "esock_stop -> done (%d, %d)\r\n", descP->sock, fd) );
#endif // if !defined(__WIN32__)
}
-/* *** socket_stop_handle_current ***
+/* *** esock_stop_handle_current ***
*
* Handle current requestor (reader, writer or acceptor) during
* socket stop.
*/
#if !defined(__WIN32__)
static
-void socket_stop_handle_current(ErlNifEnv* env,
- const char* role,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ESockRequestor* reqP)
+void esock_stop_handle_current(ErlNifEnv* env,
+ const char* role,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ESockRequestor* reqP)
{
- SSDBG( descP, ("SOCKET", "socket_stop -> handle current %s\r\n", role) );
+ SSDBG( descP, ("SOCKET", "esock_stop -> handle current %s\r\n", role) );
- DEMONP("socket_stop_handle_current", env, descP, &reqP->mon);
+ DEMONP("esock_stop_handle_current", env, descP, &reqP->mon);
if (COMPARE_PIDS(&descP->closerPid, &reqP->pid) != 0) {
- SSDBG( descP, ("SOCKET", "socket_stop_handle_current -> "
+ SSDBG( descP, ("SOCKET", "esock_stop_handle_current -> "
"send abort message to current %s %T\r\n",
role, reqP->pid) );
@@ -18321,6 +19190,7 @@ void socket_stop_handle_current(ErlNifEnv* env,
"current %s %T\r\n",
reqP->ref, role, reqP->pid);
}
+ reqP->env = NULL;
}
}
@@ -18376,6 +19246,7 @@ void inform_waiting_procs(ErlNifEnv* env,
currentP->data.pid);
}
+ currentP->data.env = NULL,
DEMONP("inform_waiting_procs -> current 'request'",
env, descP, &currentP->data.mon);
@@ -18393,21 +19264,21 @@ void inform_waiting_procs(ErlNifEnv* env,
/* =========================================================================
- * socket_down - Callback function for resource down (monitored processes)
+ * esock_down - Callback function for resource down (monitored processes)
*
*/
static
-void socket_down(ErlNifEnv* env,
- void* obj,
- const ErlNifPid* pid,
- const ErlNifMonitor* mon)
+void esock_down(ErlNifEnv* env,
+ void* obj,
+ const ErlNifPid* pid,
+ const ErlNifMonitor* mon)
{
#if !defined(__WIN32__)
ESockDescriptor* descP = (ESockDescriptor*) obj;
int sres;
ERL_NIF_TERM sockRef;
- SSDBG( descP, ("SOCKET", "socket_down -> entry with"
+ SSDBG( descP, ("SOCKET", "esock_down -> entry with"
"\r\n sock: %d"
"\r\n pid: %T"
"\r\n Close: %s (%s)"
@@ -18425,9 +19296,9 @@ void socket_down(ErlNifEnv* env,
*/
SSDBG( descP,
- ("SOCKET", "socket_down -> controlling process exit\r\n") );
+ ("SOCKET", "esock_down -> controlling process exit\r\n") );
- descP->state = SOCKET_STATE_CLOSING;
+ descP->state = ESOCK_STATE_CLOSING;
descP->closeLocal = TRUE;
descP->closerPid = *pid;
MON_INIT(&descP->closerMon);
@@ -18439,10 +19310,10 @@ void socket_down(ErlNifEnv* env,
/* We are done - we can finalize (socket close) directly */
SSDBG( descP,
("SOCKET",
- "socket_down -> [%d] stop called\r\n", descP->sock) );
+ "esock_down -> [%d] stop called\r\n", descP->sock) );
dec_socket(descP->domain, descP->type, descP->protocol);
- descP->state = SOCKET_STATE_CLOSED;
+ descP->state = ESOCK_STATE_CLOSED;
/* And finally close the socket.
* Since we close the socket because of an exiting owner,
@@ -18465,7 +19336,7 @@ void socket_down(ErlNifEnv* env,
descP->sock = INVALID_SOCKET;
descP->event = INVALID_EVENT;
- descP->state = SOCKET_STATE_CLOSED;
+ descP->state = ESOCK_STATE_CLOSED;
} else if (sres & ERL_NIF_SELECT_STOP_SCHEDULED) {
@@ -18476,7 +19347,7 @@ void socket_down(ErlNifEnv* env,
*/
SSDBG( descP,
("SOCKET",
- "socket_down -> [%d] stop scheduled\r\n",
+ "esock_down -> [%d] stop scheduled\r\n",
descP->sock) );
dec_socket(descP->domain, descP->type, descP->protocol);
@@ -18510,6 +19381,17 @@ void socket_down(ErlNifEnv* env,
MON2T(env, mon));
}
+ } else if (COMPARE_PIDS(&descP->connPid, pid) == 0) {
+
+ /* The connPid is only set during the connection.
+ * The same goes for the monitor (connMon).
+ */
+
+ descP->state = ESOCK_STATE_OPEN; /* restore state */
+ enif_set_pid_undefined(&descP->connPid);
+ DEMONP("esock_down -> connector",
+ env, descP, &descP->connMon);
+
} else {
/* check all operation queue(s): acceptor, writer and reader.
@@ -18518,43 +19400,43 @@ void socket_down(ErlNifEnv* env,
*
*/
- SSDBG( descP, ("SOCKET", "socket_down -> other process term\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_down -> other process term\r\n") );
sockRef = enif_make_resource(env, descP);
MLOCK(descP->accMtx);
if (descP->currentAcceptorP != NULL)
- socket_down_acceptor(env, descP, sockRef, pid);
+ esock_down_acceptor(env, descP, sockRef, pid);
MUNLOCK(descP->accMtx);
MLOCK(descP->writeMtx);
if (descP->currentWriterP != NULL)
- socket_down_writer(env, descP, sockRef, pid);
+ esock_down_writer(env, descP, sockRef, pid);
MUNLOCK(descP->writeMtx);
MLOCK(descP->readMtx);
if (descP->currentReaderP != NULL)
- socket_down_reader(env, descP, sockRef, pid);
+ esock_down_reader(env, descP, sockRef, pid);
MUNLOCK(descP->readMtx);
}
}
- SSDBG( descP, ("SOCKET", "socket_down -> done\r\n") );
+ SSDBG( descP, ("SOCKET", "esock_down -> done\r\n") );
#endif // if !defined(__WIN32__)
}
-/* *** socket_down_acceptor ***
+/* *** esock_down_acceptor ***
*
* Check and then handle a downed acceptor process.
*
*/
#if !defined(__WIN32__)
static
-void socket_down_acceptor(ErlNifEnv* env,
+void esock_down_acceptor(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pid)
@@ -18562,15 +19444,15 @@ void socket_down_acceptor(ErlNifEnv* env,
if (COMPARE_PIDS(&descP->currentAcceptor.pid, pid) == 0) {
SSDBG( descP, ("SOCKET",
- "socket_down_acceptor -> "
+ "esock_down_acceptor -> "
"current acceptor - try activate next\r\n") );
if (!activate_next_acceptor(env, descP, sockRef)) {
SSDBG( descP,
- ("SOCKET", "socket_down_acceptor -> no more writers\r\n") );
+ ("SOCKET", "esock_down_acceptor -> no more writers\r\n") );
- descP->state = SOCKET_STATE_LISTENING;
+ descP->state = ESOCK_STATE_LISTENING;
descP->currentAcceptorP = NULL;
descP->currentAcceptor.ref = esock_atom_undefined;
@@ -18583,7 +19465,7 @@ void socket_down_acceptor(ErlNifEnv* env,
/* Maybe unqueue one of the waiting acceptors */
SSDBG( descP, ("SOCKET",
- "socket_down_acceptor -> "
+ "esock_down_acceptor -> "
"not current acceptor - maybe a waiting acceptor\r\n") );
acceptor_unqueue(env, descP, pid);
@@ -18593,13 +19475,13 @@ void socket_down_acceptor(ErlNifEnv* env,
-/* *** socket_down_writer ***
+/* *** esock_down_writer ***
*
* Check and then handle a downed writer process.
*
*/
static
-void socket_down_writer(ErlNifEnv* env,
+void esock_down_writer(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pid)
@@ -18607,12 +19489,12 @@ void socket_down_writer(ErlNifEnv* env,
if (COMPARE_PIDS(&descP->currentWriter.pid, pid) == 0) {
SSDBG( descP, ("SOCKET",
- "socket_down_writer -> "
+ "esock_down_writer -> "
"current writer - try activate next\r\n") );
if (!activate_next_writer(env, descP, sockRef)) {
SSDBG( descP, ("SOCKET",
- "socket_down_writer -> no active writer\r\n") );
+ "esock_down_writer -> no active writer\r\n") );
descP->currentWriterP = NULL;
descP->currentWriter.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentWriter.pid);
@@ -18624,7 +19506,7 @@ void socket_down_writer(ErlNifEnv* env,
/* Maybe unqueue one of the waiting writer(s) */
SSDBG( descP, ("SOCKET",
- "socket_down_writer -> "
+ "esock_down_writer -> "
"not current writer - maybe a waiting writer\r\n") );
writer_unqueue(env, descP, pid);
@@ -18634,13 +19516,13 @@ void socket_down_writer(ErlNifEnv* env,
-/* *** socket_down_reader ***
+/* *** esock_down_reader ***
*
* Check and then handle a downed reader process.
*
*/
static
-void socket_down_reader(ErlNifEnv* env,
+void esock_down_reader(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
const ErlNifPid* pid)
@@ -18648,12 +19530,13 @@ void socket_down_reader(ErlNifEnv* env,
if (COMPARE_PIDS(&descP->currentReader.pid, pid) == 0) {
SSDBG( descP, ("SOCKET",
- "socket_down_reader -> "
+ "esock_down_reader -> "
"current reader - try activate next\r\n") );
if (!activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
- ("SOCKET", "ncancel_recv_current -> no more readers\r\n") );
+ ("SOCKET",
+ "esock_down_reader -> no more readers\r\n") );
descP->currentReaderP = NULL;
descP->currentReader.ref = esock_atom_undefined;
enif_set_pid_undefined(&descP->currentReader.pid);
@@ -18665,7 +19548,7 @@ void socket_down_reader(ErlNifEnv* env,
/* Maybe unqueue one of the waiting reader(s) */
SSDBG( descP, ("SOCKET",
- "socket_down_reader -> "
+ "esock_down_reader -> "
"not current reader - maybe a waiting reader\r\n") );
reader_unqueue(env, descP, pid);
@@ -18681,16 +19564,16 @@ void socket_down_reader(ErlNifEnv* env,
*/
static
-ErlNifFunc socket_funcs[] =
+ErlNifFunc esock_funcs[] =
{
// Some utility and support functions
{"nif_info", 0, nif_info, 0},
+ {"nif_info", 1, nif_info, 0},
{"nif_supports", 1, nif_supports, 0},
- // {"nif_debug", 1, nif_debug, 0},
- // {"nif_command", 1, nif_command, 0},
+ {"nif_command", 1, nif_command, 0},
// The proper "socket" interface
- // nif_open/1 is used when we already have a file descriptor
+ // nif_open/1 is (supposed to be) used when we already have a file descriptor
// {"nif_open", 1, nif_open, 0},
{"nif_open", 4, nif_open, 0},
{"nif_bind", 2, nif_bind, 0},
@@ -18733,7 +19616,7 @@ BOOLEAN_T extract_debug(ErlNifEnv* env,
*/
ERL_NIF_TERM debug = MKA(env, "debug");
- return esock_extract_bool_from_map(env, map, debug, SOCKET_GLOBAL_DEBUG_DEFAULT);
+ return esock_extract_bool_from_map(env, map, debug, ESOCK_GLOBAL_DEBUG_DEFAULT);
}
static
@@ -18746,7 +19629,7 @@ BOOLEAN_T extract_iow(ErlNifEnv* env,
*/
ERL_NIF_TERM iow = MKA(env, "iow");
- return esock_extract_bool_from_map(env, map, iow, SOCKET_NIF_IOW_DEFAULT);
+ return esock_extract_bool_from_map(env, map, iow, ESOCK_NIF_IOW_DEFAULT);
}
#endif // if !defined(__WIN32__)
@@ -18767,7 +19650,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
data.iow = extract_iow(env, load_info);
/* +++ Global Counters +++ */
- data.cntMtx = MCREATE("socket[gcnt]");
+ data.cntMtx = MCREATE("esock[gcnt]");
data.numSockets = 0;
data.numTypeDGrams = 0;
data.numTypeStreams = 0;
@@ -18794,13 +19677,21 @@ GLOBAL_ERROR_REASON_ATOMS
#undef GLOBAL_ATOM_DECL
esock_atom_socket_tag = MKA(env, "$socket");
- sockets = enif_open_resource_type_x(env,
- "sockets",
- &socketInit,
- ERL_NIF_RT_CREATE,
- NULL);
+ esocks = enif_open_resource_type_x(env,
+ "sockets",
+ &esockInit,
+ ERL_NIF_RT_CREATE,
+ NULL);
- return !sockets;
+ return !esocks;
}
-ERL_NIF_INIT(socket, socket_funcs, on_load, NULL, NULL, NULL)
+/*
+ * MODULE: socket (the erlang API/interface module)
+ * funcs: esock_funcs (defines the API of this nif)
+ * load: on_load (load this nif)
+ * upgrade: NULL (not used)
+ * NULL: THIS IS NOT USED
+ * unload: NULL (not used)
+ */
+ERL_NIF_INIT(socket, esock_funcs, on_load, NULL, NULL, NULL)
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c
index 8ad95cb6b7..54c310ecc7 100644
--- a/erts/emulator/nifs/common/socket_util.c
+++ b/erts/emulator/nifs/common/socket_util.c
@@ -35,6 +35,10 @@
#include "socket_util.h"
#include "socket_dbg.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
/* We don't have a "debug flag" to check here, so we
* should use the compile debug flag, whatever that is...
*/
@@ -51,12 +55,10 @@
extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */
-#if defined(CLOCK_REALTIME)
-static int realtime(struct timespec* tsP);
-static int timespec2str(char *buf,
- unsigned int len,
- struct timespec *ts);
+#if (defined(HAVE_LOCALTIME_R) && defined(HAVE_STRFTIME))
+#define ESOCK_USE_PRETTY_TIMESTAMP 1
#endif
+
static char* make_sockaddr_in4(ErlNifEnv* env,
ERL_NIF_TERM port,
@@ -739,16 +741,24 @@ char* esock_decode_ip4_address(ErlNifEnv* env,
"\r\n", eAddr) );
if (IS_ATOM(env, eAddr)) {
- /* This is either 'any' or 'loopback' */
+
+ /* This is either 'any' | 'broadcast' | 'loopback' */
if (COMPARE(esock_atom_loopback, eAddr) == 0) {
- UDBG( ("SUTIL", "esock_decode_ip4_address -> address: lookback\r\n") );
+ UDBG( ("SUTIL",
+ "esock_decode_ip4_address -> address: lookback\r\n") );
addr.s_addr = htonl(INADDR_LOOPBACK);
} else if (COMPARE(esock_atom_any, eAddr) == 0) {
- UDBG( ("SUTIL", "esock_decode_ip4_address -> address: any\r\n") );
- addr.s_addr = htonl(INADDR_ANY);
+ UDBG( ("SUTIL",
+ "esock_decode_ip4_address -> address: any\r\n") );
+ addr.s_addr = htonl(INADDR_ANY);
+ } else if (COMPARE(esock_atom_broadcast, eAddr) == 0) {
+ UDBG( ("SUTIL",
+ "esock_decode_ip4_address -> address: broadcast\r\n") );
+ addr.s_addr = htonl(INADDR_BROADCAST);
} else {
- UDBG( ("SUTIL", "esock_decode_ip4_address -> address: unknown\r\n") );
+ UDBG( ("SUTIL",
+ "esock_decode_ip4_address -> address: unknown\r\n") );
return ESOCK_STR_EINVAL;
}
@@ -984,9 +994,27 @@ char* esock_decode_timeval(ErlNifEnv* env,
if (!GET_LONG(env, eSec, &timeP->tv_sec))
return ESOCK_STR_EINVAL;
+#if (SIZEOF_INT == 4)
+ {
+ int usec;
+ if (!GET_INT(env, eUSec, &usec))
+ return ESOCK_STR_EINVAL;
+ timeP->tv_usec = (typeof(timeP->tv_usec)) usec;
+ }
+#elif (SIZEOF_LONG == 4)
+ {
+ long usec;
+ if (!GET_LONG(env, eUSec, &usec))
+ return ESOCK_STR_EINVAL;
+ timeP->tv_usec = (typeof(timeP->tv_usec)) usec;
+ }
+#else
+ /* Ok, we give up... */
if (!GET_LONG(env, eUSec, &timeP->tv_usec))
return ESOCK_STR_EINVAL;
+#endif
+
return NULL;
}
@@ -1510,10 +1538,7 @@ void esock_warning_msg( const char* format, ... )
{
va_list args;
char f[512 + sizeof(format)]; // This has to suffice...
-#if defined(CLOCK_REALTIME)
char stamp[64]; // Just in case...
- struct timespec ts;
-#endif
int res;
/*
@@ -1525,18 +1550,13 @@ void esock_warning_msg( const char* format, ... )
// 2018-06-29 12:13:21.232089
// 29-Jun-2018::13:47:25.097097
-#if defined(CLOCK_REALTIME)
- if (!realtime(&ts) &&
- (timespec2str(stamp, sizeof(stamp), &ts) == 0)) {
+ if (esock_timestamp(stamp, sizeof(stamp))) {
res = enif_snprintf(f, sizeof(f),
"=WARNING MSG==== %s ===\r\n%s",
stamp, format);
} else {
res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format);
}
-#else
- res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format);
-#endif
if (res > 0) {
va_start (args, format);
@@ -1549,43 +1569,52 @@ void esock_warning_msg( const char* format, ... )
}
-#if defined(CLOCK_REALTIME)
-static
-int realtime(struct timespec* tsP)
-{
- return clock_gettime(CLOCK_REALTIME, tsP);
-}
-
-
-/*
- * Convert a timespec struct into a readable/printable string.
+/* *** esock_timestamp ***
*
- * "%F::%T" => 2018-06-29 12:13:21[.232089]
- * "%d-%b-%Y::%T" => 29-Jun-2018::13:47:25.097097
+ * Create a timestamp string.
+ * If awailable, we use the localtime_r and strftime function(s)
+ * to produces a nice readable timestamp. But if not (awailable),
+ * it produces a timestamp in the form of an "Epoch" (A real epoch
+ * is the number of seconds since 1/1 1970, but our timestamp is
+ * the number micro seconds since 1/1 1970).
*/
-static
-int timespec2str(char *buf, unsigned int len, struct timespec *ts)
-{
- int ret, buflen;
- struct tm t;
- tzset();
- if (localtime_r(&(ts->tv_sec), &t) == NULL)
- return 1;
+extern
+BOOLEAN_T esock_timestamp(char *buf, unsigned int len)
+{
+ int ret;
+ ErlNifTime monTime = enif_monotonic_time(ERL_NIF_USEC);
+ ErlNifTime offTime = enif_time_offset(ERL_NIF_USEC);
+ ErlNifTime time = monTime + offTime;
+#if defined(ESOCK_USE_PRETTY_TIMESTAMP)
+ time_t sec = time / 1000000; // (if _MSEC) sec = time / 1000;
+ time_t usec = time % 1000000; // (if _MSEC) msec = time % 1000;
+ int buflen;
+ struct tm t;
+
+ if (localtime_r(&sec, &t) == NULL)
+ return FALSE;
- ret = strftime(buf, len, "%d-%B-%Y::%T", &t);
- if (ret == 0)
- return 2;
- len -= ret - 1;
- buflen = strlen(buf);
+ ret = strftime(buf, len, "%d-%B-%Y::%T", &t);
+ if (ret == 0)
+ return FALSE;
+ len -= ret - 1;
+ buflen = strlen(buf);
- ret = snprintf(&buf[buflen], len, ".%06ld", ts->tv_nsec/1000);
- if (ret >= len)
- return 3;
+ ret = enif_snprintf(&buf[buflen], len, ".%06b64d", usec);
+ if (ret >= len)
+ return FALSE;
- return 0;
-}
+ return TRUE;
+#else
+ ret = enif_snprintf(buf, len, "%b64d", time);
+ if (ret == 0)
+ return FALSE;
+ else
+ return TRUE;
#endif
+}
+
/* =================================================================== *
@@ -1653,7 +1682,7 @@ char* make_sockaddr_un(ErlNifEnv* env,
ERL_NIF_TERM* sa)
{
ERL_NIF_TERM keys[] = {esock_atom_family, esock_atom_path};
- ERL_NIF_TERM vals[] = {esock_atom_inet, path};
+ ERL_NIF_TERM vals[] = {esock_atom_local, path};
unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h
index 84b1c8085f..2688a920c4 100644
--- a/erts/emulator/nifs/common/socket_util.h
+++ b/erts/emulator/nifs/common/socket_util.h
@@ -199,6 +199,9 @@ extern
ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err);
extern
+BOOLEAN_T esock_timestamp(char *buf, unsigned int len);
+
+extern
void esock_warning_msg(const char* format, ... );
diff --git a/erts/emulator/pcre/LICENCE b/erts/emulator/pcre/LICENCE
index f6ef7fd766..760a6666b6 100644
--- a/erts/emulator/pcre/LICENCE
+++ b/erts/emulator/pcre/LICENCE
@@ -25,7 +25,7 @@ Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2018 University of Cambridge
+Copyright (c) 1997-2019 University of Cambridge
All rights reserved.
@@ -34,9 +34,9 @@ PCRE JUST-IN-TIME COMPILATION SUPPORT
Written by: Zoltan Herczeg
Email local part: hzmester
-Emain domain: freemail.hu
+Email domain: freemail.hu
-Copyright(c) 2010-2018 Zoltan Herczeg
+Copyright(c) 2010-2019 Zoltan Herczeg
All rights reserved.
@@ -45,9 +45,9 @@ STACK-LESS JUST-IN-TIME COMPILER
Written by: Zoltan Herczeg
Email local part: hzmester
-Emain domain: freemail.hu
+Email domain: freemail.hu
-Copyright(c) 2009-2018 Zoltan Herczeg
+Copyright(c) 2009-2019 Zoltan Herczeg
All rights reserved.
diff --git a/erts/emulator/pcre/pcre-8.42.tar.bz2 b/erts/emulator/pcre/pcre-8.42.tar.bz2
deleted file mode 100644
index 61bfa38970..0000000000
--- a/erts/emulator/pcre/pcre-8.42.tar.bz2
+++ /dev/null
Binary files differ
diff --git a/erts/emulator/pcre/pcre-8.43.tar.bz2 b/erts/emulator/pcre/pcre-8.43.tar.bz2
new file mode 100644
index 0000000000..e20c601f71
--- /dev/null
+++ b/erts/emulator/pcre/pcre-8.43.tar.bz2
Binary files differ
diff --git a/erts/emulator/pcre/pcre.h b/erts/emulator/pcre/pcre.h
index 3563791223..49c9fc6dc8 100644
--- a/erts/emulator/pcre/pcre.h
+++ b/erts/emulator/pcre/pcre.h
@@ -43,9 +43,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */
#define PCRE_MAJOR 8
-#define PCRE_MINOR 42
+#define PCRE_MINOR 43
#define PCRE_PRERELEASE
-#define PCRE_DATE 2018-03-20
+#define PCRE_DATE 2019-02-23
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
@@ -240,6 +240,9 @@ with J. */
#define PCRE_UTF8_ERR20 20
#define PCRE_UTF8_ERR21 21
#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */
+#if defined(ERLANG_INTEGRATION)
+#define PCRE_UTF8_YIELD 23
+#endif
/* Specific error codes for UTF-16 validity checks */
diff --git a/erts/emulator/pcre/pcre_compile.c b/erts/emulator/pcre/pcre_compile.c
index ae7f6e2a2a..6ac222b27e 100644
--- a/erts/emulator/pcre/pcre_compile.c
+++ b/erts/emulator/pcre/pcre_compile.c
@@ -6,7 +6,7 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2016 University of Cambridge
+ Copyright (c) 1997-2018 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -3300,7 +3300,7 @@ for(;;)
if ((*xclass_flags & XCL_MAP) == 0)
{
/* No bits are set for characters < 256. */
- if (list[1] == 0) return TRUE;
+ if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0;
/* Might be an empty repeat. */
continue;
}
@@ -7643,6 +7643,8 @@ for (;; ptr++)
/* Can't determine a first byte now */
if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
+ zerofirstchar = firstchar;
+ zerofirstcharflags = firstcharflags;
continue;
@@ -8683,10 +8685,18 @@ do {
if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE;
}
- /* Positive forward assertions and conditions */
+ /* Positive forward assertion */
- else if (op == OP_ASSERT || op == OP_COND)
+ else if (op == OP_ASSERT)
+ {
+ if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
+ }
+
+ /* Condition; not anchored if no second branch */
+
+ else if (op == OP_COND)
{
+ if (scode[GET(scode,1)] != OP_ALT) return FALSE;
if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
}
diff --git a/erts/emulator/pcre/pcre_exec.c b/erts/emulator/pcre/pcre_exec.c
index 1946e97a72..55a7b377bf 100644
--- a/erts/emulator/pcre/pcre_exec.c
+++ b/erts/emulator/pcre/pcre_exec.c
@@ -6642,10 +6642,16 @@ typedef struct {
REAL_PCRE *Xre;
heapframe Xframe_zero; /* Always NO_RECURSE */
+ /* for yield in valid_utf() */
+
+ struct PRIV(valid_utf_ystate) valid_utf_ystate;
+
/* Original function parameters that need be saved */
int Xstart_offset;
int Xoffsetcount;
int *Xoffsets;
+ int Xlength;
+ PCRE_SPTR Xsubject;
} PcreExecContext;
#endif
@@ -6675,6 +6681,7 @@ pcre32_exec(const pcre32 *argument_re, const pcre32_extra *extra_data,
#endif
{
#ifndef ERLANG_INTEGRATION
+#define ERTS_UPDATE_CONSUMED(X, MD)
int rc, ocount, arg_offset_max;
int newline;
BOOL using_temporary_offsets = FALSE;
@@ -6736,6 +6743,8 @@ heapframe frame_zero;
start_offset = exec_context->Xstart_offset; \
offsetcount = exec_context->Xoffsetcount; \
offsets = exec_context->Xoffsets; \
+ length = exec_context->Xlength; \
+ subject = exec_context->Xsubject; \
} while (0)
#define SWAPOUT() do { \
@@ -6750,8 +6759,30 @@ heapframe frame_zero;
exec_context->Xstart_offset = start_offset; \
exec_context->Xoffsetcount = offsetcount; \
exec_context->Xoffsets = offsets; \
+ exec_context->Xlength = length; \
+ exec_context->Xsubject = subject; \
} while (0)
+#define ERTS_UPDATE_CONSUMED(X, MD) \
+do { \
+ if (((X)->flags & PCRE_EXTRA_LOOP_LIMIT) != 0) { \
+ unsigned long consumed__; \
+ if (!(X)->restart_data) { \
+ consumed__ = 0; \
+ } \
+ else { \
+ PcreExecContext *ctx__ = (PcreExecContext *) \
+ (*(X)->restart_data); \
+ consumed__ = ctx__->valid_utf_ystate.cnt; \
+ ctx__->valid_utf_ystate.cnt = 0; \
+ } \
+ if ((MD)) { \
+ match_data *md__ = (MD); \
+ consumed__ += (X)->loop_limit - md__->loop_limit; \
+ } \
+ *((X)->loop_counter_return) = consumed__; \
+ } \
+} while (0)
PcreExecContext *exec_context;
PcreExecContext internal_context;
@@ -6776,15 +6807,21 @@ pcre_uchar req_char;
/* we are restarting, every initialization is skipped and we jump directly into the loop */
exec_context = (PcreExecContext *) *(extra_data->restart_data);
SWAPIN();
-
+ if (exec_context->valid_utf_ystate.yielded)
+ goto restart_valid_utf;
goto RESTART_INTERRUPTED;
} else {
if (extra_data != NULL &&
(extra_data->flags & PCRE_EXTRA_LOOP_LIMIT)) {
exec_context = (PcreExecContext *) (erts_pcre_malloc)(sizeof(PcreExecContext));
- *(extra_data->restart_data) = (void *) exec_context;
+ *(extra_data->restart_data) = (void *) exec_context;
+ exec_context->valid_utf_ystate.yielded = 0;
/* need freeing by special routine from client */
} else {
+#if defined(ERLANG_INTEGRATION)
+ fprintf(stderr, "Unexpected execution path\n");
+ abort();
+#endif
exec_context = &internal_context;
}
@@ -6865,9 +6902,38 @@ code for an invalid string if a results vector is available. */
if (utf && (options & PCRE_NO_UTF8_CHECK) == 0)
{
int erroroffset;
- int errorcode = PRIV(valid_utf)((PCRE_PUCHAR)subject, length, &erroroffset);
+ int errorcode;
+
+#if !defined(ERLANG_INTEGRATION)
+ errorcode = PRIV(valid_utf)((PCRE_PUCHAR)subject, length);
+#else
+ struct PRIV(valid_utf_ystate) *ystate;
+
+ if (!extra_data || !extra_data->restart_data) {
+ ystate = NULL;
+ }
+ else if (!(extra_data->flags & PCRE_EXTRA_LOOP_LIMIT)) {
+ exec_context->valid_utf_ystate.cnt = 10;
+ ystate = NULL;
+ }
+ else {
+ exec_context->valid_utf_ystate.yielded = 0;
+ restart_valid_utf:
+ ystate = &exec_context->valid_utf_ystate;
+ ystate->cnt = (int) extra_data->loop_limit;
+ }
+ errorcode = PRIV(yielding_valid_utf)((PCRE_PUCHAR)subject, length,
+ &erroroffset, ystate);
+#endif
if (errorcode != 0)
{
+#if defined(ERLANG_INTEGRATION)
+ if (ystate && ystate->yielded) {
+ ERTS_UPDATE_CONSUMED(extra_data, NULL);
+ SWAPOUT();
+ return PCRE_ERROR_LOOP_LIMIT;
+ }
+#endif
if (offsetcount >= 2)
{
offsets[0] = erroroffset;
@@ -6890,6 +6956,11 @@ if (utf && (options & PCRE_NO_UTF8_CHECK) == 0)
return PCRE_ERROR_BADUTF8_OFFSET;
#endif
}
+#if defined(ERLANG_INTEGRATION)
+else {
+ exec_context->valid_utf_ystate.cnt = 0;
+}
+#endif
#endif
/* If the pattern was successfully studied with JIT support, run the JIT
@@ -6950,7 +7021,11 @@ if (extra_data != NULL)
#ifdef ERLANG_INTEGRATION
if ((flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
{
- md->loop_limit = extra_data->loop_limit;
+ md->loop_limit = extra_data->loop_limit;
+ if (extra_data->restart_data)
+ md->loop_limit -= extra_data->loop_limit - exec_context->valid_utf_ystate.cnt;
+ if (md->loop_limit < 10)
+ md->loop_limit = 10; /* At least do something if we've come this far... */
}
#endif
}
@@ -7266,14 +7341,8 @@ for(;;)
#endif
if ((start_bits[c/8] & (1 << (c&7))) != 0)
{
-#ifdef ERLANG_INTEGRATION
- if ((extra_data->flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
- {
- *extra_data->loop_counter_return =
- (extra_data->loop_limit - md->loop_limit);
- }
-#endif
- break;
+ ERTS_UPDATE_CONSUMED(extra_data, md);
+ break;
}
start_match++;
}
@@ -7298,13 +7367,7 @@ for(;;)
(pcre_uint32)(end_subject - start_match) < study->minlength)
{
rc = MATCH_NOMATCH;
-#ifdef ERLANG_INTEGRATION
- if ((extra_data->flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
- {
- *extra_data->loop_counter_return =
- (extra_data->loop_limit - md->loop_limit);
- }
-#endif
+ ERTS_UPDATE_CONSUMED(extra_data, md);
break;
}
@@ -7353,13 +7416,7 @@ for(;;)
if (p >= end_subject)
{
rc = MATCH_NOMATCH;
-#ifdef ERLANG_INTEGRATION
- if ((extra_data->flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
- {
- *extra_data->loop_counter_return =
- (extra_data->loop_limit - md->loop_limit);
- }
-#endif
+ ERTS_UPDATE_CONSUMED(extra_data, md);
break;
}
@@ -7390,11 +7447,7 @@ for(;;)
EDEBUGF(("Calling match..."));
rc = match(start_match, md->start_code, start_match, 2, md, NULL, 0);
#ifdef ERLANG_INTEGRATION
- if ((extra_data->flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
- {
- *extra_data->loop_counter_return =
- (extra_data->loop_limit - md->loop_limit);
- }
+ ERTS_UPDATE_CONSUMED(extra_data, md);
SWAPOUT();
while(rc == PCRE_ERROR_LOOP_LIMIT) {
EDEBUGF(("Loop limit break detected"));
diff --git a/erts/emulator/pcre/pcre_internal.h b/erts/emulator/pcre/pcre_internal.h
index c84dcb5a38..71f473e86f 100644
--- a/erts/emulator/pcre/pcre_internal.h
+++ b/erts/emulator/pcre/pcre_internal.h
@@ -2756,6 +2756,17 @@ extern int PRIV(strcmp_uc_c8_utf)(const pcre_uchar *,
#endif /* COMPILE_PCRE[8|16|32] */
+#if defined(ERLANG_INTEGRATION)
+struct PRIV(valid_utf_ystate) {
+ unsigned int cnt;
+ int length;
+ int yielded;
+ PCRE_PUCHAR p;
+};
+extern int PRIV(yielding_valid_utf)(PCRE_PUCHAR, int, int *,
+ struct PRIV(valid_utf_ystate) *);
+#endif
+
extern const pcre_uchar *PRIV(find_bracket)(const pcre_uchar *, BOOL, int);
extern BOOL PRIV(is_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR,
int *, BOOL);
diff --git a/erts/emulator/pcre/pcre_jit_compile.c b/erts/emulator/pcre/pcre_jit_compile.c
index 926e40f6d3..2d2288f81e 100644
--- a/erts/emulator/pcre/pcre_jit_compile.c
+++ b/erts/emulator/pcre/pcre_jit_compile.c
@@ -9002,7 +9002,7 @@ if (exact > 1)
#ifdef SUPPORT_UTF
&& !common->utf
#endif
- )
+ && type != OP_ANYNL && type != OP_EXTUNI)
{
OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact));
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
diff --git a/erts/emulator/pcre/pcre_valid_utf8.c b/erts/emulator/pcre/pcre_valid_utf8.c
index 516d8f4725..1dc1f9ba0c 100644
--- a/erts/emulator/pcre/pcre_valid_utf8.c
+++ b/erts/emulator/pcre/pcre_valid_utf8.c
@@ -107,19 +107,80 @@ Returns: = 0 if the string is a valid UTF-8 string
int
PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
{
+
+#if defined(ERLANG_INTEGRATION)
+ return PRIV(yielding_valid_utf)(string, length, erroroffset, NULL);
+}
+
+int
+PRIV(yielding_valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset, struct PRIV(valid_utf_ystate) *ystate)
+{
+#endif
+
#ifdef SUPPORT_UTF
register PCRE_PUCHAR p;
+#if defined(ERLANG_INTEGRATION)
+register long cnt;
+
+if (!ystate) {
+ cnt = -1;
+}
+else {
+ cnt = ystate->cnt;
+ if (ystate->yielded) {
+ p = ystate->p;
+ length = ystate->length;
+ if (length < 0)
+ goto restart_length;
+ else
+ goto restart_validate;
+ }
+}
+#endif
+
if (length < 0)
{
- for (p = string; *p != 0; p++);
- length = (int)(p - string);
+ for (p = string; *p != 0; p++) {
+#if defined(ERLANG_INTEGRATION)
+ if (cnt > 0 && --cnt == 0) {
+ /*
+ * Return with cnt set to amount consumed;
+ * i.e. same amount as at start...
+ */
+ ystate->yielded = !0;
+ ystate->length = length;
+ ystate->p = p;
+ return PCRE_UTF8_YIELD;
+ }
+ restart_length:
+ (void) !0;
+#endif
+ }
+ length = (int)(p - string);
}
for (p = string; length-- > 0; p++)
{
register pcre_uchar ab, c, d;
+#if defined(ERLANG_INTEGRATION)
+
+ if (cnt > 0 && --cnt == 0) {
+ /*
+ * Return with cnt set to amount consumed;
+ * i.e. same amount as at start...
+ */
+ ystate->yielded = !0;
+ ystate->length = length;
+ ystate->p = p;
+ return PCRE_UTF8_YIELD;
+ }
+
+ restart_validate:
+
+#endif
+
c = *p;
if (c < 128) continue; /* ASCII character */
@@ -290,6 +351,14 @@ for (p = string; length-- > 0; p++)
}
}
+#if defined(ERLANG_INTEGRATION)
+if (ystate) {
+ /* Return with cnt set to amount consumed... */
+ ystate->cnt -= cnt;
+ ystate->yielded = 0;
+}
+#endif
+
#else /* Not SUPPORT_UTF */
(void)(string); /* Keep picky compilers happy */
(void)(length);
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 664d677ebd..92020c6f35 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -785,15 +785,15 @@ static ErlDrvSSizeT spawn_control(ErlDrvData e, unsigned int cmd, char *buf,
static int fd_get_window_size(int fd, Uint32 *width, Uint32 *height)
{
-#ifdef TIOCGWINSZ
+#ifdef TIOCGWINSZ
struct winsize ws;
if (ioctl(fd,TIOCGWINSZ,&ws) == 0) {
*width = (Uint32) ws.ws_col;
*height = (Uint32) ws.ws_row;
- return 0;
+ return 1;
}
#endif
- return -1;
+ return 0;
}
static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
@@ -801,16 +801,28 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
- int fd = (int)(long)drv_data;
char resbuff[2*sizeof(Uint32)];
-
+ ErtsSysDriverData* dd = (ErtsSysDriverData*)drv_data;
command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER;
switch (command) {
case FD_CTRL_OP_GET_WINSIZE:
{
Uint32 w,h;
- if (fd_get_window_size(fd,&w,&h))
- return 0;
+ int success = 0;
+ if (dd->ofd != NULL) {
+ /* Try with output file descriptor */
+ int out_fd = dd->ofd->fd;
+ success = fd_get_window_size(out_fd,&w,&h);
+ }
+ if (!success && dd->ifd != NULL) {
+ /* Try with input file descriptor */
+ int in_fd = dd->ifd->fd;
+ success = fd_get_window_size(in_fd,&w,&h);
+ }
+ if (!success) {
+ return -1;
+ }
+ /* Succeeded */
memcpy(resbuff,&w,sizeof(Uint32));
memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32));
}
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 43975d1800..c5abd04e07 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -612,6 +612,16 @@ binary_to_existing_atom(Config) when is_list(Config) ->
UnlikelyAtom = binary_to_atom(id(UnlikelyBin), latin1),
UnlikelyAtom = binary_to_existing_atom(UnlikelyBin, latin1),
+
+ %% ERL-944; a binary that was too large would overflow the latin1-to-utf8
+ %% conversion buffer.
+ OverflowAtom = <<0:511/unit:8,
+ 196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
+ 196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
+ 196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
+ 196, 133, 196, 133, 196, 133, 196, 133, 196, 133>>,
+ {'EXIT', _} = (catch binary_to_existing_atom(OverflowAtom, latin1)),
+
ok.
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 4fb339926e..fbd1325c3a 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1438,7 +1438,8 @@ sleeper() ->
gc_test(Config) when is_list(Config) ->
%% Note: This test is only relevant for REFC binaries.
%% Therefore, we take care that all binaries are REFC binaries.
- B = list_to_binary(lists:seq(0, ?heap_binary_size)),
+ true = 192 > ?heap_binary_size,
+ B = list_to_binary(lists:seq(1, 192)),
Self = self(),
F1 = fun() ->
gc(),
@@ -1447,22 +1448,22 @@ gc_test(Config) when is_list(Config) ->
end,
F = fun() ->
receive go -> ok end,
- {binary,[{_,65,1}]} = process_info(self(), binary),
+ {binary,[{_,192,1}]} = process_info(self(), binary),
gc(),
- {B1,B2} = my_split_binary(B, 4),
+ {B1,B2} = my_split_binary(B, 68),
gc(),
gc(),
{binary,L1} = process_info(self(), binary),
[Binfo1,Binfo2,Binfo3] = L1,
- {_,65,3} = Binfo1 = Binfo2 = Binfo3,
- 65 = size(B),
- 4 = size(B1),
- 61 = size(B2),
+ {_,192,3} = Binfo1 = Binfo2 = Binfo3,
+ 192 = size(B),
+ 68 = size(B1),
+ 124 = size(B2),
F1()
end,
gc(),
gc(),
- 65 = size(B),
+ 192 = size(B),
gc_test1(spawn_opt(erlang, apply, [F,[]], [link,{fullsweep_after,0}])).
gc_test1(Pid) ->
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 7885d35d9d..9dcdd60060 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -1400,6 +1400,10 @@ get_conflicting_unicode_atoms(CIX, N) ->
%% The message_latency_large tests that small distribution messages are
%% not blocked by other large distribution messages. Basically it tests
%% that fragmentation of distribution messages works.
+%%
+%% Because of large problems to get reliable values from these testcases
+%% they no longer fail when the latency is incorrect. However, they are
+%% kept as they continue to find bugs in the distribution implementation.
message_latency_large_message(Config) when is_list(Config) ->
measure_latency_large_message(?FUNCTION_NAME, fun(Dropper, Payload) -> Dropper ! Payload end).
@@ -1484,7 +1488,11 @@ measure_latency_large_message(Nodename, DataFun) ->
case {lists:max(Times), lists:min(Times)} of
{Max, Min} when Max * 0.25 > Min, BuildType =:= opt ->
- ct:fail({incorrect_latency, IndexTimes});
+ %% We only issue a comment for this failure as the
+ %% testcases proved very difficult to run successfully
+ %% on many platforms.
+ ct:comment({incorrect_latency, IndexTimes}),
+ ok;
_ ->
ok
end.
@@ -1503,10 +1511,7 @@ measure_latency(DataFun, Dropper, Echo, Payload) ->
end
end) || _ <- lists:seq(1,2)],
- [receive
- {monitor, _Sender, busy_dist_port, _Info} ->
- ok
- end || _ <- lists:seq(1,10)],
+ wait_for_busy_dist(2 * 60 * 1000, 10),
{TS, Times} =
timer:tc(fun() ->
@@ -1530,6 +1535,18 @@ measure_latency(DataFun, Dropper, Echo, Payload) ->
end || {Sender, Ref} <- Senders],
TS.
+wait_for_busy_dist(_Tmo, 0) ->
+ ok;
+wait_for_busy_dist(Tmo, N) ->
+ T0 = erlang:monotonic_time(millisecond),
+ receive
+ {monitor, _Sender, busy_dist_port, _Info} ->
+ wait_for_busy_dist(Tmo - (erlang:monotonic_time(millisecond) - T0), N - 1)
+ after Tmo ->
+ ct:log("Timed out waiting for busy_dist, ~p left",[N]),
+ timeout
+ end.
+
flush() ->
receive
_ ->
@@ -2600,7 +2617,7 @@ verify_nc(Node) ->
demonitor(MonRef,[flush]),
ok;
{Ref, Error} ->
- ct:log("~p",[Error]),
+ ct:log("~s",[Error]),
ct:fail(failed_nc_refc_check);
{'DOWN', MonRef, _, _, _} = Down ->
ct:log("~p",[Down]),
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index 9f8ac42fa9..6133b82756 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -68,12 +68,14 @@ signal_abort(Config) ->
{ok, Node} = start_node(Config),
- _P1 = spawn(Node, ?MODULE, load, []),
- _P2 = spawn(Node, ?MODULE, load, []),
- _P3 = spawn(Node, ?MODULE, load, []),
- _P4 = spawn(Node, ?MODULE, load, []),
- _P5 = spawn(Node, ?MODULE, load, []),
- _P6 = spawn(Node, ?MODULE, load, []),
+ SO = rpc:call(Node, erlang, system_info, [schedulers_online]),
+
+ _P1 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (0 rem SO) + 1}]),
+ _P2 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (1 rem SO) + 1}]),
+ _P3 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (2 rem SO) + 1}]),
+ _P4 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (3 rem SO) + 1}]),
+ _P5 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (4 rem SO) + 1}]),
+ _P6 = spawn_opt(Node, ?MODULE, load, [], [{scheduler, (5 rem SO) + 1}]),
timer:sleep(500),
@@ -140,13 +142,13 @@ free_dump(Config) when is_list(Config) ->
{ok, NodeA} = start_node(Config),
{ok, NodeB} = start_node(Config),
-
Self = self(),
PidA = spawn_link(
NodeA,
fun() ->
Self ! ready,
+ Reason = lists:duplicate(1000000,100),
receive
ok ->
spawn(fun() ->
@@ -154,24 +156,29 @@ free_dump(Config) when is_list(Config) ->
timer:sleep(5),
receive
M ->
- io:format("~p",[M]),
- erlang:halt("dump")
- end
+ io:format("~p",[M])
+%% We may want to add this timeout here in-case no busy condition is triggered
+%% after 60 * 1000 ->
+%% io:format("Timeout")
+ end,
+ erlang:halt("dump")
end),
- exit(lists:duplicate(1000000,100))
+ exit(Reason)
end
end),
- spawn_link(NodeB,
- fun() ->
- [erlang:monitor(process, PidA) || _ <- lists:seq(1,10000)],
- Self ! done,
- receive _ -> ok end
- end),
+ PidB = spawn_link(NodeB,
+ fun() ->
+ [erlang:monitor(process, PidA) || _ <- lists:seq(1,10000)],
+ Self ! done,
+ receive _ -> ok end
+ end),
receive done -> ok end,
true = rpc:call(NodeA, os, putenv, ["ERL_CRASH_DUMP",Dump]),
- ct:pal("~p",[rpc:call(NodeA, distribution_SUITE, make_busy, [NodeB, 1000])]),
+ %% Make the node busy towards NodeB for 10 seconds.
+ BusyPid = rpc:call(NodeA, distribution_SUITE, make_busy, [NodeB,10000]),
+ ct:pal("~p",[BusyPid]),
receive ready -> unlink(PidA), PidA ! ok end,
@@ -185,6 +192,10 @@ free_dump(Config) when is_list(Config) ->
file:delete(Dump),
+ unlink(PidB),
+
+ rpc:call(NodeB, erlang, halt, [0]),
+
ok.
diff --git a/erts/emulator/test/esock_ttest/esock-ttest b/erts/emulator/test/esock_ttest/esock-ttest
index f0d363ab30..2ded557484 100755
--- a/erts/emulator/test/esock_ttest/esock-ttest
+++ b/erts/emulator/test/esock_ttest/esock-ttest
@@ -50,43 +50,50 @@ usage() ->
"~n units (server or client)."
"~n"
"~n options: "
- "~n --help Display this info and exit. "
- "~n --server [server-options] Start a server. "
- "~n There are no mandatory server options."
- "~n --client client-options Start a client"
- "~n Some client options are mandatory and"
- "~n others optional."
- "~n --active <active> boolean() | once."
- "~n Valid for both client and server."
- "~n Defaults to: false"
- "~n --transport <transport> Which transport to use: gen|sock[:plain|msg]"
- "~n gen: gen_tcp"
- "~n sock: socket"
- "~n plain: recv/send (default)"
- "~n msg: recvmsg/sendmsg"
- "~n Defaults to: sock:plain"
- "~n --scon <addr>:<port> Address and port of the server."
- "~n The address part is in the standard form:"
- "~n \"a.b.c.d\"."
- "~n Only valid for client."
- "~n Mandatory."
- "~n --msg-id <1|2|3> Choose which message to use during the test."
- "~n Basically: "
- "~n 1: small"
- "~n 2: medium"
- "~n 3: large"
- "~n Defaults to: 1"
- "~n --max-outstanding <Num> How many messages to send before waiting for"
- "~n a reply."
- "~n Valid only for client."
- "~n Defaults to: "
- "~n MsgID 1: 100"
- "~n MsgID 2: 10"
- "~n MsgID 3: 1"
- "~n --runtime <Time> Time of the test in seconds."
- "~n Only valid for client."
- "~n Mandatory."
- "~n Defaults to: 60 (seconds)"
+ "~n --help Display this info and exit. "
+ "~n --server [server-options] Start a server. "
+ "~n There are no mandatory server options."
+ "~n --client client-options Start a client"
+ "~n Some client options are mandatory and"
+ "~n others optional."
+ "~n --domain <domain> local | inet | inet6"
+ "~n Which domain to use."
+ "~n Only valid for server."
+ "~n Defaults to: inet"
+ "~n --async Asynchronous mode (Timeout = nowait)"
+ "~n This option is only valid for transport = sock."
+ "~n Also, its only used when active =/= false."
+ "~n --active <active> boolean() | once."
+ "~n Valid for both client and server."
+ "~n Defaults to: false"
+ "~n --transport <transport> Which transport to use: gen|sock[:plain|msg]"
+ "~n gen: gen_tcp"
+ "~n sock: socket"
+ "~n plain: recv/send (default)"
+ "~n msg: recvmsg/sendmsg"
+ "~n Defaults to: sock:plain"
+ "~n --scon <addr>:<port>|<path> Server info."
+ "~n The address part is in the standard form:"
+ "~n \"a.b.c.d\"."
+ "~n <path> is used for Unix Domain sockets (local)."
+ "~n Only valid, and mandatory, for client."
+ "~n --msg-id <1|2|3> Choose which message to use during the test."
+ "~n Basically: "
+ "~n 1: small"
+ "~n 2: medium"
+ "~n 3: large"
+ "~n Defaults to: 1"
+ "~n --max-outstanding <Num> How many messages to send before waiting for"
+ "~n a reply."
+ "~n Valid only for client."
+ "~n Defaults to: "
+ "~n MsgID 1: 100"
+ "~n MsgID 2: 10"
+ "~n MsgID 3: 1"
+ "~n --runtime <Time> Time of the test in seconds."
+ "~n Only valid for client."
+ "~n Mandatory."
+ "~n Defaults to: 60 (seconds)"
"~n"
"~n"
"~n",
@@ -106,6 +113,8 @@ process_args(Args) ->
process_server_args(Args) ->
Defaults = #{role => server,
+ domain => inet,
+ async => false,
active => false,
transport => {sock, plain}},
process_server_args(Args, Defaults).
@@ -113,6 +122,15 @@ process_server_args(Args) ->
process_server_args([], State) ->
State;
+process_server_args(["--domain", Domain|Args], State)
+ when ((Domain =:= "local") orelse
+ (Domain =:= "inet") orelse
+ (Domain =:= "inet6")) ->
+ process_server_args(Args, State#{domain => list_to_atom(Domain)});
+
+process_server_args(["--async"|Args], State) ->
+ process_server_args(Args, State#{async => true});
+
process_server_args(["--active", Active|Args], State)
when ((Active =:= "false") orelse
(Active =:= "once") orelse
@@ -134,10 +152,11 @@ process_server_args([Arg|_], _State) ->
process_client_args(Args) ->
Defaults = #{role => client,
+ async => false,
active => false,
transport => {sock, plain},
%% Will cause error if not provided
- %% Should be "addr:port"
+ %% Should be "addr:port or string()
server => undefined,
msg_id => 1,
%% Will be filled in based on msg_id if not provided
@@ -148,10 +167,13 @@ process_client_args(Args) ->
process_client_args([], State) ->
process_client_args_ensure_max_outstanding(State);
+process_client_args(["--async"|Args], State) ->
+ process_client_args(Args, State#{async => true});
+
process_client_args(["--active", Active|Args], State)
- when ((Active =:= "false") orelse
- (Active =:= "once") orelse
- (Active =:= "true")) ->
+ when (Active =:= "false") orelse
+ (Active =:= "once") orelse
+ (Active =:= "true") ->
process_client_args(Args, State#{active => list_to_atom(Active)});
process_client_args(["--transport", "gen" | Args], State) ->
@@ -181,7 +203,7 @@ process_client_args(["--max-outstanding", Max|Args], State) ->
end;
process_client_args(["--scon", Server|Args], State) ->
- case string:tokens(Server, [$:]) of
+ case string:split(Server, ":", trailing) of
[AddrStr,PortStr] ->
Addr = case inet:parse_address(AddrStr) of
{ok, A} ->
@@ -199,6 +221,8 @@ process_client_args(["--scon", Server|Args], State) ->
usage(f("Invalid Server Port: ~s", [PortStr]))
end,
process_client_args(Args, State#{server => {Addr, Port}});
+ [Path] ->
+ process_client_args(Args, State#{server => Path});
_ ->
usage(f("Invalid Server: ~s", [Server]))
end;
@@ -249,9 +273,11 @@ process_client_args_ensure_max_outstanding(
%% ==========================================================================
exec(#{role := server,
+ domain := Domain,
active := Active,
- transport := gen}) ->
- case socket_test_ttest_tcp_server_gen:start(Active) of
+ transport := gen})
+ when (Domain =:= inet) orelse (Domain =:= inet6) ->
+ case socket_test_ttest_tcp_server_gen:start(Domain, Active) of
{ok, {Pid, _}} ->
MRef = erlang:monitor(process, Pid),
receive
@@ -264,9 +290,11 @@ exec(#{role := server,
error
end;
exec(#{role := server,
+ domain := Domain,
+ async := Async,
active := Active,
transport := {sock, Method}}) ->
- case socket_test_ttest_tcp_server_socket:start(Method, Active) of
+ case socket_test_ttest_tcp_server_socket:start(Method, Domain, Async, Active) of
{ok, {Pid, _}} ->
MRef = erlang:monitor(process, Pid),
receive
@@ -283,15 +311,15 @@ exec(#{role := client,
server := undefined}) ->
usage("Mandatory option 'server' not provided");
exec(#{role := client,
- server := {Addr, Port},
+ server := {_Addr, _Port} = ServerInfo,
active := Active,
transport := gen,
msg_id := MsgID,
max_outstanding := MaxOutstanding,
runtime := RunTime}) ->
case socket_test_ttest_tcp_client_gen:start(true,
+ ServerInfo,
Active,
- Addr, Port,
MsgID, MaxOutstanding,
RunTime) of
{ok, Pid} ->
@@ -306,16 +334,18 @@ exec(#{role := client,
error
end;
exec(#{role := client,
- server := {Addr, Port},
+ server := ServerInfo,
+ async := Async,
active := Active,
transport := {sock, Method},
msg_id := MsgID,
max_outstanding := MaxOutstanding,
runtime := RunTime}) ->
case socket_test_ttest_tcp_client_socket:start(true,
+ Async,
+ Active,
Method,
- Active,
- Addr, Port,
+ ServerInfo,
MsgID, MaxOutstanding,
RunTime) of
{ok, Pid} ->
diff --git a/erts/emulator/test/esock_ttest/esock-ttest-client b/erts/emulator/test/esock_ttest/esock-ttest-client
index 1ab56f2d44..5ae05d03b8 100755
--- a/erts/emulator/test/esock_ttest/esock-ttest-client
+++ b/erts/emulator/test/esock_ttest/esock-ttest-client
@@ -20,51 +20,71 @@
# %CopyrightEnd%
#
+#
+# This is just a simple convenience wrapper to the esock-ttest.
+# That means that there are some options not available here.
+#
+
EMU=$ERL_TOP/erts/emulator
EMU_TEST=$EMU/test
ESOCK_TTEST=$EMU_TEST/esock_ttest
RUNTIME=30
+# RUNTIME=60
+# RUNTIME=600
+
+if [ $# = 3 ]; then
+ MSGID=$1
+ SERVER_INFO=$2:$3
+
+ ITERATIONS="\
+ gen false $MSGID
+ gen true $MSGID
+ gen once $MSGID
+ sock false $MSGID --async
+ sock true $MSGID --async
+ sock once $MSGID --async"
+
+else
+ if [ $# = 2 ]; then
+ MSGID=$1
+ SERVER_INFO=$2
+
+ ITERATIONS="\
+ sock false $MSGID --async
+ sock true $MSGID --async
+ sock once $MSGID --async"
+
+ else
+ echo "Invalid number of args"
+ exit 1;
+ fi
+fi
-MSGID=$1
-SERVER_ADDR=$2
-SERVER_PORT=$3
# ---------------------------------------------------------------------------
-ITERATIONS="\
- gen false $MSGID
- gen true $MSGID
- gen once $MSGID
- sock false $MSGID
- sock true $MSGID
- sock once $MSGID"
-
-# gen false 2
-# gen true 2
-# gen once 2
-# sock false 2
-# sock true 2
-# sock once 2
-# gen false 3
-# gen true 3
-# gen once 3
-# sock false 3
-# sock true 3
-# sock once 3
-#
+# For when we have figured out how to configure local for gen_tcp...
+
+#ITERATIONS="\
+# gen false $MSGID
+# gen true $MSGID
+# gen once $MSGID
+# sock false $MSGID
+# sock true $MSGID
+# sock once $MSGID"
# ---------------------------------------------------------------------------
echo "$ITERATIONS" |
- while read TRANSPORT ACTIVE MSG_ID; do
+ while read TRANSPORT ACTIVE MSG_ID ASYNC; do
echo ""
echo "=========== transport = $TRANSPORT, active = $ACTIVE, msg-id = $MSG_ID ==========="
# The /dev/null at the end is necessary because erlang "does things" with stdin
# and this case would cause the 'while read' to "fail" so that we only would
# loop one time
- $ESOCK_TTEST/esock-ttest --client --transport $TRANSPORT --active $ACTIVE --msg-id $MSG_ID --scon $SERVER_ADDR:$SERVER_PORT --runtime $RUNTIME </dev/null
+ $ESOCK_TTEST/esock-ttest --client --transport $TRANSPORT $ASYNC --active $ACTIVE --msg-id $MSG_ID --scon $SERVER_INFO --runtime $RUNTIME </dev/null
echo ""
done
diff --git a/erts/emulator/test/esock_ttest/esock-ttest-server-sock b/erts/emulator/test/esock_ttest/esock-ttest-server-sock
index 4ec0d335d9..c443d42e64 100755
--- a/erts/emulator/test/esock_ttest/esock-ttest-server-sock
+++ b/erts/emulator/test/esock_ttest/esock-ttest-server-sock
@@ -24,9 +24,33 @@ EMU=$ERL_TOP/erts/emulator
EMU_TEST=$EMU/test
ESOCK_TTEST=$EMU_TEST/esock_ttest
-if [ $# = 1 ]; then
- ACTIVE="--active $1"
+# $1 - async - boolean()
+# $2 - active - once | boolean()
+# [$3 - domain - inet (default) | inet6 | local]
+if [ $# -ge 2 ]; then
+
+ async=$1
+ active=$2
+
+ if [ $async = true ]; then
+ ASYNC="--async"
+ else
+ ASYNC=
+ fi
+
+ ACTIVE="--active $active"
+
+ if [ $# = 3 ]; then
+ DOMAIN="--domain $3"
+ fi
+
+
+else
+ echo "<ERROR> Missing args: async and active"
+ echo ""
+ exit 1
fi
-$ESOCK_TTEST/esock-ttest --server --transport sock $ACTIVE
+
+$ESOCK_TTEST/esock-ttest --server $DOMAIN $ASYNC --transport sock $ACTIVE
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index c4d9ea515a..154bce3c35 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -23,6 +23,7 @@
-export([all/0, suite/0,
badmatch/1, pending_errors/1, nil_arith/1, top_of_stacktrace/1,
stacktrace/1, nested_stacktrace/1, raise/1, gunilla/1, per/1,
+ change_exception_class/1,
exception_with_heap_frag/1, backtrace_depth/1,
line_numbers/1]).
@@ -48,6 +49,7 @@ suite() ->
all() ->
[badmatch, pending_errors, nil_arith, top_of_stacktrace,
stacktrace, nested_stacktrace, raise, gunilla, per,
+ change_exception_class,
exception_with_heap_frag, backtrace_depth, line_numbers].
-define(try_match(E),
@@ -512,6 +514,38 @@ t1(_,X,_) ->
t2(_,X,_) ->
(X bsl 1) + 1.
+change_exception_class(_Config) ->
+ try
+ change_exception_class_1(fun() -> throw(arne) end)
+ catch
+ error:arne ->
+ ok;
+ Class:arne ->
+ ct:fail({wrong_exception_class,Class})
+ end.
+
+change_exception_class_1(F) ->
+ try
+ change_exception_class_2(F)
+ after
+ %% The exception would be caught and rethrown using
+ %% an i_raise instruction. Before the correction
+ %% of the raw_raise instruction, the change of class
+ %% would not stick.
+ io:put_chars("Exception automatically rethrown here\n")
+ end.
+
+change_exception_class_2(F) ->
+ try
+ F()
+ catch
+ throw:Reason:Stack ->
+ %% Translated to a raw_raise instruction.
+ %% The change of exception class would not stick
+ %% if the i_raise instruction was later executed.
+ erlang:raise(error, Reason, Stack)
+ end.
+
%%
%% Make sure that even if a BIF builds an heap fragment, then causes an exception,
%% the stacktrace term will still be OK (specifically, that it does not contain
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 2cbde621ce..ad8ef0feff 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -27,7 +27,7 @@
fun_to_port/1,t_phash/1,t_phash2/1,md5/1,
refc/1,refc_ets/1,refc_dist/1,
const_propagation/1,t_arity/1,t_is_function2/1,
- t_fun_info/1,t_fun_info_mfa/1]).
+ t_fun_info/1,t_fun_info_mfa/1,t_fun_to_list/1]).
-export([nothing/0]).
@@ -44,7 +44,7 @@ all() ->
equality, ordering, fun_to_port, t_phash,
t_phash2, md5, refc, refc_ets, refc_dist,
const_propagation, t_arity, t_is_function2, t_fun_info,
- t_fun_info_mfa].
+ t_fun_info_mfa,t_fun_to_list].
%% Test that the correct EXIT code is returned for all types of bad funs.
bad_apply(Config) when is_list(Config) ->
@@ -802,6 +802,12 @@ t_fun_info_mfa(Config) when is_list(Config) ->
{'EXIT',_} = (catch erlang:fun_info_mfa(id(d))),
ok.
+t_fun_to_list(Config) when is_list(Config) ->
+ "fun a:b/1" = erlang:fun_to_list(fun a:b/1),
+ "fun 'a-esc':'b-esc'/1" = erlang:fun_to_list(fun 'a-esc':'b-esc'/1),
+ "fun 'a-esc':b/1" = erlang:fun_to_list(fun 'a-esc':b/1),
+ "fun a:'b-esc'/1" = erlang:fun_to_list(fun a:'b-esc'/1),
+ ok.
bad_info(Term) ->
try erlang:fun_info(Term, module) of
diff --git a/erts/emulator/test/multi_load_SUITE.erl b/erts/emulator/test/multi_load_SUITE.erl
index edf3205812..c79e2b6dcd 100644
--- a/erts/emulator/test/multi_load_SUITE.erl
+++ b/erts/emulator/test/multi_load_SUITE.erl
@@ -30,7 +30,15 @@ all() ->
[many,on_load,errors].
many(_Config) ->
- Ms = make_modules(100, fun many_module/1),
+
+ N = case erlang:system_info(build_type) of
+ valgrind ->
+ 10;
+ _ ->
+ 100
+ end,
+
+ Ms = make_modules(N, fun many_module/1),
io:put_chars("Light load\n"
"=========="),
diff --git a/erts/emulator/test/net_SUITE.erl b/erts/emulator/test/net_SUITE.erl
index 6111fc76a5..c6e77a5373 100644
--- a/erts/emulator/test/net_SUITE.erl
+++ b/erts/emulator/test/net_SUITE.erl
@@ -20,6 +20,8 @@
%%
%% This test suite is basically a "placeholder" for a proper test suite...
+%% Also we should really call prim_net directly, and not net (since that does
+%% not even reside here).
%%
%% Run the entire test suite:
@@ -127,6 +129,7 @@ api_basic_cases() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_per_suite(Config) ->
+ %% We test on the socket module for simplicity
case lists:member(socket, erlang:loaded()) of
true ->
case os:type() of
diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl
index ef4635a6f5..c44693f8d9 100644
--- a/erts/emulator/test/node_container_SUITE.erl
+++ b/erts/emulator/test/node_container_SUITE.erl
@@ -51,7 +51,8 @@
unique_pid/1,
iter_max_procs/1,
magic_ref/1,
- dist_entry_gc/1]).
+ dist_entry_gc/1,
+ persistent_term/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -63,7 +64,8 @@ all() ->
node_table_gc, dist_link_refc, dist_monitor_refc,
node_controller_refc, ets_refc, match_spec_refc,
timer_refc, pid_wrap, port_wrap, bad_nc,
- unique_pid, iter_max_procs, magic_ref].
+ unique_pid, iter_max_procs,
+ magic_ref, persistent_term].
init_per_suite(Config) ->
Config.
@@ -570,7 +572,17 @@ node_controller_refc(Config) when is_list(Config) ->
wait_until(fun () -> not is_process_alive(P) end),
lists:foreach(fun (Proc) -> garbage_collect(Proc) end, processes()),
false = get_node_references({Node,Creation}),
- false = get_dist_references(Node),
+ wait_until(fun () ->
+ case get_dist_references(Node) of
+ false ->
+ true;
+ [{{system,thread_progress_delete_timer},
+ [{system,1}]}] ->
+ false;
+ Other ->
+ ct:fail(Other)
+ end
+ end),
false = lists:member(Node, nodes(known)),
nc_refc_check(node()),
erts_debug:set_internal_state(node_tab_delayed_delete, -1), %% restore original value
@@ -871,7 +883,22 @@ magic_ref(Config) when is_list(Config) ->
{'DOWN', Mon, process, Pid, _} ->
ok
end,
- {Addr0, 2, true} = erts_debug:get_internal_state({magic_ref,MRef0}),
+ MaxTime = erlang:monotonic_time(millisecond) + 1000,
+ %% The DOWN signal is sent before heap is cleaned up,
+ %% so we might need to wait some time after the DOWN
+ %% signal has been received before the heap actually
+ %% has been cleaned up...
+ wait_until(fun () ->
+ case erts_debug:get_internal_state({magic_ref,MRef0}) of
+ {Addr0, 2, true} ->
+ true;
+ {Addr0, 3, true} ->
+ true = MaxTime >= erlang:monotonic_time(millisecond),
+ false;
+ Error ->
+ ct:fail(Error)
+ end
+ end),
id(MRef0),
id(MRef1),
MRefExt = term_to_binary(erts_debug:set_internal_state(make, magic_ref)),
@@ -881,6 +908,44 @@ magic_ref(Config) when is_list(Config) ->
true = erts_debug:get_internal_state({magic_ref,MRef2}),
ok.
+persistent_term(Config) when is_list(Config) ->
+ {ok, Node} = start_node(get_nodefirstname()),
+ Self = self(),
+ NcData = make_ref(),
+ RPid = spawn_link(Node,
+ fun () ->
+ Self ! {NcData, self(), hd(erlang:ports()), erlang:make_ref()}
+ end),
+ Data = receive
+ {NcData, RPid, RPort, RRef} ->
+ {RPid, RPort, RRef}
+ end,
+ unlink(RPid),
+ stop_node(Node),
+ Stuff = lists:foldl(fun (N, Acc) ->
+ persistent_term:put({?MODULE, N}, Data),
+ persistent_term:erase({?MODULE, N-1}),
+ node_container_refc_check(node()),
+ Data = persistent_term:get({?MODULE, N}),
+ try
+ persistent_term:get({?MODULE, N-1})
+ catch
+ error:badarg ->
+ ok
+ end,
+ case N rem 4 of
+ 0 -> [persistent_term:get({?MODULE, N})|Acc];
+ _ -> Acc
+ end
+ end,
+ [],
+ lists:seq(1, 100)),
+ persistent_term:erase({?MODULE, 100}),
+ receive after 2000 -> ok end, %% give literal gc some time to run...
+ node_container_refc_check(node()),
+ id(Stuff),
+ ok.
+
lost_pending_connection(Node) ->
_ = (catch erts_internal:new_connection(Node)),
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index b530ced566..13dde12e69 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -1098,42 +1098,86 @@ process_info_status_handled_signal(Config) when is_list(Config) ->
%% OTP-15709
%% Provoke a bug where process_info(reductions) returned wrong result
%% because REDS_IN (def_arg_reg[5]) is read when the process in not running.
+%%
+%% And a bug where process_info(reductions) on a process which was releasing its
+%% main lock during execution could result in negative reduction diffs.
process_info_reductions(Config) when is_list(Config) ->
- pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)),
- pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)),
+ {S1, S2} = case erlang:system_info(schedulers) of
+ 1 -> {1,1};
+ _ -> {1,2}
+ end,
+ io:format("Run on schedulers ~p and ~p\n", [S1,S2]),
+ Boss = self(),
+ Doer = spawn_opt(fun () ->
+ pi_reductions_tester(true, 10, fun pi_reductions_spinnloop/0, S2),
+ pi_reductions_tester(true, 10, fun pi_reductions_recvloop/0, S2),
+ pi_reductions_tester(false, 100, fun pi_reductions_main_unlocker/0, S2),
+ Boss ! {self(), done}
+ end,
+ [link, {scheduler, S1}]),
+
+ {Doer, done} = receive M -> M end,
ok.
-pi_reductions_tester(Pid) ->
- {_, DiffList} =
- lists:foldl(fun(_, {Prev, Acc}) ->
- %% Add another item that force sending the request
- %% as a signal, like 'current_function'.
- PI = process_info(Pid, [reductions, current_function]),
- [{reductions,Reds}, {current_function,_}] = PI,
- Diff = Reds - Prev,
- {Diff, true} = {Diff, (Diff >= 0)},
- {Diff, true} = {Diff, (Diff =< 1000*1000)},
- {Reds, [Diff | Acc]}
- end,
- {0, []},
- lists:seq(1,10)),
+pi_reductions_tester(ForceSignal, MaxCalls, Fun, S2) ->
+ Pid = spawn_opt(Fun, [link, {scheduler,S2}]),
+ Extra = case ForceSignal of
+ true ->
+ %% Add another item that force sending the request
+ %% as a signal, like 'current_function'.
+ [current_function];
+ false ->
+ []
+ end,
+ LoopFun = fun Me(Calls, Prev, Acc0) ->
+ PI = process_info(Pid, [reductions | Extra]),
+ [{reductions,Reds} | _] = PI,
+ Diff = Reds - Prev,
+ %% Verify we get sane non-negative reduction diffs
+ {Diff, true} = {Diff, (Diff >= 0)},
+ {Diff, true} = {Diff, (Diff =< 1000*1000)},
+ Acc1 = [Diff | Acc0],
+ case Calls >= MaxCalls of
+ true -> Acc1;
+ false -> Me(Calls+1, Reds, Acc1)
+ end
+ end,
+ DiffList = LoopFun(0, 0, []),
unlink(Pid),
exit(Pid,kill),
- io:format("Reduction diffs: ~p\n", [DiffList]),
+ io:format("Reduction diffs: ~p\n", [lists:reverse(DiffList)]),
ok.
pi_reductions_spinnloop() ->
%% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN
- pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14).
+ pi_reductions_spinnloop(999*1000, atom, "hej", self(), make_ref(), 3.14).
-pi_reductions_spinnloop(A,B,C,D,E,F) ->
- pi_reductions_spinnloop(B,C,D,E,F,A).
+pi_reductions_spinnloop(N,A,B,C,D,E) when N > 0 ->
+ pi_reductions_spinnloop(N-1,B,C,D,E,A);
+pi_reductions_spinnloop(0,_,_,_,_,_) ->
+ %% Stop to limit max number of reductions consumed
+ pi_reductions_recvloop().
pi_reductions_recvloop() ->
receive
"a free lunch" -> false
end.
+pi_reductions_main_unlocker() ->
+ Other = spawn_link(fun() -> receive die -> ok end end),
+ pi_reductions_main_unlocker_loop(Other).
+
+pi_reductions_main_unlocker_loop(Other) ->
+ %% Assumption: register(OtherPid, Name) will unlock main lock of calling
+ %% process during execution.
+ register(pi_reductions_main_unlocker, Other),
+ unregister(pi_reductions_main_unlocker),
+
+ %% Yield in order to increase probability of process_info sometimes probing
+ %% this process when it's not RUNNING.
+ erlang:yield(),
+ pi_reductions_main_unlocker_loop(Other).
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
@@ -2556,14 +2600,20 @@ garb_other_running(Config) when is_list(Config) ->
no_priority_inversion(Config) when is_list(Config) ->
Prio = process_flag(priority, max),
- HTLs = lists:map(fun (_) ->
+ Master = self(),
+ Executing = make_ref(),
+ HTLs = lists:map(fun (Sched) ->
spawn_opt(fun () ->
+ Master ! {self(), Executing},
tok_loop()
end,
- [{priority, high}, monitor, link])
+ [{priority, high},
+ {scheduler, Sched},
+ monitor,
+ link])
end,
- lists:seq(1, 2*erlang:system_info(schedulers))),
- receive after 500 -> ok end,
+ lists:seq(1, erlang:system_info(schedulers_online))),
+ lists:foreach(fun ({P, _}) -> receive {P,Executing} -> ok end end, HTLs),
LTL = spawn_opt(fun () ->
tok_loop()
end,
@@ -2585,14 +2635,19 @@ no_priority_inversion(Config) when is_list(Config) ->
no_priority_inversion2(Config) when is_list(Config) ->
Prio = process_flag(priority, max),
- MTLs = lists:map(fun (_) ->
+ Master = self(),
+ Executing = make_ref(),
+ MTLs = lists:map(fun (Sched) ->
spawn_opt(fun () ->
+ Master ! {self(), Executing},
tok_loop()
end,
- [{priority, max}, monitor, link])
+ [{priority, max},
+ {scheduler, Sched},
+ monitor, link])
end,
- lists:seq(1, 2*erlang:system_info(schedulers))),
- receive after 2000 -> ok end,
+ lists:seq(1, erlang:system_info(schedulers_online))),
+ lists:foreach(fun ({P, _}) -> receive {P,Executing} -> ok end end, MTLs),
{PL, ML} = spawn_opt(fun () ->
tok_loop()
end,
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index e3545ccbf9..4980ea2a82 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -58,6 +58,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("common_test/include/ct_event.hrl").
+-include("socket_test_evaluator.hrl").
%% Suite exports
-export([suite/0, all/0, groups/0]).
@@ -67,18 +68,72 @@
%% Test cases
-export([
+ %% *** API Misc ***
+ api_m_debug/1,
+
%% *** API Basic ***
api_b_open_and_close_udp4/1,
api_b_open_and_close_tcp4/1,
+ api_b_open_and_close_udpL/1,
+ api_b_open_and_close_tcpL/1,
api_b_sendto_and_recvfrom_udp4/1,
+ api_b_sendto_and_recvfrom_udpL/1,
api_b_sendmsg_and_recvmsg_udp4/1,
+ api_b_sendmsg_and_recvmsg_udpL/1,
api_b_send_and_recv_tcp4/1,
+ api_b_send_and_recv_tcpL/1,
api_b_sendmsg_and_recvmsg_tcp4/1,
+ api_b_sendmsg_and_recvmsg_tcpL/1,
+
+ %% *** API async ***
+ api_a_connect_tcp4/1,
+ api_a_connect_tcp6/1,
+ api_a_sendto_and_recvfrom_udp4/1,
+ api_a_sendto_and_recvfrom_udp6/1,
+ api_a_sendmsg_and_recvmsg_udp4/1,
+ api_a_sendmsg_and_recvmsg_udp6/1,
+ api_a_send_and_recv_tcp4/1,
+ api_a_send_and_recv_tcp6/1,
+ api_a_sendmsg_and_recvmsg_tcp4/1,
+ api_a_sendmsg_and_recvmsg_tcp6/1,
+ api_a_recvfrom_cancel_udp4/1,
+ api_a_recvfrom_cancel_udp6/1,
+ api_a_recvmsg_cancel_udp4/1,
+ api_a_recvmsg_cancel_udp6/1,
+ api_a_accept_cancel_tcp4/1,
+ api_a_accept_cancel_tcp6/1,
+ api_a_recv_cancel_tcp4/1,
+ api_a_recv_cancel_tcp6/1,
+ api_a_recvmsg_cancel_tcp4/1,
+ api_a_recvmsg_cancel_tcp6/1,
+ api_a_mrecvfrom_cancel_udp4/1,
+ api_a_mrecvfrom_cancel_udp6/1,
+ api_a_mrecvmsg_cancel_udp4/1,
+ api_a_mrecvmsg_cancel_udp6/1,
+ api_a_maccept_cancel_tcp4/1,
+ api_a_maccept_cancel_tcp6/1,
+ api_a_mrecv_cancel_tcp4/1,
+ api_a_mrecv_cancel_tcp6/1,
+ api_a_mrecvmsg_cancel_tcp4/1,
+ api_a_mrecvmsg_cancel_tcp6/1,
+
%% *** API Options ***
api_opt_simple_otp_options/1,
api_opt_simple_otp_rcvbuf_option/1,
api_opt_simple_otp_controlling_process/1,
+ api_opt_sock_acceptconn_udp/1,
+ api_opt_sock_acceptconn_tcp/1,
+ api_opt_sock_acceptfilter/1,
+ api_opt_sock_bindtodevice/1,
+ api_opt_sock_broadcast/1,
+ api_opt_sock_debug/1,
+ api_opt_sock_domain/1,
+ api_opt_sock_dontroute/1,
+ api_opt_sock_error/1,
+ api_opt_sock_keepalive/1,
+ api_opt_sock_linger/1,
+ api_opt_ip_add_drop_membership/1,
%% *** API Operation Timeout ***
api_to_connect_tcp4/1,
@@ -107,57 +162,92 @@
%% *** Socket Closure ***
sc_cpe_socket_cleanup_tcp4/1,
sc_cpe_socket_cleanup_tcp6/1,
+ sc_cpe_socket_cleanup_tcpL/1,
sc_cpe_socket_cleanup_udp4/1,
sc_cpe_socket_cleanup_udp6/1,
+ sc_cpe_socket_cleanup_udpL/1,
sc_lc_recv_response_tcp4/1,
sc_lc_recv_response_tcp6/1,
+ sc_lc_recv_response_tcpL/1,
sc_lc_recvfrom_response_udp4/1,
sc_lc_recvfrom_response_udp6/1,
+ sc_lc_recvfrom_response_udpL/1,
sc_lc_recvmsg_response_tcp4/1,
sc_lc_recvmsg_response_tcp6/1,
+ sc_lc_recvmsg_response_tcpL/1,
sc_lc_recvmsg_response_udp4/1,
sc_lc_recvmsg_response_udp6/1,
+ sc_lc_recvmsg_response_udpL/1,
sc_lc_acceptor_response_tcp4/1,
sc_lc_acceptor_response_tcp6/1,
+ sc_lc_acceptor_response_tcpL/1,
sc_rc_recv_response_tcp4/1,
sc_rc_recv_response_tcp6/1,
+ sc_rc_recv_response_tcpL/1,
sc_rc_recvmsg_response_tcp4/1,
sc_rc_recvmsg_response_tcp6/1,
+ sc_rc_recvmsg_response_tcpL/1,
sc_rs_recv_send_shutdown_receive_tcp4/1,
sc_rs_recv_send_shutdown_receive_tcp6/1,
+ sc_rs_recv_send_shutdown_receive_tcpL/1,
sc_rs_recvmsg_send_shutdown_receive_tcp4/1,
sc_rs_recvmsg_send_shutdown_receive_tcp6/1,
+ sc_rs_recvmsg_send_shutdown_receive_tcpL/1,
%% *** Traffic ***
+ traffic_send_and_recv_counters_tcp4/1,
+ traffic_send_and_recv_counters_tcp6/1,
+ traffic_send_and_recv_counters_tcpL/1,
+ traffic_sendmsg_and_recvmsg_counters_tcp4/1,
+ traffic_sendmsg_and_recvmsg_counters_tcp6/1,
+ traffic_sendmsg_and_recvmsg_counters_tcpL/1,
+ traffic_sendto_and_recvfrom_counters_udp4/1,
+ traffic_sendto_and_recvfrom_counters_udp6/1,
+ traffic_sendto_and_recvfrom_counters_udpL/1,
+ traffic_sendmsg_and_recvmsg_counters_udp4/1,
+ traffic_sendmsg_and_recvmsg_counters_udp6/1,
+ traffic_sendmsg_and_recvmsg_counters_udpL/1,
+
traffic_send_and_recv_chunks_tcp4/1,
traffic_send_and_recv_chunks_tcp6/1,
+ traffic_send_and_recv_chunks_tcpL/1,
traffic_ping_pong_small_send_and_recv_tcp4/1,
traffic_ping_pong_small_send_and_recv_tcp6/1,
+ traffic_ping_pong_small_send_and_recv_tcpL/1,
traffic_ping_pong_medium_send_and_recv_tcp4/1,
traffic_ping_pong_medium_send_and_recv_tcp6/1,
+ traffic_ping_pong_medium_send_and_recv_tcpL/1,
traffic_ping_pong_large_send_and_recv_tcp4/1,
traffic_ping_pong_large_send_and_recv_tcp6/1,
+ traffic_ping_pong_large_send_and_recv_tcpL/1,
traffic_ping_pong_small_sendto_and_recvfrom_udp4/1,
traffic_ping_pong_small_sendto_and_recvfrom_udp6/1,
+ traffic_ping_pong_small_sendto_and_recvfrom_udpL/1,
traffic_ping_pong_medium_sendto_and_recvfrom_udp4/1,
traffic_ping_pong_medium_sendto_and_recvfrom_udp6/1,
+ traffic_ping_pong_medium_sendto_and_recvfrom_udpL/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp4/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp6/1,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_udpL/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6/1,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL/1,
%% *** Time Test ***
%% Server: transport = gen_tcp, active = false
@@ -325,24 +415,33 @@
%% Client: transport = socket(tcp)
ttest_ssockf_csockf_small_tcp4/1,
ttest_ssockf_csockf_small_tcp6/1,
+ ttest_ssockf_csockf_small_tcpL/1,
ttest_ssockf_csockf_medium_tcp4/1,
ttest_ssockf_csockf_medium_tcp6/1,
+ ttest_ssockf_csockf_medium_tcpL/1,
ttest_ssockf_csockf_large_tcp4/1,
ttest_ssockf_csockf_large_tcp6/1,
+ ttest_ssockf_csockf_large_tcpL/1,
ttest_ssockf_csocko_small_tcp4/1,
ttest_ssockf_csocko_small_tcp6/1,
+ ttest_ssockf_csocko_small_tcpL/1,
ttest_ssockf_csocko_medium_tcp4/1,
ttest_ssockf_csocko_medium_tcp6/1,
+ ttest_ssockf_csocko_medium_tcpL/1,
ttest_ssockf_csocko_large_tcp4/1,
ttest_ssockf_csocko_large_tcp6/1,
+ ttest_ssockf_csocko_large_tcpL/1,
ttest_ssockf_csockt_small_tcp4/1,
ttest_ssockf_csockt_small_tcp6/1,
+ ttest_ssockf_csockt_small_tcpL/1,
ttest_ssockf_csockt_medium_tcp4/1,
ttest_ssockf_csockt_medium_tcp6/1,
+ ttest_ssockf_csockt_medium_tcpL/1,
ttest_ssockf_csockt_large_tcp4/1,
ttest_ssockf_csockt_large_tcp6/1,
+ ttest_ssockf_csockt_large_tcpL/1,
%% Server: transport = socket(tcp), active = once
%% Client: transport = gen_tcp
@@ -371,24 +470,33 @@
%% Client: transport = socket(tcp)
ttest_ssocko_csockf_small_tcp4/1,
ttest_ssocko_csockf_small_tcp6/1,
+ ttest_ssocko_csockf_small_tcpL/1,
ttest_ssocko_csockf_medium_tcp4/1,
+ ttest_ssocko_csockf_medium_tcpL/1,
ttest_ssocko_csockf_medium_tcp6/1,
ttest_ssocko_csockf_large_tcp4/1,
ttest_ssocko_csockf_large_tcp6/1,
+ ttest_ssocko_csockf_large_tcpL/1,
ttest_ssocko_csocko_small_tcp4/1,
ttest_ssocko_csocko_small_tcp6/1,
+ ttest_ssocko_csocko_small_tcpL/1,
ttest_ssocko_csocko_medium_tcp4/1,
ttest_ssocko_csocko_medium_tcp6/1,
+ ttest_ssocko_csocko_medium_tcpL/1,
ttest_ssocko_csocko_large_tcp4/1,
ttest_ssocko_csocko_large_tcp6/1,
+ ttest_ssocko_csocko_large_tcpL/1,
ttest_ssocko_csockt_small_tcp4/1,
ttest_ssocko_csockt_small_tcp6/1,
+ ttest_ssocko_csockt_small_tcpL/1,
ttest_ssocko_csockt_medium_tcp4/1,
ttest_ssocko_csockt_medium_tcp6/1,
+ ttest_ssocko_csockt_medium_tcpL/1,
ttest_ssocko_csockt_large_tcp4/1,
ttest_ssocko_csockt_large_tcp6/1,
+ ttest_ssocko_csockt_large_tcpL/1,
%% Server: transport = socket(tcp), active = true
%% Client: transport = gen_tcp
@@ -417,53 +525,63 @@
%% Client: transport = socket(tcp)
ttest_ssockt_csockf_small_tcp4/1,
ttest_ssockt_csockf_small_tcp6/1,
+ ttest_ssockt_csockf_small_tcpL/1,
ttest_ssockt_csockf_medium_tcp4/1,
ttest_ssockt_csockf_medium_tcp6/1,
+ ttest_ssockt_csockf_medium_tcpL/1,
ttest_ssockt_csockf_large_tcp4/1,
ttest_ssockt_csockf_large_tcp6/1,
+ ttest_ssockt_csockf_large_tcpL/1,
ttest_ssockt_csocko_small_tcp4/1,
ttest_ssockt_csocko_small_tcp6/1,
+ ttest_ssockt_csocko_small_tcpL/1,
ttest_ssockt_csocko_medium_tcp4/1,
ttest_ssockt_csocko_medium_tcp6/1,
+ ttest_ssockt_csocko_medium_tcpL/1,
ttest_ssockt_csocko_large_tcp4/1,
ttest_ssockt_csocko_large_tcp6/1,
+ ttest_ssockt_csocko_large_tcpL/1,
ttest_ssockt_csockt_small_tcp4/1,
ttest_ssockt_csockt_small_tcp6/1,
+ ttest_ssockt_csockt_small_tcpL/1,
ttest_ssockt_csockt_medium_tcp4/1,
ttest_ssockt_csockt_medium_tcp6/1,
+ ttest_ssockt_csockt_medium_tcpL/1,
ttest_ssockt_csockt_large_tcp4/1,
- ttest_ssockt_csockt_large_tcp6/1
+ ttest_ssockt_csockt_large_tcp6/1,
+ ttest_ssockt_csockt_large_tcpL/1
%% Tickets
]).
--include("socket_test_evaluator.hrl").
-
%% Internal exports
%% -export([]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(BASIC_REQ, <<"hejsan">>).
--define(BASIC_REP, <<"hoppsan">>).
+-define(LIB, socket_test_lib).
+-define(TTEST_LIB, socket_test_ttest_lib).
+-define(LOGGER, socket_test_logger).
+
+-define(BASIC_REQ, <<"hejsan">>).
+-define(BASIC_REP, <<"hoppsan">>).
--define(DATA, <<"HOPPSAN">>). % Temporary
--define(FAIL(R), exit(R)).
+-define(DATA, <<"HOPPSAN">>). % Temporary
+-define(FAIL(R), exit(R)).
--define(SLEEP(T), receive after T -> ok end).
+-define(SLEEP(T), receive after T -> ok end).
--define(MINS(M), timer:minutes(M)).
--define(SECS(S), timer:seconds(S)).
+-define(MINS(M), timer:minutes(M)).
+-define(SECS(S), timer:seconds(S)).
--define(TT(T), ct:timetrap(T)).
+-define(TT(T), ct:timetrap(T)).
+
+-define(F(F, A), ?LIB:f(F, A)).
--define(LIB, socket_test_lib).
--define(TTEST_LIB, socket_test_ttest_lib).
--define(LOGGER, socket_test_logger).
-define(TPP_SMALL, lists:seq(1, 8)).
-define(TPP_MEDIUM, lists:flatten(lists:duplicate(1024, ?TPP_SMALL))).
@@ -483,10 +601,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- Groups = [{api, "ESOCK_TEST_API", include},
- {socket_closure, "ESOCK_TEST_SOCK_CLOSE", include},
- {traffic, "ESOCK_TEST_TRAFFIC", include},
- {ttest, "ESOCK_TEST_TTEST", exclude}],
+ Groups = [{api, "ESOCK_TEST_API", include},
+ {socket_close, "ESOCK_TEST_SOCK_CLOSE", include},
+ {traffic, "ESOCK_TEST_TRAFFIC", include},
+ {ttest, "ESOCK_TEST_TTEST", exclude}],
[use_group(Group, Env, Default) || {Group, Env, Default} <- Groups].
use_group(Group, Env, Default) ->
@@ -508,99 +626,201 @@ use_group(Group, Env, Default) ->
groups() ->
- [{api, [], api_cases()},
- {api_basic, [], api_basic_cases()},
- {api_options, [], api_options_cases()},
- {api_op_with_timeout, [], api_op_with_timeout_cases()},
- {socket_closure, [], socket_closure_cases()},
- {sc_ctrl_proc_exit, [], sc_cp_exit_cases()},
- {sc_local_close, [], sc_lc_cases()},
- {sc_remote_close, [], sc_rc_cases()},
- {sc_remote_shutdown, [], sc_rs_cases()},
- {traffic, [], traffic_cases()},
- {ttest, [], ttest_cases()},
- {ttest_sgenf, [], ttest_sgenf_cases()},
- {ttest_sgenf_cgen, [], ttest_sgenf_cgen_cases()},
- {ttest_sgenf_cgenf, [], ttest_sgenf_cgenf_cases()},
- {ttest_sgenf_cgeno, [], ttest_sgenf_cgeno_cases()},
- {ttest_sgenf_cgent, [], ttest_sgenf_cgent_cases()},
- {ttest_sgenf_csock, [], ttest_sgenf_csock_cases()},
- {ttest_sgenf_csockf, [], ttest_sgenf_csockf_cases()},
- {ttest_sgenf_csocko, [], ttest_sgenf_csocko_cases()},
- {ttest_sgenf_csockt, [], ttest_sgenf_csockt_cases()},
- {ttest_sgeno, [], ttest_sgeno_cases()},
- {ttest_sgeno_cgen, [], ttest_sgeno_cgen_cases()},
- {ttest_sgeno_cgenf, [], ttest_sgeno_cgenf_cases()},
- {ttest_sgeno_cgeno, [], ttest_sgeno_cgeno_cases()},
- {ttest_sgeno_cgent, [], ttest_sgeno_cgent_cases()},
- {ttest_sgeno_csock, [], ttest_sgeno_csock_cases()},
- {ttest_sgeno_csockf, [], ttest_sgeno_csockf_cases()},
- {ttest_sgeno_csocko, [], ttest_sgeno_csocko_cases()},
- {ttest_sgeno_csockt, [], ttest_sgeno_csockt_cases()},
- {ttest_sgent, [], ttest_sgent_cases()},
- {ttest_sgent_cgen, [], ttest_sgent_cgen_cases()},
- {ttest_sgent_cgenf, [], ttest_sgent_cgenf_cases()},
- {ttest_sgent_cgeno, [], ttest_sgent_cgeno_cases()},
- {ttest_sgent_cgent, [], ttest_sgent_cgent_cases()},
- {ttest_sgent_csock, [], ttest_sgent_csock_cases()},
- {ttest_sgent_csockf, [], ttest_sgent_csockf_cases()},
- {ttest_sgent_csocko, [], ttest_sgent_csocko_cases()},
- {ttest_sgent_csockt, [], ttest_sgent_csockt_cases()},
- {ttest_ssockf, [], ttest_ssockf_cases()},
- {ttest_ssockf_cgen, [], ttest_ssockf_cgen_cases()},
- {ttest_ssockf_cgenf, [], ttest_ssockf_cgenf_cases()},
- {ttest_ssockf_cgeno, [], ttest_ssockf_cgeno_cases()},
- {ttest_ssockf_cgent, [], ttest_ssockf_cgent_cases()},
- {ttest_ssockf_csock, [], ttest_ssockf_csock_cases()},
- {ttest_ssockf_csockf, [], ttest_ssockf_csockf_cases()},
- {ttest_ssockf_csocko, [], ttest_ssockf_csocko_cases()},
- {ttest_ssockf_csockt, [], ttest_ssockf_csockt_cases()},
- {ttest_ssocko, [], ttest_ssocko_cases()},
- {ttest_ssocko_cgen, [], ttest_ssocko_cgen_cases()},
- {ttest_ssocko_cgenf, [], ttest_ssocko_cgenf_cases()},
- {ttest_ssocko_cgeno, [], ttest_ssocko_cgeno_cases()},
- {ttest_ssocko_cgent, [], ttest_ssocko_cgent_cases()},
- {ttest_ssocko_csock, [], ttest_ssocko_csock_cases()},
- {ttest_ssocko_csockf, [], ttest_ssocko_csockf_cases()},
- {ttest_ssocko_csocko, [], ttest_ssocko_csocko_cases()},
- {ttest_ssocko_csockt, [], ttest_ssocko_csockt_cases()},
- {ttest_ssockt, [], ttest_ssockt_cases()},
- {ttest_ssockt_cgen, [], ttest_ssockt_cgen_cases()},
- {ttest_ssockt_cgenf, [], ttest_ssockt_cgenf_cases()},
- {ttest_ssockt_cgeno, [], ttest_ssockt_cgeno_cases()},
- {ttest_ssockt_cgent, [], ttest_ssockt_cgent_cases()},
- {ttest_ssockt_csock, [], ttest_ssockt_csock_cases()},
- {ttest_ssockt_csockf, [], ttest_ssockt_csockf_cases()},
- {ttest_ssockt_csocko, [], ttest_ssockt_csocko_cases()},
- {ttest_ssockt_csockt, [], ttest_ssockt_csockt_cases()}
+ [{api, [], api_cases()},
+ {api_misc, [], api_misc_cases()},
+ {api_basic, [], api_basic_cases()},
+ {api_async, [], api_async_cases()},
+ {api_options, [], api_options_cases()},
+ {api_options_otp, [], api_options_otp_cases()},
+ {api_options_socket, [], api_options_socket_cases()},
+ {api_option_sock_acceptconn, [], api_option_sock_acceptconn_cases()},
+ {api_options_ip, [], api_options_ip_cases()},
+ %% {api_options_ipv6, [], api_options_ipv6_cases()},
+ %% {api_options_tcp, [], api_options_tcp_cases()},
+ %% {api_options_udp, [], api_options_udp_cases()},
+ %% {api_options_sctp, [], api_options_sctp_cases()},
+ {api_op_with_timeout, [], api_op_with_timeout_cases()},
+ {socket_close, [], socket_close_cases()},
+ {sc_ctrl_proc_exit, [], sc_cp_exit_cases()},
+ {sc_local_close, [], sc_lc_cases()},
+ {sc_remote_close, [], sc_rc_cases()},
+ {sc_remote_shutdown, [], sc_rs_cases()},
+ {traffic, [], traffic_cases()},
+ {traffic_counters, [], traffic_counters_cases()},
+ {traffic_chunks, [], traffic_chunks_cases()},
+ {traffic_pp_send_recv, [], traffic_pp_send_recv_cases()},
+ {traffic_pp_sendto_recvfrom, [], traffic_pp_sendto_recvfrom_cases()},
+ {traffic_pp_sendmsg_recvmsg, [], traffic_pp_sendmsg_recvmsg_cases()},
+ {ttest, [], ttest_cases()},
+ {ttest_sgenf, [], ttest_sgenf_cases()},
+ {ttest_sgenf_cgen, [], ttest_sgenf_cgen_cases()},
+ {ttest_sgenf_cgenf, [], ttest_sgenf_cgenf_cases()},
+ {ttest_sgenf_cgeno, [], ttest_sgenf_cgeno_cases()},
+ {ttest_sgenf_cgent, [], ttest_sgenf_cgent_cases()},
+ {ttest_sgenf_csock, [], ttest_sgenf_csock_cases()},
+ {ttest_sgenf_csockf, [], ttest_sgenf_csockf_cases()},
+ {ttest_sgenf_csocko, [], ttest_sgenf_csocko_cases()},
+ {ttest_sgenf_csockt, [], ttest_sgenf_csockt_cases()},
+ {ttest_sgeno, [], ttest_sgeno_cases()},
+ {ttest_sgeno_cgen, [], ttest_sgeno_cgen_cases()},
+ {ttest_sgeno_cgenf, [], ttest_sgeno_cgenf_cases()},
+ {ttest_sgeno_cgeno, [], ttest_sgeno_cgeno_cases()},
+ {ttest_sgeno_cgent, [], ttest_sgeno_cgent_cases()},
+ {ttest_sgeno_csock, [], ttest_sgeno_csock_cases()},
+ {ttest_sgeno_csockf, [], ttest_sgeno_csockf_cases()},
+ {ttest_sgeno_csocko, [], ttest_sgeno_csocko_cases()},
+ {ttest_sgeno_csockt, [], ttest_sgeno_csockt_cases()},
+ {ttest_sgent, [], ttest_sgent_cases()},
+ {ttest_sgent_cgen, [], ttest_sgent_cgen_cases()},
+ {ttest_sgent_cgenf, [], ttest_sgent_cgenf_cases()},
+ {ttest_sgent_cgeno, [], ttest_sgent_cgeno_cases()},
+ {ttest_sgent_cgent, [], ttest_sgent_cgent_cases()},
+ {ttest_sgent_csock, [], ttest_sgent_csock_cases()},
+ {ttest_sgent_csockf, [], ttest_sgent_csockf_cases()},
+ {ttest_sgent_csocko, [], ttest_sgent_csocko_cases()},
+ {ttest_sgent_csockt, [], ttest_sgent_csockt_cases()},
+ {ttest_ssockf, [], ttest_ssockf_cases()},
+ {ttest_ssockf_cgen, [], ttest_ssockf_cgen_cases()},
+ {ttest_ssockf_cgenf, [], ttest_ssockf_cgenf_cases()},
+ {ttest_ssockf_cgeno, [], ttest_ssockf_cgeno_cases()},
+ {ttest_ssockf_cgent, [], ttest_ssockf_cgent_cases()},
+ {ttest_ssockf_csock, [], ttest_ssockf_csock_cases()},
+ {ttest_ssockf_csockf, [], ttest_ssockf_csockf_cases()},
+ {ttest_ssockf_csocko, [], ttest_ssockf_csocko_cases()},
+ {ttest_ssockf_csockt, [], ttest_ssockf_csockt_cases()},
+ {ttest_ssocko, [], ttest_ssocko_cases()},
+ {ttest_ssocko_cgen, [], ttest_ssocko_cgen_cases()},
+ {ttest_ssocko_cgenf, [], ttest_ssocko_cgenf_cases()},
+ {ttest_ssocko_cgeno, [], ttest_ssocko_cgeno_cases()},
+ {ttest_ssocko_cgent, [], ttest_ssocko_cgent_cases()},
+ {ttest_ssocko_csock, [], ttest_ssocko_csock_cases()},
+ {ttest_ssocko_csockf, [], ttest_ssocko_csockf_cases()},
+ {ttest_ssocko_csocko, [], ttest_ssocko_csocko_cases()},
+ {ttest_ssocko_csockt, [], ttest_ssocko_csockt_cases()},
+ {ttest_ssockt, [], ttest_ssockt_cases()},
+ {ttest_ssockt_cgen, [], ttest_ssockt_cgen_cases()},
+ {ttest_ssockt_cgenf, [], ttest_ssockt_cgenf_cases()},
+ {ttest_ssockt_cgeno, [], ttest_ssockt_cgeno_cases()},
+ {ttest_ssockt_cgent, [], ttest_ssockt_cgent_cases()},
+ {ttest_ssockt_csock, [], ttest_ssockt_csock_cases()},
+ {ttest_ssockt_csockf, [], ttest_ssockt_csockf_cases()},
+ {ttest_ssockt_csocko, [], ttest_ssockt_csocko_cases()},
+ {ttest_ssockt_csockt, [], ttest_ssockt_csockt_cases()}
%% {tickets, [], ticket_cases()}
].
api_cases() ->
[
+ {group, api_misc},
{group, api_basic},
+ {group, api_async},
{group, api_options},
{group, api_op_with_timeout}
].
+api_misc_cases() ->
+ [
+ api_m_debug
+ ].
+
api_basic_cases() ->
[
api_b_open_and_close_udp4,
api_b_open_and_close_tcp4,
+ api_b_open_and_close_udpL,
+ api_b_open_and_close_tcpL,
api_b_sendto_and_recvfrom_udp4,
+ api_b_sendto_and_recvfrom_udpL,
api_b_sendmsg_and_recvmsg_udp4,
+ api_b_sendmsg_and_recvmsg_udpL,
api_b_send_and_recv_tcp4,
- api_b_sendmsg_and_recvmsg_tcp4
+ api_b_send_and_recv_tcpL,
+ api_b_sendmsg_and_recvmsg_tcp4,
+ api_b_sendmsg_and_recvmsg_tcpL
+ ].
+
+api_async_cases() ->
+ [
+ api_a_connect_tcp4,
+ api_a_connect_tcp6,
+ api_a_sendto_and_recvfrom_udp4,
+ api_a_sendto_and_recvfrom_udp6,
+ api_a_sendmsg_and_recvmsg_udp4,
+ api_a_sendmsg_and_recvmsg_udp6,
+ api_a_send_and_recv_tcp4,
+ api_a_send_and_recv_tcp6,
+ api_a_sendmsg_and_recvmsg_tcp4,
+ api_a_sendmsg_and_recvmsg_tcp6,
+ api_a_recvfrom_cancel_udp4,
+ api_a_recvfrom_cancel_udp6,
+ api_a_recvmsg_cancel_udp4,
+ api_a_recvmsg_cancel_udp6,
+ api_a_accept_cancel_tcp4,
+ api_a_accept_cancel_tcp6,
+ api_a_recv_cancel_tcp4,
+ api_a_recv_cancel_tcp6,
+ api_a_recvmsg_cancel_tcp4,
+ api_a_recvmsg_cancel_tcp6,
+ api_a_mrecvfrom_cancel_udp4,
+ api_a_mrecvfrom_cancel_udp6,
+ api_a_mrecvmsg_cancel_udp4,
+ api_a_mrecvmsg_cancel_udp6,
+ api_a_maccept_cancel_tcp4,
+ api_a_maccept_cancel_tcp6,
+ api_a_mrecv_cancel_tcp4,
+ api_a_mrecv_cancel_tcp6,
+ api_a_mrecvmsg_cancel_tcp4,
+ api_a_mrecvmsg_cancel_tcp6
].
api_options_cases() ->
[
+ {group, api_options_otp},
+ {group, api_options_socket},
+ {group, api_options_ip}% ,
+ %% {group, api_options_ipv6},
+ %% {group, api_options_tcp},
+ %% {group, api_options_udp},
+ %% {group, api_options_sctp}
+ ].
+
+api_options_otp_cases() ->
+ [
api_opt_simple_otp_options,
api_opt_simple_otp_rcvbuf_option,
api_opt_simple_otp_controlling_process
].
+api_options_socket_cases() ->
+ [
+ {group, api_option_sock_acceptconn},
+ api_opt_sock_acceptfilter,
+ api_opt_sock_bindtodevice,
+ api_opt_sock_broadcast,
+ api_opt_sock_debug,
+ api_opt_sock_domain,
+ api_opt_sock_dontroute,
+ api_opt_sock_error,
+ api_opt_sock_keepalive,
+ api_opt_sock_linger
+ ].
+
+api_option_sock_acceptconn_cases() ->
+ [
+ api_opt_sock_acceptconn_udp,
+ api_opt_sock_acceptconn_tcp
+ ].
+
+api_options_ip_cases() ->
+ [
+ api_opt_ip_add_drop_membership
+ ].
+
+%% api_options_ipv6_cases() ->
+%% [
+%% ].
+
api_op_with_timeout_cases() ->
[
api_to_connect_tcp4,
@@ -629,7 +849,7 @@ api_op_with_timeout_cases() ->
%% These cases tests what happens when the socket is closed/shutdown,
%% locally or remotely.
-socket_closure_cases() ->
+socket_close_cases() ->
[
{group, sc_ctrl_proc_exit},
{group, sc_local_close},
@@ -638,13 +858,15 @@ socket_closure_cases() ->
].
%% These cases are all about socket cleanup after the controlling process
-%% exits *without* calling socket:close/1.
+%% exits *without* explicitly calling socket:close/1.
sc_cp_exit_cases() ->
[
sc_cpe_socket_cleanup_tcp4,
sc_cpe_socket_cleanup_tcp6,
+ sc_cpe_socket_cleanup_tcpL,
sc_cpe_socket_cleanup_udp4,
- sc_cpe_socket_cleanup_udp6
+ sc_cpe_socket_cleanup_udp6,
+ sc_cpe_socket_cleanup_udpL
].
%% These cases tests what happens when the socket is closed locally.
@@ -652,17 +874,22 @@ sc_lc_cases() ->
[
sc_lc_recv_response_tcp4,
sc_lc_recv_response_tcp6,
+ sc_lc_recv_response_tcpL,
sc_lc_recvfrom_response_udp4,
sc_lc_recvfrom_response_udp6,
+ sc_lc_recvfrom_response_udpL,
sc_lc_recvmsg_response_tcp4,
sc_lc_recvmsg_response_tcp6,
+ sc_lc_recvmsg_response_tcpL,
sc_lc_recvmsg_response_udp4,
sc_lc_recvmsg_response_udp6,
+ sc_lc_recvmsg_response_udpL,
sc_lc_acceptor_response_tcp4,
- sc_lc_acceptor_response_tcp6
+ sc_lc_acceptor_response_tcp6,
+ sc_lc_acceptor_response_tcpL
].
%% These cases tests what happens when the socket is closed remotely.
@@ -670,9 +897,11 @@ sc_rc_cases() ->
[
sc_rc_recv_response_tcp4,
sc_rc_recv_response_tcp6,
+ sc_rc_recv_response_tcpL,
sc_rc_recvmsg_response_tcp4,
- sc_rc_recvmsg_response_tcp6
+ sc_rc_recvmsg_response_tcp6,
+ sc_rc_recvmsg_response_tcpL
].
%% These cases tests what happens when the socket is shutdown/closed remotely
@@ -681,43 +910,89 @@ sc_rs_cases() ->
[
sc_rs_recv_send_shutdown_receive_tcp4,
sc_rs_recv_send_shutdown_receive_tcp6,
+ sc_rs_recv_send_shutdown_receive_tcpL,
sc_rs_recvmsg_send_shutdown_receive_tcp4,
- sc_rs_recvmsg_send_shutdown_receive_tcp6
+ sc_rs_recvmsg_send_shutdown_receive_tcp6,
+ sc_rs_recvmsg_send_shutdown_receive_tcpL
].
traffic_cases() ->
[
+ {group, traffic_counters},
+ {group, traffic_chunks},
+ {group, traffic_pp_send_recv},
+ {group, traffic_pp_sendto_recvfrom},
+ {group, traffic_pp_sendmsg_recvmsg}
+ ].
+
+traffic_counters_cases() ->
+ [
+ traffic_send_and_recv_counters_tcp4,
+ traffic_send_and_recv_counters_tcp6,
+ traffic_send_and_recv_counters_tcpL,
+ traffic_sendmsg_and_recvmsg_counters_tcp4,
+ traffic_sendmsg_and_recvmsg_counters_tcp6,
+ traffic_sendmsg_and_recvmsg_counters_tcpL,
+ traffic_sendto_and_recvfrom_counters_udp4,
+ traffic_sendto_and_recvfrom_counters_udp6,
+ traffic_sendto_and_recvfrom_counters_udpL,
+ traffic_sendmsg_and_recvmsg_counters_udp4,
+ traffic_sendmsg_and_recvmsg_counters_udp6,
+ traffic_sendmsg_and_recvmsg_counters_udpL
+ ].
+
+traffic_chunks_cases() ->
+ [
traffic_send_and_recv_chunks_tcp4,
traffic_send_and_recv_chunks_tcp6,
+ traffic_send_and_recv_chunks_tcpL
+ ].
+traffic_pp_send_recv_cases() ->
+ [
traffic_ping_pong_small_send_and_recv_tcp4,
traffic_ping_pong_small_send_and_recv_tcp6,
+ traffic_ping_pong_small_send_and_recv_tcpL,
traffic_ping_pong_medium_send_and_recv_tcp4,
traffic_ping_pong_medium_send_and_recv_tcp6,
+ traffic_ping_pong_medium_send_and_recv_tcpL,
traffic_ping_pong_large_send_and_recv_tcp4,
traffic_ping_pong_large_send_and_recv_tcp6,
+ traffic_ping_pong_large_send_and_recv_tcpL
+ ].
+traffic_pp_sendto_recvfrom_cases() ->
+ [
traffic_ping_pong_small_sendto_and_recvfrom_udp4,
traffic_ping_pong_small_sendto_and_recvfrom_udp6,
+ traffic_ping_pong_small_sendto_and_recvfrom_udpL,
traffic_ping_pong_medium_sendto_and_recvfrom_udp4,
traffic_ping_pong_medium_sendto_and_recvfrom_udp6,
+ traffic_ping_pong_medium_sendto_and_recvfrom_udpL
+ ].
+traffic_pp_sendmsg_recvmsg_cases() ->
+ [
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp4,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_udpL,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4,
- traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL
].
-
-
+
ttest_cases() ->
[
%% Server: transport = gen_tcp, active = false
@@ -1123,12 +1398,15 @@ ttest_ssockf_csockf_cases() ->
[
ttest_ssockf_csockf_small_tcp4,
ttest_ssockf_csockf_small_tcp6,
+ ttest_ssockf_csockf_small_tcpL,
ttest_ssockf_csockf_medium_tcp4,
ttest_ssockf_csockf_medium_tcp6,
+ ttest_ssockf_csockf_medium_tcpL,
ttest_ssockf_csockf_large_tcp4,
- ttest_ssockf_csockf_large_tcp6
+ ttest_ssockf_csockf_large_tcp6,
+ ttest_ssockf_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = false
@@ -1137,12 +1415,15 @@ ttest_ssockf_csocko_cases() ->
[
ttest_ssockf_csocko_small_tcp4,
ttest_ssockf_csocko_small_tcp6,
+ ttest_ssockf_csocko_small_tcpL,
ttest_ssockf_csocko_medium_tcp4,
ttest_ssockf_csocko_medium_tcp6,
+ ttest_ssockf_csocko_medium_tcpL,
ttest_ssockf_csocko_large_tcp4,
- ttest_ssockf_csocko_large_tcp6
+ ttest_ssockf_csocko_large_tcp6,
+ ttest_ssockf_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = false
@@ -1151,12 +1432,15 @@ ttest_ssockf_csockt_cases() ->
[
ttest_ssockf_csockt_small_tcp4,
ttest_ssockf_csockt_small_tcp6,
+ ttest_ssockf_csockt_small_tcpL,
ttest_ssockf_csockt_medium_tcp4,
ttest_ssockf_csockt_medium_tcp6,
+ ttest_ssockf_csockt_medium_tcpL,
ttest_ssockf_csockt_large_tcp4,
- ttest_ssockf_csockt_large_tcp6
+ ttest_ssockf_csockt_large_tcp6,
+ ttest_ssockf_csockt_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1232,12 +1516,15 @@ ttest_ssocko_csockf_cases() ->
[
ttest_ssocko_csockf_small_tcp4,
ttest_ssocko_csockf_small_tcp6,
+ ttest_ssocko_csockf_small_tcpL,
ttest_ssocko_csockf_medium_tcp4,
ttest_ssocko_csockf_medium_tcp6,
+ ttest_ssocko_csockf_medium_tcpL,
ttest_ssocko_csockf_large_tcp4,
- ttest_ssocko_csockf_large_tcp6
+ ttest_ssocko_csockf_large_tcp6,
+ ttest_ssocko_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1246,12 +1533,15 @@ ttest_ssocko_csocko_cases() ->
[
ttest_ssocko_csocko_small_tcp4,
ttest_ssocko_csocko_small_tcp6,
+ ttest_ssocko_csocko_small_tcpL,
ttest_ssocko_csocko_medium_tcp4,
ttest_ssocko_csocko_medium_tcp6,
+ ttest_ssocko_csocko_medium_tcpL,
ttest_ssocko_csocko_large_tcp4,
- ttest_ssocko_csocko_large_tcp6
+ ttest_ssocko_csocko_large_tcp6,
+ ttest_ssocko_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1260,12 +1550,15 @@ ttest_ssocko_csockt_cases() ->
[
ttest_ssocko_csockt_small_tcp4,
ttest_ssocko_csockt_small_tcp6,
+ ttest_ssocko_csockt_small_tcpL,
ttest_ssocko_csockt_medium_tcp4,
ttest_ssocko_csockt_medium_tcp6,
+ ttest_ssocko_csockt_medium_tcpL,
ttest_ssocko_csockt_large_tcp4,
- ttest_ssocko_csockt_large_tcp6
+ ttest_ssocko_csockt_large_tcp6,
+ ttest_ssocko_csockt_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1341,12 +1634,15 @@ ttest_ssockt_csockf_cases() ->
[
ttest_ssockt_csockf_small_tcp4,
ttest_ssockt_csockf_small_tcp6,
+ ttest_ssockt_csockf_small_tcpL,
ttest_ssockt_csockf_medium_tcp4,
ttest_ssockt_csockf_medium_tcp6,
+ ttest_ssockt_csockf_medium_tcpL,
ttest_ssockt_csockf_large_tcp4,
- ttest_ssockt_csockf_large_tcp6
+ ttest_ssockt_csockf_large_tcp6,
+ ttest_ssockt_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1355,12 +1651,15 @@ ttest_ssockt_csocko_cases() ->
[
ttest_ssockt_csocko_small_tcp4,
ttest_ssockt_csocko_small_tcp6,
+ ttest_ssockt_csocko_small_tcpL,
ttest_ssockt_csocko_medium_tcp4,
ttest_ssockt_csocko_medium_tcp6,
+ ttest_ssockt_csocko_medium_tcpL,
ttest_ssockt_csocko_large_tcp4,
- ttest_ssockt_csocko_large_tcp6
+ ttest_ssockt_csocko_large_tcp6,
+ ttest_ssockt_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1369,12 +1668,15 @@ ttest_ssockt_csockt_cases() ->
[
ttest_ssockt_csockt_small_tcp4,
ttest_ssockt_csockt_small_tcp6,
+ ttest_ssockt_csockt_small_tcpL,
ttest_ssockt_csockt_medium_tcp4,
ttest_ssockt_csockt_medium_tcp6,
+ ttest_ssockt_csockt_medium_tcpL,
ttest_ssockt_csockt_large_tcp4,
- ttest_ssockt_csockt_large_tcp6
+ ttest_ssockt_csockt_large_tcp6,
+ ttest_ssockt_csockt_large_tcpL
].
%% ticket_cases() ->
@@ -1413,11 +1715,12 @@ init_per_group(ttest = _GroupName, Config) ->
io:format("init_per_group(~w) -> entry with"
"~n Config: ~p"
"~n", [_GroupName, Config]),
+ ttest_manager_start(),
case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
{value, _} ->
Config;
false ->
- [{esock_test_ttest_runtime, which_ttest_runtime_env()}|Config]
+ [{esock_test_ttest_runtime, which_ttest_runtime_env()} | Config]
end;
init_per_group(_GroupName, Config) ->
Config.
@@ -1426,6 +1729,7 @@ end_per_group(ttest = _GroupName, Config) ->
io:format("init_per_group(~w) -> entry with"
"~n Config: ~p"
"~n", [_GroupName, Config]),
+ ttest_manager_stop(),
lists:keydelete(esock_test_ttest_runtime, 1, Config);
end_per_group(_GroupName, Config) ->
Config.
@@ -1435,16 +1739,16 @@ init_per_testcase(_TC, Config) ->
io:format("init_per_testcase(~w) -> entry with"
"~n Config: ~p"
"~n", [_TC, Config]),
- case quiet_mode(Config) of
- default ->
- ?LOGGER:start();
- Quiet ->
- ?LOGGER:start(Quiet)
- end,
+ %% case quiet_mode(Config) of
+ %% default ->
+ %% ?LOGGER:start();
+ %% Quiet ->
+ %% ?LOGGER:start(Quiet)
+ %% end,
Config.
end_per_testcase(_TC, Config) ->
- ?LOGGER:stop(),
+ %% ?LOGGER:stop(),
Config.
@@ -1465,6 +1769,80 @@ quiet_mode(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
+%% API MISC %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% A simple test case that tests that the global debug can be channged.
+%% At the same time, it will test the info function (since it uses it
+%% for verification).
+
+api_m_debug(suite) ->
+ [];
+api_m_debug(doc) ->
+ [];
+api_m_debug(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_m_debug,
+ fun() -> has_bugfree_gcc() end,
+ fun() ->
+ ok = api_m_debug()
+ end).
+
+%% For some reason this test case triggers a gcc bug, which causes
+%% a segfault, on an ancient Fedora 16 VM. So, check the version of gcc...
+%% Not pretty, but the simplest way to skip (without actually testing for the host).
+has_bugfree_gcc() ->
+ has_bugfree_gcc(os:type()).
+
+%% Make sure we are on linux
+has_bugfree_gcc({unix, linux}) ->
+ has_bugfree_gcc2(string:trim(os:cmd("cat /etc/issue")));
+has_bugfree_gcc(_) ->
+ ok.
+
+%% Make sure we are on Fedora 16
+has_bugfree_gcc2("Fedora release 16 " ++ _) ->
+ has_bugfree_gcc3(os:cmd("gcc --version"));
+has_bugfree_gcc2("Welcome to SUSE Linux " ++ _) ->
+ has_bugfree_gcc4(os:cmd("gcc --version"));
+has_bugfree_gcc2(_) ->
+ ok.
+
+has_bugfree_gcc3("gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2" ++ _) ->
+ skip("Buggy GCC");
+has_bugfree_gcc3(_) ->
+ ok.
+
+has_bugfree_gcc4("gcc (SUSE Linux) 4.3.2" ++ _) ->
+ skip("Buggy GCC");
+has_bugfree_gcc4(_) ->
+ ok.
+
+api_m_debug() ->
+ i("get initial info"),
+ #{debug := D0} = socket:info(),
+ D1 = not D0,
+ i("set new debug (~w => ~w)", [D0, D1]),
+ ok = socket:debug(D1),
+ i("get updated info (~w)", [D1]),
+ #{debug := D1} = socket:info(),
+ D2 = not D1,
+ i("set new debug (~w => ~w)", [D1, D2]),
+ ok = socket:debug(D2),
+ i("get updated info (~w)", [D2]),
+ #{debug := D2} = socket:info(),
+ i("ok"),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
%% API BASIC %%
%% %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1510,6 +1888,46 @@ api_b_open_and_close_tcp4(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Basically open (create) and close an Unix Domain dgram (UDP) socket.
+%% With some extra checks...
+api_b_open_and_close_udpL(suite) ->
+ [];
+api_b_open_and_close_udpL(doc) ->
+ [];
+api_b_open_and_close_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_open_and_close_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => dgram,
+ protocol => default},
+ ok = api_b_open_and_close(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically open (create) and close an Unix Domain stream (TCP) socket.
+%% With some extra checks...
+api_b_open_and_close_tcpL(suite) ->
+ [];
+api_b_open_and_close_tcpL(doc) ->
+ [];
+api_b_open_and_close_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_open_and_close_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => stream,
+ protocol => default},
+ ok = api_b_open_and_close(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
api_b_open_and_close(InitState) ->
Seq =
[
@@ -1633,6 +2051,37 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) ->
socket:recvfrom(Sock)
end,
InitState = #{domain => inet,
+ proto => udp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom.
+api_b_sendto_and_recvfrom_udpL(suite) ->
+ [];
+api_b_sendto_and_recvfrom_udpL(doc) ->
+ [];
+api_b_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_sendto_and_recvfrom_udpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ unix_domain_socket_host_cond()
+ end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock)
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_udp(InitState)
@@ -1665,17 +2114,66 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
end,
Recv = fun(Sock) ->
%% We have some issues on old darwing...
- socket:setopt(Sock, otp, debug, true),
+ %% socket:setopt(Sock, otp, debug, true),
case socket:recvmsg(Sock) of
{ok, #{addr := Source,
iov := [Data]}} ->
- socket:setopt(Sock, otp, debug, false),
+ %% socket:setopt(Sock, otp, debug, false),
{ok, {Source, Data}};
{error, _} = ERROR ->
ERROR
end
end,
InitState = #{domain => inet,
+ proto => udp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket
+%% using sendmsg and recvmsg.
+api_b_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+api_b_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+api_b_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_sendmsg_and_recvmsg_udpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ unix_domain_socket_host_cond()
+ end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ %% We need tests for this,
+ %% but this is not the place it.
+ %% CMsgHdr = #{level => ip,
+ %% type => tos,
+ %% data => reliability},
+ %% CMsgHdrs = [CMsgHdr],
+ MsgHdr = #{addr => Dest,
+ %% ctrl => CMsgHdrs,
+ iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ %% We have some issues on old darwing...
+ %% socket:setopt(Sock, otp, debug, true),
+ case socket:recvmsg(Sock) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ %% socket:setopt(Sock, otp, debug, false),
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_udp(InitState)
@@ -1688,42 +2186,64 @@ api_b_send_and_recv_udp(InitState) ->
Seq =
[
#{desc => "local address",
- cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
- {ok, State#{lsa => LSA}}
+ cmd => fun(#{domain := local = Domain} = State) ->
+ LSASrc = which_local_socket_addr(Domain),
+ LSADst = which_local_socket_addr(Domain),
+ {ok, State#{lsa_src => LSASrc,
+ lsa_dst => LSADst}};
+ (#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa_src => LSA,
+ lsa_dst => LSA}}
end},
+
#{desc => "open src socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
- SASrc = sock_sockname(Sock),
- {ok, State#{sock_src => Sock, sa_src => SASrc}}
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
+ {ok, State#{sock_src => Sock}}
end},
#{desc => "bind src",
- cmd => fun(#{sock_src := Sock, lsa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ cmd => fun(#{sock_src := Sock, lsa_src := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "sockname src socket",
cmd => fun(#{sock_src := Sock} = State) ->
SASrc = sock_sockname(Sock),
- %% ei("src sockaddr: ~p", [SASrc]),
+ ?SEV_IPRINT("src sockaddr: "
+ "~n ~p", [SASrc]),
{ok, State#{sa_src => SASrc}}
end},
+
#{desc => "open dst socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
{ok, State#{sock_dst => Sock}}
end},
#{desc => "bind dst",
- cmd => fun(#{sock_dst := Sock, lsa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "sockname dst socket",
cmd => fun(#{sock_dst := Sock} = State) ->
SADst = sock_sockname(Sock),
- %% ei("dst sockaddr: ~p", [SADst]),
+ ?SEV_IPRINT("dst sockaddr: "
+ "~n ~p", [SADst]),
{ok, State#{sa_dst => SADst}}
end},
#{desc => "send req (to dst)",
@@ -1761,12 +2281,32 @@ api_b_send_and_recv_udp(InitState) ->
end
end},
#{desc => "close src socket",
- cmd => fun(#{sock_src := Sock}) ->
- ok = socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock_src := Sock,
+ lsa_src := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() -> maps:remove(lsa_src, State) end,
+ fun() -> State end),
+ {ok, maps:remove(sock_src, State1)};
+ (#{sock_src := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock_src, State)}
end},
#{desc => "close dst socket",
- cmd => fun(#{sock_dst := Sock}) ->
- ok = socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock_dst := Sock,
+ lsa_dst := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() -> maps:remove(lsa_dst, State) end,
+ fun() -> State end),
+ {ok, maps:remove(sock_dst, State1)};
+ (#{sock_dst := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock_dst, State)}
end},
%% *** We are done ***
@@ -1796,6 +2336,34 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) ->
socket:recv(Sock)
end,
InitState = #{domain => inet,
+ proto => tcp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an Unix Domain (stream) socket (TCP).
+api_b_send_and_recv_tcpL(suite) ->
+ [];
+api_b_send_and_recv_tcpL(doc) ->
+ [];
+api_b_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_b_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_tcp(InitState)
@@ -1828,6 +2396,56 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
end
end,
InitState = #{domain => inet,
+ proto => tcp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an Unix Domain (stream) socket (TCP).
+api_b_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+api_b_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+api_b_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_b_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ socket:setopt(Sock,
+ otp,
+ debug,
+ false),
+ {ok, Data};
+ {error, _} = ERROR ->
+ socket:setopt(Sock,
+ otp,
+ debug,
+ false),
+ ERROR
+ end
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_tcp(InitState)
@@ -1855,13 +2473,13 @@ api_b_send_and_recv_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -1869,9 +2487,19 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, lsa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -1882,7 +2510,12 @@ api_b_send_and_recv_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, lsa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester, lport := Port}) ->
+ %% This is actually not used for unix domain socket
?SEV_ANNOUNCE_READY(Tester, init, Port),
ok
end},
@@ -1946,12 +2579,29 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "close connection socket",
- cmd => fun(#{csock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{csock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(csock, State)}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := LSock} = State) ->
+ case socket:close(LSock) of
+ ok ->
+ {ok, maps:remove(lsock, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
end},
%% *** We are done ***
@@ -1962,7 +2612,10 @@ api_b_send_and_recv_tcp(InitState) ->
[
%% *** Wait for start order ***
#{desc => "await start (from tester)",
- cmd => fun(State) ->
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, Path} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_path => Path}};
+ (State) ->
{Tester, Port} = ?SEV_AWAIT_START(),
{ok, State#{tester => Tester, server_port => Port}}
end},
@@ -1974,16 +2627,20 @@ api_b_send_and_recv_tcp(InitState) ->
%% *** The init part ***
#{desc => "which server (local) address",
- cmd => fun(#{domain := Domain, server_port := Port} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
- SSA = LSA#{port => Port},
+ cmd => fun(#{domain := local = Domain,
+ server_path := Path} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = #{family => Domain, path => Path},
+ {ok, State#{local_sa => LSA, server_sa => SSA}};
+ (#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
{ok, State#{local_sa => LSA, server_sa => SSA}}
end},
#{desc => "create socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -2054,8 +2711,20 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
end},
%% *** We are done ***
@@ -2105,11 +2774,7 @@ api_b_send_and_recv_tcp(InitState) ->
?SEV_ANNOUNCE_CONTINUE(Server, accept),
ok
end},
- #{desc => "sleep",
- cmd => fun(_) ->
- ?SLEEP(?SECS(1)),
- ok
- end},
+ ?SEV_SLEEP(?SECS(1)),
#{desc => "order client to continue (with connect)",
cmd => fun(#{client := Client} = _State) ->
?SEV_ANNOUNCE_CONTINUE(Client, connect),
@@ -2196,6 +2861,4313 @@ api_b_send_and_recv_tcp(InitState) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically establish a TCP connection via an async connect. IPv4.
+
+api_a_connect_tcp4(suite) ->
+ [];
+api_a_connect_tcp4(doc) ->
+ [];
+api_a_connect_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_connect_tcp4,
+ fun() ->
+ ok = api_a_connect_tcpD(inet)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically establish a TCP connection via an async connect. IPv6.
+
+api_a_connect_tcp6(suite) ->
+ [];
+api_a_connect_tcp6(doc) ->
+ [];
+api_a_connect_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_connect_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ ok = api_a_connect_tcpD(inet6)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_connect_tcpD(Domain) ->
+ 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 => Domain,
+ connect => Connect,
+ send => Send,
+ recv => Recv},
+ api_a_connect_tcp(InitState).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_connect_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, Sock} ->
+ ?SEV_IPRINT("accepted: ~n ~p", [Sock]),
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ 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) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(csock, State)}
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(lsock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (async connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, async_connect)
+ end},
+ #{desc => "connect (async) to server",
+ cmd => fun(#{sock := Sock,
+ server_sa := SSA,
+ connect := Connect} = State) ->
+ case Connect(Sock, SSA) of
+ ok ->
+ ?SEV_IPRINT("ok -> "
+ "unexpected success => SKIP",
+ []),
+ {skip, unexpected_success};
+ {select, {select_info, ST, SR}} ->
+ ?SEV_IPRINT("select ->"
+ "~n tag: ~p"
+ "~n ref: ~p", [ST, SR]),
+ {ok, State#{connect_stag => ST,
+ connect_sref => SR}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (connect select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, connect_sref := Ref}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ ?SEV_IPRINT("select message ->"
+ "~n ref: ~p", [Ref]),
+ ok
+ after 5000 ->
+ ?SEV_EPRINT("timeout: "
+ "~n message queue: ~p",
+ [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "connect (async) to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA, connect := Connect}) ->
+ case Connect(Sock, SSA) of
+ ok ->
+ ok;
+ {select, SelectInfo} ->
+ {error, {unexpected_select, SelectInfo}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+ #{desc => "get peername",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case socket:peername(Sock) of
+ {ok, SockAddr} ->
+ ?SEV_IPRINT("Peer Name: ~p", [SockAddr]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ 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) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ State2 = maps:remove(sock, State),
+ State3 = maps:remove(connect_stag, State2),
+ State4 = maps:remove(connect_sref, State3),
+ {ok, State4}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order client to continue (async connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, async_connect),
+ ok
+ end},
+ #{desc => "await client ready (connect select)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, select)
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?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",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+ i("await evaluator(s)"),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvfrom,
+%% since its much more difficult to "arrange" for sendto.
+%%
+api_a_sendto_and_recvfrom_udp4(suite) ->
+ [];
+api_a_sendto_and_recvfrom_udp4(doc) ->
+ [];
+api_a_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendto_and_recvfrom_udp4,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv6 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvfrom,
+%% since its much more difficult to "arrange" for sendto.
+%%
+api_a_sendto_and_recvfrom_udp6(suite) ->
+ [];
+api_a_sendto_and_recvfrom_udp6(doc) ->
+ [];
+api_a_sendto_and_recvfrom_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendto_and_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%%
+api_a_sendmsg_and_recvmsg_udp4(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp4(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendmsg_and_recvmsg_udp4,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ %% ctrl => CMsgHdrs,
+ iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv6 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%%
+api_a_sendmsg_and_recvmsg_udp6(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp6(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendmsg_and_recvmsg_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ %% ctrl => CMsgHdrs,
+ iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_send_and_recv_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ ServerSA = LSA#{port => Port},
+ ?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, RecvRef}} ->
+ ?SEV_IPRINT("expected select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, RecvRef]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => RecvRef}};
+ {ok, X} ->
+ {error, {unexpected_succes, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (request)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, {Src, ?BASIC_REQ}} ->
+ {ok, State#{req_src => Src}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+
+ #{desc => "await continue (send reply)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_reply)
+ end},
+ #{desc => "send reply",
+ cmd => fun(#{sock := Sock, req_src := Src, send := Send}) ->
+ Send(Sock, ?BASIC_REP, Src)
+ end},
+ #{desc => "announce ready (send)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, ServerSA} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester,
+ server_sa => ServerSA}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "open socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ Sock = sock_open(Domain, dgram, udp),
+ SA = sock_sockname(Sock),
+ {ok, State#{sock => Sock, sa => SA}}
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, lsa := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (send request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send request",
+ cmd => fun(#{sock := Sock, server_sa := Server, send := Send}) ->
+ Send(Sock, ?BASIC_REQ, Server)
+ end},
+ #{desc => "announce ready (send request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv reply (with nowait)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, RecvRef}} ->
+ {ok, State#{recv_stag => Tag,
+ recv_sref => RecvRef}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (reply)",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, {_Src, ?BASIC_REP}} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ {ok, State4};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, ServerSA} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_sa => ServerSA}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid,
+ server_sa := ServerSA} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, ServerSA),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv_select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order client continue (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, send_req)
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_req)
+ end},
+
+ #{desc => "order client continue (recv)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await client ready (recv_select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, recv_select)
+ end},
+ #{desc => "order server continue (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_reply),
+ ok
+ end},
+ #{desc => "await server ready (send)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, send)
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, select)
+ end},
+ #{desc => "await client ready (recv reply)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, recv_rep)
+ end},
+
+ %% Terminations
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(client, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState,
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState,
+ Client = ?SEV_START("client", ClientSeq, ClientInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an IPv4 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recv,
+%% since its much more difficult to "arrange" for send.
+%% We *also* test async for accept.
+api_a_send_and_recv_tcp4(suite) ->
+ [];
+api_a_send_and_recv_tcp4(doc) ->
+ [];
+api_a_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_send_and_recv_tcp4,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an IPv6 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recv,
+%% since its much more difficult to "arrange" for send.
+%% We *also* test async for accept.
+api_a_send_and_recv_tcp6(suite) ->
+ [];
+api_a_send_and_recv_tcp6(doc) ->
+ [];
+api_a_send_and_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_send_and_recv_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an IPv4 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%% We *also* test async for accept.
+api_a_sendmsg_and_recvmsg_tcp4(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp4(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_sendmsg_and_recvmsg_tcp4,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an IPv6 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%% We *also* test async for accept.
+api_a_sendmsg_and_recvmsg_tcp6(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp6(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_sendmsg_and_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_send_and_recv_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock, nowait) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("accept select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{accept_stag => Tag,
+ accept_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{lsock := Sock, accept_sref := Ref}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "await connection (again)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock, nowait) of
+ {ok, Sock} ->
+ ?SEV_IPRINT("accepted: "
+ "~n Sock: ~p", [Sock]),
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (recv request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_req)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (request)",
+ cmd => fun(#{csock := Sock, recv := Recv} = _State) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REQ} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+
+ #{desc => "await continue (send reply)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_rep)
+ end},
+ #{desc => "send reply",
+ cmd => fun(#{csock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REP)
+ end},
+ #{desc => "announce ready (send reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_rep),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock}) ->
+ socket:close(Sock)
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ #{desc => "await continue (send request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send request (to server)",
+ cmd => fun(#{sock := Sock, send := Send}) ->
+ ok = Send(Sock, ?BASIC_REQ)
+ end},
+ #{desc => "announce ready (send request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+
+ #{desc => "try recv reply (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (reply)",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ {ok, ?BASIC_REP} = Recv(Sock),
+ ok
+ end},
+ #{desc => "announce ready (recv reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+ #{desc => "order client to continue (with connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept)
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+
+ #{desc => "order server to continue (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_req),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "order client to continue (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send request)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_req)
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_req)
+ end},
+
+ #{desc => "order client to continue (recv reply)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_rep),
+ ok
+ end},
+ #{desc => "await client ready (recv select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, recv_select)
+ end},
+ #{desc => "order server to continue (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_rep),
+ ok
+ end},
+ #{desc => "await server ready (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, send_rep)
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, select)
+ end},
+ #{desc => "await client ready (reply recv)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_rep)
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvfrom,
+%% wait some time and then cancel. IPv4
+%%
+api_a_recvfrom_cancel_udp4(suite) ->
+ [];
+api_a_recvfrom_cancel_udp4(doc) ->
+ [];
+api_a_recvfrom_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvfrom_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvfrom,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvfrom_cancel_udp6(suite) ->
+ [];
+api_a_recvfrom_cancel_udp6(doc) ->
+ [];
+api_a_recvfrom_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvfrom_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv4
+%%
+api_a_recvmsg_cancel_udp4(suite) ->
+ [];
+api_a_recvmsg_cancel_udp4(doc) ->
+ [];
+api_a_recvmsg_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvmsg_cancel_udp6(suite) ->
+ [];
+api_a_recvmsg_cancel_udp6(doc) ->
+ [];
+api_a_recvmsg_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_recv_cancel_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ ServerSA = LSA#{port => Port},
+ ?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{sock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{sock := Sock, recv_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, ServerSA} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_sa => ServerSA}}
+ end},
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server continue (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% Terminations
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState,
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Tester]).
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to accept,
+%% wait some time and then cancel. IPv4
+%%
+api_a_accept_cancel_tcp4(suite) ->
+ [];
+api_a_accept_cancel_tcp4(doc) ->
+ [];
+api_a_accept_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_accept_cancel_tcp4,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ accept => Accept},
+ ok = api_a_accept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to accept,
+%% wait some time and then cancel. IPv6
+%%
+api_a_accept_cancel_tcp6(suite) ->
+ [];
+api_a_accept_cancel_tcp6(doc) ->
+ [];
+api_a_accept_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_accept_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ accept => Accept},
+ ok = api_a_accept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_accept_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock, accept := Accept} = State) ->
+ case Accept(LSock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("accept select: "
+ "~n T: ~p"
+ "~n R: ~p", [T, R]),
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{lsock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{lsock := Sock, accept_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server to continue (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recv,
+%% wait some time and then cancel. IPv4
+%%
+api_a_recv_cancel_tcp4(suite) ->
+ [];
+api_a_recv_cancel_tcp4(doc) ->
+ [];
+api_a_recv_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recv_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recv,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recv_cancel_tcp6(suite) ->
+ [];
+api_a_recv_cancel_tcp6(doc) ->
+ [];
+api_a_recv_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recv_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv4
+%%
+api_a_recvmsg_cancel_tcp4(suite) ->
+ [];
+api_a_recvmsg_cancel_tcp4(doc) ->
+ [];
+api_a_recvmsg_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvmsg_cancel_tcp6(suite) ->
+ [];
+api_a_recvmsg_cancel_tcp6(doc) ->
+ [];
+api_a_recvmsg_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_recv_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, CSock} ->
+ {ok, State#{csock => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (nowait recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [T, R]),
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{csock := Sock, recv_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock}) ->
+ socket:close(Sock)
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "order client to continue (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept)
+ end},
+
+ #{desc => "order server to continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server to continue (send request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvfrom
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes. IPv4
+%%
+api_a_mrecvfrom_cancel_udp4(suite) ->
+ [];
+api_a_mrecvfrom_cancel_udp4(doc) ->
+ [];
+api_a_mrecvfrom_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvfrom_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvfrom
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecvfrom_cancel_udp6(suite) ->
+ [];
+api_a_mrecvfrom_cancel_udp6(doc) ->
+ [];
+api_a_mrecvfrom_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvfrom_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes. IPv4
+%%
+api_a_mrecvmsg_cancel_udp4(suite) ->
+ [];
+api_a_mrecvmsg_cancel_udp4(doc) ->
+ [];
+api_a_mrecvmsg_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecvmsg_cancel_udp6(suite) ->
+ [];
+api_a_mrecvmsg_cancel_udp6(doc) ->
+ [];
+api_a_mrecvmsg_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_mrecv_cancel_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, sock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, sock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(recv_select_info, State),
+ State2 = maps:remove(tester, State1),
+ State3 = maps:remove(sock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt-server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt-server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (recv)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (recv select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, recv_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (recv)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (recv select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, recv_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+ %% Terminations
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Tester]).
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to accept
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv4
+%%
+api_a_maccept_cancel_tcp4(suite) ->
+ [];
+api_a_maccept_cancel_tcp4(doc) ->
+ [];
+api_a_maccept_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_maccept_cancel_tcp4,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ accept => Accept},
+ ok = api_a_maccept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to accept
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_maccept_cancel_tcp6(suite) ->
+ [];
+api_a_maccept_cancel_tcp6(doc) ->
+ [];
+api_a_maccept_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_maccept_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ accept => Accept},
+ ok = api_a_maccept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_maccept_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lsock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock, accept := Accept} = State) ->
+ case Accept(LSock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("accept select: "
+ "~n T: ~p"
+ "~n R: ~p", [T, R]),
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{lsock := Sock,
+ accept_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(lsock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, lsock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "try accept request (with nowait, expect select)",
+ cmd => fun(#{lsock := Sock, accept := Accept} = State) ->
+ case Accept(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{lsock := Sock,
+ accept_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(tester, State),
+ State2 = maps:remove(accept_select_info, State1),
+ State3 = maps:remove(lsock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt-server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt-server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server continue (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (accept)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (accept select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, accept_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (accept)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (accept select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, accept_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recv
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv4
+%%
+api_a_mrecv_cancel_tcp4(suite) ->
+ [];
+api_a_mrecv_cancel_tcp4(doc) ->
+ [];
+api_a_mrecv_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecv_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recv
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecv_cancel_tcp6(suite) ->
+ [];
+api_a_mrecv_cancel_tcp6(doc) ->
+ [];
+api_a_mrecv_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecv_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv4
+%%
+api_a_mrecvmsg_cancel_tcp4(suite) ->
+ [];
+api_a_mrecvmsg_cancel_tcp4(doc) ->
+ [];
+api_a_mrecvmsg_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecvmsg_cancel_tcp6(suite) ->
+ [];
+api_a_mrecvmsg_cancel_tcp6(doc) ->
+ [];
+api_a_mrecvmsg_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet6,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_mrecv_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, CSock} ->
+ {ok, State#{csock => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester, csock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept, Sock),
+ ok
+ end},
+
+ #{desc => "await continue (nowait recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [T, R]),
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, sock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(recv_select_info, State),
+ State2 = maps:remove(tester, State1),
+ State3 = maps:remove(sock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "order client to continue (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, accept),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (recv)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (recv select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, recv_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (recv)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (recv select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, recv_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+ %% Terminations
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% API OPTIONS %%
@@ -2530,8 +7502,7 @@ api_opt_simple_otp_rcvbuf_option() ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -2776,8 +7747,7 @@ api_opt_simple_otp_rcvbuf_option() ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create socket",
@@ -3173,7 +8143,7 @@ api_opt_simple_otp_controlling_process(suite) ->
api_opt_simple_otp_controlling_process(doc) ->
[];
api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(api_opt_simple_otp_controlling_process,
fun() -> api_opt_simple_otp_controlling_process() end).
@@ -3418,6 +8388,2027 @@ api_opt_simple_otp_controlling_process() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptconn for UDP.
+%% This should be possible to get but not set.
+
+api_opt_sock_acceptconn_udp(suite) ->
+ [];
+api_opt_sock_acceptconn_udp(doc) ->
+ [];
+api_opt_sock_acceptconn_udp(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptconn_udp,
+ fun() ->
+ has_support_sock_acceptconn()
+ end,
+ fun() -> api_opt_sock_acceptconn_udp() end).
+
+
+
+api_opt_sock_acceptconn_udp() ->
+ Opt = acceptconn,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify socket (before bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, enoprotoopt = Reason} ->
+ %% On some platforms this is not accepted
+ %% for UDP, so skip this part (UDP).
+ ?SEV_EPRINT("Expected Failure: "
+ "~p => SKIP", [Reason]),
+ (catch socket:close(Sock)),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify socket (before bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p",
+ [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "bind socket to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify socket (after bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify socket (after bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p",
+ [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptconn for TCP.
+%% This should be possible to get but not set.
+
+api_opt_sock_acceptconn_tcp(suite) ->
+ [];
+api_opt_sock_acceptconn_tcp(doc) ->
+ [];
+api_opt_sock_acceptconn_tcp(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptconn_tcp,
+ fun() ->
+ has_support_sock_acceptconn()
+ end,
+ fun() -> api_opt_sock_acceptconn_tcp() end).
+
+
+
+api_opt_sock_acceptconn_tcp() ->
+ Opt = acceptconn,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (before bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, enoprotoopt = Reason} ->
+ ?SEV_EPRINT("Expected Failure: "
+ "~p => SKIP", [Reason]),
+ (catch socket:close(Sock)),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (before bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "bind listen socket to local address",
+ cmd => fun(#{lsock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{server_sa => LSA#{port => Port}}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "make listen socket accept connections",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case socket:listen(Sock) of
+ ok ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after listen)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Accepting connections"),
+ ok;
+ {ok, false} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Not accepting connections"),
+ {error, {unexpected_success, {Opt, false}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after listen)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, false) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=false)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "create (connecting) socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{csockc => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "bind connecting socket to local address",
+ cmd => fun(#{csockc := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify connecting socket (before connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connecting socket (before connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "connect to server",
+ cmd => fun(#{csockc := Sock, server_sa := SSA} = _State) ->
+ case socket:connect(Sock, SSA) of
+ ok ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "accept connection",
+ cmd => fun(#{lsock := Sock} = State) ->
+ case socket:accept(Sock) of
+ {ok, CSock} ->
+ {ok, State#{csocks => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify connecting socket (after connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connecting socket (after connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "[get] verify connected socket",
+ cmd => fun(#{csocks := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connected socket",
+ cmd => fun(#{csocks := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after connect)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Accepting connections"),
+ ok;
+ {ok, false} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Not accepting connections"),
+ {error, {unexpected_success, {Opt, false}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after connect)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, false) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=false)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close connecting socket(s)",
+ cmd => fun(#{csockc := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(csockc, State0),
+ State2 = maps:remove(csocks, State1), %% Auto-close
+ {ok, maps:remove(csockc, State2)}
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(lsock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptfilter. PLACEHOLDER!
+
+api_opt_sock_acceptfilter(suite) ->
+ [];
+api_opt_sock_acceptfilter(doc) ->
+ [];
+api_opt_sock_acceptfilter(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptfilter,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option bindtodevice.
+%% It has not always been possible to 'get' this option
+%% (atleast on linux).
+
+api_opt_sock_bindtodevice(suite) ->
+ [];
+api_opt_sock_bindtodevice(doc) ->
+ [];
+api_opt_sock_bindtodevice(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_bindtodevice,
+ fun() -> has_support_sock_bindtodevice() end,
+ fun() -> api_opt_sock_bindtodevice() end).
+
+
+api_opt_sock_bindtodevice() ->
+ Opt = bindtodevice,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name, addr := Addr}} ->
+ ?SEV_IPRINT("local host info (~p): "
+ "~n Name: ~p"
+ "~n Addr: ~p",
+ [Domain, Name, Addr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ {ok, State#{dev => Name,
+ local_sa => LSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create UDP socket 1",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create UDP socket 2",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket 1",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket 2",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify UDP socket 1 (before bindtodevice)",
+ cmd => fun(#{usock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, enoprotoopt = Reason} ->
+ ?SEV_EPRINT("Unexpected Failure: ~p => SKIP",
+ [Reason]),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify UDP socket 2 (before bind)",
+ cmd => fun(#{usock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 1 (before bindtodevice)",
+ cmd => fun(#{tsock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 2 (before bind)",
+ cmd => fun(#{tsock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "Bind UDP socket 1 to device",
+ cmd => fun(#{usock1 := Sock, dev := Dev} = State) ->
+ case Set(Sock, Dev) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, eperm = Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ (catch socket:close(Sock)),
+ {ok, State#{usock1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind UDP socket 2 to local address",
+ cmd => fun(#{usock2 := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind TCP socket 1 to device",
+ cmd => fun(#{usock1 := USock1,
+ tsock1 := Sock, dev := Dev} = State) ->
+ case Set(Sock, Dev) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, eperm = Reason} when (USock1 =:= skip) ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ {skip, Reason};
+ {error, eperm = Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ (catch socket:close(Sock)),
+ {ok, State#{tsock1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind TCP socket 2 to local address",
+ cmd => fun(#{tsock2 := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify UDP socket 1 (after bindtodevice)",
+ cmd => fun(#{usock1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP'ed (previous eperm)"),
+ ok;
+ (#{usock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify UDP socket 2 (after bind)",
+ cmd => fun(#{usock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 1 (after bindtodevice)",
+ cmd => fun(#{tsock1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP'ed (previous eperm)"),
+ ok;
+ (#{tsock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 2 (after bind)",
+ cmd => fun(#{tsock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ %% *** Termination ***
+ #{desc => "close UDP socket 1",
+ cmd => fun(#{usock1 := skip} = State) ->
+ ?SEV_IPRINT("SKIP'ed (already closed)"),
+ {ok, maps:remove(usock1, State)};
+ (#{usock1 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(usock1, State)}
+ end},
+ #{desc => "close UDP socket 2",
+ cmd => fun(#{usock2 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(usock2, State)}
+ end},
+ #{desc => "close TCP socket 1",
+ cmd => fun(#{tsock1 := skip} = State) ->
+ ?SEV_IPRINT("SKIP'ed (already closed)"),
+ {ok, maps:remove(tsock1, State)};
+ (#{tsock1 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(tsock1, State)}
+ end},
+ #{desc => "close TCP socket 2",
+ cmd => fun(#{tsock2 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(tsock2, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option broadcast.
+%% Make it possible for datagram sockets to send packets to a broadcast
+%% address (IPv4 only).
+
+api_opt_sock_broadcast(suite) ->
+ [];
+api_opt_sock_broadcast(doc) ->
+ [];
+api_opt_sock_broadcast(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_broadcast,
+ fun() -> has_support_sock_broadcast() end,
+ fun() -> api_opt_sock_broadcast() end).
+
+
+api_opt_sock_broadcast() ->
+ Opt = broadcast,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[socket 1] create UDP socket (listening 1)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] Bind UDP socket (to limited broadcast address)",
+ cmd => fun(#{sock1 := Sock} = State) ->
+ BSA = #{family => inet,
+ addr => broadcast},
+ ?SEV_IPRINT("Try bind (socket 1) to: "
+ "~n ~p", [BSA]),
+ case socket:bind(Sock, BSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa1 => BSA#{port => Port}}};
+ {error, eaddrnotavail = Reason} ->
+ ?SEV_IPRINT("~p => "
+ "SKIP limited broadcast test",
+ [Reason]),
+ {ok, State#{sa1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] UDP socket sockname",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock1 := Sock} = _State) ->
+ case socket:sockname(Sock) of
+ {ok, SA} ->
+ ?SEV_IPRINT("SA: ~p", [SA]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 2] create UDP socket (listening 2)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] Bind UDP socket (to subnet-directed broadcast address)",
+ cmd => fun(#{sock2 := Sock,
+ bsa := BSA} = State) ->
+ ?SEV_IPRINT("Try bind (socket 1) to: "
+ "~n ~p", [BSA]),
+ case socket:bind(Sock, BSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa2 => BSA#{port => Port}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] UDP socket sockname",
+ cmd => fun(#{sock2 := Sock} = _State) ->
+ case socket:sockname(Sock) of
+ {ok, SA} ->
+ ?SEV_IPRINT("SA: ~p", [SA]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] create UDP socket (sender)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock3 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3][get] verify UDP socket (before bind and set)",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast not allowed"),
+ ok;
+ {ok, true} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast already allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] Try make broadcast allowed",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Set(Sock, true) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast now allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] verify UDP socket broadcast allowed",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast allowed"),
+ ok;
+ {ok, false} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast *not* allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] Bind UDP socket (to local address)",
+ cmd => fun(#{sock3 := Sock, lsa := LSA} = State) ->
+ ?SEV_IPRINT("Try bind (socket 2) to: "
+ "~n ~p", [LSA]),
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa3 => LSA#{port => Port}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] verify UDP socket (after set)",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast allowed"),
+ ok;
+ {ok, false} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast not allowed"),
+ {error, not_allowed};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] try send to limited broadcast address",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock3 := Sock,
+ sa1 := Dest} = _State) ->
+ Data = list_to_binary("hejsan"),
+ ?SEV_IPRINT("try send to bradcast address: "
+ "~n ~p", [Dest]),
+ case socket:sendto(Sock, Data, Dest) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast message sent"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] try recv",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock1 := Sock} = State) ->
+ case socket:recvfrom(Sock, 0, 5000) of
+ {ok, _} ->
+ ?SEV_IPRINT("Expected Success: "
+ "received message"),
+ ok;
+ {error, timeout = Reason} ->
+ %% Some platforms seem to balk at this.
+ %% It spossible to bind to this, and
+ %% send to it, but no data is received.
+ %% At some point we should investigate...
+ %% For now, we just skip this part of
+ %% the test...
+ ?SEV_IPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ {ok, State#{sa1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] try send to subnet-directed broadcast address",
+ cmd => fun(#{sock3 := Sock,
+ sa2 := Dest} = _State) ->
+ Data = list_to_binary("hejsan"),
+ ?SEV_IPRINT("try send to bradcast address: "
+ "~n ~p", [Dest]),
+ case socket:sendto(Sock, Data, Dest) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast message sent"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] try recv",
+ cmd => fun(#{sock2 := Sock, sa1 := SA1} = _State) ->
+ case socket:recvfrom(Sock, 0, 5000) of
+ {ok, _} ->
+ ?SEV_IPRINT("Expected Success: "
+ "received message"),
+ ok;
+ {error, timeout = Reason} when (SA1 =:= skip) ->
+ ?SEV_IPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ {skip, "receive timeout"};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "[socket 3] close UDP socket (sender)",
+ cmd => fun(#{sock3 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock3, State0),
+ State2 = maps:remove(sa3, State1),
+ {ok, State2}
+ end},
+ #{desc => "[socket 2] close UDP socket (listener 2)",
+ cmd => fun(#{sock2 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock2, State0),
+ State2 = maps:remove(sa2, State1),
+ {ok, State2}
+ end},
+ #{desc => "[socket 1] close UDP socket (listener 1)",
+ cmd => fun(#{sock1 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock1, State0),
+ State2 = maps:remove(sa1, State1),
+ {ok, State2}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option debug.
+%% On linux, this test requires that the user running the test to have
+%% CAP_NET_ADMIN capabilities or be root (effective user ID of 0),
+%% therefor we explicitly test for the result eacces when attempting to
+%% set, and skip if we get it.
+
+api_opt_sock_debug(suite) ->
+ [];
+api_opt_sock_debug(doc) ->
+ [];
+api_opt_sock_debug(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_debug,
+ fun() -> has_support_sock_debug() end,
+ fun() -> api_opt_sock_debug() end).
+
+
+api_opt_sock_debug() ->
+ Opt = debug,
+ Set = fun(S, Val) when is_integer(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create UDP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get current debug value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Debug} when is_integer(Debug) ->
+ ?SEV_IPRINT("Success: ~p", [Debug]),
+ {ok, State#{debug => Debug}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try enable socket debug",
+ cmd => fun(#{sock := Sock, debug := Debug} = State) ->
+ NewDebug = Debug + 1,
+ case Set(Sock, NewDebug) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{debug => NewDebug}};
+ {error, eacces = Reason} ->
+ ?SEV_EPRINT("NO ACCESS => SKIP"),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Get current (new) debug value",
+ cmd => fun(#{sock := Sock, debug := Debug} = _State) ->
+ case Get(Sock) of
+ {ok, Debug} when is_integer(Debug) ->
+ ?SEV_IPRINT("Success: ~p", [Debug]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option domain.
+%% This is a read only option. Also not available on all platforms.
+
+api_opt_sock_domain(suite) ->
+ [];
+api_opt_sock_domain(doc) ->
+ [];
+api_opt_sock_domain(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_domain,
+ fun() -> has_support_sock_domain() end,
+ fun() -> api_opt_sock_domain() end).
+
+
+api_opt_sock_domain() ->
+ Opt = domain,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create IPv4 UDP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get domain for the UDP socket",
+ cmd => fun(#{domain := Domain, usock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Domain} ->
+ ?SEV_IPRINT("Success: ~p", [Domain]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get domain for the TCP socket",
+ cmd => fun(#{domain := Domain, tsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Domain} ->
+ ?SEV_IPRINT("Success: ~p", [Domain]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{usock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(usock, State0),
+ {ok, State1}
+ end},
+ #{desc => "close TCP socket",
+ cmd => fun(#{tsock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(tsock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option dontroute.
+%% The man page has the following to say:
+%% "Don't send via a gateway, send only to directly connected hosts.
+%% The same effect can be achieved by setting the MSG_DONTROUTE
+%% flag on a socket send(2) operation."
+%% Since its "kind of" difficult to check if it actually takes an
+%% effect (you would need a gateway for that and a machine "on the
+%% other side"), we only test if we can set and get the value.
+%% Better then nothing.
+
+api_opt_sock_dontroute(suite) ->
+ [];
+api_opt_sock_dontroute(doc) ->
+ [];
+api_opt_sock_dontroute(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_dontroute,
+ fun() -> has_support_sock_dontroute() end,
+ fun() -> api_opt_sock_dontroute() end).
+
+
+api_opt_sock_dontroute() ->
+ Opt = dontroute,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create UDP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get current value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Val} when is_boolean(Val) ->
+ ?SEV_IPRINT("Success: ~p", [Val]),
+ {ok, State#{dontroute => Val}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try change value",
+ cmd => fun(#{sock := Sock, dontroute := Current} = State) ->
+ New = not Current,
+ ?SEV_IPRINT("Change from ~p to ~p", [Current, New]),
+ case Set(Sock, New) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{dontroute => New}};
+ {error, eopnotsupp = Reason} ->
+ ?SEV_EPRINT("Expected Failure: ~p",
+ [Reason]),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Verify changed value",
+ cmd => fun(#{sock := Sock, dontroute := Val} = _State) ->
+ case Get(Sock) of
+ {ok, Val} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option error. PLACEHOLDER!
+
+api_opt_sock_error(suite) ->
+ [];
+api_opt_sock_error(doc) ->
+ [];
+api_opt_sock_error(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_error,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option keepalive.
+%% This is bit tricky to test, partly because we have no control over
+%% the underlying TCP timeouts. So, for now, we just test that we can
+%% change the value.
+
+api_opt_sock_keepalive(suite) ->
+ [];
+api_opt_sock_keepalive(doc) ->
+ [];
+api_opt_sock_keepalive(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_keepalive,
+ fun() -> has_support_sock_keepalive() end,
+ fun() -> api_opt_sock_keepalive() end).
+
+
+api_opt_sock_keepalive() ->
+ Opt = keepalive,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create TCP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get current value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Val} when is_boolean(Val) ->
+ ?SEV_IPRINT("Success: ~p", [Val]),
+ {ok, State#{keepalive => Val}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try change the value",
+ cmd => fun(#{sock := Sock, keepalive := Current} = State) ->
+ New = not Current,
+ ?SEV_IPRINT("Try change value from ~p to ~p",
+ [Current, New]),
+ case Set(Sock, New) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{keepalive => New}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Verify (new) current value",
+ cmd => fun(#{sock := Sock, keepalive := Val} = _State) ->
+ case Get(Sock) of
+ {ok, Val} ->
+ ?SEV_IPRINT("Expected Success (~p)", [Val]),
+ ok;
+ {ok, OtherVal} ->
+ ?SEV_IPRINT("Unexpected Success: ~p",
+ [OtherVal]),
+ {error, {unexpected_success_value,
+ Val, OtherVal}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option linger. PLACEHOLDER!
+
+api_opt_sock_linger(suite) ->
+ [];
+api_opt_sock_linger(doc) ->
+ [];
+api_opt_sock_linger(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_linger,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests that the add_mambership and drop_membership ip options work.
+%% We create one server and two clients. The server only send messages,
+%% the clients only receives messages.
+%% An UDP datagram is forbidden (RFC 1122) from having a source address
+%% that is a multicast address (or a broadcast address).
+%% So, the server create a socket "for sending" and the clients sockets
+%% "for receiving".
+%% Sending socket: Bound to the local address (and any port).
+%% When sending, the dest will be the multicast address
+%% and port of the receiving socket.
+%% Receiving socket: Bound to the multicast address and port.
+api_opt_ip_add_drop_membership(suite) ->
+ [];
+api_opt_ip_add_drop_membership(doc) ->
+ ["OTP-15908 (ERL-980)"];
+api_opt_ip_add_drop_membership(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_ip_add_drop_membership,
+ fun() ->
+ has_support_ip_add_membership(),
+ has_support_ip_drop_membership(),
+ has_support_ip_multicast()
+ end,
+ fun() -> api_opt_ip_add_drop_membership() end).
+
+
+api_opt_ip_add_drop_membership() ->
+ Set = fun(S, Key, Val) ->
+ socket:setopt(S, ip, Key, Val)
+ end,
+ AddMembership = fun(S, Val) -> Set(S, add_membership, Val) end,
+ DropMembership = fun(S, Val) -> Set(S, drop_membership, Val) end,
+
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, MSA} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, msa => MSA}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make recv socket reuse addr",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case socket:setopt(Sock, socket, reuseaddr, true) of
+ ok ->
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed set reuseaddr: "
+ "~n ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "bind recv socket to multicast address",
+ cmd => fun(#{sock := Sock, msa := MSA} = State) ->
+ case socket:bind(Sock, MSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("bound to:"
+ "~n ~p", [Port]),
+ {ok, State#{msa => MSA#{port => Port}}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (add_membership)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, add_membership)
+ end},
+ #{desc => "add membership",
+ cmd => fun(#{sock := Sock,
+ msa := #{addr := MAddr},
+ local_sa := #{addr := Addr}} = State) ->
+ MReq = #{multiaddr => MAddr,
+ interface => Addr},
+ ?SEV_IPRINT("try add membership to:"
+ "~n ~p", [MReq]),
+ case AddMembership(Sock, MReq) of
+ ok ->
+ ?SEV_IPRINT("membership added"),
+ {ok, State#{mreq => MReq}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed adding membership to: "
+ "~n ~p"
+ "~n Reason: ~p",
+ [MReq, Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (add-membership)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, add_membership),
+ ok
+ end},
+
+ #{desc => "await continue (drop_membership)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, drop_membership)
+ end},
+ #{desc => "drop membership",
+ cmd => fun(#{sock := Sock,
+ mreq := MReq} = State) ->
+ ?SEV_IPRINT("try drop membership from:"
+ "~n ~p", [MReq]),
+ case DropMembership(Sock, MReq) of
+ ok ->
+ ?SEV_IPRINT("membership dropped"),
+ {ok, maps:remove(mreq, State)};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed drop membership from: "
+ "~n ~p"
+ "~n Reason: ~p",
+ [MReq, Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (drop-membership)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, drop_membership),
+ ok
+ end},
+
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Server} = _State) ->
+ _MRef = erlang:monitor(process, Server),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid, msa := MSA} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, MSA),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = _State) ->
+ case ?SEV_AWAIT_READY(Pid, server, init) of
+ ok ->
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Start of server failed: "
+ "~n ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (add-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, add_membership),
+ ok
+ end},
+ #{desc => "await server ready (add-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, add_membership)
+ end},
+
+ #{desc => "order server to continue (drop-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, drop_membership),
+ ok
+ end},
+ #{desc => "await server ready (drop-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, drop_membership)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ %% *** Termination ***
+ #{desc => "order server terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ {ok, maps:remove(server, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ Domain = inet,
+ i("get multicast address"),
+ MAddr = which_ip_multicast_address(),
+ MSA = #{family => Domain, addr => MAddr},
+
+ i("start server evaluator"),
+ ServerInitState = #{domain => Domain},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{domain => Domain,
+ msa => MSA,
+ server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester, Server]).
+
+
+
+which_ip_multicast_address() ->
+ which_multicast_address(inet).
+
+which_multicast_address(Domain) ->
+ case os:type() of
+ {unix, linux} ->
+ WhichMAddr = fun([_, _, MAddr]) -> MAddr end,
+ which_multicast_address2(Domain, WhichMAddr);
+
+ {unix, sunos} ->
+ WhichMAddr = fun([_, MAddr, _]) -> MAddr end,
+ which_multicast_address2(Domain, WhichMAddr);
+
+ Type ->
+ %% Actually, what is "not supported". is netstat!
+ not_supported({multicast, Type})
+ end.
+
+%% Note that the 'netstat -g' table looks different on linux and SunOS
+%% Linux: IfName - RefCnt - Group
+%% SunOS: IfName - Group - RefCnt
+
+which_multicast_address2(Domain, WhichMAddr) ->
+ IfName = which_local_host_ifname(Domain),
+ %% On some platforms the netstat barfs out some crap on stderr
+ %% before the actual info...
+ case os:cmd("netstat -g 2>/dev/null | grep " ++ IfName) of
+ [] ->
+ %% Can't figure out if we support multicast or not...
+ not_supported(no_netstat);
+ NetstatGroupsStr ->
+ try
+ begin
+ NetstatGroups0 = string:tokens(NetstatGroupsStr, [$\n]),
+ NetstatGroups = [string:tokens(G, [$ ]) ||
+ G <- NetstatGroups0],
+ MAddrs = [WhichMAddr(NetstatGroup) ||
+ NetstatGroup <- NetstatGroups],
+ which_multicast_address3(Domain, MAddrs)
+ end
+ catch
+ throw:E:_ ->
+ throw(E);
+ C:E:S ->
+ not_supported({multicast, {C,E,S}})
+ end
+ end.
+
+which_multicast_address3(_Domain, []) ->
+ not_supported({multicast, no_valid_addrs});
+which_multicast_address3(Domain, [MAddrStr|MAddrs]) ->
+ %% Even on linux some of these are not actually addresses, but
+ %% "host names", such as all-systems.mcast.net. But both
+ %% address strings, such as "224.0.0.251" and host name strings
+ %% gets translated into an address by the inet:inet:getaddr/2.
+ case inet:getaddr(MAddrStr, Domain) of
+ {ok, MAddr} ->
+ MAddr;
+ {error, _} ->
+ which_multicast_address3(Domain, MAddrs)
+ end.
+
+which_local_host_ifname(Domain) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name}} ->
+ Name;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% API OPERATIONS WITH TIMEOUT %%
@@ -3434,11 +10425,11 @@ api_to_connect_tcp4(suite) ->
api_to_connect_tcp4(doc) ->
[];
api_to_connect_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
Cond = fun() -> api_to_connect_cond() end,
tc_try(api_to_connect_tcp4,
Cond,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet,
backlog => 1,
timeout => 5000,
@@ -3454,7 +10445,9 @@ api_to_connect_cond() ->
%% So, just to simplify, we require atleast 4.15
api_to_connect_cond({unix, linux}, {Maj, Min, _Rev}) ->
if
- ((Maj >= 4) andalso (Min >= 15)) ->
+ (Maj > 4) ->
+ ok;
+ ((Maj =:= 4) andalso (Min >= 15)) ->
ok;
true ->
skip("TC does not work")
@@ -3491,10 +10484,10 @@ api_to_connect_tcp6(suite) ->
api_to_connect_tcp6(doc) ->
[];
api_to_connect_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_connect_tcp6,
fun() -> has_support_ipv6(), api_to_connect_cond() end,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet6,
backlog => 1,
timeout => 5000,
@@ -3531,8 +10524,7 @@ api_to_connect_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -3603,8 +10595,7 @@ api_to_connect_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create node",
@@ -3754,8 +10745,7 @@ api_to_connect_tcp(InitState) ->
end},
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "order server start",
@@ -3906,9 +10896,7 @@ api_toc_tcp_client_await_terminate(Parent) ->
end.
api_to_connect_tcp_await_timeout(To, ServerSA, Domain, ConLimit) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
NewSock = fun() ->
S = case socket:open(Domain, stream, tcp) of
{ok, Sock} ->
@@ -3986,9 +10974,9 @@ api_to_accept_tcp4(suite) ->
api_to_accept_tcp4(doc) ->
[];
api_to_accept_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_accept_tcp4,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet, timeout => 5000},
ok = api_to_accept_tcp(InitState)
end).
@@ -4003,10 +10991,10 @@ api_to_accept_tcp6(suite) ->
api_to_accept_tcp6(doc) ->
[];
api_to_accept_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_accept_tcp4,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet6, timeout => 5000},
ok = api_to_accept_tcp(InitState)
end).
@@ -4020,8 +11008,7 @@ api_to_accept_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
@@ -4145,8 +11132,7 @@ api_to_maccept_tcp(InitState) ->
end},
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
@@ -4489,6 +11475,7 @@ api_to_send_tcp6(doc) ->
[];
api_to_send_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_send_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_send_tcp(inet6)
@@ -4521,6 +11508,7 @@ api_to_sendto_udp6(doc) ->
[];
api_to_sendto_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_sendto_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_sendto_to_udp(inet6)
@@ -4553,6 +11541,7 @@ api_to_sendmsg_tcp6(doc) ->
[];
api_to_sendmsg_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_sendmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_sendmsg_tcp(inet6)
@@ -4587,6 +11576,7 @@ api_to_recv_udp6(doc) ->
[];
api_to_recv_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_recv_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_recv_udp(inet6)
@@ -4602,9 +11592,9 @@ api_to_recv_tcp4(suite) ->
api_to_recv_tcp4(doc) ->
[];
api_to_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recv_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -4622,12 +11612,12 @@ api_to_recv_tcp6(suite) ->
api_to_recv_tcp6(doc) ->
[];
api_to_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recv_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
case socket:supports(ipv6) of
true ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) ->
socket:recv(Sock, 0, To)
end,
@@ -4663,8 +11653,7 @@ api_to_receive_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -4782,10 +11771,8 @@ api_to_receive_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain, server_port := Port} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
- SSA = LSA#{port => Port},
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
{ok, State#{local_sa => LSA, server_sa => SSA}}
end},
#{desc => "create socket",
@@ -4961,9 +11948,9 @@ api_to_recvfrom_udp4(suite) ->
api_to_recvfrom_udp4(doc) ->
[];
api_to_recvfrom_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvfrom_udp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -4981,10 +11968,10 @@ api_to_recvfrom_udp6(suite) ->
api_to_recvfrom_udp6(doc) ->
[];
api_to_recvfrom_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvfrom_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5001,8 +11988,7 @@ api_to_receive_udp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create socket",
@@ -5078,9 +12064,9 @@ api_to_recvmsg_udp4(suite) ->
api_to_recvmsg_udp4(doc) ->
[];
api_to_recvmsg_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_udp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -5098,10 +12084,10 @@ api_to_recvmsg_udp6(suite) ->
api_to_recvmsg_udp6(doc) ->
[];
api_to_recvmsg_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5119,9 +12105,9 @@ api_to_recvmsg_tcp4(suite) ->
api_to_recvmsg_tcp4(doc) ->
[];
api_to_recvmsg_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -5139,10 +12125,10 @@ api_to_recvmsg_tcp6(suite) ->
api_to_recvmsg_tcp6(doc) ->
[];
api_to_recvmsg_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5170,9 +12156,9 @@ sc_cpe_socket_cleanup_tcp4(suite) ->
sc_cpe_socket_cleanup_tcp4(doc) ->
[];
sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_tcp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => stream,
protocol => tcp},
@@ -5190,10 +12176,10 @@ sc_cpe_socket_cleanup_tcp6(suite) ->
sc_cpe_socket_cleanup_tcp6(doc) ->
[];
sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet6,
type => stream,
protocol => tcp},
@@ -5204,6 +12190,27 @@ sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the sockets are cleaned up
%% ("removed") when the controlling process terminates (without explicitly
+%% calling the close function). For a Unix Domain (stream) socket (TCP).
+
+sc_cpe_socket_cleanup_tcpL(suite) ->
+ [];
+sc_cpe_socket_cleanup_tcpL(doc) ->
+ [];
+sc_cpe_socket_cleanup_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_cpe_socket_cleanup_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => stream,
+ protocol => default},
+ ok = sc_cpe_socket_cleanup(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sockets are cleaned up
+%% ("removed") when the controlling process terminates (without explicitly
%% calling the close function). For a IPv4 UDP (dgram) socket.
sc_cpe_socket_cleanup_udp4(suite) ->
@@ -5211,9 +12218,9 @@ sc_cpe_socket_cleanup_udp4(suite) ->
sc_cpe_socket_cleanup_udp4(doc) ->
[];
sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_udp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => dgram,
protocol => udp},
@@ -5232,10 +12239,10 @@ sc_cpe_socket_cleanup_udp6(suite) ->
sc_cpe_socket_cleanup_udp6(doc) ->
[];
sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet6,
type => dgram,
protocol => udp},
@@ -5244,6 +12251,28 @@ sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sockets are cleaned up
+%% ("removed") when the controlling process terminates (without explicitly
+%% calling the close function). For a Unix Domain (dgram) socket (UDP).
+
+sc_cpe_socket_cleanup_udpL(suite) ->
+ [];
+sc_cpe_socket_cleanup_udpL(doc) ->
+ [];
+sc_cpe_socket_cleanup_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_cpe_socket_cleanup_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => dgram,
+ protocol => default},
+ ok = sc_cpe_socket_cleanup(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_cpe_socket_cleanup(InitState) ->
OwnerSeq =
@@ -5337,8 +12366,15 @@ sc_cpe_socket_cleanup(InitState) ->
ERROR
end
end},
+
+ ?SEV_SLEEP(?SECS(5)),
+
%% The reason we get closed, is that as long as there is a ref to
%% the resource (socket), then it will not be garbage collected.
+ %% Note that its still a race that the nif has processed that the
+ %% "controlling process" has terminated. There really is no
+ %% proper timeout for this, but the 5 seconds "should" be enough...
+ %% We should really have some way to subscribe to socket events...
#{desc => "verify no socket (closed)",
cmd => fun(#{owner := Pid, sock := Sock} = _State) ->
case socket:getopt(Sock, otp, controlling_process) of
@@ -5386,12 +12422,11 @@ sc_lc_recv_response_tcp4(suite) ->
sc_lc_recv_response_tcp4(doc) ->
[];
sc_lc_recv_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recv_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -5408,13 +12443,12 @@ sc_lc_recv_response_tcp6(suite) ->
sc_lc_recv_response_tcp6(doc) ->
[];
sc_lc_recv_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recv_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -5422,6 +12456,28 @@ sc_lc_recv_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recv function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_recv_response_tcpL(suite) ->
+ [];
+sc_lc_recv_response_tcpL(doc) ->
+ [];
+sc_lc_recv_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_lc_recv_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recv(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_lc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_lc_receive_response_tcp(InitState) ->
%% This (acceptor) is the server that accepts connections.
@@ -5444,15 +12500,13 @@ sc_lc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
- {ok, State#{local_sa => LSA}}
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -5460,9 +12514,22 @@ sc_lc_receive_response_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ ?SEV_IPRINT("bind to LSA: "
+ "~n ~p", [LSA]),
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ lsa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -5473,7 +12540,12 @@ sc_lc_receive_response_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ lsa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester, lport := Port}) ->
?SEV_ANNOUNCE_READY(Tester, init, Port),
ok
end},
@@ -5494,7 +12566,8 @@ sc_lc_receive_response_tcp(InitState) ->
cmd => fun(#{lsock := LSock} = State) ->
case socket:accept(LSock) of
{ok, Sock} ->
- ?SEV_IPRINT("connection accepted"),
+ ?SEV_IPRINT("connection accepted: "
+ "~n ~p", [socket:sockname(Sock)]),
{ok, State#{csock => Sock}};
{error, _} = ERROR ->
ERROR
@@ -5525,9 +12598,8 @@ sc_lc_receive_response_tcp(InitState) ->
?SEV_AWAIT_CONTINUE(Tester, tester, close),
ok
end},
- #{desc => "close the connection socket",
+ #{desc => "close connection socket",
cmd => fun(#{csock := Sock} = State) ->
- %% ok = socket:setopt(Sock, otp, debug, true),
case socket:close(Sock) of
ok ->
{ok, maps:remove(csock, State)};
@@ -5551,8 +12623,19 @@ sc_lc_receive_response_tcp(InitState) ->
ERROR
end
end},
- #{desc => "close socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ #{desc => "close listen socket",
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ lsa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->maps:remove(lsa, State) end,
+ fun() -> State end),
+ State2 = maps:remove(lsock, State1),
+ State3 = maps:remove(lport, State2),
+ {ok, State3};
+ (#{lsock := Sock} = State) ->
case socket:close(Sock) of
ok ->
State1 = maps:remove(lsock, State),
@@ -5667,15 +12750,13 @@ sc_lc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -5684,6 +12765,8 @@ sc_lc_receive_response_tcp(InitState) ->
end},
#{desc => "bind socket to local address",
cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ ?SEV_IPRINT("bind to LSA: "
+ "~n ~p", [LSA]),
case socket:bind(Sock, LSA) of
{ok, _} ->
ok;
@@ -5699,7 +12782,19 @@ sc_lc_receive_response_tcp(InitState) ->
%% The actual test
#{desc => "await continue (connect)",
- cmd => fun(#{tester := Tester, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local = Domain,
+ tester := Tester} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester, connect) of
+ {ok, ServerPath} ->
+ ?SEV_IPRINT("Server Path: "
+ "~n ~s", [ServerPath]),
+ ServerSA = #{family => Domain,
+ path => ServerPath},
+ {ok, State#{server_sa => ServerSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{tester := Tester, local_sa := LSA} = State) ->
case ?SEV_AWAIT_CONTINUE(Tester, tester, connect) of
{ok, Port} ->
ServerSA = LSA#{port => Port},
@@ -5729,7 +12824,18 @@ sc_lc_receive_response_tcp(InitState) ->
end
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ sock_close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
sock_close(Sock),
{ok, maps:remove(sock, State)}
end},
@@ -5776,8 +12882,8 @@ sc_lc_receive_response_tcp(InitState) ->
#{desc => "await acceptor ready (init)",
cmd => fun(#{acceptor := Pid} = State) ->
case ?SEV_AWAIT_READY(Pid, acceptor, init) of
- {ok, Port} ->
- {ok, State#{lport => Port}};
+ {ok, PortOrPath} ->
+ {ok, State#{server_info => PortOrPath}};
{error, _} = ERROR ->
ERROR
end
@@ -5834,8 +12940,8 @@ sc_lc_receive_response_tcp(InitState) ->
end},
?SEV_SLEEP(?SECS(1)),
#{desc => "order client to continue (connect)",
- cmd => fun(#{client := Pid, lport := Port} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, connect, Port),
+ cmd => fun(#{client := Pid, server_info := Info} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect, Info),
ok
end},
#{desc => "await acceptor ready (accept)",
@@ -6002,12 +13108,11 @@ sc_lc_recvfrom_response_udp4(suite) ->
sc_lc_recvfrom_response_udp4(doc) ->
[];
sc_lc_recvfrom_response_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_lc_recvfrom_response_udp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
InitState = #{domain => inet,
- type => dgram,
protocol => udp,
recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
@@ -6024,13 +13129,36 @@ sc_lc_recvfrom_response_udp6(suite) ->
sc_lc_recvfrom_response_udp6(doc) ->
[];
sc_lc_recvfrom_response_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_lc_recvfrom_response_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
- InitState = #{domain => inet6,
- recv => Recv},
+ InitState = #{domain => inet6,
+ protocol => udp,
+ recv => Recv},
+ ok = sc_lc_receive_response_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recv function.
+%% Socket is Unix Domainm (dgram) socket.
+
+sc_lc_recvfrom_response_udpL(suite) ->
+ [];
+sc_lc_recvfrom_response_udpL(doc) ->
+ [];
+sc_lc_recvfrom_response_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_lc_recvfrom_response_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6055,20 +13183,25 @@ sc_lc_receive_response_udp(InitState) ->
%% *** Init part ***
#{desc => "local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "open socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
+ cmd => fun(#{domain := Domain, protocol := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
SA = sock_sockname(Sock),
{ok, State#{sock => Sock, sa => SA}}
end},
#{desc => "bind socket",
cmd => fun(#{sock := Sock, local_sa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "announce ready (init)",
cmd => fun(#{tester := Tester, sock := Sock}) ->
@@ -6107,7 +13240,18 @@ sc_lc_receive_response_udp(InitState) ->
ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
case socket:close(Sock) of
ok ->
{ok, maps:remove(sock, State)};
@@ -6400,9 +13544,9 @@ sc_lc_receive_response_udp(InitState) ->
i("start 'tester' evaluator"),
TesterInitState = #{prim_server => PrimServer#ev.pid,
- sec_server1 => SecServer1#ev.pid,
- sec_server2 => SecServer2#ev.pid,
- sec_server3 => SecServer3#ev.pid},
+ sec_server1 => SecServer1#ev.pid,
+ sec_server2 => SecServer2#ev.pid,
+ sec_server3 => SecServer3#ev.pid},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
i("await evaluator"),
@@ -6422,12 +13566,11 @@ sc_lc_recvmsg_response_tcp4(suite) ->
sc_lc_recvmsg_response_tcp4(doc) ->
[];
sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recvmsg_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -6444,13 +13587,12 @@ sc_lc_recvmsg_response_tcp6(suite) ->
sc_lc_recvmsg_response_tcp6(doc) ->
[];
sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_recvmsg_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -6460,6 +13602,28 @@ sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test what happens when a socket is
%% locally closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_recvmsg_response_tcpL(suite) ->
+ [];
+sc_lc_recvmsg_response_tcpL(doc) ->
+ [];
+sc_lc_recvmsg_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_recvmsg_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recvmsg(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_lc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recvmsg function.
%% Socket is IPv4.
sc_lc_recvmsg_response_udp4(suite) ->
@@ -6471,8 +13635,9 @@ sc_lc_recvmsg_response_udp4(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
- InitState = #{domain => inet,
- recv => Recv},
+ InitState = #{domain => inet,
+ protocol => udp,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6492,8 +13657,32 @@ sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
- InitState = #{domain => inet6,
- recv => Recv},
+ InitState = #{domain => inet6,
+ protocol => udp,
+ recv => Recv},
+ ok = sc_lc_receive_response_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (dgram) socket.
+
+sc_lc_recvmsg_response_udpL(suite) ->
+ [];
+sc_lc_recvmsg_response_udpL(doc) ->
+ [];
+sc_lc_recvmsg_response_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_recvmsg_response_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6511,11 +13700,10 @@ sc_lc_acceptor_response_tcp4(suite) ->
sc_lc_acceptor_response_tcp4(doc) ->
[];
sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_acceptor_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet,
- type => stream,
protocol => tcp},
ok = sc_lc_acceptor_response_tcp(InitState)
end).
@@ -6533,18 +13721,39 @@ sc_lc_acceptor_response_tcp6(suite) ->
sc_lc_acceptor_response_tcp6(doc) ->
[];
sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_acceptor_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
- InitState = #{domain => inet,
- type => stream,
+ InitState = #{domain => inet6,
protocol => tcp},
ok = sc_lc_acceptor_response_tcp(InitState)
end).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the accept function.
+%% We test what happens with a non-controlling_process also, since we
+%% git the setup anyway.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_acceptor_response_tcpL(suite) ->
+ [];
+sc_lc_acceptor_response_tcpL(doc) ->
+ [];
+sc_lc_acceptor_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_lc_acceptor_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ protocol => default},
+ ok = sc_lc_acceptor_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_lc_acceptor_response_tcp(InitState) ->
PrimAcceptorSeq =
@@ -6564,15 +13773,13 @@ sc_lc_acceptor_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -6609,8 +13816,8 @@ sc_lc_acceptor_response_tcp(InitState) ->
end
end},
#{desc => "await connection",
- cmd => fun(#{sock := Sock, timeout := Timeout} = _State) ->
- case socket:accept(Sock, Timeout) of
+ cmd => fun(#{sock := LSock, timeout := Timeout} = _State) ->
+ case socket:accept(LSock, Timeout) of
{error, timeout} ->
ok;
{ok, Sock} ->
@@ -6631,7 +13838,25 @@ sc_lc_acceptor_response_tcp(InitState) ->
ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ lsa := #{path := Path}} = State) ->
+ case socket:close(Sock) of
+ ok ->
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(lsa, State)
+ end,
+ fun() ->
+ State
+ end),
+ {ok, maps:remove(sock, State1)};
+ {error, _} = ERROR ->
+ unlink_path(Path),
+ ERROR
+ end;
+ (#{sock := Sock} = State) ->
case socket:close(Sock) of
ok ->
{ok, maps:remove(sock, State)};
@@ -6946,12 +14171,11 @@ sc_rc_recv_response_tcp4(suite) ->
sc_rc_recv_response_tcp4(doc) ->
[];
sc_rc_recv_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recv_response_tcp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -6968,13 +14192,12 @@ sc_rc_recv_response_tcp6(suite) ->
sc_rc_recv_response_tcp6(doc) ->
[];
sc_rc_recv_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recv_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -6982,6 +14205,28 @@ sc_rc_recv_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recv function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rc_recv_response_tcpL(suite) ->
+ [];
+sc_rc_recv_response_tcpL(doc) ->
+ [];
+sc_rc_recv_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_rc_recv_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recv(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_rc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_rc_receive_response_tcp(InitState) ->
%% Each connection are handled by handler processes.
@@ -7004,13 +14249,12 @@ sc_rc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, protocol := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -7018,7 +14262,17 @@ sc_rc_receive_response_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
{ok, State#{lport => Port}};
@@ -7031,7 +14285,15 @@ sc_rc_receive_response_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := LSA}) ->
+ %% Actually we only need to send the path,
+ %% but to keep it simple, we send the "same"
+ %% as for non-local.
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -7213,7 +14475,25 @@ sc_rc_receive_response_tcp(InitState) ->
{ok, State2}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := LSock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := #{path := Path}} = State) ->
+ case socket:close(LSock) of
+ ok ->
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(lsa, State)
+ end,
+ fun() ->
+ State
+ end),
+ {ok, maps:remove(lsock, State1)};
+ {error, _} = ERROR ->
+ unlink_path(Path),
+ ERROR
+ end;
+ (#{lsock := LSock} = State) ->
case socket:close(LSock) of
ok ->
{ok, maps:remove(lsock, State)};
@@ -7270,8 +14550,10 @@ sc_rc_receive_response_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ server_sa := ServerSA,
+ protocol := Proto}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -7672,16 +14954,16 @@ sc_rc_tcp_client_start(Node) ->
sc_rc_tcp_client(Parent) ->
sc_rc_tcp_client_init(Parent),
- ServerSA = sc_rc_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = sc_rc_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = sc_rc_tcp_client_create(Domain),
- sc_rc_tcp_client_bind(Sock, Domain),
+ Sock = sc_rc_tcp_client_create(Domain, Proto),
+ Path = sc_rc_tcp_client_bind(Sock, Domain),
sc_rc_tcp_client_announce_ready(Parent, init),
sc_rc_tcp_client_await_continue(Parent, connect),
sc_rc_tcp_client_connect(Sock, ServerSA),
sc_rc_tcp_client_announce_ready(Parent, connect),
sc_rc_tcp_client_await_continue(Parent, close),
- sc_rc_tcp_client_close(Sock),
+ sc_rc_tcp_client_close(Sock, Path),
sc_rc_tcp_client_announce_ready(Parent, close),
Reason = sc_rc_tcp_client_await_terminate(Parent),
?SEV_IPRINT("terminate"),
@@ -7697,9 +14979,9 @@ sc_rc_tcp_client_await_start(Parent) ->
i("sc_rc_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-sc_rc_tcp_client_create(Domain) ->
+sc_rc_tcp_client_create(Domain, Proto) ->
i("sc_rc_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
case socket:getopt(Sock, otp, fd) of
{ok, FD} ->
@@ -7714,12 +14996,17 @@ sc_rc_tcp_client_create(Domain) ->
sc_rc_tcp_client_bind(Sock, Domain) ->
i("sc_rc_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -7741,13 +15028,17 @@ sc_rc_tcp_client_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-sc_rc_tcp_client_close(Sock) ->
+sc_rc_tcp_client_close(Sock, Path) ->
i("sc_rc_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
sc_rc_tcp_client_await_terminate(Parent) ->
@@ -7827,12 +15118,11 @@ sc_rc_recvmsg_response_tcp4(suite) ->
sc_rc_recvmsg_response_tcp4(doc) ->
[];
sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recvmsg_response_tcp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -7849,13 +15139,12 @@ sc_rc_recvmsg_response_tcp6(suite) ->
sc_rc_recvmsg_response_tcp6(doc) ->
[];
sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recvmsg_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -7863,6 +15152,28 @@ sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rc_recvmsg_response_tcpL(suite) ->
+ [];
+sc_rc_recvmsg_response_tcpL(doc) ->
+ [];
+sc_rc_recvmsg_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_rc_recvmsg_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recvmsg(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_rc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test what happens when a socket is
%% remotely closed while the process is calling the recv function.
%% The remote client sends data, then shutdown(write) and then the
@@ -7872,6 +15183,7 @@ sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%% To minimize the chance of "weirdness", we should really have test cases
%% where the two sides of the connection is on different machines. But for
%% now, we will make do with different VMs on the same host.
+%% This would of course not work for Unix Domain sockets.
%%
sc_rs_recv_send_shutdown_receive_tcp4(suite) ->
@@ -7879,9 +15191,9 @@ sc_rs_recv_send_shutdown_receive_tcp4(suite) ->
sc_rs_recv_send_shutdown_receive_tcp4(doc) ->
[];
sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rs_recv_send_shutdown_receive_tcp4,
fun() ->
- ?TT(?SECS(30)),
MsgData = ?DATA,
Recv = fun(Sock) ->
socket:recv(Sock)
@@ -7890,6 +15202,7 @@ sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
socket:send(Sock, Data)
end,
InitState = #{domain => inet,
+ proto => tcp,
recv => Recv,
send => Send,
data => MsgData},
@@ -7921,6 +15234,39 @@ sc_rs_recv_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
socket:send(Sock, Data)
end,
InitState = #{domain => inet6,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
+ ok = sc_rs_send_shutdown_receive_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recv function.
+%% The remote client sends data, then shutdown(write) and then the
+%% reader attempts a recv.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rs_recv_send_shutdown_receive_tcpL(suite) ->
+ [];
+sc_rs_recv_send_shutdown_receive_tcpL(doc) ->
+ [];
+sc_rs_recv_send_shutdown_receive_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_rs_recv_send_shutdown_receive_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ MsgData = ?DATA,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ InitState = #{domain => local,
+ proto => default,
recv => Recv,
send => Send,
data => MsgData},
@@ -7952,13 +15298,12 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
i("get local address for ~p", [Domain]),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -7966,9 +15311,19 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -7979,7 +15334,11 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -8090,7 +15449,18 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
{ok, State2}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := LSock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := LSock} = State) ->
case socket:close(LSock) of
ok ->
{ok, maps:remove(lsock, State)};
@@ -8148,8 +15518,10 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ proto := Proto,
+ server_sa := ServerSA}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -8479,12 +15851,14 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState)},
Server = ?SEV_START("server", ServerSeq, ServerInitState),
i("start client evaluator"),
ClientInitState = #{host => local_host(),
domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
send => maps:get(send, InitState)},
Client = ?SEV_START("client", ClientSeq, ClientInitState),
@@ -8506,10 +15880,10 @@ sc_rs_tcp_client_start(Node, Send) ->
sc_rs_tcp_client(Parent, Send) ->
sc_rs_tcp_client_init(Parent),
- ServerSA = sc_rs_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = sc_rs_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = sc_rs_tcp_client_create(Domain),
- sc_rs_tcp_client_bind(Sock, Domain),
+ Sock = sc_rs_tcp_client_create(Domain, Proto),
+ Path = sc_rs_tcp_client_bind(Sock, Domain),
sc_rs_tcp_client_announce_ready(Parent, init),
sc_rs_tcp_client_await_continue(Parent, connect),
sc_rs_tcp_client_connect(Sock, ServerSA),
@@ -8521,7 +15895,7 @@ sc_rs_tcp_client(Parent, Send) ->
sc_rs_tcp_client_shutdown(Sock),
sc_rs_tcp_client_announce_ready(Parent, shutdown),
sc_rs_tcp_client_await_continue(Parent, close),
- sc_rs_tcp_client_close(Sock),
+ sc_rs_tcp_client_close(Sock, Path),
sc_rs_tcp_client_announce_ready(Parent, close),
Reason = sc_rs_tcp_client_await_terminate(Parent),
?SEV_IPRINT("terminate"),
@@ -8537,9 +15911,9 @@ sc_rs_tcp_client_await_start(Parent) ->
i("sc_rs_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-sc_rs_tcp_client_create(Domain) ->
+sc_rs_tcp_client_create(Domain, Proto) ->
i("sc_rs_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
Sock;
{error, Reason} ->
@@ -8548,12 +15922,17 @@ sc_rs_tcp_client_create(Domain) ->
sc_rs_tcp_client_bind(Sock, Domain) ->
i("sc_rs_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -8600,13 +15979,17 @@ sc_rs_tcp_client_shutdown(Sock) ->
exit({shutdown, Reason})
end.
-sc_rs_tcp_client_close(Sock) ->
+sc_rs_tcp_client_close(Sock, Path) ->
i("sc_rs_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
sc_rs_tcp_client_await_terminate(Parent) ->
@@ -8711,12 +16094,11 @@ sc_rs_recvmsg_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
MsgHdr = #{iov => [Data]},
socket:sendmsg(Sock, MsgHdr)
end,
- InitState = #{domain => inet,
- type => stream,
- protocol => tcp,
- recv => Recv,
- send => Send,
- data => MsgData},
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
ok = sc_rs_send_shutdown_receive_tcp(InitState)
end).
@@ -8748,20 +16130,2105 @@ sc_rs_recvmsg_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
end
end,
Send = fun(Sock, Data) when is_binary(Data) ->
- MsgHdr = #{iov => [Data]},
- socket:sendmsg(Sock, MsgHdr)
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
end,
- InitState = #{domain => inet6,
- type => stream,
- protocol => tcp,
- recv => Recv,
- send => Send,
- data => MsgData},
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
+ ok = sc_rs_send_shutdown_receive_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recvmsg function.
+%% The remote client sends data, then shutdown(write) and then the
+%% reader attempts a recv.
+%% Socket is UNix Domain (stream) socket.
+
+sc_rs_recvmsg_send_shutdown_receive_tcpL(suite) ->
+ [];
+sc_rs_recvmsg_send_shutdown_receive_tcpL(doc) ->
+ [];
+sc_rs_recvmsg_send_shutdown_receive_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_rs_recvmsg_send_shutdown_receive_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ {ok, CWD} = file:get_cwd(),
+ ?SEV_IPRINT("CWD: ~s", [CWD]),
+ MsgData = ?DATA,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ Send = fun(Sock, Data) when is_binary(Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ InitState = #{domain => local,
+ proto => default,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
ok = sc_rs_send_shutdown_receive_tcp(InitState)
end).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv4.
+
+traffic_send_and_recv_counters_tcp4(suite) ->
+ [];
+traffic_send_and_recv_counters_tcp4(doc) ->
+ [];
+traffic_send_and_recv_counters_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv6.
+
+traffic_send_and_recv_counters_tcp6(suite) ->
+ [];
+traffic_send_and_recv_counters_tcp6(doc) ->
+ [];
+traffic_send_and_recv_counters_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (TCP) on local.
+
+traffic_send_and_recv_counters_tcpL(suite) ->
+ [];
+traffic_send_and_recv_counters_tcpL(doc) ->
+ [];
+traffic_send_and_recv_counters_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv4.
+
+traffic_sendmsg_and_recvmsg_counters_tcp4(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp4(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv6.
+
+traffic_sendmsg_and_recvmsg_counters_tcp6(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp6(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (TCP) on local.
+
+traffic_sendmsg_and_recvmsg_counters_tcpL(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcpL(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+traffic_send_and_recv_tcp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, eafnosupport = Reason} ->
+ {skip, Reason};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ local_sa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
+ lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "accept",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, Sock} ->
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "initial counter validation (=zero)",
+ cmd => fun(#{csock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{csock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := Pkg,
+ read_byte := Byte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, Pkg},
+ {read_byte, Byte},
+ {read_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{csock := Sock,
+ send := Send} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{csock := Sock,
+ recv := Recv,
+ read_pkg := Pkg,
+ read_byte := Byte} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => Pkg + 1,
+ read_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{csock := Sock,
+ send := Send,
+ write_pkg := Pkg,
+ write_byte := Byte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => Pkg + 1,
+ write_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket (just in case)",
+ cmd => fun(#{csock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(csock, State)}
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(lsock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start (from tester)",
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, Path} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_path => Path}};
+ (State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := local = Domain,
+ server_path := Path} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = #{family => Domain, path => Path},
+ {ok, State#{local_sa => LSA, server_sa => SSA}};
+ (#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, eafnosupport = Reason} ->
+ {skip, Reason};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect),
+ ok
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ write_pkg := SPkg,
+ write_byte := SByte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => SPkg + 1,
+ write_byte => SByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{domain := local,
+ client := Pid,
+ path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
+ port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (with connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, connect),
+ ok
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, accept)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState#{host => local_host()},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState#{host => local_host()},
+ Client = ?SEV_START("client", ClientSeq, ClientInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+traffic_sar_counters_validation(Counters) ->
+ traffic_sar_counters_validation(Counters, []).
+
+traffic_sar_counters_validation(Counters, []) ->
+ (catch lists:foreach(
+ fun({_Cnt, 0}) -> ok;
+ ({Cnt, Val}) -> throw({error, {invalid_counter, Cnt, Val}})
+ end,
+ Counters));
+traffic_sar_counters_validation(Counters, [{Cnt, Val}|ValidateCounters]) ->
+ case lists:keysearch(Cnt, 1, Counters) of
+ {value, {Cnt, Val}} ->
+ Counters2 = lists:keydelete(Cnt, 1, Counters),
+ traffic_sar_counters_validation(Counters2, ValidateCounters);
+ {value, {Cnt, _Val}} when (Val =:= any) ->
+ Counters2 = lists:keydelete(Cnt, 1, Counters),
+ traffic_sar_counters_validation(Counters2, ValidateCounters);
+ {value, {Cnt, InvVal}} ->
+ {error, {invalid_counter, Cnt, InvVal, Val}};
+ false ->
+ {error, {unknown_counter, Cnt, Counters}}
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv4.
+
+traffic_sendto_and_recvfrom_counters_udp4(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp4(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => udp,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv6.
+
+traffic_sendto_and_recvfrom_counters_udp6(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp6(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => udp,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (UDP) on local.
+
+traffic_sendto_and_recvfrom_counters_udpL(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udpL(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp4,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv4.
+
+traffic_sendmsg_and_recvmsg_counters_udp4(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp4(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => udp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv6.
+
+traffic_sendmsg_and_recvmsg_counters_udp6(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp6(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => udp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (UDP) on local.
+
+traffic_sendmsg_and_recvmsg_counters_udpL(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udpL(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+traffic_send_and_recv_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := LSock,
+ local_sa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "initial counter validation (=zero)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
+ lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, {ClientSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{client_sa => ClientSA,
+ read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := Pkg,
+ read_byte := Byte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, Pkg},
+ {read_byte, Byte},
+ {read_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ client_sa := ClientSA} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ClientSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ read_pkg := Pkg,
+ read_byte := Byte} = State) ->
+ case Recv(Sock) of
+ {ok, {Source, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{client_sa => Source,
+ read_pkg => Pkg + 1,
+ read_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ client_sa := ClientSA,
+ send := Send,
+ write_pkg := Pkg,
+ write_byte := Byte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ClientSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => Pkg + 1,
+ write_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket (just in case)",
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{sock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start (from tester)",
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, Path} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_path => Path}};
+ (State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := local = Domain,
+ server_path := Path} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = #{family => Domain, path => Path},
+ {ok, State#{local_sa => LSA, server_sa => SSA}};
+ (#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "initial counter validation (=zero)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ server_sa := ServerSA} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ServerSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ server_sa := #{family := local} = ServerSA} = State) ->
+ case Recv(Sock) of
+ {ok, {ServerSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock,
+ recv := Recv,
+ server_sa := #{addr := Addr, port := Port}} = State) ->
+ case Recv(Sock) of
+ {ok, {#{addr := Addr, port := Port}, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ server_sa := ServerSA,
+ write_pkg := SPkg,
+ write_byte := SByte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ServerSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => SPkg + 1,
+ write_byte => SByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ server_sa := #{family := local} = ServerSA,
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, {ServerSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock,
+ server_sa := #{addr := Addr, port := Port},
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, {#{addr := Addr, port := Port}, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{domain := local,
+ client := Pid,
+ path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
+ port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+
+ #{desc => "order server to continue (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState#{host => local_host()},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState#{host => local_host()},
+ Client = ?SEV_START("client", ClientSeq, ClientInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the send and recv functions
%% behave as expected when sending and/or reading chunks.
%% First send data in one "big" chunk, and read it in "small" chunks.
@@ -8773,10 +18240,11 @@ traffic_send_and_recv_chunks_tcp4(suite) ->
traffic_send_and_recv_chunks_tcp4(doc) ->
[];
traffic_send_and_recv_chunks_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(traffic_send_and_recv_chunks_tcp4,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet},
+ InitState = #{domain => inet,
+ proto => tcp},
ok = traffic_send_and_recv_chunks_tcp(InitState)
end).
@@ -8794,11 +18262,34 @@ traffic_send_and_recv_chunks_tcp6(suite) ->
traffic_send_and_recv_chunks_tcp6(doc) ->
[];
traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(traffic_send_and_recv_chunks_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet6},
+ InitState = #{domain => inet6,
+ proto => tcp},
+ ok = traffic_send_and_recv_chunks_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% behave as expected when sending and/or reading chunks.
+%% First send data in one "big" chunk, and read it in "small" chunks.
+%% Second, send in a bunch of "small" chunks, and read in one "big" chunk.
+%% Socket is UNix Domain (Stream) socket.
+
+traffic_send_and_recv_chunks_tcpL(suite) ->
+ [];
+traffic_send_and_recv_chunks_tcpL(doc) ->
+ [];
+traffic_send_and_recv_chunks_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(traffic_send_and_recv_chunks_tcp6,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default},
ok = traffic_send_and_recv_chunks_tcp(InitState)
end).
@@ -8823,13 +18314,12 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -8837,7 +18327,17 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
{ok, State#{lport => Port}};
@@ -8850,7 +18350,14 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester,
+ local_sa := LSA,
+ lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -9045,9 +18552,20 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
{ok, maps:remove(csock, State)}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := Sock} = State) ->
(catch socket:close(Sock)),
- {ok, maps:remove(lsock, State)}
+ {ok, maps:remove(lsock, State)}
end},
%% *** We are done ***
@@ -9098,8 +18616,10 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ server_sa := ServerSA,
+ proto := Proto}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -9654,14 +19174,14 @@ traffic_snr_tcp_client_start(Node) ->
erlang:spawn(Node, Fun).
traffic_snr_tcp_client(Parent) ->
- {Sock, ServerSA} = traffic_snr_tcp_client_init(Parent),
+ {Sock, ServerSA, Path} = traffic_snr_tcp_client_init(Parent),
traffic_snr_tcp_client_announce_ready(Parent, init),
traffic_snr_tcp_client_await_continue(Parent, connect),
traffic_snr_tcp_client_connect(Sock, ServerSA),
traffic_snr_tcp_client_announce_ready(Parent, connect),
traffic_snr_tcp_client_send_loop(Parent, Sock),
Reason = traffic_snr_tcp_client_await_terminate(Parent),
- traffic_snr_tcp_client_close(Sock),
+ traffic_snr_tcp_client_close(Sock, Path),
exit(Reason).
@@ -9687,19 +19207,19 @@ traffic_snr_tcp_client_init(Parent) ->
put(sname, "rclient"),
?SEV_IPRINT("init"),
_MRef = erlang:monitor(process, Parent),
- ServerSA = traffic_snr_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = traffic_snr_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = traffic_snr_tcp_client_create(Domain),
- traffic_snr_tcp_client_bind(Sock, Domain),
- {Sock, ServerSA}.
+ Sock = traffic_snr_tcp_client_create(Domain, Proto),
+ Path = traffic_snr_tcp_client_bind(Sock, Domain),
+ {Sock, ServerSA, Path}.
traffic_snr_tcp_client_await_start(Parent) ->
i("traffic_snr_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-traffic_snr_tcp_client_create(Domain) ->
+traffic_snr_tcp_client_create(Domain, Proto) ->
i("traffic_snr_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
Sock;
{error, Reason} ->
@@ -9708,12 +19228,17 @@ traffic_snr_tcp_client_create(Domain) ->
traffic_snr_tcp_client_bind(Sock, Domain) ->
i("traffic_snr_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -9734,13 +19259,17 @@ traffic_snr_tcp_client_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-traffic_snr_tcp_client_close(Sock) ->
+traffic_snr_tcp_client_close(Sock, Path) ->
i("traffic_snr_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
traffic_snr_tcp_client_await_terminate(Parent) ->
@@ -9768,12 +19297,13 @@ traffic_ping_pong_small_send_and_recv_tcp4(suite) ->
traffic_ping_pong_small_send_and_recv_tcp4(doc) ->
[];
traffic_ping_pong_small_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_send_and_recv_tcp4,
fun() ->
- ?TT(?SECS(15)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9795,13 +19325,42 @@ traffic_ping_pong_small_send_and_recv_tcp6(suite) ->
traffic_ping_pong_small_send_and_recv_tcp6(doc) ->
[];
traffic_ping_pong_small_send_and_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_send_and_recv_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(15)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_small_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_small_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_small_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9828,6 +19387,7 @@ traffic_ping_pong_medium_send_and_recv_tcp4(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9855,6 +19415,36 @@ traffic_ping_pong_medium_send_and_recv_tcp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_medium_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_medium_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_medium_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9876,12 +19466,13 @@ traffic_ping_pong_large_send_and_recv_tcp4(suite) ->
traffic_ping_pong_large_send_and_recv_tcp4(doc) ->
[];
traffic_ping_pong_large_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_send_and_recv_tcp4,
fun() ->
- ?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9909,6 +19500,7 @@ traffic_ping_pong_large_send_and_recv_tcp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet6,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9917,6 +19509,47 @@ traffic_ping_pong_large_send_and_recv_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'large' message test case, for UNix Domain (stream) socket.
+
+traffic_ping_pong_large_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_large_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_large_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
+ Msg = l2b(?TPP_LARGE),
+ Num = ?TPP_LARGE_NUM,
+ tc_try(traffic_ping_pong_large_send_and_recv_tcpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ traffic_ping_pong_large_host_cond()
+ end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+%% This test case is a bit extreme and fails on some hosts
+%% (e.g. OpenIndiana Hipster), so exclude them.
+traffic_ping_pong_large_host_cond() ->
+ traffic_ping_pong_large_host_cond(os:type(), os:version()).
+
+traffic_ping_pong_large_host_cond({unix, sunos}, _) ->
+ skip("TC does not work on platform");
+traffic_ping_pong_large_host_cond(_, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the sendto and recvfrom
%% functions by repeatedly sending a meassage between two entities.
%% The same basic test case is used for two different message sizes;
@@ -9936,6 +19569,7 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -9959,9 +19593,40 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
?TT(?SECS(45)),
- InitState = #{domain => inet,
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendto and recvfrom
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for two different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(suite) ->
+ [];
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(doc) ->
+ [];
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(45)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -9989,6 +19654,7 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -10016,6 +19682,36 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp6(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendto and recvfrom
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for two different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendto_and_recvfrom_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(45)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -10043,6 +19739,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(20)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10070,6 +19767,35 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(20)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(20)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10096,6 +19822,7 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10121,8 +19848,37 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ ?TT(?SECS(30)),
+ InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(30)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10146,15 +19902,27 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4,
+ fun() -> traffic_ping_pong_large_sendmsg_and_recvmsg_cond() end,
fun() ->
- ?TT(?SECS(30)),
+ ?TT(?SECS(60)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
end).
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond() ->
+ traffic_ping_pong_large_sendmsg_and_recvmsg_cond(os:type(), os:version()).
+
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond({unix, linux}, {M, _, _})
+ when (M < 3) ->
+ skip("TC may not work on this version");
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond(_, _) ->
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the sendmsg and recvmsg functions
%% by repeatedly sending a meassage between two entities.
@@ -10172,10 +19940,43 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6,
- fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
+ has_support_ipv6(),
+ traffic_ping_pong_large_sendmsg_and_recvmsg_cond()
+ end,
+ fun() ->
+ ?TT(?SECS(60)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'large' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_LARGE),
+ Num = ?TPP_LARGE_NUM,
+ tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10203,6 +20004,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(60)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10228,8 +20030,37 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet,
+ ?TT(?SECS(60)),
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10254,8 +20085,9 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4,
fun() ->
- ?TT(?SECS(30)),
+ ?TT(?SECS(60)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10281,8 +20113,38 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ ?TT(?SECS(60)),
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10302,14 +20164,26 @@ traffic_ping_pong_send_and_recv_tcp(InitState) ->
},
traffic_ping_pong_send_and_receive_tcp(InitState2).
-traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
- Send = fun(Sock, Data) when is_binary(Data) ->
- MsgHdr = #{iov => [Data]},
- socket:sendmsg(Sock, MsgHdr);
- (Sock, Data) when is_list(Data) -> %% We assume iovec...
- MsgHdr = #{iov => Data},
- socket:sendmsg(Sock, MsgHdr)
+traffic_ping_pong_sendmsg_and_recvmsg_tcp(#{domain := local} = InitState) ->
+ Recv = fun(Sock, Sz) ->
+ case socket:recvmsg(Sock, Sz, 0) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
end,
+ InitState2 = InitState#{recv => Recv}, % Receive function
+ traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState2);
+traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
Recv = fun(Sock, Sz) ->
case socket:recvmsg(Sock, Sz, 0) of
{ok, #{addr := undefined,
@@ -10319,9 +20193,18 @@ traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
ERROR
end
end,
- InitState2 = InitState#{send => Send, % Send function
- recv => Recv % Receive function
- },
+ InitState2 = InitState#{recv => Recv}, % Receive function
+ traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState2).
+
+traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState) ->
+ Send = fun(Sock, Data) when is_binary(Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr);
+ (Sock, Data) when is_list(Data) -> %% We assume iovec...
+ MsgHdr = #{iov => Data},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ InitState2 = InitState#{send => Send}, % Send function
traffic_ping_pong_send_and_receive_tcp(InitState2).
@@ -10331,12 +20214,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("RcvBuf is ~p (needs atleast ~p)",
[RcvSz, 16+size(Msg)]),
if (RcvSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, rcvbuf, 1024+size(Msg)) of
+ NewRcvSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, rcvbuf, NewRcvSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, rcvbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [rcvbuf, NewRcvSz]));
{error, Reason1} ->
?FAIL({rcvbuf, Reason1})
end;
@@ -10347,12 +20232,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("SndBuf is ~p (needs atleast ~p)",
[SndSz, 16+size(Msg)]),
if (SndSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, sndbuf, 1024+size(Msg)) of
+ NewSndSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, sndbuf, NewSndSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, sndbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [sndbuf, NewSndSz]));
{error, Reason2} ->
?FAIL({sndbuf, Reason2})
end;
@@ -10381,13 +20268,12 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -10395,9 +20281,19 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -10412,7 +20308,11 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -10523,9 +20423,20 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
{ok, State1}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ (catch socket:close(Sock)),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := Sock} = State) ->
(catch socket:close(Sock)),
- {ok, maps:remove(lsock, State)}
+ {ok, maps:remove(lsock, State)}
end},
%% *** We are done ***
@@ -10577,12 +20488,14 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
end},
#{desc => "order remote client to start",
cmd => fun(#{rclient := RClient,
+ proto := Proto,
server_sa := ServerSA,
buf_init := BufInit,
send := Send,
recv := Recv}) ->
?SEV_ANNOUNCE_START(RClient,
- {ServerSA, BufInit, Send, Recv}),
+ {ServerSA, Proto, BufInit,
+ Send, Recv}),
ok
end},
#{desc => "await remote client ready",
@@ -10883,6 +20796,7 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState),
send => maps:get(send, InitState),
buf_init => maps:get(buf_init, InitState)},
@@ -10976,14 +20890,6 @@ tpp_tcp_handler_msg_exchange_loop(Sock, Send, Recv, N, Sent, Received, Start) ->
?SEV_EPRINT("send (~w): ~p", [N, SReason]),
exit({send, SReason, N})
end;
- %% {error, timeout} ->
- %% ?SEV_IPRINT("timeout(~w) - try again", [N]),
- %% case Send(Sock, list_to_binary("ping")) of
- %% ok ->
- %% exit({'ping-send', ok, N});
- %% {error, Reason} ->
- %% exit({'ping-send', Reason, N})
- %% end;
{error, closed} ->
?SEV_IPRINT("closed - we are done: ~w, ~w, ~w", [N, Sent, Received]),
Stop = ?LIB:timestamp(),
@@ -11002,10 +20908,10 @@ tpp_tcp_client_create(Node) ->
tpp_tcp_client(Parent) ->
tpp_tcp_client_init(Parent),
- {ServerSA, BufInit, Send, Recv} = tpp_tcp_client_await_start(Parent),
+ {ServerSA, Proto, BufInit, Send, Recv} = tpp_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = tpp_tcp_client_sock_open(Domain, BufInit),
- tpp_tcp_client_sock_bind(Sock, Domain),
+ Sock = tpp_tcp_client_sock_open(Domain, Proto, BufInit),
+ Path = tpp_tcp_client_sock_bind(Sock, Domain),
tpp_tcp_client_announce_ready(Parent, init),
tpp_tcp_client_await_continue(Parent, connect),
tpp_tcp_client_sock_connect(Sock, ServerSA),
@@ -11014,7 +20920,7 @@ tpp_tcp_client(Parent) ->
Result = tpp_tcp_client_msg_exchange(Sock, Send, Recv, InitMsg, Num),
tpp_tcp_client_announce_ready(Parent, send, Result),
Reason = tpp_tcp_client_await_terminate(Parent),
- tpp_tcp_client_sock_close(Sock),
+ tpp_tcp_client_sock_close(Sock, Path),
?SEV_IPRINT("terminating"),
exit(Reason).
@@ -11054,8 +20960,10 @@ tpp_tcp_client_await_terminate(Parent) ->
?SEV_IPRINT("await terminate"),
case ?SEV_AWAIT_TERMINATE(Parent, parent) of
ok ->
- ok;
+ ?SEV_IPRINT("termination received: normal"),
+ normal;
{error, Reason} ->
+ ?SEV_IPRINT("termination received: ~w", [Reason]),
Reason
end.
@@ -11099,8 +21007,8 @@ tpp_tcp_client_msg_exchange_loop(Sock, Send, Recv, Data,
exit({send, SReason, N})
end.
-tpp_tcp_client_sock_open(Domain, BufInit) ->
- case socket:open(Domain, stream, tcp) of
+tpp_tcp_client_sock_open(Domain, Proto, BufInit) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
ok = BufInit(Sock),
Sock;
@@ -11109,14 +21017,19 @@ tpp_tcp_client_sock_open(Domain, BufInit) ->
end.
tpp_tcp_client_sock_bind(Sock, Domain) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
- {error, Reason} ->
- exit({bind, Reason})
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
+ {error, Reason2} ->
+ exit({bind, Reason2})
end.
tpp_tcp_client_sock_connect(Sock, ServerSA) ->
@@ -11127,14 +21040,20 @@ tpp_tcp_client_sock_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-tpp_tcp_client_sock_close(Sock) ->
+tpp_tcp_client_sock_close(Sock, Path) ->
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
+
+
-define(TPP_REQUEST, 1).
-define(TPP_REPLY, 2).
@@ -11300,13 +21219,12 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
- #{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, dgram, udp) of
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -11314,7 +21232,15 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock, local_sa := LSA} = State) ->
case socket:bind(Sock, LSA) of
{ok, Port} ->
{ok, State#{port => Port}};
@@ -11357,7 +21283,11 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
end
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, port := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -11396,6 +21326,19 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
ERROR
end
end},
+ #{desc => "(maybe) unlink socket",
+ cmd => fun(#{domain := local,
+ local_sa := #{path := Path}} = State) ->
+ unlink_path(Path,
+ fun() ->
+ {ok, maps:remove(local_sa, State)}
+ end,
+ fun() ->
+ ok
+ end);
+ (_) ->
+ ok
+ end},
#{desc => "announce ready (close)",
cmd => fun(#{tester := Tester} = _State) ->
?SEV_ANNOUNCE_READY(Tester, close),
@@ -11492,11 +21435,13 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
#{desc => "order remote handler to start",
cmd => fun(#{handler := Handler,
server_sa := ServerSA,
+ proto := Proto,
buf_init := BufInit,
send := Send,
recv := Recv}) ->
?SEV_ANNOUNCE_START(Handler,
- {ServerSA, BufInit, Send, Recv}),
+ {ServerSA, Proto, BufInit,
+ Send, Recv}),
ok
end},
#{desc => "await (remote) handler ready",
@@ -11741,6 +21686,7 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState),
send => maps:get(send, InitState),
buf_init => maps:get(buf_init, InitState)},
@@ -11841,12 +21787,12 @@ tpp_udp_client_handler_create(Node) ->
tpp_udp_client_handler(Parent) ->
tpp_udp_client_handler_init(Parent),
?SEV_IPRINT("await start command"),
- {ServerSA, BufInit, Send, Recv} = tpp_udp_handler_await_start(Parent),
+ {ServerSA, Proto, BufInit, Send, Recv} = tpp_udp_handler_await_start(Parent),
?SEV_IPRINT("start command with"
"~n ServerSA: ~p", [ServerSA]),
Domain = maps:get(family, ServerSA),
- Sock = tpp_udp_sock_open(Domain, BufInit),
- tpp_udp_sock_bind(Sock, Domain),
+ Sock = tpp_udp_sock_open(Domain, Proto, BufInit),
+ Path = tpp_udp_sock_bind(Sock, Domain),
?SEV_IPRINT("announce ready", []),
tpp_udp_handler_announce_ready(Parent, init),
{InitMsg, Num} = tpp_udp_handler_await_continue(Parent, send),
@@ -11859,7 +21805,7 @@ tpp_udp_client_handler(Parent) ->
?SEV_IPRINT("await terminate"),
Reason = tpp_udp_handler_await_terminate(Parent),
?SEV_IPRINT("terminate with ~p", [Reason]),
- tpp_udp_sock_close(Sock),
+ tpp_udp_sock_close(Sock, Path),
?SEV_IPRINT("terminating"),
exit(Reason).
@@ -11881,7 +21827,9 @@ tpp_udp_client_handler_msg_exchange_loop(_Sock, _Dest, _Send, _Recv, _Msg,
Start) ->
Stop = ?LIB:timestamp(),
{Sent, Received, Start, Stop};
-tpp_udp_client_handler_msg_exchange_loop(Sock, Dest, Send, Recv, Data,
+tpp_udp_client_handler_msg_exchange_loop(Sock,
+ #{family := local} = Dest,
+ Send, Recv, Data,
Num, N, Sent, Received, Start) ->
case tpp_udp_send_req(Sock, Send, Data, Dest) of
{ok, SendSz} ->
@@ -11900,6 +21848,28 @@ tpp_udp_client_handler_msg_exchange_loop(Sock, Dest, Send, Recv, Data,
{error, SReason} ->
?SEV_EPRINT("send (~w of ~w): ~p", [N, Num, SReason]),
exit({send, SReason, N})
+ end;
+tpp_udp_client_handler_msg_exchange_loop(Sock,
+ #{addr := Addr, port := Port} = Dest0,
+ Send, Recv, Data,
+ Num, N, Sent, Received, Start) ->
+ case tpp_udp_send_req(Sock, Send, Data, Dest0) of
+ {ok, SendSz} ->
+ case tpp_udp_recv_rep(Sock, Recv) of
+ {ok, NewData, RecvSz, #{addr := Addr, port := Port} = Dest1} ->
+ tpp_udp_client_handler_msg_exchange_loop(Sock, Dest1,
+ Send, Recv,
+ NewData, Num, N+1,
+ Sent+SendSz,
+ Received+RecvSz,
+ Start);
+ {error, RReason} ->
+ ?SEV_EPRINT("recv (~w of ~w): ~p", [N, Num, RReason]),
+ exit({recv, RReason, N})
+ end;
+ {error, SReason} ->
+ ?SEV_EPRINT("send (~w of ~w): ~p", [N, Num, SReason]),
+ exit({send, SReason, N})
end.
@@ -11997,8 +21967,8 @@ tpp_udp_handler_await_terminate(Parent) ->
end.
-tpp_udp_sock_open(Domain, BufInit) ->
- case socket:open(Domain, dgram, udp) of
+tpp_udp_sock_open(Domain, Proto, BufInit) ->
+ case socket:open(Domain, dgram, Proto) of
{ok, Sock} ->
ok = BufInit(Sock),
Sock;
@@ -12007,9 +21977,7 @@ tpp_udp_sock_open(Domain, BufInit) ->
end.
tpp_udp_sock_bind(Sock, Domain) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
ok;
@@ -12017,12 +21985,16 @@ tpp_udp_sock_bind(Sock, Domain) ->
exit({bind, Reason})
end.
-tpp_udp_sock_close(Sock) ->
+tpp_udp_sock_close(Sock, Path) ->
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("Failed closing socket: "
+ "~n ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
@@ -15104,6 +25076,30 @@ ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -15152,6 +25148,30 @@ ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15199,6 +25219,30 @@ ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -15248,6 +25292,30 @@ ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -15296,6 +25364,30 @@ ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15343,6 +25435,30 @@ ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -15390,6 +25506,30 @@ ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -15440,6 +25580,30 @@ ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15486,6 +25650,30 @@ ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = gen_tcp, Active = false
%% Message Size: small (=1)
@@ -15968,6 +26156,30 @@ ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16016,6 +26228,30 @@ ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16063,6 +26299,30 @@ ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -16112,6 +26372,30 @@ ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16160,6 +26444,30 @@ ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16207,6 +26515,30 @@ ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -16254,6 +26586,30 @@ ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -16304,6 +26660,30 @@ ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16350,6 +26730,30 @@ ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = gen_tcp, Active = false
%% Message Size: small (=1)
@@ -16832,6 +27236,30 @@ ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16880,6 +27308,30 @@ ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16927,6 +27379,30 @@ ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -16976,6 +27452,30 @@ ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -17024,6 +27524,30 @@ ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -17071,6 +27595,30 @@ ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -17118,6 +27666,30 @@ ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -17168,6 +27740,30 @@ ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -17212,6 +27808,30 @@ ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
which_ttest_runtime(Config) when is_list(Config) ->
case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
@@ -17235,7 +27855,7 @@ which_ttest_runtime_env(false) ->
%% ms: milliseconds
%% s: seconds (default)
%% m: minutes
-which_ttest_runtime_env2([$m, $s | MS]) when (length(MS) > 0) ->
+which_ttest_runtime_env2([$s, $m | MS]) when (length(MS) > 0) ->
convert_time(MS, fun(X) -> X end);
which_ttest_runtime_env2([$m | M]) when (length(M) > 0) ->
convert_time(M, fun(X) -> ?MINS(X) end);
@@ -17272,7 +27892,8 @@ ttest_tcp(TC,
tc_try(TC,
fun() ->
if
- (Domain =/= inet) -> has_support_ipv6();
+ (Domain =:= local) -> has_support_unix_domain_socket();
+ (Domain =:= inet6) -> has_support_ipv6();
true -> ok
end
end,
@@ -17326,11 +27947,25 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "start ttest (remote) server",
- cmd => fun(#{mod := Mod,
+ cmd => fun(#{domain := local = Domain,
+ mod := Mod,
+ active := Active,
+ node := Node} = State) ->
+ case ttest_tcp_server_start(Node,
+ Domain, Mod, Active) of
+ {ok, {{Pid, _}, Path}} ->
+ {ok, State#{rserver => Pid,
+ path => Path}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{domain := Domain,
+ mod := Mod,
active := Active,
node := Node} = State) ->
- case ttest_tcp_server_start(Node, Mod, Active) of
- {ok, {{Pid, _MRef}, {Addr, Port}}} ->
+ case ttest_tcp_server_start(Node,
+ Domain, Mod, Active) of
+ {ok, {{Pid, _}, {Addr, Port}}} ->
{ok, State#{rserver => Pid,
addr => Addr,
port => Port}};
@@ -17339,7 +27974,12 @@ ttest_tcp(InitState) ->
end
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester,
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ path := Path}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
addr := Addr,
port := Port}) ->
?SEV_ANNOUNCE_READY(Tester, init, {Addr, Port}),
@@ -17394,8 +28034,14 @@ ttest_tcp(InitState) ->
[
%% *** Wait for start order part ***
#{desc => "await start",
- cmd => fun(State) ->
- {Tester, {ServerAddr, ServerPort}} = ?SEV_AWAIT_START(),
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, ServerPath} =
+ ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester,
+ server_path => ServerPath}};
+ (State) ->
+ {Tester, {ServerAddr, ServerPort}} =
+ ?SEV_AWAIT_START(),
{ok, State#{tester => Tester,
server_addr => ServerAddr,
server_port => ServerPort}}
@@ -17436,7 +28082,32 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "start ttest (remote) client",
- cmd => fun(#{node := Node,
+ cmd => fun(#{domain := local = Domain,
+ node := Node,
+ mod := Mod,
+ active := Active,
+ msg_id := MsgID,
+ max_outstanding := MaxOutstanding,
+ runtime := RunTime,
+ server_path := Path} = State) ->
+ Self = self(),
+ Notify =
+ fun(Result) ->
+ ?SEV_ANNOUNCE_READY(Self, ttest, Result)
+ end,
+ case ttest_tcp_client_start(Node, Notify,
+ Domain, Mod,
+ Path,
+ Active,
+ MsgID, MaxOutstanding,
+ RunTime) of
+ {ok, {Pid, _MRef}} ->
+ {ok, State#{rclient => Pid}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{domain := Domain,
+ node := Node,
mod := Mod,
active := Active,
msg_id := MsgID,
@@ -17450,8 +28121,9 @@ ttest_tcp(InitState) ->
?SEV_ANNOUNCE_READY(Self, ttest, Result)
end,
case ttest_tcp_client_start(Node, Notify,
- Mod, Active,
- Addr, Port,
+ Domain, Mod,
+ {Addr, Port},
+ Active,
MsgID, MaxOutstanding,
RunTime) of
{ok, {Pid, _MRef}} ->
@@ -17463,8 +28135,6 @@ ttest_tcp(InitState) ->
#{desc => "await ttest ready",
cmd => fun(#{tester := Tester,
rclient := RClient} = State) ->
- %% TTestResult = ?SEV_AWAIT_READY(RClient, rclient, ttest,
- %% [{tester, Tester}]),
case ?SEV_AWAIT_READY(RClient, rclient, ttest,
[{tester, Tester}]) of
{ok, Result} ->
@@ -17535,8 +28205,13 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "await server ready (init)",
- cmd => fun(#{server := Pid} = State) ->
- {ok, {Addr, Port}} = ?SEV_AWAIT_READY(Pid, server, init),
+ cmd => fun(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, {Addr, Port}} =
+ ?SEV_AWAIT_READY(Pid, server, init),
{ok, State#{server_addr => Addr,
server_port => Port}}
end},
@@ -17544,7 +28219,12 @@ ttest_tcp(InitState) ->
%% Start the client
#{desc => "order client start",
- cmd => fun(#{client := Pid,
+ cmd => fun(#{domain := local,
+ client := Pid,
+ server_path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
server_addr := Addr,
server_port := Port} = _State) ->
?SEV_ANNOUNCE_START(Pid, {Addr, Port}),
@@ -17600,12 +28280,23 @@ ttest_tcp(InitState) ->
%% Present the results
#{desc => "present the results",
- cmd => fun(#{result := Result} = State) ->
+ cmd => fun(#{result := Result,
+ domain := Domain,
+ server_mod := ServerTrans,
+ server_active := ServerActive,
+ client_mod := ClientTrans,
+ client_active := ClientActive,
+ msg_id := MsgID} = State) ->
case Result of
#{status := ok,
runtime := RunTime,
cnt := Cnt,
bcnt := BCnt} ->
+ ttest_report(Domain,
+ ServerTrans, ServerActive,
+ ClientTrans, ClientActive,
+ MsgID,
+ RunTime, BCnt, Cnt),
?SEV_IPRINT(
"TTest results: "
"~n Run Time: ~s"
@@ -17665,16 +28356,22 @@ ttest_tcp(InitState) ->
?SEV_FINISH_NORMAL
],
+ Domain = maps:get(domain, InitState),
+ LHost = local_host(),
+ LAddr = which_local_addr(Domain),
+
i("start server evaluator"),
- ServerInitState = #{host => local_host(),
- domain => maps:get(domain, InitState),
+ ServerInitState = #{host => LHost,
+ addr => LAddr,
+ domain => Domain,
mod => maps:get(server_mod, InitState),
active => maps:get(server_active, InitState)},
Server = ?SEV_START("server", ServerSeq, ServerInitState),
i("start client evaluator"),
- ClientInitState = #{host => local_host(),
- domain => maps:get(domain, InitState),
+ ClientInitState = #{host => LHost,
+ addr => LAddr,
+ domain => Domain,
mod => maps:get(client_mod, InitState),
active => maps:get(client_active, InitState),
msg_id => maps:get(msg_id, InitState),
@@ -17683,8 +28380,14 @@ ttest_tcp(InitState) ->
Client = ?SEV_START("client", ClientSeq, ClientInitState),
i("start 'tester' evaluator"),
- TesterInitState = #{server => Server#ev.pid,
- client => Client#ev.pid},
+ TesterInitState = #{domain => Domain,
+ msg_id => maps:get(msg_id, InitState),
+ client => Client#ev.pid,
+ client_mod => maps:get(client_mod, InitState),
+ client_active => maps:get(client_active, InitState),
+ server => Server#ev.pid,
+ server_mod => maps:get(server_mod, InitState),
+ server_active => maps:get(server_active, InitState)},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
i("await evaluator(s)"),
@@ -17692,12 +28395,15 @@ ttest_tcp(InitState) ->
-ttest_tcp_server_start(Node, gen, Active) ->
- Transport = socket_test_ttest_tcp_gen,
+ttest_tcp_server_start(Node, Domain, gen, Active) ->
+ TransportMod = socket_test_ttest_tcp_gen,
+ Transport = {TransportMod, #{domain => Domain}},
socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active);
-ttest_tcp_server_start(Node, sock, Active) ->
+ttest_tcp_server_start(Node, Domain, sock, Active) ->
TransportMod = socket_test_ttest_tcp_socket,
- Transport = {TransportMod, #{method => plain}},
+ Transport = {TransportMod, #{domain => Domain,
+ async => true,
+ method => plain}},
socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active).
ttest_tcp_server_stop(Pid) ->
@@ -17705,31 +28411,211 @@ ttest_tcp_server_stop(Pid) ->
ttest_tcp_client_start(Node,
Notify,
- gen,
- Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
- Transport = socket_test_ttest_tcp_gen,
+ Domain, gen,
+ ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
+ TransportMod = socket_test_ttest_tcp_gen,
+ Transport = {TransportMod, #{domain => Domain}},
socket_test_ttest_tcp_client:start_monitor(Node,
Notify,
Transport,
+ ServerInfo,
Active,
- Addr, Port,
MsgID, MaxOutstanding, RunTime);
ttest_tcp_client_start(Node,
Notify,
- sock,
- Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+ Domain, sock,
+ ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
TransportMod = socket_test_ttest_tcp_socket,
- Transport = {TransportMod, #{method => plain}},
+ Transport = {TransportMod, #{domain => Domain,
+ async => true,
+ method => plain}},
socket_test_ttest_tcp_client:start_monitor(Node,
Notify,
Transport,
+ ServerInfo,
Active,
- Addr, Port,
MsgID, MaxOutstanding, RunTime).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(TTEST_MANAGER, esock_ttest_manager).
+
+-record(ttest_report_id,
+ {domain :: socket:domain(),
+ serv_trans :: gen | sock,
+ serv_active :: once | boolean(),
+ client_trans :: gen | sock,
+ client_active :: once | boolean(),
+ msg_id :: small | medium | large}).
+
+-record(ttest_report, {id :: #ttest_report_id{},
+ time :: non_neg_integer(),
+ bytes :: non_neg_integer(),
+ msgs :: non_neg_integer()}).
+
+-spec ttest_report(Domain :: socket:domain(),
+ ServTrans :: gen | sock, ServActive :: once | boolean(),
+ ClientTrans :: gen | sock, ClientActive :: once | boolean(),
+ MsgID :: 1 | 2 | 3,
+ RunTime :: non_neg_integer(),
+ NumBytes :: non_neg_integer(),
+ NumMsgs :: non_neg_integer()) -> ok.
+
+ttest_report(Domain,
+ ServTrans, ServActive,
+ ClientTrans, ClientActive,
+ MsgID,
+ RunTime,
+ NumBytes,
+ NumMsgs) ->
+ ID = #ttest_report_id{domain = Domain,
+ serv_trans = ServTrans,
+ serv_active = ServActive,
+ client_trans = ClientTrans,
+ client_active = ClientActive,
+ msg_id = ttest_msg_id_num_to_name(MsgID)},
+ Report = #ttest_report{id = ID,
+ time = RunTime,
+ bytes = NumBytes,
+ msgs = NumMsgs},
+ %% If we run just one test case, the group init has never been run
+ %% and therefor the ttest manager is not running (we also don't actually
+ %% care about collecting reports in that case).
+ (catch global:send(?TTEST_MANAGER, Report)),
+ ok.
+
+ttest_msg_id_num_to_name(1) ->
+ small;
+ttest_msg_id_num_to_name(2) ->
+ medium;
+ttest_msg_id_num_to_name(3) ->
+ large.
+
+ttest_manager_start() ->
+ Self = self(),
+ {Pid, MRef} = spawn_monitor(fun() -> ttest_manager_init(Self) end),
+ receive
+ {ttest_manager_started, Pid} ->
+ erlang:demonitor(MRef, [flush]),
+ ok;
+ {'DOWN', MRef, process, Pid, Reason} ->
+ exit({failed_starting, ttest_manager, Reason})
+ after 5000 ->
+ exit(Pid, kill),
+ exit({failed_starting, ttest_manager, timeout})
+ end.
+
+ttest_manager_stop() ->
+ case global:whereis_name(?TTEST_MANAGER) of
+ Pid when is_pid(Pid) ->
+ erlang:monitor(process, Pid),
+ global:send(?TTEST_MANAGER, stop),
+ receive
+ {'DOWN', _MRef, process, Pid, _} ->
+ ok
+ after 10000 ->
+ exit(Pid, kill),
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
+ttest_manager_init(Parent) ->
+ yes = global:register_name(?TTEST_MANAGER, self()),
+ ets:new(?TTEST_MANAGER,
+ [{keypos, #ttest_report.id}, named_table, protected, ordered_set]),
+ Parent ! {ttest_manager_started, self()},
+ ttest_manager_loop().
+
+ttest_manager_loop() ->
+ receive
+ stop ->
+ ?LOGGER:format("manager stopping~n", []),
+ ttest_manager_done();
+
+ #ttest_report{id = _ID,
+ time = _RunTime,
+ bytes = _NumBytes,
+ msgs = _NumMsgs} = Report ->
+ true = ets:insert_new(?TTEST_MANAGER, Report),
+ ttest_manager_loop()
+ end.
+
+%% We are supposed to pretty print the result here...
+ttest_manager_done() ->
+ format_reports(inet),
+ %% format_reports(inet6),
+ ets:delete(?TTEST_MANAGER),
+ exit(normal).
+
+format_reports(Domain) ->
+ ?LOGGER:format("Domain ~w reports:~n~n", [Domain]),
+ format_reports(Domain, small),
+ format_reports(Domain, medium),
+ format_reports(Domain, large).
+
+format_reports(Domain, MsgID) when is_atom(MsgID) ->
+ case which_ttest_reports(Domain, MsgID) of
+ [] ->
+ ?LOGGER:format(" No ~w reports~n~n", [MsgID]);
+ Reports ->
+ ?LOGGER:format(" ~w reports: ~n", [MsgID]),
+ lists:foreach(fun(R) -> format_report(R) end, Reports)
+ end.
+
+%% This should really be a table like this:
+%%
+%% client
+%% server gen(false) gen(once) gen(true) sock(false) sock(once) sock(true)
+%% gen(false) nnn
+%% gen(once) nnn
+%% gen(true) nnn
+%% sock(false) nnn
+%% sock(once) nnn
+%% sock(true) nnn
+%%
+format_report(#ttest_report{id = #ttest_report_id{serv_trans = STrans,
+ serv_active = SActive,
+ client_trans = CTrans,
+ client_active = CActive},
+ time = RunTime,
+ bytes = BCnt,
+ msgs = MCnt}) ->
+ ?LOGGER:format(" server ~w[~w] - client ~w[~w] => "
+ "~n Run Time: ~s"
+ "~n Bytes: ~s"
+ "~n Messages: ~s"
+ "~n", [STrans, SActive, CTrans, CActive,
+ ?TTEST_LIB:format_time(RunTime),
+ if ((BCnt =:= 0) orelse (RunTime =:= 0)) ->
+ ?TTEST_LIB:format("~w, ~w",
+ [BCnt, RunTime]);
+ true ->
+ ?TTEST_LIB:format("~p => ~p byte / ms",
+ [BCnt, BCnt div RunTime])
+ end,
+ if (RunTime =:= 0) ->
+ "-";
+ true ->
+ ?TTEST_LIB:format("~p => ~p iterations / ms",
+ [MCnt, MCnt div RunTime])
+ end]),
+ ok.
+
+
+which_ttest_reports(Domain, all) ->
+ [R || R = #ttest_report{id = #ttest_report_id{domain = D}} <-
+ ets:tab2list(?TTEST_MANAGER), Domain =:= D];
+which_ttest_reports(Domain, MsgID) ->
+ [R || R = #ttest_report{id = #ttest_report_id{domain = D, msg_id = MID}} <-
+ ets:tab2list(?TTEST_MANAGER), (Domain =:= D) andalso (MsgID =:= MID)].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% This mechanism has only one purpose: So that we are able to kill
%% the node-starter process if it takes to long. The node-starter
%% runs on the local node.
@@ -17801,19 +28687,6 @@ sock_open(Domain, Type, Proto) ->
end.
-sock_bind(Sock, SockAddr) ->
- try socket:bind(Sock, SockAddr) of
- {ok, Port} ->
- Port;
- {error, Reason} ->
- i("sock_bind -> error: ~p", [Reason]),
- ?FAIL({bind, Reason})
- catch
- C:E:S ->
- i("sock_bind -> failed: ~p, ~p, ~p", [C, E, S]),
- ?FAIL({bind, C, E, S})
- end.
-
sock_connect(Sock, SockAddr) ->
try socket:connect(Sock, SockAddr) of
ok ->
@@ -17836,39 +28709,6 @@ sock_sockname(Sock) ->
?FAIL({sockname, C, E, S})
end.
-
-%% sock_listen(Sock) ->
-%% sock_listen2(fun() -> socket:listen(Sock) end).
-
-%% sock_listen(Sock, BackLog) ->
-%% sock_listen2(fun() -> socket:listen(Sock, BackLog) end).
-
-%% sock_listen2(Listen) ->
-%% try Listen() of
-%% ok ->
-%% ok;
-%% {error, Reason} ->
-%% ?FAIL({listen, Reason})
-%% catch
-%% C:E:S ->
-%% ?FAIL({listen, C, E, S})
-%% end.
-
-
-%% sock_accept(LSock) ->
-%% try socket:accept(LSock) of
-%% {ok, Sock} ->
-%% Sock;
-%% {error, Reason} ->
-%% i("sock_accept -> error: ~p", [Reason]),
-%% ?FAIL({accept, Reason})
-%% catch
-%% C:E:S ->
-%% i("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]),
-%% ?FAIL({accept, C, E, S})
-%% end.
-
-
sock_close(Sock) ->
try socket:close(Sock) of
ok ->
@@ -17899,64 +28739,213 @@ local_host() ->
end.
+%% The point of this is to "ensure" that paths from different test runs
+%% don't clash.
+mk_unique_path() ->
+ [NodeName | _] = string:tokens(atom_to_list(node()), [$@]),
+ Path = ?LIB:f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]),
+ ensure_unique_path(Path).
+
+ensure_unique_path(Path) ->
+ case file:read_file_info(Path) of
+ {ok, _} -> % Ouch, append a unique ID and try again
+ ensure_unique_path(Path, 1);
+ {error, _} ->
+ %% We assume this means it does not exist yet...
+ %% If we have several process in paralell trying to create
+ %% (unique) path's, then we are in trouble. To *really* be
+ %% on the safe side we should have a (central) path registry...
+ Path
+ end.
+
+ensure_unique_path(Path, ID) when (ID < 100) -> % If this is not enough...
+ NewPath = ?LIB:f("~s_~w", [Path, ID]),
+ case file:read_file_info(NewPath) of
+ {ok, _} -> % Ouch, this also existed, increment and try again
+ ensure_unique_path(Path, ID + 1);
+ {error, _} -> % We assume this means it does not exist yet...
+ NewPath
+ end;
+ensure_unique_path(_, _) ->
+ skip("Could not create unique path").
+
+
+which_local_socket_addr(local = Domain) ->
+ #{family => Domain,
+ path => mk_unique_path()};
+
+%% This gets the local socket address (not 127.0...)
+%% We should really implement this using the (new) net module,
+%% but until that gets the necessary functionality...
+which_local_socket_addr(Domain) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{addr := Addr}} ->
+ #{family => Domain,
+ addr => Addr};
+ {error, Reason} ->
+ ?FAIL(Reason)
+ end.
+
+
+
+which_local_addr(local = _Domain) ->
+ mk_unique_path();
+
%% This gets the local address (not 127.0...)
%% We should really implement this using the (new) net module,
%% but until that gets the necessary functionality...
which_local_addr(Domain) ->
- case inet:getifaddrs() of
- {ok, IFL} ->
- which_addr(Domain, IFL);
+ ?LIB:which_local_addr(Domain).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Here are all the *general* test case condition functions.
+
+%% We also need (be able) to figure out the the multicast address,
+%% which we only support for some platforms (linux and sunos).
+%% We don't do that here, but since we can only do that (find a
+%% multicast address) for specific platforms, we check that we are
+%% on of those platforms here.
+has_support_ip_multicast() ->
+ case os:type() of
+ {unix, OsName} when (OsName =:= linux) orelse
+ (OsName =:= sunos) ->
+ case ?LIB:which_local_host_info(inet) of
+ {ok, #{flags := Flags}} ->
+ case lists:member(multicast, Flags) of
+ true ->
+ ok;
+ false ->
+ not_supported(multicast)
+ end;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end;
+ {unix, OsName} ->
+ skip(?F("Not Supported: platform ~w", [OsName]));
+ Type ->
+ skip(?F("Not Supported: platform ~p", [Type]))
+ end.
+
+has_support_sock_acceptconn() ->
+ has_support_socket_option_sock(acceptconn).
+
+has_support_sock_bindtodevice() ->
+ has_support_socket_option_sock(bindtodevice).
+
+has_support_sock_broadcast() ->
+ has_support_socket_option_sock(broadcast),
+ case ?LIB:which_local_host_info(inet) of
+ {ok, #{flags := Flags}} ->
+ case lists:member(broadcast, Flags) of
+ true ->
+ ok;
+ false ->
+ not_supported({broadcast, Flags})
+ end;
{error, Reason} ->
- ?FAIL({inet, getifaddrs, Reason})
+ not_supported({broadcast, Reason})
end.
-which_addr(_Domain, []) ->
- ?FAIL(no_address);
-which_addr(Domain, [{"lo" ++ _, _}|IFL]) ->
- which_addr(Domain, IFL);
-which_addr(Domain, [{_Name, IFO}|IFL]) ->
- case which_addr2(Domain, IFO) of
- {ok, Addr} ->
- Addr;
- {error, no_address} ->
- which_addr(Domain, IFL)
- end;
-which_addr(Domain, [_|IFL]) ->
- which_addr(Domain, IFL).
+has_support_sock_debug() ->
+ has_support_socket_option_sock(debug).
-which_addr2(_Domain, []) ->
- {error, no_address};
-which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
- {ok, Addr};
-which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
- {ok, Addr};
-which_addr2(Domain, [_|IFO]) ->
- which_addr2(Domain, IFO).
+has_support_sock_domain() ->
+ has_support_socket_option_sock(domain).
+has_support_sock_dontroute() ->
+ has_support_socket_option_sock(dontroute).
+has_support_sock_keepalive() ->
+ has_support_socket_option_sock(keepalive).
+has_support_ip_add_membership() ->
+ has_support_socket_option_ip(add_membership).
+
+has_support_ip_drop_membership() ->
+ has_support_socket_option_ip(drop_membership).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Here are all the *general* test vase condition functions.
+has_support_socket_option_ip(Opt) ->
+ has_support_socket_option(ip, Opt).
+
+has_support_socket_option_sock(Opt) ->
+ has_support_socket_option(socket, Opt).
+
+has_support_socket_option(Level, Option) ->
+ case socket:supports(options, Level, Option) of
+ true ->
+ ok;
+ false ->
+ skip(?F("Not Supported: ~w option ~w", [Level, Option]))
+ end.
+
+
+
+
+unix_domain_socket_host_cond() ->
+ unix_domain_socket_host_cond(os:type(), os:version()).
+
+unix_domain_socket_host_cond({unix, linux}, {M, _, _}) when (M < 3) ->
+ skip("TC may not work on this version");
+unix_domain_socket_host_cond(_, _) ->
+ ok.
+
+has_support_unix_domain_socket() ->
+ case os:type() of
+ {win32, _} ->
+ skip("Not supported");
+ _ ->
+ case socket:supports(local) of
+ true ->
+ ok;
+ false ->
+ skip("Not supported")
+ end
+ end.
+
%% The idea is that this function shall test if the test host has
%% support for IPv6. If not, there is no point in running IPv6 tests.
%% Currently we just skip.
has_support_ipv6() ->
- %% case socket:supports(ipv6) of
- %% true ->
- %% ok;
- %% false ->
- %% {error, not_supported}
- %% end.
- not_yet_implemented().
+ ?LIB:has_support_ipv6().
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+unlink_path(Path) ->
+ unlink_path(Path, fun() -> ok end, fun() -> ok end).
+
+unlink_path(Path, Success, Failure) when is_list(Path) andalso
+ is_function(Success, 0) andalso
+ is_function(Failure, 0) ->
+ ?SEV_IPRINT("try unlink path: "
+ "~n ~s", [Path]),
+ case os:cmd("unlink " ++ Path) of
+ "" ->
+ ?SEV_IPRINT("path unlinked: "
+ "~n Path: ~s", [Path]),
+ Success();
+ Result ->
+ ?SEV_EPRINT("unlink maybe failed: "
+ "~n Path: ~s"
+ "~n Res: ~s", [Path, Result]),
+ Failure()
+ end;
+unlink_path(_, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+not_supported(What) ->
+ skip({not_supported, What}).
+
not_yet_implemented() ->
skip("not yet implemented").
diff --git a/erts/emulator/test/socket_test_lib.erl b/erts/emulator/test/socket_test_lib.erl
index 4e65c4f3c0..39cbf0c79f 100644
--- a/erts/emulator/test/socket_test_lib.erl
+++ b/erts/emulator/test/socket_test_lib.erl
@@ -32,6 +32,12 @@
%% String and format
f/2,
+ %% Generic 'has support' test function(s)
+ has_support_ipv6/0,
+
+ which_local_host_info/1,
+ which_local_addr/1,
+
%% Skipping
not_yet_implemented/0,
skip/1
@@ -40,6 +46,11 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(FAIL(R), exit(R)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
pi(Item) when is_atom(Item) ->
pi(self(), Item).
@@ -88,6 +99,196 @@ f(F, A) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+has_support_ipv6() ->
+ case socket:supports(ipv6) of
+ true ->
+ ok;
+ false ->
+ skip("IPv6 Not Supported")
+ end,
+ Domain = inet6,
+ LocalAddr =
+ case which_local_addr(Domain) of
+ {ok, Addr} ->
+ Addr;
+ {error, R1} ->
+ skip(f("Local Address eval failed: ~p", [R1]))
+ end,
+ ServerSock =
+ case socket:open(Domain, dgram, udp) of
+ {ok, SS} ->
+ SS;
+ {error, R2} ->
+ skip(f("(server) socket open failed: ~p", [R2]))
+ end,
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ ServerPort =
+ case socket:bind(ServerSock, LocalSA) of
+ {ok, P1} ->
+ P1;
+ {error, R3} ->
+ socket:close(ServerSock),
+ skip(f("(server) socket bind failed: ~p", [R3]))
+ end,
+ ServerSA = LocalSA#{port => ServerPort},
+ ClientSock =
+ case socket:open(Domain, dgram, udp) of
+ {ok, CS} ->
+ CS;
+ {error, R4} ->
+ skip(f("(client) socket open failed: ~p", [R4]))
+ end,
+ case socket:bind(ClientSock, LocalSA) of
+ {ok, _} ->
+ ok;
+ {error, R5} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ skip(f("(client) socket bind failed: ~p", [R5]))
+ end,
+ case socket:sendto(ClientSock, <<"hejsan">>, ServerSA) of
+ ok ->
+ ok;
+ {error, R6} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ skip(f("failed socket sendto test: ~p", [R6]))
+ end,
+ case socket:recvfrom(ServerSock) of
+ {ok, {_, <<"hejsan">>}} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ ok;
+ {error, R7} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ skip(f("failed socket recvfrom test: ~p", [R7]))
+ end.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This gets the local address (not {127, _} or {0, ...} or {16#fe80, ...})
+%% We should really implement this using the (new) net module,
+%% but until that gets the necessary functionality...
+which_local_addr(Domain) ->
+ case which_local_host_info(Domain) of
+ {ok, #{addr := Addr}} ->
+ {ok, Addr};
+ {error, _Reason} = ERROR ->
+ ERROR
+ end.
+
+
+%% Returns the interface (name), flags and address (not 127...)
+%% of the local host.
+which_local_host_info(Domain) ->
+ case inet:getifaddrs() of
+ {ok, IFL} ->
+ which_local_host_info(Domain, IFL);
+ {error, _} = ERROR ->
+ ERROR
+ end.
+
+which_local_host_info(_Domain, []) ->
+ {error, no_address};
+which_local_host_info(Domain, [{"lo" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{"docker" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{"br-" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{Name, IFO}|IFL]) ->
+ try which_local_host_info2(Domain, IFO) of
+ Info ->
+ {ok, Info#{name => Name}}
+ catch
+ throw:_:_ ->
+ which_local_host_info(Domain, IFL)
+ end;
+which_local_host_info(Domain, [_|IFL]) ->
+ which_local_host_info(Domain, IFL).
+
+%% which_local_host_info2(Domain, IFO) ->
+%% case lists:keysearch(flags, 1, IFO) of
+%% {value, {flags, Flags}} ->
+%% which_local_host_info2(Domain, IFO, Flags);
+%% false ->
+%% {error, no_flags}
+%% end.
+
+
+%% which_local_host_info2(_Domain, [], _Flags) ->
+%% {error, no_address};
+%% which_local_host_info2(inet = _Domain, [{addr, Addr}|_IFO], Flags)
+%% when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) ->
+%% {ok, {Flags, Addr}};
+%% which_local_host_info2(inet6 = _Domain, [{addr, Addr}|_IFO], Flags)
+%% when (size(Addr) =:= 8) andalso
+%% (element(1, Addr) =/= 0) andalso
+%% (element(1, Addr) =/= 16#fe80) ->
+%% {ok, {Flags, Addr}};
+%% which_local_host_info2(Domain, [_|IFO], Flags) ->
+%% which_local_host_info2(Domain, IFO, Flags).
+
+%% foo(Info, inet = Domain, IFO) ->
+%% foo(Info, Domain, IFO, [flags, addr, netmask, broadaddr, hwaddr]);
+%% foo(Info, inet6 = Domain, IFO) ->
+%% foo(Info, Domain, IFO, [flags, addr, netmask, hwaddr]).
+
+which_local_host_info2(inet = _Domain, IFO) ->
+ Addr = which_local_host_info3(addr, IFO,
+ fun({A, _, _, _}) when (A =/= 127) -> true;
+ (_) -> false
+ end),
+ NetMask = which_local_host_info3(netmask, IFO,
+ fun({_, _, _, _}) -> true;
+ (_) -> false
+ end),
+ BroadAddr = which_local_host_info3(broadaddr, IFO,
+ fun({_, _, _, _}) -> true;
+ (_) -> false
+ end),
+ Flags = which_local_host_info3(flags, IFO, fun(_) -> true end),
+ #{flags => Flags,
+ addr => Addr,
+ broadaddr => BroadAddr,
+ netmask => NetMask};
+which_local_host_info2(inet6 = _Domain, IFO) ->
+ Addr = which_local_host_info3(addr, IFO,
+ fun({A, _, _, _, _, _, _, _})
+ when (A =/= 0) andalso
+ (A =/= 16#fe80) -> true;
+ (_) -> false
+ end),
+ NetMask = which_local_host_info3(netmask, IFO,
+ fun({_, _, _, _, _, _, _, _}) -> true;
+ (_) -> false
+ end),
+ Flags = which_local_host_info3(flags, IFO, fun(_) -> true end),
+ #{flags => Flags,
+ addr => Addr,
+ netmask => NetMask}.
+
+which_local_host_info3(_Key, [], _) ->
+ throw({error, no_address});
+which_local_host_info3(Key, [{Key, Val}|IFO], Check) ->
+ case Check(Val) of
+ true ->
+ Val;
+ false ->
+ which_local_host_info3(Key, IFO, Check)
+ end;
+which_local_host_info3(Key, [_|IFO], Check) ->
+ which_local_host_info3(Key, IFO, Check).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
not_yet_implemented() ->
skip("not yet implemented").
diff --git a/erts/emulator/test/socket_test_logger.erl b/erts/emulator/test/socket_test_logger.erl
index 26610e9ef3..f5d4c8c7b2 100644
--- a/erts/emulator/test/socket_test_logger.erl
+++ b/erts/emulator/test/socket_test_logger.erl
@@ -43,7 +43,7 @@ start(Quiet) ->
ok;
undefined ->
Self = self(),
- Pid = spawn_link(fun() -> init(Self, Quiet) end),
+ Pid = spawn(fun() -> init(Self, Quiet) end),
yes = global:register_name(?LOGGER, Pid),
ok
end.
diff --git a/erts/emulator/test/socket_test_ttest_tcp_client.erl b/erts/emulator/test/socket_test_ttest_tcp_client.erl
index 5efa3fe491..f28819ca69 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_client.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_client.erl
@@ -42,16 +42,16 @@
-export([
%% These are for the test suite
- start_monitor/6, start_monitor/7, start_monitor/9,
+ start_monitor/5, start_monitor/6, start_monitor/8,
%% These are for starting in a shell when run "manually"
- start/4, start/5, start/7, start/8,
+ start/3, start/4, start/6, start/7,
stop/1
]).
%% Internal exports
-export([
- do_start/10
+ do_start/9
]).
-include_lib("kernel/include/inet.hrl").
@@ -80,25 +80,25 @@
%% ==========================================================================
-start_monitor(Node, Notify, Transport, Active, Addr, Port) ->
- start_monitor(Node, Notify, Transport, Active, Addr, Port, ?MSG_ID_DEFAULT).
+start_monitor(Node, Notify, Transport, ServerInfo, Active) ->
+ start_monitor(Node, Notify, Transport, ServerInfo, Active, ?MSG_ID_DEFAULT).
-start_monitor(Node, Notify, Transport, Active, Addr, Port, 1 = MsgID) ->
- start_monitor(Node, Notify, Transport, Active, Addr, Port, MsgID,
+start_monitor(Node, Notify, Transport, ServerInfo, Active, 1 = MsgID) ->
+ start_monitor(Node, Notify, Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_1, ?RUNTIME_DEFAULT);
-start_monitor(Node, Notify, Transport, Active, Addr, Port, 2 = MsgID) ->
- start_monitor(Node, Notify, Transport, Active, Addr, Port, MsgID,
+start_monitor(Node, Notify, Transport, ServerInfo, Active, 2 = MsgID) ->
+ start_monitor(Node, Notify, Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_2, ?RUNTIME_DEFAULT);
-start_monitor(Node, Notify, Transport, Active, Addr, Port, 3 = MsgID) ->
- start_monitor(Node, Notify, Transport, Active, Addr, Port, MsgID,
+start_monitor(Node, Notify, Transport, ServerInfo, Active, 3 = MsgID) ->
+ start_monitor(Node, Notify, Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_3, ?RUNTIME_DEFAULT).
-start_monitor(Node, Notify, Transport, Active, Addr, Port,
+start_monitor(Node, Notify, Transport, ServerInfo, Active,
MsgID, MaxOutstanding, RunTime)
when (Node =/= node()) ->
Args = [false,
self(), Notify,
- Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime],
+ Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime],
case rpc:call(Node, ?MODULE, do_start, Args) of
{badrpc, _} = Reason ->
{error, Reason};
@@ -108,11 +108,11 @@ start_monitor(Node, Notify, Transport, Active, Addr, Port,
{error, _} = ERROR ->
ERROR
end;
-start_monitor(_, Notify, Transport, Active, Addr, Port,
+start_monitor(_, Notify, Transport, ServerInfo, Active,
MsgID, MaxOutstanding, RunTime) ->
case do_start(false,
self(), Notify,
- Transport, Active, Addr, Port,
+ Transport, Active, ServerInfo,
MsgID, MaxOutstanding, RunTime) of
{ok, Pid} ->
MRef = erlang:monitor(process, Pid),
@@ -122,50 +122,48 @@ start_monitor(_, Notify, Transport, Active, Addr, Port,
end.
-start(Transport, Active, Addr, Port) ->
- start(Transport, Active, Addr, Port, ?MSG_ID_DEFAULT).
+start(Transport, ServerInfo, Active) ->
+ start(Transport, ServerInfo, Active, ?MSG_ID_DEFAULT).
-start(Transport, Active, Addr, Port, 1 = MsgID) ->
+start(Transport, ServerInfo, Active, 1 = MsgID) ->
start(false,
- Transport, Active, Addr, Port, MsgID,
+ Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_1, ?RUNTIME_DEFAULT);
-start(Transport, Active, Addr, Port, 2 = MsgID) ->
+start(Transport, ServerInfo, Active, 2 = MsgID) ->
start(false,
- Transport, Active, Addr, Port, MsgID,
+ Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_2, ?RUNTIME_DEFAULT);
-start(Transport, Active, Addr, Port, 3 = MsgID) ->
+start(Transport, ServerInfo, Active, 3 = MsgID) ->
start(false,
- Transport, Active, Addr, Port, MsgID,
+ Transport, ServerInfo, Active, MsgID,
?MAX_OUTSTANDING_DEFAULT_3, ?RUNTIME_DEFAULT).
-start(Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
start(false,
- Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime).
+ Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime).
-start(Quiet, Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(Quiet, Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
Notify = fun(R) -> present_results(R) end,
do_start(Quiet,
self(), Notify,
- Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime).
+ Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime).
-spec do_start(Quiet,
Parent,
Notify,
Transport,
+ ServerInfo,
Active,
- Addr,
- Port,
MsgID,
MaxOutstanding,
RunTime) -> {ok, Pid} | {error, Reason} when
- Quiet :: pid(),
+ Quiet :: boolean(),
Parent :: pid(),
Notify :: function(),
Transport :: atom() | tuple(),
+ ServerInfo :: {inet:ip_address(), inet:port_number()} | string(),
Active :: active(),
- Addr :: inet:ip_address(),
- Port :: inet:port_number(),
MsgID :: msg_id(),
MaxOutstanding :: max_outstanding(),
RunTime :: runtime(),
@@ -174,14 +172,13 @@ start(Quiet, Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
do_start(Quiet,
Parent, Notify,
- Transport, Active, Addr, Port, MsgID, MaxOutstanding, RunTime)
+ Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime)
when is_boolean(Quiet) andalso
is_pid(Parent) andalso
is_function(Notify) andalso
(is_atom(Transport) orelse is_tuple(Transport)) andalso
(is_boolean(Active) orelse (Active =:= once)) andalso
- is_tuple(Addr) andalso
- (is_integer(Port) andalso (Port > 0)) andalso
+ (is_tuple(ServerInfo) orelse is_list(ServerInfo)) andalso
(is_integer(MsgID) andalso (MsgID >= 1) andalso (MsgID =< 3)) andalso
(is_integer(MaxOutstanding) andalso (MaxOutstanding > 0)) andalso
(is_integer(RunTime) andalso (RunTime > 0)) ->
@@ -191,7 +188,7 @@ do_start(Quiet,
Starter,
Parent,
Notify,
- Transport, Active, Addr, Port,
+ Transport, Active, ServerInfo,
MsgID, MaxOutstanding, RunTime)
end,
{Pid, MRef} = spawn_monitor(Init),
@@ -217,25 +214,30 @@ stop(Pid) when is_pid(Pid) ->
init(Quiet,
Starter,
Parent, Notify,
- Transport, Active, Addr, Port,
+ Transport, Active, ServerInfo,
MsgID, MaxOutstanding, RunTime) ->
if
not Quiet ->
?I("init with"
"~n Transport: ~p"
"~n Active: ~p"
- "~n Addr: ~s"
- "~n Port: ~p"
+ "~n ServerInfo: ~s"
"~n Msg ID: ~p (=> 16 + ~w bytes)"
"~n Max Outstanding: ~p"
"~n (Suggested) Run Time: ~p ms",
- [Transport, Active, inet:ntoa(Addr), Port,
+ [Transport, Active,
+ case ServerInfo of
+ {Addr, Port} ->
+ ?F("Addr: ~s, Port: ~w", [inet:ntoa(Addr), Port]);
+ Path ->
+ Path
+ end,
MsgID, size(which_msg_data(MsgID)), MaxOutstanding, RunTime]);
true ->
ok
end,
{Mod, Connect} = process_transport(Transport),
- case Connect(Addr, Port) of
+ case Connect(ServerInfo) of
{ok, Sock} ->
if not Quiet -> ?I("connected");
true -> ok
@@ -264,14 +266,21 @@ init(Quiet,
(catch Mod:close(Sock)),
exit(normal);
{error, Reason} ->
- ?E("connect failed: ~p", [Reason]),
- exit({connect, Reason})
+ ?E("connect failed: ~p"
+ "~n ~p", [Reason, ServerInfo]),
+ exit({connect, Reason, ServerInfo})
end.
process_transport(Mod) when is_atom(Mod) ->
- {Mod, fun(A, P) -> Mod:connect(A, P) end};
-process_transport({Mod, Opts}) ->
- {Mod, fun(A, P) -> Mod:connect(A, P, Opts) end}.
+ %% In this case we assume it to be a plain tcp socket
+ {Mod, fun({A, P}) -> Mod:connect(A, P) end};
+process_transport({Mod, #{domain := Domain} = Opts}) ->
+ Connect =
+ case Domain of
+ local -> fun(Path) -> Mod:connect(Path, Opts) end;
+ _ -> fun({A, P}) -> Mod:connect(A, P, Opts) end
+ end,
+ {Mod, Connect}.
which_msg_data(1) -> ?MSG_DATA1;
diff --git a/erts/emulator/test/socket_test_ttest_tcp_client_gen.erl b/erts/emulator/test/socket_test_ttest_tcp_client_gen.erl
index 0ec2e908d7..65a3a94d38 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_client_gen.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_client_gen.erl
@@ -21,28 +21,28 @@
-module(socket_test_ttest_tcp_client_gen).
-export([
- start/3, start/4, start/6, start/7,
+ start/2, start/3, start/5, start/6,
stop/1
]).
-define(TRANSPORT_MOD, socket_test_ttest_tcp_gen).
-start(Active, Addr, Port) ->
- socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, Active, Addr, Port).
+start(ServerInfo, Active) ->
+ socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, ServerInfo, Active).
-start(Active, Addr, Port, MsgID) ->
- socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, Active, Addr, Port, MsgID).
+start(ServerInfo, Active, MsgID) ->
+ socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, ServerInfo, Active, MsgID).
-start(Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
socket_test_ttest_tcp_client:start(false,
?TRANSPORT_MOD,
- Active, Addr, Port,
+ ServerInfo, Active,
MsgID, MaxOutstanding, RunTime).
-start(Quiet, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(Quiet, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
socket_test_ttest_tcp_client:start(Quiet,
?TRANSPORT_MOD,
- Active, Addr, Port,
+ ServerInfo, Active,
MsgID, MaxOutstanding, RunTime).
stop(Pid) ->
diff --git a/erts/emulator/test/socket_test_ttest_tcp_client_socket.erl b/erts/emulator/test/socket_test_ttest_tcp_client_socket.erl
index acf2556793..2fb1242028 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_client_socket.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_client_socket.erl
@@ -26,25 +26,90 @@
]).
-define(TRANSPORT_MOD, socket_test_ttest_tcp_socket).
--define(MOD(M), {?TRANSPORT_MOD, #{method => Method}}).
+-define(MOD(D, A, M), {?TRANSPORT_MOD, #{domain => D,
+ async => A,
+ method => M}}).
-start(Method, Active, Addr, Port) ->
- socket_test_ttest_tcp_client:start_monitor(?MOD(Method), Active, Addr, Port).
+start(Method, Async, Active, ServerInfo)
+ when is_list(ServerInfo) ->
+ Domain = local,
+ socket_test_ttest_tcp_client:start_monitor(?MOD(Domain, Async, Method),
+ ServerInfo, Active);
+start(Method, Async, Active, ServerInfo = {Addr, _})
+ when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
+ Domain = inet,
+ socket_test_ttest_tcp_client:start_monitor(?MOD(Domain, Async, Method),
+ ServerInfo, Active);
+start(Method, Async, Active, ServerInfo = {Addr, _})
+ when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
+ Domain = inet6,
+ socket_test_ttest_tcp_client:start_monitor(?MOD(Domain, Async, Method),
+ ServerInfo, Active).
-start(Method, Active, Addr, Port, MsgID) ->
- socket_test_ttest_tcp_client:start(?MOD(Method),
- Active, Addr, Port, MsgID).
+start(Method, Async, Active, ServerInfo, MsgID)
+ when is_list(ServerInfo) ->
+ %% This is just a simplification
+ Domain = local,
+ socket_test_ttest_tcp_client:start(?MOD(Domain, Async, Method),
+ ServerInfo, Active, MsgID);
+start(Method, Async, Active, ServerInfo = {Addr, _}, MsgID)
+ when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
+ %% This is just a simplification
+ Domain = inet,
+ socket_test_ttest_tcp_client:start(?MOD(Domain, Async, Method),
+ Active, ServerInfo, MsgID);
+start(Method, Async, Active, ServerInfo = {Addr, _}, MsgID)
+ when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
+ Domain = inet6,
+ socket_test_ttest_tcp_client:start(?MOD(Domain, Async, Method),
+ ServerInfo, Active, MsgID).
-start(Method, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(Method, Async, Active, ServerInfo, MsgID, MaxOutstanding, RunTime)
+ when is_list(ServerInfo) ->
+ Domain = local,
socket_test_ttest_tcp_client:start(false,
- ?MOD(Method),
- Active, Addr, Port,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
+ MsgID, MaxOutstanding, RunTime);
+start(Method, Async, Active, ServerInfo = {Addr, _},
+ MsgID, MaxOutstanding, RunTime)
+ when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
+ Domain = inet,
+ socket_test_ttest_tcp_client:start(false,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
+ MsgID, MaxOutstanding, RunTime);
+start(Method, Async, Active, ServerInfo = {Addr, _},
+ MsgID, MaxOutstanding, RunTime)
+ when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
+ Domain = inet6,
+ socket_test_ttest_tcp_client:start(false,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
MsgID, MaxOutstanding, RunTime).
-start(Quiet, Method, Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+start(Quiet, Async, Active, Method, ServerInfo, MsgID, MaxOutstanding, RunTime)
+ when is_list(ServerInfo) ->
+ Domain = local,
+ socket_test_ttest_tcp_client:start(Quiet,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
+ MsgID, MaxOutstanding, RunTime);
+start(Quiet, Async, Active, Method, ServerInfo = {Addr, _},
+ MsgID, MaxOutstanding, RunTime)
+ when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
+ Domain = inet,
+ socket_test_ttest_tcp_client:start(Quiet,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
+ MsgID, MaxOutstanding, RunTime);
+start(Quiet, Async, Active, Method, ServerInfo = {Addr, _},
+ MsgID, MaxOutstanding, RunTime)
+ when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
+ Domain = inet6,
socket_test_ttest_tcp_client:start(Quiet,
- ?MOD(Method),
- Active, Addr, Port,
+ ?MOD(Domain, Async, Method),
+ ServerInfo, Active,
MsgID, MaxOutstanding, RunTime).
stop(Pid) ->
diff --git a/erts/emulator/test/socket_test_ttest_tcp_gen.erl b/erts/emulator/test/socket_test_ttest_tcp_gen.erl
index 604408c489..e59bd881e7 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_gen.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,9 +24,9 @@
accept/1, accept/2,
active/2,
close/1,
- connect/2,
+ connect/2, connect/3,
controlling_process/2,
- listen/0, listen/1,
+ listen/0, listen/1, listen/2,
peername/1,
port/1,
recv/2, recv/3,
@@ -36,19 +36,7 @@
]).
-%% ==========================================================================
-
-%% getopt(Sock, Opt) when is_atom(Opt) ->
-%% case inet:getopts(Sock, [Opt]) of
-%% {ok, [{Opt, Value}]} ->
-%% {ok, Value};
-%% {error, _} = ERROR ->
-%% ERROR
-%% end.
-
-%% setopt(Sock, Opt, Value) when is_atom(Opt) ->
-%% inet:setopts(Sock, [{Opt, Value}]).
-
+-define(LIB, socket_test_lib).
%% ==========================================================================
@@ -80,6 +68,13 @@ close(Sock) ->
connect(Addr, Port) ->
Opts = [binary, {packet, raw}, {active, false}, {buffer, 32*1024}],
+ do_connect(Addr, Port, Opts).
+
+connect(Addr, Port, #{domain := Domain}) ->
+ Opts = [Domain, binary, {packet, raw}, {active, false}, {buffer, 32*1024}],
+ do_connect(Addr, Port, Opts).
+
+do_connect(Addr, Port, Opts) ->
case gen_tcp:connect(Addr, Port, Opts) of
{ok, Sock} ->
{ok, Sock};
@@ -95,12 +90,16 @@ controlling_process(Sock, NewPid) ->
listen() ->
listen(0).
-listen(Port) when is_integer(Port) andalso (Port >= 0) ->
- Opts = [binary, {ip, {0,0,0,0}}, {packet, raw}, {active, false},
- {buffer, 32*1024}],
- case gen_tcp:listen(Port, Opts) of
- {ok, Sock} ->
- {ok, Sock};
+listen(Port) ->
+ listen(Port, #{domain => inet}).
+
+listen(Port, #{domain := Domain}) when is_integer(Port) andalso (Port >= 0) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, {_, _, Addr}} ->
+ Opts = [Domain,
+ binary, {ip, Addr}, {packet, raw}, {active, false},
+ {buffer, 32*1024}],
+ gen_tcp:listen(Port, Opts);
{error, _} = ERROR ->
ERROR
end.
diff --git a/erts/emulator/test/socket_test_ttest_tcp_server.erl b/erts/emulator/test/socket_test_ttest_tcp_server.erl
index e8d626e3d8..2394dc7924 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_server.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -90,14 +90,17 @@ start_monitor(_, Transport, Active) ->
start(Transport, Active) ->
do_start(self(), Transport, Active).
-
+%% Note that the Async option is actually only "used" for the
+%% socket transport module (it details how to implement the
+%% active feature).
do_start(Parent, Transport, Active)
when is_pid(Parent) andalso
(is_atom(Transport) orelse is_tuple(Transport)) andalso
(is_boolean(Active) orelse (Active =:= once)) ->
Starter = self(),
- ServerInit = fun() -> put(sname, "server"),
- server_init(Starter, Parent, Transport, Active)
+ ServerInit = fun() ->
+ put(sname, "server"),
+ server_init(Starter, Parent, Transport, Active)
end,
{Pid, MRef} = spawn_monitor(ServerInit),
receive
@@ -126,17 +129,35 @@ server_init(Starter, Parent, Transport, Active) ->
case Listen(0) of
{ok, LSock} ->
case Mod:port(LSock) of
- {ok, Port} ->
- Addr = which_addr(), % This is just for convenience
- ?I("listening on:"
- "~n Addr: ~p (~s)"
- "~n Port: ~w"
- "~n", [Addr, inet:ntoa(Addr), Port]),
- Starter ! {?MODULE, self(), {ok, {Addr, Port}}},
+ {ok, PortOrPath} ->
+ Result =
+ if
+ is_integer(PortOrPath) ->
+ %% This is just for convenience
+ case Mod:sockname(LSock) of
+ {ok, {Addr, _}} ->
+ ?I("listening on:"
+ "~n Addr: ~p (~s)"
+ "~n Port: ~w"
+ "~n", [Addr,
+ inet:ntoa(Addr),
+ PortOrPath]),
+ {Addr, PortOrPath};
+ {error, SNReason} ->
+ exit({sockname, SNReason})
+ end;
+ is_list(PortOrPath) ->
+ ?I("listening on:"
+ "~n Path: ~s"
+ "~n", [PortOrPath]),
+ PortOrPath
+ end,
+ Starter ! {?MODULE, self(), {ok, Result}},
server_loop(#{parent => Parent,
mod => Mod,
active => Active,
lsock => LSock,
+ port_or_path => PortOrPath,
handlers => [],
stats_interval => StatsInterval,
%% Accumulation
@@ -166,49 +187,68 @@ process_transport({Mod, Opts}, _Active) ->
server_loop(State) ->
- server_loop( server_handle_message( server_accept(State) ) ).
+ server_loop( server_handle_message( server_accept(State, ?ACC_TIMEOUT), 0) ).
-server_accept(#{mod := Mod,
- active := Active,
- lsock := LSock,
- handlers := Handlers} = State) ->
- case Mod:accept(LSock, ?ACC_TIMEOUT) of
+server_accept(#{mod := Mod, lsock := LSock} = State, Timeout) ->
+ case Mod:accept(LSock, Timeout) of
{ok, Sock} ->
- ?I("accepted connection from ~s",
- [case Mod:peername(Sock) of
- {ok, Peer} ->
- format_peername(Peer);
- {error, _} ->
- "-"
- end]),
- {Pid, _} = handler_start(),
- ?I("handler ~p started -> try transfer socket control", [Pid]),
- case Mod:controlling_process(Sock, Pid) of
- ok ->
- maybe_start_stats_timer(State, Pid),
- ?I("server-accept: handler ~p started", [Pid]),
- handler_continue(Pid, Mod, Sock, Active),
- Handlers2 = [Pid | Handlers],
- State#{handlers => Handlers2};
- {error, CPReason} ->
- (catch Mod:close(Sock)),
- (catch Mod:close(LSock)),
- exit({controlling_process, CPReason})
- end;
- {error, timeout} ->
+ server_handle_accepted(State, Sock);
+ {error, timeout} when (Timeout =/= nowait) ->
State;
{error, AReason} ->
(catch Mod:close(LSock)),
exit({accept, AReason})
end.
+%% server_accept(#{mod := Mod,
+%% lsock := LSock} = State) ->
+%% case Mod:accept(LSock, ?ACC_TIMEOUT) of
+%% {ok, Sock} ->
+%% server_handle_accepted(State, Sock);
+%% {error, timeout} ->
+%% State;
+%% {error, AReason} ->
+%% (catch Mod:close(LSock)),
+%% exit({accept, AReason})
+%% end.
+
+server_handle_accepted(#{mod := Mod,
+ lsock := LSock,
+ active := Active,
+ handlers := Handlers} = State,
+ Sock) ->
+ ?I("accepted connection from ~s",
+ [case Mod:peername(Sock) of
+ {ok, Peer} ->
+ format_peername(Peer);
+ {error, _} ->
+ "-"
+ end]),
+ {Pid, _} = handler_start(),
+ ?I("handler ~p started -> try transfer socket control", [Pid]),
+ case Mod:controlling_process(Sock, Pid) of
+ ok ->
+ maybe_start_stats_timer(State, Pid),
+ ?I("server-accept: handler ~p started", [Pid]),
+ handler_continue(Pid, Mod, Sock, Active),
+ Handlers2 = [Pid | Handlers],
+ State#{handlers => Handlers2};
+ {error, CPReason} ->
+ (catch Mod:close(Sock)),
+ (catch Mod:close(LSock)),
+ exit({controlling_process, CPReason})
+ end.
+
+
format_peername({Addr, Port}) ->
case inet:gethostbyaddr(Addr) of
{ok, #hostent{h_name = N}} ->
?F("~s (~s:~w)", [N, inet:ntoa(Addr), Port]);
{error, _} ->
?F("~p, ~p", [Addr, Port])
- end.
+ end;
+format_peername(Path) when is_list(Path) ->
+ Path.
maybe_start_stats_timer(#{active := Active, stats_interval := Time}, Handler)
when (Active =/= false) andalso (is_integer(Time) andalso (Time > 0)) ->
@@ -219,7 +259,10 @@ maybe_start_stats_timer(_, _) ->
start_stats_timer(Time, ProcStr, Pid) ->
erlang:start_timer(Time, self(), {stats, Time, ProcStr, Pid}).
-server_handle_message(#{parent := Parent, handlers := H} = State) ->
+server_handle_message(#{mod := Mod,
+ lsock := LSock,
+ parent := Parent,
+ handlers := H} = State, Timeout) ->
receive
{timeout, _TRef, {stats, Interval, ProcStr, Pid}} ->
case server_handle_stats(ProcStr, Pid) of
@@ -229,16 +272,17 @@ server_handle_message(#{parent := Parent, handlers := H} = State) ->
ok
end,
State;
-
+
{?MODULE, Ref, Parent, stop} ->
reply(Parent, Ref, ok),
lists:foreach(fun(P) -> handler_stop(P) end, H),
+ (catch Mod:close(LSock)),
exit(normal);
{'DOWN', _MRef, process, Pid, Reason} ->
server_handle_down(Pid, Reason, State)
- after 0 ->
+ after Timeout ->
State
end.
@@ -272,28 +316,26 @@ server_handle_handler_down(Pid,
AccMCnt2 = AccMCnt + MCnt,
AccBCnt2 = AccBCnt + BCnt,
AccHCnt2 = AccHCnt + 1,
- ?I("handler ~p (~w) done => accumulated results: "
- "~n Run Time: ~s ms"
+ MsgCount2Str =
+ fun(RT, ART, MC, AMC) when (RT > 0) ->
+ ?F("~w => ~w (~w) msgs / ms", [MC, MC div RT, AMC div ART]);
+ (_, _, MC, AMC) ->
+ ?F("~w (~w)", [MC, AMC])
+ end,
+ ByteCount2Str =
+ fun(RT, ART, BC, ABC) when (RT > 0) ->
+ ?F("~w => ~w (~w) bytes / ms", [BC, BC div RT, ABC div ART]);
+ (_, _, BC, ABC) ->
+ ?F("~w", [BC, ABC])
+ end,
+ ?I("handler ~p (~w) done: "
+ "~n Run Time: ~s"
"~n Message Count: ~s"
"~n Byte Count: ~s",
[Pid, AccHCnt2,
- ?FORMAT_TIME(AccRunTime2),
- if (AccRunTime2 > 0) ->
- ?F("~w => ~w (~w) msgs / ms",
- [AccMCnt2,
- AccMCnt2 div AccRunTime2,
- (AccMCnt2 div AccHCnt2) div AccRunTime2]);
- true ->
- ?F("~w", [AccMCnt2])
- end,
- if (AccRunTime2 > 0) ->
- ?F("~w => ~w (~w) bytes / ms",
- [AccBCnt2,
- AccBCnt2 div AccRunTime2,
- (AccBCnt2 div AccHCnt2) div AccRunTime2]);
- true ->
- ?F("~w", [AccBCnt2])
- end]),
+ ?FORMAT_TIME(RunTime),
+ MsgCount2Str(RunTime, AccRunTime2, MCnt, AccMCnt2),
+ ByteCount2Str(RunTime, AccRunTime2, BCnt, AccBCnt2)]),
State#{runtime => AccRunTime2,
mcnt => AccMCnt2,
bcnt => AccBCnt2,
@@ -325,15 +367,15 @@ handler_init(Parent) ->
?I("received continue"),
reply(Parent, Ref, ok),
handler_initial_activation(Mod, Sock, Active),
- handler_loop(#{parent => Parent,
- mod => Mod,
- sock => Sock,
- active => Active,
- start => ?T(),
- mcnt => 0,
- bcnt => 0,
- last_reply => none,
- acc => <<>>})
+ handler_loop(#{parent => Parent,
+ mod => Mod,
+ sock => Sock,
+ active => Active,
+ start => ?T(),
+ mcnt => 0,
+ bcnt => 0,
+ last_reply => none,
+ acc => <<>>})
after 5000 ->
?I("timeout when message queue: "
@@ -533,51 +575,51 @@ handler_maybe_activate(_, _, _) ->
%% ==========================================================================
-which_addr() ->
- case inet:getifaddrs() of
- {ok, IfAddrs} ->
- which_addrs(inet, IfAddrs);
- {error, Reason} ->
- exit({getifaddrs, Reason})
- end.
-
-which_addrs(_Family, []) ->
- exit({getifaddrs, not_found});
-which_addrs(Family, [{"lo", _} | IfAddrs]) ->
- %% Skip
- which_addrs(Family, IfAddrs);
-which_addrs(Family, [{"docker" ++ _, _} | IfAddrs]) ->
- %% Skip docker
- which_addrs(Family, IfAddrs);
-which_addrs(Family, [{"br-" ++ _, _} | IfAddrs]) ->
- %% Skip docker
- which_addrs(Family, IfAddrs);
-which_addrs(Family, [{"en" ++ _, IfOpts} | IfAddrs]) ->
- %% Maybe take this one
- case which_addr(Family, IfOpts) of
- {ok, Addr} ->
- Addr;
- error ->
- which_addrs(Family, IfAddrs)
- end;
-which_addrs(Family, [{_IfName, IfOpts} | IfAddrs]) ->
- case which_addr(Family, IfOpts) of
- {ok, Addr} ->
- Addr;
- error ->
- which_addrs(Family, IfAddrs)
- end.
-
-which_addr(_, []) ->
- error;
-which_addr(inet, [{addr, Addr}|_])
- when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
- {ok, Addr};
-which_addr(inet6, [{addr, Addr}|_])
- when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
- {ok, Addr};
-which_addr(Family, [_|IfOpts]) ->
- which_addr(Family, IfOpts).
+%% which_addr() ->
+%% case inet:getifaddrs() of
+%% {ok, IfAddrs} ->
+%% which_addrs(inet, IfAddrs);
+%% {error, Reason} ->
+%% exit({getifaddrs, Reason})
+%% end.
+
+%% which_addrs(_Family, []) ->
+%% exit({getifaddrs, not_found});
+%% which_addrs(Family, [{"lo", _} | IfAddrs]) ->
+%% %% Skip
+%% which_addrs(Family, IfAddrs);
+%% which_addrs(Family, [{"docker" ++ _, _} | IfAddrs]) ->
+%% %% Skip docker
+%% which_addrs(Family, IfAddrs);
+%% which_addrs(Family, [{"br-" ++ _, _} | IfAddrs]) ->
+%% %% Skip docker
+%% which_addrs(Family, IfAddrs);
+%% which_addrs(Family, [{"en" ++ _, IfOpts} | IfAddrs]) ->
+%% %% Maybe take this one
+%% case which_addr(Family, IfOpts) of
+%% {ok, Addr} ->
+%% Addr;
+%% error ->
+%% which_addrs(Family, IfAddrs)
+%% end;
+%% which_addrs(Family, [{_IfName, IfOpts} | IfAddrs]) ->
+%% case which_addr(Family, IfOpts) of
+%% {ok, Addr} ->
+%% Addr;
+%% error ->
+%% which_addrs(Family, IfAddrs)
+%% end.
+
+%% which_addr(_, []) ->
+%% error;
+%% which_addr(inet, [{addr, Addr}|_])
+%% when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
+%% {ok, Addr};
+%% which_addr(inet6, [{addr, Addr}|_])
+%% when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
+%% {ok, Addr};
+%% which_addr(Family, [_|IfOpts]) ->
+%% which_addr(Family, IfOpts).
%% ==========================================================================
diff --git a/erts/emulator/test/socket_test_ttest_tcp_server_gen.erl b/erts/emulator/test/socket_test_ttest_tcp_server_gen.erl
index b1b31f5158..fdf40f1369 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_server_gen.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_server_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,20 +21,18 @@
-module(socket_test_ttest_tcp_server_gen).
-export([
- start/1,
+ start/1, start/2,
stop/1
]).
-define(TRANSPORT_MOD, socket_test_ttest_tcp_gen).
+-define(MOD(D), {?TRANSPORT_MOD, #{domain => D}}).
start(Active) ->
- socket_test_ttest_tcp_server:start(?TRANSPORT_MOD, Active).
- %% {ok, {Pid, AddrPort}} ->
- %% MRef = erlang:monitor(process, Pid),
- %% {ok, {Pid, MRef, AddrPort}};
- %% {error, _} = ERROR ->
- %% ERROR
- %% end.
+ start(inet, Active).
+
+start(Domain, Active) ->
+ socket_test_ttest_tcp_server:start(?MOD(Domain), Active).
stop(Pid) ->
diff --git a/erts/emulator/test/socket_test_ttest_tcp_server_socket.erl b/erts/emulator/test/socket_test_ttest_tcp_server_socket.erl
index b7ea1e8e93..4045bf4e4e 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_server_socket.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_server_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,17 +21,20 @@
-module(socket_test_ttest_tcp_server_socket).
-export([
- start/2,
+ start/4,
stop/1
]).
-define(TRANSPORT_MOD, socket_test_ttest_tcp_socket).
-%% -define(MOD(M), {?TRANSPORT_MOD, #{method => M,
+%% -define(MOD(M), {?TRANSPORT_MOD, #{async => false,
+%% method => M,
%% stats_interval => 10000}}).
--define(MOD(M), {?TRANSPORT_MOD, #{method => M}}).
+-define(MOD(D,M,A), {?TRANSPORT_MOD, #{domain => D,
+ async => A,
+ method => M}}).
-start(Method, Active) ->
- socket_test_ttest_tcp_server:start(?MOD(Method), Active).
+start(Method, Domain, Async, Active) ->
+ socket_test_ttest_tcp_server:start(?MOD(Domain, Method, Async), Active).
%% {ok, {Pid, AddrPort}} ->
%% MRef = erlang:monitor(process, Pid),
%% {ok, {Pid, MRef, AddrPort}};
diff --git a/erts/emulator/test/socket_test_ttest_tcp_socket.erl b/erts/emulator/test/socket_test_ttest_tcp_socket.erl
index 0ae2412e4c..9112748b4c 100644
--- a/erts/emulator/test/socket_test_ttest_tcp_socket.erl
+++ b/erts/emulator/test/socket_test_ttest_tcp_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
accept/1, accept/2,
active/2,
close/1,
- connect/2, connect/3,
+ connect/1, connect/2, connect/3,
controlling_process/2,
listen/0, listen/1, listen/2,
port/1,
@@ -36,6 +36,8 @@
]).
+-define(LIB, socket_test_lib).
+
-define(READER_RECV_TIMEOUT, 1000).
-define(DATA_MSG(Sock, Method, Data),
@@ -55,7 +57,7 @@
%% ==========================================================================
-%% This does not really work. Its just a placeholder for the time beeing...
+%% This does not really work. Its just a placeholder for the time being...
%% getopt(Sock, Opt) when is_atom(Opt) ->
%% socket:getopt(Sock, socket, Opt).
@@ -66,22 +68,32 @@
%% ==========================================================================
-accept(#{sock := LSock, opts := #{method := Method} = Opts}) ->
+%% The way we use server async its no point in doing a async accept call
+%% (we do never actually run the test with more than one client).
+accept(#{sock := LSock, opts := #{async := Async,
+ method := Method} = Opts}) ->
case socket:accept(LSock) of
- {ok, Sock} ->
+ {ok, Sock} ->
Self = self(),
- Reader = spawn(fun() -> reader_init(Self, Sock, false, Method) end),
+ Reader = spawn(fun() ->
+ reader_init(Self, Sock, Async, false, Method)
+ end),
maybe_start_stats_timer(Opts, Reader),
{ok, #{sock => Sock, reader => Reader, method => Method}};
{error, _} = ERROR ->
ERROR
end.
-accept(#{sock := LSock, opts := #{method := Method} = Opts}, Timeout) ->
+%% If a timeout has been explictly specified, then we do not use
+%% async here. We will pass it on to the reader process.
+accept(#{sock := LSock, opts := #{async := Async,
+ method := Method} = Opts}, Timeout) ->
case socket:accept(LSock, Timeout) of
{ok, Sock} ->
Self = self(),
- Reader = spawn(fun() -> reader_init(Self, Sock, false, Method) end),
+ Reader = spawn(fun() ->
+ reader_init(Self, Sock, Async, false, Method)
+ end),
maybe_start_stats_timer(Opts, Reader),
{ok, #{sock => Sock, reader => Reader, method => Method}};
{error, _} = ERROR ->
@@ -97,41 +109,92 @@ active(#{reader := Pid}, NewActive)
close(#{sock := Sock, reader := Pid}) ->
Pid ! {?MODULE, stop},
- socket:close(Sock).
+ Unlink = case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ fun() -> os:cmd("unlink " ++ Path), ok end;
+ _ ->
+ fun() -> ok end
+ end,
+ Res = socket:close(Sock),
+ Unlink(),
+ Res.
%% Create a socket and connect it to a peer
-connect(Addr, Port) ->
- connect(Addr, Port, #{method => plain}).
-
-connect(Addr, Port, #{method := Method} = Opts) ->
+connect(ServerPath) when is_list(ServerPath) ->
+ Domain = local,
+ ClientPath = mk_unique_path(),
+ LocalSA = #{family => Domain,
+ path => ClientPath},
+ ServerSA = #{family => Domain, path => ServerPath},
+ Opts = #{domain => Domain,
+ proto => default,
+ method => plain},
+ Cleanup = fun() -> os:cmd("unlink " ++ ClientPath), ok end,
+ do_connect(LocalSA, ServerSA, Cleanup, Opts).
+
+connect(Addr, Port) when is_tuple(Addr) andalso is_integer(Port) ->
+ Domain = inet,
+ LocalSA = any,
+ ServerSA = #{family => Domain,
+ addr => Addr,
+ port => Port},
+ Opts = #{domain => Domain,
+ proto => tcp,
+ method => plain},
+ Cleanup = fun() -> ok end,
+ do_connect(LocalSA, ServerSA, Cleanup, Opts);
+connect(ServerPath,
+ #{domain := local = Domain} = Opts)
+ when is_list(ServerPath) ->
+ ClientPath = mk_unique_path(),
+ LocalSA = #{family => Domain,
+ path => ClientPath},
+ ServerSA = #{family => Domain,
+ path => ServerPath},
+ Cleanup = fun() -> os:cmd("unlink " ++ ClientPath), ok end,
+ do_connect(LocalSA, ServerSA, Cleanup, Opts#{proto => default}).
+
+connect(Addr, Port, #{domain := Domain} = Opts) ->
+ LocalSA = any,
+ ServerSA = #{family => Domain,
+ addr => Addr,
+ port => Port},
+ Cleanup = fun() -> ok end,
+ do_connect(LocalSA, ServerSA, Cleanup, Opts#{proto => tcp}).
+
+do_connect(LocalSA, ServerSA, Cleanup, #{domain := Domain,
+ proto := Proto,
+ async := Async,
+ method := Method} = Opts) ->
try
begin
Sock =
- case socket:open(inet, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, S} ->
S;
{error, OReason} ->
throw({error, {open, OReason}})
end,
- case socket:bind(Sock, any) of
+ case socket:bind(Sock, LocalSA) of
{ok, _} ->
ok;
{error, BReason} ->
(catch socket:close(Sock)),
+ Cleanup(),
throw({error, {bind, BReason}})
end,
- SA = #{family => inet,
- addr => Addr,
- port => Port},
- case socket:connect(Sock, SA) of
+ case socket:connect(Sock, ServerSA) of
ok ->
ok;
{error, CReason} ->
(catch socket:close(Sock)),
+ Cleanup(),
throw({error, {connect, CReason}})
end,
Self = self(),
- Reader = spawn(fun() -> reader_init(Self, Sock, false, Method) end),
+ Reader = spawn(fun() ->
+ reader_init(Self, Sock, Async, false, Method)
+ end),
maybe_start_stats_timer(Opts, Reader),
{ok, #{sock => Sock, reader => Reader, method => Method}}
end
@@ -140,6 +203,9 @@ connect(Addr, Port, #{method := Method} = Opts) ->
ERROR
end.
+mk_unique_path() ->
+ [NodeName | _] = string:tokens(atom_to_list(node()), [$@]),
+ ?LIB:f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]).
maybe_start_stats_timer(#{stats_to := Pid,
stats_interval := T},
@@ -163,37 +229,65 @@ controlling_process(#{sock := Sock, reader := Pid}, NewPid) ->
%% Create a listen socket
listen() ->
- listen(0, #{method => plain}).
+ listen(0).
+
+listen(Port) when is_integer(Port) ->
+ listen(Port, #{domain => inet, async => false, method => plain});
+listen(Path) when is_list(Path) ->
+ listen(Path, #{domain => local, async => false, method => plain}).
+
+listen(0, #{domain := local} = Opts) ->
+ listen(mk_unique_path(), Opts);
+listen(Path, #{domain := local = Domain} = Opts)
+ when is_list(Path) andalso (Path =/= []) ->
+ SA = #{family => Domain,
+ path => Path},
+ Cleanup = fun() -> os:cmd("unlink " ++ Path), ok end,
+ do_listen(SA, Cleanup, Opts#{proto => default});
+listen(Port, #{domain := Domain} = Opts)
+ when is_integer(Port) andalso (Port >= 0) ->
+ %% Bind fills in the rest
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, {_, _, Addr}} ->
+ SA = #{family => Domain,
+ addr => Addr,
+ port => Port},
+ Cleanup = fun() -> ok end,
+ do_listen(SA, Cleanup, Opts#{proto => tcp});
+ {error, _} = ERROR ->
+ ERROR
+ end.
-listen(Port) ->
- listen(Port, #{method => plain}).
-listen(Port, #{method := Method} = Opts)
- when (is_integer(Port) andalso (Port >= 0)) andalso
- ((Method =:= plain) orelse (Method =:= msg)) ->
+do_listen(SA,
+ Cleanup,
+ #{domain := Domain, proto := Proto,
+ async := Async, method := Method} = Opts)
+ when (Method =:= plain) orelse (Method =:= msg) andalso
+ is_boolean(Async) ->
try
begin
- Sock = case socket:open(inet, stream, tcp) of
+ Sock = case socket:open(Domain, stream, Proto) of
{ok, S} ->
S;
{error, OReason} ->
throw({error, {open, OReason}})
end,
- SA = #{family => inet,
- port => Port},
case socket:bind(Sock, SA) of
{ok, _} ->
ok;
{error, BReason} ->
(catch socket:close(Sock)),
+ Cleanup(),
throw({error, {bind, BReason}})
end,
case socket:listen(Sock) of
ok ->
- ok;
- {error, LReason} ->
+ ok;
+ {error, LReason} ->
(catch socket:close(Sock)),
- throw({error, {listen, LReason}})
- end,
+ Cleanup(),
+ throw({error, {listen, LReason}})
+ end,
{ok, #{sock => Sock, opts => Opts}}
end
catch
@@ -204,6 +298,8 @@ listen(Port, #{method := Method} = Opts)
port(#{sock := Sock}) ->
case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ {ok, Path};
{ok, #{port := Port}} ->
{ok, Port};
{error, _} = ERROR ->
@@ -213,6 +309,8 @@ port(#{sock := Sock}) ->
peername(#{sock := Sock}) ->
case socket:peername(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ {ok, Path};
{ok, #{addr := Addr, port := Port}} ->
{ok, {Addr, Port}};
{error, _} = ERROR ->
@@ -262,13 +360,18 @@ sockname(#{sock := Sock}) ->
%% ==========================================================================
-reader_init(ControllingProcess, Sock, Active, Method)
+reader_init(ControllingProcess, Sock, Async, Active, Method)
when is_pid(ControllingProcess) andalso
+ is_boolean(Async) andalso
(is_boolean(Active) orelse (Active =:= once)) andalso
((Method =:= plain) orelse (Method =:= msg)) ->
+ put(verbose, false),
MRef = erlang:monitor(process, ControllingProcess),
reader_loop(#{ctrl_proc => ControllingProcess,
ctrl_proc_mref => MRef,
+ async => Async,
+ select_info => undefined,
+ select_num => 0, % Count the number of select messages
active => Active,
sock => Sock,
method => Method}).
@@ -279,11 +382,11 @@ reader_loop(#{active := false,
ctrl_proc := Pid} = State) ->
receive
{?MODULE, stop} ->
- exit(normal);
+ reader_exit(State, stop);
{?MODULE, Pid, controlling_process, NewPid} ->
- MRef = maps:get(ctrl_proc_mref, State),
- erlang:demonitor(MRef, [flush]),
+ OldMRef = maps:get(ctrl_proc_mref, State),
+ erlang:demonitor(OldMRef, [flush]),
NewMRef = erlang:monitor(process, NewPid),
Pid ! {?MODULE, self(), controlling_process},
reader_loop(State#{ctrl_proc => NewPid,
@@ -294,10 +397,8 @@ reader_loop(#{active := false,
{'DOWN', MRef, process, Pid, Reason} ->
case maps:get(ctrl_proc_mref, State) of
- MRef when (Reason =:= normal) ->
- exit(normal);
MRef ->
- exit({controlling_process, Reason});
+ reader_exit(State, {ctrl_exit, Reason});
_ ->
reader_loop(State)
end
@@ -305,7 +406,8 @@ reader_loop(#{active := false,
%% Read *once* and then change to false
reader_loop(#{active := once,
- sock := Sock,
+ async := false,
+ sock := Sock,
method := Method,
ctrl_proc := Pid} = State) ->
case do_recv(Method, Sock) of
@@ -315,25 +417,23 @@ reader_loop(#{active := once,
{error, timeout} ->
receive
{?MODULE, stop} ->
- exit(normal);
+ reader_exit(State, stop);
{?MODULE, Pid, controlling_process, NewPid} ->
- MRef = maps:get(ctrl_proc_mref, State),
- erlang:demonitor(MRef, [flush]),
- MRef = erlang:monitor(process, NewPid),
+ OldMRef = maps:get(ctrl_proc_mref, State),
+ erlang:demonitor(OldMRef, [flush]),
+ NewMRef = erlang:monitor(process, NewPid),
Pid ! {?MODULE, self(), controlling_process},
reader_loop(State#{ctrl_proc => NewPid,
- ctrl_proc_mref => MRef});
+ ctrl_proc_mref => NewMRef});
{?MODULE, active, NewActive} ->
reader_loop(State#{active => NewActive});
{'DOWN', MRef, process, Pid, Reason} ->
case maps:get(ctrl_proc_mref, State) of
- MRef when (Reason =:= normal) ->
- exit(normal);
- MRef ->
- exit({controlling_process, Reason});
+ MRef ->
+ reader_exit(State, {ctrl_exit, Reason});
_ ->
reader_loop(State)
end
@@ -341,17 +441,86 @@ reader_loop(#{active := once,
reader_loop(State)
end;
- {error, closed} ->
+ {error, closed} = E1 ->
+ Pid ! ?CLOSED_MSG(Sock, Method),
+ reader_exit(State, E1);
+
+ {error, Reason} = E2 ->
+ Pid ! ?ERROR_MSG(Sock, Method, Reason),
+ reader_exit(State, E2)
+ end;
+reader_loop(#{active := once,
+ async := true,
+ select_info := undefined,
+ sock := Sock,
+ method := Method,
+ ctrl_proc := Pid} = State) ->
+ case do_recv(Method, Sock, nowait) of
+ {select, SelectInfo} ->
+ reader_loop(State#{select_info => SelectInfo});
+ {ok, Data} ->
+ Pid ! ?DATA_MSG(Sock, Method, Data),
+ reader_loop(State#{active => false});
+
+ {error, closed} = E1 ->
Pid ! ?CLOSED_MSG(Sock, Method),
- exit(normal);
+ reader_exit(State, E1);
- {error, Reason} ->
+ {error, Reason} = E2 ->
Pid ! ?ERROR_MSG(Sock, Method, Reason),
- exit(Reason)
+ reader_exit(State, E2)
+ end;
+reader_loop(#{active := once,
+ async := true,
+ select_info := {select_info, _, Ref},
+ select_num := N,
+ sock := Sock,
+ method := Method,
+ ctrl_proc := Pid} = State) ->
+ receive
+ {?MODULE, stop} ->
+ reader_exit(State, stop);
+
+ {?MODULE, Pid, controlling_process, NewPid} ->
+ OldMRef = maps:get(ctrl_proc_mref, State),
+ erlang:demonitor(OldMRef, [flush]),
+ NewMRef = erlang:monitor(process, NewPid),
+ Pid ! {?MODULE, self(), controlling_process},
+ reader_loop(State#{ctrl_proc => NewPid,
+ ctrl_proc_mref => NewMRef});
+
+ {?MODULE, active, NewActive} ->
+ reader_loop(State#{active => NewActive});
+
+ {'DOWN', MRef, process, Pid, Reason} ->
+ case maps:get(ctrl_proc_mref, State) of
+ MRef ->
+ reader_exit(State, {ctrl_exit, Reason});
+ _ ->
+ reader_loop(State)
+ end;
+
+ {'$socket', Sock, select, Ref} ->
+ case do_recv(Method, Sock, nowait) of
+ {ok, Data} when is_binary(Data) ->
+ Pid ! ?DATA_MSG(Sock, Method, Data),
+ reader_loop(State#{active => false,
+ select_info => undefined,
+ select_num => N+1});
+
+ {error, closed} = E1 ->
+ Pid ! ?CLOSED_MSG(Sock, Method),
+ reader_exit(State, E1);
+
+ {error, Reason} = E2 ->
+ Pid ! ?ERROR_MSG(Sock, Method, Reason),
+ reader_exit(State, E2)
+ end
end;
%% Read and forward data continuously
reader_loop(#{active := true,
+ async := false,
sock := Sock,
method := Method,
ctrl_proc := Pid} = State) ->
@@ -362,25 +531,23 @@ reader_loop(#{active := true,
{error, timeout} ->
receive
{?MODULE, stop} ->
- exit(normal);
+ reader_exit(State, stop);
{?MODULE, Pid, controlling_process, NewPid} ->
- MRef = maps:get(ctrl_proc_mref, State),
- erlang:demonitor(MRef, [flush]),
- MRef = erlang:monitor(process, NewPid),
+ OldMRef = maps:get(ctrl_proc_mref, State),
+ erlang:demonitor(OldMRef, [flush]),
+ NewMRef = erlang:monitor(process, NewPid),
Pid ! {?MODULE, self(), controlling_process},
reader_loop(State#{ctrl_proc => NewPid,
- ctrl_proc_mref => MRef});
+ ctrl_proc_mref => NewMRef});
{?MODULE, active, NewActive} ->
reader_loop(State#{active => NewActive});
{'DOWN', MRef, process, Pid, Reason} ->
case maps:get(ctrl_proc_mref, State) of
- MRef when (Reason =:= normal) ->
- exit(normal);
MRef ->
- exit({controlling_process, Reason});
+ reader_exit(State, {ctrl_exit, Reason});
_ ->
reader_loop(State)
end
@@ -388,27 +555,170 @@ reader_loop(#{active := true,
reader_loop(State)
end;
- {error, closed} ->
+ {error, closed} = E1 ->
Pid ! ?CLOSED_MSG(Sock, Method),
- exit(normal);
+ reader_exit(State, E1);
- {error, Reason} ->
+ {error, Reason} = E2 ->
Pid ! ?ERROR_MSG(Sock, Method, Reason),
- exit(Reason)
+ reader_exit(State, E2)
+ end;
+reader_loop(#{active := true,
+ async := true,
+ select_info := undefined,
+ sock := Sock,
+ method := Method,
+ ctrl_proc := Pid} = State) ->
+ case do_recv(Method, Sock) of
+ {select, SelectInfo} ->
+ reader_loop(State#{select_info => SelectInfo});
+ {ok, Data} ->
+ Pid ! ?DATA_MSG(Sock, Method, Data),
+ reader_loop(State);
+
+ {error, closed} = E1 ->
+ Pid ! ?CLOSED_MSG(Sock, Method),
+ reader_exit(State, E1);
+
+ {error, Reason} = E2 ->
+ Pid ! ?ERROR_MSG(Sock, Method, Reason),
+ reader_exit(State, E2)
+ end;
+reader_loop(#{active := true,
+ async := true,
+ select_info := {select_info, _, Ref},
+ select_num := N,
+ sock := Sock,
+ method := Method,
+ ctrl_proc := Pid} = State) ->
+ receive
+ {?MODULE, stop} ->
+ reader_exit(State, stop);
+
+ {?MODULE, Pid, controlling_process, NewPid} ->
+ OldMRef = maps:get(ctrl_proc_mref, State),
+ erlang:demonitor(OldMRef, [flush]),
+ NewMRef = erlang:monitor(process, NewPid),
+ Pid ! {?MODULE, self(), controlling_process},
+ reader_loop(State#{ctrl_proc => NewPid,
+ ctrl_proc_mref => NewMRef});
+
+ {?MODULE, active, NewActive} ->
+ reader_loop(State#{active => NewActive});
+
+ {'DOWN', MRef, process, Pid, Reason} ->
+ case maps:get(ctrl_proc_mref, State) of
+ MRef ->
+ reader_exit(State, {ctrl_exit, Reason});
+ _ ->
+ reader_loop(State)
+ end;
+
+ {'$socket', Sock, select, Ref} ->
+ case do_recv(Method, Sock, nowait) of
+ {ok, Data} when is_binary(Data) ->
+ Pid ! ?DATA_MSG(Sock, Method, Data),
+ reader_loop(State#{select_info => undefined,
+ select_num => N+1});
+
+ {error, closed} = E1 ->
+ Pid ! ?CLOSED_MSG(Sock, Method),
+ reader_exit(State, E1);
+
+ {error, Reason} = E2 ->
+ Pid ! ?ERROR_MSG(Sock, Method, Reason),
+ reader_exit(State, E2)
+ end
end.
-do_recv(plain, Sock) ->
- socket:recv(Sock, 0, ?READER_RECV_TIMEOUT);
-do_recv(msg, Sock) ->
- case socket:recvmsg(Sock, 0, 0, [], ?READER_RECV_TIMEOUT) of
+do_recv(Method, Sock) ->
+ do_recv(Method, Sock, ?READER_RECV_TIMEOUT).
+
+do_recv(plain, Sock, Timeout) ->
+ socket:recv(Sock, 0, Timeout);
+do_recv(msg, Sock, Timeout) ->
+ case socket:recvmsg(Sock, 0, 0, [], Timeout) of
{ok, #{iov := [Bin]}} ->
{ok, Bin};
+ {select, _} = SELECT ->
+ SELECT;
{error, _} = ERROR ->
ERROR
end.
-
-
+
+
+reader_exit(#{async := false, active := Active}, stop) ->
+ vp("reader stopped when active: ~w", [Active]),
+ exit(normal);
+reader_exit(#{async := true,
+ active := Active,
+ select_info := SelectInfo,
+ select_num := N}, stop) ->
+ vp("reader stopped when active: ~w"
+ "~n Current select info: ~p"
+ "~n Number of select messages: ~p", [Active, SelectInfo, N]),
+ exit(normal);
+reader_exit(#{async := false, active := Active}, {ctrl_exit, normal}) ->
+ vp("reader ctrl exit when active: ~w", [Active]),
+ exit(normal);
+reader_exit(#{async := true,
+ active := Active,
+ select_info := SelectInfo,
+ select_num := N}, {ctrl_exit, normal}) ->
+ vp("reader ctrl exit when active: ~w"
+ "~n Current select info: ~p"
+ "~n Number of select messages: ~p", [Active, SelectInfo, N]),
+ exit(normal);
+reader_exit(#{async := false, active := Active}, {ctrl_exit, Reason}) ->
+ vp("reader exit when ctrl crash when active: ~w", [Active]),
+ exit({controlling_process, Reason});
+reader_exit(#{async := true,
+ active := Active,
+ select_info := SelectInfo,
+ select_num := N}, {ctrl_exit, Reason}) ->
+ vp("reader exit when ctrl crash when active: ~w"
+ "~n Current select info: ~p"
+ "~n Number of select messages: ~p", [Active, SelectInfo, N]),
+ exit({controlling_process, Reason});
+reader_exit(#{async := false, active := Active}, {error, closed}) ->
+ vp("reader exit when socket closed when active: ~w", [Active]),
+ exit(normal);
+reader_exit(#{async := true,
+ active := Active,
+ select_info := SelectInfo,
+ select_num := N}, {error, closed}) ->
+ vp("reader exit when socket closed when active: ~w "
+ "~n Current select info: ~p"
+ "~n Number of select messages: ~p", [Active, SelectInfo, N]),
+ exit(normal);
+reader_exit(#{async := false, active := Active}, {error, Reason}) ->
+ vp("reader exit when socket error when active: ~w", [Active]),
+ exit(Reason);
+reader_exit(#{async := true,
+ active := Active,
+ select_info := SelectInfo,
+ select_num := N}, {error, Reason}) ->
+ vp("reader exit when socket error when active: ~w: "
+ "~n Current select info: ~p"
+ "~n Number of select messages: ~p", [Active, SelectInfo, N]),
+ exit(Reason).
+
+
+
+
+
%% ==========================================================================
+vp(F, A) ->
+ vp(get(verbose), F, A).
+
+vp(true, F, A) ->
+ p(F, A);
+vp(_, _, _) ->
+ ok.
+
+p(F, A) ->
+ io:format(F ++ "~n", A).
+
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index 55b1162cfb..b48be3dd04 100644
--- a/erts/emulator/test/system_info_SUITE.erl
+++ b/erts/emulator/test/system_info_SUITE.erl
@@ -37,10 +37,13 @@
-export([process_count/1, system_version/1, misc_smoke_tests/1,
heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1,
+ procs_bug/1,
ets_count/1, atom_count/1, system_logger/1]).
-export([init/1, handle_event/2, handle_call/2]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 2}}].
@@ -48,8 +51,20 @@ suite() ->
all() ->
[process_count, system_version, misc_smoke_tests,
ets_count, heap_size, wordsize, memory, ets_limit, atom_limit, atom_count,
+ procs_bug,
system_logger].
+
+init_per_testcase(procs_bug, Config) ->
+ procs_bug(init_per_testcase, Config);
+init_per_testcase(_, Config) ->
+ Config.
+
+end_per_testcase(procs_bug, Config) ->
+ procs_bug(end_per_testcase, Config);
+end_per_testcase(_, _) ->
+ ok.
+
%%%
%%% The test cases -------------------------------------------------------------
%%%
@@ -654,3 +669,41 @@ handle_call(Msg, State) ->
handle_event(Event, State) ->
State ! {report_handler, Event},
{ok, State}.
+
+
+%% OTP-15909: Provoke bug that would cause VM crash
+%% if doing system_info(procs) when process have queued exit/down signals.
+procs_bug(init_per_testcase, Config) ->
+ %% Use single scheduler and process prio to starve monitoring processes
+ %% from handling their received DOWN signals.
+ OldSchedOnline = erlang:system_flag(schedulers_online,1),
+ [{schedulers_online, OldSchedOnline} | Config];
+procs_bug(end_per_testcase, Config) ->
+ erlang:system_flag(schedulers_online,
+ proplists:get_value(schedulers_online, Config)),
+ ok.
+
+procs_bug(Config) when is_list(Config) ->
+ {Monee,_} = spawn_opt(fun () -> receive die -> ok end end,
+ [monitor,{priority,max}]),
+ Papa = self(),
+ Pids = [begin
+ P = spawn_opt(fun () ->
+ erlang:monitor(process, Monee),
+ Papa ! {self(),ready},
+ receive "nada" -> no end
+ end,
+ [link, {priority,normal}]),
+ {P, ready} = receive M -> M end,
+ P
+ end
+ || _ <- lists:seq(1,10)],
+ process_flag(priority,high),
+ Monee ! die,
+ {'DOWN',_,process,Monee,normal} = receive M -> M end,
+
+ %% This call did crash VM as Pids have pending DOWN signals.
+ erlang:system_info(procs),
+ process_flag(priority,normal),
+ [begin unlink(P), exit(P, kill) end || P <- Pids],
+ ok.
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 8203c46a39..477a501876 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -255,7 +255,9 @@ static char* key_val_name = ERLANG_VERSION; /* Used by the registry
* access functions.
*/
static char* boot_script = NULL; /* used by option -start_erl and -boot */
-static char* config_script = NULL; /* used by option -start_erl and -config */
+static char** config_scripts = NULL; /* used by option -start_erl and -config */
+static int config_script_cnt = 0;
+static int got_start_erl = 0;
static HANDLE this_module_handle;
static int run_werl;
@@ -392,6 +394,22 @@ add_extra_suffixes(char *prog)
}
#ifdef __WIN32__
+static void add_boot_config(void)
+{
+ int i;
+ if (boot_script)
+ add_args("-boot", boot_script, NULL);
+ for (i = 0; i < config_script_cnt; i++) {
+ add_args("-config", config_scripts[i], NULL);
+ }
+}
+# define ADD_BOOT_CONFIG add_boot_config()
+#else
+# define ADD_BOOT_CONFIG
+#endif
+
+
+#ifdef __WIN32__
__declspec(dllexport) int win_erlexec(int argc, char **argv, HANDLE module, int windowed)
#else
int main(int argc, char **argv)
@@ -581,16 +599,6 @@ int main(int argc, char **argv)
i = 1;
-#ifdef __WIN32__
-#define ADD_BOOT_CONFIG \
- if (boot_script) \
- add_args("-boot", boot_script, NULL); \
- if (config_script) \
- add_args("-config", config_script, NULL);
-#else
-#define ADD_BOOT_CONFIG
-#endif
-
get_home();
add_args("-home", home, NULL);
@@ -610,7 +618,9 @@ int main(int argc, char **argv)
case 'b':
if (strcmp(argv[i], "-boot") == 0) {
if (boot_script)
- error("Conflicting -start_erl and -boot options");
+ error("Conflicting -boot options");
+ if (got_start_erl)
+ error("Conflicting -start_erl and -boot options");
if (i+1 >= argc)
usage("-boot");
boot_script = strsave(argv[i+1]);
@@ -634,11 +644,14 @@ int main(int argc, char **argv)
}
#ifdef __WIN32__
else if (strcmp(argv[i], "-config") == 0){
- if (config_script)
+ if (got_start_erl)
error("Conflicting -start_erl and -config options");
if (i+1 >= argc)
usage("-config");
- config_script = strsave(argv[i+1]);
+ config_script_cnt++;
+ config_scripts = erealloc(config_scripts,
+ config_script_cnt * sizeof(char*));
+ config_scripts[config_script_cnt-1] = strsave(argv[i+1]);
i++;
}
#endif
@@ -1371,6 +1384,7 @@ strsave(char* string)
static void get_start_erl_data(char *file)
{
+ static char* a_config_script;
int fp;
char tmpbuffer[512];
char start_erl_data[512];
@@ -1381,7 +1395,7 @@ static void get_start_erl_data(char *file)
char* tprogname;
if (boot_script)
error("Conflicting -start_erl and -boot options");
- if (config_script)
+ if (config_scripts)
error("Conflicting -start_erl and -config options");
env = get_env("RELDIR");
if (env)
@@ -1431,10 +1445,13 @@ static void get_start_erl_data(char *file)
erts_snprintf(progname,strlen(tprogname) + 20,"%s -start_erl",tprogname);
boot_script = emalloc(512);
- config_script = emalloc(512);
+ a_config_script = emalloc(512);
erts_snprintf(boot_script, 512, "%s/%s/start", reldir, otpstring);
- erts_snprintf(config_script, 512, "%s/%s/sys", reldir, otpstring);
+ erts_snprintf(a_config_script, 512, "%s/%s/sys", reldir, otpstring);
+ config_scripts = &a_config_script;
+ config_script_cnt = 1;
+ got_start_erl = 1;
}
@@ -1673,9 +1690,9 @@ static char **build_args_from_string(char *string)
for(;;) {
switch (state) {
case Start:
- if (!*p)
+ if (!*p)
goto done;
- if (argc >= alloced - 1) { /* Make room for extra NULL */
+ if (argc >= alloced - 2) { /* Make room for extra NULL and "--" */
argv = erealloc(argv, (alloced += 10) * sizeof(char *));
}
cur_s = argc + argv;
@@ -1764,11 +1781,14 @@ static char **build_args_from_string(char *string)
}
}
done:
- argv[argc] = NULL; /* Sure to be large enough */
if (!argc) {
efree(argv);
return NULL;
}
+ argv[argc++] = "--"; /* Add a -- separator in order
+ for different from different environments
+ to effect each other */
+ argv[argc++] = NULL; /* Sure to be large enough */
return argv;
#undef ENSURE
}
@@ -2019,11 +2039,13 @@ initial_argv_massage(int *argc, char ***argv)
argv_buf ab = {0}, xab = {0};
int ix, vix, ac;
char **av;
+ char *sep = "--";
struct {
int argc;
char **argv;
} avv[] = {{INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL},
- {INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL}};
+ {INT_MAX, NULL}, {INT_MAX, NULL},
+ {INT_MAX, NULL}, {INT_MAX, NULL}};
/*
* The environment flag containing OTP release is intentionally
* undocumented and intended for OTP internal use only.
@@ -2043,6 +2065,8 @@ initial_argv_massage(int *argc, char ***argv)
if (*argc > 1) {
avv[vix].argc = *argc - 1;
avv[vix++].argv = &(*argv)[1];
+ avv[vix].argc = 1;
+ avv[vix++].argv = &sep;
}
av = build_args_from_env("ERL_FLAGS");
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 8cfc2d549e..59de9bdec8 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -292,25 +292,38 @@ if [ "x$GDB" = "x" ]; then
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log"
fi
fi
- if [ "x$VALGRIND_MISC_FLAGS" = "x" ]; then
- valgrind_misc_flags=
- else
- valgrind_misc_flags="$VALGRIND_MISC_FLAGS"
+ # Add default flags
+ vgflags=$VALGRIND_MISC_FLAGS
+ if [ "x${vgflags#*--show-possibly-lost}" = "x$vgflags" ]; then
+ vgflags="$vgflags --show-possibly-lost=no"
+ fi
+ if [ "x${vgflags#*--child-silent-after-fork}" = "x$vgflags" ]; then
+ vgflags="$vgflags --child-silent-after-fork=yes"
+ fi
+ if [ "x${vgflags#*--suppressions}" = "x$vgflags" ]; then
+ if [ "x$ERL_TOP" != "x" ]; then
+ vgflags="$vgflags --suppressions=$ERL_TOP/erts/emulator/valgrind/suppress.standard"
+ else
+ echo "No valgrind suppression file found in \$VALGRIND_MISC_FLAGS and \$ERL_TOP not set."
+ fi
fi
if which taskset > /dev/null && test -e /proc/cpuinfo; then
# We only let valgrind utilize one core with "taskset 1" as it can be very slow
# on multiple cores (especially with async threads). Valgrind only run one pthread
# at a time anyway so there is no point letting it utilize more than one core.
# Use $sched_arg to force all schedulers online to emulate multicore.
- taskset1="taskset 1"
ncpu=`cat /proc/cpuinfo | grep -w processor | wc -l`
+ # Choose a random core in order to not collide with any other valgrind
+ # run on the same machine.
+ taskset1=$((1 << (`shuf -i 1-$ncpu -n 1` - 1) ))
+ taskset1="taskset $taskset1"
sched_arg="-S$ncpu:$ncpu"
else
taskset1=
sched_arg=
fi
- exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@"
+ exec $taskset1 valgrind $valgrind_xml $valgrind_log $vgflags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@"
elif [ $run_rr = yes ]; then
if [ $1 = replay ]; then
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 66d6d20c4e..20809d61e8 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -37,7 +37,7 @@ document etp-help
% - GDB command toolbox for analyzing core dumps from the
% Erlang emulator (BEAM).
%
-% Should work for 32-bit erts-5.2/R9B, ...
+% Should work for 32-bit and 64-bit unix gdb
%
% The commands are prefixed with:
% etp: Acronym for erts-term-print
@@ -55,7 +55,8 @@ document etp-help
% Special commands for not really terms:
% etp-mfa, etp-cp, etp-disasm,
% etp-msgq, etpf-msgq,
-% etp-stacktrace, etp-stackdump, etpf-stackdump, etp-dictdump
+% etp-stacktrace, etp-stacktrace-emu, etp-stackdump, etp-stackdump-emu,
+% etpf-stackdump, etp-dictdump
% etp-process-info, etp-process-memory-info
% etp-port-info, etp-port-state, etp-port-sched-flags
% etp-heapdump, etp-offheapdump, etpf-offheapdump,
@@ -132,14 +133,14 @@ define etp-1
if (($arg0) & 0x3) == 1
# Cons pointer
if $etp_flat
- printf "<etpf-cons %#x>", ($arg0)
+ printf "<etpf-cons %p>", (($arg0)-1)
else
etp-list-1 ($arg0) ($arg1)
end
else
if (($arg0) & 0x3) == 2
if $etp_flat
- printf "<etpf-boxed %#x>", ($arg0)
+ printf "<etpf-boxed %p>", (($arg0)-2)
else
etp-boxed-1 ($arg0) ($arg1)
end
@@ -187,7 +188,7 @@ define etp-list-1
# Reentrant
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
if $etp_chart
@@ -210,7 +211,7 @@ define etp-list-printable-1
# Returns: $etp_list_printable
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Loop to check if it is a printable string
set $etp_list_p = ($arg0)
@@ -272,7 +273,7 @@ define etp-list-2
# Reentrant
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
if ($arg1) >= $etp_max_depth
@@ -307,7 +308,7 @@ define etpf-cons
# Reentrant capable
#
if ((Eterm)($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
set $etp_flat = 1
@@ -336,13 +337,13 @@ define etp-boxed-1
# Reentrant
#
if (($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", ($arg0)
+ printf "#NotBoxed<%p>", ($arg0)
else
if (((Eterm*)(($arg0) & ~0x3))[0] & 0x3) != 0x0
if $etp_chart
etp-chart-entry-1 (($arg0)&~0x3) ($arg1) 1
end
- printf "#BoxedError<%#x>", ($arg0)
+ printf "#BoxedError<%p>", ($arg0)
else
if $etp_chart
etp-chart-entry-1 (($arg0)&~0x3) ($arg1) \
@@ -390,10 +391,10 @@ define etp-boxed-immediate-1
# Non-reentrant
#
if (($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", ($arg0)
+ printf "#NotBoxed<%p>", ($arg0)
else
if (((Eterm*)(($arg0) & ~0x3))[0] & 0x3) != 0x0
- printf "#BoxedError<%#x>", ($arg0)
+ printf "#BoxedError<%p>", ($arg0)
else
set $etp_boxed_immediate_p = (Eterm*)(($arg0) & ~0x3)
set $etp_boxed_immediate_h = ($etp_boxed_immediate_p[0] >> 2) & 0xF
@@ -438,12 +439,12 @@ define etp-boxed-immediate-1
while $etp_boxed_immediate_arity > 0
set $etp_boxed_immediate_p++
if $etp_boxed_immediate_arity > 1
- printf "%#x,", *$etp_boxed_immediate_p
+ printf "%p,", *$etp_boxed_immediate_p
else
- printf "%#x", *$etp_boxed_immediate_p
+ printf "%p", *$etp_boxed_immediate_p
if ($etp_boxed_immediate_h == 0xA)
set $etp_boxed_immediate_p++
- printf ":%#x", *$etp_boxed_immediate_p
+ printf ":%p", *$etp_boxed_immediate_p
end
printf ">"
end
@@ -558,7 +559,7 @@ define etp-immediate-1
# Reentrant capable
#
if (($arg0) & 0x3) != 0x3
- printf "#NotImmediate<%#x>", ($arg0)
+ printf "#NotImmediate<%p>", ($arg0)
else
if (($arg0) & 0xF) == 0x3
etp-pid-1 ($arg0)
@@ -580,7 +581,7 @@ define etp-immediate-1
if (($arg0) == $etp_nil)
printf "[]"
else
- printf "#UnknownImmediate<%#x>", ($arg0)
+ printf "#UnknownImmediate<%p>", ($arg0)
end
end
end
@@ -598,7 +599,7 @@ define etp-atom-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3f) != 0xb
- printf "#NotAtom<%#x>", ($arg0)
+ printf "#NotAtom<%p>", ($arg0)
else
set $etp_atom_1_ap = (Atom*)erts_atom_table.seg_table[(Eterm)($arg0)>>16][((Eterm)($arg0)>>6)&0x3FF]
set $etp_atom_1_i = ($etp_atom_1_ap)->len
@@ -652,7 +653,7 @@ define etp-char-1
# Non-reentrant
#
if (($arg0) < 0) || (0377 < ($arg0))
- printf "#NotChar<%#x>", ($arg0)
+ printf "#NotChar<%p>", ($arg0)
else
if ($arg0) == ($arg1)
printf "\\%c", ($arg0)
@@ -787,7 +788,7 @@ define etp-pid-1
# Internal pid
printf "<0.%u.%u>", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
else
- printf "#NotPid<%#x>", ($arg0)
+ printf "#NotPid<%p>", ($arg0)
end
end
@@ -797,11 +798,11 @@ define etp-extpid-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extpid_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extpid_1_p->header & 0x3f) != 0x30
- printf "#NotExternalPid<%#x>", $etp_extpid_1_p->header
+ printf "#NotExternalPid<%p>", $etp_extpid_1_p->header
else
## External pid
set $etp_extpid_1_number = $etp_extpid_1_p->data.ui[0]&0x7fff
@@ -812,7 +813,7 @@ define etp-extpid-1
set $etp_extpid_1_node = $etp_extpid_1_np->sysname
if ($etp_extpid_1_node & 0x3f) != 0xb
# Should be an atom
- printf "#ExternalPidError<%#x>", ($arg0)
+ printf "#ExternalPidError<%p>", ($arg0)
else
if $etp_extpid_1_dep == erts_this_dist_entry
printf "<0:"
@@ -847,7 +848,7 @@ define etp-port-1
# Internal port
printf "#Port<0.%u>", $etp_port_data
else
- printf "#NotPort<%#x>", ($arg0)
+ printf "#NotPort<%p>", ($arg0)
end
end
@@ -857,11 +858,11 @@ define etp-extport-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extport_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extport_1_p->header & 0x3F) != 0x34
- printf "#NotExternalPort<%#x>", $etp_extport_1->header
+ printf "#NotExternalPort<%p>", $etp_extport_1->header
else
## External port
set $etp_extport_1_number = $etp_extport_1_p->data.ui[0]&0x3ffff
@@ -871,7 +872,7 @@ define etp-extport-1
set $etp_extport_1_node = $etp_extport_1_np->sysname
if ($etp_extport_1_node & 0x3f) != 0xb
# Should be an atom
- printf "#ExternalPortError<%#x>", ($arg0)
+ printf "#ExternalPortError<%p>", ($arg0)
else
if $etp_extport_1_dep == erts_this_dist_entry
printf "#Port<0:"
@@ -893,15 +894,15 @@ define etp-bignum-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_bignum_1_p = (Eterm*)((Eterm)($arg0) & ~0x3)
if ($etp_bignum_1_p[0] & 0x3b) != 0x08
- printf "#NotBignum<%#x>", $etp_bignum_1_p[0]
+ printf "#NotBignum<%p>", $etp_bignum_1_p[0]
else
set $etp_bignum_1_i = ($etp_bignum_1_p[0] >> 6)
if $etp_bignum_1_i < 1
- printf "#BignumError<%#x>", (Eterm)($arg0)
+ printf "#BignumError<%p>", (Eterm)($arg0)
else
if $etp_bignum_1_p[0] & 0x04
printf "-"
@@ -932,11 +933,11 @@ define etp-float-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_float_1_p = (Eterm*)((Eterm)($arg0) & ~0x3)
if ($etp_float_1_p[0] & 0x3f) != 0x18
- printf "#NotFloat<%#x>", $etp_float_1_p[0]
+ printf "#NotFloat<%p>", $etp_float_1_p[0]
else
printf "%f", *(double*)($etp_float_1_p+1)
end
@@ -951,14 +952,14 @@ define etp-ref-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_ref_1_p = (ErtsORefThing *)((Eterm)($arg0) & ~0x3)
if ($etp_ref_1_p->header & 0x3b) != 0x10
- printf "#NotRef<%#x>", $etp_ref_1_p->header
+ printf "#NotRef<%p>", $etp_ref_1_p->header
else
if $etp_ref_1_p->header != etp_ref_header && $etp_ref_1_p->header != etp_magic_ref_header
- printf "#InternalRefError<%#x>", ($arg0)
+ printf "#InternalRefError<%p>", ($arg0)
else
set $etp_magic_ref = 0
set $etp_ref_1_i = 3
@@ -998,11 +999,11 @@ define etp-extref-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extref_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extref_1_p->header & 0x3F) != 0x38
- printf "#NotExternalRef<%#x>", $etp_extref_1->header
+ printf "#NotExternalRef<%p>", $etp_extref_1->header
else
## External ref
set $etp_extref_1_nump = (Uint32 *) 0
@@ -1041,7 +1042,7 @@ define etp-extref-1
end
end
if $etp_extref_1_error
- printf "#ExternalRefError<%#x>", ($arg0)
+ printf "#ExternalRefError<%p>", ($arg0)
else
set $etp_extref_1_i--
while $etp_extref_1_i >= 0
@@ -1166,7 +1167,7 @@ define etp-cp-1
if *(Eterm*)($etp_cp) == beam_return_to_trace[0]
printf "#Cp<return to trace>"
else
- printf "#Cp<%#x>", $etp_cp
+ printf "#Cp<%p>", $etp_cp
end
end
end
@@ -1452,30 +1453,74 @@ end
define etp-stack-preamble
set $etp_stack_p = ($arg0)->stop
set $etp_stack_end = ($arg0)->hend
+ if ($arg0)->state.counter & 0x8000
+ printf "%%%%%% WARNING: The process is currently running, so c_p->stop will not be correct\r\n"
+ printf "%%%%%% Consider using %s-emu instead\r\n", $arg1
+ end
printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p
if ($arg0)->i != 0
- etp-1 ((Eterm)($arg0)->i) 0
- printf " (I)\n"
+ printf "I: "
+ etp ((Eterm)($arg0)->i)
+ end
+ if ($arg0)->cp != 0
+ printf "cp:"
+ etp ((Eterm)($arg0)->cp)
end
+end
+
+define etp-stack-preamble-emu
+ set $etp_stack_p = E
+ set $etp_stack_end = ($arg0)->hend
+ printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p
+ printf "I: "
+ etp ((BeamInstr)I)
if ($arg0)->cp != 0
- etp-1 ((Eterm)($arg0)->cp) 0
- printf " (cp)\n"
+ printf "cp: "
+ etp ((Eterm)($arg0)->cp)
+ end
+end
+
+define etp-stacktrace-1
+ set $etp_stack_stop = (Eterm*)($arg0)
+ set $etp_stack_send = (Eterm*)($arg1)
+ set $etp_stack_cnt = 0
+ while $etp_stack_stop < $etp_stack_send
+ if ($etp_stack_stop[0] & 0x3) == 0x0
+ # Continuation pointer
+ printf "%d: ", $etp_stack_cnt
+ etp $etp_stack_stop[0]
+ end
+ set $etp_stack_stop++
+ set $etp_stack_cnt++
end
end
+define etp-stacktrace-emu
+# Args: Process*
+#
+# Non-reentrant
+#
+ etp-stack-preamble-emu ($arg0)
+ etp-stacktrace-1 $etp_stack_p $etp_stack_end
+end
+
+document etp-stacktrace-emu
+%---------------------------------------------------------------------------
+% etp-stacktrace-emu Process*
+%
+% Take an Process* and print a stactrace for the process.
+% This macro assumes that the current frame is the process_main frame
+% and that E is not optimized out.
+%---------------------------------------------------------------------------
+end
+
define etp-stacktrace
# Args: Process*
#
# Non-reentrant
#
- etp-stack-preamble ($arg0)
- while $etp_stack_p < $etp_stack_end
- if ($etp_stack_p[0] & 0x3) == 0x0
- # Continuation pointer
- etp $etp_stack_p[0]
- end
- set $etp_stack_p++
- end
+ etp-stack-preamble ($arg0) "etp-stacktrace"
+ etp-stacktrace-1 $etp_stack_p $etp_stack_end
end
document etp-stacktrace
@@ -1488,16 +1533,48 @@ document etp-stacktrace
%---------------------------------------------------------------------------
end
+define etp-stackdump-1
+ # Args: Eterm *stop, Eterm *hend
+ #
+ # Non-reentrant
+ #
+ set $etp_stackdump_stop = (Eterm*)($arg0)
+ set $etp_stackdump_send = (Eterm*)($arg1)
+ set $etp_stackdump_cnt = 0
+ while $etp_stackdump_stop < $etp_stackdump_send
+ printf "%d: ", $etp_stackdump_cnt
+ etp $etp_stackdump_stop[0]
+ set $etp_stackdump_stop++
+ set $etp_stackdump_cnt++
+ end
+end
+
+define etp-stackdump-emu
+# Args: Process*
+#
+# Non-reentrant
+#
+ etp-stack-preamble-emu ($arg0)
+ etp-stackdump-1 $etp_stack_p $etp_stack_end
+end
+
+document etp-stacktrace-emu
+%---------------------------------------------------------------------------
+% etp-stacktrace-emu Process*
+%
+% Take an Process* and print a stactdump for the process.
+% This macro assumes that the current frame is the process_main frame
+% and that E is not optimized out.
+%---------------------------------------------------------------------------
+end
+
define etp-stackdump
# Args: Process*
#
# Non-reentrant
#
- etp-stack-preamble ($arg0)
- while $etp_stack_p < $etp_stack_end
- etp $etp_stack_p[0]
- set $etp_stack_p++
- end
+ etp-stack-preamble ($arg0) "etp-stackdump"
+ etp-stackdump-1 $etp_stack_p $etp_stack_end
end
document etp-stackdump
@@ -1743,7 +1820,7 @@ define etp-term-dump-pid
# Internal pid
printf "| <0.%04u.%03u> ", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
else
- printf "| #NotPid<%#x> ", ($arg0)
+ printf "| #NotPid<%p> ", ($arg0)
end
end
@@ -2959,12 +3036,21 @@ define etp-fds
end
end
+document etp-fds
+%---------------------------------------------------------------------------
+% etp-fds
+%
+% Print the state of the fds currently in check_io. Only works in running systems.
+%---------------------------------------------------------------------------
+end
+
define etp-disasm-1
- set $code_ptr = ((BeamInstr*)$arg0)
- set $addr = *$code_ptr
+ set $code_ptr = ((BeamInstr*)($arg0))
+ set $addr32 = (BeamInstr)(Uint32)*$code_ptr
+ set $addr64 = (BeamInstr)(Uint64)*$code_ptr
set $i = 0
- while $i < (sizeof(opc) / sizeof(OpEntry))
- if $addr == beam_ops[$i]
+ while $i < num_instructions
+ if $addr32 == beam_ops[$i] || $addr64 == beam_ops[$i]
printf "%s %d", opc[$i].name, opc[$i].sz
set $next_i = $code_ptr + opc[$i].sz
set $i += 4999
@@ -2974,6 +3060,11 @@ define etp-disasm-1
end
define etp-disasm
+ if $argc == 1
+ set $code_end = $arg0
+ else
+ set $code_end = $arg1
+ end
etp-cp-func-info-1 $arg0
if $etp_cp_p == 0
printf "invalid argument"
@@ -2982,7 +3073,7 @@ define etp-disasm
printf ": "
etp-disasm-1 $arg0
printf "\r\n"
- while $next_i < ((BeamInstr*)$arg1)
+ while $next_i < ((BeamInstr*)$code_end)
set $prev_i = $next_i
etp-cp-func-info-1 $next_i
etp-mfa-1 $etp_cp_p $cp_cp_p_offset
@@ -2998,6 +3089,16 @@ define etp-disasm
end
end
+document etp-disasm
+%---------------------------------------------------------------------------
+% etp-fds BeamInstr* (BeamInstr*)
+%
+% Disassemble the instructions inbetween arg0 and arg1,
+% if no second argument is given only the current
+% instruction is printed.
+%---------------------------------------------------------------------------
+end
+
############################################################################
#
# Timer Wheel
@@ -3324,7 +3425,7 @@ define etp-offheapdump
set $etp_offheapdump_p = $etp_offheapdump_p->next
set $etp_offheapdump_i++
else
- printf "#TaggedPtr<%#x>", $etp_offheapdump_p
+ printf "#TaggedPtr<%p>", $etp_offheapdump_p
set $etp_offheapdump_p = 0
end
end
@@ -3363,12 +3464,12 @@ define etp-search-heaps
#
# Non-reentrant
#
- printf "%% Search all (<%u) process heaps for ", erts_max_processes
+ printf "%% Search all (<%u) process heaps for ", erts_proc.r.o.max
set $etp_flat = 1
etp-1 ($arg0) 0
set $etp_flat = 0
printf ":...\n"
- etp-search-heaps-1 ((Eterm*)((Eterm)($arg0)&~3))
+ etp-search-heaps-1 ((Eterm*)((Eterm)($arg0)&~(Eterm)3))
end
define etp-search-heaps-1
@@ -3376,8 +3477,8 @@ define etp-search-heaps-1
#
# Non-reentrant
#
- set $etp_search_heaps_q = erts_max_processes / 10
- set $etp_search_heaps_r = erts_max_processes % 10
+ set $etp_search_heaps_q = erts_proc.r.o.max / 10
+ set $etp_search_heaps_r = erts_proc.r.o.max % 10
set $etp_search_heaps_t = 10
set $etp_search_heaps_m = $etp_search_heaps_q
if $etp_search_heaps_r > 0
@@ -3387,7 +3488,7 @@ define etp-search-heaps-1
set $etp_search_heaps_i = 0
set $etp_search_heaps_found = 0
while $etp_search_heaps_i < erts_proc.r.o.max
- set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$proc_ix])
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$etp_search_heaps_i])
if $proc
if ($proc->heap <= ($arg0)) && \
(($arg0) < $proc->hend)
@@ -3404,7 +3505,7 @@ define etp-search-heaps-1
while $etp_search_heaps_p && ($etp_search_heaps_cnt < $etp_max_depth)
set $etp_search_heaps_cnt++
if (&($etp_search_heaps_p->mem) <= ($arg0)) && \
- (($arg0) < &($etp_search_heaps_p->mem)+$etp_search_heaps_p->size)
+ (($arg0) < &($etp_search_heaps_p->mem)+$etp_search_heaps_p->used_size)
printf "process_tab[%d]->mbuf(%d)+%d\n", \
$etp_search_heaps_i, $etp_search_heaps_cnt, \
($arg0)-&($etp_search_heaps_p->mem)
@@ -3700,8 +3801,8 @@ define etp-overlapped-heaps
# Non-reentrant
#
printf "%% Dumping heap addresses to \"etp-commands.bin\"\n"
- set $etp_overlapped_heaps_q = erts_max_processes / 10
- set $etp_overlapped_heaps_r = erts_max_processes % 10
+ set $etp_overlapped_heaps_q = erts_proc.r.o.max / 10
+ set $etp_overlapped_heaps_r = erts_proc.r.o.max % 10
set $etp_overlapped_heaps_t = 10
set $etp_overlapped_heaps_m = $etp_overlapped_heaps_q
if $etp_overlapped_heaps_r > 0
@@ -3727,7 +3828,7 @@ define etp-overlapped-heaps
append binary value etp-commands.bin 'p'
append binary value etp-commands.bin 's'
append binary value etp-commands.bin '\0'
- while $etp_overlapped_heaps_i < erts_max_processes
+ while $etp_overlapped_heaps_i < erts_proc.r.o.max
if process_tab[$etp_overlapped_heaps_i]
append binary value etp-commands.bin \
(Eterm)$etp_overlapped_heaps_i
@@ -3868,7 +3969,7 @@ define etp-chart-entry-1
append binary value etp-commands.bin (Eterm)(($arg2)*sizeof(Eterm))
append binary value etp-commands.bin (Eterm)$etp_chart_id
append binary value etp-commands.bin (Eterm)($arg1)
-# printf "<dumped %#x %lu %lu %lu>", ($arg0)&~0x3, \
+# printf "<dumped %p %lu %lu %lu>", ($arg0)&~0x3, \
# (Eterm)(($arg2)*sizeof(Eterm)), (Eterm)$etp_chart_id, (Eterm)($arg1)
end
@@ -3892,22 +3993,79 @@ end
# ETS table debug
#
+define etp-ets-tab-status-int
+# Args:
+#
+# Non-reentrant
+ if ($arg0 & 0x1)
+ printf "priv"
+ end
+ if ($arg0 & 0x2)
+ printf "prot"
+ end
+ if ($arg0 & 0x4)
+ printf "pub"
+ end
+ if ($arg0 & 0x8)
+ printf "|del"
+ end
+ if ($arg0 & 0x10)
+ printf "|set"
+ end
+ if ($arg0 & 0x20)
+ printf "|bag"
+ end
+ if ($arg0 & 0x40)
+ printf "|dbag"
+ end
+ if ($arg0 & 0x80)
+ printf "|oset"
+ end
+ if ($arg0 & 0x100)
+ printf "|caoset"
+ end
+ if ($arg0 & 0x200)
+ printf "|flocked"
+ end
+ if ($arg0 & 0x400)
+ printf "|fread"
+ end
+ if ($arg0 & 0x800)
+ printf "|named"
+ end
+ if ($arg0 & 0x1000)
+ printf "|busy"
+ end
+end
+
define etp-ets-tables
# Args:
#
# Non-reentrant
- printf "%% Dumping < %lu ETS tables\n", (unsigned long)db_max_tabs
- while $etp_ets_tables_i < db_max_tabs
- if (meta_main_tab[$etp_ets_tables_i].u.next_free & 3) == 0
- printf "%% %d:", $etp_ets_tables_i
- etp-1 ((Eterm)(meta_main_tab[$etp_ets_tables_i].u.tb->common.id)) 0
+ set $sched_ix = 0
+ while $sched_ix < erts_no_schedulers
+ set $ets_tabs = &erts_aligned_scheduler_data[$sched_ix].esd.ets_tables
+ set $no_ets_tabs = *(unsigned long *)&($ets_tabs->count)
+ printf "\n%% %lu ETS tables created on scheduler %lu...\n\n", $no_ets_tabs, (unsigned long)$sched_ix+1
+ set $ets_tab = $ets_tabs->clist
+ set $first_ets_tab = $ets_tab
+ while $ets_tab
+ set $refn = &((ErtsMagicBinary *)$ets_tab->common->btid)->refn
+ printf "%% "
+ etp-1 $ets_tab->common.the_name 0
+ printf " #Ref<0.%u.%u.%u> ", (unsigned)$refn[2], (unsigned)$refn[1], (unsigned)$refn[0]
+ etp-1 $ets_tab->common.owner 0
printf " "
- etp-1 ((Eterm)(meta_main_tab[$etp_ets_tables_i].u.tb->common.owner)) 0
- printf "\n"
+ etp-ets-tab-status-int $ets_tab->common.status
+ printf " (DbTable*)%p\n", $ets_tab
+ if $ets_tab->common.all.next == $first_ets_tab
+ set $ets_tab = (DbTable *) 0
+ else
+ set $ets_tab = $ets_tab->common.all.next
+ end
end
- set $etp_ets_tables_i++
+ set $sched_ix++
end
- set $etp_ets_tables_i = 0
end
document etp-ets-tables
diff --git a/erts/etc/unix/gcov-gen-html b/erts/etc/unix/gcov-gen-html
new file mode 100755
index 0000000000..3fd9f1ca49
--- /dev/null
+++ b/erts/etc/unix/gcov-gen-html
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+@ARGV == 2 or die "Usage: gcov-gen-html \$ERL_TOP <output directory>\n";
+
+my $srcdir = shift @ARGV;
+my $outdir = shift @ARGV;
+
+my $verbose = 1;
+my $flavor = "smp";
+
+# setup filenames and paths, observe geninfos --base-directory
+# it needs a correct path just after the $geninfo
+
+my $lcov_path = ""; #/usr/local/bin/";
+
+my $geninfo = $lcov_path . "geninfo --no-checksum --base-directory";
+my $genhtml = $lcov_path . "genhtml";
+
+# src paths
+
+my $emu_src_path = "$srcdir/erts/emulator";
+my $elib_src_path = "$srcdir/erts/lib_src";
+my $pcre_src_path = "$emu_src_path";
+my $zlib_src_path = "$emu_src_path";
+
+# obj paths
+
+my $emu_obj_path = <$emu_src_path/obj/*-linux-*/gcov/$flavor>;
+my $elib_obj_path = <$elib_src_path/obj/*-linux-*/gcov>;
+my $pcre_obj_path = <$emu_src_path/pcre/obj/*-linux-*/gcov>;
+my $zlib_obj_path = <$emu_src_path/zlib/obj/*-linux-*/gcov>;
+
+# info files
+
+my $emu_info = "$srcdir/emulator-cover.info";
+my $elib_info = "$srcdir/elib-cover.info";
+my $pcre_info = "$srcdir/pcre-cover.info";
+
+my $infofiles = "$emu_info $elib_info $pcre_info";
+
+run("$geninfo $emu_src_path -o $emu_info $emu_obj_path");
+run("$geninfo $elib_src_path -o $elib_info $elib_obj_path");
+run("$geninfo $pcre_src_path -o $pcre_info $pcre_obj_path");
+
+if (<$zlib_obj_path/*.o>) {
+ my $zlib_info = "$srcdir/zlib-cover.info";
+ $infofiles .= " $zlib_info";
+ run("$geninfo $zlib_src_path -o $zlib_info $zlib_obj_path");
+}
+
+run("$genhtml -o $outdir $infofiles");
+
+
+
+sub run {
+ my $cmd = shift;
+ print STDERR "\nrun($cmd)\n" if $verbose > 0;
+ system("$cmd 2>&1") == 0 or die "\nCan't run \"$cmd\": $?";
+}
diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh
index 2b0482e876..71af14b9b2 100644
--- a/erts/etc/win32/msys_tools/vc/cc.sh
+++ b/erts/etc/win32/msys_tools/vc/cc.sh
@@ -195,7 +195,6 @@ mkdir $TMPOBJDIR
# Compile
for x in $SOURCES; do
- start_time=`date '+%s'`
# Compile each source
if [ $LINKING = false ]; then
# We should have an output defined, which is a directory
@@ -260,16 +259,28 @@ for x in $SOURCES; do
else
tail -n +2 $ERR_FILE >&2
if test $DEPENDENCIES = true; then
- if test `grep -v $x $MSG_FILE | grep -c '#line'` != "0"; then
- o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'`
- echo -n $o':'
-# cat $MSG_FILE | grep '#line' | grep -v $x | awk -F\" '{printf("%s\n",$2)}' | sort -u | grep -v " " | xargs -n 1 win2msys_path.sh | awk '{printf("\\\n %s ",$0)}'
- cat $MSG_FILE | grep '#line' | grep -v $x | awk -F\" '{printf("%s\n",$2)}' | sort -u | grep -v " " | sed 's,^\([A-Za-z]\):[\\/]*,/\1/,;s,\\\\*,/,g'| awk '{printf("\\\n %s ",$0)}'
- echo
- echo
- after_sed=`date '+%s'`
- echo Made dependencies for $x':' `expr $after_sed '-' $start_time` 's' >&2
- fi
+ perl -e '
+my $file = "'$x'";
+while (<>) {
+ next unless /^#line/;
+ next if /$file/o;
+ (undef,$_) = split(/\"/);
+ next if / /;
+ $all{$_} = 1;
+}
+foreach (sort keys %all) {
+ s@^([A-Za-z]):@/$1@;
+ s@\\\\@/@g;
+ push @f, "\\\n $_ ";
+}
+if (@f) {
+ my $oname = $file;
+ $oname =~ s@.*/@@;
+ $oname =~ s@[.]cp*@.o@;
+ print $oname, ":", @f;
+ print "\n\n";
+ print STDERR "Made dependencies for $file\n";
+}' $MSG_FILE
else
cat $MSG_FILE
fi
diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c
index b4b12fcd86..b567ed81b0 100644
--- a/erts/lib_src/pthread/ethread.c
+++ b/erts/lib_src/pthread/ethread.c
@@ -208,9 +208,9 @@ ethr_x86_cpuid__(int *eax, int *ebx, int *ecx, int *edx)
"popl %%eax\n\t"
"movl $0x0, %0\n\t"
"xorl %%ecx, %%eax\n\t"
- "jz no_cpuid\n\t"
+ "jz 1f\n\t"
"movl $0x1, %0\n\t"
- "no_cpuid:\n\t"
+ "1:\n\t"
: "=r"(have_cpuid)
:
: "%eax", "%ecx", "cc");
diff --git a/erts/preloaded/ebin/atomics.beam b/erts/preloaded/ebin/atomics.beam
index ef402b5fee..c74ce3ce2d 100644
--- a/erts/preloaded/ebin/atomics.beam
+++ b/erts/preloaded/ebin/atomics.beam
Binary files differ
diff --git a/erts/preloaded/ebin/counters.beam b/erts/preloaded/ebin/counters.beam
index 674d0d27fa..2aec433bcb 100644
--- a/erts/preloaded/ebin/counters.beam
+++ b/erts/preloaded/ebin/counters.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam
index 0313988e3e..bc7639781c 100644
--- a/erts/preloaded/ebin/erl_init.beam
+++ b/erts/preloaded/ebin/erl_init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 661bcd8413..13fdd7908b 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index ec4d6153d1..16e17b870b 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 62dc8702e7..866f9df79f 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index 669149df82..d81bc08282 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
index 6d3528c2dc..a8d492dfa5 100644
--- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index b3af713809..dd08111aad 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index fc2bf6f6bd..0f7dd6efbe 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 1d89174b25..942f29a11c 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/net.beam b/erts/preloaded/ebin/net.beam
deleted file mode 100644
index f61b2b4a69..0000000000
--- a/erts/preloaded/ebin/net.beam
+++ /dev/null
Binary files differ
diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam
index c882e4fad4..7871b64991 100644
--- a/erts/preloaded/ebin/persistent_term.beam
+++ b/erts/preloaded/ebin/persistent_term.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam
index cf671bf8f4..90d9596fe6 100644
--- a/erts/preloaded/ebin/prim_buffer.beam
+++ b/erts/preloaded/ebin/prim_buffer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 24911123f9..19935eeee3 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 0efd954e50..a2c5f2f336 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index ff9268ad38..f77e9e863d 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_net.beam b/erts/preloaded/ebin/prim_net.beam
new file mode 100644
index 0000000000..9d50b3210f
--- /dev/null
+++ b/erts/preloaded/ebin/prim_net.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index d319d7a343..bd51c3b271 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 558a886565..73a0bd4f72 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 9610c94ac2..8b7c5fe2ef 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 27d450c873..38b85915cc 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -36,10 +36,9 @@ include $(ERL_TOP)/lib/kernel/vsn.mk
ifeq ($(USE_ESOCK), yes)
PRE_LOADED_ERL_ESOCK_MODULES = \
socket \
- net
+ prim_net
else
-PRE_LOADED_ERL_ESOCK_MODULES = \
- net
+PRE_LOADED_ERL_ESOCK_MODULES =
endif
PRE_LOADED_ERL_MODULES = \
@@ -82,9 +81,9 @@ APP_FILE= erts.app
APP_SRC= $(APP_FILE).src
APP_TARGET= $(STATIC_EBIN)/$(APP_FILE)
ifeq ($(USE_ESOCK), yes)
-APP_ESOCK_MODS= net, socket
+APP_ESOCK_MODS= prim_net, socket
else
-APP_ESOCK_MODS= net
+APP_ESOCK_MODS=
endif
@@ -96,6 +95,15 @@ ERL_COMPILE_FLAGS += +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE)
DIA_PLT = erts-preloaded.plt
DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis
+ifeq ($(DIAW_EH),true)
+DIA_WARNINGS += -Werror_handling
+endif
+ifeq ($(DIAW_US),true)
+DIA_WARNINGS += -Wunderspecs
+endif
+ifeq ($(DIAW_UR),true)
+DIA_WARNINGS += -Wunmatched_returns
+endif
debug opt: $(TARGET_FILES)
@@ -145,6 +153,7 @@ dialyzer: $(DIA_PLT)
@echo "Running dialyzer on $(basename $(DIA_PLT))"
@dialyzer --plt $< \
../ebin \
+ $(DIA_WARNINGS) \
--verbose
#
diff --git a/erts/preloaded/src/erl_init.erl b/erts/preloaded/src/erl_init.erl
index d209c4033b..dadf7dda6f 100644
--- a/erts/preloaded/src/erl_init.erl
+++ b/erts/preloaded/src/erl_init.erl
@@ -35,7 +35,8 @@ start(Mod, BootArgs) ->
erl_tracer:on_load(),
prim_buffer:on_load(),
prim_file:on_load(),
- conditional_load(socket, [socket, net]), % socket:on_load(), net:on_load(),
+ %% socket:on_load(), prim_net:on_load(),
+ conditional_load(socket, [socket, prim_net]),
%% Proceed to the specified boot module
run(Mod, boot, BootArgs).
@@ -49,7 +50,9 @@ run(M, F, A) ->
end.
conditional_load(CondMod, Mods2Load) ->
- conditional_load(CondMod, erlang:loaded(), Mods2Load).
+ Loaded = erlang:loaded(),
+ %% erlang:display({?MODULE, conditional_load, Loaded}),
+ conditional_load(CondMod, Loaded, Mods2Load).
conditional_load(_CondMod, [], _Mods2LOad) ->
ok;
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index ac73946dc0..06f0ee1dc6 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -3361,7 +3361,7 @@ dist_ctrl_get_opt(_DHandle, _Opt) ->
DHandle :: dist_handle(),
InputPackets :: non_neg_integer(),
OutputPackets :: non_neg_integer(),
- PendingOutputPackets :: boolean(),
+ PendingOutputPackets :: non_neg_integer(),
Res :: {'ok', InputPackets, OutputPackets, PendingOutputPackets}.
dist_get_stat(_DHandle) ->
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index d5abdd2483..4dab3de006 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -427,7 +427,7 @@ accept_opts(L, S, FamilyOpts) ->
case
getopts(
L,
- [active, nodelay, keepalive, delay_send, priority]
+ [active, nodelay, keepalive, delay_send, priority, linger]
++ FamilyOpts)
of
{ok, Opts} ->
@@ -553,34 +553,49 @@ send(S, Data) ->
%% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
%% is known to be connected.
-sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
- case type_value(set, addr, Addr) of
- true ->
- ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
- try
- erlang:port_command(S, [enc_value(set, addr, Addr),Data])
- of
- true ->
- receive
- {inet_reply,S,Reply} ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> ~p~n", [Reply]),
- Reply
- end
- catch
- error:_ ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end;
- false ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end;
-sendto(S, IP, Port, Data) ->
- sendto(S, {IP, Port}, 0, Data).
-
+sendto(S, {_, _} = Address, AncOpts, Data)
+ when is_port(S), is_list(AncOpts) ->
+ case encode_opt_val(AncOpts) of
+ {ok, AncData} ->
+ AncDataLen = iolist_size(AncData),
+ case
+ type_value(set, addr, Address) andalso
+ type_value(set, uint32, AncDataLen)
+ of
+ true ->
+ ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p, ~p)~n",
+ [S,Address,AncOpts,Data]),
+ PortCommandData =
+ [enc_value(set, addr, Address),
+ enc_value(set, uint32, AncDataLen), AncData,
+ Data],
+ try erlang:port_command(S, PortCommandData) of
+ true ->
+ receive
+ {inet_reply,S,Reply} ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> ~p~n", [Reply]),
+ Reply
+ end
+ catch
+ _:_ ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+ false ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+ {error,_} ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+sendto(S, IP, Port, Data)
+ when is_port(S), is_integer(Port) ->
+ sendto(S, {IP, Port}, [], Data).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -1993,15 +2008,15 @@ enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) ->
[?INET_AF_LOCAL,iolist_size(File)|File];
%%
enc_value_2(addr, {inet,{any,Port}}) ->
- [?INET_AF_INET,?int16(Port),0,0,0,0];
+ [?INET_AF_INET,?int16(Port)|ip4_to_bytes({0,0,0,0})];
enc_value_2(addr, {inet,{loopback,Port}}) ->
- [?INET_AF_INET,?int16(Port),127,0,0,1];
+ [?INET_AF_INET,?int16(Port)|ip4_to_bytes({127,0,0,1})];
enc_value_2(addr, {inet,{IP,Port}}) ->
[?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
enc_value_2(addr, {inet6,{any,Port}}) ->
- [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0];
+ [?INET_AF_INET6,?int16(Port)|ip6_to_bytes({0,0,0,0,0,0,0,0})];
enc_value_2(addr, {inet6,{loopback,Port}}) ->
- [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1];
+ [?INET_AF_INET6,?int16(Port)|ip6_to_bytes({0,0,0,0,0,0,0,1})];
enc_value_2(addr, {inet6,{IP,Port}}) ->
[?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
enc_value_2(addr, {local,Addr}) ->
@@ -2149,10 +2164,10 @@ enum_name(_, []) -> false.
%% encode opt/val REVERSED since options are stored in reverse order
%% i.e. the recent options first (we must process old -> new)
encode_opt_val(Opts) ->
- try
- enc_opt_val(Opts, [])
+ try
+ {ok, enc_opt_val(Opts, [])}
catch
- Reason -> {error,Reason}
+ throw:Reason -> {error,Reason}
end.
%% {active, once} and {active, N} are specially optimized because they will
@@ -2171,17 +2186,21 @@ enc_opt_val([binary|Opts], Acc) ->
enc_opt_val(Opts, Acc, mode, binary);
enc_opt_val([list|Opts], Acc) ->
enc_opt_val(Opts, Acc, mode, list);
-enc_opt_val([_|_], _) -> {error,einval};
-enc_opt_val([], Acc) -> {ok,Acc}.
+enc_opt_val([_|_], _) ->
+ throw(einval);
+enc_opt_val([], Acc) ->
+ Acc.
enc_opt_val(Opts, Acc, Opt, Val) when is_atom(Opt) ->
Type = type_opt(set, Opt),
case type_value(set, Type, Val) of
true ->
enc_opt_val(Opts, [enc_opt(Opt),enc_value(set, Type, Val)|Acc]);
- false -> {error,einval}
+ false ->
+ throw(einval)
end;
-enc_opt_val(_, _, _, _) -> {error,einval}.
+enc_opt_val(_, _, _, _) ->
+ throw(einval).
diff --git a/erts/preloaded/src/net.erl b/erts/preloaded/src/prim_net.erl
index 13d2e3a117..107043d1aa 100644
--- a/erts/preloaded/src/net.erl
+++ b/erts/preloaded/src/prim_net.erl
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
--module(net).
+-module(prim_net).
-compile(no_native).
@@ -31,22 +31,14 @@
-export([
gethostname/0,
- getnameinfo/1, getnameinfo/2,
- getaddrinfo/1, getaddrinfo/2,
+ getnameinfo/2,
+ getaddrinfo/2,
if_name2index/1,
if_index2name/1,
if_names/0
]).
-%% Deprecated functions from the "old" net module
--export([call/4,
- cast/4,
- broadcast/3,
- ping/1,
- relay/1,
- sleep/1]).
-
-export_type([
address_info/0,
name_info/0,
@@ -59,13 +51,6 @@
network_interface_index/0
]).
--deprecated({call, 4, eventually}).
--deprecated({cast, 4, eventually}).
--deprecated({broadcast, 3, eventually}).
--deprecated({ping, 1, eventually}).
--deprecated({relay, 1, eventually}).
--deprecated({sleep, 1, eventually}).
-
-type name_info_flags() :: [name_info_flag()|name_info_flag_ext()].
-type name_info_flag() :: namereqd |
@@ -88,21 +73,6 @@
%% ===========================================================================
%%
-%% D E P R E C A T E D F U N C T I O N S
-%%
-%% ===========================================================================
-
-call(N,M,F,A) -> rpc:call(N,M,F,A).
-cast(N,M,F,A) -> rpc:cast(N,M,F,A).
-broadcast(M,F,A) -> rpc:eval_everywhere(M,F,A).
-ping(Node) -> net_adm:ping(Node).
-sleep(T) -> receive after T -> ok end.
-relay(X) -> slave:relay(X).
-
-
-
-%% ===========================================================================
-%%
%% Administrative and utility API
%%
%% ===========================================================================
@@ -117,7 +87,7 @@ on_load() ->
Extra :: map().
on_load(Extra) ->
- ok = erlang:load_nif(atom_to_list(?MODULE), Extra).
+ ok = erlang:load_nif(atom_to_list(net), Extra).
-spec info() -> list().
@@ -159,14 +129,6 @@ gethostname() ->
%%
%%
--spec getnameinfo(SockAddr) -> {ok, Info} | {error, Reason} when
- SockAddr :: socket:sockaddr(),
- Info :: name_info(),
- Reason :: term().
-
-getnameinfo(SockAddr) ->
- getnameinfo(SockAddr, undefined).
-
-spec getnameinfo(SockAddr, Flags) -> {ok, Info} | {error, Reason} when
SockAddr :: socket:sockaddr(),
Flags :: name_info_flags() | undefined,
@@ -178,44 +140,18 @@ getnameinfo(SockAddr, [] = _Flags) ->
getnameinfo(#{family := Fam, addr := _Addr} = SockAddr, Flags)
when ((Fam =:= inet) orelse (Fam =:= inet6)) andalso
(is_list(Flags) orelse (Flags =:= undefined)) ->
- nif_getnameinfo((catch ensure_sockaddr(SockAddr)), Flags);
+ nif_getnameinfo(socket:ensure_sockaddr(SockAddr), Flags);
getnameinfo(#{family := Fam, path := _Path} = SockAddr, Flags)
when (Fam =:= local) andalso (is_list(Flags) orelse (Flags =:= undefined)) ->
nif_getnameinfo(SockAddr, Flags).
-%% This function is intended to "handle" the case when the user
-%% has built their (OTP) system with "--disable-esock".
-%% That means the socket module does not exist. This is not really
-%% a problem since the nif_getnameinfo won't work either (since
-%% the nif file is not part of the system). The result of calling
-%% getnameinfo will be a undef exception (erlang:nif_error(undef)).
-%%
-%% The only functions in this module that actually work in this case
-%% (--disable-esock) is the depricated stuff (call, cast, ...).
-%%
-ensure_sockaddr(SockAddr) ->
- try socket:ensure_sockaddr(SockAddr)
- catch
- error:undef:_ ->
- undefined
- end.
-
%% ===========================================================================
%%
%% getaddrinfo - Network address and service translation
%%
%% There is also a "hint" argument that we "at some point" should implement.
--spec getaddrinfo(Host) -> {ok, Info} | {error, Reason} when
- Host :: string(),
- Info :: [address_info()],
- Reason :: term().
-
-getaddrinfo(Host) when is_list(Host) ->
- getaddrinfo(Host, undefined).
-
-
-spec getaddrinfo(Host, undefined) -> {ok, Info} | {error, Reason} when
Host :: string(),
Info :: [address_info()],
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 126db66cdd..07e720c44d 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -26,9 +26,13 @@
%% Administrative and "global" utility functions
-export([
on_load/0, on_load/1,
- info/0,
- supports/0, supports/1, supports/2, supports/3,
- ensure_sockaddr/1
+
+ ensure_sockaddr/1,
+
+ debug/1,
+ %% command/1,
+ info/0, info/1,
+ supports/0, supports/1, supports/2, supports/3
]).
-export([
@@ -53,10 +57,22 @@
getopt/3,
sockname/1,
- peername/1
+ peername/1,
+
+ cancel/2
]).
-export_type([
+ select_tag/0,
+ select_ref/0,
+ select_info/0,
+
+ socket_counters/0,
+ socket_counter/0,
+ socket_info/0,
+
+ %% command/0,
+
domain/0,
type/0,
protocol/0,
@@ -129,6 +145,27 @@
]).
+%% The command type has the general form:
+%% #{
+%% command := atom(),
+%% data := term()
+%% }
+%% But only certain values are actually valid, so the type gets the form:
+-type debug_command() :: #{
+ command := debug,
+ data := boolean()
+ }.
+%% -type command() :: debug_command().
+
+-type socket_counters() :: [{socket_counter(), non_neg_integer()}].
+-type socket_counter() :: read_byte | read_fails | read_pkg | read_tries |
+ read_waits | write_byte | write_fails | write_pkg |
+ write_tries | write_waits.
+-type socket_info() :: #{counters := socket_counters(),
+ num_readers := non_neg_integer(),
+ num_writers := non_neg_integer(),
+ num_acceptors := non_neg_integer()}.
+
-type uint8() :: 0..16#FF.
-type uint16() :: 0..16#FFFF.
-type uint20() :: 0..16#FFFFF.
@@ -276,7 +313,8 @@
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
port := port_number(),
- addr := any | loopback | ip4_address()}.
+ %% The 'broadcast' here is the "limited broadcast"
+ addr := any | broadcast | loopback | ip4_address()}.
-type sockaddr_in6() :: #{family := inet6,
port := port_number(),
addr := any | loopback | ip6_address(),
@@ -297,7 +335,7 @@
-define(SOCKADDR_IN6_DEFAULTS, ?SOCKADDR_IN6_DEFAULTS(any)).
-define(SOCKADDR_IN6_DEFAULT(A), (?SOCKADDR_IN6_DEFAULTS(A))#{family => inet6}).
-%% otp - The option is internal to our (OTP) imeplementation.
+%% otp - This option is internal to our (OTP) implementation.
%% socket - The socket layer (SOL_SOCKET).
%% ip - The IP layer (SOL_IP or is it IPPROTO_IP?).
%% ipv6 - The IPv6 layer (SOL_IPV6).
@@ -305,6 +343,7 @@
%% udp - The UDP (User Datagram Protocol) layer (IPPROTO_UDP).
%% sctp - The SCTP (Stream Control Transmission Protocol) layer (IPPROTO_SCTP).
%% Int - Raw level, sent down and used "as is".
+%% Its up to the caller to make sure this is correct!
-type sockopt_level() :: otp |
socket |
ip | ipv6 | tcp | udp | sctp |
@@ -585,6 +624,17 @@
#{level := integer(), type := integer(), data := binary()}.
+-opaque select_tag() :: atom().
+-opaque select_ref() :: reference().
+
+%% -record(select_info, {tag :: select_tag(), ref :: select_ref()}).
+
+-type select_info() :: {select_info, select_tag(), select_ref()}.
+
+-define(SELECT_INFO(T, R), {select_info, T, R}).
+-define(SELECT(T, R), {select, ?SELECT_INFO(T, R)}).
+
+
%% This is used in messages sent from the nif-code to erlang processes:
%%
%% {?SOCKET_TAG, Socket :: socket(), Tag :: atom(), Info :: term()}
@@ -602,12 +652,13 @@
%% -define(SOCKET_TYPE_RDM, 4).
-define(SOCKET_TYPE_SEQPACKET, 5).
--define(SOCKET_PROTOCOL_IP, 1).
--define(SOCKET_PROTOCOL_TCP, 2).
--define(SOCKET_PROTOCOL_UDP, 3).
--define(SOCKET_PROTOCOL_SCTP, 4).
--define(SOCKET_PROTOCOL_ICMP, 5).
--define(SOCKET_PROTOCOL_IGMP, 6).
+-define(SOCKET_PROTOCOL_DEFAULT, 0).
+-define(SOCKET_PROTOCOL_IP, 1).
+-define(SOCKET_PROTOCOL_TCP, 2).
+-define(SOCKET_PROTOCOL_UDP, 3).
+-define(SOCKET_PROTOCOL_SCTP, 4).
+-define(SOCKET_PROTOCOL_ICMP, 5).
+-define(SOCKET_PROTOCOL_IGMP, 6).
-define(SOCKET_LISTEN_BACKLOG_DEFAULT, 5).
@@ -820,6 +871,7 @@
-define(SOCKET_SUPPORTS_OPTIONS, 16#0001).
-define(SOCKET_SUPPORTS_SCTP, 16#0002).
-define(SOCKET_SUPPORTS_IPV6, 16#0003).
+-define(SOCKET_SUPPORTS_LOCAL, 16#0004).
%% ===========================================================================
@@ -842,12 +894,46 @@ on_load(Extra) ->
--spec info() -> list().
+-spec info() -> map().
info() ->
nif_info().
+-spec debug(D) -> ok when
+ D :: boolean().
+
+debug(D) when is_boolean(D) ->
+ command(#{command => debug,
+ data => D}).
+
+
+-spec command(Command) -> ok when
+ Command :: debug_command().
+
+command(#{command := debug,
+ data := Dbg} = Command) when is_boolean(Dbg) ->
+ nif_command(Command).
+
+
+
+%% ===========================================================================
+%%
+%% info - Get miscellaneous information about a socket.
+%%
+%% Generates a list of various info about the socket, such as counter values.
+%%
+%% Do *not* call this function often.
+%%
+%% ===========================================================================
+
+-spec info(Socket) -> socket_info() when
+ Socket :: socket().
+
+info(#socket{ref = SockRef}) ->
+ nif_info(SockRef).
+
+
%% ===========================================================================
%%
@@ -875,18 +961,21 @@ info() ->
-spec supports() -> [{options, supports_options()} |
{sctp, boolean()} |
- {ipv6, boolean()}].
+ {ipv6, boolean()} |
+ {local, boolean()}].
supports() ->
[{options, supports(options)},
{sctp, supports(sctp)},
- {ipv6, supports(ipv6)}].
+ {ipv6, supports(ipv6)},
+ {local, supports(local)}].
-dialyzer({nowarn_function, supports/1}).
-spec supports(options) -> supports_options();
(sctp) -> boolean();
(ipv6) -> boolean();
+ (local) -> boolean();
(Key1) -> false when
Key1 :: term().
@@ -896,6 +985,8 @@ supports(sctp) ->
nif_supports(?SOCKET_SUPPORTS_SCTP);
supports(ipv6) ->
nif_supports(?SOCKET_SUPPORTS_IPV6);
+supports(local) ->
+ nif_supports(?SOCKET_SUPPORTS_LOCAL);
supports(_Key1) ->
false.
@@ -1006,12 +1097,12 @@ supports(_Key1, _Key2, _Key3) ->
Reason :: term().
open(Domain, Type) ->
- open(Domain, Type, null).
+ open(Domain, Type, default).
-spec open(Domain, Type, Protocol) -> {ok, Socket} | {error, Reason} when
Domain :: domain(),
Type :: type(),
- Protocol :: null | protocol(),
+ Protocol :: default | protocol(),
Socket :: socket(),
Reason :: term().
@@ -1021,15 +1112,14 @@ open(Domain, Type, Protocol) ->
-spec open(Domain, Type, Protocol, Extra) -> {ok, Socket} | {error, Reason} when
Domain :: domain(),
Type :: type(),
- Protocol :: null | protocol(),
+ Protocol :: default | protocol(),
Extra :: map(),
Socket :: socket(),
Reason :: term().
-open(Domain, Type, Protocol0, Extra) when is_map(Extra) ->
+open(Domain, Type, Protocol, Extra) when is_map(Extra) ->
try
begin
- Protocol = default_protocol(Protocol0, Type),
EDomain = enc_domain(Domain),
EType = enc_type(Domain, Type),
EProtocol = enc_protocol(Type, Protocol),
@@ -1052,34 +1142,31 @@ open(Domain, Type, Protocol0, Extra) when is_map(Extra) ->
{error, Reason}
end.
-%% Note that this is just a convenience function for when the protocol was
-%% not specified. If its actually specified, then that will be selected.
-%% Also, this only works for the some of the type's (stream, dgram and
-%% seqpacket).
-default_protocol(null, stream) -> tcp;
-default_protocol(null, dgram) -> udp;
-default_protocol(null, seqpacket) -> sctp;
-default_protocol(null, Type) -> throw({error, {no_default_protocol, Type}});
-default_protocol(Protocol, _) -> Protocol.
%% ===========================================================================
%%
%% bind - bind a name to a socket
%%
+%% Note that Addr can only have the value of broadcast *if* Domain =:= inet!
+%%
-spec bind(Socket, Addr) -> ok | {error, Reason} when
Socket :: socket(),
- Addr :: any | loopback | sockaddr(),
+ Addr :: any | broadcast | loopback | sockaddr(),
Reason :: term().
bind(#socket{ref = SockRef}, Addr)
- when ((Addr =:= any) orelse (Addr =:= loopback)) ->
+ when ((Addr =:= any) orelse
+ (Addr =:= broadcast) orelse
+ (Addr =:= loopback)) ->
try which_domain(SockRef) of
inet ->
nif_bind(SockRef, ?SOCKADDR_IN4_DEFAULT(Addr));
- inet6 ->
- nif_bind(SockRef, ?SOCKADDR_IN6_DEFAULT(Addr))
+ inet6 when (Addr =:= any) orelse (Addr =:= loopback) ->
+ nif_bind(SockRef, ?SOCKADDR_IN6_DEFAULT(Addr));
+ _ ->
+ einval()
catch
%% <WIN32-TEMPORARY>
error:notsup:S ->
@@ -1192,18 +1279,24 @@ validate_inet6_addrs(Addrs) ->
%%
-spec connect(Socket, SockAddr) -> ok | {error, Reason} when
- Socket :: socket(),
- SockAddr :: sockaddr(),
- Reason :: term().
+ Socket :: socket(),
+ SockAddr :: sockaddr(),
+ Reason :: term().
connect(Socket, SockAddr) ->
connect(Socket, SockAddr, infinity).
--spec connect(Socket, SockAddr, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- SockAddr :: sockaddr(),
- Timeout :: timeout(),
- Reason :: term().
+-spec connect(Socket, SockAddr, nowait) ->
+ ok | {select, SelectInfo} | {error, Reason} when
+ Socket :: socket(),
+ SockAddr :: sockaddr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, SockAddr, Timeout) -> ok | {error, Reason} when
+ Socket :: socket(),
+ SockAddr :: sockaddr(),
+ Timeout :: timeout(),
+ Reason :: term().
%% <KOLLA>
%% Is it possible to connect with family = local for the (dest) sockaddr?
@@ -1213,12 +1306,18 @@ connect(_Socket, _SockAddr, Timeout)
{error, timeout};
connect(#socket{ref = SockRef}, #{family := Fam} = SockAddr, Timeout)
when ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso
- ((Timeout =:= infinity) orelse is_integer(Timeout)) ->
+ ((Timeout =:= nowait) orelse
+ (Timeout =:= infinity) orelse is_integer(Timeout)) ->
TS = timestamp(Timeout),
- case nif_connect(SockRef, SockAddr) of
+ case nif_connect(SockRef, ensure_sockaddr(SockAddr)) of
ok ->
%% Connected!
ok;
+
+ {ok, Ref} when (Timeout =:= nowait) ->
+ %% Connecting, but the caller does not want to wait...
+ ?SELECT(connect, Ref);
+
{ok, Ref} ->
%% Connecting...
NewTimeout = next_timeout(TS, Timeout),
@@ -1271,17 +1370,27 @@ listen(#socket{ref = SockRef}, Backlog)
accept(Socket) ->
accept(Socket, ?SOCKET_ACCEPT_TIMEOUT_DEFAULT).
--spec accept(LSocket, Timeout) -> {ok, Socket} | {error, Reason} when
- LSocket :: socket(),
- Timeout :: timeout(),
- Socket :: socket(),
- Reason :: term().
+-spec accept(LSocket, nowait) ->
+ {ok, Socket} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ LSocket :: socket(),
+ Socket :: socket(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (LSocket, Timeout) -> {ok, Socket} | {error, Reason} when
+ LSocket :: socket(),
+ Timeout :: timeout(),
+ Socket :: socket(),
+ Reason :: term().
%% Do we really need this optimization?
accept(_, Timeout) when is_integer(Timeout) andalso (Timeout =< 0) ->
{error, timeout};
accept(#socket{ref = LSockRef}, Timeout)
- when is_integer(Timeout) orelse (Timeout =:= infinity) ->
+ when is_integer(Timeout) orelse
+ (Timeout =:= infinity) orelse
+ (Timeout =:= nowait) ->
do_accept(LSockRef, Timeout).
do_accept(LSockRef, Timeout) ->
@@ -1292,6 +1401,11 @@ do_accept(LSockRef, Timeout) ->
Socket = #socket{ref = SockRef},
{ok, Socket};
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(accept, AccRef);
+
+
{error, eagain} ->
%% Each call is non-blocking, but even then it takes
%% *some* time, so just to be sure, recalculate before
@@ -1330,33 +1444,56 @@ send(Socket, Data) ->
send(Socket, Data, ?SOCKET_SEND_FLAGS_DEFAULT, ?SOCKET_SEND_TIMEOUT_DEFAULT).
-spec send(Socket, Data, Flags) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: iodata(),
- Flags :: send_flags(),
- Reason :: term()
+ Socket :: socket(),
+ Data :: iodata(),
+ Flags :: send_flags(),
+ Reason :: term()
+ ; (Socket, Data, Timeout :: nowait) -> ok |
+ {select, SelectInfo} |
+ {ok, {RestData, SelectInfo}} |
+ {error, Reason} when
+ Socket :: socket(),
+ Data :: iodata(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
; (Socket, Data, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: iodata(),
- Timeout :: timeout(),
- Reason :: term().
+ Socket :: socket(),
+ Data :: iodata(),
+ Timeout :: timeout(),
+ Reason :: term().
send(Socket, Data, Flags) when is_list(Flags) ->
send(Socket, Data, Flags, ?SOCKET_SEND_TIMEOUT_DEFAULT);
send(Socket, Data, Timeout) ->
send(Socket, Data, ?SOCKET_SEND_FLAGS_DEFAULT, Timeout).
--spec send(Socket, Data, Flags, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: iodata(),
- Flags :: send_flags(),
- Timeout :: timeout(),
- Reason :: term().
+-spec send(Socket, Data, Flags, nowait) -> ok |
+ {select, SelectInfo} |
+ {ok, {RestData, SelectInfo}} |
+ {error, Reason} when
+ Socket :: socket(),
+ Data :: iodata(),
+ Flags :: send_flags(),
+ RestData :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Data, Flags, Timeout) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Data :: iodata(),
+ Flags :: send_flags(),
+ Timeout :: timeout(),
+ Reason :: term().
send(Socket, Data, Flags, Timeout) when is_list(Data) ->
Bin = erlang:list_to_binary(Data),
send(Socket, Bin, Flags, Timeout);
send(#socket{ref = SockRef}, Data, Flags, Timeout)
- when is_binary(Data) andalso is_list(Flags) ->
+ when is_binary(Data) andalso
+ is_list(Flags) andalso
+ ((Timeout =:= nowait) orelse
+ (Timeout =:= infinity) orelse
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
EFlags = enc_send_flags(Flags),
do_send(SockRef, Data, EFlags, Timeout).
@@ -1366,6 +1503,15 @@ do_send(SockRef, Data, EFlags, Timeout) ->
case nif_send(SockRef, SendRef, Data, EFlags) of
ok ->
ok;
+
+
+ {ok, Written} when (Timeout =:= nowait) ->
+ <<_:Written/binary, Rest/binary>> = Data,
+ %% We are partially done, but the user don't want to wait (here)
+ %% for completion
+ {ok, {Rest, ?SELECT_INFO(send, SendRef)}};
+
+
{ok, Written} ->
NewTimeout = next_timeout(TS, Timeout),
%% We are partially done, wait for continuation
@@ -1387,6 +1533,12 @@ do_send(SockRef, Data, EFlags, Timeout) ->
cancel(SockRef, send, SendRef),
{error, {timeout, size(Data)}}
end;
+
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(send, SendRef);
+
+
{error, eagain} ->
receive
{?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
@@ -1415,24 +1567,32 @@ do_send(SockRef, Data, EFlags, Timeout) ->
ok | {error, Reason} when
Socket :: socket(),
Data :: binary(),
- Dest :: null | sockaddr(),
+ Dest :: sockaddr(),
Reason :: term().
sendto(Socket, Data, Dest) ->
sendto(Socket, Data, Dest, ?SOCKET_SENDTO_FLAGS_DEFAULT).
-spec sendto(Socket, Data, Dest, Flags) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: binary(),
- Dest :: null | sockaddr(),
- Flags :: send_flags(),
- Reason :: term()
+ Socket :: socket(),
+ Data :: binary(),
+ Dest :: sockaddr(),
+ Flags :: send_flags(),
+ Reason :: term()
+ ; (Socket, Data, Dest, Timeout :: nowait) -> ok |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
; (Socket, Data, Dest, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: iodata(),
- Dest :: null | sockaddr(),
- Timeout :: timeout(),
- Reason :: term().
+ Socket :: socket(),
+ Data :: iodata(),
+ Dest :: sockaddr(),
+ Timeout :: timeout(),
+ Reason :: term().
sendto(Socket, Data, Dest, Flags) when is_list(Flags) ->
sendto(Socket, Data, Dest, Flags, ?SOCKET_SENDTO_TIMEOUT_DEFAULT);
@@ -1440,31 +1600,35 @@ sendto(Socket, Data, Dest, Timeout) ->
sendto(Socket, Data, Dest, ?SOCKET_SENDTO_FLAGS_DEFAULT, Timeout).
--spec sendto(Socket, Data, Dest, Flags, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- Data :: binary(),
- Dest :: null | sockaddr(),
- Flags :: send_flags(),
- Timeout :: timeout(),
- Reason :: term().
+-spec sendto(Socket, Data, Dest, Flags, nowait) -> ok |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ Data :: binary(),
+ Dest :: sockaddr(),
+ Flags :: send_flags(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Data, Dest, Flags, Timeout) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Data :: binary(),
+ Dest :: sockaddr(),
+ Flags :: send_flags(),
+ Timeout :: timeout(),
+ Reason :: term().
sendto(Socket, Data, Dest, Flags, Timeout) when is_list(Data) ->
Bin = erlang:list_to_binary(Data),
sendto(Socket, Bin, Dest, Flags, Timeout);
-sendto(#socket{ref = SockRef}, Data, Dest, Flags, Timeout)
- when is_binary(Data) andalso
- (Dest =:= null) andalso
- is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
- EFlags = enc_send_flags(Flags),
- do_sendto(SockRef, Data, Dest, EFlags, Timeout);
sendto(#socket{ref = SockRef}, Data, #{family := Fam} = Dest, Flags, Timeout)
when is_binary(Data) andalso
((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso
is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
+ ((Timeout =:= nowait) orelse
+ (Timeout =:= infinity) orelse
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
EFlags = enc_send_flags(Flags),
- do_sendto(SockRef, Data, Dest, EFlags, Timeout).
+ do_sendto(SockRef, Data, ensure_sockaddr(Dest), EFlags, Timeout).
do_sendto(SockRef, Data, Dest, EFlags, Timeout) ->
TS = timestamp(Timeout),
@@ -1474,6 +1638,11 @@ do_sendto(SockRef, Data, Dest, EFlags, Timeout) ->
%% We are done
ok;
+ {ok, Written} when (Timeout =:= nowait) ->
+ <<_:Written/binary, Rest/binary>> = Data,
+ {ok, {Rest, ?SELECT_INFO(sendto, SendRef)}};
+
+
{ok, Written} ->
%% We are partially done, wait for continuation
receive
@@ -1495,6 +1664,11 @@ do_sendto(SockRef, Data, Dest, EFlags, Timeout) ->
{error, timeout}
end;
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(sendto, SendRef);
+
+
{error, eagain} ->
receive
{?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
@@ -1538,11 +1712,18 @@ sendmsg(Socket, MsgHdr) ->
MsgHdr :: msghdr(),
Flags :: send_flags(),
Reason :: term()
+ ; (Socket, MsgHdr, Timeout :: nowait) -> ok |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
; (Socket, MsgHdr, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- MsgHdr :: msghdr(),
- Timeout :: timeout(),
- Reason :: term().
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ Timeout :: timeout(),
+ Reason :: term().
sendmsg(Socket, MsgHdr, Flags) when is_list(Flags) ->
sendmsg(Socket, MsgHdr, Flags, ?SOCKET_SENDMSG_TIMEOUT_DEFAULT);
@@ -1551,19 +1732,34 @@ sendmsg(Socket, MsgHdr, Timeout)
sendmsg(Socket, MsgHdr, ?SOCKET_SENDMSG_FLAGS_DEFAULT, Timeout).
--spec sendmsg(Socket, MsgHdr, Flags, Timeout) ->
- ok | {ok, Remaining} | {error, Reason} when
- Socket :: socket(),
- MsgHdr :: msghdr(),
- Flags :: send_flags(),
- Timeout :: timeout(),
- Remaining :: erlang:iovec(),
- Reason :: term().
+-spec sendmsg(Socket, MsgHdr, Flags, nowait) ->
+ ok |
+ {ok, Remaining} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ Flags :: send_flags(),
+ Remaining :: erlang:iovec(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, MsgHdr, Flags, Timeout) ->
+ ok |
+ {ok, Remaining} |
+ {error, Reason} when
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ Flags :: send_flags(),
+ Timeout :: timeout(),
+ Remaining :: erlang:iovec(),
+ Reason :: term().
sendmsg(#socket{ref = SockRef}, #{iov := IOV} = MsgHdr, Flags, Timeout)
when is_list(IOV) andalso
is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
+ ((Timeout =:= nowait) orelse
+ (Timeout =:= infinity) orelse
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
try ensure_msghdr(MsgHdr) of
M ->
EFlags = enc_send_flags(Flags),
@@ -1583,6 +1779,7 @@ do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
%% We are done
ok;
+
{ok, Written} when is_integer(Written) andalso (Written > 0) ->
%% We should not retry here since the protocol may not
%% be able to handle a message being split. Leave it to
@@ -1594,6 +1791,11 @@ do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
cancel(SockRef, sendmsg, SendRef),
{ok, do_sendmsg_rest(maps:get(iov, MsgHdr), Written)};
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(sendmsg, SendRef);
+
+
{error, eagain} ->
receive
{?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
@@ -1617,8 +1819,12 @@ do_sendmsg_rest([B|IOVec], Written) ->
ensure_msghdr(#{ctrl := []} = M) ->
ensure_msghdr(maps:remove(ctrl, M));
-ensure_msghdr(#{iov := IOV} = M) when is_list(IOV) andalso (IOV =/= []) ->
- M#{iov := erlang:iolist_to_iovec(IOV)};
+ensure_msghdr(#{iov := IOV, addr := Addr} = M)
+ when is_list(IOV) andalso (IOV =/= []) ->
+ M#{iov => erlang:iolist_to_iovec(IOV), addr => ensure_sockaddr(Addr)};
+ensure_msghdr(#{iov := IOV} = M)
+ when is_list(IOV) andalso (IOV =/= []) ->
+ M#{iov => erlang:iolist_to_iovec(IOV)};
ensure_msghdr(_) ->
einval().
@@ -1667,13 +1873,24 @@ recv(Socket, Length) ->
?SOCKET_RECV_FLAGS_DEFAULT,
?SOCKET_RECV_TIMEOUT_DEFAULT).
--spec recv(Socket, Length, Flags) -> {ok, Data} | {error, Reason} when
+-spec recv(Socket, Length, Flags) -> {ok, Data} |
+ {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Flags :: recv_flags(),
Data :: binary(),
Reason :: term()
- ; (Socket, Length, Timeout) -> {ok, Data} | {error, Reason} when
+ ; (Socket, Length, Timeout :: nowait) -> {ok, Data} |
+ {select, SelectInfo} |
+ {ok, {Data, SelectInfo}} |
+ {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Length, Timeout) -> {ok, Data} |
+ {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
@@ -1685,18 +1902,31 @@ recv(Socket, Length, Flags) when is_list(Flags) ->
recv(Socket, Length, Timeout) ->
recv(Socket, Length, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
--spec recv(Socket, Length, Flags, Timeout) -> {ok, Data} | {error, Reason} when
- Socket :: socket(),
- Length :: non_neg_integer(),
- Flags :: recv_flags(),
- Timeout :: timeout(),
- Data :: binary(),
- Reason :: term().
+-spec recv(Socket, Length, Flags, nowait) -> {ok, Data} |
+ {select, SelectInfo} |
+ {ok, {Data, SelectInfo}} |
+ {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Length, Flags, Timeout) -> {ok, Data} |
+ {error, Reason} when
+ Socket :: socket(),
+ Length :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Timeout :: timeout(),
+ Data :: binary(),
+ Reason :: term().
recv(#socket{ref = SockRef}, Length, Flags, Timeout)
when (is_integer(Length) andalso (Length >= 0)) andalso
is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
+ (is_integer(Timeout) orelse
+ (Timeout =:= infinity) orelse
+ (Timeout =:= nowait)) ->
EFlags = enc_recv_flags(Flags),
do_recv(SockRef, undefined, Length, EFlags, <<>>, Timeout).
@@ -1704,8 +1934,12 @@ recv(#socket{ref = SockRef}, Length, Flags, Timeout)
%% with Length = 0. This case makes it neccessary to have a timeout function
%% clause since we may never wait for anything (no receive select), and so the
%% the only timeout check will be the function clause.
+%% Note that the Timeout value of 'nowait' has a special meaning. It means
+%% that we will either return with data or with the with {error, NNNN}. In
+%% wich case the caller will receive a select message at some later time.
do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
- when (Timeout =:= infinity) orelse
+ when (Timeout =:= nowait) orelse
+ (Timeout =:= infinity) orelse
(is_integer(Timeout) andalso (Timeout > 0)) ->
TS = timestamp(Timeout),
RecvRef = make_ref(),
@@ -1726,6 +1960,15 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
<<Acc/binary, Bin/binary>>,
next_timeout(TS, Timeout));
+
+ %% Did not get all the user asked for, but the user also
+ %% specified 'nowait', so deliver what we got and the
+ %% select info.
+ {ok, false = _Completed, Bin} when (Timeout =:= nowait) andalso
+ (size(Acc) =:= 0) ->
+ {ok, {Bin, ?SELECT_INFO(recv, RecvRef)}};
+
+
{ok, false = _Completed, Bin} when (size(Acc) =:= 0) ->
%% We got the first chunk of it.
%% We will be notified (select message) when there
@@ -1764,6 +2007,17 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
{error, {timeout, Acc}}
end;
+
+ %% The user does not want to wait!
+ %% The user will be informed that there is something to read
+ %% via the select socket message (see below).
+
+ {error, eagain} when (Timeout =:= nowait) andalso (size(Acc) =:= 0) ->
+ ?SELECT(recv, RecvRef);
+ {error, eagain} when (Timeout =:= nowait) ->
+ {ok, {Acc, ?SELECT_INFO(recv, RecvRef)}};
+
+
%% We return with the accumulated binary (if its non-empty)
{error, eagain} when (Length =:= 0) andalso (size(Acc) > 0) ->
%% CAN WE REALLY DO THIS? THE NIF HAS SELECTED!! OR?
@@ -1854,30 +2108,51 @@ recvfrom(Socket, BufSz) ->
?SOCKET_RECV_FLAGS_DEFAULT,
?SOCKET_RECV_TIMEOUT_DEFAULT).
--spec recvfrom(Socket, Flags, Timeout) ->
- {ok, {Source, Data}} | {error, Reason} when
- Socket :: socket(),
- Flags :: recv_flags(),
- Timeout :: timeout(),
- Source :: sockaddr() | undefined,
- Data :: binary(),
- Reason :: term()
+-spec recvfrom(Socket, Flags, nowait) ->
+ {ok, {Source, Data}} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ Flags :: recv_flags(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Flags, Timeout) ->
+ {ok, {Source, Data}} |
+ {error, Reason} when
+ Socket :: socket(),
+ Flags :: recv_flags(),
+ Timeout :: timeout(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ Reason :: term()
; (Socket, BufSz, Flags) ->
{ok, {Source, Data}} | {error, Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Flags :: recv_flags(),
- Source :: sockaddr() | undefined,
- Data :: binary(),
- Reason :: term()
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ Reason :: term()
+ ; (Socket, BufSz, nowait) ->
+ {ok, {Source, Data}} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
; (Socket, BufSz, Timeout) ->
{ok, {Source, Data}} | {error, Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Timeout :: timeout(),
- Source :: sockaddr() | undefined,
- Data :: binary(),
- Reason :: term().
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Timeout :: timeout(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ Reason :: term().
recvfrom(Socket, Flags, Timeout) when is_list(Flags) ->
recvfrom(Socket, 0, Flags, Timeout);
@@ -1886,20 +2161,34 @@ recvfrom(Socket, BufSz, Flags) when is_list(Flags) ->
recvfrom(Socket, BufSz, Timeout) ->
recvfrom(Socket, BufSz, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
--spec recvfrom(Socket, BufSz, Flags, Timeout) ->
- {ok, {Source, Data}} | {error, Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- Flags :: recv_flags(),
- Timeout :: timeout(),
- Source :: sockaddr() | undefined,
- Data :: binary(),
- Reason :: term().
+-spec recvfrom(Socket, BufSz, Flags, nowait) ->
+ {ok, {Source, Data}} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, BufSz, Flags, Timeout) ->
+ {ok, {Source, Data}} |
+ {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Timeout :: timeout(),
+ Source :: sockaddr() | undefined,
+ Data :: binary(),
+ Reason :: term().
recvfrom(#socket{ref = SockRef}, BufSz, Flags, Timeout)
when (is_integer(BufSz) andalso (BufSz >= 0)) andalso
is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
+ (is_integer(Timeout) orelse
+ (Timeout =:= infinity) orelse
+ (Timeout =:= nowait)) ->
EFlags = enc_recv_flags(Flags),
do_recvfrom(SockRef, BufSz, EFlags, Timeout).
@@ -1910,6 +2199,11 @@ do_recvfrom(SockRef, BufSz, EFlags, Timeout) ->
{ok, {_Source, _NewData}} = OK ->
OK;
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(recvfrom, RecvRef);
+
+
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
@@ -1950,29 +2244,44 @@ recvmsg(Socket) ->
Flags :: recv_flags(),
MsgHdr :: msghdr(),
Reason :: term()
+ ; (Socket, Timeout :: nowait) -> {ok, MsgHdr} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ MsgHdr :: msghdr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
; (Socket, Timeout) -> {ok, MsgHdr} | {error, Reason} when
- Socket :: socket(),
- Timeout :: timeout(),
- MsgHdr :: msghdr(),
- Reason :: term().
+ Socket :: socket(),
+ Timeout :: timeout(),
+ MsgHdr :: msghdr(),
+ Reason :: term().
recvmsg(Socket, Flags) when is_list(Flags) ->
recvmsg(Socket, 0, 0, Flags, ?SOCKET_RECV_TIMEOUT_DEFAULT);
recvmsg(Socket, Timeout) ->
recvmsg(Socket, 0, 0, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
--spec recvmsg(Socket, Flags, Timeout) -> {ok, MsgHdr} | {error, Reason} when
- Socket :: socket(),
- Flags :: recv_flags(),
- Timeout :: timeout(),
- MsgHdr :: msghdr(),
- Reason :: term()
+-spec recvmsg(Socket, Flags, nowait) -> {ok, MsgHdr} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ Flags :: recv_flags(),
+ MsgHdr :: msghdr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket, Flags, Timeout) -> {ok, MsgHdr} | {error, Reason} when
+ Socket :: socket(),
+ Flags :: recv_flags(),
+ Timeout :: timeout(),
+ MsgHdr :: msghdr(),
+ Reason :: term()
; (Socket, BufSz, CtrlSz) -> {ok, MsgHdr} | {error, Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- MsgHdr :: msghdr(),
- Reason :: term().
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ MsgHdr :: msghdr(),
+ Reason :: term().
recvmsg(Socket, Flags, Timeout) when is_list(Flags) ->
recvmsg(Socket, 0, 0, Flags, Timeout);
@@ -1983,20 +2292,34 @@ recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz) andalso is_integer(CtrlSz)
-spec recvmsg(Socket,
BufSz, CtrlSz,
- Flags, Timeout) -> {ok, MsgHdr} | {error, Reason} when
- Socket :: socket(),
- BufSz :: non_neg_integer(),
- CtrlSz :: non_neg_integer(),
- Flags :: recv_flags(),
- Timeout :: timeout(),
- MsgHdr :: msghdr(),
- Reason :: term().
+ Flags, nowait) -> {ok, MsgHdr} |
+ {select, SelectInfo} |
+ {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Flags :: recv_flags(),
+ MsgHdr :: msghdr(),
+ SelectInfo :: select_info(),
+ Reason :: term()
+ ; (Socket,
+ BufSz, CtrlSz,
+ Flags, Timeout) -> {ok, MsgHdr} | {error, Reason} when
+ Socket :: socket(),
+ BufSz :: non_neg_integer(),
+ CtrlSz :: non_neg_integer(),
+ Flags :: recv_flags(),
+ Timeout :: timeout(),
+ MsgHdr :: msghdr(),
+ Reason :: term().
recvmsg(#socket{ref = SockRef}, BufSz, CtrlSz, Flags, Timeout)
when (is_integer(BufSz) andalso (BufSz >= 0)) andalso
(is_integer(CtrlSz) andalso (CtrlSz >= 0)) andalso
is_list(Flags) andalso
- (is_integer(Timeout) orelse (Timeout =:= infinity)) ->
+ (is_integer(Timeout) orelse
+ (Timeout =:= infinity) orelse
+ (Timeout =:= nowait)) ->
EFlags = enc_recv_flags(Flags),
do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout).
@@ -2007,6 +2330,11 @@ do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout) ->
{ok, _MsgHdr} = OK ->
OK;
+
+ {error, eagain} when (Timeout =:= nowait) ->
+ ?SELECT(recvmsg, RecvRef);
+
+
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
@@ -2342,6 +2670,25 @@ peername(#socket{ref = SockRef}) ->
nif_peername(SockRef).
+%% ===========================================================================
+%%
+%% cancel - cancel an operation resulting in a select
+%%
+%% A call to accept, recv/recvfrom/recvmsg and send/sendto/sendmsg
+%% can result in a select if they are called with the Timeout argument
+%% set to nowait. This is indicated by the return of the select-info.
+%% Such a operation can be cancelled by calling this function.
+%%
+
+-spec cancel(Socket, SelectInfo) -> ok | {error, Reason} when
+ Socket :: socket(),
+ SelectInfo :: select_info(),
+ Reason :: term().
+
+cancel(#socket{ref = SockRef}, ?SELECT_INFO(Tag, Ref)) ->
+ cancel(SockRef, Tag, Ref).
+
+
%% ===========================================================================
%%
@@ -2349,39 +2696,40 @@ peername(#socket{ref = SockRef}) ->
%%
%% ===========================================================================
--spec enc_domain(Domain) -> non_neg_integer() when
- Domain :: domain().
+%% -spec enc_domain(Domain) -> non_neg_integer() when
+%% Domain :: domain().
enc_domain(local) -> ?SOCKET_DOMAIN_LOCAL;
enc_domain(inet) -> ?SOCKET_DOMAIN_INET;
enc_domain(inet6) -> ?SOCKET_DOMAIN_INET6;
-enc_domain(Domain) -> throw({error, {invalid_domain, Domain}}).
+enc_domain(Domain) -> invalid_domain(Domain).
--spec enc_type(Domain, Type) -> non_neg_integer() when
- Domain :: domain(),
- Type :: type().
+%% -spec enc_type(Domain, Type) -> non_neg_integer() when
+%% Domain :: domain(),
+%% Type :: type().
%% What combos are valid?
enc_type(_, stream) -> ?SOCKET_TYPE_STREAM;
enc_type(_, dgram) -> ?SOCKET_TYPE_DGRAM;
enc_type(_, raw) -> ?SOCKET_TYPE_RAW;
enc_type(_, seqpacket) -> ?SOCKET_TYPE_SEQPACKET;
-enc_type(_, Type) -> throw({error, {invalid_type, Type}}).
+enc_type(_, Type) -> invalid_type(Type).
-spec enc_protocol(Type, Protocol) -> non_neg_integer() |
{raw, non_neg_integer()} when
Type :: type(),
Protocol :: protocol().
-enc_protocol(dgram, ip) -> ?SOCKET_PROTOCOL_IP;
-enc_protocol(stream, tcp) -> ?SOCKET_PROTOCOL_TCP;
-enc_protocol(dgram, udp) -> ?SOCKET_PROTOCOL_UDP;
-enc_protocol(seqpacket, sctp) -> ?SOCKET_PROTOCOL_SCTP;
-enc_protocol(raw, icmp) -> ?SOCKET_PROTOCOL_ICMP;
-enc_protocol(raw, igmp) -> ?SOCKET_PROTOCOL_IGMP;
+enc_protocol(_, default) -> ?SOCKET_PROTOCOL_DEFAULT;
+enc_protocol(dgram, ip) -> ?SOCKET_PROTOCOL_IP;
+enc_protocol(stream, tcp) -> ?SOCKET_PROTOCOL_TCP;
+enc_protocol(dgram, udp) -> ?SOCKET_PROTOCOL_UDP;
+enc_protocol(seqpacket, sctp) -> ?SOCKET_PROTOCOL_SCTP;
+enc_protocol(raw, icmp) -> ?SOCKET_PROTOCOL_ICMP;
+enc_protocol(raw, igmp) -> ?SOCKET_PROTOCOL_IGMP;
enc_protocol(raw, {raw, P} = RAW) when is_integer(P) -> RAW;
enc_protocol(Type, Proto) ->
- throw({error, {invalid_protocol, {Type, Proto}}}).
+ invalid_protocol(Type, Proto).
-spec enc_send_flags(Flags) -> non_neg_integer() when
@@ -2532,7 +2880,7 @@ enc_setopt_value(otp, rcvbuf, V, _, _, _) when is_integer(V) andalso (V > 0) ->
V;
%% N: Number of reads (when specifying length = 0)
%% V: Size of the "read" buffer
-enc_setopt_value(otp, rcvbuf, {N, BufSz} = V, _, stream = _T, tcp = _P)
+enc_setopt_value(otp, rcvbuf, {N, BufSz} = V, _, stream = _T, _P)
when (is_integer(N) andalso (N > 0)) andalso
(is_integer(BufSz) andalso (BufSz > 0)) ->
V;
@@ -3028,10 +3376,12 @@ enc_sockopt_key(otp = L, Opt, _, _, _, _) ->
%% +++ SOCKET socket options +++
enc_sockopt_key(socket = _L, acceptconn = _Opt, get = _Dir, _D, _T, _P) ->
?SOCKET_OPT_SOCK_ACCEPTCONN;
+enc_sockopt_key(socket = L, acceptconn = Opt, Dir, _D, _T, _P) ->
+ not_supported({L, Opt, Dir});
enc_sockopt_key(socket = L, acceptfilter = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-%% Before linux 3.8, this socket option could be set.
-%% Maximum size of buffer for name: IFNAMSZIZ
+%% Before linux 3.8, this socket option could be set but not get.
+%% Maximum size of buffer for name: IFNAMSIZ
%% So, we let the implementation decide.
enc_sockopt_key(socket = _L, bindtodevice = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_SOCK_BINDTODEVICE;
@@ -3464,15 +3814,18 @@ flush_select_msgs(SockRef, Ref) ->
%% A timestamp in ms
+timestamp(nowait = T) ->
+ T;
timestamp(infinity) ->
undefined;
timestamp(_) ->
timestamp().
timestamp() ->
- {A,B,C} = os:timestamp(),
- A*1000000000+B*1000+(C div 1000).
+ erlang:monotonic_time(milli_seconds).
+next_timeout(_, nowait = Timeout) ->
+ Timeout;
next_timeout(_, infinity = Timeout) ->
Timeout;
next_timeout(TS, Timeout) ->
@@ -3510,6 +3863,25 @@ tdiff(T1, T2) ->
%%
%% ===========================================================================
+-spec invalid_domain(Domain) -> no_return() when
+ Domain :: term().
+
+invalid_domain(Domain) ->
+ error({invalid_domain, Domain}).
+
+-spec invalid_type(Type) -> no_return() when
+ Type :: term().
+
+invalid_type(Type) ->
+ error({invalid_type, Type}).
+
+-spec invalid_protocol(Type, Proto) -> no_return() when
+ Type :: term(),
+ Proto :: term().
+
+invalid_protocol(Type, Proto) ->
+ error({invalid_protocol, {Type, Proto}}).
+
-spec not_supported(What) -> no_return() when
What :: term().
@@ -3543,6 +3915,12 @@ error(Reason) ->
nif_info() ->
erlang:nif_error(undef).
+nif_info(_SRef) ->
+ erlang:nif_error(undef).
+
+nif_command(_Command) ->
+ erlang:nif_error(undef).
+
nif_supports(_Key) ->
erlang:nif_error(undef).
diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl
index 602dc5ce2e..952e6da4dc 100644
--- a/erts/test/erlexec_SUITE.erl
+++ b/erts/test/erlexec_SUITE.erl
@@ -30,7 +30,7 @@
-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
-export([args_file/1, evil_args_file/1, env/1, args_file_env/1,
- otp_7461/1, otp_7461_remote/1, otp_8209/1,
+ otp_7461/1, otp_7461_remote/1, argument_separation/1,
zdbbl_dist_buf_busy_limit/1]).
-include_lib("common_test/include/ct.hrl").
@@ -51,21 +51,28 @@ suite() ->
all() ->
[args_file, evil_args_file, env, args_file_env,
- otp_7461, otp_8209, zdbbl_dist_buf_busy_limit].
+ otp_7461, argument_separation, zdbbl_dist_buf_busy_limit].
%% Test that plain first argument does not
-%% destroy -home switch [OTP-8209]
-otp_8209(Config) when is_list(Config) ->
+%% destroy -home switch [OTP-8209] or interact with environments
+argument_separation(Config) when is_list(Config) ->
{ok,[[PName]]} = init:get_argument(progname),
SNameS = "erlexec_test_01",
SName = list_to_atom(SNameS++"@"++
hd(tl(string:lexemes(atom_to_list(node()),"@")))),
- Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++
- atom_to_list(erlang:get_cookie()),
- open_port({spawn,Cmd},[]),
+ Cmd = PName ++ " cmd_param -sname "++SNameS++" -setcookie "++
+ atom_to_list(erlang:get_cookie()) ++ " -cmd_test",
+ open_port({spawn,Cmd},[{env,[{"ERL_AFLAGS","-atest"},
+ {"ERL_FLAGS","env_param -test"},
+ {"ERL_ZFLAGS","zenv_param"}]}]),
pong = loop_ping(SName,40),
+ ct:log("emu_args: ~p",[rpc:call(SName,erlang,system_info,[emu_args])]),
{ok,[[_]]} = rpc:call(SName,init,get_argument,[home]),
- ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]),
+ {ok,[[]]} = rpc:call(SName,init,get_argument,[atest]),
+ {ok,[[]]} = rpc:call(SName,init,get_argument,[cmd_test]),
+ {ok,[[]]} = rpc:call(SName,init,get_argument,[test]),
+ error = rpc:call(SName,init,get_argument,[unkown]),
+ ["cmd_param","env_param","zenv_param"] = rpc:call(SName,init,get_plain_arguments,[]),
ok = cleanup_nodes(),
ok.
@@ -85,6 +92,7 @@ cleanup_node(SNameS,N) ->
end.
loop_ping(_,0) ->
+ flush(),
pang;
loop_ping(Node,N) ->
case net_adm:ping(Node) of
@@ -98,6 +106,14 @@ loop_ping(Node,N) ->
pong
end.
+flush() ->
+ receive M ->
+ ct:pal("~p",[M]),
+ flush()
+ after 10 ->
+ ok
+ end.
+
args_file(Config) when is_list(Config) ->
AFN1 = privfile("1", Config),
AFN2 = privfile("2", Config),
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 224570fb09..f06fd08540 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.4
+VSN = 10.4.4
# Port number 4365 in 4.2
# Port number 4366 in 4.3