1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2021. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(inet).
21
22-include("inet.hrl").
23-include("inet_int.hrl").
24-include("inet_sctp.hrl").
25
26%% socket
27-export([peername/1, sockname/1, port/1, send/2,
28	 peernames/1, peernames/2, socknames/1, socknames/2,
29	 setopts/2, getopts/2,
30	 getifaddrs/0, getifaddrs/1,
31	 getif/1, getif/0, getiflist/0, getiflist/1,
32	 ifget/3, ifget/2, ifset/3, ifset/2,
33	 getstat/1, getstat/2,
34         info/1, socket_to_list/1,
35	 ip/1, stats/0, options/0,
36	 pushf/3, popf/1, close/1, gethostname/0, gethostname/1,
37	 parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
38	 parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1,
39         ntoa/1, ipv4_mapped_ipv6_address/1]).
40
41-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
42-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]).
43-export([gen_tcp_module/1, gen_udp_module/1]).
44
45-export([i/0, i/1, i/2]).
46
47-export([getll/1, getfd/1, open/8, open_bind/8, fdopen/6]).
48
49-export([tcp_controlling_process/2, udp_controlling_process/2,
50	 tcp_close/1, udp_close/1]).
51
52%% used by sendfile
53-export([lock_socket/2]).
54
55%% used by socks5
56-export([setsockname/2, setpeername/2]).
57
58%% resolve
59-export([gethostbyname/1, gethostbyname/2, gethostbyname/3,
60	 gethostbyname_tm/3]).
61-export([gethostbyname_string/2, gethostbyname_self/2]).
62-export([gethostbyaddr/1, gethostbyaddr/2,
63	 gethostbyaddr_tm/2]).
64
65-export([getservbyname/2, getservbyport/2]).
66-export([getaddrs/2, getaddrs/3, getaddrs_tm/3,
67	 getaddr/2, getaddr/3, getaddr_tm/3]).
68-export([translate_ip/2]).
69
70-export([get_rc/0]).
71
72%% format error
73-export([format_error/1]).
74
75%% timer interface
76-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
77
78%% Socket monitoring
79-export([monitor/1, cancel_monitor/1]).
80
81-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
82              ip6_address/0, ip_address/0, port_number/0,
83	      family_address/0, local_address/0,
84              socket_address/0, returned_non_ip_address/0,
85	      socket_setopt/0, socket_getopt/0, ancillary_data/0,
86	      posix/0, socket/0, inet_backend/0, stat_option/0]).
87%% imports
88-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
89
90-define(DEFAULT_KERNEL_INET_BACKEND, inet). % inet_backend()
91
92%% Record Signature
93-define(RS(Record),
94	{Record, record_info(size, Record)}).
95%% Record Signature Check (guard)
96-define(RSC(Record, RS),
97	element(1, Record) =:= element(1, RS),
98	tuple_size(Record) =:= element(2, RS)).
99
100%%% ---------------------------------
101%%% Contract type definitions
102
103
104-type hostent() :: #hostent{}.
105-type hostname() :: atom() | string().
106-type ip4_address() :: {0..255,0..255,0..255,0..255}.
107-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535,
108			0..65535,0..65535,0..65535,0..65535}.
109-type ip_address() :: ip4_address() | ip6_address().
110-type port_number() :: 0..65535.
111-type family_address() :: inet_address() | inet6_address() | local_address().
112-type inet_address() ::
113        {'inet', {ip4_address() | 'any' | 'loopback', port_number()}}.
114-type inet6_address() ::
115        {'inet6', {ip6_address() | 'any' | 'loopback', port_number()}}.
116-type local_address() :: {'local', File :: binary() | string()}.
117-type returned_non_ip_address() ::
118	{'local', binary()} |
119	{'unspec', <<>>} |
120	{'undefined', any()}.
121-type posix() ::
122        'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' |
123        'econnaborted' | 'econnrefused' | 'econnreset' |
124        'edestaddrreq' |
125        'ehostdown' | 'ehostunreach' |
126        'einprogress' | 'eisconn' |
127        'emsgsize' |
128        'enetdown' | 'enetunreach' |
129        'enopkg' | 'enoprotoopt' | 'enotconn' | 'enotty' | 'enotsock' |
130        'eproto' | 'eprotonosupport' | 'eprototype' |
131        'esocktnosupport' |
132        'etimedout' |
133        'ewouldblock' |
134        'exbadport' | 'exbadseq' | file:posix().
135-type module_socket() :: {'$inet', Handler :: module(), Handle :: term()}.
136-define(module_socket(Handler, Handle), {'$inet', (Handler), (Handle)}).
137-type socket() :: port() | module_socket().
138-type inet_backend() :: {'inet_backend', 'inet' | 'socket'}.
139
140-type socket_setopt() ::
141        gen_sctp:option() | gen_tcp:option() | gen_udp:option().
142
143-type socket_getopt() ::
144        gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name().
145-type ether_address() :: [0..255].
146
147-type if_setopt() ::
148      {'addr', ip_address()} |
149      {'broadaddr', ip_address()} |
150      {'dstaddr', ip_address()} |
151      {'mtu', non_neg_integer()} |
152      {'netmask', ip_address()} |
153      {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
154		 'pointtopoint' | 'no_pointtopoint' |
155		 'running' | 'multicast']} |
156      {'hwaddr', ether_address()}.
157
158-type if_getopt() ::
159      'addr' | 'broadaddr' | 'dstaddr' |
160      'mtu' | 'netmask' | 'flags' |'hwaddr'.
161
162-type if_getopt_result() ::
163      {'addr', ip_address()} |
164      {'broadaddr', ip_address()} |
165      {'dstaddr', ip_address()} |
166      {'mtu', non_neg_integer()} |
167      {'netmask', ip_address()} |
168      {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
169		 'pointtopoint' | 'no_pointtopoint' |
170		 'running' | 'multicast' | 'loopback']} |
171      {'hwaddr', ether_address()}.
172
173-type getifaddrs_ifopts() ::
174        [Ifopt :: {flags, Flags :: [up | broadcast | loopback |
175                                    pointtopoint | running | multicast]} |
176                  {addr, Addr :: ip_address()} |
177                  {netmask, Netmask :: ip_address()} |
178                  {broadaddr, Broadaddr :: ip_address()} |
179                  {dstaddr, Dstaddr :: ip_address()} |
180                  {hwaddr, Hwaddr :: [byte()]}].
181
182-type address_family() :: 'inet' | 'inet6' | 'local'.
183-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
184-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
185-type socket_address() ::
186	ip_address() | 'any' | 'loopback' | local_address().
187-type stat_option() ::
188	'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
189	'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
190
191-type ancillary_data() ::
192        [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
193
194%%% ---------------------------------
195
196-spec get_rc() -> [{Par :: atom(), Val :: any()} |
197                   {Par :: atom(), Val1 :: any(), Val2 :: any()}].
198
199get_rc() ->
200    inet_db:get_rc().
201
202-spec close(Socket) -> 'ok' when
203      Socket :: socket().
204
205close(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) ->
206    GenSocketMod:?FUNCTION_NAME(Socket);
207close(Socket) ->
208    prim_inet:close(Socket),
209    receive
210	{Closed, Socket} when Closed =:= tcp_closed; Closed =:= udp_closed ->
211	    ok
212    after 0 ->
213	    ok
214    end.
215
216
217%% -- Socket monitor
218
219-spec monitor(Socket) -> reference() when
220      Socket :: socket().
221
222monitor({'$inet', GenSocketMod, _} = Socket) when is_atom(GenSocketMod) ->
223    MRef = GenSocketMod:?FUNCTION_NAME(Socket),
224    case inet_db:put_socket_type(MRef, {socket, GenSocketMod}) of
225        ok ->
226            MRef;
227	error ->
228	    GenSocketMod:cancel_monitor(MRef),
229	    erlang:error({invalid, Socket})
230    end;
231monitor(Socket) when is_port(Socket) ->
232    MRef = erlang:monitor(port, Socket),
233    case inet_db:put_socket_type(MRef, port) of
234	ok ->
235	    MRef;
236	error ->
237	    erlang:demonitor(MRef, [flush]),
238	    erlang:error({invalid, Socket})
239    end;
240monitor(Socket) ->
241    erlang:error(badarg, [Socket]).
242
243
244%% -- Cancel socket monitor
245
246-spec cancel_monitor(MRef) -> boolean() when
247      MRef :: reference().
248
249cancel_monitor(MRef) when is_reference(MRef) ->
250    case inet_db:take_socket_type(MRef) of
251	{ok, port} ->
252	    erlang:demonitor(MRef, [info]);
253	{ok, {socket, GenSocketMod}} ->
254	    GenSocketMod:?FUNCTION_NAME(MRef);
255	error -> % Assume it has the monitor has already been cancel'ed
256	    false
257    end;
258cancel_monitor(MRef) ->
259    erlang:error(badarg, [MRef]).
260
261
262%% -- Socket peername
263
264-spec peername(Socket :: socket()) ->
265		      {ok,
266		       {ip_address(), port_number()} |
267		       returned_non_ip_address()} |
268		      {error, posix()}.
269
270peername(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) ->
271    GenSocketMod:?FUNCTION_NAME(Socket);
272peername(Socket) ->
273    prim_inet:peername(Socket).
274
275-spec setpeername(
276	Socket :: socket(),
277	Address ::
278	  {ip_address() | 'any' | 'loopback',
279	   port_number()} |
280	  socket_address()) ->
281			 'ok' | {'error', any()}.
282
283setpeername(Socket, {IP,Port}) ->
284    prim_inet:setpeername(Socket, {IP,Port});
285setpeername(Socket, undefined) ->
286    prim_inet:setpeername(Socket, undefined).
287
288-spec peernames(Socket :: socket()) ->
289		       {ok,
290			[{ip_address(), port_number()} |
291			 returned_non_ip_address()]} |
292		       {error, posix()}.
293
294peernames(Socket) ->
295    prim_inet:peernames(Socket).
296
297-spec peernames(Socket, Assoc) ->
298		       {ok, [{Address, Port}]} | {error, posix()} when
299      Socket :: socket(),
300      Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(),
301      Address :: ip_address(),
302      Port :: non_neg_integer().
303
304peernames(Socket, Assoc) ->
305    prim_inet:peernames(Socket, Assoc).
306
307
308-spec sockname(Socket :: socket()) ->
309		      {ok,
310		       {ip_address(), port_number()} |
311		       returned_non_ip_address()} |
312		      {error, posix()}.
313
314sockname(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) ->
315    GenSocketMod:?FUNCTION_NAME(Socket);
316sockname(Socket) ->
317    prim_inet:sockname(Socket).
318
319-spec setsockname(
320	Socket :: socket(),
321	Address ::
322	  {ip_address() | 'any' | 'loopback',
323	   port_number()} |
324	  socket_address()) ->
325	'ok' | {'error', any()}.
326
327setsockname(Socket, {IP,Port}) ->
328    prim_inet:setsockname(Socket, {IP,Port});
329setsockname(Socket, undefined) ->
330    prim_inet:setsockname(Socket, undefined).
331
332-spec socknames(Socket :: socket()) ->
333		       {ok,
334			[{ip_address(), port_number()} |
335			 returned_non_ip_address()]} |
336		       {error, posix()}.
337
338socknames(Socket) ->
339    prim_inet:socknames(Socket).
340
341-spec socknames(Socket, Assoc) ->
342		       {ok, [{Address, Port}]} | {error, posix()} when
343      Socket :: socket(),
344      Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(),
345      Address :: ip_address(),
346      Port :: non_neg_integer().
347
348socknames(Socket, Assoc) ->
349    prim_inet:socknames(Socket, Assoc).
350
351
352-spec port(Socket) -> {'ok', Port} | {'error', any()} when
353      Socket :: socket(),
354      Port :: port_number().
355
356port(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) ->
357    case GenSocketMod:sockname(Socket) of
358        {ok, {_, Port}} -> {ok, Port};
359        {error, _} = Error -> Error
360    end;
361port(Socket) ->
362    case prim_inet:sockname(Socket) of
363	{ok, {_,Port}} -> {ok, Port};
364	Error -> Error
365    end.
366
367-spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()?
368	'ok' | {'error', posix()}.
369
370send(Socket, Packet) ->
371    prim_inet:send(Socket, Packet).
372
373-spec setopts(Socket, Options) -> ok | {error, posix()} when
374      Socket :: socket(),
375      Options :: [socket_setopt()].
376
377setopts(?module_socket(GenSocketMod, _) = Socket, Opts) when is_atom(GenSocketMod) ->
378    GenSocketMod:?FUNCTION_NAME(Socket, Opts);
379setopts(Socket, Opts) ->
380    SocketOpts =
381	[case Opt of
382	     {netns,NS} ->
383		 {netns,filename2binary(NS)};
384	     _ ->
385		 Opt
386	 end || Opt <- Opts],
387    prim_inet:setopts(Socket, SocketOpts).
388
389-spec getopts(Socket, Options) ->
390	{'ok', OptionValues} | {'error', posix()} when
391      Socket :: socket(),
392      Options :: [socket_getopt()],
393      OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
394
395getopts(?module_socket(GenSocketMod, _) = Socket, Opts)
396  when is_atom(GenSocketMod) ->
397    GenSocketMod:?FUNCTION_NAME(Socket, Opts);
398getopts(Socket, Opts) ->
399    case prim_inet:getopts(Socket, Opts) of
400	{ok,OptionValues} ->
401	    {ok,
402	     [case OptionValue of
403		  {netns,Bin} ->
404		      {netns,binary2filename(Bin)};
405		  _ ->
406		      OptionValue
407	      end || OptionValue <- OptionValues]};
408	Other ->
409	    Other
410    end.
411
412-spec getifaddrs(
413        [Option :: {netns, Namespace :: file:filename_all()}]
414        | socket()) ->
415                        {'ok', [{Ifname :: string(),
416                                 Ifopts :: getifaddrs_ifopts()}]}
417                            | {'error', posix()}.
418getifaddrs(Opts) when is_list(Opts) ->
419    withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts);
420getifaddrs(Socket) ->
421    prim_inet:getifaddrs(Socket).
422
423-spec getifaddrs() ->
424                        {'ok', [{Ifname :: string(),
425                                 Ifopts :: getifaddrs_ifopts()}]}
426                            | {'error', posix()}.
427getifaddrs() ->
428    withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
429
430
431-spec getiflist(
432        [Option :: {netns, Namespace :: file:filename_all()}]
433        | socket()) ->
434                       {'ok', [string()]} | {'error', posix()}.
435
436getiflist(Opts) when is_list(Opts) ->
437    withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts);
438getiflist(Socket) ->
439    prim_inet:getiflist(Socket).
440
441-spec getiflist() -> {'ok', [string()]} | {'error', posix()}.
442
443getiflist() ->
444    withsocket(fun(S) -> prim_inet:getiflist(S) end).
445
446-spec ifget(Socket :: socket(),
447            Name :: string() | atom(),
448	    Opts :: [if_getopt()]) ->
449	{'ok', [if_getopt_result()]} | {'error', posix()}.
450
451ifget(Socket, Name, Opts) ->
452    prim_inet:ifget(Socket, Name, Opts).
453
454-spec ifget(
455        Name :: string() | atom(),
456        Opts :: [if_getopt() |
457                 {netns, Namespace :: file:filename_all()}]) ->
458	{'ok', [if_getopt_result()]} | {'error', posix()}.
459
460ifget(Name, Opts) ->
461    {NSOpts,IFOpts} =
462        lists:partition(
463          fun ({netns,_}) -> true;
464              (_) -> false
465          end, Opts),
466    withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts).
467
468-spec ifset(Socket :: socket(),
469            Name :: string() | atom(),
470	    Opts :: [if_setopt()]) ->
471	'ok' | {'error', posix()}.
472
473ifset(Socket, Name, Opts) ->
474    prim_inet:ifset(Socket, Name, Opts).
475
476-spec ifset(
477        Name :: string() | atom(),
478        Opts :: [if_setopt() |
479                 {netns, Namespace :: file:filename_all()}]) ->
480	'ok' | {'error', posix()}.
481
482ifset(Name, Opts) ->
483    {NSOpts,IFOpts} =
484        lists:partition(
485          fun ({netns,_}) -> true;
486              (_) -> false
487          end, Opts),
488    withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts).
489
490-spec getif() ->
491	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
492	{'error', posix()}.
493
494getif() ->
495    withsocket(fun(S) -> getif(S) end).
496
497%% backwards compatible getif
498-spec getif(
499        [Option :: {netns, Namespace :: file:filename_all()}]
500        | socket()) ->
501	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
502	{'error', posix()}.
503
504getif(Opts) when is_list(Opts) ->
505    withsocket(fun(S) -> getif(S) end, Opts);
506getif(Socket) ->
507    case prim_inet:getiflist(Socket) of
508	{ok, IfList} ->
509	    {ok, lists:foldl(
510		   fun(Name,Acc) ->
511			   case prim_inet:ifget(Socket,Name,
512						[addr,broadaddr,netmask]) of
513			       {ok,[{addr,A},{broadaddr,B},{netmask,M}]} ->
514				   [{A,B,M}|Acc];
515			       %% Some interfaces does not have a b-addr
516			       {ok,[{addr,A},{netmask,M}]} ->
517				   [{A,undefined,M}|Acc];
518			       _ ->
519				   Acc
520			   end
521		   end, [], IfList)};
522	Error -> Error
523    end.
524
525withsocket(Fun) ->
526    withsocket(Fun, []).
527%%
528withsocket(Fun, Opts) ->
529    case inet_udp:open(0, Opts) of
530	{ok,Socket} ->
531	    Res = Fun(Socket),
532	    inet_udp:close(Socket),
533	    Res;
534	Error ->
535	    Error
536    end.
537
538pushf(_Socket, Fun, _State) when is_function(Fun) ->
539    {error, einval}.
540
541popf(_Socket) ->
542    {error, einval}.
543
544
545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546% the hostname is not cached any more because this
547% could cause troubles on at least windows with plug-and-play
548% and network-cards inserted and removed in conjunction with
549% use of the DHCP-protocol
550% should never fail
551
552-spec gethostname() -> {'ok', Hostname} when
553      Hostname :: string().
554
555%%% XXX gethostname() -> net:gethostname().
556
557gethostname() ->
558    case inet_udp:open(0,[]) of
559	{ok,U} ->
560	    {ok,Res} = gethostname(U),
561	    inet_udp:close(U),
562	    {Res2,_} = lists:splitwith(fun($.)->false;(_)->true end,Res),
563	    {ok, Res2};
564	_ ->
565	    {ok, "nohost.nodomain"}
566    end.
567
568-spec gethostname(Socket :: socket()) ->
569	{'ok', string()} | {'error', posix()}.
570
571gethostname(Socket) ->
572    prim_inet:gethostname(Socket).
573
574-spec getstat(Socket) ->
575	{ok, OptionValues} | {error, posix()} when
576      Socket :: socket(),
577      OptionValues :: [{stat_option(), integer()}].
578
579getstat(Socket) ->
580    getstat(Socket, stats()).
581
582-spec getstat(Socket, Options) ->
583	{ok, OptionValues} | {error, posix()} when
584      Socket :: socket(),
585      Options :: [stat_option()],
586      OptionValues :: [{stat_option(), integer()}].
587
588getstat(?module_socket(GenSocketMod, _) = Socket, What)
589  when is_atom(GenSocketMod) ->
590    GenSocketMod:?FUNCTION_NAME(Socket, What);
591getstat(Socket, What) ->
592    prim_inet:getstat(Socket, What).
593
594-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when
595      Hostname :: hostname(),
596      Hostent :: hostent().
597
598gethostbyname(Name) ->
599    case inet_db:res_option(inet6) of
600	true ->
601	    gethostbyname_tm(Name, inet6, false);
602	false ->
603	    gethostbyname_tm(Name, inet, false)
604    end.
605
606-spec gethostbyname(Hostname, Family) ->
607                           {ok, Hostent} | {error, posix()} when
608      Hostname :: hostname(),
609      Family :: address_family(),
610      Hostent :: hostent().
611
612gethostbyname(Name,Family) ->
613    gethostbyname_tm(Name, Family, false).
614
615-spec gethostbyname(Name :: hostname(),
616	            Family :: address_family(),
617	            Timeout :: non_neg_integer() | 'infinity') ->
618	{'ok', #hostent{}} | {'error', posix()}.
619
620gethostbyname(Name,Family,Timeout) ->
621    Timer = start_timer(Timeout),
622    Res = gethostbyname_tm(Name,Family,Timer),
623    _ = stop_timer(Timer),
624    Res.
625
626gethostbyname_tm(Name,Family,Timer) ->
627    Opts0 = inet_db:res_option(lookup),
628    Opts =
629	case (lists:member(native, Opts0) orelse
630	      lists:member(string, Opts0) orelse
631	      lists:member(nostring, Opts0)) of
632	    true ->
633		Opts0;
634	    false ->
635		[string|Opts0]
636	end,
637    gethostbyname_tm(Name, Family, Timer, Opts).
638
639
640-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when
641      Address :: string() | ip_address(),
642      Hostent :: hostent().
643
644gethostbyaddr(Address) ->
645    gethostbyaddr_tm(Address, false).
646
647-spec gethostbyaddr(Address :: string() | ip_address(),
648	            Timeout :: non_neg_integer() | 'infinity') ->
649	{'ok', #hostent{}} | {'error', posix()}.
650
651gethostbyaddr(Address,Timeout) ->
652    Timer = start_timer(Timeout),
653    Res = gethostbyaddr_tm(Address, Timer),
654    _ = stop_timer(Timer),
655    Res.
656
657gethostbyaddr_tm(Address,Timer) ->
658    gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)).
659
660
661-spec socket_to_list(Socket) -> list() when
662      Socket :: socket().
663
664socket_to_list({'$inet', GenSocketMod, _} = Socket)
665  when is_atom(GenSocketMod) ->
666    GenSocketMod:?FUNCTION_NAME(Socket);
667socket_to_list(Socket) when is_port(Socket) ->
668    erlang:port_to_list(Socket).
669
670
671
672-spec info(Socket) -> Info when
673      Socket :: socket(),
674      Info :: term().
675
676info({'$inet', GenSocketMod, _} = Socket)
677  when is_atom(GenSocketMod) ->
678    GenSocketMod:?FUNCTION_NAME(Socket);
679info(Socket) when is_port(Socket) ->
680    case port_info(Socket) of
681	#{states := _} = PortInfo ->
682            case inet:getopts(Socket, [active]) of
683                {ok, [{active, Active}]} ->
684                    PortInfo#{active => Active};
685                _ ->
686                    PortInfo
687            end;
688	PortInfo0 ->
689	    %% Its actually possible to call this function for non-socket ports,
690	    %% but in that case we have no status or statistics.
691	    PortInfo1 =
692		case prim_inet:getstatus(Socket) of
693		    {ok, State} ->
694			PortInfo0#{states => State};
695		    _ ->
696			PortInfo0
697		end,
698	    case getstat(Socket) of
699		{ok, Stats0} ->
700		    PortInfo1#{counters => maps:from_list(Stats0)};
701		_ ->
702		    PortInfo1
703	    end
704    end.
705
706port_info(P) when is_port(P) ->
707    case erlang:port_info(P) of
708	PI0 when is_list(PI0) ->
709	    PI1 = port_info(PI0, [connected, links, input, output]) ++
710		[erlang:port_info(P, memory), erlang:port_info(P, monitors)],
711	    PI2 = pi_replace([{connected, owner}], PI1),
712	    maps:from_list(PI2);
713	_ ->
714	    #{states => [closed]}
715    end.
716
717port_info(PI, Items) when is_list(PI) ->
718    port_info(PI, Items, []).
719
720port_info(_PI, [], Acc) ->
721    Acc;
722port_info(PI, [Item | Items], Acc) ->
723    Val = proplists:get_value(Item, PI),
724    port_info(PI, Items, [{Item, Val} | Acc]).
725
726pi_replace([], Items) ->
727    Items;
728pi_replace([{Key1, Key2}|Keys], Items) ->
729    case lists:keysearch(Key1, 1, Items) of
730        {value, {Key1, Value}} ->
731            Items2 = lists:keyreplace(Key1, 1, Items, {Key2, Value}),
732            pi_replace(Keys, Items2);
733        false ->
734            pi_replace(Keys, Items)
735    end.
736
737-spec ip(Ip :: ip_address() | string() | atom()) ->
738	{'ok', ip_address()} | {'error', posix()}.
739
740ip({A,B,C,D}) when ?ip(A,B,C,D) ->
741    {ok, {A,B,C,D}};
742ip(Name) ->
743    case gethostbyname(Name) of
744	{ok, Ent} ->
745	    {ok, hd(Ent#hostent.h_addr_list)};
746	Error -> Error
747    end.
748
749%% This function returns the erlang port used (with inet_drv)
750
751-spec getll(Socket :: socket()) -> {'ok', socket()}.
752
753getll(Socket) when is_port(Socket) ->
754    {ok, Socket}.
755
756%%
757%% Return the internal file descriptor number
758%%
759
760-spec getfd(Socket :: socket()) ->
761	{'ok', non_neg_integer()} | {'error', posix()}.
762
763getfd(Socket) ->
764    prim_inet:getfd(Socket).
765
766%%
767%% Lookup an ip address
768%%
769
770-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
771      Host :: ip_address() | hostname(),
772      Family :: address_family(),
773      Address :: ip_address().
774
775getaddr(Address, Family) ->
776    getaddr(Address, Family, infinity).
777
778-spec getaddr(Host :: ip_address() | hostname(),
779	      Family :: address_family(),
780	      Timeout :: non_neg_integer() | 'infinity') ->
781	{'ok', ip_address()} | {'error', posix()}.
782
783getaddr(Address, Family, Timeout) ->
784    Timer = start_timer(Timeout),
785    Res = getaddr_tm(Address, Family, Timer),
786    _ = stop_timer(Timer),
787    Res.
788
789getaddr_tm(Address, Family, Timer) ->
790    case getaddrs_tm(Address, Family, Timer) of
791	{ok, [IP|_]} -> {ok, IP};
792	Error -> Error
793    end.
794
795-spec getaddrs(Host, Family) ->
796	{ok, Addresses} | {error, posix()} when
797      Host :: ip_address() | hostname(),
798      Family :: address_family(),
799      Addresses :: [ip_address()].
800
801getaddrs(Address, Family) ->
802    getaddrs(Address, Family, infinity).
803
804-spec getaddrs(Host :: ip_address() | string() | atom(),
805	       Family :: address_family(),
806	       Timeout :: non_neg_integer() | 'infinity') ->
807	{'ok', [ip_address()]} | {'error', posix()}.
808
809getaddrs(Address, Family, Timeout) ->
810    Timer = start_timer(Timeout),
811    Res = getaddrs_tm(Address, Family, Timer),
812    _ = stop_timer(Timer),
813    Res.
814
815-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
816	{'ok', string()} | {'error', posix()}.
817
818getservbyport(Port, Proto) ->
819    case inet_udp:open(0, []) of
820	{ok,U} ->
821	    Res = prim_inet:getservbyport(U, Port, Proto),
822	    inet_udp:close(U),
823	    Res;
824	Error -> Error
825    end.
826
827-spec getservbyname(Name :: atom() | string(),
828	            Protocol :: atom() | string()) ->
829	{'ok', port_number()} | {'error', posix()}.
830
831getservbyname(Name, Protocol) when is_atom(Name) ->
832    case inet_udp:open(0, []) of
833	{ok,U} ->
834	    Res = prim_inet:getservbyname(U, Name, Protocol),
835	    inet_udp:close(U),
836	    Res;
837	Error -> Error
838    end.
839
840-spec ntoa(IpAddress) -> Address | {error, einval} when
841      Address :: string(),
842      IpAddress :: ip_address().
843ntoa(Addr) ->
844    inet_parse:ntoa(Addr).
845
846-spec parse_ipv4_address(Address) ->
847	{ok, IPv4Address} | {error, einval} when
848      Address :: string(),
849      IPv4Address :: ip_address().
850parse_ipv4_address(Addr) ->
851    inet_parse:ipv4_address(Addr).
852
853-spec parse_ipv6_address(Address) ->
854	{ok, IPv6Address} | {error, einval} when
855      Address :: string(),
856      IPv6Address :: ip_address().
857parse_ipv6_address(Addr) ->
858    inet_parse:ipv6_address(Addr).
859
860-spec parse_ipv4strict_address(Address) ->
861	{ok, IPv4Address} | {error, einval} when
862      Address :: string(),
863      IPv4Address :: ip_address().
864parse_ipv4strict_address(Addr) ->
865    inet_parse:ipv4strict_address(Addr).
866
867-spec parse_ipv6strict_address(Address) ->
868	{ok, IPv6Address} | {error, einval} when
869      Address :: string(),
870      IPv6Address :: ip_address().
871parse_ipv6strict_address(Addr) ->
872    inet_parse:ipv6strict_address(Addr).
873
874-spec parse_address(Address) ->
875	{ok, IPAddress} | {error, einval} when
876      Address :: string(),
877      IPAddress :: ip_address().
878parse_address(Addr) ->
879    inet_parse:address(Addr).
880
881-spec parse_strict_address(Address) ->
882	{ok, IPAddress} | {error, einval} when
883      Address :: string(),
884      IPAddress :: ip_address().
885parse_strict_address(Addr) ->
886    inet_parse:strict_address(Addr).
887
888-spec ipv4_mapped_ipv6_address(ip_address()) -> ip_address().
889ipv4_mapped_ipv6_address({D1,D2,D3,D4})
890  when (D1 bor D2 bor D3 bor D4) < 256 ->
891    {0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4};
892ipv4_mapped_ipv6_address({D1,D2,D3,D4,D5,D6,D7,D8})
893  when (D1 bor D2 bor D3 bor D4 bor D5 bor D6 bor D7 bor D8) < 65536 ->
894    {D7 bsr 8,D7 band 255,D8 bsr 8,D8 band 255}.
895
896%% Return a list of available options
897options() ->
898    [
899     tos, tclass, priority, reuseaddr, keepalive, dontroute, linger,
900     broadcast, sndbuf, recbuf, nodelay, ipv6_v6only,
901     buffer, header, active, packet, deliver, mode,
902     multicast_if, multicast_ttl, multicast_loop,
903     exit_on_close, high_watermark, low_watermark,
904     high_msgq_watermark, low_msgq_watermark,
905     send_timeout, send_timeout_close, show_econnreset
906    ].
907
908%% Return a list of statistics options
909
910-spec stats() -> [stat_option(),...].
911
912stats() ->
913    [recv_oct, recv_cnt, recv_max, recv_avg, recv_dvi,
914     send_oct, send_cnt, send_max, send_avg, send_pend].
915
916
917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918%% Available options for tcp:connect
919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920connect_options() ->
921    [tos, tclass, priority, reuseaddr, keepalive, linger, nodelay,
922     sndbuf, recbuf,
923     recvtos, recvtclass, ttl, recvttl,
924     header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
925     exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
926     low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
927     show_econnreset, bind_to_device].
928
929connect_options(Opts, Mod) ->
930    BaseOpts =
931	case application:get_env(kernel, inet_default_connect_options) of
932	    {ok,List} when is_list(List) ->
933		NList = [{active, true} | lists:keydelete(active,1,List)],
934		#connect_opts{ opts = NList};
935	    {ok,{active,_Bool}} ->
936		#connect_opts{ opts = [{active,true}]};
937	    {ok,Option} ->
938		#connect_opts{ opts = [{active,true}, Option]};
939	    _ ->
940		#connect_opts{ opts = [{active,true}]}
941	end,
942    case con_opt(Opts, BaseOpts, connect_options()) of
943	{ok, R} ->
944	    {ok, R#connect_opts {
945		   opts = lists:reverse(R#connect_opts.opts),
946		   ifaddr = Mod:translate_ip(R#connect_opts.ifaddr)
947		  }};
948	Error -> Error
949    end.
950
951con_opt([{raw,A,B,C}|Opts],#connect_opts{} = R,As) ->
952    con_opt([{raw,{A,B,C}}|Opts],R,As);
953con_opt([Opt | Opts], #connect_opts{} = R, As) ->
954    case Opt of
955	{ip,IP}     -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
956	{ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
957	{port,P}    -> con_opt(Opts, R#connect_opts { port = P }, As);
958	{fd,Fd}     -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
959	binary      -> con_add(mode, binary, R, Opts, As);
960	list        -> con_add(mode, list, R, Opts, As);
961	{netns,NS} ->
962	    BinNS = filename2binary(NS),
963	    case prim_inet:is_sockopt_val(netns, BinNS) of
964		true ->
965		    con_opt(Opts, R#connect_opts { fd = [{netns,BinNS}] }, As);
966		false ->
967		    {error, badarg}
968	    end;
969        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
970            NOpts = lists:keydelete(active, 1, R#connect_opts.opts),
971            con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As);
972	{line_delimiter,C} when is_integer(C), C >= 0, C =< 255 ->
973	    con_add(line_delimiter, C, R, Opts, As);
974	{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
975	_ -> {error, badarg}
976    end;
977con_opt([], #connect_opts{} = R, _) ->
978    {ok, R}.
979
980con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
981    case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of
982	{ok, SOpts} ->
983	    con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts);
984	Error -> Error
985    end.
986
987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988%% Available options for tcp:listen
989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990listen_options() ->
991    [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
992     recvtos, recvtclass, ttl, recvttl,
993     header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
994     exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
995     low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
996     packet_size, raw, show_econnreset, bind_to_device].
997
998listen_options(Opts, Mod) ->
999    BaseOpts =
1000	case application:get_env(kernel, inet_default_listen_options) of
1001	    {ok,List} when is_list(List) ->
1002		NList = [{active, true} | lists:keydelete(active,1,List)],
1003		#listen_opts{ opts = NList};
1004	    {ok,{active,_Bool}} ->
1005		#listen_opts{ opts = [{active,true}]};
1006	    {ok,Option} ->
1007		#listen_opts{ opts = [{active,true}, Option]};
1008	    _ ->
1009		#listen_opts{ opts = [{active,true}]}
1010	end,
1011    case list_opt(Opts, BaseOpts, listen_options()) of
1012	{ok, R} ->
1013	    {ok, R#listen_opts {
1014		   opts = lists:reverse(R#listen_opts.opts),
1015		   ifaddr = Mod:translate_ip(R#listen_opts.ifaddr)
1016		  }};
1017	Error -> Error
1018    end.
1019
1020list_opt([{raw,A,B,C}|Opts], #listen_opts{} = R, As) ->
1021    list_opt([{raw,{A,B,C}}|Opts], R, As);
1022list_opt([Opt | Opts], #listen_opts{} = R, As) ->
1023    case Opt of
1024	{ip,IP}      ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
1025	{ifaddr,IP}  ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
1026	{port,P}     ->  list_opt(Opts, R#listen_opts { port = P }, As);
1027	{fd,Fd}      ->  list_opt(Opts, R#listen_opts { fd = Fd }, As);
1028	{backlog,BL} ->  list_opt(Opts, R#listen_opts { backlog = BL }, As);
1029	binary       ->  list_add(mode, binary, R, Opts, As);
1030	list         ->  list_add(mode, list, R, Opts, As);
1031	{netns,NS} ->
1032	    BinNS = filename2binary(NS),
1033	    case prim_inet:is_sockopt_val(netns, BinNS) of
1034		true ->
1035		    list_opt(Opts, R#listen_opts { fd = [{netns,BinNS}] }, As);
1036		false ->
1037		    {error, badarg}
1038	    end;
1039        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
1040            NOpts = lists:keydelete(active, 1, R#listen_opts.opts),
1041            list_opt(Opts, R#listen_opts { opts = [{active,N}|NOpts] }, As);
1042	{Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
1043	_ -> {error, badarg}
1044    end;
1045list_opt([], #listen_opts{} = R, _SockOpts) ->
1046    {ok, R}.
1047
1048list_add(Name, Val, #listen_opts{} = R, Opts, As) ->
1049    case add_opt(Name, Val, R#listen_opts.opts, As) of
1050	{ok, SOpts} ->
1051	    list_opt(Opts, R#listen_opts { opts = SOpts }, As);
1052	Error -> Error
1053    end.
1054
1055tcp_module(Opts) ->
1056    tcp_module_1(Opts, undefined).
1057
1058tcp_module(Opts, Addr) ->
1059    Address = {undefined,Addr},
1060    %% Address has to be a 2-tuple but the first element is ignored
1061    tcp_module_1(Opts, Address).
1062
1063tcp_module_1(Opts, Address) ->
1064    mod(
1065      Opts, tcp_module, Address,
1066      #{inet => inet_tcp, inet6 => inet6_tcp, local => local_tcp}).
1067
1068gen_tcp_module([{inet_backend, Flag}|Opts]) ->
1069    gen_tcp_module(Opts, Flag);
1070gen_tcp_module(Opts) ->
1071    gen_tcp_module(
1072      Opts,
1073      persistent_term:get(
1074        {kernel, inet_backend}, ?DEFAULT_KERNEL_INET_BACKEND)).
1075%%
1076gen_tcp_module(Opts, inet) ->
1077    {gen_tcp, Opts};
1078gen_tcp_module(Opts, socket) ->
1079    {gen_tcp_socket, Opts}.
1080
1081
1082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083%% Available options for udp:open
1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085udp_options() ->
1086    [
1087     tos, tclass,
1088     priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
1089     recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
1090     broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
1091     add_membership, drop_membership, read_packets, raw,
1092     high_msgq_watermark, low_msgq_watermark, bind_to_device
1093    ].
1094
1095
1096udp_options(Opts, Mod) ->
1097    case udp_opt(Opts, #udp_opts { }, udp_options()) of
1098	{ok, R} ->
1099	    {ok, R#udp_opts {
1100		   opts = lists:reverse(R#udp_opts.opts),
1101		   ifaddr = Mod:translate_ip(R#udp_opts.ifaddr)
1102		  }};
1103	Error -> Error
1104    end.
1105
1106udp_opt([{raw,A,B,C}|Opts], #udp_opts{} = R, As) ->
1107    udp_opt([{raw,{A,B,C}}|Opts], R, As);
1108udp_opt([Opt | Opts], #udp_opts{} = R, As) ->
1109    case Opt of
1110	{ip,IP}     ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
1111	{ifaddr,IP} ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
1112	{port,P}    ->  udp_opt(Opts, R#udp_opts { port = P }, As);
1113	{fd,Fd}     ->  udp_opt(Opts, R#udp_opts { fd = Fd }, As);
1114	binary      ->  udp_add(mode, binary, R, Opts, As);
1115	list        ->  udp_add(mode, list, R, Opts, As);
1116	{netns,NS} ->
1117	    BinNS = filename2binary(NS),
1118	    case prim_inet:is_sockopt_val(netns, BinNS) of
1119		true ->
1120		    udp_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As);
1121		false ->
1122		    {error, badarg}
1123	    end;
1124        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
1125            NOpts = lists:keydelete(active, 1, R#udp_opts.opts),
1126            udp_opt(Opts, R#udp_opts { opts = [{active,N}|NOpts] }, As);
1127	{Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
1128	_ -> {error, badarg}
1129    end;
1130udp_opt([], #udp_opts{} = R, _SockOpts) ->
1131    {ok, R}.
1132
1133udp_add(Name, Val, #udp_opts{} = R, Opts, As) ->
1134    case add_opt(Name, Val, R#udp_opts.opts, As) of
1135	{ok, SOpts} ->
1136	    udp_opt(Opts, R#udp_opts { opts = SOpts }, As);
1137	Error -> Error
1138    end.
1139
1140udp_module(Opts) ->
1141    mod(
1142      Opts, udp_module, undefined,
1143      #{inet => inet_udp, inet6 => inet6_udp, local => local_udp}).
1144
1145gen_udp_module([{inet_backend, Flag}|Opts]) ->
1146    gen_udp_module(Opts, Flag);
1147gen_udp_module(Opts) ->
1148    gen_udp_module(
1149      Opts,
1150      persistent_term:get(
1151        {kernel, inet_backend}, ?DEFAULT_KERNEL_INET_BACKEND)).
1152%%
1153gen_udp_module(Opts, inet) ->
1154    {gen_udp, Opts};
1155gen_udp_module(Opts, socket) ->
1156    {gen_udp_socket, Opts}.
1157
1158
1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160%% Available options for sctp:open
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%  Currently supported options include:
1163%  (*) {mode,   list|binary}	 or just list|binary
1164%  (*) {active, true|false|once|N}
1165%  (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6
1166%  (*) options set via setsockopt.
1167%      The full list is below in sctp_options/0 .
1168%  All other options are currently NOT supported. In particular:
1169%  (*) multicast on SCTP is not (yet) supported, as it may be incompatible
1170%      with automatic associations;
1171%  (*) passing of open FDs ("fdopen") is not supported.
1172sctp_options() ->
1173[   % The following are generic inet options supported for SCTP sockets:
1174    mode, active, buffer, tos, tclass, ttl,
1175    priority, dontroute, reuseaddr, linger,
1176    recvtos, recvtclass, recvttl,
1177    sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
1178    bind_to_device,
1179
1180    % Other options are SCTP-specific (though they may be similar to their
1181    % TCP and UDP counter-parts):
1182    sctp_rtoinfo,   		 sctp_associnfo,	sctp_initmsg,
1183    sctp_autoclose,		 sctp_nodelay,		sctp_disable_fragments,
1184    sctp_i_want_mapped_v4_addr,  sctp_maxseg,		sctp_primary_addr,
1185    sctp_set_peer_primary_addr,  sctp_adaptation_layer,	sctp_peer_addr_params,
1186    sctp_default_send_param,	 sctp_events,		sctp_delayed_ack_time,
1187    sctp_status,	   	 sctp_get_peer_addr_info
1188].
1189
1190sctp_options(Opts, Mod)  ->
1191    case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
1192	{ok,SO} ->
1193	    {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}};
1194	Error -> Error
1195    end.
1196
1197sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) ->
1198    case Opt of
1199	{ip,IP} ->
1200	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
1201	{ifaddr,IP} ->
1202	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
1203	{port,Port} ->
1204	    case Mod:getserv(Port) of
1205		{ok,P} ->
1206		    sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As);
1207		Error -> Error
1208	    end;
1209	{type,Type} when Type =:= seqpacket; Type =:= stream ->
1210	    sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As);
1211	binary		-> sctp_opt (Opts, Mod, R, As, mode, binary);
1212	list		-> sctp_opt (Opts, Mod, R, As, mode, list);
1213	{netns,NS} ->
1214	    BinNS = filename2binary(NS),
1215	    case prim_inet:is_sockopt_val(netns, BinNS) of
1216		true ->
1217		    sctp_opt(
1218		      Opts, Mod,
1219		      R#sctp_opts { fd = [{netns,BinNS}] },
1220		      As);
1221		false ->
1222		    {error, badarg}
1223	    end;
1224        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
1225            NOpts = lists:keydelete(active, 1, R#sctp_opts.opts),
1226            sctp_opt(Opts, Mod, R#sctp_opts { opts = [{active,N}|NOpts] }, As);
1227	{Name,Val}	-> sctp_opt (Opts, Mod, R, As, Name, Val);
1228	_ -> {error,badarg}
1229    end;
1230sctp_opt([], _Mod, #sctp_opts{ifaddr=IfAddr}=R, _SockOpts) ->
1231    if is_list(IfAddr) ->
1232	    {ok, R#sctp_opts{ifaddr=lists:reverse(IfAddr)}};
1233       true ->
1234	    {ok, R}
1235    end.
1236
1237sctp_opt(Opts, Mod, #sctp_opts{} = R, As, Name, Val) ->
1238    case add_opt(Name, Val, R#sctp_opts.opts, As) of
1239	{ok,SocketOpts} ->
1240	    sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As);
1241	Error -> Error
1242    end.
1243
1244sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
1245    IP = Mod:translate_ip(Addr),
1246    sctp_opt(Opts, Mod,
1247	     R#sctp_opts{
1248	       ifaddr=case IfAddr of
1249			  undefined              -> IP;
1250			  _ when is_list(IfAddr) -> [IP|IfAddr];
1251			  _                      -> [IP,IfAddr]
1252		      end}, As).
1253
1254sctp_module(Opts) ->
1255    mod(
1256      Opts, sctp_module, undefined,
1257      #{inet => inet_sctp, inet6 => inet6_sctp}).
1258
1259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1260%% Util to check and insert option in option list
1261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1262
1263add_opt(Name, Val, Opts, As) ->
1264    case lists:member(Name, As) of
1265	true ->
1266	    case prim_inet:is_sockopt_val(Name, Val) of
1267		true when Name =:= raw ->
1268		    {ok, [{Name,Val} | Opts]};
1269		true ->
1270		    Opts1 = lists:keydelete(Name, 1, Opts),
1271		    {ok, [{Name,Val} | Opts1]};
1272		false -> {error,badarg}
1273	    end;
1274	false -> {error,badarg}
1275    end.
1276
1277
1278%% Passthrough all unknown - catch type errors later
1279filename2binary(List) when is_list(List) ->
1280    OutEncoding = file:native_name_encoding(),
1281    try unicode:characters_to_binary(List, unicode, OutEncoding) of
1282	Bin when is_binary(Bin) ->
1283	    Bin;
1284	_ ->
1285	    List
1286    catch
1287	error:badarg ->
1288	    List
1289    end;
1290filename2binary(Bin) ->
1291    Bin.
1292
1293binary2filename(Bin) ->
1294    InEncoding = file:native_name_encoding(),
1295    case unicode:characters_to_list(Bin, InEncoding) of
1296	Filename when is_list(Filename) ->
1297	    Filename;
1298	_ ->
1299	    %% For getopt/setopt of netns this should only happen if
1300	    %% a binary with wrong encoding was used when setting the
1301	    %% option, hence the user shall eat his/her own medicine.
1302	    %%
1303	    %% I.e passthrough here too for now.
1304	    %% Future usecases will most probably not want this,
1305	    %% rather Unicode error or warning
1306	    %% depending on emulator flag instead.
1307	    Bin
1308    end.
1309
1310%% Protocol independent, i.e common code for all
1311%% inet_* and inet6_* modules
1312%%
1313translate_ip(any,      inet)  -> {0,0,0,0};
1314translate_ip(loopback, inet)  -> {127,0,0,1};
1315translate_ip(any,      inet6) -> {0,0,0,0,0,0,0,0};
1316translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
1317translate_ip(IP, _)           -> IP.  % undefined goes here
1318
1319mod(Opts, Tag, Address, Map) ->
1320    mod(Opts, Tag, Address, Map, undefined, []).
1321%%
1322mod([{Tag, M}|Opts], Tag, Address, Map, Mod, Acc) ->
1323    mod(Opts, Tag, Address, Map, Mod, Acc, M);
1324mod([{T, _} = Opt|Opts], Tag, _Address, Map, Mod, Acc)
1325  when T =:= ip; T =:= ifaddr->
1326    mod(Opts, Tag, Opt, Map, Mod, [Opt|Acc]);
1327mod([Family|Opts], Tag, Address, Map, Mod, Acc) when is_atom(Family) ->
1328    case Map of
1329	#{Family := M} ->
1330	    mod(Opts, Tag, Address, Map, Mod, Acc, M);
1331	#{} ->
1332	    mod(Opts, Tag, Address, Map, Mod, [Family|Acc])
1333    end;
1334mod([Opt|Opts], Tag, Address, Map, Mod, Acc) ->
1335    mod(Opts, Tag, Address, Map, Mod, [Opt|Acc]);
1336mod([], Tag, Address, Map, undefined, Acc) ->
1337    {case Address of
1338	 {_, {local, _}} ->
1339	     case Map of
1340		 #{local := Mod} ->
1341		     Mod;
1342		 #{} ->
1343		     inet_db:Tag()
1344	     end;
1345	 {_, IP} when tuple_size(IP) =:= 8 ->
1346	     #{inet := IPv4Mod} = Map,
1347	     %% Get the mod, but IPv6 address overrides default IPv4
1348	     case inet_db:Tag() of
1349		 IPv4Mod ->
1350		     #{inet6 := IPv6Mod} = Map,
1351		     IPv6Mod;
1352		 Mod ->
1353		     Mod
1354	     end;
1355	 _ ->
1356	     inet_db:Tag()
1357     end, lists:reverse(Acc)};
1358mod([], _Tag, _Address, _Map, Mod, Acc) ->
1359    {Mod, lists:reverse(Acc)}.
1360%%
1361mod(Opts, Tag, Address, Map, undefined, Acc, M) ->
1362    mod(Opts, Tag, Address, Map, M, Acc);
1363mod(Opts, Tag, Address, Map, Mod, Acc, _M) ->
1364    mod(Opts, Tag, Address, Map, Mod, Acc).
1365
1366getaddrs_tm({A,B,C,D} = IP, Fam, _)  ->
1367    %% Only "syntactic" validation and check of family.
1368    if
1369	?ip(A,B,C,D) ->
1370	    if
1371		Fam =:= inet -> {ok,[IP]};
1372		true -> {error,eafnosupport}
1373	    end;
1374	true -> {error,einval}
1375    end;
1376getaddrs_tm({A,B,C,D,E,F,G,H} = IP, Fam, _) ->
1377    %% Only "syntactic" validation; we assume that the address was
1378    %% "semantically" validated when it was converted to a tuple.
1379    if
1380	?ip6(A,B,C,D,E,F,G,H) ->
1381	    if
1382		Fam =:= inet6 -> {ok,[IP]};
1383		true -> {error,eafnosupport}
1384	    end;
1385	true -> {error,einval}
1386    end;
1387getaddrs_tm(Address, Family, Timer) when is_atom(Address) ->
1388    getaddrs_tm(atom_to_list(Address), Family, Timer);
1389getaddrs_tm(Address, Family, Timer) ->
1390    case inet_parse:visible_string(Address) of
1391	false ->
1392	    {error,einval};
1393	true ->
1394	    %% Address is a host name or a valid IP address,
1395	    %% either way check it with the resolver.
1396	    case gethostbyname_tm(Address, Family, Timer) of
1397		{ok,Ent} -> {ok,Ent#hostent.h_addr_list};
1398		Error -> Error
1399	    end
1400    end.
1401
1402%%
1403%% gethostbyname with option search
1404%%
1405gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
1406    Result = gethostbyname_string(Name, Type),
1407    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1408gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
1409    Result = inet_res:gethostbyname_tm(Name, Type, Timer),
1410    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1411gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
1412    Result = inet_hosts:gethostbyname(Name, Type),
1413    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1414gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
1415    gethostbyname_tm_native(Name, Type, Timer, Opts);
1416gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
1417    gethostbyname_tm_native(Name, Type, Timer, Opts);
1418gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
1419    gethostbyname_tm_native(Name, Type, Timer, Opts);
1420gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
1421    gethostbyname_tm_native(Name, Type, Timer, Opts);
1422gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
1423    gethostbyname_tm_native(Name, Type, Timer, Opts);
1424gethostbyname_tm(Name, Type, Timer, [_|Opts]) ->
1425    gethostbyname_tm(Name, Type, Timer, Opts);
1426%% Make sure we always can look up our own hostname.
1427gethostbyname_tm(Name, Type, Timer, []) ->
1428    Result = gethostbyname_self(Name, Type),
1429    gethostbyname_tm(Name, Type, Timer, [], Result).
1430
1431gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
1432    case Result of
1433	{ok,_} ->
1434	    Result;
1435	{error,formerr} ->
1436	    {error,einval};
1437	{error,_} when Opts =:= [] ->
1438	    {error,nxdomain};
1439	{error,_} ->
1440	    gethostbyname_tm(Name, Type, Timer, tl(Opts))
1441    end.
1442
1443gethostbyname_tm_native(Name, Type, Timer, Opts) ->
1444    %% Fixme: add (global) timeout to gethost_native
1445    Result = inet_gethost_native:gethostbyname(Name, Type),
1446    gethostbyname_tm(Name, Type, Timer, Opts, Result).
1447
1448
1449
1450gethostbyname_self(Name, Type) when is_atom(Name) ->
1451    gethostbyname_self(atom_to_list(Name), Type);
1452gethostbyname_self(Name, Type)
1453  when is_list(Name), Type =:= inet;
1454       is_list(Name), Type =:= inet6 ->
1455    N = inet_db:tolower(Name),
1456    Self = inet_db:gethostname(),
1457    %%
1458    %% This is the final fallback that pretends /etc/hosts has got
1459    %% a line for the hostname on the loopback address.
1460    %% Lookups into /etc/hosts are case insensitive and return
1461    %% what is in the file. Therefore the letter case may differ between
1462    %% the returned hostent record and the hostname that was asked for.
1463    %%
1464    case inet_db:tolower(Self) of
1465	N ->
1466	    {ok,
1467	     make_hostent(
1468	       Self, [translate_ip(loopback, Type)], [], Type)};
1469	_ ->
1470	    case inet_db:res_option(domain) of
1471		"" ->
1472		    {error,nxdomain};
1473		Domain ->
1474		    FQDN = lists:append([Self,".",Domain]),
1475		    case inet_db:tolower(FQDN) of
1476			N ->
1477			    {ok,
1478			     make_hostent(
1479			       FQDN,
1480			       [translate_ip(loopback, Type)], [], Type)};
1481			_ ->
1482			    {error,nxdomain}
1483		    end
1484	    end
1485    end;
1486gethostbyname_self(_, _) ->
1487    {error,formerr}.
1488
1489gethostbyname_string(Name, Type) when is_atom(Name) ->
1490    gethostbyname_string(atom_to_list(Name), Type);
1491gethostbyname_string(Name, Type)
1492  when is_list(Name), Type =:= inet;
1493       is_list(Name), Type =:= inet6 ->
1494    case
1495	case Type of
1496	    inet ->
1497		inet_parse:ipv4_address(Name);
1498	    inet6 ->
1499		inet_parse:ipv6strict_address(Name)
1500	end of
1501	{ok,IP} ->
1502	    {ok,make_hostent(Name, [IP], [], Type)};
1503	{error,einval} ->
1504	    {error,nxdomain}
1505    end;
1506gethostbyname_string(_, _) ->
1507    {error,formerr}.
1508
1509make_hostent(Name, Addrs, Aliases, Type) ->
1510    #hostent{h_name = Name,
1511	     h_aliases = Aliases,
1512	     h_addrtype = Type,
1513	     h_length = case Type of inet -> 4; inet6 -> 16 end,
1514	     h_addr_list = Addrs}.
1515
1516%%
1517%% gethostbyaddr with option search
1518%%
1519gethostbyaddr_tm(Addr, Timer, [dns | Opts]) ->
1520    Res = inet_res:gethostbyaddr_tm(Addr,Timer),
1521    case Res of
1522	{ok,_} -> Res;
1523	{error,timeout} -> Res;
1524	{error,formerr} -> {error, einval};
1525	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts)
1526    end;
1527gethostbyaddr_tm(Addr, Timer, [file | Opts]) ->
1528    case inet_hosts:gethostbyaddr(Addr) of
1529	{error,formerr} -> {error, einval};
1530	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
1531	Result -> Result
1532    end;
1533gethostbyaddr_tm(Addr, Timer, [yp | Opts]) ->
1534    gethostbyaddr_tm_native(Addr, Timer, Opts);
1535gethostbyaddr_tm(Addr, Timer, [nis | Opts]) ->
1536    gethostbyaddr_tm_native(Addr, Timer, Opts);
1537gethostbyaddr_tm(Addr, Timer,  [nisplus | Opts]) ->
1538    gethostbyaddr_tm_native(Addr, Timer, Opts);
1539gethostbyaddr_tm(Addr, Timer, [wins | Opts]) ->
1540    gethostbyaddr_tm_native(Addr, Timer, Opts);
1541gethostbyaddr_tm(Addr, Timer, [native | Opts]) ->
1542    gethostbyaddr_tm_native(Addr, Timer, Opts);
1543gethostbyaddr_tm(Addr, Timer, [_ | Opts]) ->
1544    gethostbyaddr_tm(Addr, Timer, Opts);
1545gethostbyaddr_tm({127,0,0,1}=IP, _Timer, []) ->
1546    gethostbyaddr_self(IP, inet);
1547gethostbyaddr_tm({0,0,0,0,0,0,0,1}=IP, _Timer, []) ->
1548    gethostbyaddr_self(IP, inet6);
1549gethostbyaddr_tm(_Addr, _Timer, []) ->
1550    {error, nxdomain}.
1551
1552gethostbyaddr_self(IP, Type) ->
1553    Name = inet_db:gethostname(),
1554    case inet_db:res_option(domain) of
1555	"" ->
1556	    {ok,make_hostent(Name, [IP], [], Type)};
1557	Domain ->
1558	    {ok,make_hostent(Name++"."++Domain, [IP], [Name], Type)}
1559    end.
1560
1561gethostbyaddr_tm_native(Addr, Timer, Opts) ->
1562    %% Fixme: user timer for timeoutvalue
1563    case inet_gethost_native:gethostbyaddr(Addr) of
1564	{error,formerr} -> {error, einval};
1565	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
1566	Result -> Result
1567    end.
1568
1569
1570-spec open(Fd_or_OpenOpts :: integer() | list(),
1571	   BAddr ::
1572	     socket_address() |
1573	     {ip_address() | 'any' | 'loopback', % Unofficial
1574	      port_number()} |
1575	     {inet, % Unofficial
1576	      {ip4_address() | 'any' | 'loopback',
1577	       port_number()}} |
1578	     {inet6, % Unofficial
1579	      {ip6_address() | 'any' | 'loopback',
1580	       port_number()}} |
1581	     undefined, % Internal - no bind()
1582	   BPort :: port_number(),
1583	   Opts :: [socket_setopt()],
1584	   Protocol :: socket_protocol(),
1585	   Family :: address_family(),
1586	   Type :: socket_type(),
1587	   Module :: atom()) ->
1588	{'ok', port()} | {'error', posix()}.
1589
1590open(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module)
1591  when is_integer(Fd), 0 =< Fd ->
1592    open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module);
1593open(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
1594    open_opts(
1595      Fd_or_OpenOpts,
1596      if
1597          BAddr =:= undefined, BPort =/= 0 ->
1598              translate_ip(any, Family);
1599          true ->
1600              BAddr
1601      end, BPort, Opts, Protocol, Family, Type, Module).
1602
1603%% The only difference between open/8 and open_bind/8 is that
1604%% if Fd_or_OpenOpts is not a FileDescriptor :: non_neg_integer()
1605%% i.e option {fd,Fd} has not been used hence we are not handling
1606%% an already open socket handle, and also if no bind address
1607%% has been specified (BAddr =:= undefined).
1608%%
1609%% Then open_bind/8 will bind to the wildcard address and the
1610%% specified port (BPort, 0 = wildcard port per default),
1611%% which is the legacy behaviour by this module when opening a socket.
1612%%
1613%% In the same situation, open/8 will bind to the wildcard address
1614%% and the specified port, only if BPort is not 0, i.e a bind port
1615%% has been specified to not be the wildcard port.
1616%%
1617%% So open/8 per default does not bind to an address, which
1618%% is used by TCP connect to let the OS automatically bind to
1619%% an address later, during TCP connect operation.  This
1620%% gives the OS more freedom in choosing the originating port and
1621%% therefore makes far more effective use of the port range.
1622
1623-spec open_bind(Fd_or_OpenOpts :: integer() | list(),
1624                BAddr ::
1625                  socket_address() |
1626                  {ip_address() | 'any' | 'loopback', % Unofficial
1627                   port_number()} |
1628                  {inet, % Unofficial
1629                   {ip4_address() | 'any' | 'loopback',
1630                    port_number()}} |
1631                  {inet6, % Unofficial
1632                   {ip6_address() | 'any' | 'loopback',
1633                    port_number()}} |
1634                  undefined, % Internal - translated to 'any'
1635                BPort :: port_number(),
1636                Opts :: [socket_setopt()],
1637                Protocol :: socket_protocol(),
1638                Family :: address_family(),
1639                Type :: socket_type(),
1640                Module :: atom()) ->
1641                       {'ok', port()} | {'error', posix()}.
1642
1643open_bind(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module)
1644  when is_integer(Fd), 0 =< Fd ->
1645    open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module);
1646open_bind(
1647  Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
1648    open_opts(
1649      Fd_or_OpenOpts,
1650      if
1651          BAddr =:= undefined ->
1652              translate_ip(any, Family);
1653          true ->
1654              BAddr
1655      end, BPort, Opts, Protocol, Family, Type, Module).
1656
1657
1658open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
1659    DoNotBind =
1660	%% We do not do any binding if no port+addr options
1661	%% were given, in order to keep backwards compatability
1662	%% with pre Erlang/OTP 17
1663        BAddr =:= undefined, % Presumably already bound
1664    if
1665        DoNotBind ->
1666            0 = BPort, ok; % Assertion
1667        true ->
1668            ok
1669    end,
1670    case prim_inet:fdopen(Protocol, Family, Type, Fd, DoNotBind) of
1671	{ok, S} ->
1672            open_setopts(S, BAddr, BPort, Opts, Module);
1673        Error ->
1674            Error
1675    end.
1676
1677open_opts(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
1678    OpenOpts =
1679	if
1680            is_list(Fd_or_OpenOpts) -> Fd_or_OpenOpts;
1681	    true -> []
1682	end,
1683    case prim_inet:open(Protocol, Family, Type, OpenOpts) of
1684	{ok,S} ->
1685            open_setopts(S, BAddr, BPort, Opts, Module);
1686        Error ->
1687            Error
1688    end.
1689
1690%% If BAddr is undefined - do not bind to an address
1691%%
1692open_setopts(S, BAddr, BPort, Opts, Module) ->
1693    case prim_inet:setopts(S, Opts) of
1694        ok when BAddr =:= undefined ->
1695            inet_db:register_socket(S, Module),
1696            {ok,S};
1697        ok ->
1698            case bind(S, BAddr, BPort) of
1699                {ok, _} ->
1700                    inet_db:register_socket(S, Module),
1701                    {ok,S};
1702                Error  ->
1703                    prim_inet:close(S),
1704                    Error
1705            end;
1706        Error  ->
1707            prim_inet:close(S),
1708            Error
1709    end.
1710
1711
1712
1713bind(S, Addr, Port) when is_list(Addr) ->
1714    bindx(S, Addr, Port);
1715bind(S, Addr, Port) ->
1716    prim_inet:bind(S, Addr, Port).
1717
1718bindx(S, [Addr], Port0) ->
1719    {IP, Port} = set_bindx_port(Addr, Port0),
1720    prim_inet:bind(S, IP, Port);
1721bindx(S, Addrs, Port0) ->
1722    [{IP, Port} | Rest] = [set_bindx_port(Addr, Port0) || Addr <- Addrs],
1723    case prim_inet:bind(S, IP, Port) of
1724	{ok, AssignedPort} when Port =:= 0 ->
1725	    %% On newer Linux kernels, Solaris and FreeBSD, calling
1726	    %% bindx with port 0 is ok, but on SuSE 10, it results in einval
1727	    Rest2 = [change_bindx_0_port(Addr, AssignedPort) || Addr <- Rest],
1728	    prim_inet:bind(S, add, Rest2);
1729	{ok, _} ->
1730	    prim_inet:bind(S, add, Rest);
1731	Error ->
1732	    Error
1733    end.
1734
1735set_bindx_port({_IP, _Port}=Addr, _OtherPort) ->
1736    Addr;
1737set_bindx_port(IP, Port) ->
1738    {IP, Port}.
1739
1740change_bindx_0_port({IP, 0}, AssignedPort) ->
1741    {IP, AssignedPort};
1742change_bindx_0_port({_IP, _Port}=Addr, _AssignedPort) ->
1743    Addr.
1744
1745
1746-spec fdopen(Fd :: non_neg_integer(),
1747	     Opts :: [socket_setopt()],
1748	     Protocol :: socket_protocol(),
1749	     Family :: address_family(),
1750	     Type :: socket_type(),
1751	     Module :: atom()) ->
1752	{'ok', socket()} | {'error', posix()}.
1753
1754fdopen(Fd, Opts, Protocol, Family, Type, Module)
1755  when is_integer(Fd), 0 =< Fd ->
1756    open_fd(Fd, undefined, 0, Opts, Protocol, Family, Type, Module).
1757
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759%%  socket stat
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761
1762-spec i() -> ok.
1763i() -> i(tcp), i(udp), i(sctp).
1764
1765-spec i(socket_protocol()) -> ok.
1766i(Proto) -> i(Proto, [port, module, recv, sent, owner,
1767		      local_address, foreign_address, state, type]).
1768
1769-spec i(socket_protocol(), [atom()]) -> ok.
1770i(tcp, Fs) ->
1771    ii(tcp_sockets(), Fs, tcp);
1772i(udp, Fs) ->
1773    ii(udp_sockets(), Fs, udp);
1774i(sctp, Fs) ->
1775    ii(sctp_sockets(), Fs, sctp).
1776
1777ii(Ss, Fs, Proto) ->
1778    LLs =
1779	case info_lines(Ss, Fs, Proto) of
1780	    [] -> [];
1781	    InfoLines -> [h_line(Fs) | InfoLines]
1782	end,
1783    Maxs = foldl(
1784	     fun(Line,Max0) -> smax(Max0,Line) end,
1785	     duplicate(length(Fs),0),LLs),
1786    Fmt = append(["~-" ++ integer_to_list(N) ++ "s " || N <- Maxs]) ++ "\n",
1787    lists:foreach(fun(Line) -> io:format(Fmt, Line) end, LLs).
1788
1789smax([Max|Ms], [Str|Strs]) ->
1790    N = length(Str),
1791    [if N > Max -> N; true -> Max end | smax(Ms, Strs)];
1792smax([], []) -> [].
1793
1794info_lines(Ss, Fs, Proto) -> [i_line(S, Fs,Proto) || S <- Ss].
1795i_line(S, Fs, Proto)      -> [info(S, F, Proto) || F <- Fs].
1796
1797h_line(Fs) -> [h_field(atom_to_list(F)) || F <- Fs].
1798
1799h_field([C|Cs]) -> [upper(C) | hh_field(Cs)].
1800
1801hh_field([$_,C|Cs]) -> [$\s,upper(C) | hh_field(Cs)];
1802hh_field([C|Cs]) -> [C|hh_field(Cs)];
1803hh_field([]) -> [].
1804
1805upper(C) when C >= $a, C =< $z -> (C-$a) + $A;
1806upper(C) -> C.
1807
1808
1809info({'$inet', GenSocketMod, _} = S, F, Proto) when is_atom(GenSocketMod) ->
1810    case F of
1811	owner ->
1812	    case GenSocketMod:info(S) of
1813		#{owner := Owner} when is_pid(Owner) -> pid_to_list(Owner);
1814		_ -> " "
1815	    end;
1816	port ->
1817	    case GenSocketMod:getopts(S, [fd]) of
1818		{ok, [{fd, FD}]} ->
1819		    "esock[" ++ integer_to_list(FD) ++ "]";
1820		_ ->
1821		    "esock"
1822	    end;
1823	sent ->
1824	    case GenSocketMod:getstat(S, [send_oct]) of
1825		{ok, [{send_oct, N}]} -> integer_to_list(N);
1826		_ -> " "
1827	    end;
1828	recv ->
1829	    case GenSocketMod:getstat(S, [recv_oct]) of
1830		{ok, [{recv_oct, N}]} -> integer_to_list(N);
1831		_ -> " "
1832	    end;
1833	local_address ->
1834	    fmt_addr(GenSocketMod:sockname(S), Proto);
1835	foreign_address ->
1836	    fmt_addr(GenSocketMod:peername(S), Proto);
1837	state ->
1838	    case GenSocketMod:info(S) of
1839		#{rstates := RStates,
1840		  wstates := WStates} -> fmt_compat_status(RStates, WStates);
1841		_ -> " "
1842	    end;
1843	packet ->
1844	    case GenSocketMod:which_packet_type(S) of
1845		{ok, Type} -> atom_to_list(Type);
1846		_ -> " "
1847	    end;
1848	type ->
1849	    case GenSocketMod:info(S) of
1850		#{type := stream} -> "STREAM";
1851		_ -> " "
1852	    end;
1853	%% Why do we have this here? Its never called (see i/2 calling i/2).
1854	fd ->
1855	    case GenSocketMod:getopts(S, [fd]) of
1856		{ok, [{fd, Fd}]} -> integer_to_list(Fd);
1857		_ -> " "
1858	    end;
1859	module ->
1860	    atom_to_list(GenSocketMod)
1861    end;
1862info(S, F, Proto) ->
1863    case F of
1864	owner ->
1865	    case erlang:port_info(S, connected) of
1866		{connected, Owner} -> pid_to_list(Owner);
1867		_ -> " "
1868	    end;
1869	port ->
1870	    case erlang:port_info(S,id) of
1871		{id, Id}  -> integer_to_list(Id);
1872		undefined -> " "
1873	    end;
1874	sent ->
1875	    case prim_inet:getstat(S, [send_oct]) of
1876		{ok,[{send_oct,N}]} -> integer_to_list(N);
1877		_ -> " "
1878	    end;
1879	recv ->
1880	    case  prim_inet:getstat(S, [recv_oct]) of
1881		{ok,[{recv_oct,N}]} -> integer_to_list(N);
1882		_ -> " "
1883	    end;
1884	local_address ->
1885	    fmt_addr(prim_inet:sockname(S), Proto);
1886	foreign_address ->
1887	    fmt_addr(prim_inet:peername(S), Proto);
1888	state ->
1889	    case prim_inet:getstatus(S) of
1890		{ok,Status} -> fmt_status(Status);
1891		_ -> " "
1892	    end;
1893	packet ->
1894	    case prim_inet:getopt(S, packet) of
1895		{ok,Type} when is_atom(Type) -> atom_to_list(Type);
1896		{ok,Type} when is_integer(Type) -> integer_to_list(Type);
1897		_ -> " "
1898	    end;
1899	type ->
1900	    case prim_inet:gettype(S) of
1901		{ok,{_,stream}} -> "STREAM";
1902		{ok,{_,dgram}}  -> "DGRAM";
1903		{ok,{_,seqpacket}} -> "SEQPACKET";
1904		_ -> " "
1905	    end;
1906	%% Why do we have this here? Its never called (see i/2 calling i/2).
1907	fd ->
1908	    case prim_inet:getfd(S) of
1909		{ok, Fd} -> integer_to_list(Fd);
1910		_ -> " "
1911	    end;
1912	module ->
1913	    case inet_db:lookup_socket(S) of
1914		{ok,Mod} -> atom_to_list(Mod);
1915		_ -> "prim_inet"
1916	    end
1917    end.
1918
1919%% Possible flags: (sorted)
1920%% [accepting,bound,busy,connected,connecting,listen,listening,open]
1921%% Actually, we no longer gets listening...
1922fmt_status(Flags) ->
1923    case lists:sort(Flags) of
1924	[accepting | _]               -> "ACCEPTING";
1925	[bound,busy,connected|_]      -> "CONNECTED(BB)";
1926	[bound,connected|_]           -> "CONNECTED(B)";
1927	[bound,listen,listening | _]  -> "LISTENING";
1928	[bound,listen | _]            -> "LISTEN";
1929	[bound,connecting | _]        -> "CONNECTING";
1930	[bound,open]                  -> "BOUND";
1931	[connected,open]              -> "CONNECTED(O)";
1932	[open]                        -> "IDLE";
1933	[]                            -> "CLOSED";
1934	Sorted                        -> fmt_status2(Sorted)
1935    end.
1936
1937fmt_compat_status(RFlags, WFlags) ->
1938    fmt_status(fmt_compat_status_merge(RFlags, WFlags)).
1939
1940fmt_compat_status_merge(RFlags, WFlags) ->
1941    fmt_compat_status_merge(RFlags, WFlags, []).
1942
1943fmt_compat_status_merge([], WFlags, Merged) ->
1944    Merged ++ WFlags;
1945fmt_compat_status_merge([RFlag|RFlags], WFlags, Merged) ->
1946    fmt_compat_status_merge(RFlags,
1947			    lists:delete(RFlag, WFlags),
1948			    [RFlag|Merged]).
1949
1950fmt_status2([H]) ->
1951    fmt_status3(H);
1952fmt_status2([H|T]) ->
1953    fmt_status3(H) ++ ":"  ++ fmt_status2(T).
1954
1955fmt_status3(accepting) ->
1956    "A";
1957fmt_status3(bound) ->
1958    "BD";
1959fmt_status3(busy) ->
1960    "BY";
1961fmt_status3(connected) ->
1962    "CD";
1963fmt_status3(connecting) ->
1964    "CG";
1965fmt_status3(listen) ->
1966    "LN";
1967fmt_status3(listening) ->
1968    "LG";
1969fmt_status3(open) ->
1970    "O";
1971fmt_status3(selected) ->
1972    "SD";
1973fmt_status3(X) when is_atom(X) ->
1974    string:uppercase(atom_to_list(X)).
1975
1976
1977fmt_addr({error,enotconn}, _) -> "*:*";
1978fmt_addr({error,_}, _)        -> " ";
1979fmt_addr({ok,Addr}, Proto) ->
1980    case Addr of
1981	%%Dialyzer {0,0}            -> "*:*";
1982	{{0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
1983	{{0,0,0,0,0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
1984	{{127,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
1985	{{0,0,0,0,0,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
1986	{local, Path} -> "local:" ++ binary_to_list(Path);
1987	{IP,Port} -> inet_parse:ntoa(IP) ++ ":" ++ fmt_port(Port, Proto)
1988    end.
1989
1990fmt_port(N, Proto) ->
1991    case inet:getservbyport(N, Proto) of
1992	{ok, Name} -> Name;
1993	_ -> integer_to_list(N)
1994    end.
1995
1996%% Return a list of all tcp sockets
1997tcp_sockets()  -> port_list("tcp_inet") ++ gen_tcp_socket:which_sockets().
1998udp_sockets()  -> port_list("udp_inet") ++ gen_udp_socket:which_sockets().
1999sctp_sockets() -> port_list("sctp_inet").
2000
2001%% Return all ports having the name 'Name'
2002port_list(Name) ->
2003    filter(
2004      fun(Port) ->
2005	      case erlang:port_info(Port, name) of
2006		  {name, Name} -> true;
2007		  _ -> false
2008	      end
2009      end, erlang:ports()).
2010
2011
2012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013%%  utils
2014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015
2016-spec format_error(Reason) -> string() when
2017      Reason :: posix() | system_limit.
2018
2019format_error(exbadport) -> "invalid port state";
2020format_error(exbadseq) ->  "bad command sequence";
2021format_error(system_limit) ->
2022    "a system limit was hit, probably not enough ports";
2023format_error(Tag) ->
2024    erl_posix_msg:message(Tag).
2025
2026%% Close a TCP socket.
2027tcp_close(S) when is_port(S) ->
2028    %% if exit_on_close is set we must force a close even if remotely closed!!!
2029    prim_inet:close(S),
2030    receive {tcp_closed, S} -> ok after 0 -> ok end.
2031
2032%% Close a UDP socket.
2033udp_close(S) when is_port(S) ->
2034    receive
2035	{udp_closed, S} -> ok
2036    after 0 ->
2037	    prim_inet:close(S),
2038	    receive {udp_closed, S} -> ok after 0 -> ok end
2039    end.
2040
2041%% Set controlling process for TCP socket.
2042tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
2043    case erlang:port_info(S, connected) of
2044	{connected, NewOwner} ->
2045	    ok;
2046	{connected, Pid} when Pid =/= self() ->
2047	    {error, not_owner};
2048	undefined ->
2049	    {error, einval};
2050	_ ->
2051	    case prim_inet:getopt(S, active) of
2052		{ok, A0} ->
2053		    SetOptRes =
2054			case A0 of
2055			    false -> ok;
2056			    _ -> prim_inet:setopt(S, active, false)
2057			end,
2058		    case {tcp_sync_input(S, NewOwner, false), SetOptRes} of
2059			{true, _} ->  %% socket already closed
2060			    ok;
2061			{false, ok} ->
2062			    try erlang:port_connect(S, NewOwner) of
2063				true ->
2064				    unlink(S), %% unlink from port
2065				    case A0 of
2066					false -> ok;
2067					_ -> prim_inet:setopt(S, active, A0)
2068				    end
2069			    catch
2070				error:Reason ->
2071				    {error, Reason}
2072			    end;
2073			{false, Error} ->
2074			    Error
2075		    end;
2076		Error ->
2077		    Error
2078	    end
2079    end.
2080
2081tcp_sync_input(S, Owner, Flag) ->
2082    receive
2083	{tcp, S, Data} ->
2084	    Owner ! {tcp, S, Data},
2085	    tcp_sync_input(S, Owner, Flag);
2086	{tcp_closed, S} ->
2087	    Owner ! {tcp_closed, S},
2088	    tcp_sync_input(S, Owner, true);
2089	{S, {data, Data}} ->
2090	    Owner ! {S, {data, Data}},
2091	    tcp_sync_input(S, Owner, Flag);
2092	{inet_async, S, Ref, Status} ->
2093	    Owner ! {inet_async, S, Ref, Status},
2094	    tcp_sync_input(S, Owner, Flag);
2095	{inet_reply, S, Status} ->
2096	    Owner ! {inet_reply, S, Status},
2097	    tcp_sync_input(S, Owner, Flag)
2098    after 0 ->
2099	    Flag
2100    end.
2101
2102%% Set controlling process for UDP or SCTP socket.
2103udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
2104    case erlang:port_info(S, connected) of
2105	{connected, NewOwner} ->
2106	    ok;
2107	{connected, Pid} when Pid =/= self() ->
2108	    {error, not_owner};
2109	_ ->
2110	    {ok, A0} = prim_inet:getopt(S, active),
2111	    ok = prim_inet:setopt(S, active, false),
2112	    udp_sync_input(S, NewOwner),
2113	    try erlang:port_connect(S, NewOwner) of
2114		true ->
2115		    unlink(S),
2116		    ok = prim_inet:setopt(S, active, A0)
2117	    catch
2118		error:Reason ->
2119		    {error, Reason}
2120	    end
2121    end.
2122
2123udp_sync_input(S, Owner) ->
2124    receive
2125	{sctp, S, _, _, _}=Msg    -> udp_sync_input(S, Owner, Msg);
2126	{udp, S, _, _, _}=Msg     -> udp_sync_input(S, Owner, Msg);
2127	{udp_closed, S}=Msg       -> udp_sync_input(S, Owner, Msg);
2128	{S, {data,_}}=Msg         -> udp_sync_input(S, Owner, Msg);
2129	{inet_async, S, _, _}=Msg -> udp_sync_input(S, Owner, Msg);
2130	{inet_reply, S, _}=Msg    -> udp_sync_input(S, Owner, Msg)
2131    after 0 ->
2132	    ok
2133    end.
2134
2135udp_sync_input(S, Owner, Msg) ->
2136    Owner ! Msg,
2137    udp_sync_input(S, Owner).
2138
2139start_timer(infinity) -> false;
2140start_timer(Timeout) ->
2141    erlang:start_timer(Timeout, self(), inet).
2142
2143timeout(false) -> infinity;
2144timeout(Timer) ->
2145    case erlang:read_timer(Timer) of
2146	false -> 0;
2147	Time  -> Time
2148    end.
2149
2150timeout(Time, false) -> Time;
2151timeout(Time, Timer) ->
2152    TimerTime = timeout(Timer),
2153    if TimerTime < Time -> TimerTime;
2154       true -> Time
2155    end.
2156
2157stop_timer(false) -> false;
2158stop_timer(Timer) ->
2159    case erlang:cancel_timer(Timer) of
2160	false ->
2161	    receive
2162		{timeout,Timer,_} -> false
2163	    after 0 ->
2164		    false
2165	    end;
2166	T -> T
2167    end.
2168
2169
2170lock_socket(S,Val) ->
2171    case erlang:port_info(S, connected) of
2172	{connected, Pid} when Pid =/= self() ->
2173	    {error, not_owner};
2174	undefined ->
2175	    {error, einval};
2176	_ ->
2177	    prim_inet:ignorefd(S,Val)
2178    end.
2179