aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/c_src/crypto.c252
-rw-r--r--lib/crypto/src/crypto.erl19
-rw-r--r--lib/crypto/test/crypto_SUITE.erl4
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml69
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml16
-rw-r--r--lib/kernel/doc/src/gen_udp.xml35
-rw-r--r--lib/kernel/doc/src/inet.xml123
-rw-r--r--lib/kernel/src/gen_sctp.erl18
-rw-r--r--lib/kernel/src/gen_tcp.erl16
-rw-r--r--lib/kernel/src/gen_udp.erl19
-rw-r--r--lib/kernel/src/inet.erl17
-rw-r--r--lib/kernel/src/inet6_tcp.erl8
-rw-r--r--lib/kernel/src/inet_int.hrl7
-rw-r--r--lib/kernel/src/inet_tcp.erl8
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl209
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl163
-rw-r--r--lib/snmp/doc/src/notes.xml4
-rw-r--r--lib/snmp/doc/src/snmp.xml33
-rw-r--r--lib/snmp/doc/src/snmpa.xml38
-rw-r--r--lib/snmp/doc/src/snmpm.xml38
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl111
-rw-r--r--lib/snmp/src/compile/snmpc.erl6
-rw-r--r--lib/snmp/src/misc/snmp_log.erl334
-rw-r--r--lib/snmp/vsn.mk4
-rw-r--r--lib/stdlib/doc/src/ets.xml2
25 files changed, 1079 insertions, 474 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 07ef60e395..d40d285f86 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -213,8 +213,10 @@
# define HAVE_ECB_IVEC_BUG
#endif
-#ifdef RSA_SSLV23_PADDING
-# define HAVE_RSA_SSLV23_PADDING
+#ifndef HAS_LIBRESSL
+# ifdef RSA_SSLV23_PADDING
+# define HAVE_RSA_SSLV23_PADDING
+# endif
#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
@@ -551,9 +553,6 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -646,9 +645,6 @@ static ErlNifFunc nif_funcs[] = {
{"aead_encrypt", 6, aead_encrypt},
{"aead_decrypt", 6, aead_decrypt},
- {"chacha20_poly1305_encrypt", 4, chacha20_poly1305_encrypt},
- {"chacha20_poly1305_decrypt", 5, chacha20_poly1305_decrypt},
-
{"chacha20_stream_init", 2, chacha20_stream_init},
{"chacha20_stream_encrypt", 2, chacha20_stream_crypt},
{"chacha20_stream_decrypt", 2, chacha20_stream_crypt},
@@ -724,6 +720,9 @@ static ERL_NIF_TERM atom_aes_gcm;
#ifdef HAVE_CCM
static ERL_NIF_TERM atom_aes_ccm;
#endif
+#ifdef HAVE_CHACHA20_POLY1305
+static ERL_NIF_TERM atom_chacha20_poly1305;
+#endif
#ifdef HAVE_ECB_IVEC_BUG
static ERL_NIF_TERM atom_aes_ecb;
static ERL_NIF_TERM atom_des_ecb;
@@ -1170,6 +1169,9 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#ifdef HAVE_CCM
atom_aes_ccm = enif_make_atom(env, "aes_ccm");
#endif
+#ifdef HAVE_CHACHA20_POLY1305
+ atom_chacha20_poly1305 = enif_make_atom(env,"chacha20_poly1305");
+#endif
#ifdef HAVE_ECB_IVEC_BUG
atom_aes_ecb = enif_make_atom(env, "aes_ecb");
atom_des_ecb = enif_make_atom(env, "des_ecb");
@@ -2590,46 +2592,53 @@ static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
/* Use cipher_type some day. Must check block_encrypt|decrypt first */
#if defined(HAVE_GCM)
- if ((type == atom_aes_gcm)
- && (iv.size > 0)
- && (1 <= tag_len && tag_len <= 16)) {
- ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
- ctx_ctrl_get_tag = EVP_CTRL_GCM_GET_TAG;
- if (key.size == 16) cipher = EVP_aes_128_gcm();
- else if (key.size == 24) cipher = EVP_aes_192_gcm();
- else if (key.size == 32) cipher = EVP_aes_256_gcm();
- else
+ if (type == atom_aes_gcm) {
+ if ((iv.size > 0)
+ && (1 <= tag_len && tag_len <= 16)) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_GCM_GET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_gcm();
+ else if (key.size == 24) cipher = EVP_aes_192_gcm();
+ else if (key.size == 32) cipher = EVP_aes_256_gcm();
+ else enif_make_badarg(env);
+ } else
enif_make_badarg(env);
-
} else
#endif
#if defined(HAVE_CCM)
- if ((type == atom_aes_ccm)
- && (7 <= iv.size && iv.size <= 13)
- && (4 <= tag_len && tag_len <= 16)
- && ((tag_len & 1) == 0)
- ) {
- ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
- ctx_ctrl_get_tag = EVP_CTRL_CCM_GET_TAG;
- if (key.size == 16) cipher = EVP_aes_128_ccm();
- else if (key.size == 24) cipher = EVP_aes_192_ccm();
- else if (key.size == 32) cipher = EVP_aes_256_ccm();
- else
+ if (type == atom_aes_ccm) {
+ if ((7 <= iv.size && iv.size <= 13)
+ && (4 <= tag_len && tag_len <= 16)
+ && ((tag_len & 1) == 0)
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_CCM_GET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_ccm();
+ else if (key.size == 24) cipher = EVP_aes_192_ccm();
+ else if (key.size == 32) cipher = EVP_aes_256_ccm();
+ else enif_make_badarg(env);
+ } else
enif_make_badarg(env);
-
} else
#endif
- enif_make_badarg(env);
+#if defined(HAVE_CHACHA20_POLY1305)
+ if (type == atom_chacha20_poly1305) {
+ if ((key.size == 32)
+ && (1 <= iv.size && iv.size <= 16)
+ && (tag_len == 16)
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_AEAD_GET_TAG,
+ cipher = EVP_chacha20_poly1305();
+ } else enif_make_badarg(env);
+ } else
+#endif
+ return enif_raise_exception(env, atom_notsup);
ctx = EVP_CIPHER_CTX_new();
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err;
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err;
-#if defined(HAVE_GCM)
- if (type == atom_aes_gcm) {
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
- } else
-#endif
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) goto out_err;
@@ -2637,14 +2646,14 @@ static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in.size) != 1) goto out_err;
} else
#endif
- goto out_err;
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
outp = enif_make_new_binary(env, in.size, &out);
if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp, &len) != 1) goto out_err;
+ if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1) goto out_err;
tagp = enif_make_new_binary(env, tag_len, &out_tag);
@@ -2671,7 +2680,7 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ErlNifBinary key, iv, aad, in, tag;
unsigned char *outp;
ERL_NIF_TERM type, out;
- int len, ctx_ctrl_set_ivlen;
+ int len, ctx_ctrl_set_ivlen, ctx_ctrl_set_tag;
type = argv[0];
#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
@@ -2690,30 +2699,43 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
/* Use cipher_type some day. Must check block_encrypt|decrypt first */
#if defined(HAVE_GCM)
- if ((type == atom_aes_gcm)
- && (iv.size > 0)) {
- ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
- if (key.size == 16) cipher = EVP_aes_128_gcm();
- else if (key.size == 24) cipher = EVP_aes_192_gcm();
- else if (key.size == 32) cipher = EVP_aes_256_gcm();
- else
+ if (type == atom_aes_gcm) {
+ if (iv.size > 0) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_GCM_SET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_gcm();
+ else if (key.size == 24) cipher = EVP_aes_192_gcm();
+ else if (key.size == 32) cipher = EVP_aes_256_gcm();
+ else enif_make_badarg(env);
+ } else
enif_make_badarg(env);
-
} else
#endif
#if defined(HAVE_CCM)
- if ((type == atom_aes_ccm)
- && (iv.size > 0)) {
- ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
- if (key.size == 16) cipher = EVP_aes_128_ccm();
- else if (key.size == 24) cipher = EVP_aes_192_ccm();
- else if (key.size == 32) cipher = EVP_aes_256_ccm();
- else
+ if (type == atom_aes_ccm) {
+ if (iv.size > 0) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
+ if (key.size == 16) cipher = EVP_aes_128_ccm();
+ else if (key.size == 24) cipher = EVP_aes_192_ccm();
+ else if (key.size == 32) cipher = EVP_aes_256_ccm();
+ else enif_make_badarg(env);
+ } else
enif_make_badarg(env);
-
} else
#endif
- enif_make_badarg(env);
+#if defined(HAVE_CHACHA20_POLY1305)
+ if (type == atom_chacha20_poly1305) {
+ if ((key.size == 32)
+ && (1 <= iv.size && iv.size <= 16)
+ && tag.size == 16
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_AEAD_SET_TAG;
+ cipher = EVP_chacha20_poly1305();
+ } else enif_make_badarg(env);
+ } else
+#endif
+ return enif_raise_exception(env, atom_notsup);
outp = enif_make_new_binary(env, in.size, &out);
@@ -2738,9 +2760,9 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
-#if defined(HAVE_GCM)
+#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305)
if (type == atom_aes_gcm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size, tag.data) != 1) goto out_err;
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, tag.size, tag.data) != 1) goto out_err;
if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1) goto out_err;
}
#endif
@@ -2805,120 +2827,6 @@ out_err:
#endif /* HAVE_GCM_EVP_DECRYPT_BUG */
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- tagp = enif_make_new_binary(env, 16, &out_tag);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagp) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return enif_make_tuple2(env, out, out_tag);
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != 16) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-
static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IV) */
#if defined(HAVE_CHACHA20)
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 960fe46c09..2db73c4af0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -526,8 +526,9 @@ block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= aes_gcm;
block_encrypt(Type, Key, Ivec, {AAD, PlainText, TagLength}) when Type =:= aes_gcm;
Type =:= aes_ccm ->
aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength);
-block_encrypt(chacha20_poly1305, Key, Ivec, {AAD, PlainText}) ->
- chacha20_poly1305_encrypt(Key, Ivec, AAD, PlainText).
+block_encrypt(chacha20_poly1305=Type, Key, Ivec, {AAD, PlainText}) ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16).
+
-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(),
@@ -557,11 +558,9 @@ block_decrypt(des3_cfb, Key0, Ivec, Data) ->
block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
- Type =:= aes_ccm ->
- aead_decrypt(Type, Key, Ivec, AAD, Data, Tag);
-block_decrypt(chacha20_poly1305, Key, Ivec, {AAD, Data, Tag}) ->
- chacha20_poly1305_decrypt(Key, Ivec, AAD, Data, Tag).
-
+ Type =:= aes_ccm;
+ Type =:= chacha20_poly1305 ->
+ aead_decrypt(Type, Key, Ivec, AAD, Data, Tag).
-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
@@ -1617,12 +1616,6 @@ aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
%%
-%% Chacha20/Ppoly1305
-%%
-chacha20_poly1305_encrypt(_Key, _Ivec, _AAD, _In) -> ?nif_stub.
-chacha20_poly1305_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
-
-%%
%% AES - with 256 bit key in infinite garble extension mode (IGE)
%%
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index ff9c5163a3..495c2adb55 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1419,8 +1419,8 @@ group_config(rsa = Type, Config) ->
{rsa, PublicS, PrivateS, MsgPubEnc, [{rsa_padding, rsa_sslv23_padding}]},
{rsa, PublicS, PrivateS, MsgPubEnc, [{rsa_padding, rsa_x931_padding}]},
rsa_oaep(),
- rsa_oaep_label(),
- rsa_oaep256(),
+ %% rsa_oaep_label(),
+ %% rsa_oaep256(),
no_padding()
],
Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 737800c6b1..1e08b25f66 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -331,6 +331,37 @@ connect(Socket, Ip, Port>,
with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large
<seealso marker="inet#option-sndbuf">kernel</seealso> and driver
<seealso marker="inet#option-buffer">buffers</seealso>.</p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">passive</seealso>
+ mode data can be received through the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ calls.
+ </p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">active</seealso>
+ mode data received data is delivered to the controlling process
+ as messages:
+ </p>
+ <code type="none">
+{sctp, <anno>Socket</anno>, FromIP, FromPort, {AncData, Data}}
+ </code>
+ <p>
+ See
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ for a description of the message fields.
+ </p>
+ <note>
+ <p>
+ This message format unfortunately differs slightly from the
+ <seealso marker="gen_udp#open/1"><c>gen_udp</c></seealso>
+ message format with ancillary data,
+ and from the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ return tuple format.
+ </p>
+ </note>
</desc>
</func>
@@ -380,6 +411,19 @@ connect(Socket, Ip, Port>,
socket option
<seealso marker="#option-sctp_get_peer_addr_info"><c>sctp_get_peer_addr_info</c></seealso>,
but this does still not produce the stream number).</p>
+ <p>
+ <c><anno>AncData</anno></c> may also contain
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ from the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ if that is supported by the platform for the socket.
+ </p>
<p>The <c><anno>Data</anno></c> received can be a <c>binary()</c>
or a <c>list()</c> of bytes (integers in the range 0 through 255)
depending on the socket mode, or an SCTP event.</p>
@@ -544,12 +588,25 @@ connect(Socket, Ip, Port>,
<seealso marker="#recv/1"><c>recv</c></seealso> call
to retrieve the available data from the socket.</p>
</item>
+ <item>
+ <p>
+ If <c>true|once|N</c> (active modes)
+ received data or events are sent to the owning process.
+ See <seealso marker="#open/0"><c>open/0..2</c></seealso>
+ for the message format.
+ </p>
+ </item>
<item>
- <p>If <c>true</c> (full active mode), the pending data or events are
- sent to the owning process.</p>
- <p>Notice that this can cause the message queue to overflow,
- as there is no way to throttle the sender in this case
- (no flow control).</p>
+ <p>
+ If <c>true</c> (full active mode) there is no flow control.
+ </p>
+ <note>
+ <p>
+ Note that this can cause the message queue to overflow
+ causing for example the virtual machine
+ to run out of memory and crash.
+ </p>
+ </note>
</item>
<item>
<p>If <c>once</c>, only one message is automatically placed
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index e6104b0c76..cf649991d0 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -70,6 +70,20 @@ do_recv(Sock, Bs) ->
<name name="option"/>
</datatype>
<datatype>
+ <name name="pktoptions_value"/>
+ <desc>
+ <p>
+ If the platform implements the IPv4 option
+ <c>IP_PKTOPTIONS</c> (probably Linux specific), or the IPv6 option
+ <c>IPV6_PKTOPTIONS</c> or <c>IPV6_2292PKTOPTIONS</c> for the socket
+ this value is returned from
+ <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>
+ when called with the option name
+ <seealso marker="#type-option_name"><c>pktoptions</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="option_name"/>
</datatype>
<datatype>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index f79566ef71..840ca3c188 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -147,7 +147,21 @@
at the opened port, if the socket is in an active mode, the packets
are delivered as messages to the controlling process:</p>
<code type="none">
-{udp, Socket, IP, InPortNo, Packet}</code>
+{udp, Socket, IP, InPortNo, Packet} % Without ancillary data
+{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data
+ </code>
+ <p>
+ The message contains an <c>AncData</c> field
+ if any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, otherwise it does not.
+ </p>
+ <p>
+ </p>
<p>If the socket is not in an active mode, data can be
retrieved through the
<seealso marker="#recv/2"><c>recv/2,3</c></seealso> calls.
@@ -179,9 +193,22 @@
<name name="recv" arity="3"/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<desc>
- <p>Receives a packet from a socket in passive mode. Optional parameter
+ <p>
+ Receives a packet from a socket in passive mode. Optional parameter
<c><anno>Timeout</anno></c> specifies a time-out in milliseconds.
- Defaults to <c>infinity</c>.</p>
+ Defaults to <c>infinity</c>.
+ </p>
+ <p>
+ If any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, the <c><anno>RecvData</anno></c> tuple contains an
+ <c><anno>AncData</anno></c> field,
+ otherwise it does not.
+ </p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index f281d61459..ed775d67eb 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -177,6 +177,27 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
+ <name name="ancillary_data"/>
+ <desc>
+ <p>
+ Ancillary data received with the data packet
+ or read with the socket option
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ from a TCP socket.
+ </p>
+ <p>
+ The value(s) correspond to the currently active socket
+ <seealso marker="#type-socket_setopt">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ and
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
@@ -344,7 +365,11 @@ fe80::204:acff:fe17:bf38
<desc>
<p>Gets one or more options for a socket. For a list of available
options, see
- <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.</p>
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ See also the description for the type
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>gen_tcp:pktoptions_value()</c>
+ </seealso>.</p>
<p>The number of elements in the returned
<c><anno>OptionValues</anno></c>
list does not necessarily correspond to the number of options
@@ -360,7 +385,7 @@ fe80::204:acff:fe17:bf38
socket options not (explicitly) supported by the emulator. The
use of raw socket options makes the code non-portable, but
allows the Erlang programmer to take advantage of unusual features
- present on the current platform.</p>
+ present on a particular platform.</p>
<p><c>RawOptReq</c> consists of tag <c>raw</c> followed
by the protocol level, the option number, and either a binary
or the size, in bytes, of the
@@ -1115,6 +1140,100 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
the socket. You are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to retrieve the size set by your operating system.</p>
+ <marker id="option-recvtclass"></marker>
+ </item>
+ <tag><c>{recvtclass, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TCLASS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IPV6</c>
+ option <c>IPV6_RECVTCLASS</c> or <c>IPV6_2292RECVTCLASS</c>
+ for the socket.
+ The value is returned as a <c>{tclass,TCLASS}</c> tuple
+ regardless of if the platform returns an <c>IPV6_TCLASS</c>
+ or an <c>IPV6_RECVTCLASS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TCLASS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TCLASS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvtos"></marker>
+ </item>
+ <tag><c>{recvtos, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TOS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTOS</c>
+ for the socket.
+ The value is returned as a <c>{tos,TOS}</c> tuple
+ regardless of if the platform returns an <c>IP_TOS</c>
+ or an <c>IP_RECVTOS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TOS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TOS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvttl"></marker>
+ </item>
+ <tag><c>{recvttl, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TTL</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTTL</c>
+ for the socket.
+ The value is returned as a <c>{ttl,TTL}</c> tuple
+ regardless of if the platform returns an <c>IP_TTL</c>
+ or an <c>IP_RECVTTL</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TTL</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TTL</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
</item>
<tag><c>{reuseaddr, Boolean}</c></tag>
<item>
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index bf795ee9c6..d893d44079 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -66,7 +66,12 @@
{sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
{sctp_status, #sctp_status{}} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()}.
-type option_name() ::
active |
buffer |
@@ -97,7 +102,12 @@
sctp_set_peer_primary_addr |
sctp_status |
sndbuf |
- tos.
+ tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl.
-type sctp_socket() :: port().
-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]).
@@ -365,7 +375,7 @@ send(S, AssocChange, Stream, Data) ->
Socket :: sctp_socket(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
@@ -382,7 +392,7 @@ recv(S) ->
Timeout :: timeout(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index c61411e814..7f7833ec23 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -62,7 +62,14 @@
{show_econnreset, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
+-type pktoptions_value() ::
+ {pktoptions, inet:ancillary_data()}.
-type option_name() ::
active |
buffer |
@@ -81,6 +88,7 @@
nodelay |
packet |
packet_size |
+ pktoptions |
priority |
{raw,
Protocol :: non_neg_integer(),
@@ -94,6 +102,12 @@
show_econnreset |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type connect_option() ::
{ip, inet:socket_address()} |
@@ -119,7 +133,7 @@
-type socket() :: port().
-export_type([option/0, option_name/0, connect_option/0, listen_option/0,
- socket/0]).
+ socket/0, pktoptions_value/0]).
%%
%% Connect a socket
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 44eef9f3c5..d6e8652e77 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -51,6 +51,11 @@
{reuseaddr, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
-type option_name() ::
active |
@@ -76,6 +81,12 @@
reuseaddr |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type socket() :: port().
@@ -147,11 +158,13 @@ send(S, Packet) when is_port(S) ->
end.
-spec recv(Socket, Length) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -164,12 +177,14 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
end.
-spec recv(Socket, Length, Timeout) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 73c53b9011..5dd68dc285 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -76,7 +76,7 @@
-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
- socket_setopt/0, socket_getopt/0,
+ socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -163,6 +163,9 @@
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
+-type ancillary_data() ::
+ [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
+
%%% ---------------------------------
-spec get_rc() -> [{Par :: atom(), Val :: any()} |
@@ -302,7 +305,7 @@ setopts(Socket, Opts) ->
{'ok', OptionValues} | {'error', posix()} when
Socket :: socket(),
Options :: [socket_getopt()],
- OptionValues :: [socket_setopt()].
+ OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
getopts(Socket, Opts) ->
case prim_inet:getopts(Socket, Opts) of
@@ -722,6 +725,7 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
@@ -790,6 +794,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
@@ -870,7 +875,7 @@ tcp_module_1(Opts, Address) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
[tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
- deliver, ipv6_v6only,
+ recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
high_msgq_watermark, low_msgq_watermark, bind_to_device].
@@ -940,8 +945,10 @@ udp_module(Opts) ->
% (*) passing of open FDs ("fdopen") is not supported.
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
- mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
+ mode, active, buffer, tos, tclass, ttl,
+ priority, dontroute, reuseaddr, linger,
+ recvtos, recvtclass, recvttl,
+ sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
bind_to_device,
% Other options are SCTP-specific (though they may be similar to their
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index a0d5d3df70..347b8b9a1b 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -167,7 +167,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -175,13 +175,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tclass, recvtclass].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 357e27826c..c8e09d18ad 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -157,6 +157,11 @@
-define(INET_LOPT_LINE_DELIM, 40).
-define(INET_OPT_TCLASS, 41).
-define(INET_OPT_BIND_TO_DEVICE, 42).
+-define(INET_OPT_RECVTOS, 43).
+-define(INET_OPT_RECVTCLASS, 44).
+-define(INET_OPT_PKTOPTIONS, 45).
+-define(INET_OPT_TTL, 46).
+-define(INET_OPT_RECVTTL, 47).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index dac6b3119d..f1e3116856 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -164,7 +164,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -172,13 +172,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tos, ttl, recvtos, recvttl].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 950f5bea6f..d532537eb9 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -41,6 +41,7 @@
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
partial_recv_and_close_2/1,partial_recv_and_close_3/1,so_priority/1,
+ recvtos/1, recvttl/1, recvtosttl/1, recvtclass/1,
%% Accept tests
primitive_accept/1,multi_accept_close_listen/1,accept_timeout/1,
accept_timeouts_in_order/1,accept_timeouts_in_order2/1,
@@ -83,7 +84,8 @@ all() ->
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
partial_recv_and_close_2, partial_recv_and_close_3,
- so_priority, primitive_accept,
+ so_priority, recvtos, recvttl, recvtosttl,
+ recvtclass, primitive_accept,
multi_accept_close_listen, accept_timeout,
accept_timeouts_in_order, accept_timeouts_in_order2,
accept_timeouts_in_order3, accept_timeouts_in_order4,
@@ -1914,6 +1916,209 @@ so_priority(Config) when is_list(Config) ->
end
end.
+
+
+%% IP_RECVTOS and IP_RECVTCLASS for IP_PKTOPTIONS
+%% does not seem to be implemented in Linux until kernel 3.0
+
+recvtos(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2,
+ false).
+
+recvtosttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end,
+ false).
+
+recvttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2,
+ false).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_pktoptions(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2,
+ true);
+ [] ->
+ {skip,{ipv6_not_supported,IFs}}
+ end.
+
+%% These version numbers are the highest noted in daily tests
+%% where the test fails for a plausible reason, so
+%% skip on that platform.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Does not return any value - not implemented for pktoptions
+recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,linux}, _) -> true;
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+%% Using the option returns einval up to 0.9.0, so it is not implemented.
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_pktoptions(Family, Spec, OSFilter, CheckAccept) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_pktoptions(Family, Spec, CheckAccept, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_pktoptions(Family, Spec, CheckAccept, OSType, OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ Address =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ %% Set RecvOpts on listen socket
+ {ok,L} =
+ gen_tcp:listen(
+ 0,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts]),
+ {ok,P} = inet:port(L),
+ {ok,TrueRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts and Option values on connect socket
+ {ok,S2} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts ++ OptsVals],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S2, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S1} = gen_tcp:accept(L, Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S1, Opts),
+%%% %%
+%%% %% Handshake
+%%% ok = gen_tcp:send(S1, <<"hello">>),
+%%% {ok,<<"hello">>} = gen_tcp:recv(S2, 5, Timeout),
+%%% ok = gen_tcp:send(S2, <<"hi">>),
+%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
+ {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
+ (Result1 = sets_eq(OptsVals1, OptsVals))
+ orelse io:format(
+ "Accept differs: ~p neq ~p~n", [OptsVals1,OptsVals]),
+ (Result2 = sets_eq(OptsVals2, OptsValsDefault))
+ orelse io:format(
+ "Connect differs: ~p neq ~p~n",
+ [OptsVals2,OptsValsDefault]),
+ %%
+ ok = gen_tcp:close(S2),
+ ok = gen_tcp:close(S1),
+ %%
+ %%
+ %% Clear RecvOpts on listen socket and set Option values
+ ok = inet:setopts(L, FalseRecvOpts ++ OptsVals),
+ {ok,FalseRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsVals} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts on connecting socket
+ %%
+ {ok,S4} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S4, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S4, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S3} = gen_tcp:accept(L, Timeout),
+ {ok,FalseRecvOpts} = inet:getopts(S3, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S3, Opts),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,[]}]} = inet:getopts(S3, [pktoptions]),
+ {ok,[{pktoptions,OptsVals4}]} = inet:getopts(S4, [pktoptions]),
+ (Result3 = sets_eq(OptsVals4, OptsVals))
+ orelse io:format(
+ "Accept2 differs: ~p neq ~p~n", [OptsVals4,OptsVals]),
+ %%
+ ok = gen_tcp:close(S4),
+ ok = gen_tcp:close(S3),
+ ok = gen_tcp:close(L),
+ (Result1 and ((not CheckAccept) or (Result2 and Result3)))
+ orelse
+ exit({failed,
+ [{OptsVals1,OptsVals4,OptsVals},
+ {OptsVals2,OptsValsDefault}],
+ {OSType,OSVer}}),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+sets_eq(L1, L2) ->
+ lists:sort(L1) == lists:sort(L2).
+
+
+
%% Accept test utilities (suites are below)
millis() ->
@@ -2205,7 +2410,7 @@ wait_until_accepting(Proc,0) ->
exit({timeout_waiting_for_accepting,Proc});
wait_until_accepting(Proc,N) ->
case process_info(Proc,current_function) of
- {current_function,{prim_inet,accept0,2}} ->
+ {current_function,{prim_inet,accept0,3}} ->
case process_info(Proc,status) of
{status,waiting} ->
ok;
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 3acfff929e..878e48786c 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -36,6 +36,7 @@
-export([send_to_closed/1, active_n/1,
buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -47,6 +48,7 @@ all() ->
[send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
+ recvtos, recvtosttl, recvttl, recvtclass,
{group, local}].
groups() ->
@@ -572,6 +574,167 @@ active_n(Config) when is_list(Config) ->
ok.
+
+recvtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2).
+
+recvtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end).
+
+recvttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
+%% These version numbers are just above the highest noted in daily tests
+%% where the test fails for a plausible reason, that is the lowest
+%% where we can expect that the test mighe succeed, so
+%% skip on platforms lower than this.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,11,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_recv_opts(Family, Spec, OSFilter) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_recv_opts(Family, Spec, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ TrueRecvOpts_OptsVals = TrueRecvOpts ++ OptsVals,
+ Addr =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ {ok,S1} =
+ gen_udp:open(0, [Family,binary,{active,false}|TrueRecvOpts]),
+ {ok,P1} = inet:port(S1),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
+ {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
+ %%
+ {ok,S2} =
+ gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
+ {ok,P2} = inet:port(S2),
+ {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
+ OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals3, OptsVals2),
+ receive
+ {udp,S2,_,P1,<<"fghij">>} ->
+ ok;
+ Other1 ->
+ exit({unexpected,Other1})
+ after Timeout ->
+ exit(timeout)
+ end,
+ %%
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S2, TrueRecvOpts),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
+ receive
+ {udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
+ verify_sets_eq(OptsVals4, OptsVals);
+ Other2 ->
+ exit({unexpected,Other2})
+ after Timeout ->
+ exit(timeout)
+ end,
+ ok = gen_udp:close(S1),
+ ok = gen_udp:close(S2),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+verify_sets_eq(L1, L2) ->
+ L = lists:sort(L1),
+ case lists:sort(L2) of
+ L ->
+ ok;
+ _ ->
+ exit({sets_neq,L1,L2})
+ end.
+
+
local_basic(_Config) ->
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index f64e0cca97..1607363ad1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -48,7 +48,7 @@
</list>
</section>
-</section>
+ </section>
<section><title>SNMP 5.2.10</title>
diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml
index 801193675c..480ed2e825 100644
--- a/lib/snmp/doc/src/snmp.xml
+++ b/lib/snmp/doc/src/snmp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -341,10 +341,10 @@
</func>
<func>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -355,6 +355,9 @@
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
<v>Block = boolean()</v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -394,16 +397,25 @@
and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual
version of the protocol data unit. There is a new line
between <c>Vsn</c> and <c>PDU</c>.</p>
+
+ <p>If the entire log is successfully converted, the function
+ will return <c>ok</c>.
+ If one of more entries fail to convert, the function will instead
+ return <c>{ok, {NumOK, NumERR}}</c>, where the counters indicate
+ how many valid and erroneous entries where found.
+ If instead <c>{error, Reason}</c> is returned, the conversion
+ encountered a fatal error and where either never done of aborted
+ midway. </p>
<marker id="log_to_io"></marker>
</desc>
</func>
<func>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -412,6 +424,9 @@
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index d756ff7a65..b78f14da01 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -559,13 +559,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -576,6 +576,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -597,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -614,6 +617,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 4818aeb697..be4cd58a1a 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1216,13 +1216,13 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1233,6 +1233,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -1254,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
<name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1272,6 +1275,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index ecf9498ca9..afed4482d2 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. 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.
@@ -137,11 +137,10 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
proc_lib:init_ack({ok, self()}),
try loop(State)
catch
- C:E when C =/= exit, E =/= shutdown ->
+ C:E:S when C =/= exit, E =/= shutdown ->
Fmt =
"loop/1 EXCEPTION ~w:~w~n"
" ~p",
- S = erlang:get_stacktrace(),
case C of
exit ->
%% Externally killed, root cause is elsewhere
@@ -647,10 +646,10 @@ maybe_handle_recv(
case
try FilterMod:accept_recv(From_1, From_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p",
- [From_1,From_2,Class,Exception,erlang:get_stacktrace()]),
+ [From_1, From_2, Class, Exception, StackTrace]),
true
end
of
@@ -753,12 +752,11 @@ maybe_handle_recv_pdu(
case
try FilterMod:accept_recv_pdu(From_1, From_2, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n"
" ~p",
- [From_1,From_2,Type,Class,Exception,
- erlang:get_stacktrace()]),
+ [From_1, From_2, Type, Class, Exception, StackTrace]),
true
end
of
@@ -834,11 +832,10 @@ maybe_handle_reply_pdu(
try
FilterMod:accept_send_pdu(Addresses, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [Addresses, Type, Class, Exception,
- erlang:get_stacktrace()]),
+ [Addresses, Type, Class, Exception, StackTrace]),
true
end
of
@@ -872,7 +869,7 @@ handle_reply_pdu(
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- try maybe_udp_send(S, Transport, To, Packet)
+ try maybe_udp_send_wo_log(S, Transport, To, Packet)
catch
{Reason, Sz} ->
error_msg("Cannot send message "
@@ -917,11 +914,10 @@ maybe_handle_send_pdu(
case
try FilterMod:accept_send_pdu(AddressesToFilter, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [AddressesToFilter,Type,
- Class,Exception,erlang:get_stacktrace()]),
+ [AddressesToFilter, Type, Class, Exception, StackTrace]),
true
end
of
@@ -1049,46 +1045,36 @@ do_handle_send_pdu(S, Type, Pdu, Addresses) ->
[Sz, Reason, Pdu])
end.
-do_handle_send_pdu1(
- #state{transports = Transports} = S,
- Type, Addresses) ->
+do_handle_send_pdu1(S, Type, Addresses) ->
lists:foreach(
- fun ({Domain, Address, Packet}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet)
- end;
- ({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending encrypted packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet, Type, LogData)
- end
+ fun ({Domain, Address, Pkg}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, Pkg, "");
+ ({Domain, Address, {Pkg, LogPkg}}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, LogPkg, " encrypted")
end,
Addresses).
-maybe_udp_send(
+do_handle_send_pdu2(#state{transports = Transports} = S,
+ Type, Domain, Address, Pkg, LogPkg, EncrStr) ->
+ ?vdebug("[~w] sending~s packet:"
+ "~n size: ~p"
+ "~n to: ~p", [Domain, EncrStr, sz(Pkg), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg("Can not find transport: "
+ "~n size: ~p"
+ "~n to: ~s",
+ [sz(Pkg), format_address(To)]);
+ Transport ->
+ maybe_udp_send_w_log(S, Transport, To, Pkg, LogPkg, Type)
+ end.
+
+
+%% This function is used when logging has already been done!
+maybe_udp_send_wo_log(
#state{filter = FilterMod, transports = Transports},
#transport{socket = Socket},
To, Packet) ->
@@ -1096,10 +1082,10 @@ maybe_udp_send(
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p",
- [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1118,18 +1104,18 @@ maybe_udp_send(
udp_send(Socket, To, Packet)
end.
-maybe_udp_send(
+maybe_udp_send_w_log(
#state{log = Log, filter = FilterMod, transports = Transports},
#transport{socket = Socket},
- To, Packet, Type, _LogData) ->
+ To, Pkg, LogPkg, Type) ->
{To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
- [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1143,10 +1129,10 @@ maybe_udp_send(
_ ->
error_msg(
"FilterMod:accept_send(~p, ~p) returned: ~p",
- [To_1,To_2,Other])
+ [To_1, To_2, Other])
end,
- log(Log, Type, Packet, To),
- udp_send(Socket, To, Packet)
+ log(Log, Type, LogPkg, To),
+ udp_send(Socket, To, Pkg)
end.
udp_send(Socket, To, B) ->
@@ -1168,11 +1154,10 @@ udp_send(Socket, To, B) ->
ok ->
ok
catch
- error:ExitReason ->
+ error:ExitReason:StackTrace ->
error_msg("[exit] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
- [IpAddr, IpPort, sz(B), ExitReason,
- erlang:get_stacktrace()])
+ [IpAddr, IpPort, sz(B), ExitReason, StackTrace])
end.
sz(L) when is_list(L) -> length(L);
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index 7f627d66d9..c810bfcd41 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -169,11 +169,7 @@ get_version() ->
MI = ?MODULE:module_info(),
Attr = get_info(attributes, MI),
Vsn = get_info(app_vsn, Attr),
- Comp = get_info(compile, MI),
- Time = get_info(time, Comp),
- {Year, Month, Day, Hour, Min, Sec} = Time,
- io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
- [Vsn, Year, Month, Day, Hour, Min, Sec]).
+ Vsn.
maybe_display_options(Opts) ->
case lists:member(options, Opts) of
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 767d801eee..5713c14912 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. 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.
@@ -649,13 +649,14 @@ do_log_to_file(Log, TextFile, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format(Fd, "~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format(Fd, "~s", [S]),
+ Tag;
+ Ignore ->
+ Ignore
end
end,
- Res = (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
file:close(Fd),
Res;
@@ -668,39 +669,63 @@ do_log_to_io(Log, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format("~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format("~s", [S]),
+ Tag;
+ X ->
+ X
end
end,
- (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
- ok.
+ Res.
+
+loop(Log, Write) ->
+ loop(disk_log:chunk(Log, start), Log, Write, 0, 0).
-loop(eof, _Log, _Write) ->
+loop(eof, _Log, _Write, _NumOK, 0 = _NumERR) ->
ok;
-loop({error, _} = Error, _Log, _Write) ->
+loop(eof, _Log, _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop({error, _} = Error, _Log, _Write, _NumOK, _NumERR) ->
Error;
-loop({Cont, Terms}, Log, Write) ->
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
+loop({Cont, Terms}, Log, Write, NumOK, NumERR) ->
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
end;
-loop({Cont, Terms, BadBytes}, Log, Write) ->
+loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) ->
error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n",
[BadBytes, Log]),
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
- end;
-loop(Error, _Log, _Write) ->
- Error.
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
+ end.
+
+
+loop_terms(Terms, Write) ->
+ loop_terms(Terms, Write, 0, 0).
+
+loop_terms([], _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop_terms([Term|Terms], Write, NumOK, NumERR) ->
+ case Write(Term) of
+ ok ->
+ loop_terms(Terms, Write, NumOK+1, NumERR);
+ error ->
+ loop_terms(Terms, Write, NumOK, NumERR+1);
+ _ ->
+ loop_terms(Terms, Write, NumOK, NumERR)
+ end.
format_msg(Entry, Mib, Start, Stop) ->
@@ -733,88 +758,149 @@ do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) ->
%% This is crap...
do_format_msg(_, _) ->
- format_tab("** unknown entry in log file\n\n", []).
+ {error, format_tab("** unknown entry in log file\n\n", [])}.
do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), AddrStr, Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab("** error in log file ~p\n\n", [Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, AddrStr, DecT, DecE)
+
end.
-
+
+sm2atom(?SEC_ANY) -> any;
+sm2atom(?SEC_V1) -> v1;
+sm2atom(?SEC_V2C) -> v2c;
+sm2atom(?SEC_USM) -> usm;
+sm2atom(_) -> unknown.
+
do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end.
-
-
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}},
-%% Mib, Start, Stop) ->
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop);
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
-%% ScopedPDU when record(ScopedPDU, scopedPdu) ->
-%% Msg = #message{version = 'version-3',
-%% vsn_hdr = V3Hdr,
-%% data = ScopedPDU},
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
-%% [ts2str(TimeStamp), ip(Addr), Port, Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) ->
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop);
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
-%% Msg when record(Msg, message) ->
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file ~p\n\n", [Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg(_, _Mib, _Start, _Stop) ->
-%% format_tab("** unknown entry in log file\n\n", []).
+
+
+format_error(WhatStr, TimeStamp, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~w: ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, T, E]),
+ {error, Str}.
+
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~w, ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, T, E]),
+ {error, Str}.
+
f(TimeStamp, SeqNo,
#message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
@@ -838,51 +924,21 @@ f(TimeStamp, SeqNo,
end,
format_tab(
"~w ~s - ~s [~s]~s ~w\n~s",
- [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f(TimeStamp, SeqNo,
-%% #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
-%% Addr, Port, Mib) ->
-%% Str = format_pdu(Data, Mib),
-%% HdrStr = format_header(Vsn, VsnHdr),
-%% case get_type(Data) of
-%% trappdu ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'snmpv2-trap' ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'inform-request' ->
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'get-response' ->
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% report ->
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% _ ->
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
-%% end.
-
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]);
+f(TimeStamp, SeqNo, Msg, AddrStr, _Mib) ->
+ io:format("<ERROR> Unexpected data: "
+ "~n TimeStamp: ~s~s"
+ "~n Msg: ~p"
+ "~n AddrStr: ~p"
+ "~n", [TimeStamp, SeqNo, Msg, AddrStr]),
+ throw({error, 'invalid-message'}).
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
ipPort2Str(Ip, Port) ->
snmp_conf:mk_addr_string({Ip, Port}).
- %% io_lib:format("~s:~w", [ip(Ip), Port]).
%% Convert a timestamp 2-tupple to a printable string
%%
@@ -973,7 +1029,13 @@ format_pdu(#scopedPdu{contextName = Context, data = Pdu}, Mib) ->
io_lib:format("Context: \"~s\"\n~s",
[Context, snmp_misc:format_pdu(Pdu, Mib)]);
format_pdu(Pdu, Mib) ->
- snmp_misc:format_pdu(Pdu, Mib).
+ try snmp_misc:format_pdu(Pdu, Mib) of
+ Str ->
+ Str
+ catch
+ _:_ ->
+ throw({error, 'invalid-pdu'})
+ end.
get_type(#scopedPdu{data = Pdu}) ->
get_type(Pdu);
@@ -983,12 +1045,6 @@ get_type(#pdu{type = Type}) ->
Type.
-%% ip(Domain, Addr) ->
-%% snmp_conf:mk_addr_string(Domain, Addr).
-%% ip({A,B,C,D}) ->
-%% io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
-
-
%% -------------------------------------------------------------------
%% Various utility functions
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 96123f02f5..4d5a0fbce8 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. 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.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.11
+SNMP_VSN = 5.2.12
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index f8c54fb79a..ad006f9a2b 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -1023,7 +1023,7 @@ ets:select(Table, MatchSpec),</code>
be used in subsequent operations. The table identifier can be
sent to other processes so that a table can be shared between
different processes within a node.</p>
- <p>Parameter <c><anno>Options</anno></c> is a list of atoms that
+ <p>Parameter <c><anno>Options</anno></c> is a list of options that
specifies table type, access rights, key position, and whether the
table is named. Default values are used for omitted options.
This means that not specifying any options (<c>[]</c>) is the same