PageRenderTime 112ms CodeModel.GetById 2ms app.highlight 99ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/kernel/src/inet.erl

https://github.com/alricb/Erlang-OTP
Erlang | 1342 lines | 1049 code | 187 blank | 106 comment | 9 complexity | 446dc994267cd4487d3f2be2a48b0ab3 MD5 | raw file
   1%%
   2%% %CopyrightBegin%
   3%%
   4%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
   5%%
   6%% The contents of this file are subject to the Erlang Public License,
   7%% Version 1.1, (the "License"); you may not use this file except in
   8%% compliance with the License. You should have received a copy of the
   9%% Erlang Public License along with this software. If not, it can be
  10%% retrieved online at http://www.erlang.org/.
  11%%
  12%% Software distributed under the License is distributed on an "AS IS"
  13%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14%% the License for the specific language governing rights and limitations
  15%% under the License.
  16%%
  17%% %CopyrightEnd%
  18%%
  19-module(inet).
  20
  21-include("inet.hrl").
  22-include("inet_int.hrl").
  23-include("inet_sctp.hrl").
  24
  25%% socket
  26-export([peername/1, sockname/1, port/1, send/2,
  27	 setopts/2, getopts/2, 
  28	 getifaddrs/0, getifaddrs/1,
  29	 getif/1, getif/0, getiflist/0, getiflist/1,
  30	 ifget/3, ifget/2, ifset/3, ifset/2,
  31	 getstat/1, getstat/2,
  32	 ip/1, stats/0, options/0, 
  33	 pushf/3, popf/1, close/1, gethostname/0, gethostname/1]).
  34
  35-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
  36
  37-export([i/0, i/1, i/2]).
  38
  39-export([getll/1, getfd/1, open/7, fdopen/5]).
  40
  41-export([tcp_controlling_process/2, udp_controlling_process/2,
  42	 tcp_close/1, udp_close/1]).
  43%% used by socks5
  44-export([setsockname/2, setpeername/2]).
  45
  46%% resolve
  47-export([gethostbyname/1, gethostbyname/2, gethostbyname/3, 
  48	 gethostbyname_tm/3]).
  49-export([gethostbyname_string/2, gethostbyname_self/2]).
  50-export([gethostbyaddr/1, gethostbyaddr/2, 
  51	 gethostbyaddr_tm/2]).
  52
  53-export([getservbyname/2, getservbyport/2]).
  54-export([getaddrs/2, getaddrs/3, getaddrs_tm/3,
  55	 getaddr/2, getaddr/3, getaddr_tm/3]).
  56-export([translate_ip/2]).
  57
  58-export([get_rc/0]).
  59
  60%% format error
  61-export([format_error/1]).
  62
  63%% timer interface
  64-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
  65
  66-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
  67              ip6_address/0, ip_address/0, posix/0, socket/0,
  68              port_number/0]).
  69
  70%% imports
  71-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
  72
  73%% Record Signature
  74-define(RS(Record),
  75	{Record, record_info(size, Record)}).
  76%% Record Signature Check (guard)
  77-define(RSC(Record, RS),
  78	element(1, Record) =:= element(1, RS),
  79	tuple_size(Record) =:= element(2, RS)).
  80
  81%%% ---------------------------------
  82%%% Contract type definitions
  83
  84
  85-type hostent() :: #hostent{}.
  86-type hostname() :: atom() | string().
  87-type ip4_address() :: {0..255,0..255,0..255,0..255}.
  88-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535,
  89			0..65535,0..65535,0..65535,0..65535}.
  90-type ip_address() :: ip4_address() | ip6_address().
  91-type port_number() :: 0..65535.
  92-type posix() :: exbadport | exbadseq | file:posix().
  93-type socket() :: port().
  94
  95-type socket_setopt() ::
  96        gen_sctp:option() | gen_tcp:option() | gen_udp:option().
  97
  98-type socket_getopt() ::
  99        gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name().
 100-type ether_address() :: [0..255].
 101
 102-type if_setopt() ::
 103      {'addr', ip_address()} |
 104      {'broadaddr', ip_address()} |
 105      {'dstaddr', ip_address()} |
 106      {'mtu', non_neg_integer()} |
 107      {'netmask', ip_address()} |
 108      {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
 109		 'pointtopoint' | 'no_pointtopoint' | 
 110		 'running' | 'multicast']} |
 111      {'hwaddr', ether_address()}.
 112
 113-type if_getopt() ::
 114      'addr' | 'broadaddr' | 'dstaddr' | 
 115      'mtu' | 'netmask' | 'flags' |'hwaddr'.
 116
 117-type address_family() :: 'inet' | 'inet6'.
 118-type protocol_option() :: 'tcp' | 'udp' | 'sctp'.
 119-type stat_option() :: 
 120	'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
 121	'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
 122
 123%%% ---------------------------------
 124
 125-spec get_rc() -> [{Par :: any(), Val :: any()}].
 126
 127get_rc() ->
 128    inet_db:get_rc().
 129
 130-spec close(Socket) -> 'ok' when
 131      Socket :: socket().
 132
 133close(Socket) ->
 134    prim_inet:close(Socket),
 135    receive
 136	{Closed, Socket} when Closed =:= tcp_closed; Closed =:= udp_closed ->
 137	    ok
 138    after 0 ->
 139	    ok
 140    end.
 141
 142-spec peername(Socket) ->  {ok, {Address, Port}} | {error, posix()} when
 143      Socket :: socket(),
 144      Address :: ip_address(),
 145      Port :: non_neg_integer().
 146
 147peername(Socket) -> 
 148    prim_inet:peername(Socket).
 149
 150-spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
 151	'ok' | {'error', any()}.
 152
 153setpeername(Socket, {IP,Port}) ->
 154    prim_inet:setpeername(Socket, {IP,Port});
 155setpeername(Socket, undefined) ->
 156    prim_inet:setpeername(Socket, undefined).
 157
 158
 159-spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when
 160      Socket :: socket(),
 161      Address :: ip_address(),
 162      Port :: non_neg_integer().
 163
 164sockname(Socket) -> 
 165    prim_inet:sockname(Socket).
 166
 167-spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
 168	'ok' | {'error', any()}.
 169
 170setsockname(Socket, {IP,Port}) -> 
 171    prim_inet:setsockname(Socket, {IP,Port});
 172setsockname(Socket, undefined) ->
 173    prim_inet:setsockname(Socket, undefined).
 174
 175-spec port(Socket) -> {'ok', Port} | {'error', any()} when
 176      Socket :: socket(),
 177      Port :: port_number().
 178
 179port(Socket) ->
 180    case prim_inet:sockname(Socket) of
 181	{ok, {_,Port}} -> {ok, Port};
 182	Error -> Error
 183    end.
 184
 185-spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()?
 186	'ok' | {'error', posix()}.
 187
 188send(Socket, Packet) -> 
 189    prim_inet:send(Socket, Packet).
 190    
 191-spec setopts(Socket, Options) -> ok | {error, posix()} when
 192      Socket :: socket(),
 193      Options :: [socket_setopt()].
 194
 195setopts(Socket, Opts) -> 
 196    prim_inet:setopts(Socket, Opts).
 197
 198-spec getopts(Socket, Options) ->
 199	{'ok', OptionValues} | {'error', posix()} when
 200      Socket :: socket(),
 201      Options :: [socket_getopt()],
 202      OptionValues :: [socket_setopt()].
 203
 204getopts(Socket, Opts) ->
 205    prim_inet:getopts(Socket, Opts).
 206
 207-spec getifaddrs(Socket :: socket()) ->
 208	{'ok', [string()]} | {'error', posix()}.
 209
 210getifaddrs(Socket) ->
 211    prim_inet:getifaddrs(Socket).
 212
 213-spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
 214      Iflist :: [{Ifname,[Ifopt]}],
 215      Ifname :: string(),
 216      Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
 217             | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
 218             | {hwaddr,Hwaddr},
 219      Flag :: up | broadcast | loopback | pointtopoint
 220            | running | multicast,
 221      Addr :: ip_address(),
 222      Netmask :: ip_address(),
 223      Broadaddr :: ip_address(),
 224      Dstaddr :: ip_address(),
 225      Hwaddr :: [byte()].
 226
 227getifaddrs() ->
 228    withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
 229
 230-spec getiflist(Socket :: socket()) ->
 231	{'ok', [string()]} | {'error', posix()}.
 232
 233getiflist(Socket) -> 
 234    prim_inet:getiflist(Socket).
 235
 236-spec getiflist() -> {'ok', [string()]} | {'error', posix()}.
 237
 238getiflist() -> 
 239    withsocket(fun(S) -> prim_inet:getiflist(S) end).
 240    
 241-spec ifget(Socket :: socket(),
 242            Name :: string() | atom(),
 243	    Opts :: [if_getopt()]) ->
 244	{'ok', [if_setopt()]} | {'error', posix()}.
 245
 246ifget(Socket, Name, Opts) -> 
 247    prim_inet:ifget(Socket, Name, Opts).
 248
 249-spec ifget(Name :: string() | atom(), Opts :: [if_getopt()]) ->
 250	{'ok', [if_setopt()]} | {'error', posix()}.
 251
 252ifget(Name, Opts) ->
 253    withsocket(fun(S) -> prim_inet:ifget(S, Name, Opts) end).
 254
 255-spec ifset(Socket :: socket(),
 256            Name :: string() | atom(),
 257	    Opts :: [if_setopt()]) ->
 258	'ok' | {'error', posix()}.
 259
 260ifset(Socket, Name, Opts) -> 
 261    prim_inet:ifset(Socket, Name, Opts).
 262
 263-spec ifset(Name :: string() | atom(), Opts :: [if_setopt()]) ->
 264	'ok' | {'error', posix()}.
 265
 266ifset(Name, Opts) ->
 267    withsocket(fun(S) -> prim_inet:ifset(S, Name, Opts) end).
 268
 269-spec getif() ->
 270	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 
 271	{'error', posix()}.
 272
 273getif() -> 
 274    withsocket(fun(S) -> getif(S) end).
 275
 276%% backwards compatible getif
 277-spec getif(Socket :: socket()) ->
 278	{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 
 279	{'error', posix()}.
 280
 281getif(Socket) ->
 282    case prim_inet:getiflist(Socket) of
 283	{ok, IfList} ->
 284	    {ok, lists:foldl(
 285		   fun(Name,Acc) ->
 286			   case prim_inet:ifget(Socket,Name,
 287						[addr,broadaddr,netmask]) of
 288			       {ok,[{addr,A},{broadaddr,B},{netmask,M}]} ->
 289				   [{A,B,M}|Acc];
 290			       %% Some interfaces does not have a b-addr
 291			       {ok,[{addr,A},{netmask,M}]} ->
 292				   [{A,undefined,M}|Acc];
 293			       _ ->
 294				   Acc
 295			   end
 296		   end, [], IfList)};
 297	Error -> Error
 298    end.
 299
 300withsocket(Fun) ->
 301    case inet_udp:open(0,[]) of
 302	{ok,Socket} ->
 303	    Res = Fun(Socket),
 304	    inet_udp:close(Socket),
 305	    Res;
 306	Error ->
 307	    Error
 308    end.
 309
 310pushf(_Socket, Fun, _State) when is_function(Fun) ->
 311    {error, einval}.
 312
 313popf(_Socket) ->
 314    {error, einval}.
 315
 316
 317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 318% the hostname is not cached any more because this
 319% could cause troubles on at least windows with plug-and-play
 320% and network-cards inserted and removed in conjunction with
 321% use of the DHCP-protocol
 322% should never fail
 323
 324-spec gethostname() -> {'ok', Hostname} when
 325      Hostname :: string().
 326
 327gethostname() ->
 328    case inet_udp:open(0,[]) of
 329	{ok,U} ->
 330	    {ok,Res} = gethostname(U),
 331	    inet_udp:close(U),
 332	    {Res2,_} = lists:splitwith(fun($.)->false;(_)->true end,Res),
 333	    {ok, Res2};
 334	_ ->
 335	    {ok, "nohost.nodomain"}
 336    end.
 337
 338-spec gethostname(Socket :: socket()) ->
 339	{'ok', string()} | {'error', posix()}.
 340
 341gethostname(Socket) ->
 342    prim_inet:gethostname(Socket).
 343
 344-spec getstat(Socket) ->
 345	{ok, OptionValues} | {error, posix()} when
 346      Socket :: socket(),
 347      OptionValues :: [{stat_option(), integer()}].
 348
 349getstat(Socket) ->
 350    prim_inet:getstat(Socket, stats()).
 351
 352-spec getstat(Socket, Options) ->
 353	{ok, OptionValues} | {error, posix()} when
 354      Socket :: socket(),
 355      Options :: [stat_option()],
 356      OptionValues :: [{stat_option(), integer()}].
 357
 358getstat(Socket,What) ->
 359    prim_inet:getstat(Socket, What).
 360
 361-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when
 362      Hostname :: hostname(),
 363      Hostent :: hostent().
 364
 365gethostbyname(Name) -> 
 366    gethostbyname_tm(Name, inet, false).
 367
 368-spec gethostbyname(Hostname, Family) ->
 369                           {ok, Hostent} | {error, posix()} when
 370      Hostname :: hostname(),
 371      Family :: address_family(),
 372      Hostent :: hostent().
 373
 374gethostbyname(Name,Family) -> 
 375    gethostbyname_tm(Name, Family, false).
 376
 377-spec gethostbyname(Name :: hostname(),
 378	            Family :: address_family(),
 379	            Timeout :: non_neg_integer() | 'infinity') ->
 380	{'ok', #hostent{}} | {'error', posix()}.
 381	
 382gethostbyname(Name,Family,Timeout) ->
 383    Timer = start_timer(Timeout),
 384    Res = gethostbyname_tm(Name,Family,Timer),
 385    stop_timer(Timer),
 386    Res.
 387
 388gethostbyname_tm(Name,Family,Timer) ->
 389    Opts0 = inet_db:res_option(lookup),
 390    Opts =
 391	case (lists:member(native, Opts0) orelse
 392	      lists:member(string, Opts0) orelse
 393	      lists:member(nostring, Opts0)) of
 394	    true ->
 395		Opts0;
 396	    false ->
 397		[string|Opts0]
 398	end,
 399    gethostbyname_tm(Name, Family, Timer, Opts).
 400
 401
 402-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when
 403      Address :: string() | ip_address(),
 404      Hostent :: hostent().
 405
 406gethostbyaddr(Address) ->
 407    gethostbyaddr_tm(Address, false).
 408
 409-spec gethostbyaddr(Address :: string() | ip_address(), 
 410	            Timeout :: non_neg_integer() | 'infinity') ->
 411	{'ok', #hostent{}} | {'error', posix()}.
 412
 413gethostbyaddr(Address,Timeout) ->
 414    Timer = start_timer(Timeout),    
 415    Res = gethostbyaddr_tm(Address, Timer),
 416    stop_timer(Timer),
 417    Res.
 418
 419gethostbyaddr_tm(Address,Timer) ->
 420    gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)).
 421
 422-spec ip(Ip :: ip_address() | string() | atom()) ->
 423	{'ok', ip_address()} | {'error', posix()}.
 424
 425ip({A,B,C,D}) when ?ip(A,B,C,D) ->
 426    {ok, {A,B,C,D}};
 427ip(Name) ->
 428    case gethostbyname(Name) of
 429	{ok, Ent} ->
 430	    {ok, hd(Ent#hostent.h_addr_list)};
 431	Error -> Error
 432    end.
 433
 434%% This function returns the erlang port used (with inet_drv)
 435
 436-spec getll(Socket :: socket()) -> {'ok', socket()}.
 437
 438getll(Socket) when is_port(Socket) ->
 439    {ok, Socket}.
 440
 441%%
 442%% Return the internal file descriptor number
 443%%
 444
 445-spec getfd(Socket :: socket()) ->
 446	{'ok', non_neg_integer()} | {'error', posix()}.
 447
 448getfd(Socket) ->
 449    prim_inet:getfd(Socket).
 450
 451%%
 452%% Lookup an ip address
 453%%
 454
 455-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
 456      Host :: ip_address() | hostname(),
 457      Family :: address_family(),
 458      Address :: ip_address().
 459
 460getaddr(Address, Family) ->
 461    getaddr(Address, Family, infinity).
 462
 463-spec getaddr(Host :: ip_address() | hostname(),
 464	      Family :: address_family(),
 465	      Timeout :: non_neg_integer() | 'infinity') ->
 466	{'ok', ip_address()} | {'error', posix()}.
 467
 468getaddr(Address, Family, Timeout) ->
 469    Timer = start_timer(Timeout),
 470    Res = getaddr_tm(Address, Family, Timer),
 471    stop_timer(Timer),
 472    Res.
 473
 474getaddr_tm(Address, Family, Timer) ->
 475    case getaddrs_tm(Address, Family, Timer) of
 476	{ok, [IP|_]} -> {ok, IP};
 477	Error -> Error
 478    end.
 479
 480-spec getaddrs(Host, Family) ->
 481	{ok, Addresses} | {error, posix()} when
 482      Host :: ip_address() | hostname(),
 483      Family :: address_family(),
 484      Addresses :: [ip_address()].
 485
 486getaddrs(Address, Family) -> 
 487    getaddrs(Address, Family, infinity).
 488
 489-spec getaddrs(Host :: ip_address() | string() | atom(),
 490	       Family :: address_family(),
 491	       Timeout :: non_neg_integer() | 'infinity') ->
 492	{'ok', [ip_address()]} | {'error', posix()}.
 493
 494getaddrs(Address, Family, Timeout) ->
 495    Timer = start_timer(Timeout),
 496    Res = getaddrs_tm(Address, Family, Timer),
 497    stop_timer(Timer),
 498    Res.
 499
 500-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
 501	{'ok', string()} | {'error', posix()}.
 502
 503getservbyport(Port, Proto) ->
 504    case inet_udp:open(0, []) of
 505	{ok,U} ->
 506	    Res = prim_inet:getservbyport(U, Port, Proto),
 507	    inet_udp:close(U),
 508	    Res;
 509	Error -> Error
 510    end.
 511
 512-spec getservbyname(Name :: atom() | string(),
 513	            Protocol :: atom() | string()) ->
 514	{'ok', port_number()} | {'error', posix()}.
 515
 516getservbyname(Name, Protocol) when is_atom(Name) ->
 517    case inet_udp:open(0, []) of
 518	{ok,U} ->
 519	    Res = prim_inet:getservbyname(U, Name, Protocol),
 520	    inet_udp:close(U),
 521	    Res;
 522	Error -> Error
 523    end.
 524
 525%% Return a list of available options
 526options() ->
 527    [
 528     tos, priority, reuseaddr, keepalive, dontroute, linger,
 529     broadcast, sndbuf, recbuf, nodelay,
 530     buffer, header, active, packet, deliver, mode,
 531     multicast_if, multicast_ttl, multicast_loop,
 532     exit_on_close, high_watermark, low_watermark,
 533     bit8, send_timeout, send_timeout_close
 534    ].
 535
 536%% Return a list of statistics options
 537
 538-spec stats() -> [stat_option(),...].
 539
 540stats() ->
 541    [recv_oct, recv_cnt, recv_max, recv_avg, recv_dvi,
 542     send_oct, send_cnt, send_max, send_avg, send_pend].
 543
 544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 545%% Available options for tcp:connect
 546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 547connect_options() ->
 548    [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
 549     header, active, packet, packet_size, buffer, mode, deliver,
 550     exit_on_close, high_watermark, low_watermark, bit8, send_timeout,
 551     send_timeout_close, delay_send,raw].
 552    
 553connect_options(Opts, Family) ->
 554    BaseOpts = 
 555	case application:get_env(kernel, inet_default_connect_options) of
 556	    {ok,List} when is_list(List) ->
 557		NList = [{active, true} | lists:keydelete(active,1,List)],     
 558		#connect_opts{ opts = NList};
 559	    {ok,{active,_Bool}} -> 
 560		#connect_opts{ opts = [{active,true}]};
 561	    {ok,Option} -> 
 562		#connect_opts{ opts = [{active,true}, Option]};
 563	    _ ->
 564		#connect_opts{ opts = [{active,true}]}
 565	end,
 566    case con_opt(Opts, BaseOpts, connect_options()) of
 567	{ok, R} ->
 568	    {ok, R#connect_opts {
 569		   ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
 570		  }};
 571	Error -> Error	    
 572    end.
 573
 574con_opt([{raw,A,B,C}|Opts],R,As) ->
 575    con_opt([{raw,{A,B,C}}|Opts],R,As);
 576con_opt([Opt | Opts], R, As) ->
 577    case Opt of
 578	{ip,IP}     -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
 579	{ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
 580	{port,P}    -> con_opt(Opts, R#connect_opts { port = P }, As);
 581	{fd,Fd}     -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
 582	binary      -> con_add(mode, binary, R, Opts, As);
 583	list        -> con_add(mode, list, R, Opts, As);
 584	{tcp_module,_}  -> con_opt(Opts, R, As);
 585	inet        -> con_opt(Opts, R, As);
 586	inet6       -> con_opt(Opts, R, As);
 587	{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
 588	_ -> {error, badarg}
 589    end;
 590con_opt([], R, _) ->
 591    {ok, R}.
 592
 593con_add(Name, Val, R, Opts, AllOpts) ->
 594    case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of
 595	{ok, SOpts} ->
 596	    con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts);
 597	Error -> Error
 598    end.
 599
 600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 601%% Available options for tcp:listen
 602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 603listen_options() ->
 604    [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
 605     header, active, packet, buffer, mode, deliver, backlog,
 606     exit_on_close, high_watermark, low_watermark, bit8, send_timeout,
 607     send_timeout_close, delay_send, packet_size,raw].
 608
 609listen_options(Opts, Family) ->
 610    BaseOpts = 
 611	case application:get_env(kernel, inet_default_listen_options) of
 612	    {ok,List} when is_list(List) ->
 613		NList = [{active, true} | lists:keydelete(active,1,List)],		       
 614		#listen_opts{ opts = NList};
 615	    {ok,{active,_Bool}} -> 
 616		#listen_opts{ opts = [{active,true}]};
 617	    {ok,Option} -> 
 618		#listen_opts{ opts = [{active,true}, Option]};
 619	    _ ->
 620		#listen_opts{ opts = [{active,true}]}
 621	end,
 622    case list_opt(Opts, BaseOpts, listen_options()) of
 623	{ok, R} ->
 624	    {ok, R#listen_opts {
 625		   ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
 626		  }};
 627	Error -> Error
 628    end.
 629	
 630list_opt([{raw,A,B,C}|Opts], R, As) ->
 631    list_opt([{raw,{A,B,C}}|Opts], R, As);
 632list_opt([Opt | Opts], R, As) ->
 633    case Opt of
 634	{ip,IP}      ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
 635	{ifaddr,IP}  ->  list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
 636	{port,P}     ->  list_opt(Opts, R#listen_opts { port = P }, As);
 637	{fd,Fd}      ->  list_opt(Opts, R#listen_opts { fd = Fd }, As);
 638	{backlog,BL} ->  list_opt(Opts, R#listen_opts { backlog = BL }, As);
 639	binary       ->  list_add(mode, binary, R, Opts, As);
 640	list         ->  list_add(mode, list, R, Opts, As);
 641	{tcp_module,_}  -> list_opt(Opts, R, As);
 642	inet         -> list_opt(Opts, R, As);
 643	inet6        -> list_opt(Opts, R, As);
 644	{Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
 645	_ -> {error, badarg}
 646    end;
 647list_opt([], R, _SockOpts) ->
 648    {ok, R}.
 649
 650list_add(Name, Val, R, Opts, As) ->
 651    case add_opt(Name, Val, R#listen_opts.opts, As) of
 652	{ok, SOpts} ->
 653	    list_opt(Opts, R#listen_opts { opts = SOpts }, As);
 654	Error -> Error
 655    end.
 656
 657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 658%% Available options for udp:open
 659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 660udp_options() ->
 661    [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, 
 662     deliver,
 663     broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
 664     add_membership, drop_membership, read_packets,raw].
 665
 666
 667udp_options(Opts, Family) ->
 668    case udp_opt(Opts, #udp_opts { }, udp_options()) of
 669	{ok, R} ->
 670	    {ok, R#udp_opts {
 671		   ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
 672		  }};
 673	Error -> Error
 674    end.
 675
 676udp_opt([{raw,A,B,C}|Opts], R, As) ->
 677    udp_opt([{raw,{A,B,C}}|Opts], R, As);
 678udp_opt([Opt | Opts], R, As) ->
 679    case Opt of
 680	{ip,IP}     ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
 681	{ifaddr,IP} ->  udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
 682	{port,P}    ->  udp_opt(Opts, R#udp_opts { port = P }, As);
 683	{fd,Fd}     ->  udp_opt(Opts, R#udp_opts { fd = Fd }, As);
 684	binary      ->  udp_add(mode, binary, R, Opts, As);
 685	list        ->  udp_add(mode, list, R, Opts, As);
 686	{udp_module,_} -> udp_opt(Opts, R, As);
 687	inet        -> udp_opt(Opts, R, As);
 688	inet6       -> udp_opt(Opts, R, As);
 689	{Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
 690	_ -> {error, badarg}
 691    end;
 692udp_opt([], R, _SockOpts) ->
 693    {ok, R}.
 694
 695udp_add(Name, Val, R, Opts, As) ->
 696    case add_opt(Name, Val, R#udp_opts.opts, As) of
 697	{ok, SOpts} ->
 698	    udp_opt(Opts, R#udp_opts { opts = SOpts }, As);
 699	Error -> Error
 700    end.
 701
 702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 703%% Available options for sctp:open
 704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 705%  Currently supported options include:
 706%  (*) {mode,   list|binary}	 or just list|binary
 707%  (*) {active, true|false|once}
 708%  (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6
 709%  (*) options set via setsockopt.
 710%      The full list is below in sctp_options/0 .
 711%  All other options are currently NOT supported. In particular:
 712%  (*) multicast on SCTP is not (yet) supported, as it may be incompatible
 713%      with automatic associations;
 714%  (*) passing of open FDs ("fdopen") is not supported.
 715sctp_options() ->
 716[   % The following are generic inet options supported for SCTP sockets:
 717    mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
 718    recbuf,
 719
 720    % Other options are SCTP-specific (though they may be similar to their
 721    % TCP and UDP counter-parts):
 722    sctp_rtoinfo,   		 sctp_associnfo,	sctp_initmsg,
 723    sctp_autoclose,		 sctp_nodelay,		sctp_disable_fragments,
 724    sctp_i_want_mapped_v4_addr,  sctp_maxseg,		sctp_primary_addr,
 725    sctp_set_peer_primary_addr,  sctp_adaptation_layer,	sctp_peer_addr_params,
 726    sctp_default_send_param,	 sctp_events,		sctp_delayed_ack_time,
 727    sctp_status,	   	 sctp_get_peer_addr_info
 728].
 729
 730sctp_options(Opts, Mod)  ->
 731    case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
 732	{ok,#sctp_opts{ifaddr=undefined}=SO} -> 
 733	    {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
 734	{ok,_}=OK ->
 735	    OK;
 736	Error -> Error
 737    end.
 738
 739sctp_opt([Opt|Opts], Mod, R, As) ->
 740    case Opt of
 741	{ip,IP} ->
 742	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
 743	{ifaddr,IP} ->
 744	    sctp_opt_ifaddr(Opts, Mod, R, As, IP);
 745	{port,Port} ->
 746	    case Mod:getserv(Port) of
 747		{ok,P} ->
 748		    sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As);
 749		Error -> Error
 750	    end;
 751	binary		-> sctp_opt (Opts, Mod, R, As, mode, binary);
 752	list		-> sctp_opt (Opts, Mod, R, As, mode, list);
 753	{sctp_module,_}	-> sctp_opt (Opts, Mod, R, As); % Done with
 754	inet		-> sctp_opt (Opts, Mod, R, As); % Done with
 755	inet6		-> sctp_opt (Opts, Mod, R, As); % Done with
 756	{Name,Val}	-> sctp_opt (Opts, Mod, R, As, Name, Val);
 757	_ -> {error,badarg}
 758    end;
 759sctp_opt([], _Mod, R, _SockOpts) ->
 760    {ok, R}.
 761
 762sctp_opt(Opts, Mod, R, As, Name, Val) ->
 763    case add_opt(Name, Val, R#sctp_opts.opts, As) of
 764	{ok,SocketOpts} ->
 765	    sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As);
 766	Error -> Error
 767    end.
 768
 769sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
 770    IP = Mod:translate_ip(Addr),
 771    sctp_opt(Opts, Mod, 
 772	     R#sctp_opts{
 773	       ifaddr=case IfAddr of
 774			  undefined              -> IP;
 775			  _ when is_list(IfAddr) -> [IP|IfAddr];
 776			  _                      -> [IP,IfAddr]
 777		      end}, As).
 778
 779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 780%% Util to check and insert option in option list
 781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 782
 783add_opt(Name, Val, Opts, As) ->
 784    case lists:member(Name, As) of
 785	true ->
 786	    case prim_inet:is_sockopt_val(Name, Val) of
 787		true ->
 788		    Opts1 = lists:keydelete(Name, 1, Opts),
 789		    {ok, [{Name,Val} | Opts1]};
 790		false -> {error,badarg}
 791	    end;
 792	false -> {error,badarg}
 793    end.
 794	
 795
 796translate_ip(any,      inet) -> {0,0,0,0};
 797translate_ip(loopback, inet) -> {127,0,0,1};
 798translate_ip(any,      inet6) -> {0,0,0,0,0,0,0,0};
 799translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
 800translate_ip(IP, _) -> IP.
 801
 802
 803getaddrs_tm({A,B,C,D} = IP, Fam, _)  ->
 804    %% Only "syntactic" validation and check of family.
 805    if 
 806	?ip(A,B,C,D) ->
 807	    if
 808		Fam =:= inet -> {ok,[IP]};
 809		true -> {error,eafnosupport}
 810	    end;
 811	true -> {error,einval}
 812    end;
 813getaddrs_tm({A,B,C,D,E,F,G,H} = IP, Fam, _) ->
 814    %% Only "syntactic" validation; we assume that the address was
 815    %% "semantically" validated when it was converted to a tuple.
 816    if 
 817	?ip6(A,B,C,D,E,F,G,H) ->
 818	    if
 819		Fam =:= inet6 -> {ok,[IP]};
 820		true -> {error,eafnosupport}
 821	    end;
 822	true -> {error,einval}
 823    end;
 824getaddrs_tm(Address, Family, Timer) when is_atom(Address) ->
 825    getaddrs_tm(atom_to_list(Address), Family, Timer);
 826getaddrs_tm(Address, Family, Timer) ->
 827    case inet_parse:visible_string(Address) of
 828	false ->
 829	    {error,einval};
 830	true ->
 831	    %% Address is a host name or a valid IP address,
 832	    %% either way check it with the resolver.
 833	    case gethostbyname_tm(Address, Family, Timer) of
 834		{ok,Ent} -> {ok,Ent#hostent.h_addr_list};
 835		Error -> Error
 836	    end
 837    end.
 838
 839%%
 840%% gethostbyname with option search
 841%%
 842gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
 843    Result = gethostbyname_string(Name, Type),
 844    gethostbyname_tm(Name, Type, Timer, Opts, Result);
 845gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
 846    Result = inet_res:gethostbyname_tm(Name, Type, Timer),
 847    gethostbyname_tm(Name, Type, Timer, Opts, Result);
 848gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
 849    Result = inet_hosts:gethostbyname(Name, Type),
 850    gethostbyname_tm(Name, Type, Timer, Opts, Result);
 851gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
 852    gethostbyname_tm_native(Name, Type, Timer, Opts);
 853gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
 854    gethostbyname_tm_native(Name, Type, Timer, Opts);
 855gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
 856    gethostbyname_tm_native(Name, Type, Timer, Opts);
 857gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
 858    gethostbyname_tm_native(Name, Type, Timer, Opts);
 859gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
 860    gethostbyname_tm_native(Name, Type, Timer, Opts);
 861gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) ->
 862    gethostbyname_tm(Name, Type, Timer, Opts);
 863%% Make sure we always can look up our own hostname.
 864gethostbyname_tm(Name, Type, Timer, []) ->
 865    Result = gethostbyname_self(Name, Type),
 866    gethostbyname_tm(Name, Type, Timer, [], Result).
 867
 868gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
 869    case Result of
 870	{ok,_} ->
 871	    Result;
 872	{error,formerr} ->
 873	    {error,einval};
 874	{error,_} when Opts =:= [] ->
 875	    {error,nxdomain};
 876	{error,_} ->
 877	    gethostbyname_tm(Name, Type, Timer, tl(Opts))
 878    end.
 879
 880gethostbyname_tm_native(Name, Type, Timer, Opts) ->
 881    %% Fixme: add (global) timeout to gethost_native
 882    Result = inet_gethost_native:gethostbyname(Name, Type),
 883    gethostbyname_tm(Name, Type, Timer, Opts, Result).
 884
 885
 886
 887gethostbyname_self(Name, Type) when is_atom(Name) ->
 888    gethostbyname_self(atom_to_list(Name), Type);
 889gethostbyname_self(Name, Type)
 890  when is_list(Name), Type =:= inet;
 891       is_list(Name), Type =:= inet6 ->
 892    case inet_db:gethostname() of
 893	Name ->
 894	    {ok,make_hostent(Name,
 895			     [translate_ip(loopback, Type)],
 896			     [], Type)};
 897	Self ->
 898	    case inet_db:res_option(domain) of
 899		"" -> {error,nxdomain};
 900		Domain ->
 901		    case lists:append([Self,".",Domain]) of
 902			Name ->
 903			    {ok,make_hostent(Name,
 904					     [translate_ip(loopback, Type)],
 905					     [], Type)};
 906			_ -> {error,nxdomain}
 907		    end
 908	    end
 909    end;
 910gethostbyname_self(_, _) ->
 911    {error,formerr}.
 912
 913gethostbyname_string(Name, Type) when is_atom(Name) ->
 914    gethostbyname_string(atom_to_list(Name), Type);
 915gethostbyname_string(Name, Type)
 916  when is_list(Name), Type =:= inet;
 917       is_list(Name), Type =:= inet6 ->
 918    case
 919	case Type of
 920	    inet ->
 921		inet_parse:ipv4_address(Name);
 922	    inet6 ->
 923		%% XXX should we really translate IPv4 addresses here
 924		%% even if we do not know if this host can do IPv6?
 925		inet_parse:ipv6_address(Name)
 926	end of
 927	{ok,IP} ->
 928	    {ok,make_hostent(Name, [IP], [], Type)};
 929	{error,einval} ->
 930	    {error,nxdomain}
 931    end;
 932gethostbyname_string(_, _) ->
 933    {error,formerr}.
 934
 935make_hostent(Name, Addrs, Aliases, Type) ->
 936    #hostent{h_name = Name,
 937	     h_aliases = Aliases,
 938	     h_addrtype = Type,
 939	     h_length = case Type of inet -> 4; inet6 -> 16 end,
 940	     h_addr_list = Addrs}.
 941
 942%%
 943%% gethostbyaddr with option search
 944%%
 945gethostbyaddr_tm(Addr, Timer, [dns | Opts]) ->
 946    Res = inet_res:gethostbyaddr_tm(Addr,Timer),
 947    case Res of
 948	{ok,_} -> Res;
 949	{error,timeout} -> Res;
 950	{error,formerr} -> {error, einval};
 951	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts)
 952    end;    
 953gethostbyaddr_tm(Addr, Timer, [file | Opts]) ->
 954    case inet_hosts:gethostbyaddr(Addr) of
 955	{error,formerr} -> {error, einval};
 956	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
 957	Result -> Result
 958    end;
 959gethostbyaddr_tm(Addr, Timer, [yp | Opts]) ->
 960    gethostbyaddr_tm_native(Addr, Timer, Opts);
 961gethostbyaddr_tm(Addr, Timer, [nis | Opts]) ->
 962    gethostbyaddr_tm_native(Addr, Timer, Opts);
 963gethostbyaddr_tm(Addr, Timer,  [nisplus | Opts]) ->
 964    gethostbyaddr_tm_native(Addr, Timer, Opts);
 965gethostbyaddr_tm(Addr, Timer, [wins | Opts]) ->
 966    gethostbyaddr_tm_native(Addr, Timer, Opts);
 967gethostbyaddr_tm(Addr, Timer, [native | Opts]) ->
 968    gethostbyaddr_tm_native(Addr, Timer, Opts);
 969gethostbyaddr_tm(Addr, Timer, [_ | Opts]) ->
 970    gethostbyaddr_tm(Addr, Timer, Opts);
 971gethostbyaddr_tm({127,0,0,1}=IP, _Timer, []) ->
 972    gethostbyaddr_self(IP, inet);
 973gethostbyaddr_tm({0,0,0,0,0,0,0,1}=IP, _Timer, []) ->
 974    gethostbyaddr_self(IP, inet6);
 975gethostbyaddr_tm(_Addr, _Timer, []) ->
 976    {error, nxdomain}.
 977
 978gethostbyaddr_self(IP, Type) ->
 979    Name = inet_db:gethostname(),
 980    case inet_db:res_option(domain) of
 981	"" ->
 982	    {ok,make_hostent(Name, [IP], [], Type)};
 983	Domain ->
 984	    {ok,make_hostent(Name++"."++Domain, [IP], [Name], Type)}
 985    end.
 986	    
 987gethostbyaddr_tm_native(Addr, Timer, Opts) ->
 988    %% Fixme: user timer for timeoutvalue
 989    case inet_gethost_native:gethostbyaddr(Addr) of
 990	{error,formerr} -> {error, einval};
 991	{error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
 992	Result -> Result
 993    end.
 994
 995-spec open(Fd :: integer(),
 996	   Addr :: ip_address(),
 997	   Port :: port_number(),
 998	   Opts :: [socket_setopt()],
 999	   Protocol :: protocol_option(),
1000	   Family :: 'inet' | 'inet6',
1001	   Module :: atom()) ->
1002	{'ok', socket()} | {'error', posix()}.
1003
1004open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 ->
1005    case prim_inet:open(Protocol, Family) of
1006	{ok,S} ->
1007	    case prim_inet:setopts(S, Opts) of
1008		ok ->
1009		    case if is_list(Addr) ->
1010				 prim_inet:bind(S, add,
1011						[case A of
1012						     {_,_} -> A;
1013						     _     -> {A,Port}
1014						 end || A <- Addr]);
1015			    true ->
1016				 prim_inet:bind(S, Addr, Port)
1017			 end of
1018			{ok, _} -> 
1019			    inet_db:register_socket(S, Module),
1020			    {ok,S};
1021			Error  ->
1022			    prim_inet:close(S),
1023			    Error
1024		    end;
1025		Error  ->
1026		    prim_inet:close(S),
1027		    Error
1028	    end;
1029	Error ->
1030	    Error
1031    end;
1032open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) ->
1033    fdopen(Fd, Opts, Protocol, Family, Module).
1034
1035-spec fdopen(Fd :: non_neg_integer(),
1036	     Opts :: [socket_setopt()],
1037	     Protocol :: protocol_option(),
1038	     Family :: address_family(),
1039	     Module :: atom()) ->
1040	{'ok', socket()} | {'error', posix()}.
1041
1042fdopen(Fd, Opts, Protocol, Family, Module) ->
1043    case prim_inet:fdopen(Protocol, Fd, Family) of
1044	{ok, S} ->
1045	    case prim_inet:setopts(S, Opts) of
1046		ok ->
1047		    inet_db:register_socket(S, Module),
1048		    {ok, S};
1049		Error ->
1050		    prim_inet:close(S), Error
1051	    end;
1052	Error -> Error
1053    end.
1054
1055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1056%%  socket stat
1057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1058
1059i() -> i(tcp), i(udp).
1060
1061i(Proto) -> i(Proto, [port, module, recv, sent, owner,
1062		      local_address, foreign_address, state]).
1063
1064i(tcp, Fs) ->
1065    ii(tcp_sockets(), Fs, tcp);
1066i(udp, Fs) ->
1067    ii(udp_sockets(), Fs, udp).
1068
1069ii(Ss, Fs, Proto) ->
1070    LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)],
1071    Maxs = foldl(
1072	     fun(Line,Max0) -> smax(Max0,Line) end, 
1073	     duplicate(length(Fs),0),LLs),
1074    Fmt = append(["~-" ++ integer_to_list(N) ++ "s " || N <- Maxs]) ++ "\n",
1075    lists:foreach(fun(Line) -> io:format(Fmt, Line) end, LLs).
1076
1077smax([Max|Ms], [Str|Strs]) ->
1078    N = length(Str),
1079    [if N > Max -> N; true -> Max end | smax(Ms, Strs)];
1080smax([], []) -> [].
1081
1082info_lines(Ss, Fs, Proto) -> [i_line(S, Fs,Proto) || S <- Ss].
1083i_line(S, Fs, Proto)      -> [info(S, F, Proto) || F <- Fs].
1084
1085h_line(Fs) -> [h_field(atom_to_list(F)) || F <- Fs].
1086
1087h_field([C|Cs]) -> [upper(C) | hh_field(Cs)].
1088
1089hh_field([$_,C|Cs]) -> [$\s,upper(C) | hh_field(Cs)];
1090hh_field([C|Cs]) -> [C|hh_field(Cs)];
1091hh_field([]) -> [].
1092
1093upper(C) when C >= $a, C =< $z -> (C-$a) + $A;
1094upper(C) -> C.
1095
1096    
1097info(S, F, Proto) ->
1098    case F of
1099	owner ->
1100	    case erlang:port_info(S, connected) of
1101		{connected, Owner} -> pid_to_list(Owner);
1102		_ -> " "
1103	    end;
1104	port ->
1105	    case erlang:port_info(S,id) of
1106		{id, Id}  -> integer_to_list(Id);
1107		undefined -> " "
1108	    end;
1109	sent ->
1110	    case prim_inet:getstat(S, [send_oct]) of
1111		{ok,[{send_oct,N}]} -> integer_to_list(N);
1112		_ -> " "
1113	    end;
1114	recv ->
1115	    case  prim_inet:getstat(S, [recv_oct]) of
1116		{ok,[{recv_oct,N}]} -> integer_to_list(N);
1117		_ -> " "
1118	    end;
1119	local_address ->
1120	    fmt_addr(prim_inet:sockname(S), Proto);
1121	foreign_address ->
1122	    fmt_addr(prim_inet:peername(S), Proto);
1123	state ->
1124	    case prim_inet:getstatus(S) of
1125		{ok,Status} -> fmt_status(Status);
1126		_ -> " "
1127	    end;
1128	packet ->
1129	    case prim_inet:getopt(S, packet) of
1130		{ok,Type} when is_atom(Type) -> atom_to_list(Type);
1131		{ok,Type} when is_integer(Type) -> integer_to_list(Type);
1132		_ -> " "
1133	    end;
1134	type ->
1135	    case prim_inet:gettype(S) of
1136		{ok,{_,stream}} -> "STREAM";
1137		{ok,{_,dgram}}  -> "DGRAM";
1138		_ -> " "
1139	    end;
1140	fd ->
1141	    case prim_inet:getfd(S) of
1142		{ok, Fd} -> integer_to_list(Fd);
1143		_ -> " "
1144	    end;
1145	module ->
1146	    case inet_db:lookup_socket(S) of
1147		{ok,Mod} -> atom_to_list(Mod);
1148		_ -> "prim_inet"
1149	    end
1150    end.
1151%% Possible flags: (sorted)
1152%% [accepting,bound,busy,connected,connecting,listen,listening,open]
1153%%
1154fmt_status(Flags) ->
1155    case lists:sort(Flags) of
1156	[accepting | _]               -> "ACCEPTING";
1157	[bound,busy,connected|_]      -> "CONNECTED*";
1158	[bound,connected|_]           -> "CONNECTED";
1159	[bound,listen,listening | _]  -> "LISTENING";
1160	[bound,listen | _]            -> "LISTEN";
1161	[bound,connecting | _]        -> "CONNECTING";
1162	[bound,open]                  -> "BOUND";
1163	[open]                        -> "IDLE";
1164	[]                            -> "CLOSED";
1165	_                             -> "????"
1166    end.
1167
1168fmt_addr({error,enotconn}, _) -> "*:*";
1169fmt_addr({error,_}, _)        -> " ";
1170fmt_addr({ok,Addr}, Proto) ->
1171    case Addr of
1172	%%Dialyzer {0,0}            -> "*:*";
1173	{{0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
1174	{{0,0,0,0,0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
1175	{{127,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
1176	{{0,0,0,0,0,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
1177	{IP,Port} -> inet_parse:ntoa(IP) ++ ":" ++ fmt_port(Port, Proto)
1178    end.
1179
1180fmt_port(N, Proto) ->
1181    case inet:getservbyport(N, Proto) of
1182	{ok, Name} -> Name;
1183	_ -> integer_to_list(N)
1184    end.
1185
1186%% Return a list of all tcp sockets
1187tcp_sockets() -> port_list("tcp_inet").
1188udp_sockets() -> port_list("udp_inet").
1189
1190%% Return all ports having the name 'Name'
1191port_list(Name) ->
1192    filter(
1193      fun(Port) ->
1194	      case erlang:port_info(Port, name) of
1195		  {name, Name} -> true;
1196		  _ -> false
1197	      end
1198      end, erlang:ports()).
1199
1200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201%%  utils
1202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203
1204-spec format_error(Posix) -> string() when
1205      Posix :: posix().
1206
1207format_error(exbadport) -> "invalid port state";
1208format_error(exbadseq) ->  "bad command sequence";
1209format_error(Tag) ->
1210    erl_posix_msg:message(Tag).
1211
1212%% Close a TCP socket.
1213tcp_close(S) when is_port(S) ->
1214    %% if exit_on_close is set we must force a close even if remotely closed!!!
1215    prim_inet:close(S),
1216    receive {tcp_closed, S} -> ok after 0 -> ok end.
1217
1218%% Close a UDP socket.
1219udp_close(S) when is_port(S) ->
1220    receive 
1221	{udp_closed, S} -> ok
1222    after 0 ->
1223	    prim_inet:close(S),
1224	    receive {udp_closed, S} -> ok after 0 -> ok end
1225    end.
1226
1227%% Set controlling process for TCP socket.
1228tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
1229    case erlang:port_info(S, connected) of
1230	{connected, Pid} when Pid =/= self() ->
1231	    {error, not_owner};
1232	undefined ->
1233	    {error, einval};
1234	_ ->
1235	    case prim_inet:getopt(S, active) of
1236		{ok, A0} ->
1237		    prim_inet:setopt(S, active, false),
1238		    case tcp_sync_input(S, NewOwner, false) of
1239			true ->  %% socket already closed, 
1240			    ok;
1241			false ->
1242			    try erlang:port_connect(S, NewOwner) of
1243				true -> 
1244				    unlink(S), %% unlink from port
1245				    prim_inet:setopt(S, active, A0),
1246				    ok
1247			    catch
1248				error:Reason -> 
1249				    {error, Reason}
1250			    end
1251		    end;
1252		Error ->
1253		    Error
1254	    end
1255    end.
1256
1257tcp_sync_input(S, Owner, Flag) ->
1258    receive
1259	{tcp, S, Data} ->
1260	    Owner ! {tcp, S, Data},
1261	    tcp_sync_input(S, Owner, Flag);
1262	{tcp_closed, S} ->
1263	    Owner ! {tcp_closed, S},
1264	    tcp_sync_input(S, Owner, true);
1265	{S, {data, Data}} ->
1266	    Owner ! {S, {data, Data}},
1267	    tcp_sync_input(S, Owner, Flag);	    
1268	{inet_async, S, Ref, Status} ->
1269	    Owner ! {inet_async, S, Ref, Status},
1270	    tcp_sync_input(S, Owner, Flag);
1271	{inet_reply, S, Status} ->
1272	    Owner ! {inet_reply, S, Status},
1273	    tcp_sync_input(S, Owner, Flag)
1274    after 0 -> 
1275	    Flag
1276    end.
1277
1278%% Set controlling process for UDP or SCTP socket.
1279udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
1280    case erlang:port_info(S, connected) of
1281	{connected, Pid} when Pid =/= self() ->
1282	    {error, not_owner};
1283	_ ->
1284	    {ok, A0} = prim_inet:getopt(S, active),
1285	    prim_inet:setopt(S, active, false),
1286	    udp_sync_input(S, NewOwner),
1287	    try erlang:port_connect(S, NewOwner) of
1288		true -> 
1289		    unlink(S),
1290		    prim_inet:setopt(S, active, A0),
1291		    ok
1292	    catch
1293		error:Reason -> 
1294		    {error, Reason}
1295	    end
1296    end.
1297
1298udp_sync_input(S, Owner) ->
1299    receive
1300	{sctp, S, _, _, _}=Msg    -> udp_sync_input(S, Owner, Msg);
1301	{udp, S, _, _, _}=Msg     -> udp_sync_input(S, Owner, Msg);
1302	{udp_closed, S}=Msg       -> udp_sync_input(S, Owner, Msg);
1303	{S, {data,_}}=Msg         -> udp_sync_input(S, Owner, Msg);
1304	{inet_async, S, _, _}=Msg -> udp_sync_input(S, Owner, Msg);
1305	{inet_reply, S, _}=Msg    -> udp_sync_input(S, Owner, Msg)
1306    after 0 ->
1307	    ok
1308    end.
1309
1310udp_sync_input(S, Owner, Msg) ->
1311    Owner ! Msg,
1312    udp_sync_input(S, Owner).
1313
1314start_timer(infinity) -> false;
1315start_timer(Timeout) ->
1316    erlang:start_timer(Timeout, self(), inet).
1317
1318timeout(false) -> infinity;
1319timeout(Timer) ->
1320    case erlang:read_timer(Timer) of
1321	false -> 0;
1322	Time  -> Time
1323    end.
1324
1325timeout(Time, false) -> Time;
1326timeout(Time, Timer) ->
1327    TimerTime = timeout(Timer),
1328    if TimerTime < Time -> TimerTime;
1329       true -> Time
1330    end.
1331
1332stop_timer(false) -> false;
1333stop_timer(Timer) ->
1334    case erlang:cancel_timer(Timer) of
1335	false ->
1336	    receive
1337		{timeout,Timer,_} -> false
1338	    after 0 ->
1339		    false
1340	    end;
1341	T -> T
1342    end.