/lib/kernel/src/inet.erl
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