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