PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/kernel/src/inet.erl

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