PageRenderTime 174ms CodeModel.GetById 2ms app.highlight 158ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/kernel/src/inet.erl

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

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