aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/nifs/common/socket_nif.c54
-rw-r--r--erts/preloaded/src/socket.erl28
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);