PageRenderTime 55ms 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

Large files files are truncated, but you can click here to view the full file

  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_

Large files files are truncated, but you can click here to view the full file