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

/lib/kernel/src/inet.erl

https://github.com/alricb/Erlang-OTP
Erlang | 1342 lines | 1049 code | 187 blank | 106 comment | 9 complexity | 446dc994267cd4487d3f2be2a48b0ab3 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. %%
  2. %% %CopyrightBegin%
  3. %%
  4. %% Copyright Ericsson AB 1997-2011. All Rights Reserved.
  5. %%
  6. %% The contents of this file are subject to the Erlang Public License,
  7. %% Version 1.1, (the "License"); you may not use this file except in
  8. %% compliance with the License. You should have received a copy of the
  9. %% Erlang Public License along with this software. If not, it can be
  10. %% retrieved online at http://www.erlang.org/.
  11. %%
  12. %% Software distributed under the License is distributed on an "AS IS"
  13. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. %% the License for the specific language governing rights and limitations
  15. %% under the License.
  16. %%
  17. %% %CopyrightEnd%
  18. %%
  19. -module(inet).
  20. -include("inet.hrl").
  21. -include("inet_int.hrl").
  22. -include("inet_sctp.hrl").
  23. %% socket
  24. -export([peername/1, sockname/1, port/1, send/2,
  25. setopts/2, getopts/2,
  26. getifaddrs/0, getifaddrs/1,
  27. getif/1, getif/0, getiflist/0, getiflist/1,
  28. ifget/3, ifget/2, ifset/3, ifset/2,
  29. getstat/1, getstat/2,
  30. ip/1, stats/0, options/0,
  31. pushf/3, popf/1, close/1, gethostname/0, gethostname/1]).
  32. -export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
  33. -export([i/0, i/1, i/2]).
  34. -export([getll/1, getfd/1, open/7, fdopen/5]).
  35. -export([tcp_controlling_process/2, udp_controlling_process/2,
  36. tcp_close/1, udp_close/1]).
  37. %% used by socks5
  38. -export([setsockname/2, setpeername/2]).
  39. %% resolve
  40. -export([gethostbyname/1, gethostbyname/2, gethostbyname/3,
  41. gethostbyname_tm/3]).
  42. -export([gethostbyname_string/2, gethostbyname_self/2]).
  43. -export([gethostbyaddr/1, gethostbyaddr/2,
  44. gethostbyaddr_tm/2]).
  45. -export([getservbyname/2, getservbyport/2]).
  46. -export([getaddrs/2, getaddrs/3, getaddrs_tm/3,
  47. getaddr/2, getaddr/3, getaddr_tm/3]).
  48. -export([translate_ip/2]).
  49. -export([get_rc/0]).
  50. %% format error
  51. -export([format_error/1]).
  52. %% timer interface
  53. -export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
  54. -export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
  55. ip6_address/0, ip_address/0, posix/0, socket/0,
  56. port_number/0]).
  57. %% imports
  58. -import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
  59. %% Record Signature
  60. -define(RS(Record),
  61. {Record, record_info(size, Record)}).
  62. %% Record Signature Check (guard)
  63. -define(RSC(Record, RS),
  64. element(1, Record) =:= element(1, RS),
  65. tuple_size(Record) =:= element(2, RS)).
  66. %%% ---------------------------------
  67. %%% Contract type definitions
  68. -type hostent() :: #hostent{}.
  69. -type hostname() :: atom() | string().
  70. -type ip4_address() :: {0..255,0..255,0..255,0..255}.
  71. -type ip6_address() :: {0..65535,0..65535,0..65535,0..65535,
  72. 0..65535,0..65535,0..65535,0..65535}.
  73. -type ip_address() :: ip4_address() | ip6_address().
  74. -type port_number() :: 0..65535.
  75. -type posix() :: exbadport | exbadseq | file:posix().
  76. -type socket() :: port().
  77. -type socket_setopt() ::
  78. gen_sctp:option() | gen_tcp:option() | gen_udp:option().
  79. -type socket_getopt() ::
  80. gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name().
  81. -type ether_address() :: [0..255].
  82. -type if_setopt() ::
  83. {'addr', ip_address()} |
  84. {'broadaddr', ip_address()} |
  85. {'dstaddr', ip_address()} |
  86. {'mtu', non_neg_integer()} |
  87. {'netmask', ip_address()} |
  88. {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
  89. 'pointtopoint' | 'no_pointtopoint' |
  90. 'running' | 'multicast']} |
  91. {'hwaddr', ether_address()}.
  92. -type if_getopt() ::
  93. 'addr' | 'broadaddr' | 'dstaddr' |
  94. 'mtu' | 'netmask' | 'flags' |'hwaddr'.
  95. -type address_family() :: 'inet' | 'inet6'.
  96. -type protocol_option() :: 'tcp' | 'udp' | 'sctp'.
  97. -type stat_option() ::
  98. 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
  99. 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
  100. %%% ---------------------------------
  101. -spec get_rc() -> [{Par :: any(), Val :: any()}].
  102. get_rc() ->
  103. inet_db:get_rc().
  104. -spec close(Socket) -> 'ok' when
  105. Socket :: socket().
  106. close(Socket) ->
  107. prim_inet:close(Socket),
  108. receive
  109. {Closed, Socket} when Closed =:= tcp_closed; Closed =:= udp_closed ->
  110. ok
  111. after 0 ->
  112. ok
  113. end.
  114. -spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when
  115. Socket :: socket(),
  116. Address :: ip_address(),
  117. Port :: non_neg_integer().
  118. peername(Socket) ->
  119. prim_inet:peername(Socket).
  120. -spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
  121. 'ok' | {'error', any()}.
  122. setpeername(Socket, {IP,Port}) ->
  123. prim_inet:setpeername(Socket, {IP,Port});
  124. setpeername(Socket, undefined) ->
  125. prim_inet:setpeername(Socket, undefined).
  126. -spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when
  127. Socket :: socket(),
  128. Address :: ip_address(),
  129. Port :: non_neg_integer().
  130. sockname(Socket) ->
  131. prim_inet:sockname(Socket).
  132. -spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
  133. 'ok' | {'error', any()}.
  134. setsockname(Socket, {IP,Port}) ->
  135. prim_inet:setsockname(Socket, {IP,Port});
  136. setsockname(Socket, undefined) ->
  137. prim_inet:setsockname(Socket, undefined).
  138. -spec port(Socket) -> {'ok', Port} | {'error', any()} when
  139. Socket :: socket(),
  140. Port :: port_number().
  141. port(Socket) ->
  142. case prim_inet:sockname(Socket) of
  143. {ok, {_,Port}} -> {ok, Port};
  144. Error -> Error
  145. end.
  146. -spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()?
  147. 'ok' | {'error', posix()}.
  148. send(Socket, Packet) ->
  149. prim_inet:send(Socket, Packet).
  150. -spec setopts(Socket, Options) -> ok | {error, posix()} when
  151. Socket :: socket(),
  152. Options :: [socket_setopt()].
  153. setopts(Socket, Opts) ->
  154. prim_inet:setopts(Socket, Opts).
  155. -spec getopts(Socket, Options) ->
  156. {'ok', OptionValues} | {'error', posix()} when
  157. Socket :: socket(),
  158. Options :: [socket_getopt()],
  159. OptionValues :: [socket_setopt()].
  160. getopts(Socket, Opts) ->
  161. prim_inet:getopts(Socket, Opts).
  162. -spec getifaddrs(Socket :: socket()) ->
  163. {'ok', [string()]} | {'error', posix()}.
  164. getifaddrs(Socket) ->
  165. prim_inet:getifaddrs(Socket).
  166. -spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
  167. Iflist :: [{Ifname,[Ifopt]}],
  168. Ifname :: string(),
  169. Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
  170. | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
  171. | {hwaddr,Hwaddr},
  172. Flag :: up | broadcast | loopback | pointtopoint
  173. | running | multicast,
  174. Addr :: ip_address(),
  175. Netmask :: ip_address(),
  176. Broadaddr :: ip_address(),
  177. Dstaddr :: ip_address(),
  178. Hwaddr :: [byte()].
  179. getifaddrs() ->
  180. withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
  181. -spec getiflist(Socket :: socket()) ->
  182. {'ok', [string()]} | {'error', posix()}.
  183. getiflist(Socket) ->
  184. prim_inet:getiflist(Socket).
  185. -spec getiflist() -> {'ok', [string()]} | {'error', posix()}.
  186. getiflist() ->
  187. withsocket(fun(S) -> prim_inet:getiflist(S) end).
  188. -spec ifget(Socket :: socket(),
  189. Name :: string() | atom(),
  190. Opts :: [if_getopt()]) ->
  191. {'ok', [if_setopt()]} | {'error', posix()}.
  192. ifget(Socket, Name, Opts) ->
  193. prim_inet:ifget(Socket, Name, Opts).
  194. -spec ifget(Name :: string() | atom(), Opts :: [if_getopt()]) ->
  195. {'ok', [if_setopt()]} | {'error', posix()}.
  196. ifget(Name, Opts) ->
  197. withsocket(fun(S) -> prim_inet:ifget(S, Name, Opts) end).
  198. -spec ifset(Socket :: socket(),
  199. Name :: string() | atom(),
  200. Opts :: [if_setopt()]) ->
  201. 'ok' | {'error', posix()}.
  202. ifset(Socket, Name, Opts) ->
  203. prim_inet:ifset(Socket, Name, Opts).
  204. -spec ifset(Name :: string() | atom(), Opts :: [if_setopt()]) ->
  205. 'ok' | {'error', posix()}.
  206. ifset(Name, Opts) ->
  207. withsocket(fun(S) -> prim_inet:ifset(S, Name, Opts) end).
  208. -spec getif() ->
  209. {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
  210. {'error', posix()}.
  211. getif() ->
  212. withsocket(fun(S) -> getif(S) end).
  213. %% backwards compatible getif
  214. -spec getif(Socket :: socket()) ->
  215. {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
  216. {'error', posix()}.
  217. getif(Socket) ->
  218. case prim_inet:getiflist(Socket) of
  219. {ok, IfList} ->
  220. {ok, lists:foldl(
  221. fun(Name,Acc) ->
  222. case prim_inet:ifget(Socket,Name,
  223. [addr,broadaddr,netmask]) of
  224. {ok,[{addr,A},{broadaddr,B},{netmask,M}]} ->
  225. [{A,B,M}|Acc];
  226. %% Some interfaces does not have a b-addr
  227. {ok,[{addr,A},{netmask,M}]} ->
  228. [{A,undefined,M}|Acc];
  229. _ ->
  230. Acc
  231. end
  232. end, [], IfList)};
  233. Error -> Error
  234. end.
  235. withsocket(Fun) ->
  236. case inet_udp:open(0,[]) of
  237. {ok,Socket} ->
  238. Res = Fun(Socket),
  239. inet_udp:close(Socket),
  240. Res;
  241. Error ->
  242. Error
  243. end.
  244. pushf(_Socket, Fun, _State) when is_function(Fun) ->
  245. {error, einval}.
  246. popf(_Socket) ->
  247. {error, einval}.
  248. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  249. % the hostname is not cached any more because this
  250. % could cause troubles on at least windows with plug-and-play
  251. % and network-cards inserted and removed in conjunction with
  252. % use of the DHCP-protocol
  253. % should never fail
  254. -spec gethostname() -> {'ok', Hostname} when
  255. Hostname :: string().
  256. gethostname() ->
  257. case inet_udp:open(0,[]) of
  258. {ok,U} ->
  259. {ok,Res} = gethostname(U),
  260. inet_udp:close(U),
  261. {Res2,_} = lists:splitwith(fun($.)->false;(_)->true end,Res),
  262. {ok, Res2};
  263. _ ->
  264. {ok, "nohost.nodomain"}
  265. end.
  266. -spec gethostname(Socket :: socket()) ->
  267. {'ok', string()} | {'error', posix()}.
  268. gethostname(Socket) ->
  269. prim_inet:gethostname(Socket).
  270. -spec getstat(Socket) ->
  271. {ok, OptionValues} | {error, posix()} when
  272. Socket :: socket(),
  273. OptionValues :: [{stat_option(), integer()}].
  274. getstat(Socket) ->
  275. prim_inet:getstat(Socket, stats()).
  276. -spec getstat(Socket, Options) ->
  277. {ok, OptionValues} | {error, posix()} when
  278. Socket :: socket(),
  279. Options :: [stat_option()],
  280. OptionValues :: [{stat_option(), integer()}].
  281. getstat(Socket,What) ->
  282. prim_inet:getstat(Socket, What).
  283. -spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when
  284. Hostname :: hostname(),
  285. Hostent :: hostent().
  286. gethostbyname(Name) ->
  287. gethostbyname_tm(Name, inet, false).
  288. -spec gethostbyname(Hostname, Family) ->
  289. {ok, Hostent} | {error, posix()} when
  290. Hostname :: hostname(),
  291. Family :: address_family(),
  292. Hostent :: hostent().
  293. gethostbyname(Name,Family) ->
  294. gethostbyname_tm(Name, Family, false).
  295. -spec gethostbyname(Name :: hostname(),
  296. Family :: address_family(),
  297. Timeout :: non_neg_integer() | 'infinity') ->
  298. {'ok', #hostent{}} | {'error', posix()}.
  299. gethostbyname(Name,Family,Timeout) ->
  300. Timer = start_timer(Timeout),
  301. Res = gethostbyname_tm(Name,Family,Timer),
  302. stop_timer(Timer),
  303. Res.
  304. gethostbyname_tm(Name,Family,Timer) ->
  305. Opts0 = inet_db:res_option(lookup),
  306. Opts =
  307. case (lists:member(native, Opts0) orelse
  308. lists:member(string, Opts0) orelse
  309. lists:member(nostring, Opts0)) of
  310. true ->
  311. Opts0;
  312. false ->
  313. [string|Opts0]
  314. end,
  315. gethostbyname_tm(Name, Family, Timer, Opts).
  316. -spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when
  317. Address :: string() | ip_address(),
  318. Hostent :: hostent().
  319. gethostbyaddr(Address) ->
  320. gethostbyaddr_tm(Address, false).
  321. -spec gethostbyaddr(Address :: string() | ip_address(),
  322. Timeout :: non_neg_integer() | 'infinity') ->
  323. {'ok', #hostent{}} | {'error', posix()}.
  324. gethostbyaddr(Address,Timeout) ->
  325. Timer = start_timer(Timeout),
  326. Res = gethostbyaddr_tm(Address, Timer),
  327. stop_timer(Timer),
  328. Res.
  329. gethostbyaddr_tm(Address,Timer) ->
  330. gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)).
  331. -spec ip(Ip :: ip_address() | string() | atom()) ->
  332. {'ok', ip_address()} | {'error', posix()}.
  333. ip({A,B,C,D}) when ?ip(A,B,C,D) ->
  334. {ok, {A,B,C,D}};
  335. ip(Name) ->
  336. case gethostbyname(Name) of
  337. {ok, Ent} ->
  338. {ok, hd(Ent#hostent.h_addr_list)};
  339. Error -> Error
  340. end.
  341. %% This function returns the erlang port used (with inet_drv)
  342. -spec getll(Socket :: socket()) -> {'ok', socket()}.
  343. getll(Socket) when is_port(Socket) ->
  344. {ok, Socket}.
  345. %%
  346. %% Return the internal file descriptor number
  347. %%
  348. -spec getfd(Socket :: socket()) ->
  349. {'ok', non_neg_integer()} | {'error', posix()}.
  350. getfd(Socket) ->
  351. prim_inet:getfd(Socket).
  352. %%
  353. %% Lookup an ip address
  354. %%
  355. -spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when
  356. Host :: ip_address() | hostname(),
  357. Family :: address_family(),
  358. Address :: ip_address().
  359. getaddr(Address, Family) ->
  360. getaddr(Address, Family, infinity).
  361. -spec getaddr(Host :: ip_address() | hostname(),
  362. Family :: address_family(),
  363. Timeout :: non_neg_integer() | 'infinity') ->
  364. {'ok', ip_address()} | {'error', posix()}.
  365. getaddr(Address, Family, Timeout) ->
  366. Timer = start_timer(Timeout),
  367. Res = getaddr_tm(Address, Family, Timer),
  368. stop_timer(Timer),
  369. Res.
  370. getaddr_tm(Address, Family, Timer) ->
  371. case getaddrs_tm(Address, Family, Timer) of
  372. {ok, [IP|_]} -> {ok, IP};
  373. Error -> Error
  374. end.
  375. -spec getaddrs(Host, Family) ->
  376. {ok, Addresses} | {error, posix()} when
  377. Host :: ip_address() | hostname(),
  378. Family :: address_family(),
  379. Addresses :: [ip_address()].
  380. getaddrs(Address, Family) ->
  381. getaddrs(Address, Family, infinity).
  382. -spec getaddrs(Host :: ip_address() | string() | atom(),
  383. Family :: address_family(),
  384. Timeout :: non_neg_integer() | 'infinity') ->
  385. {'ok', [ip_address()]} | {'error', posix()}.
  386. getaddrs(Address, Family, Timeout) ->
  387. Timer = start_timer(Timeout),
  388. Res = getaddrs_tm(Address, Family, Timer),
  389. stop_timer(Timer),
  390. Res.
  391. -spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
  392. {'ok', string()} | {'error', posix()}.
  393. getservbyport(Port, Proto) ->
  394. case inet_udp:open(0, []) of
  395. {ok,U} ->
  396. Res = prim_inet:getservbyport(U, Port, Proto),
  397. inet_udp:close(U),
  398. Res;
  399. Error -> Error
  400. end.
  401. -spec getservbyname(Name :: atom() | string(),
  402. Protocol :: atom() | string()) ->
  403. {'ok', port_number()} | {'error', posix()}.
  404. getservbyname(Name, Protocol) when is_atom(Name) ->
  405. case inet_udp:open(0, []) of
  406. {ok,U} ->
  407. Res = prim_inet:getservbyname(U, Name, Protocol),
  408. inet_udp:close(U),
  409. Res;
  410. Error -> Error
  411. end.
  412. %% Return a list of available options
  413. options() ->
  414. [
  415. tos, priority, reuseaddr, keepalive, dontroute, linger,
  416. broadcast, sndbuf, recbuf, nodelay,
  417. buffer, header, active, packet, deliver, mode,
  418. multicast_if, multicast_ttl, multicast_loop,
  419. exit_on_close, high_watermark, low_watermark,
  420. bit8, send_timeout, send_timeout_close
  421. ].
  422. %% Return a list of statistics options
  423. -spec stats() -> [stat_option(),...].
  424. stats() ->
  425. [recv_oct, recv_cnt, recv_max, recv_avg, recv_dvi,
  426. send_oct, send_cnt, send_max, send_avg, send_pend].
  427. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  428. %% Available options for tcp:connect
  429. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  430. connect_options() ->
  431. [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
  432. header, active, packet, packet_size, buffer, mode, deliver,
  433. exit_on_close, high_watermark, low_watermark, bit8, send_timeout,
  434. send_timeout_close, delay_send,raw].
  435. connect_options(Opts, Family) ->
  436. BaseOpts =
  437. case application:get_env(kernel, inet_default_connect_options) of
  438. {ok,List} when is_list(List) ->
  439. NList = [{active, true} | lists:keydelete(active,1,List)],
  440. #connect_opts{ opts = NList};
  441. {ok,{active,_Bool}} ->
  442. #connect_opts{ opts = [{active,true}]};
  443. {ok,Option} ->
  444. #connect_opts{ opts = [{active,true}, Option]};
  445. _ ->
  446. #connect_opts{ opts = [{active,true}]}
  447. end,
  448. case con_opt(Opts, BaseOpts, connect_options()) of
  449. {ok, R} ->
  450. {ok, R#connect_opts {
  451. ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
  452. }};
  453. Error -> Error
  454. end.
  455. con_opt([{raw,A,B,C}|Opts],R,As) ->
  456. con_opt([{raw,{A,B,C}}|Opts],R,As);
  457. con_opt([Opt | Opts], R, As) ->
  458. case Opt of
  459. {ip,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
  460. {ifaddr,IP} -> con_opt(Opts, R#connect_opts { ifaddr = IP }, As);
  461. {port,P} -> con_opt(Opts, R#connect_opts { port = P }, As);
  462. {fd,Fd} -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
  463. binary -> con_add(mode, binary, R, Opts, As);
  464. list -> con_add(mode, list, R, Opts, As);
  465. {tcp_module,_} -> con_opt(Opts, R, As);
  466. inet -> con_opt(Opts, R, As);
  467. inet6 -> con_opt(Opts, R, As);
  468. {Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
  469. _ -> {error, badarg}
  470. end;
  471. con_opt([], R, _) ->
  472. {ok, R}.
  473. con_add(Name, Val, R, Opts, AllOpts) ->
  474. case add_opt(Name, Val, R#connect_opts.opts, AllOpts) of
  475. {ok, SOpts} ->
  476. con_opt(Opts, R#connect_opts { opts = SOpts }, AllOpts);
  477. Error -> Error
  478. end.
  479. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  480. %% Available options for tcp:listen
  481. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  482. listen_options() ->
  483. [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
  484. header, active, packet, buffer, mode, deliver, backlog,
  485. exit_on_close, high_watermark, low_watermark, bit8, send_timeout,
  486. send_timeout_close, delay_send, packet_size,raw].
  487. listen_options(Opts, Family) ->
  488. BaseOpts =
  489. case application:get_env(kernel, inet_default_listen_options) of
  490. {ok,List} when is_list(List) ->
  491. NList = [{active, true} | lists:keydelete(active,1,List)],
  492. #listen_opts{ opts = NList};
  493. {ok,{active,_Bool}} ->
  494. #listen_opts{ opts = [{active,true}]};
  495. {ok,Option} ->
  496. #listen_opts{ opts = [{active,true}, Option]};
  497. _ ->
  498. #listen_opts{ opts = [{active,true}]}
  499. end,
  500. case list_opt(Opts, BaseOpts, listen_options()) of
  501. {ok, R} ->
  502. {ok, R#listen_opts {
  503. ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
  504. }};
  505. Error -> Error
  506. end.
  507. list_opt([{raw,A,B,C}|Opts], R, As) ->
  508. list_opt([{raw,{A,B,C}}|Opts], R, As);
  509. list_opt([Opt | Opts], R, As) ->
  510. case Opt of
  511. {ip,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
  512. {ifaddr,IP} -> list_opt(Opts, R#listen_opts { ifaddr = IP }, As);
  513. {port,P} -> list_opt(Opts, R#listen_opts { port = P }, As);
  514. {fd,Fd} -> list_opt(Opts, R#listen_opts { fd = Fd }, As);
  515. {backlog,BL} -> list_opt(Opts, R#listen_opts { backlog = BL }, As);
  516. binary -> list_add(mode, binary, R, Opts, As);
  517. list -> list_add(mode, list, R, Opts, As);
  518. {tcp_module,_} -> list_opt(Opts, R, As);
  519. inet -> list_opt(Opts, R, As);
  520. inet6 -> list_opt(Opts, R, As);
  521. {Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
  522. _ -> {error, badarg}
  523. end;
  524. list_opt([], R, _SockOpts) ->
  525. {ok, R}.
  526. list_add(Name, Val, R, Opts, As) ->
  527. case add_opt(Name, Val, R#listen_opts.opts, As) of
  528. {ok, SOpts} ->
  529. list_opt(Opts, R#listen_opts { opts = SOpts }, As);
  530. Error -> Error
  531. end.
  532. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  533. %% Available options for udp:open
  534. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  535. udp_options() ->
  536. [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
  537. deliver,
  538. broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
  539. add_membership, drop_membership, read_packets,raw].
  540. udp_options(Opts, Family) ->
  541. case udp_opt(Opts, #udp_opts { }, udp_options()) of
  542. {ok, R} ->
  543. {ok, R#udp_opts {
  544. ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
  545. }};
  546. Error -> Error
  547. end.
  548. udp_opt([{raw,A,B,C}|Opts], R, As) ->
  549. udp_opt([{raw,{A,B,C}}|Opts], R, As);
  550. udp_opt([Opt | Opts], R, As) ->
  551. case Opt of
  552. {ip,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
  553. {ifaddr,IP} -> udp_opt(Opts, R#udp_opts { ifaddr = IP }, As);
  554. {port,P} -> udp_opt(Opts, R#udp_opts { port = P }, As);
  555. {fd,Fd} -> udp_opt(Opts, R#udp_opts { fd = Fd }, As);
  556. binary -> udp_add(mode, binary, R, Opts, As);
  557. list -> udp_add(mode, list, R, Opts, As);
  558. {udp_module,_} -> udp_opt(Opts, R, As);
  559. inet -> udp_opt(Opts, R, As);
  560. inet6 -> udp_opt(Opts, R, As);
  561. {Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
  562. _ -> {error, badarg}
  563. end;
  564. udp_opt([], R, _SockOpts) ->
  565. {ok, R}.
  566. udp_add(Name, Val, R, Opts, As) ->
  567. case add_opt(Name, Val, R#udp_opts.opts, As) of
  568. {ok, SOpts} ->
  569. udp_opt(Opts, R#udp_opts { opts = SOpts }, As);
  570. Error -> Error
  571. end.
  572. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  573. %% Available options for sctp:open
  574. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  575. % Currently supported options include:
  576. % (*) {mode, list|binary} or just list|binary
  577. % (*) {active, true|false|once}
  578. % (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6
  579. % (*) options set via setsockopt.
  580. % The full list is below in sctp_options/0 .
  581. % All other options are currently NOT supported. In particular:
  582. % (*) multicast on SCTP is not (yet) supported, as it may be incompatible
  583. % with automatic associations;
  584. % (*) passing of open FDs ("fdopen") is not supported.
  585. sctp_options() ->
  586. [ % The following are generic inet options supported for SCTP sockets:
  587. mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
  588. recbuf,
  589. % Other options are SCTP-specific (though they may be similar to their
  590. % TCP and UDP counter-parts):
  591. sctp_rtoinfo, sctp_associnfo, sctp_initmsg,
  592. sctp_autoclose, sctp_nodelay, sctp_disable_fragments,
  593. sctp_i_want_mapped_v4_addr, sctp_maxseg, sctp_primary_addr,
  594. sctp_set_peer_primary_addr, sctp_adaptation_layer, sctp_peer_addr_params,
  595. sctp_default_send_param, sctp_events, sctp_delayed_ack_time,
  596. sctp_status, sctp_get_peer_addr_info
  597. ].
  598. sctp_options(Opts, Mod) ->
  599. case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
  600. {ok,#sctp_opts{ifaddr=undefined}=SO} ->
  601. {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
  602. {ok,_}=OK ->
  603. OK;
  604. Error -> Error
  605. end.
  606. sctp_opt([Opt|Opts], Mod, R, As) ->
  607. case Opt of
  608. {ip,IP} ->
  609. sctp_opt_ifaddr(Opts, Mod, R, As, IP);
  610. {ifaddr,IP} ->
  611. sctp_opt_ifaddr(Opts, Mod, R, As, IP);
  612. {port,Port} ->
  613. case Mod:getserv(Port) of
  614. {ok,P} ->
  615. sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As);
  616. Error -> Error
  617. end;
  618. binary -> sctp_opt (Opts, Mod, R, As, mode, binary);
  619. list -> sctp_opt (Opts, Mod, R, As, mode, list);
  620. {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with
  621. inet -> sctp_opt (Opts, Mod, R, As); % Done with
  622. inet6 -> sctp_opt (Opts, Mod, R, As); % Done with
  623. {Name,Val} -> sctp_opt (Opts, Mod, R, As, Name, Val);
  624. _ -> {error,badarg}
  625. end;
  626. sctp_opt([], _Mod, R, _SockOpts) ->
  627. {ok, R}.
  628. sctp_opt(Opts, Mod, R, As, Name, Val) ->
  629. case add_opt(Name, Val, R#sctp_opts.opts, As) of
  630. {ok,SocketOpts} ->
  631. sctp_opt(Opts, Mod, R#sctp_opts{opts=SocketOpts}, As);
  632. Error -> Error
  633. end.
  634. sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
  635. IP = Mod:translate_ip(Addr),
  636. sctp_opt(Opts, Mod,
  637. R#sctp_opts{
  638. ifaddr=case IfAddr of
  639. undefined -> IP;
  640. _ when is_list(IfAddr) -> [IP|IfAddr];
  641. _ -> [IP,IfAddr]
  642. end}, As).
  643. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  644. %% Util to check and insert option in option list
  645. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  646. add_opt(Name, Val, Opts, As) ->
  647. case lists:member(Name, As) of
  648. true ->
  649. case prim_inet:is_sockopt_val(Name, Val) of
  650. true ->
  651. Opts1 = lists:keydelete(Name, 1, Opts),
  652. {ok, [{Name,Val} | Opts1]};
  653. false -> {error,badarg}
  654. end;
  655. false -> {error,badarg}
  656. end.
  657. translate_ip(any, inet) -> {0,0,0,0};
  658. translate_ip(loopback, inet) -> {127,0,0,1};
  659. translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0};
  660. translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
  661. translate_ip(IP, _) -> IP.
  662. getaddrs_tm({A,B,C,D} = IP, Fam, _) ->
  663. %% Only "syntactic" validation and check of family.
  664. if
  665. ?ip(A,B,C,D) ->
  666. if
  667. Fam =:= inet -> {ok,[IP]};
  668. true -> {error,eafnosupport}
  669. end;
  670. true -> {error,einval}
  671. end;
  672. getaddrs_tm({A,B,C,D,E,F,G,H} = IP, Fam, _) ->
  673. %% Only "syntactic" validation; we assume that the address was
  674. %% "semantically" validated when it was converted to a tuple.
  675. if
  676. ?ip6(A,B,C,D,E,F,G,H) ->
  677. if
  678. Fam =:= inet6 -> {ok,[IP]};
  679. true -> {error,eafnosupport}
  680. end;
  681. true -> {error,einval}
  682. end;
  683. getaddrs_tm(Address, Family, Timer) when is_atom(Address) ->
  684. getaddrs_tm(atom_to_list(Address), Family, Timer);
  685. getaddrs_tm(Address, Family, Timer) ->
  686. case inet_parse:visible_string(Address) of
  687. false ->
  688. {error,einval};
  689. true ->
  690. %% Address is a host name or a valid IP address,
  691. %% either way check it with the resolver.
  692. case gethostbyname_tm(Address, Family, Timer) of
  693. {ok,Ent} -> {ok,Ent#hostent.h_addr_list};
  694. Error -> Error
  695. end
  696. end.
  697. %%
  698. %% gethostbyname with option search
  699. %%
  700. gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
  701. Result = gethostbyname_string(Name, Type),
  702. gethostbyname_tm(Name, Type, Timer, Opts, Result);
  703. gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
  704. Result = inet_res:gethostbyname_tm(Name, Type, Timer),
  705. gethostbyname_tm(Name, Type, Timer, Opts, Result);
  706. gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
  707. Result = inet_hosts:gethostbyname(Name, Type),
  708. gethostbyname_tm(Name, Type, Timer, Opts, Result);
  709. gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
  710. gethostbyname_tm_native(Name, Type, Timer, Opts);
  711. gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
  712. gethostbyname_tm_native(Name, Type, Timer, Opts);
  713. gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
  714. gethostbyname_tm_native(Name, Type, Timer, Opts);
  715. gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
  716. gethostbyname_tm_native(Name, Type, Timer, Opts);
  717. gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
  718. gethostbyname_tm_native(Name, Type, Timer, Opts);
  719. gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) ->
  720. gethostbyname_tm(Name, Type, Timer, Opts);
  721. %% Make sure we always can look up our own hostname.
  722. gethostbyname_tm(Name, Type, Timer, []) ->
  723. Result = gethostbyname_self(Name, Type),
  724. gethostbyname_tm(Name, Type, Timer, [], Result).
  725. gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
  726. case Result of
  727. {ok,_} ->
  728. Result;
  729. {error,formerr} ->
  730. {error,einval};
  731. {error,_} when Opts =:= [] ->
  732. {error,nxdomain};
  733. {error,_} ->
  734. gethostbyname_tm(Name, Type, Timer, tl(Opts))
  735. end.
  736. gethostbyname_tm_native(Name, Type, Timer, Opts) ->
  737. %% Fixme: add (global) timeout to gethost_native
  738. Result = inet_gethost_native:gethostbyname(Name, Type),
  739. gethostbyname_tm(Name, Type, Timer, Opts, Result).
  740. gethostbyname_self(Name, Type) when is_atom(Name) ->
  741. gethostbyname_self(atom_to_list(Name), Type);
  742. gethostbyname_self(Name, Type)
  743. when is_list(Name), Type =:= inet;
  744. is_list(Name), Type =:= inet6 ->
  745. case inet_db:gethostname() of
  746. Name ->
  747. {ok,make_hostent(Name,
  748. [translate_ip(loopback, Type)],
  749. [], Type)};
  750. Self ->
  751. case inet_db:res_option(domain) of
  752. "" -> {error,nxdomain};
  753. Domain ->
  754. case lists:append([Self,".",Domain]) of
  755. Name ->
  756. {ok,make_hostent(Name,
  757. [translate_ip(loopback, Type)],
  758. [], Type)};
  759. _ -> {error,nxdomain}
  760. end
  761. end
  762. end;
  763. gethostbyname_self(_, _) ->
  764. {error,formerr}.
  765. gethostbyname_string(Name, Type) when is_atom(Name) ->
  766. gethostbyname_string(atom_to_list(Name), Type);
  767. gethostbyname_string(Name, Type)
  768. when is_list(Name), Type =:= inet;
  769. is_list(Name), Type =:= inet6 ->
  770. case
  771. case Type of
  772. inet ->
  773. inet_parse:ipv4_address(Name);
  774. inet6 ->
  775. %% XXX should we really translate IPv4 addresses here
  776. %% even if we do not know if this host can do IPv6?
  777. inet_parse:ipv6_address(Name)
  778. end of
  779. {ok,IP} ->
  780. {ok,make_hostent(Name, [IP], [], Type)};
  781. {error,einval} ->
  782. {error,nxdomain}
  783. end;
  784. gethostbyname_string(_, _) ->
  785. {error,formerr}.
  786. make_hostent(Name, Addrs, Aliases, Type) ->
  787. #hostent{h_name = Name,
  788. h_aliases = Aliases,
  789. h_addrtype = Type,
  790. h_length = case Type of inet -> 4; inet6 -> 16 end,
  791. h_addr_list = Addrs}.
  792. %%
  793. %% gethostbyaddr with option search
  794. %%
  795. gethostbyaddr_tm(Addr, Timer, [dns | Opts]) ->
  796. Res = inet_res:gethostbyaddr_tm(Addr,Timer),
  797. case Res of
  798. {ok,_} -> Res;
  799. {error,timeout} -> Res;
  800. {error,formerr} -> {error, einval};
  801. {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts)
  802. end;
  803. gethostbyaddr_tm(Addr, Timer, [file | Opts]) ->
  804. case inet_hosts:gethostbyaddr(Addr) of
  805. {error,formerr} -> {error, einval};
  806. {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
  807. Result -> Result
  808. end;
  809. gethostbyaddr_tm(Addr, Timer, [yp | Opts]) ->
  810. gethostbyaddr_tm_native(Addr, Timer, Opts);
  811. gethostbyaddr_tm(Addr, Timer, [nis | Opts]) ->
  812. gethostbyaddr_tm_native(Addr, Timer, Opts);
  813. gethostbyaddr_tm(Addr, Timer, [nisplus | Opts]) ->
  814. gethostbyaddr_tm_native(Addr, Timer, Opts);
  815. gethostbyaddr_tm(Addr, Timer, [wins | Opts]) ->
  816. gethostbyaddr_tm_native(Addr, Timer, Opts);
  817. gethostbyaddr_tm(Addr, Timer, [native | Opts]) ->
  818. gethostbyaddr_tm_native(Addr, Timer, Opts);
  819. gethostbyaddr_tm(Addr, Timer, [_ | Opts]) ->
  820. gethostbyaddr_tm(Addr, Timer, Opts);
  821. gethostbyaddr_tm({127,0,0,1}=IP, _Timer, []) ->
  822. gethostbyaddr_self(IP, inet);
  823. gethostbyaddr_tm({0,0,0,0,0,0,0,1}=IP, _Timer, []) ->
  824. gethostbyaddr_self(IP, inet6);
  825. gethostbyaddr_tm(_Addr, _Timer, []) ->
  826. {error, nxdomain}.
  827. gethostbyaddr_self(IP, Type) ->
  828. Name = inet_db:gethostname(),
  829. case inet_db:res_option(domain) of
  830. "" ->
  831. {ok,make_hostent(Name, [IP], [], Type)};
  832. Domain ->
  833. {ok,make_hostent(Name++"."++Domain, [IP], [Name], Type)}
  834. end.
  835. gethostbyaddr_tm_native(Addr, Timer, Opts) ->
  836. %% Fixme: user timer for timeoutvalue
  837. case inet_gethost_native:gethostbyaddr(Addr) of
  838. {error,formerr} -> {error, einval};
  839. {error,_} -> gethostbyaddr_tm(Addr,Timer,Opts);
  840. Result -> Result
  841. end.
  842. -spec open(Fd :: integer(),
  843. Addr :: ip_address(),
  844. Port :: port_number(),
  845. Opts :: [socket_setopt()],
  846. Protocol :: protocol_option(),
  847. Family :: 'inet' | 'inet6',
  848. Module :: atom()) ->
  849. {'ok', socket()} | {'error', posix()}.
  850. open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 ->
  851. case prim_inet:open(Protocol, Family) of
  852. {ok,S} ->
  853. case prim_inet:setopts(S, Opts) of
  854. ok ->
  855. case if is_list(Addr) ->
  856. prim_inet:bind(S, add,
  857. [case A of
  858. {_,_} -> A;
  859. _ -> {A,Port}
  860. end || A <- Addr]);
  861. true ->
  862. prim_inet:bind(S, Addr, Port)
  863. end of
  864. {ok, _} ->
  865. inet_db:register_socket(S, Module),
  866. {ok,S};
  867. Error ->
  868. prim_inet:close(S),
  869. Error
  870. end;
  871. Error ->
  872. prim_inet:close(S),
  873. Error
  874. end;
  875. Error ->
  876. Error
  877. end;
  878. open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) ->
  879. fdopen(Fd, Opts, Protocol, Family, Module).
  880. -spec fdopen(Fd :: non_neg_integer(),
  881. Opts :: [socket_setopt()],
  882. Protocol :: protocol_option(),
  883. Family :: address_family(),
  884. Module :: atom()) ->
  885. {'ok', socket()} | {'error', posix()}.
  886. fdopen(Fd, Opts, Protocol, Family, Module) ->
  887. case prim_inet:fdopen(Protocol, Fd, Family) of
  888. {ok, S} ->
  889. case prim_inet:setopts(S, Opts) of
  890. ok ->
  891. inet_db:register_socket(S, Module),
  892. {ok, S};
  893. Error ->
  894. prim_inet:close(S), Error
  895. end;
  896. Error -> Error
  897. end.
  898. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  899. %% socket stat
  900. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  901. i() -> i(tcp), i(udp).
  902. i(Proto) -> i(Proto, [port, module, recv, sent, owner,
  903. local_address, foreign_address, state]).
  904. i(tcp, Fs) ->
  905. ii(tcp_sockets(), Fs, tcp);
  906. i(udp, Fs) ->
  907. ii(udp_sockets(), Fs, udp).
  908. ii(Ss, Fs, Proto) ->
  909. LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)],
  910. Maxs = foldl(
  911. fun(Line,Max0) -> smax(Max0,Line) end,
  912. duplicate(length(Fs),0),LLs),
  913. Fmt = append(["~-" ++ integer_to_list(N) ++ "s " || N <- Maxs]) ++ "\n",
  914. lists:foreach(fun(Line) -> io:format(Fmt, Line) end, LLs).
  915. smax([Max|Ms], [Str|Strs]) ->
  916. N = length(Str),
  917. [if N > Max -> N; true -> Max end | smax(Ms, Strs)];
  918. smax([], []) -> [].
  919. info_lines(Ss, Fs, Proto) -> [i_line(S, Fs,Proto) || S <- Ss].
  920. i_line(S, Fs, Proto) -> [info(S, F, Proto) || F <- Fs].
  921. h_line(Fs) -> [h_field(atom_to_list(F)) || F <- Fs].
  922. h_field([C|Cs]) -> [upper(C) | hh_field(Cs)].
  923. hh_field([$_,C|Cs]) -> [$\s,upper(C) | hh_field(Cs)];
  924. hh_field([C|Cs]) -> [C|hh_field(Cs)];
  925. hh_field([]) -> [].
  926. upper(C) when C >= $a, C =< $z -> (C-$a) + $A;
  927. upper(C) -> C.
  928. info(S, F, Proto) ->
  929. case F of
  930. owner ->
  931. case erlang:port_info(S, connected) of
  932. {connected, Owner} -> pid_to_list(Owner);
  933. _ -> " "
  934. end;
  935. port ->
  936. case erlang:port_info(S,id) of
  937. {id, Id} -> integer_to_list(Id);
  938. undefined -> " "
  939. end;
  940. sent ->
  941. case prim_inet:getstat(S, [send_oct]) of
  942. {ok,[{send_oct,N}]} -> integer_to_list(N);
  943. _ -> " "
  944. end;
  945. recv ->
  946. case prim_inet:getstat(S, [recv_oct]) of
  947. {ok,[{recv_oct,N}]} -> integer_to_list(N);
  948. _ -> " "
  949. end;
  950. local_address ->
  951. fmt_addr(prim_inet:sockname(S), Proto);
  952. foreign_address ->
  953. fmt_addr(prim_inet:peername(S), Proto);
  954. state ->
  955. case prim_inet:getstatus(S) of
  956. {ok,Status} -> fmt_status(Status);
  957. _ -> " "
  958. end;
  959. packet ->
  960. case prim_inet:getopt(S, packet) of
  961. {ok,Type} when is_atom(Type) -> atom_to_list(Type);
  962. {ok,Type} when is_integer(Type) -> integer_to_list(Type);
  963. _ -> " "
  964. end;
  965. type ->
  966. case prim_inet:gettype(S) of
  967. {ok,{_,stream}} -> "STREAM";
  968. {ok,{_,dgram}} -> "DGRAM";
  969. _ -> " "
  970. end;
  971. fd ->
  972. case prim_inet:getfd(S) of
  973. {ok, Fd} -> integer_to_list(Fd);
  974. _ -> " "
  975. end;
  976. module ->
  977. case inet_db:lookup_socket(S) of
  978. {ok,Mod} -> atom_to_list(Mod);
  979. _ -> "prim_inet"
  980. end
  981. end.
  982. %% Possible flags: (sorted)
  983. %% [accepting,bound,busy,connected,connecting,listen,listening,open]
  984. %%
  985. fmt_status(Flags) ->
  986. case lists:sort(Flags) of
  987. [accepting | _] -> "ACCEPTING";
  988. [bound,busy,connected|_] -> "CONNECTED*";
  989. [bound,connected|_] -> "CONNECTED";
  990. [bound,listen,listening | _] -> "LISTENING";
  991. [bound,listen | _] -> "LISTEN";
  992. [bound,connecting | _] -> "CONNECTING";
  993. [bound,open] -> "BOUND";
  994. [open] -> "IDLE";
  995. [] -> "CLOSED";
  996. _ -> "????"
  997. end.
  998. fmt_addr({error,enotconn}, _) -> "*:*";
  999. fmt_addr({error,_}, _) -> " ";
  1000. fmt_addr({ok,Addr}, Proto) ->
  1001. case Addr of
  1002. %%Dialyzer {0,0} -> "*:*";
  1003. {{0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
  1004. {{0,0,0,0,0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto);
  1005. {{127,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
  1006. {{0,0,0,0,0,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto);
  1007. {IP,Port} -> inet_parse:ntoa(IP) ++ ":" ++ fmt_port(Port, Proto)
  1008. end.
  1009. fmt_port(N, Proto) ->
  1010. case inet:getservbyport(N, Proto) of
  1011. {ok, Name} -> Name;
  1012. _ -> integer_to_list(N)
  1013. end.
  1014. %% Return a list of all tcp sockets
  1015. tcp_sockets() -> port_list("tcp_inet").
  1016. udp_sockets() -> port_list("udp_inet").
  1017. %% Return all ports having the name 'Name'
  1018. port_list(Name) ->
  1019. filter(
  1020. fun(Port) ->
  1021. case erlang:port_info(Port, name) of
  1022. {name, Name} -> true;
  1023. _ -> false
  1024. end
  1025. end, erlang:ports()).
  1026. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1027. %% utils
  1028. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1029. -spec format_error(Posix) -> string() when
  1030. Posix :: posix().
  1031. format_error(exbadport) -> "invalid port state";
  1032. format_error(exbadseq) -> "bad command sequence";
  1033. format_error(Tag) ->
  1034. erl_posix_msg:message(Tag).
  1035. %% Close a TCP socket.
  1036. tcp_close(S) when is_port(S) ->
  1037. %% if exit_on_close is set we must force a close even if remotely closed!!!
  1038. prim_inet:close(S),
  1039. receive {tcp_closed, S} -> ok after 0 -> ok end.
  1040. %% Close a UDP socket.
  1041. udp_close(S) when is_port(S) ->
  1042. receive
  1043. {udp_closed, S} -> ok
  1044. after 0 ->
  1045. prim_inet:close(S),
  1046. receive {udp_closed, S} -> ok after 0 -> ok end
  1047. end.
  1048. %% Set controlling process for TCP socket.
  1049. tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
  1050. case erlang:port_info(S, connected) of
  1051. {connected, Pid} when Pid =/= self() ->
  1052. {error, not_owner};
  1053. undefined ->
  1054. {error, einval};
  1055. _ ->
  1056. case prim_inet:getopt(S, active) of
  1057. {ok, A0} ->
  1058. prim_inet:setopt(S, active, false),
  1059. case tcp_sync_input(S, NewOwner, false) of
  1060. true -> %% socket already closed,
  1061. ok;
  1062. false ->
  1063. try erlang:port_connect(S, NewOwner) of
  1064. true ->
  1065. unlink(S), %% unlink from port
  1066. prim_inet:setopt(S, active, A0),
  1067. ok
  1068. catch
  1069. error:Reason ->
  1070. {error, Reason}
  1071. end
  1072. end;
  1073. Error ->
  1074. Error
  1075. end
  1076. end.
  1077. tcp_sync_input(S, Owner, Flag) ->
  1078. receive
  1079. {tcp, S, Data} ->
  1080. Owner ! {tcp, S, Data},
  1081. tcp_sync_input(S, Owner, Flag);
  1082. {tcp_closed, S} ->
  1083. Owner ! {tcp_closed, S},
  1084. tcp_sync_input(S, Owner, true);
  1085. {S, {data, Data}} ->
  1086. Owner ! {S, {data, Data}},
  1087. tcp_sync_input(S, Owner, Flag);
  1088. {inet_async, S, Ref, Status} ->
  1089. Owner ! {inet_async, S, Ref, Status},
  1090. tcp_sync_input(S, Owner, Flag);
  1091. {inet_reply, S, Status} ->
  1092. Owner ! {inet_reply, S, Status},
  1093. tcp_sync_input(S, Owner, Flag)
  1094. after 0 ->
  1095. Flag
  1096. end.
  1097. %% Set controlling process for UDP or SCTP socket.
  1098. udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
  1099. case erlang:port_info(S, connected) of
  1100. {connected, Pid} when Pid =/= self() ->
  1101. {error, not_owner};
  1102. _ ->
  1103. {ok, A0} = prim_inet:getopt(S, active),
  1104. prim_inet:setopt(S, active, false),
  1105. udp_sync_input(S, NewOwner),
  1106. try erlang:port_connect(S, NewOwner) of
  1107. true ->
  1108. unlink(S),
  1109. prim_inet:setopt(S, active, A0),
  1110. ok
  1111. catch
  1112. error:Reason ->
  1113. {error, Reason}
  1114. end
  1115. end.
  1116. udp_sync_input(S, Owner) ->
  1117. receive
  1118. {sctp, S, _, _, _}=Msg -> udp_sync_input(S, Owner, Msg);
  1119. {udp, S, _, _, _}=Msg -> udp_sync_input(S, Owner, Msg);
  1120. {udp_closed, S}=Msg -> udp_sync_input(S, Owner, Msg);
  1121. {S, {data,_}}=Msg -> udp_sync_input(S, Owner, Msg);
  1122. {inet_async, S, _, _}=Msg -> udp_sync_input(S, Owner, Msg);
  1123. {inet_reply, S, _}=Msg -> udp_sync_input(S, Owner, Msg)
  1124. after 0 ->
  1125. ok
  1126. end.
  1127. udp_sync_input(S, Owner, Msg) ->
  1128. Owner ! Msg,
  1129. udp_sync_input(S, Owner).
  1130. start_timer(infinity) -> false;
  1131. start_timer(Timeout) ->
  1132. erlang:start_timer(Timeout, self(), inet).
  1133. timeout(false) -> infinity;
  1134. timeout(Timer) ->
  1135. case erlang:read_timer(Timer) of
  1136. false -> 0;
  1137. Time -> Time
  1138. end.
  1139. timeout(Time, false) -> Time;
  1140. timeout(Time, Timer) ->
  1141. TimerTime = timeout(Timer),
  1142. if TimerTime < Time -> TimerTime;
  1143. true -> Time
  1144. end.
  1145. stop_timer(false) -> false;
  1146. stop_timer(Timer) ->
  1147. case erlang:cancel_timer(Timer) of
  1148. false ->
  1149. receive
  1150. {timeout,Timer,_} -> false
  1151. after 0 ->
  1152. false
  1153. end;
  1154. T -> T
  1155. end.