/lib/kernel/src/inet.erl

https://github.com/system/erlang-otp · Erlang · 1352 lines · 1063 code · 172 blank · 117 comment · 6 complexity · 3919aabc301093e0197db4a88afba62f MD5 · raw file

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