summaryrefslogtreecommitdiff
path: root/lib/kernel/src/socket.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src/socket.erl')
-rw-r--r--lib/kernel/src/socket.erl225
1 files changed, 208 insertions, 17 deletions
diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl
index b92de6ba07..c188f516a1 100644
--- a/lib/kernel/src/socket.erl
+++ b/lib/kernel/src/socket.erl
@@ -69,6 +69,8 @@
sockname/1,
peername/1,
+ ioctl/2, ioctl/3, ioctl/4,
+
cancel/2
]).
@@ -141,6 +143,9 @@
info_keys/0
]).
+%% DUMMY
+-export_type([ioctl_device_flag/0, ioctl_device_map/0]).
+
%% We need #file_descriptor{} for sendfile/2,3,4,5
-include("file_int.hrl").
@@ -718,6 +723,31 @@
].
+%% Note that not all flags exist on all platforms!
+-type ioctl_device_flag() :: up | broadcast | debug | loopback | pointopoint |
+ notrailers | knowsepoch | running | noarp | promisc | allmulti |
+ master | oactive | slave | simplex |
+ link0 | link1 | link2 |
+ multicast | portsel | automedia |
+ cantconfig | ppromisc |
+ dynamic |
+ monitor | staticarp | dying | renaming | nogroup |
+ lower_up | dormant | echo.
+
+%% When reading the device map (gifmap), the resulting map will be
+%% "fully" populated.
+%% <DOES-THIS-WORK>
+%% When writing, it is expected that only the fields that is
+%% to be set is present.
+%% </DOES-THIS-WORK>
+-type ioctl_device_map() :: #{mem_start := non_neg_integer(),
+ mem_end := non_neg_integer(),
+ base_addr := non_neg_integer(),
+ irq := non_neg_integer(),
+ dma := non_neg_integer(),
+ port := non_neg_integer()}.
+
+
%% ===========================================================================
%%
%% Interface term formats
@@ -809,9 +839,9 @@ which_sockets(Proto)
Proto =:= udp ->
?REGISTRY:which_sockets({protocol, Proto});
-which_sockets(CTRL)
- when is_pid(CTRL) ->
- ?REGISTRY:which_sockets({ctrl, CTRL});
+which_sockets(Owner)
+ when is_pid(Owner) ->
+ ?REGISTRY:which_sockets({owner, Owner});
which_sockets(Filter) when is_function(Filter, 1) ->
?REGISTRY:which_sockets(Filter);
@@ -1202,22 +1232,14 @@ info(Socket) ->
-spec monitor(Socket) -> reference() when
Socket :: socket().
-%% Should it be possible to specify a modification of the 'Socket' part
-%% of the DOWN-message? The point would be to make it possible for
-%% a gen_tcp_socket-socket to use this and get the proper 'socket'
-%% as part of the message.
-
monitor(?socket(SockRef) = Socket) when is_reference(SockRef) ->
case prim_socket:setopt(SockRef, {otp, use_registry}, true) of
ok ->
- case socket_registry:monitor(Socket) of
- {error, MReason} ->
- erlang:error({invalid, MReason});
- MRef when is_reference(MRef) ->
- MRef
- end;
- {error, SReason} ->
- erlang:error({invalid, SReason})
+ socket_registry:monitor(Socket);
+ {error, closed = SReason} ->
+ MRef = make_ref(),
+ self() ! {'DOWN', MRef, socket, Socket, SReason},
+ MRef
end;
monitor(Socket) ->
erlang:error(badarg, [Socket]).
@@ -1268,7 +1290,8 @@ cancel_monitor(MRef) ->
boolean()}]}]}].
supports() ->
[{Key1, supports(Key1)}
- || Key1 <- [options, msg_flags, protocols]]
+ || Key1 <- [ioctl_requests, ioctl_flags,
+ options, msg_flags, protocols]]
++ prim_socket:supports().
-spec supports(Key1 :: term()) ->
@@ -4028,6 +4051,174 @@ peername(Socket) ->
erlang:error(badarg, [Socket]).
+
+%% ===========================================================================
+%%
+%% ioctl - control device - get requests
+%%
+%%
+
+-spec ioctl(Socket, GetRequest) -> {'ok', IFConf} | {'error', Reason} when
+ Socket :: socket(),
+ GetRequest :: 'gifconf',
+ IFConf :: [#{name := string, addr := sockaddr()}],
+ Reason :: posix() | 'closed'.
+
+%% gifconf | {gifaddr, string()} | {gifindex, string()} | {gifname, integer()}
+ioctl(?socket(SockRef), gifconf = GetRequest) ->
+ prim_socket:ioctl(SockRef, GetRequest);
+ioctl(Socket, GetRequest) ->
+ erlang:error(badarg, [Socket, GetRequest]).
+
+%% -spec ioctl(Socket, GetRequest, Index) -> {'ok', Name} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifname',
+%% Index :: integer(),
+%% Name :: string(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', Index} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifindex',
+%% Name :: string(),
+%% Index :: integer(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', Addr} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifaddr',
+%% Name :: string(),
+%% Addr :: sockaddr(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', DestAddr} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifdstaddr',
+%% Name :: string(),
+%% DestAddr :: sockaddr(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', BroadcastAddr} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifbrdaddr',
+%% Name :: string(),
+%% BroadcastAddr :: sockaddr(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', Netmask} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifnetmask',
+%% Name :: string(),
+%% Netmask :: sockaddr(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', HWAddr} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifhwaddr',
+%% Name :: string(),
+%% HWAddr :: sockaddr(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', MTU} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifmtu',
+%% Name :: string(),
+%% MTU :: integer(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', TransmitQLen} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'giftxqlen',
+%% Name :: string(),
+%% TransmitQLen :: integer(),
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', Flags} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifflags',
+%% Name :: string(),
+%% Flags :: [ioctl_device_flag() | integer()],
+%% Reason :: posix() | 'closed';
+%% (Socket, GetRequest, Name) -> {'ok', DevMap} | {'error', Reason} when
+%% Socket :: socket(),
+%% GetRequest :: 'gifmap',
+%% Name :: string(),
+%% DevMap :: ioctl_device_map(),
+%% Reason :: posix() | 'closed'.
+
+-spec ioctl(Socket, GetRequest, NameOrIndex) -> {'ok', Result} | {'error', Reason} when
+ Socket :: socket(),
+ GetRequest :: 'gifname' | 'gifindex' |
+ 'gifaddr' | 'gifdstaddr' | 'gifbrdaddr' |
+ 'gifnetmask' | 'gifhwaddr' |
+ 'gifmtu' | 'giftxqlen' | 'gifflags',
+ NameOrIndex :: string() | integer(),
+ Result :: term(),
+ Reason :: posix() | 'closed'.
+
+ioctl(?socket(SockRef), gifname = GetRequest, Index)
+ when is_integer(Index) ->
+ prim_socket:ioctl(SockRef, GetRequest, Index);
+ioctl(?socket(SockRef), gifindex = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifaddr = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifdstaddr = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifbrdaddr = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifnetmask = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifmtu = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifhwaddr = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), giftxqlen = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifflags = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(?socket(SockRef), gifmap = GetRequest, Name)
+ when is_list(Name) ->
+ prim_socket:ioctl(SockRef, GetRequest, Name);
+ioctl(Socket, GetRequest, Arg) ->
+ erlang:error(badarg, [Socket, GetRequest, Arg]).
+
+
+-spec ioctl(Socket, SetRequest, Name, Value) -> 'ok' | {'error', Reason} when
+ Socket :: socket(),
+ SetRequest :: 'sifflags' |
+ 'sifaddr' | 'sifdstaddr' | 'sifbrdaddr' |
+ 'sifnetmask' | 'sifhwaddr' |
+ 'gifmtu' | 'siftxqlen',
+ Name :: string(),
+ Value :: term(),
+ Reason :: posix() | 'closed'.
+
+ioctl(?socket(SockRef), sifflags = SetRequest, Name, Flags)
+ when is_list(Name) andalso is_map(Flags) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, Flags);
+ioctl(?socket(SockRef), sifaddr = SetRequest, Name, Addr)
+ when is_list(Name) andalso is_map(Addr) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(Addr));
+ioctl(?socket(SockRef), sifdstaddr = SetRequest, Name, DstAddr)
+ when is_list(Name) andalso is_map(DstAddr) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(DstAddr));
+ioctl(?socket(SockRef), sifbrdaddr = SetRequest, Name, BrdAddr)
+ when is_list(Name) andalso is_map(BrdAddr) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(BrdAddr));
+ioctl(?socket(SockRef), sifnetmask = SetRequest, Name, NetMask)
+ when is_list(Name) andalso is_map(NetMask) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(NetMask));
+ioctl(?socket(SockRef), sifmtu = SetRequest, Name, MTU)
+ when is_list(Name) andalso is_integer(MTU) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, MTU);
+ioctl(?socket(SockRef), siftxqlen = SetRequest, Name, QLen)
+ when is_list(Name) andalso is_integer(QLen) ->
+ prim_socket:ioctl(SockRef, SetRequest, Name, QLen);
+ioctl(Socket, SetRequest, Arg1, Arg2) ->
+ erlang:error(badarg, [Socket, SetRequest, Arg1, Arg2]).
+
+
%% ===========================================================================
%%
%% cancel - cancel an operation resulting in a select