1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2021. 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 info/1, socket_to_list/1, 35 ip/1, stats/0, options/0, 36 pushf/3, popf/1, close/1, gethostname/0, gethostname/1, 37 parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1, 38 parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, 39 ntoa/1, ipv4_mapped_ipv6_address/1]). 40 41-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]). 42-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]). 43-export([gen_tcp_module/1, gen_udp_module/1]). 44 45-export([i/0, i/1, i/2]). 46 47-export([getll/1, getfd/1, open/8, open_bind/8, fdopen/6]). 48 49-export([tcp_controlling_process/2, udp_controlling_process/2, 50 tcp_close/1, udp_close/1]). 51 52%% used by sendfile 53-export([lock_socket/2]). 54 55%% used by socks5 56-export([setsockname/2, setpeername/2]). 57 58%% resolve 59-export([gethostbyname/1, gethostbyname/2, gethostbyname/3, 60 gethostbyname_tm/3]). 61-export([gethostbyname_string/2, gethostbyname_self/2]). 62-export([gethostbyaddr/1, gethostbyaddr/2, 63 gethostbyaddr_tm/2]). 64 65-export([getservbyname/2, getservbyport/2]). 66-export([getaddrs/2, getaddrs/3, getaddrs_tm/3, 67 getaddr/2, getaddr/3, getaddr_tm/3]). 68-export([translate_ip/2]). 69 70-export([get_rc/0]). 71 72%% format error 73-export([format_error/1]). 74 75%% timer interface 76-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]). 77 78%% Socket monitoring 79-export([monitor/1, cancel_monitor/1]). 80 81-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0, 82 ip6_address/0, ip_address/0, port_number/0, 83 family_address/0, local_address/0, 84 socket_address/0, returned_non_ip_address/0, 85 socket_setopt/0, socket_getopt/0, ancillary_data/0, 86 posix/0, socket/0, inet_backend/0, stat_option/0]). 87%% imports 88-import(lists, [append/1, duplicate/2, filter/2, foldl/3]). 89 90-define(DEFAULT_KERNEL_INET_BACKEND, inet). % inet_backend() 91 92%% Record Signature 93-define(RS(Record), 94 {Record, record_info(size, Record)}). 95%% Record Signature Check (guard) 96-define(RSC(Record, RS), 97 element(1, Record) =:= element(1, RS), 98 tuple_size(Record) =:= element(2, RS)). 99 100%%% --------------------------------- 101%%% Contract type definitions 102 103 104-type hostent() :: #hostent{}. 105-type hostname() :: atom() | string(). 106-type ip4_address() :: {0..255,0..255,0..255,0..255}. 107-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535, 108 0..65535,0..65535,0..65535,0..65535}. 109-type ip_address() :: ip4_address() | ip6_address(). 110-type port_number() :: 0..65535. 111-type family_address() :: inet_address() | inet6_address() | local_address(). 112-type inet_address() :: 113 {'inet', {ip4_address() | 'any' | 'loopback', port_number()}}. 114-type inet6_address() :: 115 {'inet6', {ip6_address() | 'any' | 'loopback', port_number()}}. 116-type local_address() :: {'local', File :: binary() | string()}. 117-type returned_non_ip_address() :: 118 {'local', binary()} | 119 {'unspec', <<>>} | 120 {'undefined', any()}. 121-type posix() :: 122 'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' | 123 'econnaborted' | 'econnrefused' | 'econnreset' | 124 'edestaddrreq' | 125 'ehostdown' | 'ehostunreach' | 126 'einprogress' | 'eisconn' | 127 'emsgsize' | 128 'enetdown' | 'enetunreach' | 129 'enopkg' | 'enoprotoopt' | 'enotconn' | 'enotty' | 'enotsock' | 130 'eproto' | 'eprotonosupport' | 'eprototype' | 131 'esocktnosupport' | 132 'etimedout' | 133 'ewouldblock' | 134 'exbadport' | 'exbadseq' | file:posix(). 135-type module_socket() :: {'$inet', Handler :: module(), Handle :: term()}. 136-define(module_socket(Handler, Handle), {'$inet', (Handler), (Handle)}). 137-type socket() :: port() | module_socket(). 138-type inet_backend() :: {'inet_backend', 'inet' | 'socket'}. 139 140-type socket_setopt() :: 141 gen_sctp:option() | gen_tcp:option() | gen_udp:option(). 142 143-type socket_getopt() :: 144 gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name(). 145-type ether_address() :: [0..255]. 146 147-type if_setopt() :: 148 {'addr', ip_address()} | 149 {'broadaddr', ip_address()} | 150 {'dstaddr', ip_address()} | 151 {'mtu', non_neg_integer()} | 152 {'netmask', ip_address()} | 153 {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' | 154 'pointtopoint' | 'no_pointtopoint' | 155 'running' | 'multicast']} | 156 {'hwaddr', ether_address()}. 157 158-type if_getopt() :: 159 'addr' | 'broadaddr' | 'dstaddr' | 160 'mtu' | 'netmask' | 'flags' |'hwaddr'. 161 162-type if_getopt_result() :: 163 {'addr', ip_address()} | 164 {'broadaddr', ip_address()} | 165 {'dstaddr', ip_address()} | 166 {'mtu', non_neg_integer()} | 167 {'netmask', ip_address()} | 168 {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' | 169 'pointtopoint' | 'no_pointtopoint' | 170 'running' | 'multicast' | 'loopback']} | 171 {'hwaddr', ether_address()}. 172 173-type getifaddrs_ifopts() :: 174 [Ifopt :: {flags, Flags :: [up | broadcast | loopback | 175 pointtopoint | running | multicast]} | 176 {addr, Addr :: ip_address()} | 177 {netmask, Netmask :: ip_address()} | 178 {broadaddr, Broadaddr :: ip_address()} | 179 {dstaddr, Dstaddr :: ip_address()} | 180 {hwaddr, Hwaddr :: [byte()]}]. 181 182-type address_family() :: 'inet' | 'inet6' | 'local'. 183-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. 184-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. 185-type socket_address() :: 186 ip_address() | 'any' | 'loopback' | local_address(). 187-type stat_option() :: 188 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 189 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. 190 191-type ancillary_data() :: 192 [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ]. 193 194%%% --------------------------------- 195 196-spec get_rc() -> [{Par :: atom(), Val :: any()} | 197 {Par :: atom(), Val1 :: any(), Val2 :: any()}]. 198 199get_rc() -> 200 inet_db:get_rc(). 201 202-spec close(Socket) -> 'ok' when 203 Socket :: socket(). 204 205close(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) -> 206 GenSocketMod:?FUNCTION_NAME(Socket); 207close(Socket) -> 208 prim_inet:close(Socket), 209 receive 210 {Closed, Socket} when Closed =:= tcp_closed; Closed =:= udp_closed -> 211 ok 212 after 0 -> 213 ok 214 end. 215 216 217%% -- Socket monitor 218 219-spec monitor(Socket) -> reference() when 220 Socket :: socket(). 221 222monitor({'$inet', GenSocketMod, _} = Socket) when is_atom(GenSocketMod) -> 223 MRef = GenSocketMod:?FUNCTION_NAME(Socket), 224 case inet_db:put_socket_type(MRef, {socket, GenSocketMod}) of 225 ok -> 226 MRef; 227 error -> 228 GenSocketMod:cancel_monitor(MRef), 229 erlang:error({invalid, Socket}) 230 end; 231monitor(Socket) when is_port(Socket) -> 232 MRef = erlang:monitor(port, Socket), 233 case inet_db:put_socket_type(MRef, port) of 234 ok -> 235 MRef; 236 error -> 237 erlang:demonitor(MRef, [flush]), 238 erlang:error({invalid, Socket}) 239 end; 240monitor(Socket) -> 241 erlang:error(badarg, [Socket]). 242 243 244%% -- Cancel socket monitor 245 246-spec cancel_monitor(MRef) -> boolean() when 247 MRef :: reference(). 248 249cancel_monitor(MRef) when is_reference(MRef) -> 250 case inet_db:take_socket_type(MRef) of 251 {ok, port} -> 252 erlang:demonitor(MRef, [info]); 253 {ok, {socket, GenSocketMod}} -> 254 GenSocketMod:?FUNCTION_NAME(MRef); 255 error -> % Assume it has the monitor has already been cancel'ed 256 false 257 end; 258cancel_monitor(MRef) -> 259 erlang:error(badarg, [MRef]). 260 261 262%% -- Socket peername 263 264-spec peername(Socket :: socket()) -> 265 {ok, 266 {ip_address(), port_number()} | 267 returned_non_ip_address()} | 268 {error, posix()}. 269 270peername(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) -> 271 GenSocketMod:?FUNCTION_NAME(Socket); 272peername(Socket) -> 273 prim_inet:peername(Socket). 274 275-spec setpeername( 276 Socket :: socket(), 277 Address :: 278 {ip_address() | 'any' | 'loopback', 279 port_number()} | 280 socket_address()) -> 281 'ok' | {'error', any()}. 282 283setpeername(Socket, {IP,Port}) -> 284 prim_inet:setpeername(Socket, {IP,Port}); 285setpeername(Socket, undefined) -> 286 prim_inet:setpeername(Socket, undefined). 287 288-spec peernames(Socket :: socket()) -> 289 {ok, 290 [{ip_address(), port_number()} | 291 returned_non_ip_address()]} | 292 {error, posix()}. 293 294peernames(Socket) -> 295 prim_inet:peernames(Socket). 296 297-spec peernames(Socket, Assoc) -> 298 {ok, [{Address, Port}]} | {error, posix()} when 299 Socket :: socket(), 300 Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(), 301 Address :: ip_address(), 302 Port :: non_neg_integer(). 303 304peernames(Socket, Assoc) -> 305 prim_inet:peernames(Socket, Assoc). 306 307 308-spec sockname(Socket :: socket()) -> 309 {ok, 310 {ip_address(), port_number()} | 311 returned_non_ip_address()} | 312 {error, posix()}. 313 314sockname(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) -> 315 GenSocketMod:?FUNCTION_NAME(Socket); 316sockname(Socket) -> 317 prim_inet:sockname(Socket). 318 319-spec setsockname( 320 Socket :: socket(), 321 Address :: 322 {ip_address() | 'any' | 'loopback', 323 port_number()} | 324 socket_address()) -> 325 'ok' | {'error', any()}. 326 327setsockname(Socket, {IP,Port}) -> 328 prim_inet:setsockname(Socket, {IP,Port}); 329setsockname(Socket, undefined) -> 330 prim_inet:setsockname(Socket, undefined). 331 332-spec socknames(Socket :: socket()) -> 333 {ok, 334 [{ip_address(), port_number()} | 335 returned_non_ip_address()]} | 336 {error, posix()}. 337 338socknames(Socket) -> 339 prim_inet:socknames(Socket). 340 341-spec socknames(Socket, Assoc) -> 342 {ok, [{Address, Port}]} | {error, posix()} when 343 Socket :: socket(), 344 Assoc :: #sctp_assoc_change{} | gen_sctp:assoc_id(), 345 Address :: ip_address(), 346 Port :: non_neg_integer(). 347 348socknames(Socket, Assoc) -> 349 prim_inet:socknames(Socket, Assoc). 350 351 352-spec port(Socket) -> {'ok', Port} | {'error', any()} when 353 Socket :: socket(), 354 Port :: port_number(). 355 356port(?module_socket(GenSocketMod, _) = Socket) when is_atom(GenSocketMod) -> 357 case GenSocketMod:sockname(Socket) of 358 {ok, {_, Port}} -> {ok, Port}; 359 {error, _} = Error -> Error 360 end; 361port(Socket) -> 362 case prim_inet:sockname(Socket) of 363 {ok, {_,Port}} -> {ok, Port}; 364 Error -> Error 365 end. 366 367-spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()? 368 'ok' | {'error', posix()}. 369 370send(Socket, Packet) -> 371 prim_inet:send(Socket, Packet). 372 373-spec setopts(Socket, Options) -> ok | {error, posix()} when 374 Socket :: socket(), 375 Options :: [socket_setopt()]. 376 377setopts(?module_socket(GenSocketMod, _) = Socket, Opts) when is_atom(GenSocketMod) -> 378 GenSocketMod:?FUNCTION_NAME(Socket, Opts); 379setopts(Socket, Opts) -> 380 SocketOpts = 381 [case Opt of 382 {netns,NS} -> 383 {netns,filename2binary(NS)}; 384 _ -> 385 Opt 386 end || Opt <- Opts], 387 prim_inet:setopts(Socket, SocketOpts). 388 389-spec getopts(Socket, Options) -> 390 {'ok', OptionValues} | {'error', posix()} when 391 Socket :: socket(), 392 Options :: [socket_getopt()], 393 OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()]. 394 395getopts(?module_socket(GenSocketMod, _) = Socket, Opts) 396 when is_atom(GenSocketMod) -> 397 GenSocketMod:?FUNCTION_NAME(Socket, Opts); 398getopts(Socket, Opts) -> 399 case prim_inet:getopts(Socket, Opts) of 400 {ok,OptionValues} -> 401 {ok, 402 [case OptionValue of 403 {netns,Bin} -> 404 {netns,binary2filename(Bin)}; 405 _ -> 406 OptionValue 407 end || OptionValue <- OptionValues]}; 408 Other -> 409 Other 410 end. 411 412-spec getifaddrs( 413 [Option :: {netns, Namespace :: file:filename_all()}] 414 | socket()) -> 415 {'ok', [{Ifname :: string(), 416 Ifopts :: getifaddrs_ifopts()}]} 417 | {'error', posix()}. 418getifaddrs(Opts) when is_list(Opts) -> 419 withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts); 420getifaddrs(Socket) -> 421 prim_inet:getifaddrs(Socket). 422 423-spec getifaddrs() -> 424 {'ok', [{Ifname :: string(), 425 Ifopts :: getifaddrs_ifopts()}]} 426 | {'error', posix()}. 427getifaddrs() -> 428 withsocket(fun(S) -> prim_inet:getifaddrs(S) end). 429 430 431-spec getiflist( 432 [Option :: {netns, Namespace :: file:filename_all()}] 433 | socket()) -> 434 {'ok', [string()]} | {'error', posix()}. 435 436getiflist(Opts) when is_list(Opts) -> 437 withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts); 438getiflist(Socket) -> 439 prim_inet:getiflist(Socket). 440 441-spec getiflist() -> {'ok', [string()]} | {'error', posix()}. 442 443getiflist() -> 444 withsocket(fun(S) -> prim_inet:getiflist(S) end). 445 446-spec ifget(Socket :: socket(), 447 Name :: string() | atom(), 448 Opts :: [if_getopt()]) -> 449 {'ok', [if_getopt_result()]} | {'error', posix()}. 450 451ifget(Socket, Name, Opts) -> 452 prim_inet:ifget(Socket, Name, Opts). 453 454-spec ifget( 455 Name :: string() | atom(), 456 Opts :: [if_getopt() | 457 {netns, Namespace :: file:filename_all()}]) -> 458 {'ok', [if_getopt_result()]} | {'error', posix()}. 459 460ifget(Name, Opts) -> 461 {NSOpts,IFOpts} = 462 lists:partition( 463 fun ({netns,_}) -> true; 464 (_) -> false 465 end, Opts), 466 withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts). 467 468-spec ifset(Socket :: socket(), 469 Name :: string() | atom(), 470 Opts :: [if_setopt()]) -> 471 'ok' | {'error', posix()}. 472 473ifset(Socket, Name, Opts) -> 474 prim_inet:ifset(Socket, Name, Opts). 475 476-spec ifset( 477 Name :: string() | atom(), 478 Opts :: [if_setopt() | 479 {netns, Namespace :: file:filename_all()}]) -> 480 'ok' | {'error', posix()}. 481 482ifset(Name, Opts) -> 483 {NSOpts,IFOpts} = 484 lists:partition( 485 fun ({netns,_}) -> true; 486 (_) -> false 487 end, Opts), 488 withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts). 489 490-spec getif() -> 491 {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 492 {'error', posix()}. 493 494getif() -> 495 withsocket(fun(S) -> getif(S) end). 496 497%% backwards compatible getif 498-spec getif( 499 [Option :: {netns, Namespace :: file:filename_all()}] 500 | socket()) -> 501 {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | 502 {'error', posix()}. 503 504getif(Opts) when is_list(Opts) -> 505 withsocket(fun(S) -> getif(S) end, Opts); 506getif(Socket) -> 507 case prim_inet:getiflist(Socket) of 508 {ok, IfList} -> 509 {ok, lists:foldl( 510 fun(Name,Acc) -> 511 case prim_inet:ifget(Socket,Name, 512 [addr,broadaddr,netmask]) of 513 {ok,[{addr,A},{broadaddr,B},{netmask,M}]} -> 514 [{A,B,M}|Acc]; 515 %% Some interfaces does not have a b-addr 516 {ok,[{addr,A},{netmask,M}]} -> 517 [{A,undefined,M}|Acc]; 518 _ -> 519 Acc 520 end 521 end, [], IfList)}; 522 Error -> Error 523 end. 524 525withsocket(Fun) -> 526 withsocket(Fun, []). 527%% 528withsocket(Fun, Opts) -> 529 case inet_udp:open(0, Opts) of 530 {ok,Socket} -> 531 Res = Fun(Socket), 532 inet_udp:close(Socket), 533 Res; 534 Error -> 535 Error 536 end. 537 538pushf(_Socket, Fun, _State) when is_function(Fun) -> 539 {error, einval}. 540 541popf(_Socket) -> 542 {error, einval}. 543 544 545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 546% the hostname is not cached any more because this 547% could cause troubles on at least windows with plug-and-play 548% and network-cards inserted and removed in conjunction with 549% use of the DHCP-protocol 550% should never fail 551 552-spec gethostname() -> {'ok', Hostname} when 553 Hostname :: string(). 554 555%%% XXX gethostname() -> net:gethostname(). 556 557gethostname() -> 558 case inet_udp:open(0,[]) of 559 {ok,U} -> 560 {ok,Res} = gethostname(U), 561 inet_udp:close(U), 562 {Res2,_} = lists:splitwith(fun($.)->false;(_)->true end,Res), 563 {ok, Res2}; 564 _ -> 565 {ok, "nohost.nodomain"} 566 end. 567 568-spec gethostname(Socket :: socket()) -> 569 {'ok', string()} | {'error', posix()}. 570 571gethostname(Socket) -> 572 prim_inet:gethostname(Socket). 573 574-spec getstat(Socket) -> 575 {ok, OptionValues} | {error, posix()} when 576 Socket :: socket(), 577 OptionValues :: [{stat_option(), integer()}]. 578 579getstat(Socket) -> 580 getstat(Socket, stats()). 581 582-spec getstat(Socket, Options) -> 583 {ok, OptionValues} | {error, posix()} when 584 Socket :: socket(), 585 Options :: [stat_option()], 586 OptionValues :: [{stat_option(), integer()}]. 587 588getstat(?module_socket(GenSocketMod, _) = Socket, What) 589 when is_atom(GenSocketMod) -> 590 GenSocketMod:?FUNCTION_NAME(Socket, What); 591getstat(Socket, What) -> 592 prim_inet:getstat(Socket, What). 593 594-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when 595 Hostname :: hostname(), 596 Hostent :: hostent(). 597 598gethostbyname(Name) -> 599 case inet_db:res_option(inet6) of 600 true -> 601 gethostbyname_tm(Name, inet6, false); 602 false -> 603 gethostbyname_tm(Name, inet, false) 604 end. 605 606-spec gethostbyname(Hostname, Family) -> 607 {ok, Hostent} | {error, posix()} when 608 Hostname :: hostname(), 609 Family :: address_family(), 610 Hostent :: hostent(). 611 612gethostbyname(Name,Family) -> 613 gethostbyname_tm(Name, Family, false). 614 615-spec gethostbyname(Name :: hostname(), 616 Family :: address_family(), 617 Timeout :: non_neg_integer() | 'infinity') -> 618 {'ok', #hostent{}} | {'error', posix()}. 619 620gethostbyname(Name,Family,Timeout) -> 621 Timer = start_timer(Timeout), 622 Res = gethostbyname_tm(Name,Family,Timer), 623 _ = stop_timer(Timer), 624 Res. 625 626gethostbyname_tm(Name,Family,Timer) -> 627 Opts0 = inet_db:res_option(lookup), 628 Opts = 629 case (lists:member(native, Opts0) orelse 630 lists:member(string, Opts0) orelse 631 lists:member(nostring, Opts0)) of 632 true -> 633 Opts0; 634 false -> 635 [string|Opts0] 636 end, 637 gethostbyname_tm(Name, Family, Timer, Opts). 638 639 640-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when 641 Address :: string() | ip_address(), 642 Hostent :: hostent(). 643 644gethostbyaddr(Address) -> 645 gethostbyaddr_tm(Address, false). 646 647-spec gethostbyaddr(Address :: string() | ip_address(), 648 Timeout :: non_neg_integer() | 'infinity') -> 649 {'ok', #hostent{}} | {'error', posix()}. 650 651gethostbyaddr(Address,Timeout) -> 652 Timer = start_timer(Timeout), 653 Res = gethostbyaddr_tm(Address, Timer), 654 _ = stop_timer(Timer), 655 Res. 656 657gethostbyaddr_tm(Address,Timer) -> 658 gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)). 659 660 661-spec socket_to_list(Socket) -> list() when 662 Socket :: socket(). 663 664socket_to_list({'$inet', GenSocketMod, _} = Socket) 665 when is_atom(GenSocketMod) -> 666 GenSocketMod:?FUNCTION_NAME(Socket); 667socket_to_list(Socket) when is_port(Socket) -> 668 erlang:port_to_list(Socket). 669 670 671 672-spec info(Socket) -> Info when 673 Socket :: socket(), 674 Info :: term(). 675 676info({'$inet', GenSocketMod, _} = Socket) 677 when is_atom(GenSocketMod) -> 678 GenSocketMod:?FUNCTION_NAME(Socket); 679info(Socket) when is_port(Socket) -> 680 case port_info(Socket) of 681 #{states := _} = PortInfo -> 682 case inet:getopts(Socket, [active]) of 683 {ok, [{active, Active}]} -> 684 PortInfo#{active => Active}; 685 _ -> 686 PortInfo 687 end; 688 PortInfo0 -> 689 %% Its actually possible to call this function for non-socket ports, 690 %% but in that case we have no status or statistics. 691 PortInfo1 = 692 case prim_inet:getstatus(Socket) of 693 {ok, State} -> 694 PortInfo0#{states => State}; 695 _ -> 696 PortInfo0 697 end, 698 case getstat(Socket) of 699 {ok, Stats0} -> 700 PortInfo1#{counters => maps:from_list(Stats0)}; 701 _ -> 702 PortInfo1 703 end 704 end. 705 706port_info(P) when is_port(P) -> 707 case erlang:port_info(P) of 708 PI0 when is_list(PI0) -> 709 PI1 = port_info(PI0, [connected, links, input, output]) ++ 710 [erlang:port_info(P, memory), erlang:port_info(P, monitors)], 711 PI2 = pi_replace([{connected, owner}], PI1), 712 maps:from_list(PI2); 713 _ -> 714 #{states => [closed]} 715 end. 716 717port_info(PI, Items) when is_list(PI) -> 718 port_info(PI, Items, []). 719 720port_info(_PI, [], Acc) -> 721 Acc; 722port_info(PI, [Item | Items], Acc) -> 723 Val = proplists:get_value(Item, PI), 724 port_info(PI, Items, [{Item, Val} | Acc]). 725 726pi_replace([], Items) -> 727 Items; 728pi_replace([{Key1, Key2}|Keys], Items) -> 729 case lists:keysearch(Key1, 1, Items) of 730 {value, {Key1, Value}} -> 731 Items2 = lists:keyreplace(Key1, 1, Items, {Key2, Value}), 732 pi_replace(Keys, Items2); 733 false -> 734 pi_replace(Keys, Items) 735 end. 736 737-spec ip(Ip :: ip_address() | string() | atom()) -> 738 {'ok', ip_address()} | {'error', posix()}. 739 740ip({A,B,C,D}) when ?ip(A,B,C,D) -> 741 {ok, {A,B,C,D}}; 742ip(Name) -> 743 case gethostbyname(Name) of 744 {ok, Ent} -> 745 {ok, hd(Ent#hostent.h_addr_list)}; 746 Error -> Error 747 end. 748 749%% This function returns the erlang port used (with inet_drv) 750 751-spec getll(Socket :: socket()) -> {'ok', socket()}. 752 753getll(Socket) when is_port(Socket) -> 754 {ok, Socket}. 755 756%% 757%% Return the internal file descriptor number 758%% 759 760-spec getfd(Socket :: socket()) -> 761 {'ok', non_neg_integer()} | {'error', posix()}. 762 763getfd(Socket) -> 764 prim_inet:getfd(Socket). 765 766%% 767%% Lookup an ip address 768%% 769 770-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when 771 Host :: ip_address() | hostname(), 772 Family :: address_family(), 773 Address :: ip_address(). 774 775getaddr(Address, Family) -> 776 getaddr(Address, Family, infinity). 777 778-spec getaddr(Host :: ip_address() | hostname(), 779 Family :: address_family(), 780 Timeout :: non_neg_integer() | 'infinity') -> 781 {'ok', ip_address()} | {'error', posix()}. 782 783getaddr(Address, Family, Timeout) -> 784 Timer = start_timer(Timeout), 785 Res = getaddr_tm(Address, Family, Timer), 786 _ = stop_timer(Timer), 787 Res. 788 789getaddr_tm(Address, Family, Timer) -> 790 case getaddrs_tm(Address, Family, Timer) of 791 {ok, [IP|_]} -> {ok, IP}; 792 Error -> Error 793 end. 794 795-spec getaddrs(Host, Family) -> 796 {ok, Addresses} | {error, posix()} when 797 Host :: ip_address() | hostname(), 798 Family :: address_family(), 799 Addresses :: [ip_address()]. 800 801getaddrs(Address, Family) -> 802 getaddrs(Address, Family, infinity). 803 804-spec getaddrs(Host :: ip_address() | string() | atom(), 805 Family :: address_family(), 806 Timeout :: non_neg_integer() | 'infinity') -> 807 {'ok', [ip_address()]} | {'error', posix()}. 808 809getaddrs(Address, Family, Timeout) -> 810 Timer = start_timer(Timeout), 811 Res = getaddrs_tm(Address, Family, Timer), 812 _ = stop_timer(Timer), 813 Res. 814 815-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) -> 816 {'ok', string()} | {'error', posix()}. 817 818getservbyport(Port, Proto) -> 819 case inet_udp:open(0, []) of 820 {ok,U} -> 821 Res = prim_inet:getservbyport(U, Port, Proto), 822 inet_udp:close(U), 823 Res; 824 Error -> Error 825 end. 826 827-spec getservbyname(Name :: atom() | string(), 828 Protocol :: atom() | string()) -> 829 {'ok', port_number()} | {'error', posix()}. 830 831getservbyname(Name, Protocol) when is_atom(Name) -> 832 case inet_udp:open(0, []) of 833 {ok,U} -> 834 Res = prim_inet:getservbyname(U, Name, Protocol), 835 inet_udp:close(U), 836 Res; 837 Error -> Error 838 end. 839 840-spec ntoa(IpAddress) -> Address | {error, einval} when 841 Address :: string(), 842 IpAddress :: ip_address(). 843ntoa(Addr) -> 844 inet_parse:ntoa(Addr). 845 846-spec parse_ipv4_address(Address) -> 847 {ok, IPv4Address} | {error, einval} when 848 Address :: string(), 849 IPv4Address :: ip_address(). 850parse_ipv4_address(Addr) -> 851 inet_parse:ipv4_address(Addr). 852 853-spec parse_ipv6_address(Address) -> 854 {ok, IPv6Address} | {error, einval} when 855 Address :: string(), 856 IPv6Address :: ip_address(). 857parse_ipv6_address(Addr) -> 858 inet_parse:ipv6_address(Addr). 859 860-spec parse_ipv4strict_address(Address) -> 861 {ok, IPv4Address} | {error, einval} when 862 Address :: string(), 863 IPv4Address :: ip_address(). 864parse_ipv4strict_address(Addr) -> 865 inet_parse:ipv4strict_address(Addr). 866 867-spec parse_ipv6strict_address(Address) -> 868 {ok, IPv6Address} | {error, einval} when 869 Address :: string(), 870 IPv6Address :: ip_address(). 871parse_ipv6strict_address(Addr) -> 872 inet_parse:ipv6strict_address(Addr). 873 874-spec parse_address(Address) -> 875 {ok, IPAddress} | {error, einval} when 876 Address :: string(), 877 IPAddress :: ip_address(). 878parse_address(Addr) -> 879 inet_parse:address(Addr). 880 881-spec parse_strict_address(Address) -> 882 {ok, IPAddress} | {error, einval} when 883 Address :: string(), 884 IPAddress :: ip_address(). 885parse_strict_address(Addr) -> 886 inet_parse:strict_address(Addr). 887 888-spec ipv4_mapped_ipv6_address(ip_address()) -> ip_address(). 889ipv4_mapped_ipv6_address({D1,D2,D3,D4}) 890 when (D1 bor D2 bor D3 bor D4) < 256 -> 891 {0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4}; 892ipv4_mapped_ipv6_address({D1,D2,D3,D4,D5,D6,D7,D8}) 893 when (D1 bor D2 bor D3 bor D4 bor D5 bor D6 bor D7 bor D8) < 65536 -> 894 {D7 bsr 8,D7 band 255,D8 bsr 8,D8 band 255}. 895 896%% Return a list of available options 897options() -> 898 [ 899 tos, tclass, priority, reuseaddr, keepalive, dontroute, linger, 900 broadcast, sndbuf, recbuf, nodelay, ipv6_v6only, 901 buffer, header, active, packet, deliver, mode, 902 multicast_if, multicast_ttl, multicast_loop, 903 exit_on_close, high_watermark, low_watermark, 904 high_msgq_watermark, low_msgq_watermark, 905 send_timeout, send_timeout_close, show_econnreset 906 ]. 907 908%% Return a list of statistics options 909 910-spec stats() -> [stat_option(),...]. 911 912stats() -> 913 [recv_oct, recv_cnt, recv_max, recv_avg, recv_dvi, 914 send_oct, send_cnt, send_max, send_avg, send_pend]. 915 916 917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 918%% Available options for tcp:connect 919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 920connect_options() -> 921 [tos, tclass, priority, reuseaddr, keepalive, linger, nodelay, 922 sndbuf, recbuf, 923 recvtos, recvtclass, ttl, recvttl, 924 header, active, packet, packet_size, buffer, mode, deliver, line_delimiter, 925 exit_on_close, high_watermark, low_watermark, high_msgq_watermark, 926 low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw, 927 show_econnreset, bind_to_device]. 928 929connect_options(Opts, Mod) -> 930 BaseOpts = 931 case application:get_env(kernel, inet_default_connect_options) of 932 {ok,List} when is_list(List) -> 933 NList = [{active, true} | lists:keydelete(active,1,List)], 934 #connect_opts{ opts = NList}; 935 {ok,{active,_Bool}} -> 936 #connect_opts{ opts = [{active,true}]}; 937 {ok,Option} -> 938 #connect_opts{ opts = [{active,true}, Option]}; 939 _ -> 940 #connect_opts{ opts = [{active,true}]} 941 end, 942 case con_opt(Opts, BaseOpts, connect_options()) of 943 {ok, R} -> 944 {ok, R#connect_opts { 945 opts = lists:reverse(R#connect_opts.opts), 946 ifaddr = Mod:translate_ip(R#connect_opts.ifaddr) 947 }}; 948 Error -> Error 949 end. 950 951con_opt([{raw,A,B,C}|Opts],#connect_opts{} = R,As) -> 952 con_opt([{raw,{A,B,C}}|Opts],R,As); 953con_opt([Opt | Opts], #connect_opts{} = R, As) -> 954 case Opt of 955 {ip,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As); 956 {ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As); 957 {port,P} -> con_opt(Opts, R#connect_opts { port = P }, As); 958 {fd,Fd} -> con_opt(Opts, R#connect_opts { fd = Fd }, As); 959 binary -> con_add(mode, binary, R, Opts, As); 960 list -> con_add(mode, list, R, Opts, As); 961 {netns,NS} -> 962 BinNS = filename2binary(NS), 963 case prim_inet:is_sockopt_val(netns, BinNS) of 964 true -> 965 con_opt(Opts, R#connect_opts { fd = [{netns,BinNS}] }, As); 966 false -> 967 {error, badarg} 968 end; 969 {active,N} when is_integer(N), N < 32768, N >= -32768 -> 970 NOpts = lists:keydelete(active, 1, R#connect_opts.opts), 971 con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As); 972 {line_delimiter,C} when is_integer(C), C >= 0, C =< 255 -> 973 con_add(line_delimiter, C, R, Opts, As); 974 {Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As); 975 _ -> {error, badarg} 976 end; 977con_opt([], #connect_opts{} = R, _) -> 978 {ok, R}. 979 980con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) -> 981 case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of 982 {ok, SOpts} -> 983 con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts); 984 Error -> Error 985 end. 986 987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 988%% Available options for tcp:listen 989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 990listen_options() -> 991 [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, 992 recvtos, recvtclass, ttl, recvttl, 993 header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only, 994 exit_on_close, high_watermark, low_watermark, high_msgq_watermark, 995 low_msgq_watermark, send_timeout, send_timeout_close, delay_send, 996 packet_size, raw, show_econnreset, bind_to_device]. 997 998listen_options(Opts, Mod) -> 999 BaseOpts = 1000 case application:get_env(kernel, inet_default_listen_options) of 1001 {ok,List} when is_list(List) -> 1002 NList = [{active, true} | lists:keydelete(active,1,List)], 1003 #listen_opts{ opts = NList}; 1004 {ok,{active,_Bool}} -> 1005 #listen_opts{ opts = [{active,true}]}; 1006 {ok,Option} -> 1007 #listen_opts{ opts = [{active,true}, Option]}; 1008 _ -> 1009 #listen_opts{ opts = [{active,true}]} 1010 end, 1011 case list_opt(Opts, BaseOpts, listen_options()) of 1012 {ok, R} -> 1013 {ok, R#listen_opts { 1014 opts = lists:reverse(R#listen_opts.opts), 1015 ifaddr = Mod:translate_ip(R#listen_opts.ifaddr) 1016 }}; 1017 Error -> Error 1018 end. 1019 1020list_opt([{raw,A,B,C}|Opts], #listen_opts{} = R, As) -> 1021 list_opt([{raw,{A,B,C}}|Opts], R, As); 1022list_opt([Opt | Opts], #listen_opts{} = R, As) -> 1023 case Opt of 1024 {ip,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As); 1025 {ifaddr,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As); 1026 {port,P} -> list_opt(Opts, R#listen_opts { port = P }, As); 1027 {fd,Fd} -> list_opt(Opts, R#listen_opts { fd = Fd }, As); 1028 {backlog,BL} -> list_opt(Opts, R#listen_opts { backlog = BL }, As); 1029 binary -> list_add(mode, binary, R, Opts, As); 1030 list -> list_add(mode, list, R, Opts, As); 1031 {netns,NS} -> 1032 BinNS = filename2binary(NS), 1033 case prim_inet:is_sockopt_val(netns, BinNS) of 1034 true -> 1035 list_opt(Opts, R#listen_opts { fd = [{netns,BinNS}] }, As); 1036 false -> 1037 {error, badarg} 1038 end; 1039 {active,N} when is_integer(N), N < 32768, N >= -32768 -> 1040 NOpts = lists:keydelete(active, 1, R#listen_opts.opts), 1041 list_opt(Opts, R#listen_opts { opts = [{active,N}|NOpts] }, As); 1042 {Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As); 1043 _ -> {error, badarg} 1044 end; 1045list_opt([], #listen_opts{} = R, _SockOpts) -> 1046 {ok, R}. 1047 1048list_add(Name, Val, #listen_opts{} = R, Opts, As) -> 1049 case add_opt(Name, Val, R#listen_opts.opts, As) of 1050 {ok, SOpts} -> 1051 list_opt(Opts, R#listen_opts { opts = SOpts }, As); 1052 Error -> Error 1053 end. 1054 1055tcp_module(Opts) -> 1056 tcp_module_1(Opts, undefined). 1057 1058tcp_module(Opts, Addr) -> 1059 Address = {undefined,Addr}, 1060 %% Address has to be a 2-tuple but the first element is ignored 1061 tcp_module_1(Opts, Address). 1062 1063tcp_module_1(Opts, Address) -> 1064 mod( 1065 Opts, tcp_module, Address, 1066 #{inet => inet_tcp, inet6 => inet6_tcp, local => local_tcp}). 1067 1068gen_tcp_module([{inet_backend, Flag}|Opts]) -> 1069 gen_tcp_module(Opts, Flag); 1070gen_tcp_module(Opts) -> 1071 gen_tcp_module( 1072 Opts, 1073 persistent_term:get( 1074 {kernel, inet_backend}, ?DEFAULT_KERNEL_INET_BACKEND)). 1075%% 1076gen_tcp_module(Opts, inet) -> 1077 {gen_tcp, Opts}; 1078gen_tcp_module(Opts, socket) -> 1079 {gen_tcp_socket, Opts}. 1080 1081 1082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1083%% Available options for udp:open 1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1085udp_options() -> 1086 [ 1087 tos, tclass, 1088 priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, 1089 recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only, 1090 broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop, 1091 add_membership, drop_membership, read_packets, raw, 1092 high_msgq_watermark, low_msgq_watermark, bind_to_device 1093 ]. 1094 1095 1096udp_options(Opts, Mod) -> 1097 case udp_opt(Opts, #udp_opts { }, udp_options()) of 1098 {ok, R} -> 1099 {ok, R#udp_opts { 1100 opts = lists:reverse(R#udp_opts.opts), 1101 ifaddr = Mod:translate_ip(R#udp_opts.ifaddr) 1102 }}; 1103 Error -> Error 1104 end. 1105 1106udp_opt([{raw,A,B,C}|Opts], #udp_opts{} = R, As) -> 1107 udp_opt([{raw,{A,B,C}}|Opts], R, As); 1108udp_opt([Opt | Opts], #udp_opts{} = R, As) -> 1109 case Opt of 1110 {ip,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As); 1111 {ifaddr,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As); 1112 {port,P} -> udp_opt(Opts, R#udp_opts { port = P }, As); 1113 {fd,Fd} -> udp_opt(Opts, R#udp_opts { fd = Fd }, As); 1114 binary -> udp_add(mode, binary, R, Opts, As); 1115 list -> udp_add(mode, list, R, Opts, As); 1116 {netns,NS} -> 1117 BinNS = filename2binary(NS), 1118 case prim_inet:is_sockopt_val(netns, BinNS) of 1119 true -> 1120 udp_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As); 1121 false -> 1122 {error, badarg} 1123 end; 1124 {active,N} when is_integer(N), N < 32768, N >= -32768 -> 1125 NOpts = lists:keydelete(active, 1, R#udp_opts.opts), 1126 udp_opt(Opts, R#udp_opts { opts = [{active,N}|NOpts] }, As); 1127 {Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As); 1128 _ -> {error, badarg} 1129 end; 1130udp_opt([], #udp_opts{} = R, _SockOpts) -> 1131 {ok, R}. 1132 1133udp_add(Name, Val, #udp_opts{} = R, Opts, As) -> 1134 case add_opt(Name, Val, R#udp_opts.opts, As) of 1135 {ok, SOpts} -> 1136 udp_opt(Opts, R#udp_opts { opts = SOpts }, As); 1137 Error -> Error 1138 end. 1139 1140udp_module(Opts) -> 1141 mod( 1142 Opts, udp_module, undefined, 1143 #{inet => inet_udp, inet6 => inet6_udp, local => local_udp}). 1144 1145gen_udp_module([{inet_backend, Flag}|Opts]) -> 1146 gen_udp_module(Opts, Flag); 1147gen_udp_module(Opts) -> 1148 gen_udp_module( 1149 Opts, 1150 persistent_term:get( 1151 {kernel, inet_backend}, ?DEFAULT_KERNEL_INET_BACKEND)). 1152%% 1153gen_udp_module(Opts, inet) -> 1154 {gen_udp, Opts}; 1155gen_udp_module(Opts, socket) -> 1156 {gen_udp_socket, Opts}. 1157 1158 1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1160%% Available options for sctp:open 1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1162% Currently supported options include: 1163% (*) {mode, list|binary} or just list|binary 1164% (*) {active, true|false|once|N} 1165% (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6 1166% (*) options set via setsockopt. 1167% The full list is below in sctp_options/0 . 1168% All other options are currently NOT supported. In particular: 1169% (*) multicast on SCTP is not (yet) supported, as it may be incompatible 1170% with automatic associations; 1171% (*) passing of open FDs ("fdopen") is not supported. 1172sctp_options() -> 1173[ % The following are generic inet options supported for SCTP sockets: 1174 mode, active, buffer, tos, tclass, ttl, 1175 priority, dontroute, reuseaddr, linger, 1176 recvtos, recvtclass, recvttl, 1177 sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark, 1178 bind_to_device, 1179 1180 % Other options are SCTP-specific (though they may be similar to their 1181 % TCP and UDP counter-parts): 1182 sctp_rtoinfo, sctp_associnfo, sctp_initmsg, 1183 sctp_autoclose, sctp_nodelay, sctp_disable_fragments, 1184 sctp_i_want_mapped_v4_addr, sctp_maxseg, sctp_primary_addr, 1185 sctp_set_peer_primary_addr, sctp_adaptation_layer, sctp_peer_addr_params, 1186 sctp_default_send_param, sctp_events, sctp_delayed_ack_time, 1187 sctp_status, sctp_get_peer_addr_info 1188]. 1189 1190sctp_options(Opts, Mod) -> 1191 case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of 1192 {ok,SO} -> 1193 {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}}; 1194 Error -> Error 1195 end. 1196 1197sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) -> 1198 case Opt of 1199 {ip,IP} -> 1200 sctp_opt_ifaddr(Opts, Mod, R, As, IP); 1201 {ifaddr,IP} -> 1202 sctp_opt_ifaddr(Opts, Mod, R, As, IP); 1203 {port,Port} -> 1204 case Mod:getserv(Port) of 1205 {ok,P} -> 1206 sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As); 1207 Error -> Error 1208 end; 1209 {type,Type} when Type =:= seqpacket; Type =:= stream -> 1210 sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As); 1211 binary -> sctp_opt (Opts, Mod, R, As, mode, binary); 1212 list -> sctp_opt (Opts, Mod, R, As, mode, list); 1213 {netns,NS} -> 1214 BinNS = filename2binary(NS), 1215 case prim_inet:is_sockopt_val(netns, BinNS) of 1216 true -> 1217 sctp_opt( 1218 Opts, Mod, 1219 R#sctp_opts { fd = [{netns,BinNS}] }, 1220 As); 1221 false -> 1222 {error, badarg} 1223 end; 1224 {active,N} when is_integer(N), N < 32768, N >= -32768 -> 1225 NOpts = lists:keydelete(active, 1, R#sctp_opts.opts), 1226 sctp_opt(Opts, Mod, R#sctp_opts { opts = [{active,N}|NOpts] }, As); 1227 {Name,Val} -> sctp_opt (Opts, Mod, R, As, Name, Val); 1228 _ -> {error,badarg} 1229 end; 1230sctp_opt([], _Mod, #sctp_opts{ifaddr=IfAddr}=R, _SockOpts) -> 1231 if is_list(IfAddr) -> 1232 {ok, R#sctp_opts{ifaddr=lists:reverse(IfAddr)}}; 1233 true -> 1234 {ok, R} 1235 end. 1236 1237sctp_opt(Opts, Mod, #sctp_opts{} = R, As, Name, Val) -> 1238 case add_opt(Name, Val, R#sctp_opts.opts, As) of 1239 {ok,SocketOpts} -> 1240 sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As); 1241 Error -> Error 1242 end. 1243 1244sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) -> 1245 IP = Mod:translate_ip(Addr), 1246 sctp_opt(Opts, Mod, 1247 R#sctp_opts{ 1248 ifaddr=case IfAddr of 1249 undefined -> IP; 1250 _ when is_list(IfAddr) -> [IP|IfAddr]; 1251 _ -> [IP,IfAddr] 1252 end}, As). 1253 1254sctp_module(Opts) -> 1255 mod( 1256 Opts, sctp_module, undefined, 1257 #{inet => inet_sctp, inet6 => inet6_sctp}). 1258 1259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1260%% Util to check and insert option in option list 1261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1262 1263add_opt(Name, Val, Opts, As) -> 1264 case lists:member(Name, As) of 1265 true -> 1266 case prim_inet:is_sockopt_val(Name, Val) of 1267 true when Name =:= raw -> 1268 {ok, [{Name,Val} | Opts]}; 1269 true -> 1270 Opts1 = lists:keydelete(Name, 1, Opts), 1271 {ok, [{Name,Val} | Opts1]}; 1272 false -> {error,badarg} 1273 end; 1274 false -> {error,badarg} 1275 end. 1276 1277 1278%% Passthrough all unknown - catch type errors later 1279filename2binary(List) when is_list(List) -> 1280 OutEncoding = file:native_name_encoding(), 1281 try unicode:characters_to_binary(List, unicode, OutEncoding) of 1282 Bin when is_binary(Bin) -> 1283 Bin; 1284 _ -> 1285 List 1286 catch 1287 error:badarg -> 1288 List 1289 end; 1290filename2binary(Bin) -> 1291 Bin. 1292 1293binary2filename(Bin) -> 1294 InEncoding = file:native_name_encoding(), 1295 case unicode:characters_to_list(Bin, InEncoding) of 1296 Filename when is_list(Filename) -> 1297 Filename; 1298 _ -> 1299 %% For getopt/setopt of netns this should only happen if 1300 %% a binary with wrong encoding was used when setting the 1301 %% option, hence the user shall eat his/her own medicine. 1302 %% 1303 %% I.e passthrough here too for now. 1304 %% Future usecases will most probably not want this, 1305 %% rather Unicode error or warning 1306 %% depending on emulator flag instead. 1307 Bin 1308 end. 1309 1310%% Protocol independent, i.e common code for all 1311%% inet_* and inet6_* modules 1312%% 1313translate_ip(any, inet) -> {0,0,0,0}; 1314translate_ip(loopback, inet) -> {127,0,0,1}; 1315translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0}; 1316translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1}; 1317translate_ip(IP, _) -> IP. % undefined goes here 1318 1319mod(Opts, Tag, Address, Map) -> 1320 mod(Opts, Tag, Address, Map, undefined, []). 1321%% 1322mod([{Tag, M}|Opts], Tag, Address, Map, Mod, Acc) -> 1323 mod(Opts, Tag, Address, Map, Mod, Acc, M); 1324mod([{T, _} = Opt|Opts], Tag, _Address, Map, Mod, Acc) 1325 when T =:= ip; T =:= ifaddr-> 1326 mod(Opts, Tag, Opt, Map, Mod, [Opt|Acc]); 1327mod([Family|Opts], Tag, Address, Map, Mod, Acc) when is_atom(Family) -> 1328 case Map of 1329 #{Family := M} -> 1330 mod(Opts, Tag, Address, Map, Mod, Acc, M); 1331 #{} -> 1332 mod(Opts, Tag, Address, Map, Mod, [Family|Acc]) 1333 end; 1334mod([Opt|Opts], Tag, Address, Map, Mod, Acc) -> 1335 mod(Opts, Tag, Address, Map, Mod, [Opt|Acc]); 1336mod([], Tag, Address, Map, undefined, Acc) -> 1337 {case Address of 1338 {_, {local, _}} -> 1339 case Map of 1340 #{local := Mod} -> 1341 Mod; 1342 #{} -> 1343 inet_db:Tag() 1344 end; 1345 {_, IP} when tuple_size(IP) =:= 8 -> 1346 #{inet := IPv4Mod} = Map, 1347 %% Get the mod, but IPv6 address overrides default IPv4 1348 case inet_db:Tag() of 1349 IPv4Mod -> 1350 #{inet6 := IPv6Mod} = Map, 1351 IPv6Mod; 1352 Mod -> 1353 Mod 1354 end; 1355 _ -> 1356 inet_db:Tag() 1357 end, lists:reverse(Acc)}; 1358mod([], _Tag, _Address, _Map, Mod, Acc) -> 1359 {Mod, lists:reverse(Acc)}. 1360%% 1361mod(Opts, Tag, Address, Map, undefined, Acc, M) -> 1362 mod(Opts, Tag, Address, Map, M, Acc); 1363mod(Opts, Tag, Address, Map, Mod, Acc, _M) -> 1364 mod(Opts, Tag, Address, Map, Mod, Acc). 1365 1366getaddrs_tm({A,B,C,D} = IP, Fam, _) -> 1367 %% Only "syntactic" validation and check of family. 1368 if 1369 ?ip(A,B,C,D) -> 1370 if 1371 Fam =:= inet -> {ok,[IP]}; 1372 true -> {error,eafnosupport} 1373 end; 1374 true -> {error,einval} 1375 end; 1376getaddrs_tm({A,B,C,D,E,F,G,H} = IP, Fam, _) -> 1377 %% Only "syntactic" validation; we assume that the address was 1378 %% "semantically" validated when it was converted to a tuple. 1379 if 1380 ?ip6(A,B,C,D,E,F,G,H) -> 1381 if 1382 Fam =:= inet6 -> {ok,[IP]}; 1383 true -> {error,eafnosupport} 1384 end; 1385 true -> {error,einval} 1386 end; 1387getaddrs_tm(Address, Family, Timer) when is_atom(Address) -> 1388 getaddrs_tm(atom_to_list(Address), Family, Timer); 1389getaddrs_tm(Address, Family, Timer) -> 1390 case inet_parse:visible_string(Address) of 1391 false -> 1392 {error,einval}; 1393 true -> 1394 %% Address is a host name or a valid IP address, 1395 %% either way check it with the resolver. 1396 case gethostbyname_tm(Address, Family, Timer) of 1397 {ok,Ent} -> {ok,Ent#hostent.h_addr_list}; 1398 Error -> Error 1399 end 1400 end. 1401 1402%% 1403%% gethostbyname with option search 1404%% 1405gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) -> 1406 Result = gethostbyname_string(Name, Type), 1407 gethostbyname_tm(Name, Type, Timer, Opts, Result); 1408gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) -> 1409 Result = inet_res:gethostbyname_tm(Name, Type, Timer), 1410 gethostbyname_tm(Name, Type, Timer, Opts, Result); 1411gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) -> 1412 Result = inet_hosts:gethostbyname(Name, Type), 1413 gethostbyname_tm(Name, Type, Timer, Opts, Result); 1414gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) -> 1415 gethostbyname_tm_native(Name, Type, Timer, Opts); 1416gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) -> 1417 gethostbyname_tm_native(Name, Type, Timer, Opts); 1418gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) -> 1419 gethostbyname_tm_native(Name, Type, Timer, Opts); 1420gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) -> 1421 gethostbyname_tm_native(Name, Type, Timer, Opts); 1422gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) -> 1423 gethostbyname_tm_native(Name, Type, Timer, Opts); 1424gethostbyname_tm(Name, Type, Timer, [_|Opts]) -> 1425 gethostbyname_tm(Name, Type, Timer, Opts); 1426%% Make sure we always can look up our own hostname. 1427gethostbyname_tm(Name, Type, Timer, []) -> 1428 Result = gethostbyname_self(Name, Type), 1429 gethostbyname_tm(Name, Type, Timer, [], Result). 1430 1431gethostbyname_tm(Name, Type, Timer, Opts, Result) -> 1432 case Result of 1433 {ok,_} -> 1434 Result; 1435 {error,formerr} -> 1436 {error,einval}; 1437 {error,_} when Opts =:= [] -> 1438 {error,nxdomain}; 1439 {error,_} -> 1440 gethostbyname_tm(Name, Type, Timer, tl(Opts)) 1441 end. 1442 1443gethostbyname_tm_native(Name, Type, Timer, Opts) -> 1444 %% Fixme: add (global) timeout to gethost_native 1445 Result = inet_gethost_native:gethostbyname(Name, Type), 1446 gethostbyname_tm(Name, Type, Timer, Opts, Result). 1447 1448 1449 1450gethostbyname_self(Name, Type) when is_atom(Name) -> 1451 gethostbyname_self(atom_to_list(Name), Type); 1452gethostbyname_self(Name, Type) 1453 when is_list(Name), Type =:= inet; 1454 is_list(Name), Type =:= inet6 -> 1455 N = inet_db:tolower(Name), 1456 Self = inet_db:gethostname(), 1457 %% 1458 %% This is the final fallback that pretends /etc/hosts has got 1459 %% a line for the hostname on the loopback address. 1460 %% Lookups into /etc/hosts are case insensitive and return 1461 %% what is in the file. Therefore the letter case may differ between 1462 %% the returned hostent record and the hostname that was asked for. 1463 %% 1464 case inet_db:tolower(Self) of 1465 N -> 1466 {ok, 1467 make_hostent( 1468 Self, [translate_ip(loopback, Type)], [], Type)}; 1469 _ -> 1470 case inet_db:res_option(domain) of 1471 "" -> 1472 {error,nxdomain}; 1473 Domain -> 1474 FQDN = lists:append([Self,".",Domain]), 1475 case inet_db:tolower(FQDN) of 1476 N -> 1477 {ok, 1478 make_hostent( 1479 FQDN, 1480 [translate_ip(loopback, Type)], [], Type)}; 1481 _ -> 1482 {error,nxdomain} 1483 end 1484 end 1485 end; 1486gethostbyname_self(_, _) -> 1487 {error,formerr}. 1488 1489gethostbyname_string(Name, Type) when is_atom(Name) -> 1490 gethostbyname_string(atom_to_list(Name), Type); 1491gethostbyname_string(Name, Type) 1492 when is_list(Name), Type =:= inet; 1493 is_list(Name), Type =:= inet6 -> 1494 case 1495 case Type of 1496 inet -> 1497 inet_parse:ipv4_address(Name); 1498 inet6 -> 1499 inet_parse:ipv6strict_address(Name) 1500 end of 1501 {ok,IP} -> 1502 {ok,make_hostent(Name, [IP], [], Type)}; 1503 {error,einval} -> 1504 {error,nxdomain} 1505 end; 1506gethostbyname_string(_, _) -> 1507 {error,formerr}. 1508 1509make_hostent(Name, Addrs, Aliases, Type) -> 1510 #hostent{h_name = Name, 1511 h_aliases = Aliases, 1512 h_addrtype = Type, 1513 h_length = case Type of inet -> 4; inet6 -> 16 end, 1514 h_addr_list = Addrs}. 1515 1516%% 1517%% gethostbyaddr with option search 1518%% 1519gethostbyaddr_tm(Addr, Timer, [dns | Opts]) -> 1520 Res = inet_res:gethostbyaddr_tm(Addr,Timer), 1521 case Res of 1522 {ok,_} -> Res; 1523 {error,timeout} -> Res; 1524 {error,formerr} -> {error, einval}; 1525 {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts) 1526 end; 1527gethostbyaddr_tm(Addr, Timer, [file | Opts]) -> 1528 case inet_hosts:gethostbyaddr(Addr) of 1529 {error,formerr} -> {error, einval}; 1530 {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts); 1531 Result -> Result 1532 end; 1533gethostbyaddr_tm(Addr, Timer, [yp | Opts]) -> 1534 gethostbyaddr_tm_native(Addr, Timer, Opts); 1535gethostbyaddr_tm(Addr, Timer, [nis | Opts]) -> 1536 gethostbyaddr_tm_native(Addr, Timer, Opts); 1537gethostbyaddr_tm(Addr, Timer, [nisplus | Opts]) -> 1538 gethostbyaddr_tm_native(Addr, Timer, Opts); 1539gethostbyaddr_tm(Addr, Timer, [wins | Opts]) -> 1540 gethostbyaddr_tm_native(Addr, Timer, Opts); 1541gethostbyaddr_tm(Addr, Timer, [native | Opts]) -> 1542 gethostbyaddr_tm_native(Addr, Timer, Opts); 1543gethostbyaddr_tm(Addr, Timer, [_ | Opts]) -> 1544 gethostbyaddr_tm(Addr, Timer, Opts); 1545gethostbyaddr_tm({127,0,0,1}=IP, _Timer, []) -> 1546 gethostbyaddr_self(IP, inet); 1547gethostbyaddr_tm({0,0,0,0,0,0,0,1}=IP, _Timer, []) -> 1548 gethostbyaddr_self(IP, inet6); 1549gethostbyaddr_tm(_Addr, _Timer, []) -> 1550 {error, nxdomain}. 1551 1552gethostbyaddr_self(IP, Type) -> 1553 Name = inet_db:gethostname(), 1554 case inet_db:res_option(domain) of 1555 "" -> 1556 {ok,make_hostent(Name, [IP], [], Type)}; 1557 Domain -> 1558 {ok,make_hostent(Name++"."++Domain, [IP], [Name], Type)} 1559 end. 1560 1561gethostbyaddr_tm_native(Addr, Timer, Opts) -> 1562 %% Fixme: user timer for timeoutvalue 1563 case inet_gethost_native:gethostbyaddr(Addr) of 1564 {error,formerr} -> {error, einval}; 1565 {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts); 1566 Result -> Result 1567 end. 1568 1569 1570-spec open(Fd_or_OpenOpts :: integer() | list(), 1571 BAddr :: 1572 socket_address() | 1573 {ip_address() | 'any' | 'loopback', % Unofficial 1574 port_number()} | 1575 {inet, % Unofficial 1576 {ip4_address() | 'any' | 'loopback', 1577 port_number()}} | 1578 {inet6, % Unofficial 1579 {ip6_address() | 'any' | 'loopback', 1580 port_number()}} | 1581 undefined, % Internal - no bind() 1582 BPort :: port_number(), 1583 Opts :: [socket_setopt()], 1584 Protocol :: socket_protocol(), 1585 Family :: address_family(), 1586 Type :: socket_type(), 1587 Module :: atom()) -> 1588 {'ok', port()} | {'error', posix()}. 1589 1590open(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module) 1591 when is_integer(Fd), 0 =< Fd -> 1592 open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module); 1593open(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) -> 1594 open_opts( 1595 Fd_or_OpenOpts, 1596 if 1597 BAddr =:= undefined, BPort =/= 0 -> 1598 translate_ip(any, Family); 1599 true -> 1600 BAddr 1601 end, BPort, Opts, Protocol, Family, Type, Module). 1602 1603%% The only difference between open/8 and open_bind/8 is that 1604%% if Fd_or_OpenOpts is not a FileDescriptor :: non_neg_integer() 1605%% i.e option {fd,Fd} has not been used hence we are not handling 1606%% an already open socket handle, and also if no bind address 1607%% has been specified (BAddr =:= undefined). 1608%% 1609%% Then open_bind/8 will bind to the wildcard address and the 1610%% specified port (BPort, 0 = wildcard port per default), 1611%% which is the legacy behaviour by this module when opening a socket. 1612%% 1613%% In the same situation, open/8 will bind to the wildcard address 1614%% and the specified port, only if BPort is not 0, i.e a bind port 1615%% has been specified to not be the wildcard port. 1616%% 1617%% So open/8 per default does not bind to an address, which 1618%% is used by TCP connect to let the OS automatically bind to 1619%% an address later, during TCP connect operation. This 1620%% gives the OS more freedom in choosing the originating port and 1621%% therefore makes far more effective use of the port range. 1622 1623-spec open_bind(Fd_or_OpenOpts :: integer() | list(), 1624 BAddr :: 1625 socket_address() | 1626 {ip_address() | 'any' | 'loopback', % Unofficial 1627 port_number()} | 1628 {inet, % Unofficial 1629 {ip4_address() | 'any' | 'loopback', 1630 port_number()}} | 1631 {inet6, % Unofficial 1632 {ip6_address() | 'any' | 'loopback', 1633 port_number()}} | 1634 undefined, % Internal - translated to 'any' 1635 BPort :: port_number(), 1636 Opts :: [socket_setopt()], 1637 Protocol :: socket_protocol(), 1638 Family :: address_family(), 1639 Type :: socket_type(), 1640 Module :: atom()) -> 1641 {'ok', port()} | {'error', posix()}. 1642 1643open_bind(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module) 1644 when is_integer(Fd), 0 =< Fd -> 1645 open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module); 1646open_bind( 1647 Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) -> 1648 open_opts( 1649 Fd_or_OpenOpts, 1650 if 1651 BAddr =:= undefined -> 1652 translate_ip(any, Family); 1653 true -> 1654 BAddr 1655 end, BPort, Opts, Protocol, Family, Type, Module). 1656 1657 1658open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module) -> 1659 DoNotBind = 1660 %% We do not do any binding if no port+addr options 1661 %% were given, in order to keep backwards compatability 1662 %% with pre Erlang/OTP 17 1663 BAddr =:= undefined, % Presumably already bound 1664 if 1665 DoNotBind -> 1666 0 = BPort, ok; % Assertion 1667 true -> 1668 ok 1669 end, 1670 case prim_inet:fdopen(Protocol, Family, Type, Fd, DoNotBind) of 1671 {ok, S} -> 1672 open_setopts(S, BAddr, BPort, Opts, Module); 1673 Error -> 1674 Error 1675 end. 1676 1677open_opts(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) -> 1678 OpenOpts = 1679 if 1680 is_list(Fd_or_OpenOpts) -> Fd_or_OpenOpts; 1681 true -> [] 1682 end, 1683 case prim_inet:open(Protocol, Family, Type, OpenOpts) of 1684 {ok,S} -> 1685 open_setopts(S, BAddr, BPort, Opts, Module); 1686 Error -> 1687 Error 1688 end. 1689 1690%% If BAddr is undefined - do not bind to an address 1691%% 1692open_setopts(S, BAddr, BPort, Opts, Module) -> 1693 case prim_inet:setopts(S, Opts) of 1694 ok when BAddr =:= undefined -> 1695 inet_db:register_socket(S, Module), 1696 {ok,S}; 1697 ok -> 1698 case bind(S, BAddr, BPort) of 1699 {ok, _} -> 1700 inet_db:register_socket(S, Module), 1701 {ok,S}; 1702 Error -> 1703 prim_inet:close(S), 1704 Error 1705 end; 1706 Error -> 1707 prim_inet:close(S), 1708 Error 1709 end. 1710 1711 1712 1713bind(S, Addr, Port) when is_list(Addr) -> 1714 bindx(S, Addr, Port); 1715bind(S, Addr, Port) -> 1716 prim_inet:bind(S, Addr, Port). 1717 1718bindx(S, [Addr], Port0) -> 1719 {IP, Port} = set_bindx_port(Addr, Port0), 1720 prim_inet:bind(S, IP, Port); 1721bindx(S, Addrs, Port0) -> 1722 [{IP, Port} | Rest] = [set_bindx_port(Addr, Port0) || Addr <- Addrs], 1723 case prim_inet:bind(S, IP, Port) of 1724 {ok, AssignedPort} when Port =:= 0 -> 1725 %% On newer Linux kernels, Solaris and FreeBSD, calling 1726 %% bindx with port 0 is ok, but on SuSE 10, it results in einval 1727 Rest2 = [change_bindx_0_port(Addr, AssignedPort) || Addr <- Rest], 1728 prim_inet:bind(S, add, Rest2); 1729 {ok, _} -> 1730 prim_inet:bind(S, add, Rest); 1731 Error -> 1732 Error 1733 end. 1734 1735set_bindx_port({_IP, _Port}=Addr, _OtherPort) -> 1736 Addr; 1737set_bindx_port(IP, Port) -> 1738 {IP, Port}. 1739 1740change_bindx_0_port({IP, 0}, AssignedPort) -> 1741 {IP, AssignedPort}; 1742change_bindx_0_port({_IP, _Port}=Addr, _AssignedPort) -> 1743 Addr. 1744 1745 1746-spec fdopen(Fd :: non_neg_integer(), 1747 Opts :: [socket_setopt()], 1748 Protocol :: socket_protocol(), 1749 Family :: address_family(), 1750 Type :: socket_type(), 1751 Module :: atom()) -> 1752 {'ok', socket()} | {'error', posix()}. 1753 1754fdopen(Fd, Opts, Protocol, Family, Type, Module) 1755 when is_integer(Fd), 0 =< Fd -> 1756 open_fd(Fd, undefined, 0, Opts, Protocol, Family, Type, Module). 1757 1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1759%% socket stat 1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1761 1762-spec i() -> ok. 1763i() -> i(tcp), i(udp), i(sctp). 1764 1765-spec i(socket_protocol()) -> ok. 1766i(Proto) -> i(Proto, [port, module, recv, sent, owner, 1767 local_address, foreign_address, state, type]). 1768 1769-spec i(socket_protocol(), [atom()]) -> ok. 1770i(tcp, Fs) -> 1771 ii(tcp_sockets(), Fs, tcp); 1772i(udp, Fs) -> 1773 ii(udp_sockets(), Fs, udp); 1774i(sctp, Fs) -> 1775 ii(sctp_sockets(), Fs, sctp). 1776 1777ii(Ss, Fs, Proto) -> 1778 LLs = 1779 case info_lines(Ss, Fs, Proto) of 1780 [] -> []; 1781 InfoLines -> [h_line(Fs) | InfoLines] 1782 end, 1783 Maxs = foldl( 1784 fun(Line,Max0) -> smax(Max0,Line) end, 1785 duplicate(length(Fs),0),LLs), 1786 Fmt = append(["~-" ++ integer_to_list(N) ++ "s " || N <- Maxs]) ++ "\n", 1787 lists:foreach(fun(Line) -> io:format(Fmt, Line) end, LLs). 1788 1789smax([Max|Ms], [Str|Strs]) -> 1790 N = length(Str), 1791 [if N > Max -> N; true -> Max end | smax(Ms, Strs)]; 1792smax([], []) -> []. 1793 1794info_lines(Ss, Fs, Proto) -> [i_line(S, Fs,Proto) || S <- Ss]. 1795i_line(S, Fs, Proto) -> [info(S, F, Proto) || F <- Fs]. 1796 1797h_line(Fs) -> [h_field(atom_to_list(F)) || F <- Fs]. 1798 1799h_field([C|Cs]) -> [upper(C) | hh_field(Cs)]. 1800 1801hh_field([$_,C|Cs]) -> [$\s,upper(C) | hh_field(Cs)]; 1802hh_field([C|Cs]) -> [C|hh_field(Cs)]; 1803hh_field([]) -> []. 1804 1805upper(C) when C >= $a, C =< $z -> (C-$a) + $A; 1806upper(C) -> C. 1807 1808 1809info({'$inet', GenSocketMod, _} = S, F, Proto) when is_atom(GenSocketMod) -> 1810 case F of 1811 owner -> 1812 case GenSocketMod:info(S) of 1813 #{owner := Owner} when is_pid(Owner) -> pid_to_list(Owner); 1814 _ -> " " 1815 end; 1816 port -> 1817 case GenSocketMod:getopts(S, [fd]) of 1818 {ok, [{fd, FD}]} -> 1819 "esock[" ++ integer_to_list(FD) ++ "]"; 1820 _ -> 1821 "esock" 1822 end; 1823 sent -> 1824 case GenSocketMod:getstat(S, [send_oct]) of 1825 {ok, [{send_oct, N}]} -> integer_to_list(N); 1826 _ -> " " 1827 end; 1828 recv -> 1829 case GenSocketMod:getstat(S, [recv_oct]) of 1830 {ok, [{recv_oct, N}]} -> integer_to_list(N); 1831 _ -> " " 1832 end; 1833 local_address -> 1834 fmt_addr(GenSocketMod:sockname(S), Proto); 1835 foreign_address -> 1836 fmt_addr(GenSocketMod:peername(S), Proto); 1837 state -> 1838 case GenSocketMod:info(S) of 1839 #{rstates := RStates, 1840 wstates := WStates} -> fmt_compat_status(RStates, WStates); 1841 _ -> " " 1842 end; 1843 packet -> 1844 case GenSocketMod:which_packet_type(S) of 1845 {ok, Type} -> atom_to_list(Type); 1846 _ -> " " 1847 end; 1848 type -> 1849 case GenSocketMod:info(S) of 1850 #{type := stream} -> "STREAM"; 1851 _ -> " " 1852 end; 1853 %% Why do we have this here? Its never called (see i/2 calling i/2). 1854 fd -> 1855 case GenSocketMod:getopts(S, [fd]) of 1856 {ok, [{fd, Fd}]} -> integer_to_list(Fd); 1857 _ -> " " 1858 end; 1859 module -> 1860 atom_to_list(GenSocketMod) 1861 end; 1862info(S, F, Proto) -> 1863 case F of 1864 owner -> 1865 case erlang:port_info(S, connected) of 1866 {connected, Owner} -> pid_to_list(Owner); 1867 _ -> " " 1868 end; 1869 port -> 1870 case erlang:port_info(S,id) of 1871 {id, Id} -> integer_to_list(Id); 1872 undefined -> " " 1873 end; 1874 sent -> 1875 case prim_inet:getstat(S, [send_oct]) of 1876 {ok,[{send_oct,N}]} -> integer_to_list(N); 1877 _ -> " " 1878 end; 1879 recv -> 1880 case prim_inet:getstat(S, [recv_oct]) of 1881 {ok,[{recv_oct,N}]} -> integer_to_list(N); 1882 _ -> " " 1883 end; 1884 local_address -> 1885 fmt_addr(prim_inet:sockname(S), Proto); 1886 foreign_address -> 1887 fmt_addr(prim_inet:peername(S), Proto); 1888 state -> 1889 case prim_inet:getstatus(S) of 1890 {ok,Status} -> fmt_status(Status); 1891 _ -> " " 1892 end; 1893 packet -> 1894 case prim_inet:getopt(S, packet) of 1895 {ok,Type} when is_atom(Type) -> atom_to_list(Type); 1896 {ok,Type} when is_integer(Type) -> integer_to_list(Type); 1897 _ -> " " 1898 end; 1899 type -> 1900 case prim_inet:gettype(S) of 1901 {ok,{_,stream}} -> "STREAM"; 1902 {ok,{_,dgram}} -> "DGRAM"; 1903 {ok,{_,seqpacket}} -> "SEQPACKET"; 1904 _ -> " " 1905 end; 1906 %% Why do we have this here? Its never called (see i/2 calling i/2). 1907 fd -> 1908 case prim_inet:getfd(S) of 1909 {ok, Fd} -> integer_to_list(Fd); 1910 _ -> " " 1911 end; 1912 module -> 1913 case inet_db:lookup_socket(S) of 1914 {ok,Mod} -> atom_to_list(Mod); 1915 _ -> "prim_inet" 1916 end 1917 end. 1918 1919%% Possible flags: (sorted) 1920%% [accepting,bound,busy,connected,connecting,listen,listening,open] 1921%% Actually, we no longer gets listening... 1922fmt_status(Flags) -> 1923 case lists:sort(Flags) of 1924 [accepting | _] -> "ACCEPTING"; 1925 [bound,busy,connected|_] -> "CONNECTED(BB)"; 1926 [bound,connected|_] -> "CONNECTED(B)"; 1927 [bound,listen,listening | _] -> "LISTENING"; 1928 [bound,listen | _] -> "LISTEN"; 1929 [bound,connecting | _] -> "CONNECTING"; 1930 [bound,open] -> "BOUND"; 1931 [connected,open] -> "CONNECTED(O)"; 1932 [open] -> "IDLE"; 1933 [] -> "CLOSED"; 1934 Sorted -> fmt_status2(Sorted) 1935 end. 1936 1937fmt_compat_status(RFlags, WFlags) -> 1938 fmt_status(fmt_compat_status_merge(RFlags, WFlags)). 1939 1940fmt_compat_status_merge(RFlags, WFlags) -> 1941 fmt_compat_status_merge(RFlags, WFlags, []). 1942 1943fmt_compat_status_merge([], WFlags, Merged) -> 1944 Merged ++ WFlags; 1945fmt_compat_status_merge([RFlag|RFlags], WFlags, Merged) -> 1946 fmt_compat_status_merge(RFlags, 1947 lists:delete(RFlag, WFlags), 1948 [RFlag|Merged]). 1949 1950fmt_status2([H]) -> 1951 fmt_status3(H); 1952fmt_status2([H|T]) -> 1953 fmt_status3(H) ++ ":" ++ fmt_status2(T). 1954 1955fmt_status3(accepting) -> 1956 "A"; 1957fmt_status3(bound) -> 1958 "BD"; 1959fmt_status3(busy) -> 1960 "BY"; 1961fmt_status3(connected) -> 1962 "CD"; 1963fmt_status3(connecting) -> 1964 "CG"; 1965fmt_status3(listen) -> 1966 "LN"; 1967fmt_status3(listening) -> 1968 "LG"; 1969fmt_status3(open) -> 1970 "O"; 1971fmt_status3(selected) -> 1972 "SD"; 1973fmt_status3(X) when is_atom(X) -> 1974 string:uppercase(atom_to_list(X)). 1975 1976 1977fmt_addr({error,enotconn}, _) -> "*:*"; 1978fmt_addr({error,_}, _) -> " "; 1979fmt_addr({ok,Addr}, Proto) -> 1980 case Addr of 1981 %%Dialyzer {0,0} -> "*:*"; 1982 {{0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto); 1983 {{0,0,0,0,0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto); 1984 {{127,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto); 1985 {{0,0,0,0,0,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto); 1986 {local, Path} -> "local:" ++ binary_to_list(Path); 1987 {IP,Port} -> inet_parse:ntoa(IP) ++ ":" ++ fmt_port(Port, Proto) 1988 end. 1989 1990fmt_port(N, Proto) -> 1991 case inet:getservbyport(N, Proto) of 1992 {ok, Name} -> Name; 1993 _ -> integer_to_list(N) 1994 end. 1995 1996%% Return a list of all tcp sockets 1997tcp_sockets() -> port_list("tcp_inet") ++ gen_tcp_socket:which_sockets(). 1998udp_sockets() -> port_list("udp_inet") ++ gen_udp_socket:which_sockets(). 1999sctp_sockets() -> port_list("sctp_inet"). 2000 2001%% Return all ports having the name 'Name' 2002port_list(Name) -> 2003 filter( 2004 fun(Port) -> 2005 case erlang:port_info(Port, name) of 2006 {name, Name} -> true; 2007 _ -> false 2008 end 2009 end, erlang:ports()). 2010 2011 2012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2013%% utils 2014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2015 2016-spec format_error(Reason) -> string() when 2017 Reason :: posix() | system_limit. 2018 2019format_error(exbadport) -> "invalid port state"; 2020format_error(exbadseq) -> "bad command sequence"; 2021format_error(system_limit) -> 2022 "a system limit was hit, probably not enough ports"; 2023format_error(Tag) -> 2024 erl_posix_msg:message(Tag). 2025 2026%% Close a TCP socket. 2027tcp_close(S) when is_port(S) -> 2028 %% if exit_on_close is set we must force a close even if remotely closed!!! 2029 prim_inet:close(S), 2030 receive {tcp_closed, S} -> ok after 0 -> ok end. 2031 2032%% Close a UDP socket. 2033udp_close(S) when is_port(S) -> 2034 receive 2035 {udp_closed, S} -> ok 2036 after 0 -> 2037 prim_inet:close(S), 2038 receive {udp_closed, S} -> ok after 0 -> ok end 2039 end. 2040 2041%% Set controlling process for TCP socket. 2042tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> 2043 case erlang:port_info(S, connected) of 2044 {connected, NewOwner} -> 2045 ok; 2046 {connected, Pid} when Pid =/= self() -> 2047 {error, not_owner}; 2048 undefined -> 2049 {error, einval}; 2050 _ -> 2051 case prim_inet:getopt(S, active) of 2052 {ok, A0} -> 2053 SetOptRes = 2054 case A0 of 2055 false -> ok; 2056 _ -> prim_inet:setopt(S, active, false) 2057 end, 2058 case {tcp_sync_input(S, NewOwner, false), SetOptRes} of 2059 {true, _} -> %% socket already closed 2060 ok; 2061 {false, ok} -> 2062 try erlang:port_connect(S, NewOwner) of 2063 true -> 2064 unlink(S), %% unlink from port 2065 case A0 of 2066 false -> ok; 2067 _ -> prim_inet:setopt(S, active, A0) 2068 end 2069 catch 2070 error:Reason -> 2071 {error, Reason} 2072 end; 2073 {false, Error} -> 2074 Error 2075 end; 2076 Error -> 2077 Error 2078 end 2079 end. 2080 2081tcp_sync_input(S, Owner, Flag) -> 2082 receive 2083 {tcp, S, Data} -> 2084 Owner ! {tcp, S, Data}, 2085 tcp_sync_input(S, Owner, Flag); 2086 {tcp_closed, S} -> 2087 Owner ! {tcp_closed, S}, 2088 tcp_sync_input(S, Owner, true); 2089 {S, {data, Data}} -> 2090 Owner ! {S, {data, Data}}, 2091 tcp_sync_input(S, Owner, Flag); 2092 {inet_async, S, Ref, Status} -> 2093 Owner ! {inet_async, S, Ref, Status}, 2094 tcp_sync_input(S, Owner, Flag); 2095 {inet_reply, S, Status} -> 2096 Owner ! {inet_reply, S, Status}, 2097 tcp_sync_input(S, Owner, Flag) 2098 after 0 -> 2099 Flag 2100 end. 2101 2102%% Set controlling process for UDP or SCTP socket. 2103udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> 2104 case erlang:port_info(S, connected) of 2105 {connected, NewOwner} -> 2106 ok; 2107 {connected, Pid} when Pid =/= self() -> 2108 {error, not_owner}; 2109 _ -> 2110 {ok, A0} = prim_inet:getopt(S, active), 2111 ok = prim_inet:setopt(S, active, false), 2112 udp_sync_input(S, NewOwner), 2113 try erlang:port_connect(S, NewOwner) of 2114 true -> 2115 unlink(S), 2116 ok = prim_inet:setopt(S, active, A0) 2117 catch 2118 error:Reason -> 2119 {error, Reason} 2120 end 2121 end. 2122 2123udp_sync_input(S, Owner) -> 2124 receive 2125 {sctp, S, _, _, _}=Msg -> udp_sync_input(S, Owner, Msg); 2126 {udp, S, _, _, _}=Msg -> udp_sync_input(S, Owner, Msg); 2127 {udp_closed, S}=Msg -> udp_sync_input(S, Owner, Msg); 2128 {S, {data,_}}=Msg -> udp_sync_input(S, Owner, Msg); 2129 {inet_async, S, _, _}=Msg -> udp_sync_input(S, Owner, Msg); 2130 {inet_reply, S, _}=Msg -> udp_sync_input(S, Owner, Msg) 2131 after 0 -> 2132 ok 2133 end. 2134 2135udp_sync_input(S, Owner, Msg) -> 2136 Owner ! Msg, 2137 udp_sync_input(S, Owner). 2138 2139start_timer(infinity) -> false; 2140start_timer(Timeout) -> 2141 erlang:start_timer(Timeout, self(), inet). 2142 2143timeout(false) -> infinity; 2144timeout(Timer) -> 2145 case erlang:read_timer(Timer) of 2146 false -> 0; 2147 Time -> Time 2148 end. 2149 2150timeout(Time, false) -> Time; 2151timeout(Time, Timer) -> 2152 TimerTime = timeout(Timer), 2153 if TimerTime < Time -> TimerTime; 2154 true -> Time 2155 end. 2156 2157stop_timer(false) -> false; 2158stop_timer(Timer) -> 2159 case erlang:cancel_timer(Timer) of 2160 false -> 2161 receive 2162 {timeout,Timer,_} -> false 2163 after 0 -> 2164 false 2165 end; 2166 T -> T 2167 end. 2168 2169 2170lock_socket(S,Val) -> 2171 case erlang:port_info(S, connected) of 2172 {connected, Pid} when Pid =/= self() -> 2173 {error, not_owner}; 2174 undefined -> 2175 {error, einval}; 2176 _ -> 2177 prim_inet:ignorefd(S,Val) 2178 end. 2179