PageRenderTime 28ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/kernel/src/inet.erl

https://github.com/bsmr-erlang/otp
Erlang | 1832 lines | 1476 code | 224 blank | 132 comment | 13 complexity | d2294207c967405b2c62330eb0a544c0 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file