From f7f70b94f90b1f500cb884be8ae722e1a22acf2e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 8 May 2018 11:47:43 +0200 Subject: [socket-nif] setopt of (tcp) congestion --- erts/emulator/nifs/common/socket_nif.c | 54 +++++++++++++++++++++++++++++++++- erts/preloaded/src/socket.erl | 28 ++++++++++++++---- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index f4d2fbf021..11085ddab5 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -236,6 +236,14 @@ typedef unsigned long long llu_t; /* *** Misc macros and defines *** */ +#if defined(TCP_CA_NAME_MAX) +#define SOCKET_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 +#endif + + /* *** Socket state defs *** */ #define SOCKET_FLAG_OPEN 0x0001 @@ -349,14 +357,19 @@ typedef union { #define SOCKET_OPT_OTP_DEBUG 0 #define SOCKET_OPT_OTP_IOW 1 + #define SOCKET_OPT_SOCK_KEEPALIVE 0 #define SOCKET_OPT_SOCK_LINGER 1 + #define SOCKET_OPT_IP_RECVTOS 0 #define SOCKET_OPT_IP_ROUTER_ALERT 1 #define SOCKET_OPT_IP_TOS 2 #define SOCKET_OPT_IP_TTL 3 + #define SOCKET_OPT_IPV6_HOPLIMIT 0 -#define SOCKET_OPT_TCP_MAXSEG 0 + +#define SOCKET_OPT_TCP_CONGESTION 0 +#define SOCKET_OPT_TCP_MAXSEG 1 /* =================================================================== * @@ -601,6 +614,7 @@ typedef struct { #define SOCKET_OPT_VALUE_INT 2 #define SOCKET_OPT_VALUE_LINGER 3 #define SOCKET_OPT_VALUE_BIN 4 +#define SOCKET_OPT_VALUE_STR 5 typedef struct { unsigned int tag; @@ -609,6 +623,10 @@ typedef struct { int intVal; struct linger lingerVal; ErlNifBinary binVal; + struct { + unsigned int len; + char* str; + } strVal; } u; /* void* optValP; // Points to the actual data (above) @@ -3157,6 +3175,18 @@ ERL_NIF_TERM nsetopt_gen(ErlNifEnv* env, } break; + case SOCKET_OPT_VALUE_STR: + { + optLen = valP->u.strVal.len; + res = socket_setopt(descP->sock, level, opt, + valP->u.strVal.str, optLen); + if (res != 0) + result = make_error2(env, res); + else + result = atom_ok; + } + break; + default: result = make_error(env, atom_einval); } @@ -3531,6 +3561,26 @@ BOOLEAN_T eoptval2optval_tcp(ErlNifEnv* env, SocketOptValue* valP) { switch (eOpt) { +#if defined(TCP_CONGESTION) + case SOCKET_OPT_TCP_CONGESTION: + { + valP->u.strVal.len = SOCKET_OPT_TCP_CONGESTION_NAME_MAX+1; + valP->u.strVal.str = MALLOC(valP->u.strVal.len); + + if (GET_STR(env, eVal, valP->u.strVal.str, valP->u.strVal.len) > 0) { + valP->tag = SOCKET_OPT_VALUE_STR; + *opt = TCP_CONGESTION; + return TRUE; + } else { + FREE(valP->u.strVal.str); + *opt = -1; + valP->tag = SOCKET_OPT_VALUE_UNDEF; + return FALSE; + } + } + break; +#endif + #if defined(TCP_MAXSEG) case SOCKET_OPT_TCP_MAXSEG: if (!GET_INT(env, eVal, &valP->u.intVal)) { @@ -3538,6 +3588,8 @@ BOOLEAN_T eoptval2optval_tcp(ErlNifEnv* env, *opt = TCP_MAXSEG; return TRUE; } else { + *opt = -1; + valP->tag = SOCKET_OPT_VALUE_UNDEF; return FALSE; } break; diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl index 5bea039783..1304e79c99 100644 --- a/erts/preloaded/src/socket.erl +++ b/erts/preloaded/src/socket.erl @@ -267,8 +267,7 @@ -type tcp_socket_option() :: congestion | maxseg | - nodelay | - user_timeout. + nodelay. -type udp_socket_option() :: checksum | maxdgram | @@ -440,7 +439,8 @@ -define(SOCKET_OPT_IPV6_HOPLIMIT, 0). --define(SOCKET_OPT_TCP_MAXSEG, 0). +-define(SOCKET_OPT_TCP_CONGESTION, 0). +-define(SOCKET_OPT_TCP_MAXSEG, 1). -define(SOCKET_SHUTDOWN_HOW_READ, 0). -define(SOCKET_SHUTDOWN_HOW_WRITE, 1). @@ -1633,11 +1633,21 @@ enc_setopt_value(ipv6, hoplimit, V, _D, T, _P) enc_setopt_value(ipv6 = L, Opt, V, _D, _T, _P) -> not_supported({L, Opt, V}); +enc_setopt_value(tcp, congetsion, V, _D, T, P) + when is_list(V) andalso + (T =:= stream) andalso + (P =:= tcp) -> + V; enc_setopt_value(tcp, maxseg, V, _D, T, P) when is_integer(V) andalso (T =:= stream) andalso (P =:= tcp) -> V; +enc_setopt_value(tcp, nodelay, V, _D, T, P) + when is_boolean(V) andalso + (T =:= stream) andalso + (P =:= tcp) -> + V; enc_setopt_value(tcp = L, Opt, V, _D, _T, _P) -> not_supported({L, Opt, V}); @@ -1880,8 +1890,8 @@ enc_sockopt_key(ip, recvttl = Opt, _Dir, _D, T, _P) when (T =/= stream) -> not_supported(Opt); enc_sockopt_key(ip, retopts = Opt, _Dir, _D, _T, _P) -> not_supported(Opt); -enc_sockopt_key(ip, router_alert = Opt, _Dir, _D, raw = _T, _P) -> - not_supported(Opt); +enc_sockopt_key(ip, router_alert = _Opt, _Dir, _D, raw = _T, _P) -> + ?SOCKET_OPT_IP_ROUTER_ALERT; %% On FreeBSD it specifies that this option is only valid %% for stream, dgram and "some" raw sockets... %% No such condition on linux (in the man page)... @@ -1904,6 +1914,14 @@ enc_sockopt_key(ipv6, UnknownOpt, _Dir, _D, _T, _P) -> unknown(UnknownOpt); %% TCP socket options +%% There are other options that would be useful; info, +%% but they are difficult to get portable... +enc_sockopt_key(tcp, congestion = _Opt, _Dir, _D, _T, _P) -> + ?SOCKET_OPT_TCP_CONGESTION; +enc_sockopt_key(tcp, maxseg = _Opt, _Dir, _D, _T, _P) -> + ?SOCKET_OPT_TCP_MAXSEG; +enc_sockopt_key(tcp, nodelay = Opt, _Dir, _D, _T, _P) -> + not_supported(Opt); enc_sockopt_key(tcp, UnknownOpt, _Dir, _D, _T, _P) -> unknown(UnknownOpt); -- cgit v1.2.3