PageRenderTime 104ms CodeModel.GetById 25ms RepoModel.GetById 3ms app.codeStats 0ms

/erts/preloaded/src/prim_inet.erl

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