PageRenderTime 140ms CodeModel.GetById 3ms app.highlight 124ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/kernel/src/inet.erl

https://github.com/bsmr-erlang/otp
Erlang | 1832 lines | 1476 code | 224 blank | 132 comment | 13 complexity | d2294207c967405b2c62330eb0a544c0 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1%%
   2%% %CopyrightBegin%
   3%%
   4%% Copyright Ericsson AB 1997-2018. 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	 ip/1, stats/0, options/0, 
  35	 pushf/3, popf/1, close/1, gethostname/0, gethostname/1, 
  36	 parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
  37	 parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1,
  38         ntoa/1, ipv4_mapped_ipv6_address/1]).
  39
  40-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
  41-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]).
  42
  43-export([i/0, i/1, i/2]).
  44
  45-export([getll/1, getfd/1, open/8, fdopen/6]).
  46
  47-export([tcp_controlling_process/2, udp_controlling_process/2,
  48	 tcp_close/1, udp_close/1]).
  49
  50%% used by sendfile
  51-export([lock_socket/2]).
  52
  53%% used by socks5
  54-export([setsockname/2, setpeername/2]).
  55
  56%% resolve
  57-export([gethostbyname/1, gethostbyname/2, gethostbyname/3, 
  58	 gethostbyname_tm/3]).
  59-export([gethostbyname_string/2, gethostbyname_self/2]).
  60-export([gethostbyaddr/1, gethostbyaddr/2, 
  61	 gethostbyaddr_tm/2]).
  62
  63-export([getservbyname/2, getservbyport/2]).
  64-export([getaddrs/2, getaddrs/3, getaddrs_tm/3,
  65	 getaddr/2, getaddr/3, getaddr_tm/3]).
  66-export([translate_ip/2]).
  67
  68-export([get_rc/0]).
  69
  70%% format error
  71-export([format_error/1]).
  72
  73%% timer interface
  74-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
  75
  76-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
  77              ip6_address/0, ip_address/0, port_number/0,
  78	      local_address/0, socket_address/0, returned_non_ip_address/0,
  79	      socket_setopt/0, socket_getopt/0, ancillary_data/0,
  80	      posix/0, socket/0, stat_option/0]).
  81%% imports
  82-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
  83
  84%% Record Signature
  85-define(RS(Record),
  86	{Record, record_info(size, Record)}).
  87%% Record Signature Check (guard)
  88-define(RSC(Record, RS),
  89	element(1, Record) =:= element(1, RS),
  90	tuple_size(Record) =:= element(2, RS)).
  91
  92%%% ---------------------------------
  93%%% Contract type definitions
  94
  95
  96-type hostent() :: #hostent{}.
  97-type hostname() :: atom() | string().
  98-type ip4_address() :: {0..255,0..255,0..255,0..255}.
  99-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535,
 100			0..65535,0..65535,0..65535,0..65535}.
 101-type ip_address() :: ip4_address() | ip6_address().
 102-type port_number() :: 0..65535.
 103-type local_address() :: {local, File :: binary() | string()}.
 104-type returned_non_ip_address() ::
 105	{local, binary()} |
 106	{unspec, <<>>} |
 107	{undefined, any()}.
 108-type posix() ::
 109        'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' |
 110        'econnaborted' | 'econnrefused' | 'econnreset' |
 111        'edestaddrreq' |
 112        'ehostdown' | 'ehostunreach' |
 113        'einprogress' | 'eisconn' |
 114        'emsgsize' |
 115        'enetdown' | 'enetunreach' |
 116        'enopkg' | 'enoprotoopt' | 'enotconn' | 'enotty' | 'enotsock' |
 117        'eproto' | 'eprotonosupport' | 'eprototype' |
 118        'esocktnosupport' |
 119        'etimedout' |
 120        'ewouldblock' |
 121        'exbadport' | 'exbadseq' | file:posix().
 122-type socket() :: port().
 123
 124-type socket_setopt() ::
 125        gen_sctp:option() | gen_tcp:option() | gen_udp:option().
 126
 127-type socket_getopt() ::
 128        gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name().
 129-type ether_address() :: [0..255].
 130
 131-type if_setopt() ::
 132      {'addr', ip_address()} |
 133      {'broadaddr', ip_address()} |
 134      {'dstaddr', ip_address()} |
 135      {'mtu', non_neg_integer()} |
 136      {'netmask', ip_address()} |
 137      {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
 138		 'pointtopoint' | 'no_pointtopoint' | 
 139		 'running' | 'multicast']} |
 140      {'hwaddr', ether_address()}.
 141
 142-type if_getopt() ::
 143      'addr' | 'broadaddr' | 'dstaddr' | 
 144      'mtu' | 'netmask' | 'flags' |'hwaddr'.
 145
 146-type if_getopt_result() ::
 147      {'addr', ip_address()} |
 148      {'broadaddr', ip_address()} |
 149      {'dstaddr', ip_address()} |
 150      {'mtu', non_neg_integer()} |
 151      {'netmask', ip_address()} |
 152      {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
 153		 'pointtopoint' | 'no_pointtopoint' |
 154		 'running' | 'multicast' | 'loopback']} |
 155      {'hwaddr', ether_address()}.
 156
 157-type getifaddrs_ifopts() ::
 158        [Ifopt :: {flags, Flags :: [up | broadcast | loopback |
 159                                    pointtopoint | running | multicast]} |
 160                  {addr, Addr :: ip_address()} |
 161                  {netmask, Netmask :: ip_address()} |
 162                  {broadaddr, Broadaddr :: ip_address()} |
 163                  {dstaddr, Dstaddr :: ip_address()} |
 164                  {hwaddr, Hwaddr :: [byte()]}].
 165
 166-type address_family() :: 'inet' | 'inet6' | 'local'.
 167-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
 168-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
 169-type socket_address() ::
 170	ip_address() | 'any' | 'loopback' | local_address().
 171-type stat_option() :: 
 172	'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
 173	'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
 174
 175-type ancillary_data() ::
 176        [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
 177
 178%%% ---------------------------------
 179
 180-spec get_rc() -> [{Par :: atom(), Val :: any()} |
 181                   {Par :: atom(), Val1 :: any(), Val2 :: any()}].
 182
 183get_rc() ->
 184    inet_db:get_rc().
 185
 186-spec close(Socket) -> 'ok' when
 187      Socket :: socket().
 188
 189close(Socket) ->
 190    prim_inet:close(Socket),
 191    receive
 192	{Closed, Socket} when Closed =:= tcp_closed; Closed =:= udp_closed ->
 193	    ok
 194    after 0 ->
 195	    ok
 196    end.
 197
 198
 199-spec peername(Socket :: socket()) ->
 200		      {ok,
 201		       {ip_address(), port_number()} |
 202		       returned_non_ip_address()} |
 203		      {error, posix()}.
 204
 205peername(Socket) -> 
 206    prim_inet:peername(Socket).
 207
 208-spec setpeername(
 209	Socket :: socket(),
 210	Address ::
 211	  {ip_address() | 'any' | 'loopback',
 212	   port_number()} |
 213	  socket_address()) ->
 214			 'ok' | {'error', any()}.
 215
 216setpeername(Socket, {IP,Port}) ->
 217    prim_inet:setpeername(Socket, {IP,Port});
 218setpeername(Socket, undefined) ->
 219    prim_inet:setpeername(Socket, undefined).
 220
 221-spec peernames(Socket :: socket()) ->
 222		       {ok,
 223			[{ip_address(), port_number()} |
 224			 returned_non_ip_address()]} |
 225		       {error, posix()}.
 226
 227peernames(Socket) ->
 228    prim_inet:peernames(Socket).
 229
 230-spec peernames(Socket, Assoc) ->
 231		       {ok, [{Address, Port}]} | {error, posix()} when
 232      Socket :: socket(),
 233      Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(),
 234      Address :: ip_address(),
 235      Port :: non_neg_integer().
 236
 237peernames(Socket, Assoc) ->
 238    prim_inet:peernames(Socket, Assoc).
 239
 240
 241-spec sockname(Socket :: socket()) ->
 242		      {ok,
 243		       {ip_address(), port_number()} |
 244		       returned_non_ip_address()} |
 245		      {error, posix()}.
 246
 247sockname(Socket) -> 
 248    prim_inet:sockname(Socket).
 249
 250-spec setsockname(
 251	Socket :: socket(),
 252	Address ::
 253	  {ip_address() | 'any' | 'loopback',
 254	   port_number()} |
 255	  socket_address()) ->
 256	'ok' | {'error', any()}.
 257
 258setsockname(Socket, {IP,Port}) -> 
 259    prim_inet:setsockname(Socket, {IP,Port});
 260setsockname(Socket, undefined) ->
 261    prim_inet:setsockname(Socket, undefined).
 262
 263-spec socknames(Socket :: socket()) ->
 264		       {ok,
 265			[{ip_address(), port_number()} |
 266			 returned_non_ip_address()]} |
 267		       {error, posix()}.
 268
 269socknames(Socket) ->
 270    prim_inet:socknames(Socket).
 271
 272-spec socknames(Socket, Assoc) ->
 273		       {ok, [{Address, Port}]} | {error, posix()} when
 274      Socket :: socket(),
 275      Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(),
 276      Address :: ip_address(),
 277      Port :: non_neg_integer().
 278
 279socknames(Socket, Assoc) ->
 280    prim_inet:socknames(Socket, Assoc).
 281
 282
 283-spec port(Socket) -> {'ok', Port} | {'error', any()} when
 284      Socket :: socket(),
 285      Port :: port_number().
 286
 287port(Socket) ->
 288    case prim_inet:sockname(Socket) of
 289	{ok, {_,Port}} -> {ok, Port};
 290	Error -> Error
 291    end.
 292
 293-spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()?
 294	'ok' | {'error', posix()}.
 295
 296send(Socket, Packet) -> 
 297    prim_inet:send(Socket, Packet).
 298    
 299-spec setopts(Socket, Options) -> ok | {error, posix()} when
 300      Socket :: socket(),
 301      Options :: [socket_setopt()].
 302
 303setopts(Socket, Opts) -> 
 304    SocketOpts =
 305	[case Opt of
 306	     {netns,NS} ->
 307		 {netns,filename2binary(NS)};
 308	     _ ->
 309		 Opt
 310	 end || Opt <- Opts],
 311    prim_inet:setopts(Socket, SocketOpts).
 312
 313-spec getopts(Socket, Options) ->
 314	{'ok', OptionValues} | {'error', posix()} when
 315      Socket :: socket(),
 316      Options :: [socket_getopt()],
 317      OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
 318
 319getopts(Socket, Opts) ->
 320    case prim_inet:getopts(Socket, Opts) of
 321	{ok,OptionValues} ->
 322	    {ok,
 323	     [case OptionValue of
 324		  {netns,Bin} ->
 325		      {netns,binary2filename(Bin)};
 326		  _ ->
 327		      OptionValue
 328	      end || OptionValue <- OptionValues]};
 329	Other ->
 330	    Other
 331    end.
 332
 333-spec getifaddrs(
 334        [Option :: {netns, Namespace :: file:filename_all()}]
 335        | socket()) ->
 336                        {'ok', [{Ifname :: string(),
 337                                 Ifopts :: getifaddrs_ifopts()}]}
 338                            | {'error', posix()}.
 339getifaddrs(Opts) when is_list(Opts) ->
 340    withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts);
 341getifaddrs(Socket) ->
 342    prim_inet:getifaddrs(Socket).
 343
 344-spec getifaddrs() ->
 345                        {'ok', [{Ifname :: string(),
 346                                 Ifopts :: getifaddrs_ifopts()}]}
 347                            | {'error', posix()}.
 348getifaddrs() ->
 349    withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
 350
 351
 352-spec getiflist(
 353        [Option :: {netns, Namespace :: file:filename_all()}]
 354        | socket()) ->
 355                       {'ok', [string()]} | {'error', posix()}.
 356
 357getiflist(Opts) when is_list(Opts) ->
 358    withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts);
 359getiflist(Socket) -> 
 360    prim_inet:getiflist(Socket).
 361
 362-spec getiflist() -> {'ok', [string()]} | {'error', posix()}.
 363
 364getiflist() -> 
 365    withsocket(fun(S) -> prim_inet:getiflist(S) end).
 366    
 367-spec ifget(Socket :: socket(),
 368            Name :: string() | atom(),
 369	    Opts :: [if_getopt()]) ->
 370	{'ok', [if_getopt_result()]} | {'error', posix()}.
 371
 372ifget(Socket, Name, Opts) -> 
 373    prim_inet:ifget(Socket, Name, Opts).
 374
 375-spec ifget(
 376        Name :: string() | atom(),
 377        Opts :: [if_getopt() |
 378                 {netns, Namespace :: file:filename_all()}]) ->
 379	{'ok', [if_getopt_result()]} | {'error', posix()}.
 380
 381ifget(Name, Opts) ->
 382    {NSOpts,IFOpts} =
 383        lists:partition(
 384          fun ({netns,_}) -> true;
 385              (_) -> false
 386          end, Opts),
 387    withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts).
 388
 389-spec ifset(Socket :: socket(),
 390            Name :: string() | atom(),
 391	    Opts :: [if_setopt()]) ->
 392	'ok' | {'error', posix()}.
 393
 394ifset(Socket, Name, Opts) -> 
 395    prim_inet:ifset(Socket, Name, Opts).
 396
 397-spec ifset(
 398        Name :: string() | atom(),
 399        Opts :: [if_setopt() |
 400                 {netns, Namespace :: file:filename_all()}]) ->
 401	'ok' | {'error', posix()}.
 402
 403ifset(Name, Opts) ->
 404    {NSOpts,IFOpts} =
 405        lists:partition(
 406          fun ({netns,_}) -> true;
 407              (_) -> false
 408          end, Opts),
 409    withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts).
 410
 411-spec getif() ->
 412	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 
 413	{'error', posix()}.
 414
 415getif() -> 
 416    withsocket(fun(S) -> getif(S) end).
 417
 418%% backwards compatible getif
 419-spec getif(
 420        [Option :: {netns, Namespace :: file:filename_all()}]
 421        | socket()) ->
 422	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 
 423	{'error', posix()}.
 424
 425getif(Opts) when is_list(Opts) ->
 426    withsocket(fun(S) -> getif(S) end, Opts);
 427getif(Socket) ->
 428    case prim_inet:getiflist(Socket) of
 429	{ok, IfList} ->
 430	    {ok, lists:foldl(
 431		   fun(Name,Acc) ->
 432			   case prim_inet:ifget(Socket,Name,
 433						[addr,broadaddr,netmask]) of
 434			       {ok,[{addr,A},{broadaddr,B},{netmask,M}]} ->
 435				   [{A,B,M}|Acc];
 436			       %% Some interfaces does not have a b-addr
 437			       {ok,[{addr,A},{netmask,M}]} ->
 438				   [{A,undefined,M}|Acc];
 439			       _ ->
 440				   Acc
 441			   end
 442		   end, [], IfList)};
 443	Error -> Error
 444    end.
 445
 446withsocket(Fun) ->
 447    withsocket(Fun, []).
 448%%
 449withsocket(Fun, Opts) ->
 450    case inet_udp:open(0, Opts) of
 451	{ok,Socket} ->
 452	    Res = Fun(Socket),
 453	    inet_udp:close(Socket),
 454	    Res;
 455	Error ->
 456	    Error
 457    end.
 458
 459pushf(_Socket, Fun, _State) when is_function(Fun) ->
 460    {error, einval}.
 461
 462popf(_Socket) ->
 463    {error, einval}.
 464
 465
 466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 467% the hostname is not cached any more because this
 468% could cause troubles on at least windows with plug-and-play
 469% and network-cards inserted and removed in conjunction with
 470% use of the DHCP-protocol
 471% should never fail
 472
 473-spec gethostname() -> {'ok', Hostname} when
 474      Hostname :: string().
 475
 476gethostname() ->
 477    case inet_udp:open(0,[]) of
 478	{ok,U} ->
 479	    {ok,Res} = gethostname(U),
 480	    inet_udp:close(U),
 481	    {Res2,_} = lists:splitwith(fun($.)->false;(_)->true end,Res),
 482	    {ok, Res2};
 483	_ ->
 484	    {ok, "nohost.nodomain"}
 485    end.
 486
 487-spec gethostname(Socket :: socket()) ->
 488	{'ok', string()} | {'error', posix()}.
 489
 490gethostname(Socket) ->
 491    prim_inet:gethostname(Socket).
 492
 493-spec getstat(Socket) ->
 494	{ok, OptionValues} | {error, posix()} when
 495      Socket :: socket(),
 496      OptionValues :: [{stat_option(), integer()}].
 497
 498getstat(Socket) ->
 499    prim_inet:getstat(Socket, stats()).
 500
 501-spec getstat(Socket, Options) ->
 502	{ok, OptionValues} | {error, posix()} when
 503      Socket :: socket(),
 504      Options :: [stat_option()],
 505      OptionValues :: [{stat_option(), integer()}].
 506
 507getstat(Socket,What) ->
 508    prim_inet:getstat(Socket, What).
 509
 510-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when
 511      Hostname :: hostname(),
 512      Hostent :: hostent().
 513
 514gethostbyname(Name) -> 
 515    case inet_db:res_option(inet6) of
 516	true ->
 517	    gethostbyname_tm(Name, inet6, false);
 518	false ->
 519	    gethostbyname_tm(Name, inet, false)
 520    end.
 521
 522-spec gethostbyname(Hostname, Family) ->
 523                           {ok, Hostent} | {error, posix()} when
 524      Hostname :: hostname(),
 525      Family :: address_family(),
 526      Hostent :: hostent().
 527
 528gethostbyname(Name,Family) -> 
 529    gethostbyname_tm(Name, Family, false).
 530
 531-spec gethostbyname(Name :: hostname(),
 532	            Family :: address_family(),
 533	            Timeout :: non_neg_integer() | 'infinity') ->
 534	{'ok', #hostent{}} | {'error', posix()}.
 535	
 536gethostbyname(Name,Family,Timeout) ->
 537    Timer = start_timer(Timeout),
 538    Res = gethostbyname_tm(Name,Family,Timer),
 539    _ = stop_timer(Timer),
 540    Res.
 541
 542gethostbyname_tm(Name,Family,Timer) ->
 543    Opts0 = inet_db:res_option(lookup),
 544    Opts =
 545	case (lists:member(native, Opts0) orelse
 546	      lists:member(string, Opts0) orelse
 547	      lists:member(nostring, Opts0)) of
 548	    true ->
 549		Opts0;
 550	    false ->
 551		[string|Opts0]
 552	end,
 553    gethostbyname_tm(Name, Family, Timer, Opts).
 554
 555
 556-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when
 557      Address :: string() | ip_address(),
 558      Hostent :: hostent().
 559
 560gethostbyaddr(Address) ->
 561    gethostbyaddr_tm(Address, false).
 562
 563-spec gethostbyaddr(Address :: string() | ip_address(), 
 564	            Timeout :: non_neg_integer() | 'infinity') ->
 565	{'ok', #hostent{}} | {'error', posix()}.
 566
 567gethostbyaddr(Address,Timeout) ->
 568    Timer = start_timer(Timeout),    
 569    Res = gethostbyaddr_tm(Address, Timer),
 570    _ = stop_timer(Timer),
 571    Res.
 572
 573gethostbyaddr_tm(Address,Timer) ->
 574    gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)).
 575
 576-spec ip(Ip :: ip_address() | string() | atom()) ->
 577	{'ok', ip_address()} | {'error', posix()}.
 578
 579ip({A,B,C,D}) when ?ip(A,B,C,D) ->
 580    {ok, {A,B,C,D}};
 581ip(Name) ->
 582    case gethostbyname(Name) of
 583	{ok, Ent} ->
 584	    {ok, hd(Ent#hostent.h_addr_list)};
 585	Error -> Error
 586    end.
 587
 588%% This function returns the erlang port used (with inet_drv)
 589
 590-spec getll(Socket :: socket()) -> {'ok', socket()}.
 591
 592getll(Socket) when is_port(Socket) ->
 593    {ok, Socket}.
 594
 595%%
 596%% Return the internal file descriptor number
 597%%
 598
 599-spec getfd(Socket :: socket()) ->
 600	{'ok', non_neg_integer()} | {'error', posix()}.
 601
 602getfd(Socket) ->
 603    prim_inet:getfd(Socket).
 604
 605%%
 606%% Lookup an ip address
 607%%
 608
 609-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
 610      Host :: ip_address() | hostname(),
 611      Family :: address_family(),
 612      Address :: ip_address().
 613
 614getaddr(Address, Family) ->
 615    getaddr(Address, Family, infinity).
 616
 617-spec getaddr(Host :: ip_address() | hostname(),
 618	      Family :: address_family(),
 619	      Timeout :: non_neg_integer() | 'infinity') ->
 620	{'ok', ip_address()} | {'error', posix()}.
 621
 622getaddr(Address, Family, Timeout) ->
 623    Timer = start_timer(Timeout),
 624    Res = getaddr_tm(Address, Family, Timer),
 625    _ = stop_timer(Timer),
 626    Res.
 627
 628getaddr_tm(Address, Family, Timer) ->
 629    case getaddrs_tm(Address, Family, Timer) of
 630	{ok, [IP|_]} -> {ok, IP};
 631	Error -> Error
 632    end.
 633
 634-spec getaddrs(Host, Family) ->
 635	{ok, Addresses} | {error, posix()} when
 636      Host :: ip_address() | hostname(),
 637      Family :: address_family(),
 638      Addresses :: [ip_address()].
 639
 640getaddrs(Address, Family) -> 
 641    getaddrs(Address, Family, infinity).
 642
 643-spec getaddrs(Host :: ip_address() | string() | atom(),
 644	       Family :: address_family(),
 645	       Timeout :: non_neg_integer() | 'infinity') ->
 646	{'ok', [ip_address()]} | {'error', posix()}.
 647
 648getaddrs(Address, Family, Timeout) ->
 649    Timer = start_timer(Timeout),
 650    Res = getaddrs_tm(Address, Family, Timer),
 651    _ = stop_timer(Timer),
 652    Res.
 653
 654-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
 655	{'ok', string()} | {'error', posix()}.
 656
 657getservbyport(Port, Proto) ->
 658    case inet_udp:open(0, []) of
 659	{ok,U} ->
 660	    Res = prim_inet:getservbyport(U, Port, Proto),
 661	    inet_udp:close(U),
 662	    Res;
 663	Error -> Error
 664    end.
 665
 666-spec getservbyname(Name :: atom() | string(),
 667	            Protocol :: atom() | string()) ->
 668	{'ok', port_number()} | {'error', posix()}.
 669
 670getservbyname(Name, Protocol) when is_atom(Name) ->
 671    case inet_udp:open(0, []) of
 672	{ok,U} ->
 673	    Res = prim_inet:getservbyname(U, Name, Protocol),
 674	    inet_udp:close(U),
 675	    Res;
 676	Error -> Error
 677    end.
 678
 679-spec ntoa(IpAddress) -> Address | {error, einval} when
 680      Address :: string(),
 681      IpAddress :: ip_address().
 682ntoa(Addr) ->
 683    inet_parse:ntoa(Addr).
 684
 685-spec parse_ipv4_address(Address) ->
 686	{ok, IPv4Address} | {error, einval} when
 687      Address :: string(),
 688      IPv4Address :: ip_address().
 689parse_ipv4_address(Addr) ->
 690    inet_parse:ipv4_address(Addr).
 691
 692-spec parse_ipv6_address(Address) ->
 693	{ok, IPv6Address} | {error, einval} when
 694      Address :: string(),
 695      IPv6Address :: ip_address().
 696parse_ipv6_address(Addr) ->
 697    inet_parse:ipv6_address(Addr).
 698
 699-spec parse_ipv4strict_address(Address) ->
 700	{ok, IPv4Address} | {error, einval} when
 701      Address :: string(),
 702      IPv4Address :: ip_address().
 703parse_ipv4strict_address(Addr) ->
 704    inet_parse:ipv4strict_address(Addr).
 705
 706-spec parse_ipv6strict_address(Address) ->
 707	{ok, IPv6Address} | {error, einval} when
 708      Address :: string(),
 709      IPv6Address :: ip_address().
 710parse_ipv6strict_address(Addr) ->
 711    inet_parse:ipv6strict_address(Addr).
 712
 713-spec parse_address(Address) ->
 714	{ok, IPAddress} | {error, einval} when
 715      Address :: string(),
 716      IPAddress :: ip_address().
 717parse_address(Addr) ->
 718    inet_parse:address(Addr).
 719
 720-spec parse_strict_address(Address) ->
 721	{ok, IPAddress} | {error, einval} when
 722      Address :: string(),
 723      IPAddress :: ip_address().
 724parse_strict_address(Addr) ->
 725    inet_parse:strict_address(Addr).
 726
 727-spec ipv4_mapped_ipv6_address(ip_address()) -> ip_address().
 728ipv4_mapped_ipv6_address({D1,D2,D3,D4})
 729  when (D1 bor D2 bor D3 bor D4) < 256 ->
 730    {0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4};
 731ipv4_mapped_ipv6_address({D1,D2,D3,D4,D5,D6,D7,D8})
 732  when (D1 bor D2 bor D3 bor D4 bor D5 bor D6 bor D7 bor D8) < 65536 ->
 733    {D7 bsr 8,D7 band 255,D8 bsr 8,D8 band 255}.
 734
 735%% Return a list of available options
 736options() ->
 737    [
 738     tos, tclass, priority, reuseaddr, keepalive, dontroute, linger,
 739     broadcast, sndbuf, recbuf, nodelay, ipv6_v6only,
 740     buffer, header, active, packet, deliver, mode,
 741     multicast_if, multicast_ttl, multicast_loop,
 742     exit_on_close, high_watermark, low_watermark,
 743     high_msgq_watermark, low_msgq_watermark,
 744     send_timeout, send_timeout_close, show_econnreset
 745    ].
 746
 747%% Return a list of statistics options
 748
 749-spec stats() -> [stat_option(),...].
 750
 751stats() ->
 752    [recv_oct, recv_cnt, recv_max, recv_avg, recv_dvi,
 753     send_oct, send_cnt, send_max, send_avg, send_pend].
 754
 755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 756%% Available options for tcp:connect
 757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 758connect_options() ->
 759    [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
 760     recvtos, recvtclass, ttl, recvttl,
 761     header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
 762     exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
 763     low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
 764     show_econnreset, bind_to_device].
 765    
 766connect_options(Opts, Mod) ->
 767    BaseOpts = 
 768	case application:get_env(kernel, inet_default_connect_options) of
 769	    {ok,List} when is_list(List) ->
 770		NList = [{active, true} | lists:keydelete(active,1,List)],     
 771		#connect_opts{ opts = NList};
 772	    {ok,{active,_Bool}} -> 
 773		#connect_opts{ opts = [{active,true}]};
 774	    {ok,Option} -> 
 775		#connect_opts{ opts = [{active,true}, Option]};
 776	    _ ->
 777		#connect_opts{ opts = [{active,true}]}
 778	end,
 779    case con_opt(Opts, BaseOpts, connect_options()) of
 780	{ok, R} ->
 781	    {ok, R#connect_opts {
 782		   opts = lists:reverse(R#connect_opts.opts),
 783		   ifaddr = Mod:translate_ip(R#connect_opts.ifaddr)
 784		  }};
 785	Error -> Error	    
 786    end.
 787
 788con_opt([{raw,A,B,C}|Opts],#connect_opts{} = R,As) ->
 789    con_opt([{raw,{A,B,C}}|Opts],R,As);
 790con_opt([Opt | Opts], #connect_opts{} = R, As) ->
 791    case Opt of
 792	{ip,IP}     -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
 793	{ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
 794	{port,P}    -> con_opt(Opts, R#connect_opts { port = P }, As);
 795	{fd,Fd}     -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
 796	binary      -> con_add(mode, binary, R, Opts, As);
 797	list        -> con_add(mode, list, R, Opts, As);
 798	{netns,NS} ->
 799	    BinNS = filename2binary(NS),
 800	    case prim_inet:is_sockopt_val(netns, BinNS) of
 801		true ->
 802		    con_opt(Opts, R#connect_opts { fd = [{netns,BinNS}] }, As);
 803		false ->
 804		    {error, badarg}
 805	    end;
 806        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
 807            NOpts = lists:keydelete(active, 1, R#connect_opts.opts),
 808            con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As);
 809	{line_delimiter,C} when is_integer(C), C >= 0, C =< 255 ->
 810	    con_add(line_delimiter, C, R, Opts, As);
 811	{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
 812	_ -> {error, badarg}
 813    end;
 814con_opt([], #connect_opts{} = R, _) ->
 815    {ok, R}.
 816
 817con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
 818    case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of
 819	{ok, SOpts} ->
 820	    con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts);
 821	Error -> Error
 822    end.
 823
 824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 825%% Available options for tcp:listen
 826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 827listen_options() ->
 828    [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
 829     recvtos, recvtclass, ttl, recvttl,
 830     header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
 831     exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
 832     low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
 833     packet_size, raw, show_econnreset, bind_to_device].
 834
 835listen_options(Opts, Mod) ->
 836    BaseOpts = 
 837	case application:get_env(kernel, inet_default_listen_options) of
 838	    {ok,List} when is_list(List) ->
 839		NList = [{active, true} | lists:keydelete(active,1,List)],		       
 840		#listen_opts{ opts = NList};
 841	    {ok,{active,_Bool}} -> 
 842		#listen_opts{ opts = [{active,true}]};
 843	    {ok,Option} -> 
 844		#listen_opts{ opts = [{active,true}, Option]};
 845	    _ ->
 846		#listen_opts{ opts = [{active,true}]}
 847	end,
 848    case list_opt(Opts, BaseOpts, listen_options()) of
 849	{ok, R} ->
 850	    {ok, R#listen_opts {
 851		   opts = lists:reverse(R#listen_opts.opts),
 852		   ifaddr = Mod:translate_ip(R#listen_opts.ifaddr)
 853		  }};
 854	Error -> Error
 855    end.
 856	
 857list_opt([{raw,A,B,C}|Opts], #listen_opts{} = R, As) ->
 858    list_opt([{raw,{A,B,C}}|Opts], R, As);
 859list_opt([Opt | Opts], #listen_opts{} = R, As) ->
 860    case Opt of
 861	{ip,IP}      ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
 862	{ifaddr,IP}  ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
 863	{port,P}     ->  list_opt(Opts, R#listen_opts { port = P }, As);
 864	{fd,Fd}      ->  list_opt(Opts, R#listen_opts { fd = Fd }, As);
 865	{backlog,BL} ->  list_opt(Opts, R#listen_opts { backlog = BL }, As);
 866	binary       ->  list_add(mode, binary, R, Opts, As);
 867	list         ->  list_add(mode, list, R, Opts, As);
 868	{netns,NS} ->
 869	    BinNS = filename2binary(NS),
 870	    case prim_inet:is_sockopt_val(netns, BinNS) of
 871		true ->
 872		    list_opt(Opts, R#listen_opts { fd = [{netns,BinNS}] }, As);
 873		false ->
 874		    {error, badarg}
 875	    end;
 876        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
 877            NOpts = lists:keydelete(active, 1, R#listen_opts.opts),
 878            list_opt(Opts, R#listen_opts { opts = [{active,N}|NOpts] }, As);
 879	{Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
 880	_ -> {error, badarg}
 881    end;
 882list_opt([], #listen_opts{} = R, _SockOpts) ->
 883    {ok, R}.
 884
 885list_add(Name, Val, #listen_opts{} = R, Opts, As) ->
 886    case add_opt(Name, Val, R#listen_opts.opts, As) of
 887	{ok, SOpts} ->
 888	    list_opt(Opts, R#listen_opts { opts = SOpts }, As);
 889	Error -> Error
 890    end.
 891
 892tcp_module(Opts) ->
 893    tcp_module_1(Opts, undefined).
 894
 895tcp_module(Opts, Addr) ->
 896    Address = {undefined,Addr},
 897    %% Address has to be a 2-tuple but the first element is ignored
 898    tcp_module_1(Opts, Address).
 899
 900tcp_module_1(Opts, Address) ->
 901    mod(
 902      Opts, tcp_module, Address,
 903      #{inet => inet_tcp, inet6 => inet6_tcp, local => local_tcp}).
 904
 905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 906%% Available options for udp:open
 907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 908udp_options() ->
 909    [tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
 910     recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
 911     broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
 912     add_membership, drop_membership, read_packets,raw,
 913     high_msgq_watermark, low_msgq_watermark, bind_to_device].
 914
 915
 916udp_options(Opts, Mod) ->
 917    case udp_opt(Opts, #udp_opts { }, udp_options()) of
 918	{ok, R} ->
 919	    {ok, R#udp_opts {
 920		   opts = lists:reverse(R#udp_opts.opts),
 921		   ifaddr = Mod:translate_ip(R#udp_opts.ifaddr)
 922		  }};
 923	Error -> Error
 924    end.
 925
 926udp_opt([{raw,A,B,C}|Opts], #udp_opts{} = R, As) ->
 927    udp_opt([{raw,{A,B,C}}|Opts], R, As);
 928udp_opt([Opt | Opts], #udp_opts{} = R, As) ->
 929    case Opt of
 930	{ip,IP}     ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
 931	{ifaddr,IP} ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
 932	{port,P}    ->  udp_opt(Opts, R#udp_opts { port = P }, As);
 933	{fd,Fd}     ->  udp_opt(Opts, R#udp_opts { fd = Fd }, As);
 934	binary      ->  udp_add(mode, binary, R, Opts, As);
 935	list        ->  udp_add(mode, list, R, Opts, As);
 936	{netns,NS} ->
 937	    BinNS = filename2binary(NS),
 938	    case prim_inet:is_sockopt_val(netns, BinNS) of
 939		true ->
 940		    udp_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As);
 941		false ->
 942		    {error, badarg}
 943	    end;
 944        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
 945            NOpts = lists:keydelete(active, 1, R#udp_opts.opts),
 946            udp_opt(Opts, R#udp_opts { opts = [{active,N}|NOpts] }, As);
 947	{Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
 948	_ -> {error, badarg}
 949    end;
 950udp_opt([], #udp_opts{} = R, _SockOpts) ->
 951    {ok, R}.
 952
 953udp_add(Name, Val, #udp_opts{} = R, Opts, As) ->
 954    case add_opt(Name, Val, R#udp_opts.opts, As) of
 955	{ok, SOpts} ->
 956	    udp_opt(Opts, R#udp_opts { opts = SOpts }, As);
 957	Error -> Error
 958    end.
 959
 960udp_module(Opts) ->
 961    mod(
 962      Opts, udp_module, undefined,
 963      #{inet => inet_udp, inet6 => inet6_udp, local => local_udp}).
 964
 965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 966%% Available options for sctp:open
 967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 968%  Currently supported options include:
 969%  (*) {mode,   list|binary}	 or just list|binary
 970%  (*) {active, true|false|once|N}
 971%  (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6
 972%  (*) options set via setsockopt.
 973%      The full list is below in sctp_options/0 .
 974%  All other options are currently NOT supported. In particular:
 975%  (*) multicast on SCTP is not (yet) supported, as it may be incompatible
 976%      with automatic associations;
 977%  (*) passing of open FDs ("fdopen") is not supported.
 978sctp_options() ->
 979[   % The following are generic inet options supported for SCTP sockets:
 980    mode, active, buffer, tos, tclass, ttl,
 981    priority, dontroute, reuseaddr, linger,
 982    recvtos, recvtclass, recvttl,
 983    sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
 984    bind_to_device,
 985
 986    % Other options are SCTP-specific (though they may be similar to their
 987    % TCP and UDP counter-parts):
 988    sctp_rtoinfo,   		 sctp_associnfo,	sctp_initmsg,
 989    sctp_autoclose,		 sctp_nodelay,		sctp_disable_fragments,
 990    sctp_i_want_mapped_v4_addr,  sctp_maxseg,		sctp_primary_addr,
 991    sctp_set_peer_primary_addr,  sctp_adaptation_layer,	sctp_peer_addr_params,
 992    sctp_default_send_param,	 sctp_events,		sctp_delayed_ack_time,
 993    sctp_status,	   	 sctp_get_peer_addr_info
 994].
 995
 996sctp_options(Opts, Mod)  ->
 997    case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
 998	{ok,#sctp_opts{ifaddr=undefined}=SO} -> 
 999	    {ok,
1000	     SO#sctp_opts{
1001	       opts=lists:reverse(SO#sctp_opts.opts),
1002	       ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
1003	{ok,SO} ->
1004	    {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}};
1005	Error -> Error
1006    end.
1007
1008sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) ->
1009    case Opt of
1010	{ip,IP} ->
1011	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
1012	{ifaddr,IP} ->
1013	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
1014	{port,Port} ->
1015	    case Mod:getserv(Port) of
1016		{ok,P} ->
1017		    sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As);
1018		Error -> Error
1019	    end;
1020	{type,Type} when Type =:= seqpacket; Type =:= stream ->
1021	    sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As);
1022	binary		-> sctp_opt (Opts, Mod, R, As, mode, binary);
1023	list		-> sctp_opt (Opts, Mod, R, As, mode, list);
1024	{netns,NS} ->
1025	    BinNS = filename2binary(NS),
1026	    case prim_inet:is_sockopt_val(netns, BinNS) of
1027		true ->
1028		    sctp_opt(
1029		      Opts, Mod,
1030		      R#sctp_opts { fd = [{netns,BinNS}] },
1031		      As);
1032		false ->
1033		    {error, badarg}
1034	    end;
1035        {active,N} when is_integer(N), N < 32768, N >= -32768 ->
1036            NOpts = lists:keydelete(active, 1, R#sctp_opts.opts),
1037            sctp_opt(Opts, Mod, R#sctp_opts { opts = [{active,N}|NOpts] }, As);
1038	{Name,Val}	-> sctp_opt (Opts, Mod, R, As, Name, Val);
1039	_ -> {error,badarg}
1040    end;
1041sctp_opt([], _Mod, #sctp_opts{ifaddr=IfAddr}=R, _SockOpts) ->
1042    if is_list(IfAddr) ->
1043	    {ok, R#sctp_opts{ifaddr=lists:reverse(IfAddr)}};
1044       true ->
1045	    {ok, R}
1046    end.
1047
1048sctp_opt(Opts, Mod, #sctp_opts{} = R, As, Name, Val) ->
1049    case add_opt(Name, Val, R#sctp_opts.opts, As) of
1050	{ok,SocketOpts} ->
1051	    sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As);
1052	Error -> Error
1053    end.
1054
1055sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
1056    IP = Mod:translate_ip(Addr),
1057    sctp_opt(Opts, Mod, 
1058	     R#sctp_opts{
1059	       ifaddr=case IfAddr of
1060			  undefined              -> IP;
1061			  _ when is_list(IfAddr) -> [IP|IfAddr];
1062			  _                      -> [IP,IfAddr]
1063		      end}, As).
1064
1065sctp_module(Opts) ->
1066    mod(
1067      Opts, sctp_module, undefined,
1068      #{inet => inet_sctp, inet6 => inet6_sctp}).
1069
1070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071%% Util to check and insert option in option list
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073
1074add_opt(Name, Val, Opts, As) ->
1075    case lists:member(Name, As) of
1076	true ->
1077	    case prim_inet:is_sockopt_val(Name, Val) of
1078		true when Name =:= raw ->
1079		    {ok, [{Name,Val} | Opts]};
1080		true ->
1081		    Opts1 = lists:keydelete(Name, 1, Opts),
1082		    {ok, [{Name,Val} | Opts1]};
1083		false -> {error,badarg}
1084	    end;
1085	false -> {error,badarg}
1086    end.
1087	
1088
1089%% Passthrough all unknown - catch type errors later
1090filename2binary(List) when is_list(List) ->
1091    OutEncoding = file:native_name_encoding(),
1092    try unicode:characters_to_binary(List, unicode, OutEncoding) of
1093	Bin when is_binary(Bin) ->
1094	    Bin;
1095	_ ->
1096	    List
1097    catch
1098	error:badarg ->
1099	    List
1100    end;
1101filename2binary(Bin) ->
1102    Bin.
1103
1104binary2filename(Bin) ->
1105    InEncoding = file:native_name_encoding(),
1106    case unicode:characters_to_list(Bin, InEncoding) of
1107	Filename when is_list(Filename) ->
1108	    Filename;
1109	_ ->
1110	    %% For getopt/setopt of netns this should only happen if
1111	    %% a binary with wrong encoding was used when setting the
1112	    %% option, hence the user shall eat his/her own medicine.
1113	    %%
1114	    %% I.e passthrough here too for now.
1115	    %% Future usecases will most probably not want this,
1116	    %% rather Unicode error or warning
1117	    %% depending on emulator flag instead.
1118	    Bin
1119    end.
1120
1121translate_ip(any,      inet) -> {0,0,0,0};
1122translate_ip(loopback, inet) -> {127,0,0,1};
1123translate_ip(any,      inet6) -> {0,0,0,0,0,0,0,0};
1124translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
1125translate_ip(IP, _) -> IP.
1126
1127mod(Opts, Tag, Address, Map) ->
1128    mod(Opts, Tag, Address, Map, undefined, []).
1129%%
1130mod([{Tag, M}|Opts], Tag, Address, Map, Mod, Acc) ->
1131    mod(Opts, Tag, Address, Map, Mod, Acc, M);
1132mod([{T, _} = Opt|Opts], Tag, _Address, Map, Mod, Acc)
1133  when T =:= ip; T =:= ifaddr->
1134    mod(Opts, Tag, Opt, Map, Mod, [Opt|Acc]);
1135mod([Family|Opts], Tag, Address, Map, Mod, Acc) when is_atom(Family) ->
1136    case Map of
1137	#{Family := M} ->
1138	    mod(Opts, Tag, Address, Map, Mod, Acc, M);
1139	#{} ->
1140	    mod(Opts, Tag, Address, Map, Mod, [Family|Acc])
1141    end;
1142mod([Opt|Opts], Tag, Address, Map, Mod, Acc) ->
1143    mod(Opts, Tag, Address, Map, Mod, [Opt|Acc]);
1144mod([], Tag, Address, Map, undefined, Acc) ->
1145    {case Address of
1146	 {_, {local, _}} ->
1147	     case Map of
1148		 #{local := Mod} ->
1149		     Mod;
1150		 #{} ->
1151		     inet_db:Tag()
1152	     end;
1153	 {_, IP} when tuple_size(IP) =:= 8 ->
1154	     #{inet := IPv4Mod} = Map,
1155	     %% Get the mod, but IPv6 address overrides default IPv4
1156	     case inet_db:Tag() of
1157		 IPv4Mod ->
1158		     #{inet6 := IPv6Mod} = Map,
1159		     IPv6Mod;
1160		 Mod ->
1161		     Mod
1162	     end;
1163	 _ ->
1164	     inet_db:Tag()
1165     end, lists:reverse(Acc)};
1166mod([], _Tag, _Address, _Map, Mod, Acc) ->
1167    {Mod, lists:reverse(Acc)}.
1168%%
1169mod(Opts, Tag, Address, Map, undefined, Acc, M) ->
1170    mod(Opts, Tag, Address, Map, M, Acc);
1171mod(Opts, Tag, Address, Map, Mod, Acc, _M) ->
1172    mod(Opts, Tag, Address, Map, Mod, Acc).
1173
1174
1175getaddrs_tm({A,B,C,D} = IP, Fam, _)  ->
1176    %% Only "syntactic" validation and check of family.
1177    if 
1178	?ip(A,B,C,D) ->
1179	    if
1180		Fam =:= inet -> {ok,[IP]};
1181		true -> {error,eafnosupport}
1182	    end;
1183	true -> {error,einval}
1184    end;
1185getaddrs_tm({A,B,C,D,E,F,G,H} = IP, Fam, _) ->
1186    %% Only "syntactic" validation; we assume that the address was
1187    %% "semantically" validated when it was converted to a tuple.
1188    if 
1189	?ip6(A,B,C,D,E,F,G,H) ->
1190	    if
1191		Fam =:= inet6 -> {ok,[IP]};
1192		true -> {error,eafnosupport}
1193	    end;
1194	true -> {error,einval}
1195    end;
1196getaddrs_tm(Address, Family, Timer) when is_atom(Address) ->
1197    getaddrs_tm(atom_to_list(Address), Family, Timer);
1198getaddrs_tm(Address, Family, Timer) ->
1199    case inet_parse:visible_string(Address) of
1200	false ->
1201	    {error,einval};
1202	true ->
1203	    %% Address is a host name or a valid IP address,
1204	    %% either way check it with the resolver.
1205	    case gethostbyname_tm(Address, Family, Timer) of
1206		{ok,Ent} -> {ok,Ent#hostent.h_addr_list};
1207		Error -> Error
1208	    end
1209    end.
1210
1211%%
1212%% gethostbyname with option search
1213%%
1214gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
1215    Result = gethostbyname_string(Name, Type),
1216    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1217gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
1218    Result = inet_res:gethostbyname_tm(Name, Type, Timer),
1219    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1220gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
1221    Result = inet_hosts:gethostbyname(Name, Type),
1222    gethostbyname_tm(Name, Type, Timer, Opts, Result);
1223gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
1224    gethostbyname_tm_native(Name, Type, Timer, Opts);
1225gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
1226    gethostbyname_tm_native(Name, Type, Timer, Opts);
1227gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
1228    gethostbyname_tm_native(Name, Type, Timer, Opts);
1229gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
1230    gethostbyname_tm_native(Name, Type, Timer, Opts);
1231gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
1232    gethostbyname_tm_native(Name, Type, Timer, Opts);
1233gethostbyname_tm(Name, Type, Timer, [_|Opts]) ->
1234    gethostbyname_tm(Name, Type, Timer, Opts);
1235%% Make sure we always can look up our own hostname.
1236gethostbyname_tm(Name, Type, Timer, []) ->
1237    Result = gethostbyname_self(Name, Type),
1238    gethostbyname_tm(Name, Type, Timer, [], Result).
1239
1240gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
1241    case Result of
1242	{ok,_} ->
1243	    Result;
1244	{error,formerr} ->
1245	    {error,einval};
1246	{error,_} when Opts =:= [] ->
1247	    {error,nxdomain};
1248	{error,_} ->
1249	    gethostbyname_tm(Name, Type, Timer, tl(Opts))
1250    end.
1251
1252gethostbyname_tm_native(Name, Type, Timer, Opts) ->
1253    %% Fixme: add (global) timeout to gethost_native
1254    Result = inet_gethost_native:gethostbyname(Name, Type),
1255    gethostbyname_tm(Name, Type, Timer, Opts, Result).
1256
1257
1258
1259gethostbyname_self(Name, Type) when is_atom(Name) ->
1260    gethostbyname_self(atom_to_list(Name), Type);
1261gethostbyname_self(Name, Type)
1262  when is_list(Name), Type =:= inet;
1263       is_list(Name), Type =:= inet6 ->
1264    N = inet_db:tolower(Name),
1265    Self = inet_db:gethostname(),
1266    %%
1267    %% This is the final fallback that pretends /etc/hosts has got
1268    %% a line for the hostname on the loopback address.
1269    %% Lookups into /etc/hosts are case insensitive and return
1270    %% what is in the file. Therefore the letter case may differ between
1271    %% the returned hostent record and the hostname that was asked for.
1272    %%
1273    case inet_db:tolower(Self) of
1274	N ->
1275	    {ok,
1276	     make_hostent(
1277	       Self, [translate_ip(loopback, Type)], [], Type)};
1278	_ ->
1279	    case inet_db:res_option(domain) of
1280		"" ->
1281		    {error,nxdomain};
1282		Domain ->
1283		    FQDN = lists:append([Self,".",Domain]),
1284		    case inet_db:tolower(FQDN) of
1285			N ->
1286			    {ok,
1287			     make_hostent(
1288			       FQDN,
1289			       [translate_ip(loopback, Type)], [], Type)};
1290			_ ->
1291			    {error,nxdomain}
1292		    end
1293	    end
1294    end;
1295gethostbyname_self(_, _) ->
1296    {error,formerr}.
1297
1298gethostbyname_string(Name, Type) when is_atom(Name) ->
1299    gethostbyname_string(atom_to_list(Name), Type);
1300gethostbyname_string(Name, Type)
1301  when is_list(Name), Type =:= inet;
1302       is_list(Name), Type =:= inet6 ->
1303    case
1304	case Type of
1305	    inet ->
1306		inet_parse:ipv4_address(Name);
1307	    inet6 ->
1308		inet_parse:ipv6strict_address(Name)
1309	end of
1310	{ok,IP} ->
1311	    {ok,make_hostent(Name, [IP], [], Type)};
1312	{error,einval} ->
1313	    {error,nxdomain}
1314    end;
1315gethostbyname_string(_, _) ->
1316    {error,formerr}.
1317
1318make_hostent(Name, Addrs, Aliases, Type) ->
1319    #hostent{h_name = Name,
1320	     h_aliases = Aliases,
1321	     h_addrtype = Type,
1322	     h_length = case Type of inet -> 4; inet6 -> 16 end,
1323	     h_addr_list = Addrs}.
1324
1325%%
1326%% gethostbyaddr with option search
1327%%
1328gethostbyaddr_tm(Addr, Timer, [dns | Opts]) ->
1329    Res = inet_res:gethostbyaddr_tm(Addr,Timer),
1330    case Res of
1331	{ok,_} -> Res;
1332	{error,timeout} -> Res;
1333	{error,formerr} -> {error, einval};
1334	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts)
1335    end;    
1336gethostbyaddr_tm(Addr, Timer, [file | Opts]) ->
1337    case inet_hosts:gethostbyaddr(Addr) of
1338	{error,formerr} -> {error, einval};
1339	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
1340	Result -> Result
1341    end;
1342gethostbyaddr_tm(Addr, Timer, [yp | Opts]) ->
1343    gethostbyaddr_tm_native(Addr, Timer, Opts);
1344gethostbyaddr_tm(Addr, Timer, [nis | Opts]) ->
1345    gethostbyaddr_tm_native(Addr, Timer, Opts);
1346gethostbyaddr_tm(Addr, Timer,  [nisplus | Opts]) ->
1347    gethostbyaddr_tm_native(Addr, Timer, Opts);
1348gethostbyaddr_tm(Addr, Timer, [wins | Opts]) ->
1349    gethostbyaddr_tm_native(Addr, Timer, Opts);
1350gethostbyaddr_tm(Addr, Timer, [native | Opts]) ->
1351    gethostbyaddr_tm_native(Addr, Timer, Opts);
1352gethostbyaddr_tm(Addr, Timer, [_ | Opts]) ->
1353    gethostbyaddr_tm(Addr, Timer, Opts);
1354gethostbyaddr_tm({127,0,0,1}=IP, _Timer, []) ->
1355    gethostbyaddr_self(IP, inet);
1356gethostbyaddr_tm({0,0,0,0,0,0,0,1}=IP, _Timer, []) ->
1357    gethostbyaddr_self(IP, inet6);
1358gethostbyaddr_tm(_Addr, _Timer, []) ->
1359    {error, nxdomain}.
1360
1361gethostbyaddr_self(IP, Type) ->
1362    Name = inet_db:gethostname(),
1363    case inet_db:res_option(domain) of
1364	"" ->
1365	    {ok,make_hostent(Name, [IP], [], Type)};
1366	Domain ->
1367	    {ok,make_hostent(Name++"."++Domain, [IP], [Name], Type)}
1368    end.
1369	    
1370gethostbyaddr_tm_native(Addr, Timer, Opts) ->
1371    %% Fixme: user timer for timeoutvalue
1372    case inet_gethost_native:gethostbyaddr(Addr) of
1373	{error,formerr} -> {error, einval};
1374	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
1375	Result -> Result
1376    end.
1377
1378-spec open(Fd_or_OpenOpts :: integer() | list(),
1379	   Addr ::
1380	     socket_address() |
1381	     {ip_address() | 'any' | 'loopback', % Unofficial
1382	      port_number()} |
1383	     {inet, % Unofficial
1384	      {ip4_address() | 'any' | 'loopback',
1385	       port_number()}} |
1386	     {inet6, % Unofficial
1387	      {ip6_address() | 'any' | 'loopback',
1388	       port_number()}} |
1389	     undefined, % Internal - no bind()
1390	   Port :: port_number(),
1391	   Opts :: [socket_setopt()],
1392	   Protocol :: socket_protocol(),
1393	   Family :: address_family(),
1394	   Type :: socket_type(),
1395	   Module :: atom()) ->
1396	{'ok', socket()} | {'error', posix()}.
1397
1398open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module)
1399  when is_integer(FdO), FdO < 0;
1400       is_list(FdO) ->
1401    OpenOpts =
1402	if  is_list(FdO) -> FdO;
1403	    true -> []
1404	end,
1405    case prim_inet:open(Protocol, Family, Type, OpenOpts) of
1406	{ok,S} ->
1407	    case prim_inet:setopts(S, Opts) of
1408		ok when Addr =:= undefined ->
1409		    inet_db:register_socket(S, Module),
1410		    {ok,S};
1411		ok ->
1412		    case bind(S, Addr, Port) of
1413			{ok, _} ->
1414			    inet_db:register_socket(S, Module),
1415			    {ok,S};
1416			Error  ->
1417			    prim_inet:close(S),
1418			    Error
1419		    end;
1420		Error  ->
1421		    prim_inet:close(S),
1422		    Error
1423	    end;
1424	Error ->
1425	    Error
1426    end;
1427open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module)
1428  when is_integer(Fd) ->
1429    fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module).
1430
1431bind(S, Addr, Port) when is_list(Addr) ->
1432    bindx(S, Addr, Port);
1433bind(S, Addr, Port) ->
1434    prim_inet:bind(S, Addr, Port).
1435
1436bindx(S, [Addr], Port0) ->
1437    {IP, Port} = set_bindx_port(Addr, Port0),
1438    prim_inet:bind(S, IP, Port);
1439bindx(S, Addrs, Port0) ->
1440    [{IP, Port} | Rest] = [set_bindx_port(Addr, Port0) || Addr <- Addrs],
1441    case prim_inet:bind(S, IP, Port) of
1442	{ok, AssignedPort} when Port =:= 0 ->
1443	    %% On newer Linux kernels, Solaris and FreeBSD, calling
1444	    %% bindx with port 0 is ok, but on SuSE 10, it results in einval
1445	    Rest2 = [change_bindx_0_port(Addr, AssignedPort) || Addr <- Rest],
1446	    prim_inet:bind(S, add, Rest2);
1447	{ok, _} ->
1448	    prim_inet:bind(S, add, Rest);
1449	Error ->
1450	    Error
1451    end.
1452
1453set_bindx_port({_IP, _Port}=Addr, _OtherPort) ->
1454    Addr;
1455set_bindx_port(IP, Port) ->
1456    {IP, Port}.
1457
1458change_bindx_0_port({IP, 0}, AssignedPort) ->
1459    {IP, AssignedPort};
1460change_bindx_0_port({_IP, _Port}=Addr, _AssignedPort) ->
1461    Addr.
1462
1463
1464-spec fdopen(Fd :: non_neg_integer(),
1465	     Opts :: [socket_setopt()],
1466	     Protocol :: socket_protocol(),
1467	     Family :: address_family(),
1468	     Type :: socket_type(),
1469	     Module :: atom()) ->
1470	{'ok', socket()} | {'error', posix()}.
1471
1472fdopen(Fd, Opts, Protocol, Family, Type, Module) ->
1473    fdopen(Fd, any, 0, Opts, Protocol, Family, Type, Module).
1474
1475fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) ->
1476    Bound =
1477	%% We do not do any binding if default port+addr options
1478	%% were given, in order to keep backwards compatability
1479	%% with pre Erlang/OTP 17
1480	case Addr of
1481	    {0,0,0,0} when Port =:= 0 -> true;
1482	    {0,0,0,0,0,0,0,0} when Port =:= 0 -> true;
1483	    any when Port =:= 0 -> true;
1484	    _ -> false
1485	end,
1486    case prim_inet:fdopen(Protocol, Family, Type, Fd, Bound) of
1487	{ok, S} ->
1488	    case prim_inet:setopts(S, Opts) of
1489		ok
1490		  when Addr =:= undefined;
1491		       Bound ->
1492		    inet_db:register_socket(S, Module),
1493		    {ok, S};
1494		ok ->
1495		    case bind(S, Addr, Port) of
1496			{ok, _} ->
1497			    inet_db:register_socket(S, Module),
1498			    {ok, S};
1499			Error  ->
1500			    prim_inet:close(S),
1501			    Error
1502                    end;
1503		Error ->
1504		    prim_inet:close(S),
1505		    Error
1506	    end;
1507	Error -> Error
1508    end.
1509
1510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1511%%  socket stat
1512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513
1514-spec i() -> ok.
1515i() -> i(tcp), i(udp), i(sctp).
1516
1517-spec i(socket_protocol()) -> ok.
1518i(Proto) -> i(Proto, [port, module, recv, sent, owner,
1519		      local_address, foreign_address, state, type]).
1520
1521-spec i(socket_protocol(), [atom()]) -> ok.
1522i(tcp, Fs) ->
1523    ii(tcp_sockets(), Fs, tcp);
1524i(udp, Fs) ->
1525    ii(udp_sockets(), Fs, udp);
1526i(sctp, Fs) ->
1527    ii(sctp_sockets(), Fs, sctp).
1528
1529ii(Ss, Fs, Proto) ->
1530    LLs =
1531	case info_lines(Ss, Fs, Proto) of
1532	    [] -> [];
1533	    InfoLines -> [h_line(Fs) | InfoLines]
1534	end,
1535    Maxs = foldl(
1536	     fun(Line,Max0) -> smax(Max0,Line) end, 
1537	     duplicate(length(Fs),0),LLs),
1538    Fmt = append(["~-" ++ integer_to_list(N) ++ "s " || N <- Maxs]) ++ "\n",
1539    lists:foreach(fun(Line) -> io:format(Fmt, Line) end, LLs).
1540
1541smax([Max|Ms], [Str|Strs]) ->
1542    N = length(Str),
1543    [if N > Max -> N; true -> Max end | smax(Ms, Strs)];
1544smax([], []) -> [].
1545
1546info_lines(Ss, Fs, Proto) -> [i_line(S, Fs,Proto) || S <- Ss].
1547i_line(S, Fs, Proto)      -> [info(S, F, Proto) || F <- Fs].
1548
1549h_line(Fs) -> [h_field(atom_to_list(F)) || F <- Fs].
1550
1551h_field([C|Cs]) -> [upper(C) | hh_field(Cs)].
1552
1553hh_field([$_,C|Cs]) -> [$\s,upper(C) | hh_field(Cs)];
1554hh_field([C|Cs]) -> [C|hh_field(Cs)];
1555hh_field([]) -> [].
1556
1557upper(C) when C >= $a, C =< $z -> (C-$a) + $A;
1558upper(C) -> C.
1559
1560    
1561info(S, F, Proto) ->
1562    case F of
1563	owner ->
1564	    case erlang:port_info(S, connected) of
1565		{connected, Owner} -> pid_to_list(Owner);
1566		_ -> " "
1567	    end;
1568	port ->
1569	    case erlang:port_info(S,id) of
1570		{id, Id}  -> integer_to_list(Id);
1571		undefined -> " "
1572	    end;
1573	sent ->
1574	    case prim_inet:getstat(S, [send_oct]) of
1575		{ok,[{send_oct,N}]} -> integer_to_list(N);
1576		_ -> " "
1577	    end;
1578	recv ->
1579	    case  prim_inet:getstat(S, [recv_oct]) of
1580		{ok,[{recv_oct,N}]} -> integer_to_list(N);
1581		_ -> " "
1582	    end;
1583	local_address ->
1584	    fmt_addr(prim_inet:sockname(S), Proto);
1585	foreign_address ->
1586	    fmt_addr(prim_inet:peername(S), Proto);
1587	state ->
1588	    case prim_inet:getstatus(S) of
1589		{ok,Status} -> fmt_status(Status);
1590		_ -> " "
1591	    end;
1592	packet ->
1593	    case prim_inet:getopt(S, packet) of
1594		{ok,Type} when is_atom(Type) -> atom_to_list(Type);
1595		{ok,Type} when is_integer(Type) -> integer_to_list(Type);
1596		_ -> " "
1597	    end;
1598	type ->
1599	    case prim_inet:gettype(S) of
1600		{ok,{_,stream}} -> "STREAM";
1601		{ok,{_,dgram}}  -> "DGRAM";
1602		{ok,{_,seqpacket}} -> "SEQPACKET";
1603		_ -> " "
1604	    end;
1605	fd ->
1606	    case prim_inet:getfd(S) of
1607		{ok, Fd} -> integer_to_list(Fd);
1608		_ -> " "
1609	    end;
1610	module ->
1611	    case inet_db:lookup_socket(S) of
1612		{ok,Mod} -> atom_to_list(Mod);
1613		_ -> "prim_inet"
1614	    end
1615    end.
1616%% Possible flags: (sorted)
1617%% [accepting,bound,busy,connected,connecting,listen,listening,open]
1618%%
1619fmt_status(Flags) ->
1620    case lists:sort(Flags) of
1621	[accepting | _]               -> "ACCEPTING";
1622	[bound,busy,connected|_]      -> "CONNECTED*";
1623	[bound,connected|_]           -> "CONNECTED";
1624	[bound,listen,listening | _]  -> "LISTENING";
1625	[bound,listen | _]            -> "LISTEN";
1626	[bound,connecting | _]        -> "CONNECTING";
1627	[bound,open]                  -> "BOUND";
1628	[open]                        -> "IDLE";
1629	[]                            -> "CLOSED";
1630	_                             -> "????"
1631    end.
1632
1633fmt_addr({error,enotconn}, _) -> "*:*";
1634fmt_addr({err

Large files files are truncated, but you can click here to view the full file