PageRenderTime 147ms CodeModel.GetById 2ms app.highlight 134ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/kernel/src/inet.erl

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