PageRenderTime 34ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/preloaded/src/prim_inet.erl

https://github.com/bsmr-erlang/otp
Erlang | 2706 lines | 1880 code | 247 blank | 579 comment | 11 complexity | 39f297b743d9da24d2c77a35d48aa809 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. %%
  2. %% %CopyrightBegin%
  3. %%
  4. %% Copyright Ericsson AB 2000-2019. 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. %% The SCTP protocol was added 2006
  21. %% by Leonid Timochouk <l.timochouk@gmail.com>
  22. %% and Serge Aleynikov <saleyn@gmail.com>
  23. %% at IDT Corp. Adapted by the OTP team at Ericsson AB.
  24. %%
  25. -module(prim_inet).
  26. %% Primitive inet_drv interface
  27. -export([open/3, open/4, fdopen/4, fdopen/5, close/1]).
  28. -export([bind/3, listen/1, listen/2, peeloff/2]).
  29. -export([connect/3, connect/4, async_connect/4]).
  30. -export([accept/1, accept/2, accept/3, async_accept/2]).
  31. -export([shutdown/2]).
  32. -export([send/2, send/3, sendto/4, sendmsg/3, sendfile/4]).
  33. -export([recv/2, recv/3, async_recv/3]).
  34. -export([unrecv/2]).
  35. -export([recvfrom/2, recvfrom/3]).
  36. -export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]).
  37. -export([chgopt/3, chgopts/2]).
  38. -export([getstat/2, getfd/1, ignorefd/2,
  39. getindex/1, getstatus/1, gettype/1,
  40. getifaddrs/1, getiflist/1, ifget/3, ifset/3,
  41. gethostname/1]).
  42. -export([getservbyname/3, getservbyport/3]).
  43. -export([peername/1, setpeername/2, peernames/1, peernames/2]).
  44. -export([sockname/1, setsockname/2, socknames/1, socknames/2]).
  45. -export([attach/1, detach/1]).
  46. -include("inet_sctp.hrl").
  47. -include("inet_int.hrl").
  48. %%%-define(DEBUG, 1).
  49. -ifdef(DEBUG).
  50. -define(
  51. DBG_FORMAT(Format, Args),
  52. begin
  53. %% io:format((Format), (Args)),
  54. erlang:display(lists:flatten(io_lib:format((Format), (Args)))),
  55. ok
  56. end).
  57. -else.
  58. -define(DBG_FORMAT(Format, Args), ok).
  59. -endif.
  60. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  61. %%
  62. %% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket) ->
  63. %% {ok, insock()} |
  64. %% {error, Reason}
  65. %%
  66. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  67. open(Protocol, Family, Type) ->
  68. open(Protocol, Family, Type, [], ?INET_REQ_OPEN, []).
  69. open(Protocol, Family, Type, Opts) ->
  70. open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []).
  71. %% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer())
  72. fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
  73. fdopen(Protocol, Family, Type, Fd, true).
  74. fdopen(Protocol, Family, Type, Fd, Bound)
  75. when is_integer(Fd), is_boolean(Bound) ->
  76. open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN,
  77. [?int32(Fd), enc_value_2(bool, Bound)]).
  78. open(Protocol, Family, Type, Opts, Req, Data) ->
  79. Drv = protocol2drv(Protocol),
  80. AF = enc_family(Family),
  81. T = enc_type(Type),
  82. try erlang:open_port({spawn_driver,Drv}, [binary]) of
  83. S ->
  84. case setopts(S, Opts) of
  85. ok ->
  86. case ctl_cmd(S, Req, [AF,T,Data]) of
  87. {ok,_} -> {ok,S};
  88. {error,_}=E1 ->
  89. close(S),
  90. E1
  91. end;
  92. {error,_}=E2 ->
  93. close(S),
  94. E2
  95. end
  96. catch
  97. %% The only (?) way to get here is to try to open
  98. %% the sctp driver when it does not exist (badarg)
  99. error:badarg -> {error, eprotonosupport};
  100. %% system_limit if out of port slots
  101. error:system_limit -> {error, system_limit}
  102. end.
  103. enc_family(inet) -> ?INET_AF_INET;
  104. enc_family(inet6) -> ?INET_AF_INET6;
  105. enc_family(local) -> ?INET_AF_LOCAL.
  106. enc_type(stream) -> ?INET_TYPE_STREAM;
  107. enc_type(dgram) -> ?INET_TYPE_DGRAM;
  108. enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET.
  109. protocol2drv(tcp) -> "tcp_inet";
  110. protocol2drv(udp) -> "udp_inet";
  111. protocol2drv(sctp) -> "sctp_inet".
  112. drv2protocol("tcp_inet") -> tcp;
  113. drv2protocol("udp_inet") -> udp;
  114. drv2protocol("sctp_inet") -> sctp;
  115. drv2protocol(_) -> undefined.
  116. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  117. %%
  118. %% Shutdown(insock(), atom()) -> ok
  119. %%
  120. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  121. %% TODO: shutdown equivalent for SCTP
  122. %%
  123. shutdown(S, read) when is_port(S) ->
  124. shutdown_1(S, 0);
  125. shutdown(S, write) when is_port(S) ->
  126. shutdown_1(S, 1);
  127. shutdown(S, read_write) when is_port(S) ->
  128. shutdown_1(S, 2).
  129. shutdown_1(S, How) ->
  130. case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of
  131. {ok, []} -> ok;
  132. {error,_}=Error -> Error
  133. end.
  134. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  135. %%
  136. %% CLOSE(insock()) -> ok
  137. %%
  138. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  139. close(S) when is_port(S) ->
  140. ?DBG_FORMAT("prim_inet:close(~p)~n", [S]),
  141. case getopt(S, linger) of
  142. {ok,{true,0}} ->
  143. close_port(S);
  144. {ok,{true,T}} ->
  145. %% Wait for T seconds for pending output to be sent
  146. %%
  147. %% Note that this handling of Linger may look ok,
  148. %% but sweeps some problems under the rug since
  149. %% there are OS buffers that may have remaining data
  150. %% after the inet driver has emptied its buffers.
  151. %% But Linger for nonblocking sockets is broken
  152. %% anyway on all OS:es, according to hearsay,
  153. %% and is a contradiction in itself.
  154. %% We have hereby done our best...
  155. %%
  156. case subscribe(S, [subs_empty_out_q]) of
  157. {ok, [{subs_empty_out_q,0}]} ->
  158. close_port(S);
  159. {ok, [{subs_empty_out_q,N}]} when N > 0 ->
  160. %% Wait for pending output to be sent
  161. Tref = erlang:start_timer(T * 1000, self(), close_port),
  162. close_pend_loop(S, Tref, N);
  163. _ ->
  164. %% Subscribe failed - wait full time
  165. Tref = erlang:start_timer(T * 1000, self(), close_port),
  166. close_pend_loop(S, Tref, undefined)
  167. end;
  168. _ -> % Regard this as {ok,{false,_}}
  169. case subscribe(S, [subs_empty_out_q]) of
  170. {ok, [{subs_empty_out_q,N}]} when N > 0 ->
  171. %% Wait for pending output to be sent
  172. DefaultT = 180000, % Arbitrary system timeout 3 min
  173. Tref = erlang:start_timer(DefaultT, self(), close_port),
  174. close_pend_loop(S, Tref, N);
  175. _ ->
  176. %% Subscribe failed or empty out q - give up or done
  177. close_port(S)
  178. end
  179. end.
  180. close_pend_loop(S, Tref, N) ->
  181. ?DBG_FORMAT("prim_inet:close_pend_loop(~p, _, ~p)~n", [S,N]),
  182. receive
  183. {timeout,Tref,_} -> % Linger timeout
  184. ?DBG_FORMAT("prim_inet:close_pend_loop(~p, _, _) timeout~n", [S]),
  185. close_port(S);
  186. {empty_out_q,S} when N =/= undefined ->
  187. ?DBG_FORMAT(
  188. "prim_inet:close_pend_loop(~p, _, _) empty_out_q~n", [S]),
  189. close_port(S, Tref)
  190. after ?INET_CLOSE_TIMEOUT ->
  191. case getstat(S, [send_pend]) of
  192. {ok, [{send_pend,N1}]} ->
  193. ?DBG_FORMAT(
  194. "prim_inet:close_pend_loop(~p, _, _) send_pend ~p~n",
  195. [S,N1]),
  196. if
  197. N1 =:= 0 ->
  198. %% Empty outq - done
  199. close_port(S, Tref);
  200. N =:= undefined ->
  201. %% Within linger time - wait some more
  202. close_pend_loop(S, Tref, N);
  203. N1 =:= N ->
  204. %% Inactivity - give up
  205. close_port(S, Tref);
  206. true ->
  207. %% Still moving - wait some more
  208. close_pend_loop(S, Tref, N)
  209. end;
  210. _Stat ->
  211. %% Failed getstat - give up
  212. ?DBG_FORMAT(
  213. "prim_inet:close_pend_loop(~p, _, _) getstat ~p~n",
  214. [S,_Stat]),
  215. close_port(S, Tref)
  216. end
  217. end.
  218. close_port(S, Tref) ->
  219. ?DBG_FORMAT("prim_inet:close_port(~p, _)~n", [S]),
  220. case erlang:cancel_timer(Tref) of
  221. false ->
  222. receive
  223. {timeout,Tref,_} ->
  224. ok
  225. end;
  226. _N ->
  227. ok
  228. end,
  229. close_port(S).
  230. %%
  231. close_port(S) ->
  232. ?DBG_FORMAT("prim_inet:close_port(~p)~n", [S]),
  233. _Closed = (catch erlang:port_close(S)),
  234. receive {'EXIT',S,_} -> ok after 0 -> ok end,
  235. ?DBG_FORMAT("prim_inet:close_port(~p) ~p~n", [S,_Closed]),
  236. ok.
  237. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  238. %%
  239. %% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}
  240. %%
  241. %% bind the insock() to the interface address given by IP and Port
  242. %%
  243. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  244. %% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
  245. %% If no addrs are specified, it just does nothing.
  246. %% Function returns {ok, S} on success, unlike TCP/UDP "bind":
  247. bind(S, add, Addrs) when is_port(S), is_list(Addrs) ->
  248. bindx(S, 1, Addrs);
  249. bind(S, remove, Addrs) when is_port(S), is_list(Addrs) ->
  250. bindx(S, 0, Addrs);
  251. bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 ->
  252. case type_value(set, addr, Addr) of
  253. true ->
  254. case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of
  255. {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
  256. {error, _} = Error -> Error
  257. end;
  258. false ->
  259. {error, einval}
  260. end;
  261. bind(S, IP, Port) ->
  262. bind(S, {IP, Port}, 0).
  263. bindx(S, AddFlag, Addrs) ->
  264. case getprotocol(S) of
  265. sctp ->
  266. case bindx_check_addrs(Addrs) of
  267. true ->
  268. %% Really multi-homed "bindx". Stringified args:
  269. %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
  270. Args =
  271. [?int8(AddFlag)|
  272. [enc_value(set, addr, Addr) || Addr <- Addrs]],
  273. case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
  274. {ok, _} -> {ok, S};
  275. {error, _}=Error -> Error
  276. end;
  277. false ->
  278. {error, einval}
  279. end;
  280. _ ->
  281. {error, einval}
  282. end.
  283. bindx_check_addrs([Addr|Addrs]) ->
  284. type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs);
  285. bindx_check_addrs([]) ->
  286. true.
  287. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  288. %%
  289. %% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason}
  290. %%
  291. %% connect the insock() to the address given by IP and Port
  292. %% if timeout is given:
  293. %% timeout < 0 -> infinity
  294. %% 0 -> immediate connect (mostly works for loopback)
  295. %% > 0 -> wait for timeout ms if not connected then
  296. %% return {error, timeout}
  297. %%
  298. %% ASYNC_CONNECT(insock(), IP, Port, Timeout) -> {ok, S, Ref} | {error, Reason}
  299. %%
  300. %% a {inet_async,S,Ref,Status} will be sent on socket condition
  301. %%
  302. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  303. %% For TCP, UDP or SCTP sockets.
  304. %%
  305. connect(S, IP, Port) ->
  306. connect(S, IP, Port, infinity).
  307. %%
  308. connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
  309. case type_value(set, addr, Addr) of
  310. true when Time =:= infinity ->
  311. connect0(S, Addr, -1);
  312. true when is_integer(Time) ->
  313. connect0(S, Addr, Time);
  314. false ->
  315. {error, einval}
  316. end;
  317. connect(S, IP, Port, Time) ->
  318. connect(S, {IP, Port}, 0, Time).
  319. connect0(S, Addr, Time) ->
  320. case async_connect0(S, Addr, Time) of
  321. {ok, S, Ref} ->
  322. receive
  323. {inet_async, S, Ref, Status} ->
  324. Status
  325. end;
  326. Error -> Error
  327. end.
  328. async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
  329. case type_value(set, addr, Addr) of
  330. true when Time =:= infinity ->
  331. async_connect0(S, Addr, -1);
  332. true when is_integer(Time) ->
  333. async_connect0(S, Addr, Time);
  334. false ->
  335. {error, einval}
  336. end;
  337. %%
  338. async_connect(S, IP, Port, Time) ->
  339. async_connect(S, {IP, Port}, 0, Time).
  340. async_connect0(S, Addr, Time) ->
  341. case ctl_cmd(
  342. S, ?INET_REQ_CONNECT,
  343. [enc_time(Time),enc_value(set, addr, Addr)])
  344. of
  345. {ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
  346. {error, _}=Error -> Error
  347. end.
  348. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  349. %%
  350. %% ACCEPT(insock() [,Timeout][,FamilyOpts] ) -> {ok,insock()} | {error, Reason}
  351. %%
  352. %% accept incoming connection on listen socket
  353. %% if timeout is given:
  354. %% timeout < 0 -> infinity
  355. %% 0 -> immediate accept (poll)
  356. %% > 0 -> wait for timeout ms for accept if no accept then
  357. %% return {error, timeout}
  358. %% FamilyOpts are address family specific options to copy from
  359. %% listen socket to accepted socket
  360. %%
  361. %% ASYNC_ACCEPT(insock(), Timeout)
  362. %%
  363. %% async accept. return {ok,S,Ref} or {error, Reason}
  364. %% the owner of socket S will receive an {inet_async,S,Ref,Status} on
  365. %% socket condition
  366. %%
  367. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  368. %% For TCP sockets only.
  369. %%
  370. accept(L) -> accept0(L, -1, []).
  371. accept(L, infinity) -> accept0(L, -1, []);
  372. accept(L, FamilyOpts) when is_list(FamilyOpts) -> accept0(L, -1, FamilyOpts);
  373. accept(L, Time) -> accept0(L, Time, []).
  374. accept(L, infinity, FamilyOpts) -> accept0(L, -1, FamilyOpts);
  375. accept(L, Time, FamilyOpts) -> accept0(L, Time, FamilyOpts).
  376. accept0(L, Time, FamilyOpts)
  377. when is_port(L), is_integer(Time), is_list(FamilyOpts) ->
  378. case async_accept(L, Time) of
  379. {ok, Ref} ->
  380. receive
  381. {inet_async, L, Ref, {ok,S}} ->
  382. accept_opts(L, S, FamilyOpts);
  383. {inet_async, L, Ref, Error} ->
  384. Error
  385. end;
  386. Error -> Error
  387. end.
  388. %% setup options from listen socket on the connected socket
  389. accept_opts(L, S, FamilyOpts) ->
  390. case
  391. getopts(
  392. L,
  393. [active, nodelay, keepalive, delay_send, priority]
  394. ++ FamilyOpts)
  395. of
  396. {ok, Opts} ->
  397. case setopts(S, Opts) of
  398. ok ->
  399. {ok, S};
  400. Error1 ->
  401. close(S), Error1
  402. end;
  403. Error2 ->
  404. close(S), Error2
  405. end.
  406. async_accept(L, Time) ->
  407. case ctl_cmd(L,?INET_REQ_ACCEPT, [enc_time(Time)]) of
  408. {ok, [R1,R0]} -> {ok, ?u16(R1,R0)};
  409. {error,_}=Error -> Error
  410. end.
  411. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  412. %%
  413. %% LISTEN(insock() [,Backlog]) -> ok | {error, Reason}
  414. %%
  415. %% set listen mode on socket
  416. %%
  417. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  418. %% For TCP or SCTP sockets. For SCTP, Boolean backlog value (enable/disable
  419. %% listening) is also accepted:
  420. listen(S) -> listen(S, ?LISTEN_BACKLOG).
  421. listen(S, true) -> listen(S, ?LISTEN_BACKLOG);
  422. listen(S, false) -> listen(S, 0);
  423. listen(S, BackLog) when is_port(S), is_integer(BackLog) ->
  424. case ctl_cmd(S, ?INET_REQ_LISTEN, [?int16(BackLog)]) of
  425. {ok, _} -> ok;
  426. {error,_}=Error -> Error
  427. end.
  428. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  429. %%
  430. %% PEELOFF(insock(), AssocId) -> {ok,outsock()} | {error, Reason}
  431. %%
  432. %% SCTP: Peel off one association into a type stream socket
  433. %%
  434. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  435. peeloff(S, AssocId) ->
  436. case ctl_cmd(S, ?SCTP_REQ_PEELOFF, [?int32(AssocId)]) of
  437. inet_reply ->
  438. receive
  439. {inet_reply,S,Res} -> Res
  440. end;
  441. {error,_}=Error -> Error
  442. end.
  443. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  444. %%
  445. %% SEND(insock(), Data) -> ok | {error, Reason}
  446. %%
  447. %% send Data on the socket (io-list)
  448. %%
  449. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  450. %% This is a generic "port_command" interface used by TCP, UDP, SCTP, depending
  451. %% on the driver it is mapped to, and the "Data". It actually sends out data,--
  452. %% NOT delegating this task to any back-end. For SCTP, this function MUST NOT
  453. %% be called directly -- use "sendmsg" instead:
  454. %%
  455. send(S, Data, OptList) when is_port(S), is_list(OptList) ->
  456. ?DBG_FORMAT("prim_inet:send(~p, _, ~p)~n", [S,OptList]),
  457. try erlang:port_command(S, Data, OptList) of
  458. false -> % Port busy and nosuspend option passed
  459. ?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
  460. {error,busy};
  461. true ->
  462. send_recv_reply(S, undefined)
  463. catch
  464. error:_Error ->
  465. ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
  466. {error,einval}
  467. end.
  468. send_recv_reply(S, Mref) ->
  469. ReplyTimeout =
  470. case Mref of
  471. undefined ->
  472. ?INET_CLOSE_TIMEOUT;
  473. _ ->
  474. infinity
  475. end,
  476. receive
  477. {inet_reply,S,Status} ->
  478. ?DBG_FORMAT(
  479. "prim_inet:send_recv_reply(~p, _): inet_reply ~p~n",
  480. [S,Status]),
  481. case Mref of
  482. undefined -> ok;
  483. _ ->
  484. demonitor(Mref, [flush]),
  485. ok
  486. end,
  487. Status;
  488. {'DOWN',Mref,_,_,_Reason} when Mref =/= undefined ->
  489. ?DBG_FORMAT(
  490. "prim_inet:send_recv_reply(~p, _) 'DOWN' ~p~n",
  491. [S,_Reason]),
  492. {error,closed}
  493. after ReplyTimeout ->
  494. send_recv_reply(S, monitor(port, S))
  495. end.
  496. send(S, Data) ->
  497. send(S, Data, []).
  498. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  499. %%
  500. %% SENDTO(insock(), IP, Port, Data) -> ok | {error, Reason}
  501. %%
  502. %% send Datagram to the IP at port (Should add sync send!)
  503. %%
  504. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  505. %% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
  506. %% is known to be connected.
  507. sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
  508. case type_value(set, addr, Addr) of
  509. true ->
  510. ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
  511. try
  512. erlang:port_command(S, [enc_value(set, addr, Addr),Data])
  513. of
  514. true ->
  515. receive
  516. {inet_reply,S,Reply} ->
  517. ?DBG_FORMAT(
  518. "prim_inet:sendto() -> ~p~n", [Reply]),
  519. Reply
  520. end
  521. catch
  522. error:_ ->
  523. ?DBG_FORMAT(
  524. "prim_inet:sendto() -> {error,einval}~n", []),
  525. {error,einval}
  526. end;
  527. false ->
  528. ?DBG_FORMAT(
  529. "prim_inet:sendto() -> {error,einval}~n", []),
  530. {error,einval}
  531. end;
  532. sendto(S, IP, Port, Data) ->
  533. sendto(S, {IP, Port}, 0, Data).
  534. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  535. %%
  536. %% SENDMSG(insock(), IP, Port, InitMsg, Data) or
  537. %% SENDMSG(insock(), SndRcvInfo, Data) -> ok | {error, Reason}
  538. %%
  539. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  540. %% SCTP: Sending data over an existing association: no need for a destination
  541. %% addr; uses SndRcvInfo:
  542. %%
  543. sendmsg(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) ->
  544. Type = type_opt(set, sctp_default_send_param),
  545. try type_value(set, Type, SRI) of
  546. true ->
  547. send(S, [enc_value(set, Type, SRI)|Data]);
  548. false -> {error,einval}
  549. catch
  550. Reason -> {error,Reason}
  551. end.
  552. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  553. %%
  554. %% SENDFILE(outsock(), Fd, Offset, Length) -> {ok,BytesSent} | {error, Reason}
  555. %%
  556. %% send Length data bytes from a file handle, to a socket, starting at Offset
  557. %%
  558. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  559. %% "sendfile" is for TCP:
  560. sendfile(S, FileHandle, Offset, Length)
  561. when not is_port(S);
  562. not is_binary(FileHandle);
  563. not is_integer(Offset);
  564. not is_integer(Length) ->
  565. {error, badarg};
  566. sendfile(S, FileHandle, Offset, Length) ->
  567. case erlang:port_info(S, connected) of
  568. {connected, Pid} when Pid =:= self() ->
  569. Uncork = sendfile_maybe_cork(S),
  570. Result = sendfile_1(S, FileHandle, Offset, Length),
  571. sendfile_maybe_uncork(S, Uncork),
  572. Result;
  573. {connected, Pid} when Pid =/= self() ->
  574. {error, not_owner};
  575. _Other ->
  576. {error, einval}
  577. end.
  578. sendfile_maybe_cork(S) ->
  579. case getprotocol(S) of
  580. tcp ->
  581. case getopts(S, [nopush]) of
  582. {ok, [{nopush,false}]} ->
  583. _ = setopts(S, [{nopush,true}]),
  584. true;
  585. _ ->
  586. false
  587. end;
  588. _ -> false
  589. end.
  590. sendfile_maybe_uncork(S, true) ->
  591. _ = setopts(S, [{nopush,false}]),
  592. ok;
  593. sendfile_maybe_uncork(_, false) ->
  594. ok.
  595. sendfile_1(S, FileHandle, Offset, 0) ->
  596. sendfile_1(S, FileHandle, Offset, (1 bsl 63) - 1);
  597. sendfile_1(_S, _FileHandle, Offset, Length) when
  598. Offset < 0; Offset > ((1 bsl 63) - 1);
  599. Length < 0; Length > ((1 bsl 63) - 1) ->
  600. {error, einval};
  601. sendfile_1(S, FileHandle, Offset, Length) ->
  602. Args = [FileHandle,
  603. ?int64(Offset),
  604. ?int64(Length)],
  605. case ctl_cmd(S, ?TCP_REQ_SENDFILE, Args) of
  606. {ok, []} ->
  607. receive
  608. {sendfile, S, {ok, SentLow, SentHigh}} ->
  609. {ok, SentLow bor (SentHigh bsl 32)};
  610. {sendfile, S, {error, Reason}} ->
  611. {error, Reason};
  612. {'EXIT', S, _Reason} ->
  613. {error, closed}
  614. end;
  615. {error, Reason} ->
  616. {error, Reason}
  617. end.
  618. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  619. %%
  620. %% RECV(insock(), Length, [Timeout]) -> {ok,Data} | {error, Reason}
  621. %%
  622. %% receive Length data bytes from a socket
  623. %% if 0 is given then a Data packet is requested (see setopt (packet))
  624. %% N read N bytes
  625. %%
  626. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  627. %% "recv" is for TCP:
  628. recv(S, Length) -> recv0(S, Length, -1).
  629. recv(S, Length, infinity) -> recv0(S, Length,-1);
  630. recv(S, Length, Time) when is_integer(Time) -> recv0(S, Length, Time).
  631. recv0(S, Length, Time) when is_port(S), is_integer(Length), Length >= 0 ->
  632. case async_recv(S, Length, Time) of
  633. {ok, Ref} ->
  634. receive
  635. {inet_async, S, Ref, Status} -> Status;
  636. {'EXIT', S, _Reason} ->
  637. {error, closed}
  638. end;
  639. Error -> Error
  640. end.
  641. async_recv(S, Length, Time) ->
  642. case ctl_cmd(S, ?TCP_REQ_RECV, [enc_time(Time), ?int32(Length)]) of
  643. {ok,[R1,R0]} -> {ok, ?u16(R1,R0)};
  644. {error,_}=Error -> Error
  645. end.
  646. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  647. %%
  648. %% RECVFROM(insock(), Lenth [Timeout]) -> {ok,{IP,Port,Data}} | {error, Reason}
  649. %% For SCTP: -> {ok,{IP,Port,[AncData],Data}}
  650. %% | {error, Reason}
  651. %% receive Length data bytes from a datagram socket sent from IP at Port
  652. %% if 0 is given then a Data packet is requested (see setopt (packet))
  653. %% N read N bytes
  654. %%
  655. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  656. %% "recvfrom" is for both UDP and SCTP.
  657. %% NB: "Length" is actually ignored for these protocols, since they are msg-
  658. %% oriented: preserved here only for API compatibility.
  659. %%
  660. recvfrom(S, Length) ->
  661. recvfrom(S, Length, infinity).
  662. recvfrom(S, Length, infinity) when is_port(S) ->
  663. recvfrom0(S, Length, -1);
  664. recvfrom(S, Length, Time) when is_port(S) ->
  665. if
  666. is_integer(Time), 0 =< Time, Time < 16#ffffffff ->
  667. recvfrom0(S, Length, Time);
  668. true ->
  669. {error, einval}
  670. end.
  671. recvfrom0(S, Length, Time)
  672. when is_integer(Length), 0 =< Length, Length =< 16#ffffffff ->
  673. case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of
  674. {ok,[R1,R0]} ->
  675. Ref = ?u16(R1,R0),
  676. receive
  677. % Success, UDP:
  678. {inet_async, S, Ref, {ok, {[F | AddrData], AncData}}} ->
  679. %% With ancillary data
  680. case get_addr(F, AddrData) of
  681. {{Family, _} = Addr, Data} when is_atom(Family) ->
  682. {ok, {Addr, 0, AncData, Data}};
  683. {{IP, Port}, Data} ->
  684. {ok, {IP, Port, AncData, Data}}
  685. end;
  686. {inet_async, S, Ref, {ok, [F | AddrData]}} ->
  687. %% Without ancillary data
  688. case get_addr(F, AddrData) of
  689. {{Family, _} = Addr, Data} when is_atom(Family) ->
  690. {ok, {Addr, 0, Data}};
  691. {{IP, Port}, Data} ->
  692. {ok, {IP, Port, Data}}
  693. end;
  694. % Success, SCTP:
  695. {inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} ->
  696. {IP, _} = get_ip(F, Addr),
  697. {ok, {IP, ?u16(P1, P0), AncData, DE}};
  698. % Back-end error:
  699. {inet_async, S, Ref, Error={error, _}} ->
  700. Error
  701. end;
  702. {error,_}=Error ->
  703. Error % Front-end error
  704. end;
  705. recvfrom0(_, _, _) -> {error,einval}.
  706. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  707. %%
  708. %% PEERNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
  709. %%
  710. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  711. peername(S) when is_port(S) ->
  712. case ctl_cmd(S, ?INET_REQ_PEER, []) of
  713. {ok, [F | Addr]} ->
  714. {A, _} = get_addr(F, Addr),
  715. {ok, A};
  716. {error, _} = Error -> Error
  717. end.
  718. setpeername(S, undefined) when is_port(S) ->
  719. case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
  720. {ok, []} -> ok;
  721. {error, _} = Error -> Error
  722. end;
  723. setpeername(S, Addr) when is_port(S) ->
  724. case type_value(set, addr, Addr) of
  725. true ->
  726. case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of
  727. {ok, []} -> ok;
  728. {error, _} = Error -> Error
  729. end;
  730. false ->
  731. {error, einval}
  732. end.
  733. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  734. %%
  735. %% PEERNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
  736. %%
  737. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  738. peernames(S) when is_port(S) ->
  739. peernames(S, undefined).
  740. peernames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
  741. peernames(S, AssocId);
  742. peernames(S, AssocId)
  743. when is_port(S), is_integer(AssocId);
  744. is_port(S), AssocId =:= undefined ->
  745. Q = get,
  746. Type = [[sctp_assoc_id,0]],
  747. case type_value(Q, Type, AssocId) of
  748. true ->
  749. case ctl_cmd
  750. (S, ?INET_REQ_GETPADDRS,
  751. enc_value(Q, Type, AssocId)) of
  752. {ok,Addrs} ->
  753. {ok,get_addrs(Addrs)};
  754. Error ->
  755. Error
  756. end;
  757. false ->
  758. {error,einval}
  759. end.
  760. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  761. %%
  762. %% SOCKNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
  763. %%
  764. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  765. sockname(S) when is_port(S) ->
  766. case ctl_cmd(S, ?INET_REQ_NAME, []) of
  767. {ok, [F | Addr]} ->
  768. {A, _} = get_addr(F, Addr),
  769. {ok, A};
  770. {error, _} = Error -> Error
  771. end.
  772. setsockname(S, undefined) when is_port(S) ->
  773. case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
  774. {ok, []} -> ok;
  775. {error, _} = Error -> Error
  776. end;
  777. setsockname(S, Addr) when is_port(S) ->
  778. case type_value(set, addr, Addr) of
  779. true ->
  780. case
  781. ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr))
  782. of
  783. {ok, []} -> ok;
  784. {error, _} = Error -> Error
  785. end;
  786. false ->
  787. {error, einval}
  788. end.
  789. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  790. %%
  791. %% SOCKNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
  792. %%
  793. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  794. socknames(S) when is_port(S) ->
  795. socknames(S, undefined).
  796. socknames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
  797. socknames(S, AssocId);
  798. socknames(S, AssocId)
  799. when is_port(S), is_integer(AssocId);
  800. is_port(S), AssocId =:= undefined ->
  801. Q = get,
  802. Type = [[sctp_assoc_id,0]],
  803. case type_value(Q, Type, AssocId) of
  804. true ->
  805. case ctl_cmd
  806. (S, ?INET_REQ_GETLADDRS,
  807. enc_value(Q, Type, AssocId)) of
  808. {ok,Addrs} ->
  809. {ok,get_addrs(Addrs)};
  810. Error ->
  811. Error
  812. end;
  813. false ->
  814. {error,einval}
  815. end.
  816. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  817. %%
  818. %% SETOPT(insock(), Opt, Value) -> ok | {error, Reason}
  819. %% SETOPTS(insock(), [{Opt,Value}]) -> ok | {error, Reason}
  820. %%
  821. %% set socket, ip and driver option
  822. %%
  823. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  824. setopt(S, Opt, Value) when is_port(S) ->
  825. setopts(S, [{Opt,Value}]).
  826. setopts(S, Opts) when is_port(S) ->
  827. case encode_opt_val(Opts) of
  828. {ok, Buf} ->
  829. case ctl_cmd(S, ?INET_REQ_SETOPTS, Buf) of
  830. {ok, _} -> ok;
  831. {error,_}=Error -> Error
  832. end;
  833. Error -> Error
  834. end.
  835. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  836. %%
  837. %% GETOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
  838. %% GETOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
  839. %% get socket, ip and driver option
  840. %%
  841. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  842. getopt(S, Opt) when is_port(S), is_atom(Opt) ->
  843. case getopts(S, [Opt]) of
  844. {ok,[{_,Value}]} -> {ok, Value};
  845. Error -> Error
  846. end.
  847. getopts(S, Opts) when is_port(S), is_list(Opts) ->
  848. case encode_opts(Opts) of
  849. {ok,Buf} ->
  850. case ctl_cmd(S, ?INET_REQ_GETOPTS, Buf) of
  851. {ok,Rep} ->
  852. %% Non-SCTP: "Rep" contains the encoded option vals:
  853. decode_opt_val(Rep);
  854. inet_reply ->
  855. %% SCTP: Need to receive the full value:
  856. receive
  857. {inet_reply,S,Res} -> Res
  858. end;
  859. {error,_}=Error -> Error
  860. end;
  861. Error -> Error
  862. end.
  863. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  864. %%
  865. %% CHGOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
  866. %% CHGOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
  867. %% change socket, ip and driver option
  868. %%
  869. %% Same as setopts except for record value options where undefined
  870. %% fields are read with getopts before setting.
  871. %%
  872. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  873. chgopt(S, Opt, Value) when is_port(S) ->
  874. chgopts(S, [{Opt,Value}]).
  875. chgopts(S, Opts) when is_port(S), is_list(Opts) ->
  876. case getopts(S, need_template(Opts)) of
  877. {ok,Templates} ->
  878. try merge_options(Opts, Templates) of
  879. NewOpts ->
  880. setopts(S, NewOpts)
  881. catch
  882. Reason -> {error,Reason}
  883. end;
  884. Error -> Error
  885. end.
  886. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  887. %%
  888. %% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason}
  889. %%
  890. %% IfAddrsList = [{Name,[Opts]}]
  891. %% Name = string()
  892. %% Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr}
  893. %% | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()}
  894. %% Flag = up | broadcast | loopback | running | multicast
  895. %% Addr = ipv4addr() | ipv6addr()
  896. %% HwAddr = ethernet_addr()
  897. %%
  898. %% get interface name and addresses list
  899. %%
  900. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  901. getifaddrs(S) when is_port(S) ->
  902. case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
  903. {ok, Data} ->
  904. {ok, comp_ifaddrs(build_ifaddrs(Data))};
  905. {error,enotsup} ->
  906. case getiflist(S) of
  907. {ok, IFs} ->
  908. {ok, getifaddrs_ifget(S, IFs)};
  909. Err1 -> Err1
  910. end;
  911. Err2 -> Err2
  912. end.
  913. %% Restructure interface properties per interface
  914. comp_ifaddrs(IfOpts) ->
  915. comp_ifaddrs(IfOpts, ktree_empty()).
  916. %%
  917. comp_ifaddrs([{If,[{flags,Flags}|Opts]}|IfOpts], IfT) ->
  918. case ktree_is_defined(If, IfT) of
  919. true ->
  920. comp_ifaddrs(
  921. IfOpts,
  922. ktree_update(
  923. If,
  924. comp_ifaddrs_flags(Flags, Opts, ktree_get(If, IfT)),
  925. IfT));
  926. false ->
  927. comp_ifaddrs(
  928. IfOpts,
  929. ktree_insert(
  930. If,
  931. comp_ifaddrs_flags(Flags, Opts, ktree_empty()),
  932. IfT))
  933. end;
  934. comp_ifaddrs([], IfT) ->
  935. comp_ifaddrs_2(ktree_keys(IfT), IfT).
  936. comp_ifaddrs_flags(Flags, Opts, FlagsT) ->
  937. case ktree_is_defined(Flags, FlagsT) of
  938. true ->
  939. ktree_update(
  940. Flags,
  941. rev(Opts, ktree_get(Flags, FlagsT)),
  942. FlagsT);
  943. false ->
  944. ktree_insert(Flags, rev(Opts), FlagsT)
  945. end.
  946. comp_ifaddrs_2([If|Ifs], IfT) ->
  947. FlagsT = ktree_get(If, IfT),
  948. [{If,comp_ifaddrs_3(ktree_keys(FlagsT), FlagsT)}
  949. | comp_ifaddrs_2(Ifs, IfT)];
  950. comp_ifaddrs_2([], _IfT) ->
  951. [].
  952. %%
  953. comp_ifaddrs_3([Flags|FlagsL], FlagsT) ->
  954. [{flags,Flags}|hwaddr_last(rev(ktree_get(Flags, FlagsT)))]
  955. ++ hwaddr_last(comp_ifaddrs_3(FlagsL, FlagsT));
  956. comp_ifaddrs_3([], _FlagsT) ->
  957. [].
  958. %% Place hwaddr last to look more like legacy emulation
  959. hwaddr_last(Opts) ->
  960. hwaddr_last(Opts, Opts, []).
  961. %%
  962. hwaddr_last([{hwaddr,_} = Opt|Opts], L, R) ->
  963. hwaddr_last(Opts, L, [Opt|R]);
  964. hwaddr_last([_|Opts], L, R) ->
  965. hwaddr_last(Opts, L, R);
  966. hwaddr_last([], L, []) ->
  967. L;
  968. hwaddr_last([], L, R) ->
  969. rev(hwaddr_last(L, []), rev(R)).
  970. %%
  971. hwaddr_last([{hwaddr,_}|Opts], R) ->
  972. hwaddr_last(Opts, R);
  973. hwaddr_last([Opt|Opts], R) ->
  974. hwaddr_last(Opts, [Opt|R]);
  975. hwaddr_last([], R) ->
  976. R.
  977. %% Legacy emulation of getifaddrs
  978. getifaddrs_ifget(_, []) -> [];
  979. getifaddrs_ifget(S, [IF|IFs]) ->
  980. case ifget(S, IF, [flags]) of
  981. {ok,[{flags,Flags}]=FlagsVals} ->
  982. GetOpts =
  983. case member(pointtopoint, Flags) of
  984. true ->
  985. [dstaddr,hwaddr];
  986. false ->
  987. case member(broadcast, Flags) of
  988. true ->
  989. [broadaddr,hwaddr];
  990. false ->
  991. [hwaddr]
  992. end
  993. end,
  994. getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|GetOpts]);
  995. _ ->
  996. getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
  997. end.
  998. getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) ->
  999. OptVals =
  1000. case ifget(S, IF, Opts) of
  1001. {ok,OVs} -> OVs;
  1002. _ -> []
  1003. end,
  1004. [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)].
  1005. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1006. %%
  1007. %% getiflist(insock()) -> {ok,IfNameList} | {error, Reason}
  1008. %%
  1009. %% get interface name list
  1010. %%
  1011. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1012. getiflist(S) when is_port(S) ->
  1013. case ctl_cmd(S, ?INET_REQ_GETIFLIST, []) of
  1014. {ok, Data} -> {ok, build_iflist(Data)};
  1015. {error,_}=Error -> Error
  1016. end.
  1017. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1018. %%
  1019. %% ifget(insock(), IFOpts) -> {ok,IfNameList} | {error, Reason}
  1020. %%
  1021. %% get interface name list
  1022. %%
  1023. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1024. ifget(S, Name, Opts) ->
  1025. case encode_ifname(Name) of
  1026. {ok, Buf1} ->
  1027. case encode_ifopts(Opts,[]) of
  1028. {ok, Buf2} ->
  1029. case ctl_cmd(S, ?INET_REQ_IFGET, [Buf1,Buf2]) of
  1030. {ok, Data} -> decode_ifopts(Data,[]);
  1031. {error,_}=Error -> Error
  1032. end;
  1033. Error -> Error
  1034. end;
  1035. Error -> Error
  1036. end.
  1037. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1038. %%
  1039. %% ifset(insock(), Name, IFOptVals) -> {ok,IfNameList} | {error, Reason}
  1040. %%
  1041. %% set interface parameters
  1042. %%
  1043. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1044. ifset(S, Name, Opts) ->
  1045. case encode_ifname(Name) of
  1046. {ok, Buf1} ->
  1047. case encode_ifopt_val(Opts,[]) of
  1048. {ok, Buf2} ->
  1049. case ctl_cmd(S, ?INET_REQ_IFSET, [Buf1,Buf2]) of
  1050. {ok, _} -> ok;
  1051. {error,_}=Error -> Error
  1052. end;
  1053. Error -> Error
  1054. end;
  1055. Error -> Error
  1056. end.
  1057. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1058. %%
  1059. %% subscribe(insock(), SubsList) -> {ok,StatReply} | {error, Reason}
  1060. %%
  1061. %% Subscribe on socket events (from driver)
  1062. %%
  1063. %% Available event subscriptions:
  1064. %% subs_empty_out_q: StatReply = [{subs_empty_out_q, N}], where N
  1065. %% is current queue length. When the queue becomes empty
  1066. %% a {empty_out_q, insock()} message will be sent to
  1067. %% subscribing process and the subscription will be
  1068. %% removed. If N = 0, the queue is empty and no
  1069. %% subscription is made.
  1070. %%
  1071. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1072. subscribe(S, Sub) when is_port(S), is_list(Sub) ->
  1073. case encode_subs(Sub) of
  1074. {ok, Bytes} ->
  1075. case ctl_cmd(S, ?INET_REQ_SUBSCRIBE, Bytes) of
  1076. {ok, Data} -> decode_subs(Data);
  1077. {error,_}=Error -> Error
  1078. end;
  1079. Error -> Error
  1080. end.
  1081. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1082. %%
  1083. %% GETSTAT(insock(), StatList) -> {ok,StatReply} | {error, Reason}
  1084. %%
  1085. %% get socket statistics (from driver)
  1086. %%
  1087. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1088. getstat(S, Stats) when is_port(S), is_list(Stats) ->
  1089. case encode_stats(Stats) of
  1090. {ok, Bytes} ->
  1091. case ctl_cmd(S, ?INET_REQ_GETSTAT, Bytes) of
  1092. {ok, Data} -> decode_stats(Data);
  1093. {error,_}=Error -> Error
  1094. end;
  1095. Error -> Error
  1096. end.
  1097. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1098. %%
  1099. %% GETFD(insock()) -> {ok,integer()} | {error, Reason}
  1100. %%
  1101. %% get internal file descriptor
  1102. %%
  1103. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1104. getfd(S) when is_port(S) ->
  1105. case ctl_cmd(S, ?INET_REQ_GETFD, []) of
  1106. {ok, [S3,S2,S1,S0]} -> {ok, ?u32(S3,S2,S1,S0)};
  1107. {error,_}=Error -> Error
  1108. end.
  1109. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1110. %%
  1111. %% IGNOREFD(insock(),boolean()) -> {ok,integer()} | {error, Reason}
  1112. %%
  1113. %% steal internal file descriptor
  1114. %%
  1115. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1116. ignorefd(S,Bool) when is_port(S) ->
  1117. Val = if Bool -> 1; true -> 0 end,
  1118. case ctl_cmd(S, ?INET_REQ_IGNOREFD, [Val]) of
  1119. {ok, _} -> ok;
  1120. Error -> Error
  1121. end.
  1122. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1123. %%
  1124. %% GETIX(insock()) -> {ok,integer()} | {error, Reason}
  1125. %%
  1126. %% get internal socket index
  1127. %%
  1128. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1129. getindex(S) when is_port(S) ->
  1130. %% NOT USED ANY MORE
  1131. {error, einval}.
  1132. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1133. %%
  1134. %% GETTYPE(insock()) -> {ok,{Family,Type}} | {error, Reason}
  1135. %%
  1136. %% get family/type of a socket
  1137. %%
  1138. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1139. gettype(S) when is_port(S) ->
  1140. case ctl_cmd(S, ?INET_REQ_GETTYPE, []) of
  1141. {ok, [F3,F2,F1,F0,T3,T2,T1,T0]} ->
  1142. Family = case ?u32(F3,F2,F1,F0) of
  1143. ?INET_AF_INET -> inet;
  1144. ?INET_AF_INET6 -> inet6;
  1145. _ -> undefined
  1146. end,
  1147. Type = case ?u32(T3,T2,T1,T0) of
  1148. ?INET_TYPE_STREAM -> stream;
  1149. ?INET_TYPE_DGRAM -> dgram;
  1150. ?INET_TYPE_SEQPACKET -> seqpacket;
  1151. _ -> undefined
  1152. end,
  1153. {ok, {Family, Type}};
  1154. {error,_}=Error -> Error
  1155. end.
  1156. getprotocol(S) when is_port(S) ->
  1157. {name,Drv} = erlang:port_info(S, name),
  1158. drv2protocol(Drv).
  1159. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1160. %% IS_SCTP(insock()) -> true | false
  1161. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1162. %% is_sctp(S) when is_port(S) ->
  1163. %% case gettype(S) of
  1164. %% {ok, {_, seqpacket}} -> true;
  1165. %% _ -> false
  1166. %% end.
  1167. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1168. %%
  1169. %% GETSTATUS(insock()) -> {ok,Status} | {error, Reason}
  1170. %%
  1171. %% get socket status
  1172. %%
  1173. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1174. getstatus(S) when is_port(S) ->
  1175. case ctl_cmd(S, ?INET_REQ_GETSTATUS, []) of
  1176. {ok, [S3,S2,S1,S0]} ->
  1177. {ok, dec_status(?u32(S3,S2,S1,S0))};
  1178. {error,_}=Error -> Error
  1179. end.
  1180. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1181. %%
  1182. %% GETHOSTNAME(insock()) -> {ok,HostName} | {error, Reason}
  1183. %%
  1184. %% get host name
  1185. %%
  1186. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1187. gethostname(S) when is_port(S) ->
  1188. ctl_cmd(S, ?INET_REQ_GETHOSTNAME, []).
  1189. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1190. %%
  1191. %% GETSERVBYNAME(insock(),Name,Proto) -> {ok,Port} | {error, Reason}
  1192. %%
  1193. %% get service port
  1194. %%
  1195. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1196. getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_atom(Proto) ->
  1197. getservbyname1(S, atom_to_list(Name), atom_to_list(Proto));
  1198. getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_list(Proto) ->
  1199. getservbyname1(S, atom_to_list(Name), Proto);
  1200. getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_atom(Proto) ->
  1201. getservbyname1(S, Name, atom_to_list(Proto));
  1202. getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_list(Proto) ->
  1203. getservbyname1(S, Name, Proto);
  1204. getservbyname(_,_, _) ->
  1205. {error, einval}.
  1206. getservbyname1(S,Name,Proto) ->
  1207. L1 = length(Name),
  1208. L2 = length(Proto),
  1209. if L1 > 255 -> {error, einval};
  1210. L2 > 255 -> {error, einval};
  1211. true ->
  1212. case ctl_cmd(S, ?INET_REQ_GETSERVBYNAME, [L1,Name,L2,Proto]) of
  1213. {ok, [P1,P0]} ->
  1214. {ok, ?u16(P1,P0)};
  1215. {error,_}=Error ->
  1216. Error
  1217. end
  1218. end.
  1219. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1220. %%
  1221. %% GETSERVBYPORT(insock(),Port,Proto) -> {ok,Port} | {error, Reason}
  1222. %%
  1223. %% get service port from portnumber and protocol
  1224. %%
  1225. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1226. getservbyport(S,Port,Proto) when is_port(S), is_atom(Proto) ->
  1227. getservbyport1(S, Port, atom_to_list(Proto));
  1228. getservbyport(S,Port,Proto) when is_port(S), is_list(Proto) ->
  1229. getservbyport1(S, Port, Proto);
  1230. getservbyport(_, _, _) ->
  1231. {error, einval}.
  1232. getservbyport1(S,Port,Proto) ->
  1233. L = length(Proto),
  1234. if Port < 0 -> {error, einval};
  1235. Port > 16#ffff -> {error, einval};
  1236. L > 255 -> {error, einval};
  1237. true ->
  1238. case ctl_cmd(S, ?INET_REQ_GETSERVBYPORT, [?int16(Port),L,Proto]) of
  1239. {ok, Name} -> {ok, Name};
  1240. {error,_}=Error -> Error
  1241. end
  1242. end.
  1243. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1244. %%
  1245. %% UNRECV(insock(), data) -> ok | {error, Reason}
  1246. %%
  1247. %%
  1248. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1249. unrecv(S, Data) ->
  1250. case ctl_cmd(S, ?TCP_REQ_UNRECV, Data) of
  1251. {ok, _} -> ok;
  1252. {error,_}=Error -> Error
  1253. end.
  1254. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1255. %%
  1256. %% DETACH(insock()) -> ok
  1257. %%
  1258. %% unlink from a socket
  1259. %%
  1260. %% ATTACH(insock()) -> ok | {error, Reason}
  1261. %%
  1262. %% link and connect to a socket
  1263. %%
  1264. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1265. detach(S) when is_port(S) ->
  1266. unlink(S),
  1267. ok.
  1268. attach(S) when is_port(S) ->
  1269. try erlang:port_connect(S, self()) of
  1270. true -> link(S), ok
  1271. catch
  1272. error:Reason -> {error,Reason}
  1273. end.
  1274. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1275. %%
  1276. %% INTERNAL FUNCTIONS
  1277. %%
  1278. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1279. is_sockopt_val(Opt, Val) ->
  1280. Type = type_opt(set, Opt),
  1281. try type_value(set, Type, Val)
  1282. catch
  1283. _ -> false
  1284. end.
  1285. %%
  1286. %% Socket options processing: Encoding option NAMES:
  1287. %%
  1288. enc_opt(reuseaddr) -> ?INET_OPT_REUSEADDR;
  1289. enc_opt(keepalive) -> ?INET_OPT_KEEPALIVE;
  1290. enc_opt(dontroute) -> ?INET_OPT_DONTROUTE;
  1291. enc_opt(linger) -> ?INET_OPT_LINGER;
  1292. enc_opt(broadcast) -> ?INET_OPT_BROADCAST;
  1293. enc_opt(sndbuf) -> ?INET_OPT_SNDBUF;
  1294. enc_opt(recbuf) -> ?INET_OPT_RCVBUF;
  1295. enc_opt(priority) -> ?INET_OPT_PRIORITY;
  1296. enc_opt(tos) -> ?INET_OPT_TOS;
  1297. enc_opt(tclass) -> ?INET_OPT_TCLASS;
  1298. enc_opt(recvtos) -> ?INET_OPT_RECVTOS;
  1299. enc_opt(recvtclass) -> ?INET_OPT_RECVTCLASS;
  1300. enc_opt(pktoptions) -> ?INET_OPT_PKTOPTIONS;
  1301. enc_opt(ttl) -> ?INET_OPT_TTL;
  1302. enc_opt(recvttl) -> ?INET_OPT_RECVTTL;
  1303. enc_opt(nodelay) -> ?TCP_OPT_NODELAY;
  1304. enc_opt(nopush) -> ?TCP_OPT_NOPUSH;
  1305. enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF;
  1306. enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
  1307. enc_opt(multicast_loop) -> ?UDP_OPT_MULTICAST_LOOP;
  1308. enc_opt(add_membership) -> ?UDP_OPT_ADD_MEMBERSHIP;
  1309. enc_opt(drop_membership) -> ?UDP_OPT_DROP_MEMBERSHIP;
  1310. enc_opt(ipv6_v6only) -> ?INET_OPT_IPV6_V6ONLY;
  1311. enc_opt(buffer) -> ?INET_LOPT_BUFFER;
  1312. enc_opt(header) -> ?INET_LOPT_HEADER;
  1313. enc_opt(active) -> ?INET_LOPT_ACTIVE;
  1314. enc_opt(packet) -> ?INET_LOPT_PACKET;
  1315. enc_opt(mode) -> ?INET_LOPT_MODE;
  1316. enc_opt(deliver) -> ?INET_LOPT_DELIVER;
  1317. enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE;
  1318. enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK;
  1319. enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK;
  1320. enc_opt(high_msgq_watermark) -> ?INET_LOPT_MSGQ_HIWTRMRK;
  1321. enc_opt(low_msgq_watermark) -> ?INET_LOPT_MSGQ_LOWTRMRK;
  1322. enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT;
  1323. enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
  1324. enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND;
  1325. enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE;
  1326. enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS;
  1327. enc_opt(netns) -> ?INET_LOPT_NETNS;
  1328. enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET;
  1329. enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM;
  1330. enc_opt(raw) -> ?INET_OPT_RAW;
  1331. enc_opt(bind_to_device) -> ?INET_OPT_BIND_TO_DEVICE;
  1332. % Names of SCTP opts:
  1333. enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO;
  1334. enc_opt(sctp_associnfo) -> ?SCTP_OPT_ASSOCINFO;
  1335. enc_opt(sctp_initmsg) -> ?SCTP_OPT_INITMSG;
  1336. enc_opt(sctp_autoclose) -> ?SCTP_OPT_AUTOCLOSE;
  1337. enc_opt(sctp_nodelay) -> ?SCTP_OPT_NODELAY;
  1338. enc_opt(sctp_disable_fragments) -> ?SCTP_OPT_DISABLE_FRAGMENTS;
  1339. enc_opt(sctp_i_want_mapped_v4_addr)-> ?SCTP_OPT_I_WANT_MAPPED_V4_ADDR;
  1340. enc_opt(sctp_maxseg) -> ?SCTP_OPT_MAXSEG;
  1341. enc_opt(sctp_set_peer_primary_addr)-> ?SCTP_OPT_SET_PEER_PRIMARY_ADDR;
  1342. enc_opt(sctp_primary_addr) -> ?SCTP_OPT_PRIMARY_ADDR;
  1343. enc_opt(sctp_adaptation_layer) -> ?SCTP_OPT_ADAPTATION_LAYER;
  1344. enc_opt(sctp_peer_addr_params) -> ?SCTP_OPT_PEER_ADDR_PARAMS;
  1345. enc_opt(sctp_default_send_param) -> ?SCTP_OPT_DEFAULT_SEND_PARAM;
  1346. enc_opt(sctp_events) -> ?SCTP_OPT_EVENTS;
  1347. enc_opt(sctp_delayed_ack_time) -> ?SCTP_OPT_DELAYED_ACK_TIME;
  1348. enc_opt(sctp_status) -> ?SCTP_OPT_STATUS;
  1349. enc_opt(sctp_get_peer_addr_info) -> ?SCTP_OPT_GET_PEER_ADDR_INFO.
  1350. %%
  1351. %%
  1352. %% Decoding option NAMES:
  1353. %%
  1354. dec_opt(?INET_OPT_REUSEADDR) -> reuseaddr;
  1355. dec_opt(?INET_OPT_KEEPALIVE) -> keepalive;
  1356. dec_opt(?INET_OPT_DONTROUTE) -> dontroute;
  1357. dec_opt(?INET_OPT_LINGER) -> linger;
  1358. dec_opt(?INET_OPT_BROADCAST) -> broadcast;
  1359. dec_opt(?INET_OPT_SNDBUF) -> sndbuf;
  1360. dec_opt(?INET_OPT_RCVBUF) -> recbuf;
  1361. dec_opt(?INET_OPT_PRIORITY) -> priority;
  1362. dec_opt(?INET_OPT_TOS) -> tos;
  1363. dec_opt(?INET_OPT_TCLASS) -> tclass;
  1364. dec_opt(?TCP_OPT_NODELAY) -> nodelay;
  1365. dec_opt(?TCP_OPT_NOPUSH) -> nopush;
  1366. dec_opt(?INET_OPT_RECVTOS) -> recvtos;
  1367. dec_opt(?INET_OPT_RECVTCLASS) -> recvtclass;
  1368. dec_opt(?INET_OPT_PKTOPTIONS) -> pktoptions;
  1369. dec_opt(?INET_OPT_TTL) -> ttl;
  1370. dec_opt(?INET_OPT_RECVTTL) -> recvttl;
  1371. dec_opt(?UDP_OPT_MULTICAST_IF) -> multicast_if;
  1372. dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl;
  1373. dec_opt(?UDP_OPT_MULTICAST_LOOP) -> multicast_loop;
  1374. dec_opt(?UDP_OPT_ADD_MEMBERSHIP) -> add_membership;
  1375. dec_opt(?UDP_OPT_DROP_MEMBERSHIP) -> drop_membership;
  1376. dec_opt(?INET_OPT_IPV6_V6ONLY) -> ipv6_v6only;
  1377. dec_opt(?INET_LOPT_BUFFER) -> buffer;
  1378. dec_opt(?INET_LOPT_HEADER) -> header;
  1379. dec_opt(?INET_LOPT_ACTIVE) -> active;
  1380. dec_opt(?INET_LOPT_PACKET) -> packet;
  1381. dec_opt(?INET_LOPT_MODE) -> mode;
  1382. dec_opt(?INET_LOPT_DELIVER) -> deliver;
  1383. dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close;
  1384. dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark;
  1385. dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark;
  1386. dec_opt(?INET_LOPT_MSGQ_HIWTRMRK) -> high_msgq_watermark;
  1387. dec_opt(?INET_LOPT_MSGQ_LOWTRMRK) -> low_msgq_watermark;
  1388. dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
  1389. dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
  1390. dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send;
  1391. dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size;
  1392. dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets;
  1393. dec_opt(?INET_LOPT_NETNS) -> netns;
  1394. dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset;
  1395. dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter;
  1396. dec_opt(?INET_OPT_RAW) -> raw;
  1397. dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device;
  1398. dec_opt(I) when is_integer(I) -> undefined.
  1399. %% Metatypes:
  1400. %% [] Value must be 'undefined' or nonexistent
  1401. %% for setopts and getopts.
  1402. %% [Type] Value required for setopts and getopts,
  1403. %% will be encoded for both.
  1404. %% [Type,Default] Default used if value is 'undefined'.
  1405. %% [[Type,Default]] A combination of the two above.
  1406. %% Type Value must be 'undefined' or nonexistent for getops,
  1407. %% required for setopts.
  1408. %%
  1409. %% The use of [] and [[Type,Default]] is commented out in enc_value/2
  1410. %% and type_value/2 below since they are only used in record fields.
  1411. %% And record fields does not call enc_value/2 nor type_value/2.
  1412. %% Anyone introducing these metatypes otherwhere will have to activate
  1413. %% those clauses in enc_value/2 and type_value/2. You have been warned!
  1414. type_opt(get, raw) -> [{[int],[int],[binary_or_uint]}];
  1415. type_opt(_, raw) -> {int,int,binary};
  1416. %% NB: "sctp_status" and "sctp_get_peer_addr_info" are read-only options,
  1417. %% so they should not be NOT encoded for use with "setopt".
  1418. type_opt(get, sctp_status) ->
  1419. [{record,#sctp_status{
  1420. assoc_id = [sctp_assoc_id],
  1421. _ = []}}];
  1422. type_opt(get, sctp_get_peer_addr_info) ->
  1423. [{record,#sctp_paddrinfo{
  1424. assoc_id = [[sctp_assoc_id,0]],
  1425. address = [[addr,{any,0}]],
  1426. _ = []}}];
  1427. type_opt(_, Opt) ->
  1428. type_opt_1(Opt).
  1429. %% Types of option values, by option name:
  1430. %%
  1431. type_opt_1(reuseaddr) -> bool;
  1432. type_opt_1(keepalive) -> bool;
  1433. type_opt_1(dontroute) -> bool;
  1434. type_opt_1(linger) -> {bool,int};
  1435. type_opt_1(broadcast) -> bool;
  1436. type_opt_1(sndbuf) -> int;
  1437. type_opt_1(recbuf) -> int;
  1438. type_opt_1(priority) -> int;
  1439. type_opt_1(tos) -> int;
  1440. type_opt_1(tclass) -> int;
  1441. type_opt_1(recvtos) -> bool;
  1442. type_opt_1(recvtclass) -> bool;
  1443. type_opt_1(pktoptions) -> opts;
  1444. type_opt_1(ttl) -> int;
  1445. type_opt_1(recvttl) -> bool;
  1446. type_opt_1(nodelay) -> bool;
  1447. type_opt_1(nopush) -> bool;
  1448. type_opt_1(ipv6_v6only) -> bool;
  1449. %% multicast
  1450. type_opt_1(multicast_ttl) -> int;
  1451. type_opt_1(multicast_loop) -> bool;
  1452. type_opt_1(multicast_if) -> ip;
  1453. type_opt_1(add_membership) -> {ip,ip};
  1454. type_opt_1(drop_membership) -> {ip,ip};
  1455. %% driver options
  1456. type_opt_1(header) -> uint;
  1457. type_opt_1(buffer) -> int;
  1458. type_opt_1(active) ->
  1459. {enum,[{false, ?INET_PASSIVE},
  1460. {true, ?INET_ACTIVE},
  1461. {once, ?INET_ONCE},
  1462. {multi, ?INET_MULTI}]};
  1463. type_opt_1(packet) ->
  1464. {enum,[{0, ?TCP_PB_RAW},
  1465. {1, ?TCP_PB_1},
  1466. {2, ?TCP_PB_2},
  1467. {4, ?TCP_PB_4},
  1468. {raw,?TCP_PB_RAW},
  1469. {sunrm, ?TCP_PB_RM},
  1470. {asn1, ?TCP_PB_ASN1},
  1471. {cdr, ?TCP_PB_CDR},
  1472. {fcgi, ?TCP_PB_FCGI},
  1473. {line, ?TCP_PB_LINE_LF},
  1474. {tpkt, ?TCP_PB_TPKT},
  1475. {http, ?TCP_PB_HTTP},
  1476. {httph,?TCP_PB_HTTPH},
  1477. {http_bin, ?TCP_PB_HTTP_BIN},
  1478. {httph_bin,?TCP_PB_HTTPH_BIN},
  1479. {ssl, ?TCP_PB_SSL_TLS}, % obsolete
  1480. {ssl_tls, ?TCP_PB_SSL_TLS}]};
  1481. type_opt_1(line_delimiter) -> int;
  1482. type_opt_1(mode) ->
  1483. {enum,[{list, ?INET_MODE_LIST},
  1484. {binary, ?INET_MODE_BINARY}]};
  1485. type_opt_1(deliver) ->
  1486. {enum,[{port, ?INET_DELIVER_PORT},
  1487. {term, ?INET_DELIVER_TERM}]};
  1488. type_opt_1(exit_on_close) -> bool;
  1489. type_opt_1(low_watermark) -> int;
  1490. type_opt_1(high_watermark) -> int;
  1491. type_opt_1(low_msgq_watermark) -> int;
  1492. type_opt_1(high_msgq_watermark) -> int;
  1493. type_opt_1(send_timeout) -> time;
  1494. type_opt_1(send_timeout_close) -> bool;
  1495. type_opt_1(delay_send) -> bool;
  1496. type_opt_1(packet_size) -> uint;
  1497. type_opt_1(read_packets) -> uint;
  1498. type_opt_1(netns) -> binary;
  1499. type_opt_1(show_econnreset) -> bool;
  1500. type_opt_1(bind_to_device) -> binary;
  1501. %%
  1502. %% SCTP options (to be set). If the type is a record type, the corresponding
  1503. %% record signature is returned, otherwise, an "elementary" type tag
  1504. %% is returned:
  1505. %%
  1506. %% for SCTP_OPT_RTOINFO
  1507. type_opt_1(sctp_rtoinfo) ->
  1508. [{record,#sctp_rtoinfo{
  1509. assoc_id = [[sctp_assoc_id,0]],
  1510. initial = [uint32,0],
  1511. max = [uint32,0],
  1512. min = [uint32,0]}}];
  1513. %% for SCTP_OPT_ASSOCINFO
  1514. type_opt_1(sctp_associnfo) ->
  1515. [{record,#sctp_assocparams{
  1516. assoc_id = [[sctp_assoc_id,0]],
  1517. asocmaxrxt = [uint16,0],
  1518. number_peer_destinations = [uint16,0],
  1519. peer_rwnd = [uint32,0],
  1520. local_rwnd = [uint32,0],
  1521. cookie_life = [uint32,0]}}];
  1522. %% for SCTP_OPT_INITMSG and SCTP_TAG_SEND_ANC_INITMSG (send*)
  1523. type_opt_1(sctp_initmsg) ->
  1524. [{record,#sctp_initmsg{
  1525. num_ostreams = [uint16,0],
  1526. max_instreams = [uint16,0],
  1527. max_attempts = [uint16,0],
  1528. max_init_timeo = [uint16,0]}}];
  1529. %%
  1530. type_opt_1(sctp_nodelay) -> bool;
  1531. type_opt_1(sctp_autoclose) -> uint;
  1532. type_opt_1(sctp_disable_fragments) -> bool;
  1533. type_opt_1(sctp_i_want_mapped_v4_addr) -> bool;
  1534. type_opt_1(sctp_maxseg) -> uint;
  1535. %% for SCTP_OPT_PRIMARY_ADDR
  1536. type_opt_1(sctp_primary_addr) ->
  1537. [{record,#sctp_prim{
  1538. assoc_id = [sctp_assoc_id],
  1539. addr = addr}}];
  1540. %% for SCTP_OPT_SET_PEER_PRIMARY_ADDR
  1541. type_opt_1(sctp_set_peer_primary_addr) ->
  1542. [{record,#sctp_setpeerprim{
  1543. assoc_id = [sctp_assoc_id],
  1544. addr = addr}}];
  1545. %% for SCTP_OPT_ADAPTATION_LAYER
  1546. type_opt_1(sctp_adaptation_layer) ->
  1547. [{record,#sctp_setadaptation{
  1548. adaptation_ind = [uint32,0]}}];
  1549. %% for SCTP_OPT_PEER_ADDR_PARAMS
  1550. type_opt_1(sctp_peer_addr_params) ->
  1551. [{record,#sctp_paddrparams{
  1552. assoc_id = [[sctp_assoc_id,0]],
  1553. address = [[addr,{any,0}]],
  1554. hbinterval = [uint32,0],
  1555. pathmaxrxt = [uint16,0],
  1556. pathmtu = [uint32,0],
  1557. sackdelay = [uint32,0],
  1558. flags =
  1559. [{bitenumlist,
  1560. [{hb_enable, ?SCTP_FLAG_HB_ENABLE},
  1561. {hb_disable, ?SCTP_FLAG_HB_DISABLE},
  1562. {hb_demand, ?SCTP_FLAG_HB_DEMAND},
  1563. {pmtud_enable, ?SCTP_FLAG_PMTUD_ENABLE},
  1564. {pmtud_disable, ?SCTP_FLAG_PMTUD_DISABLE},
  1565. {sackdelay_enable, ?SCTP_FLAG_SACKDELAY_ENABLE},
  1566. {sackdelay_disable, ?SCTP_FLAG_SACKDELAY_DISABLE}],
  1567. uint32},[]]}}];
  1568. %% for SCTP_OPT_DEFAULT_SEND_PARAM and SCTP_TAG_SEND_ANC_PARAMS (on send*)
  1569. type_opt_1(sctp_default_send_param) ->
  1570. [{record,#sctp_sndrcvinfo{
  1571. stream = [uint16,0],
  1572. ssn = [],
  1573. flags =
  1574. [{bitenumlist,
  1575. [{unordered, ?SCTP_FLAG_UNORDERED},
  1576. {addr_over, ?SCTP_FLAG_ADDR_OVER},
  1577. {abort, ?SCTP_FLAG_ABORT},
  1578. {eof, ?SCTP_FLAG_EOF}],
  1579. uint16},[]],
  1580. ppid = [uint32,0],
  1581. context = [uint32,0],
  1582. timetolive = [uint32,0],
  1583. tsn = [],
  1584. cumtsn = [],
  1585. assoc_id = [[sctp_assoc_id,0]]}}];
  1586. %% for SCTP_OPT_EVENTS
  1587. type_opt_1(sctp_events) ->
  1588. [{record,#sctp_event_subscribe{
  1589. data_io_event = [bool8,true],
  1590. association_event = [bool8,true],
  1591. address_event = [bool8,true],
  1592. send_failure_event = [bool8,true],
  1593. peer_error_event = [bool8,true],
  1594. shutdown_event = [bool8,true],
  1595. partial_delivery_event = [bool8,true],
  1596. adaptation_layer_event = [bool8,false],
  1597. authentication_event = [bool8,false]}}];
  1598. %% for SCTP_OPT_DELAYED_ACK_TIME
  1599. type_opt_1(sctp_delayed_ack_time) ->
  1600. [{record,#sctp_assoc_value{
  1601. assoc_id = [[sctp_assoc_id,0]],
  1602. assoc_value = [uint32,0]}}];
  1603. %%
  1604. type_opt_1(undefined) -> undefined;
  1605. type_opt_1(O) when is_atom(O) -> undefined.
  1606. %% Get. No supplied value.
  1607. type_value(get, undefined) -> false; % Undefined type
  1608. %% These two clauses cannot happen since they are only used
  1609. %% in record fields - from record fields they must have a
  1610. %% value though it might be 'undefined', so record fields
  1611. %% calls type_value/3, not type_value/2.
  1612. %% type_value(get, []) -> true; % Ignored
  1613. %% type_value(get, [[Type,Default]]) -> % Required field, default value
  1614. %% type_value(get, Type, Default);
  1615. type_value(get, [{record,Types}]) -> % Implied default value for record
  1616. type_value_record(get, Types,
  1617. erlang:make_tuple(tuple_size(Types), undefined), 2);
  1618. type_value(get, [_]) -> false; % Required value missing
  1619. type_value(get, _) -> true. % Field is supposed to be undefined
  1620. %% Get and set. Value supplied.
  1621. type_value(_, undefined, _) -> false; % Undefined type
  1622. type_value(_, [], undefined) -> true; % Ignored
  1623. type_value(_, [], _) -> false; % Value should not be supplied
  1624. type_value(Q, [Type], Value) -> % Required field, proceed
  1625. type_value_default(Q, Type, Value);
  1626. type_value(set, Type, Value) -> % Required for setopts
  1627. type_value_default(set, Type, Value);
  1628. type_value(_, _, undefined) -> true; % Value should be undefined for
  1629. type_value(_, _, _) -> false. % other than setopts.
  1630. type_value_default(Q, [Type,Default], undefined) ->
  1631. type_value_1(Q, Type, Default);
  1632. type_value_default(Q, [Type,_], Value) ->
  1633. type_value_1(Q, Type, Value);
  1634. type_value_default(Q, Type, Value) ->
  1635. type_value_1(Q, Type, Value).
  1636. type_value_1(Q, {record,Types}, undefined) ->
  1637. type_value_record(Q, Types,
  1638. erlang:make_tuple(tuple_size(Types), undefined), 2);
  1639. type_value_1(Q, {record,Types}, Values)
  1640. when tuple_size(Types) =:= tuple_size(Values) ->
  1641. type_value_record(Q, Types, Values, 2);
  1642. type_value_1(Q, Types, Values)
  1643. when tuple_size(Types) =:= tuple_size(Values) ->
  1644. type_value_tuple(Q, Types, Values, 1);
  1645. type_value_1(_, Type, Value) ->
  1646. type_value_2(Type, Value).
  1647. type_value_tuple(Q, Types, Values, N)
  1648. when is_integer(N), N =< tuple_size(Types) ->
  1649. type_value(Q, element(N, Types), element(N, Values))
  1650. andalso type_value_tuple(Q, Types, Values, N+1);
  1651. type_value_tuple(_, _, _, _) -> true.
  1652. type_value_record(Q, Types, Values, N)
  1653. when is_integer(N), N =< tuple_size(Types) ->
  1654. case type_value(Q, element(N, Types), element(N, Values)) of
  1655. true -> type_value_record(Q, Types, Values, N+1);
  1656. false ->
  1657. erlang:throw({type,{record,Q,Types,Values,N}})
  1658. end;
  1659. type_value_record(_, _, _, _) -> true.
  1660. %% Simple run-time type-checking of (option) values: type -vs- value:
  1661. %% NB: the LHS is the TYPE, not the option name!
  1662. %%
  1663. %% Returns true | false | throw(ErrorReason) only for record types
  1664. %%
  1665. type_value_2(undefined, _) -> false;
  1666. %%
  1667. type_value_2(bool, true) -> true;
  1668. type_value_2(bool, false) -> true;
  1669. type_value_2(bool8, true) -> true;
  1670. type_value_2(bool8, false) -> true;
  1671. type_value_2(int, X) when is_integer(X) -> true;
  1672. type_value_2(uint, X) when is_integer(X), X >= 0 -> true;
  1673. type_value_2(uint32, X) when X band 16#ffffffff =:= X -> true;
  1674. type_value_2(uint24, X) when X band 16#ffffff =:= X -> true;
  1675. type_value_2(uint16, X) when X band 16#ffff =:= X -> true;
  1676. type_value_2(uint8, X) when X band 16#ff =:= X -> true;
  1677. type_value_2(time, infinity) -> true;
  1678. type_value_2(time, X) when is_integer(X), X >= 0 -> true;
  1679. type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true;
  1680. %%
  1681. type_value_2(addr, {any,Port}) ->
  1682. type_value_2(uint16, Port);
  1683. type_value_2(addr, {loopback,Port}) ->
  1684. type_value_2(uint16, Port);
  1685. type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 4 ->
  1686. type_value_2(addr, {inet,Addr});
  1687. type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 8 ->
  1688. type_value_2(addr, {inet6,Addr});
  1689. type_value_2(addr, {Local,_}) when is_list(Local); is_binary(Local) ->
  1690. type_value_2(addr, {local,Local});
  1691. %%
  1692. type_value_2(addr, {Family,{Tag,Port}})
  1693. when (Family =:= inet orelse Family =:= inet6) andalso
  1694. (Tag =:= any orelse Tag =:= loopback) ->
  1695. type_value_2(uint16, Port);
  1696. type_value_2(addr, {inet,{{A,B,C,D},Port}})
  1697. when ?ip(A,B,C,D) ->
  1698. type_value_2(uint16, Port);
  1699. type_value_2(addr, {inet6,{{A,B,C,D,E,F,G,H},Port}})
  1700. when ?ip6(A,B,C,D,E,F,G,H) ->
  1701. type_value_2(uint16, Port);
  1702. type_value_2(addr, {local,Addr}) ->
  1703. if
  1704. is_binary(Addr) ->
  1705. byte_size(Addr) =< 255;
  1706. true ->
  1707. try
  1708. %% We either get a badarg from byte_size
  1709. %% or from characters_to_binary
  1710. byte_size(
  1711. unicode:characters_to_binary(
  1712. Addr, file:native_name_encoding()))
  1713. of
  1714. N when N =< 255 ->
  1715. true;
  1716. _ ->
  1717. false
  1718. catch error:badarg ->
  1719. false
  1720. end
  1721. end;
  1722. %%
  1723. type_value_2(ether,[X1,X2,X3,X4,X5,X6])
  1724. when ?ether(X1,X2,X3,X4,X5,X6) -> true;
  1725. type_value_2({enum,List}, Enum) ->
  1726. case enum_val(Enum, List) of
  1727. {value,_} -> true;
  1728. false -> false
  1729. end;
  1730. type_value_2(sockaddr, Addr) ->
  1731. case Addr of
  1732. any -> true;
  1733. loopback -> true;
  1734. {A,B,C,D} when ?ip(A,B,C,D) -> true;
  1735. {A,B,C,D,E,F,G,H} when ?ip6(A,B,C,D,E,F,G,H) -> true;
  1736. _ -> false
  1737. end;
  1738. type_value_2(linkaddr, Addr) when is_list(Addr) ->
  1739. case len(Addr, 32768) of
  1740. undefined -> false;
  1741. _ -> true
  1742. end;
  1743. type_value_2({bitenumlist,List}, EnumList) ->
  1744. case enum_vals(EnumList, List) of
  1745. Ls when is_list(Ls) -> true;
  1746. false -> false
  1747. end;
  1748. type_value_2({bitenumlist,List,_}, EnumList) ->
  1749. case enum_vals(EnumList, List) of
  1750. Ls when is_list(Ls) -> true;
  1751. false -> false
  1752. end;
  1753. type_value_2(binary,Bin)
  1754. when is_binary(Bin), byte_size(Bin) < (1 bsl 32) -> true;
  1755. type_value_2(binary_or_uint,Bin)
  1756. when is_binary(Bin), byte_size(Bin) < (1 bsl 32) -> true;
  1757. type_value_2(binary_or_uint,Int)
  1758. when is_integer(Int), Int >= 0 -> true;
  1759. %% Type-checking of SCTP options
  1760. type_value_2(sctp_assoc_id, X)
  1761. when X band 16#ffffffff =:= X -> true;
  1762. type_value_2(_, _) -> false.
  1763. %% Get. No supplied value.
  1764. %%
  1765. %% These two clauses cannot happen since they are only used
  1766. %% in record fields - from record fields they must have a
  1767. %% value though it might be 'undefined', so record fields
  1768. %% calls enc_value/3, not enc_value/2.
  1769. %% enc_value(get, []) -> []; % Ignored
  1770. %% enc_value(get, [[Type,Default]]) -> % Required field, default value
  1771. %% enc_value(get, Type, Default);
  1772. enc_value(get, [{record,Types}]) -> % Implied default value for record
  1773. enc_value_tuple(get, Types,
  1774. erlang:make_tuple(tuple_size(Types), undefined), 2);
  1775. enc_value(get, _) -> [].
  1776. %% Get and set
  1777. enc_value(_, [], _) -> []; % Ignored
  1778. enc_value(Q, [Type], Value) -> % Required field, proceed
  1779. enc_value_default(Q, Type, Value);
  1780. enc_value(set, Type, Value) -> % Required for setopts
  1781. enc_value_default(set, Type, Value);
  1782. enc_value(_, _, _) -> []. % Not encoded for other than setopts
  1783. enc_value_default(Q, [Type,Default], undefined) ->
  1784. enc_value_1(Q, Type, Default);
  1785. enc_value_default(Q, [Type,_], Value) ->
  1786. enc_value_1(Q, Type, Value);
  1787. enc_value_default(Q, Type, Value) ->
  1788. enc_value_1(Q, Type, Value).
  1789. enc_value_1(Q, {record,Types}, undefined) ->
  1790. enc_value_tuple(Q, Types,
  1791. erlang:make_tuple(tuple_size(Types), undefined), 2);
  1792. enc_value_1(Q, {record,Types}, Values)
  1793. when tuple_size(Types) =:= tuple_size(Values) ->
  1794. enc_value_tuple(Q, Types, Values, 2);
  1795. enc_value_1(Q, Types, Values) when tuple_size(Types) =:= tuple_size(Values) ->
  1796. enc_value_tuple(Q, Types, Values, 1);
  1797. enc_value_1(_, Type, Value) ->
  1798. enc_value_2(Type, Value).
  1799. enc_value_tuple(Q, Types, Values, N)
  1800. when is_integer(N), N =< tuple_size(Types) ->
  1801. [enc_value(Q, element(N, Types), element(N, Values))
  1802. |enc_value_tuple(Q, Types, Values, N+1)];
  1803. enc_value_tuple(_, _, _, _) -> [].
  1804. %%
  1805. %% Encoding of option VALUES:
  1806. %%
  1807. enc_value_2(bool, true) -> [0,0,0,1];
  1808. enc_value_2(bool, false) -> [0,0,0,0];
  1809. enc_value_2(bool8, true) -> [1];
  1810. enc_value_2(bool8, false) -> [0];
  1811. enc_value_2(int, Val) -> ?int32(Val);
  1812. enc_value_2(uint, Val) -> ?int32(Val);
  1813. enc_value_2(uint32, Val) -> ?int32(Val);
  1814. enc_value_2(uint24, Val) -> ?int24(Val);
  1815. enc_value_2(uint16, Val) -> ?int16(Val);
  1816. enc_value_2(uint8, Val) -> ?int8(Val);
  1817. enc_value_2(time, infinity) -> ?int32(-1);
  1818. enc_value_2(time, Val) -> ?int32(Val);
  1819. enc_value_2(ip,{A,B,C,D}) -> [A,B,C,D];
  1820. enc_value_2(ip, any) -> [0,0,0,0];
  1821. enc_value_2(ip, loopback) -> [127,0,0,1];
  1822. %%
  1823. enc_value_2(addr, {any,Port}) ->
  1824. [?INET_AF_ANY|?int16(Port)];
  1825. enc_value_2(addr, {loopback,Port}) ->
  1826. [?INET_AF_LOOPBACK|?int16(Port)];
  1827. enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 ->
  1828. [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
  1829. enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 ->
  1830. [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
  1831. enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) ->
  1832. [?INET_AF_LOCAL,iolist_size(File)|File];
  1833. %%
  1834. enc_value_2(addr, {inet,{any,Port}}) ->
  1835. [?INET_AF_INET,?int16(Port),0,0,0,0];
  1836. enc_value_2(addr, {inet,{loopback,Port}}) ->
  1837. [?INET_AF_INET,?int16(Port),127,0,0,1];
  1838. enc_value_2(addr, {inet,{IP,Port}}) ->
  1839. [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
  1840. enc_value_2(addr, {inet6,{any,Port}}) ->
  1841. [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0];
  1842. enc_value_2(addr, {inet6,{loopback,Port}}) ->
  1843. [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1];
  1844. enc_value_2(addr, {inet6,{IP,Port}}) ->
  1845. [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
  1846. enc_value_2(addr, {local,Addr}) ->
  1847. %% A binary is passed as is, but anything else will be
  1848. %% regarded as a filename and therefore encoded according to
  1849. %% the current system filename encoding mode.
  1850. Bin =
  1851. if
  1852. is_binary(Addr) ->
  1853. Addr;
  1854. true ->
  1855. unicode:characters_to_binary(
  1856. Addr, file:native_name_encoding())
  1857. end,
  1858. [?INET_AF_LOCAL,byte_size(Bin),Bin];
  1859. %%
  1860. enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs;
  1861. enc_value_2(sockaddr, any) ->
  1862. [?INET_AF_ANY];
  1863. enc_value_2(sockaddr, loopback) ->
  1864. [?INET_AF_LOOPBACK];
  1865. enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 ->
  1866. [?INET_AF_INET|ip4_to_bytes(IP)];
  1867. enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 ->
  1868. [?INET_AF_INET6|ip6_to_bytes(IP)];
  1869. enc_value_2(linkaddr, Linkaddr) ->
  1870. [?int16(length(Linkaddr)),Linkaddr];
  1871. enc_value_2(sctp_assoc_id, Val) -> ?int32(Val);
  1872. %% enc_value_2(sctp_assoc_id, Bin) -> [byte_size(Bin),Bin];
  1873. enc_value_2({enum,List}, Enum) ->
  1874. {value,Val} = enum_val(Enum, List),
  1875. ?int32(Val);
  1876. enc_value_2({bitenumlist,List}, EnumList) ->
  1877. Vs = enum_vals(EnumList, List),
  1878. Val = borlist(Vs, 0),
  1879. ?int32(Val);
  1880. enc_value_2({bitenumlist,List,Type}, EnumList) ->
  1881. Vs = enum_vals(EnumList, List),
  1882. Value = borlist(Vs, 0),
  1883. enc_value_2(Type, Value);
  1884. enc_value_2(binary,Bin) -> [?int32(byte_size(Bin)),Bin];
  1885. enc_value_2(binary_or_uint,Datum) when is_binary(Datum) ->
  1886. [1,enc_value_2(binary, Datum)];
  1887. enc_value_2(binary_or_uint,Datum) when is_integer(Datum) ->
  1888. [0,enc_value_2(uint, Datum)].
  1889. %%
  1890. %% Decoding of option VALUES receved from "getopt":
  1891. %% NOT required for SCTP, as it always returns ready terms, not lists:
  1892. %%
  1893. dec_value(bool, [0,0,0,0|T]) -> {false,T};
  1894. dec_value(bool, [_,_,_,_|T]) -> {true,T};
  1895. %% Currently not used i.e only used by SCTP that does not dec_value/2
  1896. %% dec_value(bool8, [0|T]) -> {false,T};
  1897. %% dec_value(bool8, [_|T]) -> {true,T};
  1898. dec_value(int, [X3,X2,X1,X0|T]) -> {?i32(X3,X2,X1,X0),T};
  1899. dec_value(uint, [X3,X2,X1,X0|T]) -> {?u32(X3,X2,X1,X0),T};
  1900. %% Currently not used i.e only used by SCTP that does not dec_value/2
  1901. %% dec_value(uint32, [X3,X2,X1,X0|T]) -> {?u32(X3,X2,X1,X0),T};
  1902. %% dec_value(uint24, [X2,X1,X0|T]) -> {?u24(X2,X1,X0),T};
  1903. %% dec_value(uint16, [X1,X0|T]) -> {?u16(X1,X0),T};
  1904. %% dec_value(uint8, [X0|T]) -> {?u8(X0),T};
  1905. dec_value(time, [X3,X2,X1,X0|T]) ->
  1906. case ?i32(X3,X2,X1,X0) of
  1907. -1 -> {infinity, T};
  1908. Val -> {Val, T}
  1909. end;
  1910. dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T};
  1911. %% dec_value(ether, [X1,X2,X3,X4,X5,X6|T]) -> {[X1,X2,X3,X4,X5,X6],T};
  1912. dec_value(sockaddr, [X|T]) ->
  1913. get_ip(X, T);
  1914. dec_value(linkaddr, [X1,X0|T]) ->
  1915. split(?i16(X1,X0), T);
  1916. dec_value({enum,List}, [X3,X2,X1,X0|T]) ->
  1917. Val = ?i32(X3,X2,X1,X0),
  1918. case enum_name(Val, List) of
  1919. {name, Enum} -> {Enum, T};
  1920. _ -> {undefined, T}
  1921. end;
  1922. dec_value({bitenumlist,List}, [X3,X2,X1,X0|T]) ->
  1923. Val = ?i32(X3,X2,X1,X0),
  1924. {enum_names(Val, List), T};
  1925. %% Currently not used i.e only used by SCTP that does not dec_value/2
  1926. %% dec_value({bitenumlist,List,Type}, T0) ->
  1927. %% {Val,T} = dec_value(Type, T0),
  1928. %% {enum_names(Val, List), T};
  1929. dec_value(binary,[L0,L1,L2,L3|List]) ->
  1930. Len = ?i32(L0,L1,L2,L3),
  1931. {X,T}=split(Len,List),
  1932. {list_to_binary(X),T};
  1933. dec_value(opts, [L0,L1,L2,L3|List]) ->
  1934. Len = ?u32(L0,L1,L2,L3),
  1935. {X,T} = split(Len, List),
  1936. Opts = dec_opt_val(X),
  1937. {Opts,T};
  1938. dec_value(Types, List) when is_tuple(Types) ->
  1939. {L,T} = dec_value_tuple(Types, List, 1, []),
  1940. {list_to_tuple(L),T};
  1941. dec_value(Type, Val) ->
  1942. erlang:error({decode,Type,Val}).
  1943. %% dec_value(_, B) ->
  1944. %% {undefined, B}.
  1945. dec_value_tuple(Types, List, N, Acc)
  1946. when is_integer(N), N =< tuple_size(Types) ->
  1947. {Term,Tail} = dec_value(element(N, Types), List),
  1948. dec_value_tuple(Types, Tail, N+1, [Term|Acc]);
  1949. dec_value_tuple(_, List, _, Acc) ->
  1950. {rev(Acc),List}.
  1951. borlist([V|Vs], Value) ->
  1952. borlist(Vs, V bor Value);
  1953. borlist([], Value) -> Value.
  1954. enum_vals([Enum|Es], List) ->
  1955. case enum_val(Enum, List) of
  1956. false -> false;
  1957. {value,Value} -> [Value | enum_vals(Es, List)]
  1958. end;
  1959. enum_vals([], _) -> [].
  1960. enum_names(Val, [{Enum,BitVal} |List]) ->
  1961. if Val band BitVal =:= BitVal ->
  1962. [Enum | enum_names(Val, List)];
  1963. true ->
  1964. enum_names(Val, List)
  1965. end;
  1966. enum_names(_, []) -> [].
  1967. enum_val(Enum, [{Enum,Value}|_]) -> {value,Value};
  1968. enum_val(Enum, [_|List]) -> enum_val(Enum, List);
  1969. enum_val(_, []) -> false.
  1970. enum_name(Val, [{Enum,Val}|_]) -> {name,Enum};
  1971. enum_name(Val, [_|List]) -> enum_name(Val, List);
  1972. enum_name(_, []) -> false.
  1973. %% Encoding for setopts
  1974. %%
  1975. %% encode opt/val REVERSED since options are stored in reverse order
  1976. %% i.e. the recent options first (we must process old -> new)
  1977. encode_opt_val(Opts) ->
  1978. try
  1979. enc_opt_val(Opts, [])
  1980. catch
  1981. Reason -> {error,Reason}
  1982. end.
  1983. %% {active, once} and {active, N} are specially optimized because they will
  1984. %% be used for every packet or every N packets, not only once when
  1985. %% initializing the socket. Measurements show that this optimization is
  1986. %% worthwhile.
  1987. enc_opt_val([{active,once}|Opts], Acc) ->
  1988. enc_opt_val(Opts, [<<?INET_LOPT_ACTIVE:8,?INET_ONCE:32>>|Acc]);
  1989. enc_opt_val([{active,N}|Opts], Acc) when is_integer(N), N < 32768, N >= -32768 ->
  1990. enc_opt_val(Opts, [<<?INET_LOPT_ACTIVE:8,?INET_MULTI:32,N:16>>|Acc]);
  1991. enc_opt_val([{raw,P,O,B}|Opts], Acc) ->
  1992. enc_opt_val(Opts, Acc, raw, {P,O,B});
  1993. enc_opt_val([{Opt,Val}|Opts], Acc) ->
  1994. enc_opt_val(Opts, Acc, Opt, Val);
  1995. enc_opt_val([binary|Opts], Acc) ->
  1996. enc_opt_val(Opts, Acc, mode, binary);
  1997. enc_opt_val([list|Opts], Acc) ->
  1998. enc_opt_val(Opts, Acc, mode, list);
  1999. enc_opt_val([_|_], _) -> {error,einval};
  2000. enc_opt_val([], Acc) -> {ok,Acc}.
  2001. enc_opt_val(Opts, Acc, Opt, Val) when is_atom(Opt) ->
  2002. Type = type_opt(set, Opt),
  2003. case type_value(set, Type, Val) of
  2004. true ->
  2005. enc_opt_val(Opts, [enc_opt(Opt),enc_value(set, Type, Val)|Acc]);
  2006. false -> {error,einval}
  2007. end;
  2008. enc_opt_val(_, _, _, _) -> {error,einval}.
  2009. %% Encoding for getopts
  2010. %%
  2011. %% "encode_opts" is for "getopt" only, not setopt". But it uses "enc_opt" which
  2012. %% is common for "getopt" and "setopt":
  2013. encode_opts(Opts) ->
  2014. try enc_opts(Opts) of
  2015. Buf -> {ok,Buf}
  2016. catch
  2017. Error -> {error,Error}
  2018. end.
  2019. % Raw options are a special case, they need to be rewritten to be properly
  2020. % handled and the types need checking even when querying.
  2021. enc_opts([{raw,P,O,S}|Opts]) ->
  2022. enc_opts(Opts, raw, {P,O,S});
  2023. enc_opts([{Opt,Val}|Opts]) ->
  2024. enc_opts(Opts, Opt, Val);
  2025. enc_opts([Opt|Opts]) ->
  2026. enc_opts(Opts, Opt);
  2027. enc_opts([]) -> [].
  2028. enc_opts(Opts, Opt) when is_atom(Opt) ->
  2029. Type = type_opt(get, Opt),
  2030. case type_value(get, Type) of
  2031. true ->
  2032. [enc_opt(Opt),enc_value(get, Type)|enc_opts(Opts)];
  2033. false ->
  2034. throw(einval)
  2035. end;
  2036. enc_opts(_, _) ->
  2037. throw(einval).
  2038. enc_opts(Opts, Opt, Val) when is_atom(Opt) ->
  2039. Type = type_opt(get, Opt),
  2040. case type_value(get, Type, Val) of
  2041. true ->
  2042. [enc_opt(Opt),enc_value(get, Type, Val)|enc_opts(Opts)];
  2043. false ->
  2044. throw(einval)
  2045. end;
  2046. enc_opts(_, _, _) ->
  2047. throw(einval).
  2048. %% Decoding of raw list data options
  2049. %%
  2050. decode_opt_val(Buf) ->
  2051. try dec_opt_val(Buf) of
  2052. Result -> {ok,Result}
  2053. catch
  2054. Error -> {error,Error}
  2055. end.
  2056. dec_opt_val([B|Buf]=BBuf) ->
  2057. case dec_opt(B) of
  2058. undefined ->
  2059. erlang:error({decode,BBuf});
  2060. Opt ->
  2061. Type = type_opt(dec, Opt),
  2062. dec_opt_val(Buf, Opt, Type)
  2063. end;
  2064. dec_opt_val([]) -> [].
  2065. dec_opt_val(Buf, raw, Type) ->
  2066. {{P,O,B},T} = dec_value(Type, Buf),
  2067. [{raw,P,O,B}|dec_opt_val(T)];
  2068. dec_opt_val(Buf, active, Type) ->
  2069. case dec_value(Type, Buf) of
  2070. {multi,[M0,M1|T]} ->
  2071. <<N:16>> = list_to_binary([M0,M1]),
  2072. [{active,N}|dec_opt_val(T)];
  2073. {Val,T} ->
  2074. [{active,Val}|dec_opt_val(T)]
  2075. end;
  2076. dec_opt_val(Buf, Opt, Type) ->
  2077. {Val,T} = dec_value(Type, Buf),
  2078. [{Opt,Val}|dec_opt_val(T)].
  2079. %% Pre-processing of options for chgopts
  2080. %%
  2081. %% Return list of option requests for getopts
  2082. %% for all options that containing 'undefined' record fields.
  2083. %%
  2084. need_template([{Opt,undefined}=OV|Opts]) when is_atom(Opt) ->
  2085. [OV|need_template(Opts)];
  2086. need_template([{Opt,Val}|Opts]) when is_atom(Opt) ->
  2087. case need_template(Val, 2) of
  2088. true ->
  2089. [{Opt,undefined}|need_template(Opts)];
  2090. false ->
  2091. need_template(Opts)
  2092. end;
  2093. need_template([_|Opts]) ->
  2094. need_template(Opts);
  2095. need_template([]) -> [].
  2096. %%
  2097. need_template(T, N) when is_integer(N), N =< tuple_size(T) ->
  2098. case element(N, T) of
  2099. undefined -> true;
  2100. _ ->
  2101. need_template(T, N+1)
  2102. end;
  2103. need_template(_, _) -> false.
  2104. %% Replace 'undefined' record fields in option values with values
  2105. %% from template records.
  2106. %%
  2107. merge_options([{Opt,undefined}|Opts], [{Opt,_}=T|Templates]) ->
  2108. [T|merge_options(Opts, Templates)];
  2109. merge_options([{Opt,Val}|Opts], [{Opt,Template}|Templates])
  2110. when is_atom(Opt), tuple_size(Val) >= 2 ->
  2111. Key = element(1, Val),
  2112. Size = tuple_size(Val),
  2113. if Size =:= tuple_size(Template), Key =:= element(1, Template) ->
  2114. %% is_record(Template, Key)
  2115. [{Opt,list_to_tuple([Key|merge_fields(Val, Template, 2)])}
  2116. |merge_options(Opts, Templates)];
  2117. true ->
  2118. throw({merge,Val,Template})
  2119. end;
  2120. merge_options([OptVal|Opts], Templates) ->
  2121. [OptVal|merge_options(Opts, Templates)];
  2122. merge_options([], []) -> [];
  2123. merge_options(Opts, Templates) ->
  2124. throw({merge,Opts,Templates}).
  2125. merge_fields(Opt, Template, N) when is_integer(N), N =< tuple_size(Opt) ->
  2126. case element(N, Opt) of
  2127. undefined ->
  2128. [element(N, Template)|merge_fields(Opt, Template, N+1)];
  2129. Val ->
  2130. [Val|merge_fields(Opt, Template, N+1)]
  2131. end;
  2132. merge_fields(_, _, _) -> [].
  2133. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2134. %%
  2135. %% handle interface options
  2136. %%
  2137. %%
  2138. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2139. type_ifopt(addr) -> sockaddr;
  2140. type_ifopt(broadaddr) -> sockaddr;
  2141. type_ifopt(dstaddr) -> sockaddr;
  2142. type_ifopt(mtu) -> int;
  2143. type_ifopt(netmask) -> sockaddr;
  2144. type_ifopt(flags) ->
  2145. {bitenumlist,
  2146. [{up, ?INET_IFF_UP},
  2147. {down, ?INET_IFF_DOWN},
  2148. {broadcast, ?INET_IFF_BROADCAST},
  2149. {no_broadcast, ?INET_IFF_NBROADCAST},
  2150. {loopback, ?INET_IFF_LOOPBACK},
  2151. {pointtopoint, ?INET_IFF_POINTTOPOINT},
  2152. {no_pointtopoint, ?INET_IFF_NPOINTTOPOINT},
  2153. {running, ?INET_IFF_RUNNING},
  2154. {multicast, ?INET_IFF_MULTICAST}]};
  2155. type_ifopt(hwaddr) -> linkaddr;
  2156. type_ifopt(Opt) when is_atom(Opt) -> undefined.
  2157. enc_ifopt(addr) -> ?INET_IFOPT_ADDR;
  2158. enc_ifopt(broadaddr) -> ?INET_IFOPT_BROADADDR;
  2159. enc_ifopt(dstaddr) -> ?INET_IFOPT_DSTADDR;
  2160. enc_ifopt(mtu) -> ?INET_IFOPT_MTU;
  2161. enc_ifopt(netmask) -> ?INET_IFOPT_NETMASK;
  2162. enc_ifopt(flags) -> ?INET_IFOPT_FLAGS;
  2163. enc_ifopt(hwaddr) -> ?INET_IFOPT_HWADDR;
  2164. enc_ifopt(Opt) when is_atom(Opt) -> -1.
  2165. dec_ifopt(?INET_IFOPT_ADDR) -> addr;
  2166. dec_ifopt(?INET_IFOPT_BROADADDR) -> broadaddr;
  2167. dec_ifopt(?INET_IFOPT_DSTADDR) -> dstaddr;
  2168. dec_ifopt(?INET_IFOPT_MTU) -> mtu;
  2169. dec_ifopt(?INET_IFOPT_NETMASK) -> netmask;
  2170. dec_ifopt(?INET_IFOPT_FLAGS) -> flags;
  2171. dec_ifopt(?INET_IFOPT_HWADDR) -> hwaddr;
  2172. dec_ifopt(I) when is_integer(I) -> undefined.
  2173. %% decode if options returns a reversed list
  2174. decode_ifopts([B | Buf], Acc) ->
  2175. case dec_ifopt(B) of
  2176. undefined ->
  2177. {error, einval};
  2178. Opt ->
  2179. {Val,T} = dec_value(type_ifopt(Opt), Buf),
  2180. decode_ifopts(T, [{Opt,Val} | Acc])
  2181. end;
  2182. decode_ifopts(_,Acc) -> {ok,Acc}.
  2183. %% encode if options return a reverse list
  2184. encode_ifopts([Opt|Opts], Acc) ->
  2185. case enc_ifopt(Opt) of
  2186. -1 -> {error,einval};
  2187. B -> encode_ifopts(Opts,[B|Acc])
  2188. end;
  2189. encode_ifopts([],Acc) -> {ok,Acc}.
  2190. %% encode if options return a reverse list
  2191. encode_ifopt_val([{Opt,Val}|Opts], Buf) ->
  2192. Type = type_ifopt(Opt),
  2193. try type_value(set, Type, Val) of
  2194. true ->
  2195. encode_ifopt_val(Opts,
  2196. [Buf,enc_ifopt(Opt),enc_value(set, Type, Val)]);
  2197. false -> {error,einval}
  2198. catch
  2199. Reason -> {error,Reason}
  2200. end;
  2201. encode_ifopt_val([], Buf) -> {ok,Buf}.
  2202. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2203. %%
  2204. %% handle subscribe options
  2205. %%
  2206. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2207. encode_subs(L) ->
  2208. try enc_subs(L) of
  2209. Result -> {ok,Result}
  2210. catch
  2211. Error -> {error,Error}
  2212. end.
  2213. enc_subs([H|T]) ->
  2214. case H of
  2215. subs_empty_out_q -> [?INET_SUBS_EMPTY_OUT_Q|enc_subs(T)]%;
  2216. %%Dialyzer _ -> throw(einval)
  2217. end;
  2218. enc_subs([]) -> [].
  2219. decode_subs(Bytes) ->
  2220. try dec_subs(Bytes) of
  2221. Result -> {ok,Result}
  2222. catch
  2223. Error -> {error,Error}
  2224. end.
  2225. dec_subs([X,X3,X2,X1,X0|R]) ->
  2226. Val = ?u32(X3,X2,X1,X0),
  2227. case X of
  2228. ?INET_SUBS_EMPTY_OUT_Q -> [{subs_empty_out_q,Val}|dec_subs(R)];
  2229. _ -> throw(einval)
  2230. end;
  2231. dec_subs([]) -> [].
  2232. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2233. %%
  2234. %% handle statictics options
  2235. %%
  2236. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2237. encode_stats(L) ->
  2238. try enc_stats(L) of
  2239. Result -> {ok,Result}
  2240. catch
  2241. Error -> {error,Error}
  2242. end.
  2243. enc_stats([H|T]) ->
  2244. case H of
  2245. recv_cnt -> [?INET_STAT_RECV_CNT |enc_stats(T)];
  2246. recv_max -> [?INET_STAT_RECV_MAX |enc_stats(T)];
  2247. recv_avg -> [?INET_STAT_RECV_AVG |enc_stats(T)];
  2248. recv_dvi -> [?INET_STAT_RECV_DVI |enc_stats(T)];
  2249. send_cnt -> [?INET_STAT_SEND_CNT |enc_stats(T)];
  2250. send_max -> [?INET_STAT_SEND_MAX |enc_stats(T)];
  2251. send_avg -> [?INET_STAT_SEND_AVG |enc_stats(T)];
  2252. send_pend -> [?INET_STAT_SEND_PEND|enc_stats(T)];
  2253. send_oct -> [?INET_STAT_SEND_OCT |enc_stats(T)];
  2254. recv_oct -> [?INET_STAT_RECV_OCT |enc_stats(T)];
  2255. _ -> throw(einval)
  2256. end;
  2257. enc_stats([]) -> [].
  2258. decode_stats(Bytes) ->
  2259. try dec_stats(Bytes) of
  2260. Result -> {ok,Result}
  2261. catch
  2262. Error -> {error,Error}
  2263. end.
  2264. dec_stats([?INET_STAT_SEND_OCT,X7,X6,X5,X4,X3,X2,X1,X0|R]) ->
  2265. Val = ?u64(X7,X6,X5,X4,X3,X2,X1,X0),
  2266. [{send_oct, Val}|dec_stats(R)];
  2267. dec_stats([?INET_STAT_RECV_OCT,X7,X6,X5,X4,X3,X2,X1,X0|R]) ->
  2268. Val = ?u64(X7,X6,X5,X4,X3,X2,X1,X0),
  2269. [{recv_oct, Val}|dec_stats(R)];
  2270. dec_stats([X,X3,X2,X1,X0|R]) ->
  2271. Val = ?u32(X3,X2,X1,X0),
  2272. case X of
  2273. ?INET_STAT_RECV_CNT -> [{recv_cnt,Val} |dec_stats(R)];
  2274. ?INET_STAT_RECV_MAX -> [{recv_max,Val} |dec_stats(R)];
  2275. ?INET_STAT_RECV_AVG -> [{recv_avg,Val} |dec_stats(R)];
  2276. ?INET_STAT_RECV_DVI -> [{recv_dvi,Val} |dec_stats(R)];
  2277. ?INET_STAT_SEND_CNT -> [{send_cnt,Val} |dec_stats(R)];
  2278. ?INET_STAT_SEND_MAX -> [{send_max,Val} |dec_stats(R)];
  2279. ?INET_STAT_SEND_AVG -> [{send_avg,Val} |dec_stats(R)];
  2280. ?INET_STAT_SEND_PEND -> [{send_pend,Val}|dec_stats(R)];
  2281. _ -> throw(einval)
  2282. end;
  2283. dec_stats([]) -> [].
  2284. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2285. %%
  2286. %% handle status options
  2287. %%
  2288. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2289. dec_status(Flags) ->
  2290. enum_names(Flags,
  2291. [
  2292. {busy, ?INET_F_BUSY},
  2293. %% {listening, ?INET_F_LST}, NOT USED ANY MORE
  2294. {accepting, ?INET_F_ACC},
  2295. {connecting, ?INET_F_CON},
  2296. {listen, ?INET_F_LISTEN},
  2297. {connected, ?INET_F_ACTIVE},
  2298. {bound, ?INET_F_BOUND},
  2299. {open, ?INET_F_OPEN}
  2300. ]).
  2301. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2302. %%
  2303. %% UTILS
  2304. %%
  2305. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2306. enc_time(Time) when Time < 0 -> [255,255,255,255];
  2307. enc_time(Time) -> ?int32(Time).
  2308. encode_ifname(Name) when is_atom(Name) -> encode_ifname(atom_to_list(Name));
  2309. encode_ifname(Name) ->
  2310. N = length(Name),
  2311. if N > 255 -> {error, einval};
  2312. true -> {ok,[N | Name]}
  2313. end.
  2314. build_ifaddrs(Cs) ->
  2315. build_ifaddrs(Cs, []).
  2316. %%
  2317. build_ifaddrs([], []) ->
  2318. [];
  2319. build_ifaddrs([0|Cs], Acc) ->
  2320. Name = utf8_to_characters(rev(Acc)),
  2321. {Opts,Rest} = build_ifaddrs_opts(Cs, []),
  2322. [{Name,Opts}|build_ifaddrs(Rest)];
  2323. build_ifaddrs([C|Cs], Acc) ->
  2324. build_ifaddrs(Cs, [C|Acc]).
  2325. build_ifaddrs_opts([0|Cs], Acc) ->
  2326. {rev(Acc),Cs};
  2327. build_ifaddrs_opts([C|Cs]=CCs, Acc) ->
  2328. case dec_ifopt(C) of
  2329. undefined ->
  2330. erlang:error(badarg, [CCs,Acc]);
  2331. Opt ->
  2332. Type = type_ifopt(Opt),
  2333. {Val,Rest} = dec_value(Type, Cs),
  2334. build_ifaddrs_opts(Rest, [{Opt,Val}|Acc])
  2335. end.
  2336. build_iflist(Cs) ->
  2337. build_iflist(Cs, [], []).
  2338. %% Turn a NULL separated list of chars into a list of strings, removing
  2339. %% duplicates.
  2340. build_iflist([0|L], Acc, [H|T]) ->
  2341. case rev(Acc) of
  2342. H -> build_iflist(L, [], [H|T]);
  2343. N -> build_iflist(L, [], [N,H|T])
  2344. end;
  2345. build_iflist([0|L], Acc, []) ->
  2346. build_iflist(L, [], [rev(Acc)]);
  2347. build_iflist([C|L], Acc, List) ->
  2348. build_iflist(L, [C|Acc], List);
  2349. build_iflist([], [], List) ->
  2350. rev(List);
  2351. build_iflist([], Acc, List) ->
  2352. build_iflist([0], Acc, List).
  2353. rev(L) -> rev(L,[]).
  2354. rev([C|L],Acc) -> rev(L,[C|Acc]);
  2355. rev([],Acc) -> Acc.
  2356. split(N, L) -> split(N, L, []).
  2357. split(0, L, R) when is_list(L) -> {rev(R),L};
  2358. split(N, [H|T], R) when is_integer(N), N > 0 -> split(N-1, T, [H|R]).
  2359. len(L, N) -> len(L, N, 0).
  2360. len([], N, C) when is_integer(N), N >= 0 -> C;
  2361. len(L, 0, _) when is_list(L) -> undefined;
  2362. len([_|L], N, C) when is_integer(N), N >= 0 -> len(L, N-1, C+1).
  2363. member(X, [X|_]) -> true;
  2364. member(X, [_|Xs]) -> member(X, Xs);
  2365. member(_, []) -> false.
  2366. %% Lookup tree that keeps key insert order
  2367. ktree_empty() -> {[],tree()}.
  2368. ktree_is_defined(Key, {_,T}) -> tree(T, Key, is_defined).
  2369. ktree_get(Key, {_,T}) -> tree(T, Key, get).
  2370. ktree_insert(Key, V, {Keys,T}) -> {[Key|Keys],tree(T, Key, {insert,V})}.
  2371. ktree_update(Key, V, {Keys,T}) -> {Keys,tree(T, Key, {update,V})}.
  2372. ktree_keys({Keys,_}) -> rev(Keys).
  2373. %% Simple lookup tree. Hash the key to get statistical balance.
  2374. %% Key is matched equal, not compared equal.
  2375. tree() -> nil.
  2376. tree(T, Key, Op) -> tree(T, Key, Op, erlang:phash2(Key)).
  2377. tree(nil, _, is_defined, _) -> false;
  2378. tree(nil, K, {insert,V}, _) -> {K,V,nil,nil};
  2379. tree({K,_,_,_}, K, is_defined, _) -> true;
  2380. tree({K,V,_,_}, K, get, _) -> V;
  2381. tree({K,_,L,R}, K, {update,V}, _) -> {K,V,L,R};
  2382. tree({K0,V0,L,R}, K, Op, H) ->
  2383. H0 = erlang:phash2(K0),
  2384. if H0 < H; H0 =:= H, K0 < K ->
  2385. if is_tuple(Op) ->
  2386. {K0,V0,tree(L, K, Op, H),R};
  2387. true ->
  2388. tree(L, K, Op, H)
  2389. end;
  2390. true ->
  2391. if is_tuple(Op) ->
  2392. {K0,V0,L,tree(R, K, Op, H)};
  2393. true ->
  2394. tree(R, K, Op, H)
  2395. end
  2396. end.
  2397. utf8_to_characters([]) -> [];
  2398. utf8_to_characters([B|Bs]=Arg) when (B band 16#FF) =:= B ->
  2399. if 16#F8 =< B ->
  2400. erlang:error(badarg, [Arg]);
  2401. 16#F0 =< B ->
  2402. utf8_to_characters(Bs, B band 16#07, 3);
  2403. 16#E0 =< B ->
  2404. utf8_to_characters(Bs, B band 16#0F, 2);
  2405. 16#C0 =< B ->
  2406. utf8_to_characters(Bs, B band 16#1F, 1);
  2407. 16#80 =< B ->
  2408. erlang:error(badarg, [Arg]);
  2409. true ->
  2410. [B|utf8_to_characters(Bs)]
  2411. end.
  2412. %%
  2413. utf8_to_characters(Bs, U, 0) ->
  2414. [U|utf8_to_characters(Bs)];
  2415. utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B ->
  2416. utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1).
  2417. ip4_to_bytes({A,B,C,D}) ->
  2418. [A band 16#ff, B band 16#ff, C band 16#ff, D band 16#ff].
  2419. ip6_to_bytes({A,B,C,D,E,F,G,H}) ->
  2420. [?int16(A), ?int16(B), ?int16(C), ?int16(D),
  2421. ?int16(E), ?int16(F), ?int16(G), ?int16(H)].
  2422. get_addrs([]) ->
  2423. [];
  2424. get_addrs([F|Addrs]) ->
  2425. {Addr,Rest} = get_addr(F, Addrs),
  2426. [Addr|get_addrs(Rest)].
  2427. get_addr(?INET_AF_LOCAL, [N|Addr]) ->
  2428. {A,Rest} = split(N, Addr),
  2429. {{local,iolist_to_binary(A)},Rest};
  2430. get_addr(?INET_AF_UNSPEC, Rest) ->
  2431. {{unspec,<<>>},Rest};
  2432. get_addr(?INET_AF_UNDEFINED, Rest) ->
  2433. {{undefined,<<>>},Rest};
  2434. get_addr(Family, [P1,P0|Addr]) ->
  2435. {IP,Rest} = get_ip(Family, Addr),
  2436. {{IP,?u16(P1, P0)},Rest}.
  2437. get_ip(?INET_AF_INET, Addr) ->
  2438. get_ip4(Addr);
  2439. get_ip(?INET_AF_INET6, Addr) ->
  2440. get_ip6(Addr).
  2441. get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}.
  2442. get_ip6([X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16 | T]) ->
  2443. { { ?u16(X1,X2),?u16(X3,X4),?u16(X5,X6),?u16(X7,X8),
  2444. ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)},
  2445. T }.
  2446. -define(ERTS_INET_DRV_CONTROL_MAGIC_NUMBER, 16#03f1a300).
  2447. %% Control command
  2448. ctl_cmd(Port, Cmd, Args) ->
  2449. ?DBG_FORMAT("prim_inet:ctl_cmd(~p, ~p, ~p)~n", [Port,Cmd,Args]),
  2450. Result =
  2451. try erlang:port_control(Port, Cmd+?ERTS_INET_DRV_CONTROL_MAGIC_NUMBER, Args) of
  2452. [?INET_REP_OK|Reply] -> {ok,Reply};
  2453. [?INET_REP] -> inet_reply;
  2454. [?INET_REP_ERROR|Err] -> {error,list_to_atom(Err)}
  2455. catch
  2456. error:_ -> {error,einval}
  2457. end,
  2458. ?DBG_FORMAT("prim_inet:ctl_cmd() -> ~p~n", [Result]),
  2459. Result.