aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-13 14:42:34 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit5e0a36abaa984358f617541b102b4e4cbb112956 (patch)
tree0431de23a2aa25700b4bbb6696dd17551dd82160
parent416644989e26ac76038523511d81ebf9e0b8fc4f (diff)
downloadotp-5e0a36abaa984358f617541b102b4e4cbb112956.tar.gz
otp-5e0a36abaa984358f617541b102b4e4cbb112956.tar.bz2
otp-5e0a36abaa984358f617541b102b4e4cbb112956.zip
[socket-nif] Add support for socket (level socket) option bindtodevice
Added support for socket level socket option BINDTODEVICE. OTP-14831
-rw-r--r--erts/emulator/nifs/common/socket_nif.c246
-rw-r--r--erts/preloaded/ebin/socket.beambin46248 -> 46292 bytes
-rw-r--r--erts/preloaded/src/socket.erl28
-rw-r--r--lib/kernel/test/socket_server.erl51
4 files changed, 216 insertions, 109 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index d973633606..141b42a3cd 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -346,21 +346,22 @@ typedef union {
#define SOCKET_OPT_OTP_IOW 2
#define SOCKET_OPT_OTP_CTRL_PROC 3
-#define SOCKET_OPT_SOCK_ACCEPTCONN 1
-#define SOCKET_OPT_SOCK_BROADCAST 4
-#define SOCKET_OPT_SOCK_DEBUG 6
-#define SOCKET_OPT_SOCK_DOMAIN 7
-#define SOCKET_OPT_SOCK_DONTROUTE 8
-#define SOCKET_OPT_SOCK_KEEPALIVE 10
-#define SOCKET_OPT_SOCK_LINGER 11
-#define SOCKET_OPT_SOCK_OOBINLINE 13
-#define SOCKET_OPT_SOCK_PEEK_OFF 15
-#define SOCKET_OPT_SOCK_PRIORITY 17
-#define SOCKET_OPT_SOCK_PROTOCOL 18
-#define SOCKET_OPT_SOCK_RCVBUF 19
-#define SOCKET_OPT_SOCK_REUSEADDR 23
-#define SOCKET_OPT_SOCK_SNDBUF 27
-#define SOCKET_OPT_SOCK_TYPE 32
+#define SOCKET_OPT_SOCK_ACCEPTCONN 1
+#define SOCKET_OPT_SOCK_BINDTODEVICE 3
+#define SOCKET_OPT_SOCK_BROADCAST 4
+#define SOCKET_OPT_SOCK_DEBUG 6
+#define SOCKET_OPT_SOCK_DOMAIN 7
+#define SOCKET_OPT_SOCK_DONTROUTE 8
+#define SOCKET_OPT_SOCK_KEEPALIVE 10
+#define SOCKET_OPT_SOCK_LINGER 11
+#define SOCKET_OPT_SOCK_OOBINLINE 13
+#define SOCKET_OPT_SOCK_PEEK_OFF 15
+#define SOCKET_OPT_SOCK_PRIORITY 17
+#define SOCKET_OPT_SOCK_PROTOCOL 18
+#define SOCKET_OPT_SOCK_RCVBUF 19
+#define SOCKET_OPT_SOCK_REUSEADDR 23
+#define SOCKET_OPT_SOCK_SNDBUF 27
+#define SOCKET_OPT_SOCK_TYPE 32
#define SOCKET_OPT_IP_ADD_MEMBERSHIP 1
#define SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP 2
@@ -803,7 +804,14 @@ static ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
int eOpt,
ERL_NIF_TERM eVal);
+
/* *** Handling set of socket options for level = socket *** */
+
+#if defined(SO_BINDTODEVICE)
+static ERL_NIF_TERM nsetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(SO_BROADCAST)
static ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1080,6 +1088,10 @@ static ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sock_acceptconn(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(SO_BINDTODEVICE)
+static ERL_NIF_TERM ngetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(SO_BROADCAST)
static ERL_NIF_TERM ngetopt_lvl_sock_broadcast(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -3902,6 +3914,12 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
"\r\n", eOpt) );
switch (eOpt) {
+#if defined(SO_BINDTODEVICE)
+ case SOCKET_OPT_SOCK_BINDTODEVICE:
+ result = nsetopt_lvl_sock_bindtodevice(env, descP, eVal);
+ break;
+#endif
+
#if defined(SO_BROADCAST)
case SOCKET_OPT_SOCK_BROADCAST:
result = nsetopt_lvl_sock_broadcast(env, descP, eVal);
@@ -3977,6 +3995,19 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
}
+#if defined(SO_BINDTODEVICE)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_str_opt(env, descP,
+ SOL_SOCKET, SO_BROADCAST,
+ IFNAMSIZ, eVal);
+}
+#endif
+
+
#if defined(SO_BROADCAST)
static
ERL_NIF_TERM nsetopt_lvl_sock_broadcast(ErlNifEnv* env,
@@ -5111,38 +5142,6 @@ ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
-/* nsetopt_str_opt - set an option that has an string value
- */
-static
-ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
- SocketDescriptor* descP,
- int level,
- int opt,
- int max,
- ERL_NIF_TERM eVal)
-{
- ERL_NIF_TERM result;
- char* val = MALLOC(max);
-
- if (GET_STR(env, eVal, val, max) > 0) {
- int optLen = strlen(val);
- int res = socket_setopt(descP->sock, level, opt, &val, optLen);
-
- if (res != 0)
- result = esock_make_error_errno(env, sock_errno());
- else
- result = esock_atom_ok;
-
- } else {
- result = esock_make_error(env, esock_atom_einval);
- }
-
- FREE(val);
-
- return result;
-}
-
-
/* nsetopt_bool_opt - set an option that has an (integer) bool value
*/
static
@@ -5198,6 +5197,38 @@ ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
}
+/* nsetopt_str_opt - set an option that has an string value
+ */
+static
+ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ int max,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ char* val = MALLOC(max);
+
+ if (GET_STR(env, eVal, val, max) > 0) {
+ int optLen = strlen(val);
+ int res = socket_setopt(descP->sock, level, opt, &val, optLen);
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ } else {
+ result = esock_make_error(env, esock_atom_einval);
+ }
+
+ FREE(val);
+
+ return result;
+}
+
+
static
BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
int eLevel,
@@ -5389,6 +5420,8 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
ERL_NIF_TERM eIsEncoded;
BOOLEAN_T isEncoded, isOTP;
+ SGDBG( ("SOCKET", "nif_getopt -> entry with argc: %d\r\n", argc) );
+
if ((argc != 4) ||
!enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
!GET_INT(env, argv[2], &eLevel) ||
@@ -5397,6 +5430,14 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
}
eIsEncoded = argv[1];
+ SSDBG( descP,
+ ("SOCKET", "nif_getopt -> args when sock = %d:"
+ "\r\n Socket: %T"
+ "\r\n eIsEncoded: %T"
+ "\r\n eLevel: %d"
+ "\r\n eOpt: %d"
+ "\r\n", descP->sock, argv[0], eIsEncoded, eLevel, eOpt) );
+
isEncoded = esock_decode_bool(eIsEncoded);
if (!elevel2level(isEncoded, eLevel, &isOTP, &level))
@@ -5417,6 +5458,14 @@ ERL_NIF_TERM ngetopt(ErlNifEnv* env,
{
ERL_NIF_TERM result;
+ SSDBG( descP,
+ ("SOCKET", "ngetopt -> entry with"
+ "\r\n isEncoded: %d"
+ "\r\n isOTP: %d"
+ "\r\n level: %d"
+ "\r\n eOpt: %d"
+ "\r\n", isEncoded, isOTP, level, eOpt) );
+
if (isOTP) {
/* These are not actual socket options,
* but options for our implementation.
@@ -5581,6 +5630,12 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env,
{
ERL_NIF_TERM result;
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_level -> entry with"
+ "\r\n level: %d"
+ "\r\n eOpt: %d"
+ "\r\n", level, eOpt) );
+
switch (level) {
case SOL_SOCKET:
result = ngetopt_lvl_socket(env, descP, eOpt);
@@ -5632,6 +5687,11 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
{
ERL_NIF_TERM result;
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_socket -> entry with"
+ "\r\n eOpt: %d"
+ "\r\n", eOpt) );
+
switch (eOpt) {
#if defined(SO_ACCEPTCONN)
case SOCKET_OPT_SOCK_ACCEPTCONN:
@@ -5639,6 +5699,12 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
break;
#endif
+#if defined(SO_BINDTODEVICE)
+ case SOCKET_OPT_SOCK_BINDTODEVICE:
+ result = ngetopt_lvl_sock_bindtodevice(env, descP);
+ break;
+#endif
+
#if defined(SO_BROADCAST)
case SOCKET_OPT_SOCK_BROADCAST:
result = ngetopt_lvl_sock_broadcast(env, descP);
@@ -5742,6 +5808,19 @@ ERL_NIF_TERM ngetopt_lvl_sock_acceptconn(ErlNifEnv* env,
#endif
+#if defined(SO_BINDTODEVICE)
+static
+ERL_NIF_TERM ngetopt_lvl_sock_bindtodevice(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sock_bindtodevice -> entry with\r\n") );
+
+ return ngetopt_str_opt(env, descP, SOL_SOCKET, SO_BROADCAST, IFNAMSIZ+1);
+}
+#endif
+
+
#if defined(SO_BROADCAST)
static
ERL_NIF_TERM ngetopt_lvl_sock_broadcast(ErlNifEnv* env,
@@ -6628,18 +6707,17 @@ ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
-/* ngetopt_str_opt - get an string option
+/* ngetopt_bool_opt - get an (integer) bool option
*/
static
-ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
- SocketDescriptor* descP,
- int level,
- int opt,
- int max)
+ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt)
{
ERL_NIF_TERM result;
- char* val = MALLOC(max);
- SOCKOPTLEN_T valSz = max;
+ int val;
+ SOCKOPTLEN_T valSz = sizeof(val);
int res;
res = sock_getopt(descP->sock, level, opt, &val, &valSz);
@@ -6647,24 +6725,22 @@ ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
if (res != 0) {
result = esock_make_error_errno(env, sock_errno());
} else {
- ERL_NIF_TERM sval = MKSL(env, val, valSz);
+ ERL_NIF_TERM bval = ((val) ? atom_true : atom_false);
- result = esock_make_ok2(env, sval);
+ result = esock_make_ok2(env, bval);
}
- FREE(val);
-
return result;
}
-/* nsetopt_bool_opt - get an (integer) bool option
+/* ngetopt_int_opt - get an integer option
*/
static
-ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
- SocketDescriptor* descP,
- int level,
- int opt)
+ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt)
{
ERL_NIF_TERM result;
int val;
@@ -6676,42 +6752,62 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
if (res != 0) {
result = esock_make_error_errno(env, sock_errno());
} else {
- ERL_NIF_TERM bval = ((val) ? atom_true : atom_false);
-
- result = esock_make_ok2(env, bval);
+ result = esock_make_ok2(env, MKI(env, val));
}
return result;
}
-/* nsetopt_int_opt - get an integer option
+
+/* ngetopt_str_opt - get an string option
+ *
+ * We provide the max size of the string. This is the
+ * size of the buffer we allocate for the value.
+ * The actual size of the (read) value will be communicated
+ * in the optSz variable.
*/
static
-ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
+ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
SocketDescriptor* descP,
int level,
- int opt)
+ int opt,
+ int max)
{
ERL_NIF_TERM result;
- int val;
- SOCKOPTLEN_T valSz = sizeof(val);
+ char* val = MALLOC(max);
+ SOCKOPTLEN_T valSz = max;
int res;
- res = sock_getopt(descP->sock, level, opt, &val, &valSz);
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_str_opt -> entry with"
+ "\r\n level: %d"
+ "\r\n opt: %d"
+ "\r\n max: %d"
+ "\r\n", level, opt, max) );
+
+ res = sock_getopt(descP->sock, level, opt, val, &valSz);
if (res != 0) {
result = esock_make_error_errno(env, sock_errno());
} else {
- result = esock_make_ok2(env, MKI(env, val));
+ ERL_NIF_TERM sval = MKSL(env, val, valSz);
+
+ result = esock_make_ok2(env, sval);
}
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_str_opt -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ FREE(val);
+
return result;
}
-
/* ----------------------------------------------------------------------
* nif_sockname - get socket name
*
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 03a7012131..5032366c93 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 8d377d808e..d4bf55511c 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -366,15 +366,15 @@
status |
use_ext_recvinfo.
-%% -type plain_socket_options() :: integer().
-%% -type sockopts() :: otp_socket_options() |
-%% socket_options() |
-%% ip_socket_options() |
-%% ipv6_socket_options() |
-%% tcp_socket_options() |
-%% udp_socket_options() |
-%% sctp_socket_options() |
-%% plain_socket_options().
+%% -type plain_socket_option() :: integer().
+%% -type sockopt() :: otp_socket_option() |
+%% socket_option() |
+%% ip_socket_option() |
+%% ipv6_socket_option() |
+%% tcp_socket_option() |
+%% udp_socket_option() |
+%% sctp_socket_option() |
+%% plain_socket_option().
%% If the integer value is used its up to the caller to ensure its valid!
-type ip_tos_flag() :: lowdeley |
@@ -496,7 +496,7 @@
-define(SOCKET_OPT_SOCK_ACCEPTCONN, 1).
%% -define(SOCKET_OPT_SOCK_ACCEPTFILTER, 2).
-%% -define(SOCKET_OPT_SOCK_BINDTODEVICE, 3).
+-define(SOCKET_OPT_SOCK_BINDTODEVICE, 3).
-define(SOCKET_OPT_SOCK_BROADCAST, 4).
%% -define(SOCKET_OPT_SOCK_BUSY_POLL, 5).
-define(SOCKET_OPT_SOCK_DEBUG, 6).
@@ -1959,6 +1959,8 @@ enc_setopt_value(otp, controlling_process, V, _, _, _) when is_pid(V) ->
enc_setopt_value(otp = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
+enc_setopt_value(socket, bindtodevice, V, _D, _T, _P) when is_list(V) ->
+ V;
enc_setopt_value(socket, broadcast, V, _D, _T, _P) when is_boolean(V) ->
V;
enc_setopt_value(socket, debug, V, _D, _T, _P) when is_integer(V) ->
@@ -2253,10 +2255,10 @@ enc_sockopt_key(socket = _L, acceptconn = _Opt, get = _Dir, _D, _T, _P) ->
enc_sockopt_key(socket = L, acceptfilter = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
%% Before linux 3.8, this socket option could be set.
-%% Size of buffer for name: IFNAMSZ
+%% Maximum size of buffer for name: IFNAMSZIZ
%% So, we let the implementation decide.
-enc_sockopt_key(socket = L, bindtodevide = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(socket = _L, bindtodevice = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SOCK_BINDTODEVICE;
enc_sockopt_key(socket, broadcast = _Opt, _Dir, _D, dgram = _T, _P) ->
?SOCKET_OPT_SOCK_BROADCAST;
enc_sockopt_key(socket = L, busy_poll = Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index ff8f6575a3..6d002db38e 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -101,7 +101,7 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
{ok, Sock} ->
F = fun(X) -> case socket:getopt(Sock, socket, X) of
{ok, V} -> f("~p", [V]);
- {error, _} -> "-"
+ {error, R} -> f("error: ~p", [R])
end
end,
i("socket opened (~s,~s,~s): "
@@ -129,11 +129,16 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
{error, BReason} ->
throw({bind, BReason})
end,
- i("try start handler for"
- "~n ~p", [case socket:sockname(Sock) of
- {ok, Name} -> Name;
- {error, _} = E -> E
- end]),
+ socket:setopt(Sock, otp, debug, true),
+ i("bound to: "
+ "~n ~s"
+ "~n (socket) Bind To Device: ~s"
+ "~n => try start handler",
+ [case socket:sockname(Sock) of
+ {ok, Name} -> f("~p", [Name]);
+ {error, R} -> f("error: ~p", [R])
+ end,
+ F(bindtodevice)]),
case handler_start(1, Sock, Peek) of
{ok, {Pid, MRef}} ->
i("handler (~p) started", [Pid]),
@@ -435,37 +440,41 @@ handler_init(Manager, ID, Peek, Sock) ->
{handler, Pid, Ref, continue} ->
i("got continue"),
handler_reply(Pid, Ref, ok),
- G = fun(K) -> case socket:getopt(Sock, ip, K) of
- {ok, Val} ->
- f("~p", [Val]);
- {error, R} when is_atom(R) ->
- f("error: ~w", [R]);
- {error, {T, R}} when is_atom(T) ->
- f("error: ~w, ~p", [T, R]);
- {error, R} ->
- f("error: ~p", [R])
+ G = fun(L, O) -> case socket:getopt(Sock, L, O) of
+ {ok, Val} ->
+ f("~p", [Val]);
+ {error, R} when is_atom(R) ->
+ f("error: ~w", [R]);
+ {error, {T, R}} when is_atom(T) ->
+ f("error: ~w, ~p", [T, R]);
+ {error, R} ->
+ f("error: ~p", [R])
end
end,
+ GIP = fun(O) -> G(ip, O) end,
+ GSO = fun(O) -> G(socket, O) end,
{ok, Domain} = socket:getopt(Sock, socket, domain),
{ok, Type} = socket:getopt(Sock, socket, type),
{ok, Proto} = socket:getopt(Sock, socket, protocol),
+ B2D = GSO(bindtodevice),
{ok, OOBI} = socket:getopt(Sock, socket, oobinline),
{ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
{ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
{ok, Linger} = socket:getopt(Sock, socket, linger),
- MTU = G(mtu),
- MTUDisc = G(mtu_discover),
+ MTU = GIP(mtu),
+ MTUDisc = GIP(mtu_discover),
{ok, MALL} = socket:getopt(Sock, ip, multicast_all),
{ok, MIF} = socket:getopt(Sock, ip, multicast_if),
{ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
{ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
- NF = G(nodefrag), % raw only
- RecvTOS = G(recvtos),
- RecvTTL = G(recvttl), % not stream
+ NF = GIP(nodefrag), % raw only
+ RecvTOS = GIP(recvtos),
+ RecvTTL = GIP(recvttl), % not stream
i("got continue when: "
"~n (socket) Domain: ~p"
"~n (socket) Type: ~p"
"~n (socket) Protocol: ~p"
+ "~n (socket) Bind To Device: ~s"
"~n (socket) OOBInline: ~p"
"~n (socket) SndBuf: ~p"
"~n (socket) RcvBuf: ~p"
@@ -480,7 +489,7 @@ handler_init(Manager, ID, Peek, Sock) ->
"~n (ip) RecvTOS: ~s"
"~n (ip) RecvTTL: ~s",
[Domain, Type, Proto,
- OOBI, SndBuf, RcvBuf, Linger,
+ B2D, OOBI, SndBuf, RcvBuf, Linger,
MTU, MTUDisc, MALL, MIF, MLoop, MTTL,
NF, RecvTOS, RecvTTL]),
%% socket:setopt(Sock, otp, debug, true),