From 1a3aca0a849af0bae994c9cf89de0dcfe7b310c2 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 18 Jul 2018 12:05:00 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option mtu_discover Added support for the VPv6 socket option MTU_DISCOVER. OTP-14831. --- erts/emulator/nifs/common/socket_nif.c | 190 +++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) (limited to 'erts/emulator') diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index 0222d58e6d..d2f7e21ad0 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -389,6 +389,7 @@ typedef union { #define SOCKET_OPT_IPV6_DROP_MEMBERSHIP 6 #define SOCKET_OPT_IPV6_HOPLIMIT 12 #define SOCKET_OPT_IPV6_MTU 17 +#define SOCKET_OPT_IPV6_MTU_DISCOVER 18 #define SOCKET_OPT_IPV6_V6ONLY 33 #define SOCKET_OPT_TCP_CONGESTION 1 @@ -1014,6 +1015,11 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env, SocketDescriptor* descP, ERL_NIF_TERM eVal); #endif +#if defined(IPV6_MTU_DISCOVER) +static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env, + SocketDescriptor* descP, + ERL_NIF_TERM eVal); +#endif #if defined(IPV6_V6ONLY) static ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env, SocketDescriptor* descP, @@ -1237,6 +1243,10 @@ static ERL_NIF_TERM ngetopt_lvl_ipv6_hoplimit(ErlNifEnv* env, static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env, SocketDescriptor* descP); #endif +#if defined(IPV6_MTU_DISCOVER) +static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env, + SocketDescriptor* descP); +#endif #if defined(IPV6_V6ONLY) static ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env, SocketDescriptor* descP); @@ -1451,6 +1461,16 @@ static void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal); #endif +#if defined(IPV6_MTU_DISCOVER) +static char* decode_ipv6_pmtudisc(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IPV6_MTU_DISCOVER) +static void encode_ipv6_pmtudisc(ErlNifEnv* env, + int val, + ERL_NIF_TERM* eVal); +#endif /* static BOOLEAN_T decode_bool(ErlNifEnv* env, @@ -4977,6 +4997,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env, break; #endif +#if defined(IPV6_MTU_DISCOVER) + case SOCKET_OPT_IPV6_MTU_DISCOVER: + result = nsetopt_lvl_ipv6_mtu_discover(env, descP, eVal); + break; +#endif + #if defined(IPV6_V6ONLY) case SOCKET_OPT_IPV6_V6ONLY: result = nsetopt_lvl_ipv6_v6only(env, descP, eVal); @@ -5038,6 +5064,42 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env, #endif +/* nsetopt_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, + SocketDescriptor* descP, + ERL_NIF_TERM eVal) +{ + ERL_NIF_TERM result; + int val; + char* xres; + int res; + + if ((xres = decode_ipv6_pmtudisc(env, eVal, &val)) != NULL) { + + result = esock_make_error_str(env, xres); + + } else { + + res = socket_setopt(descP->sock, SOL_IPV6, IPV6_MTU_DISCOVER, + &val, sizeof(val)); + + if (res != 0) + result = esock_make_error_errno(env, sock_errno()); + else + result = esock_atom_ok; + + } + + return result; +} +#endif + + #if defined(IPV6_V6ONLY) static ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env, @@ -6731,6 +6793,12 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env, break; #endif +#if defined(IPV6_MTU_DISCOVER) + case SOCKET_OPT_IPV6_MTU_DISCOVER: + result = ngetopt_lvl_ipv6_mtu_discover(env, descP); + break; +#endif + #if defined(IPV6_V6ONLY) case SOCKET_OPT_IPV6_V6ONLY: result = ngetopt_lvl_ipv6_v6only(env, descP); @@ -6771,6 +6839,35 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env, #endif +/* ngetopt_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, + SocketDescriptor* descP) +{ + ERL_NIF_TERM result; + ERL_NIF_TERM eMtuDisc; + int mtuDisc; + SOCKOPTLEN_T mtuDiscSz = sizeof(mtuDisc); + int res; + + res = sock_getopt(descP->sock, SOL_IPV6, IPV6_MTU_DISCOVER, + &mtuDisc, &mtuDiscSz); + + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + encode_ipv6_pmtudisc(env, mtuDisc, &eMtuDisc); + result = esock_make_ok2(env, eMtuDisc); + } + + return result; + +} +#endif + + #if defined(IPV6_V6ONLY) static ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env, @@ -7723,6 +7820,57 @@ char* decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) +/* +++ decode the ipv6 socket option MTU_DISCOVER +++ + * The (ip) option can be provide in two ways: + * + * atom() | integer() + * + * When its an atom it can have the values: + * + * want | dont | do | probe + * + */ +#if defined(IPV6_MTU_DISCOVER) +static +char* decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) +{ + char* res = NULL; + + if (IS_ATOM(env, eVal)) { + + if (COMPARE(eVal, atom_want) == 0) { + *val = IPV6_PMTUDISC_WANT; + } else if (COMPARE(eVal, atom_dont) == 0) { + *val = IPV6_PMTUDISC_DONT; + } else if (COMPARE(eVal, atom_do) == 0) { + *val = IPV6_PMTUDISC_DO; + } else if (COMPARE(eVal, atom_probe) == 0) { + *val = IPV6_PMTUDISC_PROBE; + } else { + *val = -1; + res = ESOCK_STR_EINVAL; + } + + } else if (IS_NUM(env, eVal)) { + + if (!GET_INT(env, eVal, val)) { + *val = -1; + res = ESOCK_STR_EINVAL; + } + + } else { + + *val = -1; + res = ESOCK_STR_EINVAL; + + } + + return res; +} +#endif + + + /* +++ encode the ip socket option MTU_DISCOVER +++ * The (ip) option can be provide in two ways: * @@ -7765,6 +7913,48 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) +/* +++ encode the ipv6 socket option MTU_DISCOVER +++ + * The (ipv6) option can be provide in two ways: + * + * atom() | integer() + * + * If its one of the "known" values, it will be an atom: + * + * want | dont | do | probe + * + */ +#if defined(IPV6_MTU_DISCOVER) +static +void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) +{ + switch (val) { + case IPV6_PMTUDISC_WANT: + *eVal = atom_want; + break; + + case IPV6_PMTUDISC_DONT: + *eVal = atom_dont; + break; + + case IPV6_PMTUDISC_DO: + *eVal = atom_do; + break; + + case IPV6_PMTUDISC_PROBE: + *eVal = atom_probe; + break; + + default: + *eVal = MKI(env, val); + break; + } + + return; +} +#endif + + + /* +++ decocde the native getopt option +++ * The option is in this case provide in the form of a two tuple: * -- cgit v1.2.3