/erts/preloaded/src/prim_inet.erl
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
Large files files are truncated, but you can click here to view the full file
- %%
- %% %CopyrightBegin%
- %%
- %% Copyright Ericsson AB 2000-2017. All Rights Reserved.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%
- %% %CopyrightEnd%
- %%
- %% The SCTP protocol was added 2006
- %% by Leonid Timochouk <l.timochouk@gmail.com>
- %% and Serge Aleynikov <saleyn@gmail.com>
- %% at IDT Corp. Adapted by the OTP team at Ericsson AB.
- %%
- -module(prim_inet).
- %% Primitive inet_drv interface
- -export([open/3, open/4, fdopen/4, fdopen/5, close/1]).
- -export([bind/3, listen/1, listen/2, peeloff/2]).
- -export([connect/3, connect/4, async_connect/4]).
- -export([accept/1, accept/2, async_accept/2]).
- -export([shutdown/2]).
- -export([send/2, send/3, sendto/4, sendmsg/3, sendfile/4]).
- -export([recv/2, recv/3, async_recv/3]).
- -export([unrecv/2]).
- -export([recvfrom/2, recvfrom/3]).
- -export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]).
- -export([chgopt/3, chgopts/2]).
- -export([getstat/2, getfd/1, ignorefd/2,
- getindex/1, getstatus/1, gettype/1,
- getifaddrs/1, getiflist/1, ifget/3, ifset/3,
- gethostname/1]).
- -export([getservbyname/3, getservbyport/3]).
- -export([peername/1, setpeername/2, peernames/1, peernames/2]).
- -export([sockname/1, setsockname/2, socknames/1, socknames/2]).
- -export([attach/1, detach/1]).
- -include("inet_sctp.hrl").
- -include("inet_int.hrl").
- %-define(DEBUG, 1).
- -ifdef(DEBUG).
- -define(DBG_FORMAT(Format, Args), (io:format((Format), (Args)))).
- -else.
- -define(DBG_FORMAT(Format, Args), ok).
- -endif.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket) ->
- %% {ok, insock()} |
- %% {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- open(Protocol, Family, Type) ->
- open(Protocol, Family, Type, [], ?INET_REQ_OPEN, []).
- open(Protocol, Family, Type, Opts) ->
- open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []).
- %% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer())
- fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
- fdopen(Protocol, Family, Type, Fd, true).
- fdopen(Protocol, Family, Type, Fd, Bound)
- when is_integer(Fd), is_boolean(Bound) ->
- open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN,
- [?int32(Fd), enc_value_2(bool, Bound)]).
- open(Protocol, Family, Type, Opts, Req, Data) ->
- Drv = protocol2drv(Protocol),
- AF = enc_family(Family),
- T = enc_type(Type),
- try erlang:open_port({spawn_driver,Drv}, [binary]) of
- S ->
- case setopts(S, Opts) of
- ok ->
- case ctl_cmd(S, Req, [AF,T,Data]) of
- {ok,_} -> {ok,S};
- {error,_}=E1 ->
- close(S),
- E1
- end;
- {error,_}=E2 ->
- close(S),
- E2
- end
- catch
- %% The only (?) way to get here is to try to open
- %% the sctp driver when it does not exist (badarg)
- error:badarg -> {error, eprotonosupport};
- %% system_limit if out of port slots
- error:system_limit -> {error, system_limit}
- end.
- enc_family(inet) -> ?INET_AF_INET;
- enc_family(inet6) -> ?INET_AF_INET6;
- enc_family(local) -> ?INET_AF_LOCAL.
- enc_type(stream) -> ?INET_TYPE_STREAM;
- enc_type(dgram) -> ?INET_TYPE_DGRAM;
- enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET.
- protocol2drv(tcp) -> "tcp_inet";
- protocol2drv(udp) -> "udp_inet";
- protocol2drv(sctp) -> "sctp_inet".
- drv2protocol("tcp_inet") -> tcp;
- drv2protocol("udp_inet") -> udp;
- drv2protocol("sctp_inet") -> sctp;
- drv2protocol(_) -> undefined.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% Shutdown(insock(), atom()) -> ok
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% TODO: shutdown equivalent for SCTP
- %%
- shutdown(S, read) when is_port(S) ->
- shutdown_1(S, 0);
- shutdown(S, write) when is_port(S) ->
- shutdown_1(S, 1);
- shutdown(S, read_write) when is_port(S) ->
- shutdown_1(S, 2).
- shutdown_1(S, How) ->
- case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of
- {ok, []} -> ok;
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% CLOSE(insock()) -> ok
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- close(S) when is_port(S) ->
- case getopt(S, linger) of
- {ok,{true,0}} ->
- close_port(S);
- _ ->
- case subscribe(S, [subs_empty_out_q]) of
- {ok, [{subs_empty_out_q,N}]} when N > 0 ->
- close_pend_loop(S, N); %% wait for pending output to be sent
- _ ->
- close_port(S)
- end
- end.
- close_pend_loop(S, N) ->
- receive
- {empty_out_q,S} ->
- close_port(S)
- after ?INET_CLOSE_TIMEOUT ->
- case getstat(S, [send_pend]) of
- {ok, [{send_pend,N1}]} ->
- if
- N1 =:= N ->
- close_port(S);
- true ->
- close_pend_loop(S, N1)
- end;
- _ ->
- close_port(S)
- end
- end.
- close_port(S) ->
- catch erlang:port_close(S),
- receive {'EXIT',S,_} -> ok after 0 -> ok end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}
- %%
- %% bind the insock() to the interface address given by IP and Port
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
- %% If no addrs are specified, it just does nothing.
- %% Function returns {ok, S} on success, unlike TCP/UDP "bind":
- bind(S, add, Addrs) when is_port(S), is_list(Addrs) ->
- bindx(S, 1, Addrs);
- bind(S, remove, Addrs) when is_port(S), is_list(Addrs) ->
- bindx(S, 0, Addrs);
- bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 ->
- case type_value(set, addr, Addr) of
- true ->
- case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of
- {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
- {error, _} = Error -> Error
- end;
- false ->
- {error, einval}
- end;
- bind(S, IP, Port) ->
- bind(S, {IP, Port}, 0).
- bindx(S, AddFlag, Addrs) ->
- case getprotocol(S) of
- sctp ->
- case bindx_check_addrs(Addrs) of
- true ->
- %% Really multi-homed "bindx". Stringified args:
- %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
- Args =
- [?int8(AddFlag)|
- [enc_value(set, addr, Addr) || Addr <- Addrs]],
- case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
- {ok, _} -> {ok, S};
- {error, _}=Error -> Error
- end;
- false ->
- {error, einval}
- end;
- _ ->
- {error, einval}
- end.
- bindx_check_addrs([Addr|Addrs]) ->
- type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs);
- bindx_check_addrs([]) ->
- true.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason}
- %%
- %% connect the insock() to the address given by IP and Port
- %% if timeout is given:
- %% timeout < 0 -> infinity
- %% 0 -> immediate connect (mostly works for loopback)
- %% > 0 -> wait for timeout ms if not connected then
- %% return {error, timeout}
- %%
- %% ASYNC_CONNECT(insock(), IP, Port, Timeout) -> {ok, S, Ref} | {error, Reason}
- %%
- %% a {inet_async,S,Ref,Status} will be sent on socket condition
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% For TCP, UDP or SCTP sockets.
- %%
- connect(S, IP, Port) ->
- connect(S, IP, Port, infinity).
- %%
- connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
- case type_value(set, addr, Addr) of
- true when Time =:= infinity ->
- connect0(S, Addr, -1);
- true when is_integer(Time) ->
- connect0(S, Addr, Time);
- false ->
- {error, einval}
- end;
- connect(S, IP, Port, Time) ->
- connect(S, {IP, Port}, 0, Time).
- connect0(S, Addr, Time) ->
- case async_connect0(S, Addr, Time) of
- {ok, S, Ref} ->
- receive
- {inet_async, S, Ref, Status} ->
- Status
- end;
- Error -> Error
- end.
- async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
- case type_value(set, addr, Addr) of
- true when Time =:= infinity ->
- async_connect0(S, Addr, -1);
- true when is_integer(Time) ->
- async_connect0(S, Addr, Time);
- false ->
- {error, einval}
- end;
- %%
- async_connect(S, IP, Port, Time) ->
- async_connect(S, {IP, Port}, 0, Time).
- async_connect0(S, Addr, Time) ->
- case ctl_cmd(
- S, ?INET_REQ_CONNECT,
- [enc_time(Time),enc_value(set, addr, Addr)])
- of
- {ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
- {error, _}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% ACCEPT(insock() [,Timeout] ) -> {ok,insock()} | {error, Reason}
- %%
- %% accept incoming connection on listen socket
- %% if timeout is given:
- %% timeout < 0 -> infinity
- %% 0 -> immediate accept (poll)
- %% > 0 -> wait for timeout ms for accept if no accept then
- %% return {error, timeout}
- %%
- %% ASYNC_ACCEPT(insock(), Timeout)
- %%
- %% async accept. return {ok,S,Ref} or {error, Reason}
- %% the owner of socket S will receive an {inet_async,S,Ref,Status} on
- %% socket condition
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% For TCP sockets only.
- %%
- accept(L) -> accept0(L, -1).
- accept(L, infinity) -> accept0(L, -1);
- accept(L, Time) -> accept0(L, Time).
- accept0(L, Time) when is_port(L), is_integer(Time) ->
- case async_accept(L, Time) of
- {ok, Ref} ->
- receive
- {inet_async, L, Ref, {ok,S}} ->
- accept_opts(L, S);
- {inet_async, L, Ref, Error} ->
- Error
- end;
- Error -> Error
- end.
- %% setup options from listen socket on the connected socket
- accept_opts(L, S) ->
- case getopts(L, [active, nodelay, keepalive, delay_send, priority, tos]) of
- {ok, Opts} ->
- case setopts(S, Opts) of
- ok ->
- case getopts(L, [tclass]) of
- {ok, []} ->
- {ok, S};
- {ok, TClassOpts} ->
- case setopts(S, TClassOpts) of
- ok ->
- {ok, S};
- Error -> close(S), Error
- end
- end;
- Error -> close(S), Error
- end;
- Error ->
- close(S), Error
- end.
- async_accept(L, Time) ->
- case ctl_cmd(L,?INET_REQ_ACCEPT, [enc_time(Time)]) of
- {ok, [R1,R0]} -> {ok, ?u16(R1,R0)};
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% LISTEN(insock() [,Backlog]) -> ok | {error, Reason}
- %%
- %% set listen mode on socket
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% For TCP or SCTP sockets. For SCTP, Boolean backlog value (enable/disable
- %% listening) is also accepted:
- listen(S) -> listen(S, ?LISTEN_BACKLOG).
- listen(S, true) -> listen(S, ?LISTEN_BACKLOG);
- listen(S, false) -> listen(S, 0);
- listen(S, BackLog) when is_port(S), is_integer(BackLog) ->
- case ctl_cmd(S, ?INET_REQ_LISTEN, [?int16(BackLog)]) of
- {ok, _} -> ok;
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% PEELOFF(insock(), AssocId) -> {ok,outsock()} | {error, Reason}
- %%
- %% SCTP: Peel off one association into a type stream socket
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- peeloff(S, AssocId) ->
- case ctl_cmd(S, ?SCTP_REQ_PEELOFF, [?int32(AssocId)]) of
- inet_reply ->
- receive
- {inet_reply,S,Res} -> Res
- end;
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SEND(insock(), Data) -> ok | {error, Reason}
- %%
- %% send Data on the socket (io-list)
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% This is a generic "port_command" interface used by TCP, UDP, SCTP, depending
- %% on the driver it is mapped to, and the "Data". It actually sends out data,--
- %% NOT delegating this task to any back-end. For SCTP, this function MUST NOT
- %% be called directly -- use "sendmsg" instead:
- %%
- send(S, Data, OptList) when is_port(S), is_list(OptList) ->
- ?DBG_FORMAT("prim_inet:send(~p, ~p)~n", [S,Data]),
- try erlang:port_command(S, Data, OptList) of
- false -> % Port busy and nosuspend option passed
- ?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
- {error,busy};
- true ->
- receive
- {inet_reply,S,Status} ->
- ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Status]),
- Status
- end
- catch
- error:_Error ->
- ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
- {error,einval}
- end.
- send(S, Data) ->
- send(S, Data, []).
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SENDTO(insock(), IP, Port, Data) -> ok | {error, Reason}
- %%
- %% send Datagram to the IP at port (Should add sync send!)
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
- %% is known to be connected.
- sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
- case type_value(set, addr, Addr) of
- true ->
- ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
- try
- erlang:port_command(S, [enc_value(set, addr, Addr),Data])
- of
- true ->
- receive
- {inet_reply,S,Reply} ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> ~p~n", [Reply]),
- Reply
- end
- catch
- error:_ ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end;
- false ->
- ?DBG_FORMAT(
- "prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end;
- sendto(S, IP, Port, Data) ->
- sendto(S, {IP, Port}, 0, Data).
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SENDMSG(insock(), IP, Port, InitMsg, Data) or
- %% SENDMSG(insock(), SndRcvInfo, Data) -> ok | {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% SCTP: Sending data over an existing association: no need for a destination
- %% addr; uses SndRcvInfo:
- %%
- sendmsg(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) ->
- Type = type_opt(set, sctp_default_send_param),
- try type_value(set, Type, SRI) of
- true ->
- send(S, [enc_value(set, Type, SRI)|Data]);
- false -> {error,einval}
- catch
- Reason -> {error,Reason}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SENDFILE(outsock(), Fd, Offset, Length) -> {ok,BytesSent} | {error, Reason}
- %%
- %% send Length data bytes from a file handle, to a socket, starting at Offset
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% "sendfile" is for TCP:
- sendfile(S, FileHandle, Offset, Length)
- when not is_port(S);
- not is_binary(FileHandle);
- not is_integer(Offset);
- not is_integer(Length) ->
- {error, badarg};
- sendfile(S, FileHandle, Offset, Length) ->
- case erlang:port_info(S, connected) of
- {connected, Pid} when Pid =:= self() ->
- sendfile_1(S, FileHandle, Offset, Length);
- {connected, Pid} when Pid =/= self() ->
- {error, not_owner};
- _Other ->
- {error, einval}
- end.
- sendfile_1(S, FileHandle, Offset, 0) ->
- sendfile_1(S, FileHandle, Offset, (1 bsl 63) - 1);
- sendfile_1(_S, _FileHandle, Offset, Length) when
- Offset < 0; Offset > ((1 bsl 63) - 1);
- Length < 0; Length > ((1 bsl 63) - 1) ->
- {error, einval};
- sendfile_1(S, FileHandle, Offset, Length) ->
- Args = [FileHandle,
- ?int64(Offset),
- ?int64(Length)],
- case ctl_cmd(S, ?TCP_REQ_SENDFILE, Args) of
- {ok, []} ->
- receive
- {sendfile, S, {ok, SentLow, SentHigh}} ->
- {ok, SentLow bor (SentHigh bsl 32)};
- {sendfile, S, {error, Reason}} ->
- {error, Reason};
- {'EXIT', S, _Reason} ->
- {error, closed}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% RECV(insock(), Length, [Timeout]) -> {ok,Data} | {error, Reason}
- %%
- %% receive Length data bytes from a socket
- %% if 0 is given then a Data packet is requested (see setopt (packet))
- %% N read N bytes
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% "recv" is for TCP:
- recv(S, Length) -> recv0(S, Length, -1).
- recv(S, Length, infinity) -> recv0(S, Length,-1);
- recv(S, Length, Time) when is_integer(Time) -> recv0(S, Length, Time).
- recv0(S, Length, Time) when is_port(S), is_integer(Length), Length >= 0 ->
- case async_recv(S, Length, Time) of
- {ok, Ref} ->
- receive
- {inet_async, S, Ref, Status} -> Status;
- {'EXIT', S, _Reason} ->
- {error, closed}
- end;
- Error -> Error
- end.
-
- async_recv(S, Length, Time) ->
- case ctl_cmd(S, ?TCP_REQ_RECV, [enc_time(Time), ?int32(Length)]) of
- {ok,[R1,R0]} -> {ok, ?u16(R1,R0)};
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% RECVFROM(insock(), Lenth [Timeout]) -> {ok,{IP,Port,Data}} | {error, Reason}
- %% For SCTP: -> {ok,{IP,Port,[AncData],Data}}
- %% | {error, Reason}
- %% receive Length data bytes from a datagram socket sent from IP at Port
- %% if 0 is given then a Data packet is requested (see setopt (packet))
- %% N read N bytes
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% "recvfrom" is for both UDP and SCTP.
- %% NB: "Length" is actually ignored for these protocols, since they are msg-
- %% oriented: preserved here only for API compatibility.
- %%
- recvfrom(S, Length) ->
- recvfrom(S, Length, infinity).
- recvfrom(S, Length, infinity) when is_port(S) ->
- recvfrom0(S, Length, -1);
- recvfrom(S, Length, Time) when is_port(S) ->
- if
- is_integer(Time), 0 =< Time, Time < 16#ffffffff ->
- recvfrom0(S, Length, Time);
- true ->
- {error, einval}
- end.
- recvfrom0(S, Length, Time)
- when is_integer(Length), 0 =< Length, Length =< 16#ffffffff ->
- case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of
- {ok,[R1,R0]} ->
- Ref = ?u16(R1,R0),
- receive
- % Success, UDP:
- {inet_async, S, Ref, {ok, [F | AddrData]}} ->
- case get_addr(F, AddrData) of
- {{Family, _} = Addr, Data} when is_atom(Family) ->
- {ok, {Addr, 0, Data}};
- {{IP, Port}, Data} ->
- {ok, {IP, Port, Data}}
- end;
- % Success, SCTP:
- {inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} ->
- {IP, _} = get_ip(F, Addr),
- {ok, {IP, ?u16(P1, P0), AncData, DE}};
- % Back-end error:
- {inet_async, S, Ref, Error={error, _}} ->
- Error
- end;
- {error,_}=Error ->
- Error % Front-end error
- end;
- recvfrom0(_, _, _) -> {error,einval}.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% PEERNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- peername(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_PEER, []) of
- {ok, [F | Addr]} ->
- {A, _} = get_addr(F, Addr),
- {ok, A};
- {error, _} = Error -> Error
- end.
- setpeername(S, undefined) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
- {ok, []} -> ok;
- {error, _} = Error -> Error
- end;
- setpeername(S, Addr) when is_port(S) ->
- case type_value(set, addr, Addr) of
- true ->
- case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of
- {ok, []} -> ok;
- {error, _} = Error -> Error
- end;
- false ->
- {error, einval}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% PEERNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- peernames(S) when is_port(S) ->
- peernames(S, undefined).
- peernames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
- peernames(S, AssocId);
- peernames(S, AssocId)
- when is_port(S), is_integer(AssocId);
- is_port(S), AssocId =:= undefined ->
- Q = get,
- Type = [[sctp_assoc_id,0]],
- case type_value(Q, Type, AssocId) of
- true ->
- case ctl_cmd
- (S, ?INET_REQ_GETPADDRS,
- enc_value(Q, Type, AssocId)) of
- {ok,Addrs} ->
- {ok,get_addrs(Addrs)};
- Error ->
- Error
- end;
- false ->
- {error,einval}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SOCKNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- sockname(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_NAME, []) of
- {ok, [F | Addr]} ->
- {A, _} = get_addr(F, Addr),
- {ok, A};
- {error, _} = Error -> Error
- end.
- setsockname(S, undefined) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
- {ok, []} -> ok;
- {error, _} = Error -> Error
- end;
- setsockname(S, Addr) when is_port(S) ->
- case type_value(set, addr, Addr) of
- true ->
- case
- ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr))
- of
- {ok, []} -> ok;
- {error, _} = Error -> Error
- end;
- false ->
- {error, einval}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SOCKNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- socknames(S) when is_port(S) ->
- socknames(S, undefined).
- socknames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
- socknames(S, AssocId);
- socknames(S, AssocId)
- when is_port(S), is_integer(AssocId);
- is_port(S), AssocId =:= undefined ->
- Q = get,
- Type = [[sctp_assoc_id,0]],
- case type_value(Q, Type, AssocId) of
- true ->
- case ctl_cmd
- (S, ?INET_REQ_GETLADDRS,
- enc_value(Q, Type, AssocId)) of
- {ok,Addrs} ->
- {ok,get_addrs(Addrs)};
- Error ->
- Error
- end;
- false ->
- {error,einval}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% SETOPT(insock(), Opt, Value) -> ok | {error, Reason}
- %% SETOPTS(insock(), [{Opt,Value}]) -> ok | {error, Reason}
- %%
- %% set socket, ip and driver option
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- setopt(S, Opt, Value) when is_port(S) ->
- setopts(S, [{Opt,Value}]).
- setopts(S, Opts) when is_port(S) ->
- case encode_opt_val(Opts) of
- {ok, Buf} ->
- case ctl_cmd(S, ?INET_REQ_SETOPTS, Buf) of
- {ok, _} -> ok;
- {error,_}=Error -> Error
- end;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
- %% GETOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
- %% get socket, ip and driver option
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getopt(S, Opt) when is_port(S), is_atom(Opt) ->
- case getopts(S, [Opt]) of
- {ok,[{_,Value}]} -> {ok, Value};
- Error -> Error
- end.
- getopts(S, Opts) when is_port(S), is_list(Opts) ->
- case encode_opts(Opts) of
- {ok,Buf} ->
- case ctl_cmd(S, ?INET_REQ_GETOPTS, Buf) of
- {ok,Rep} ->
- %% Non-SCTP: "Rep" contains the encoded option vals:
- decode_opt_val(Rep);
- inet_reply ->
- %% SCTP: Need to receive the full value:
- receive
- {inet_reply,S,Res} -> Res
- end;
- {error,_}=Error -> Error
- end;
- Error -> Error
- end.
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% CHGOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
- %% CHGOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
- %% change socket, ip and driver option
- %%
- %% Same as setopts except for record value options where undefined
- %% fields are read with getopts before setting.
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- chgopt(S, Opt, Value) when is_port(S) ->
- chgopts(S, [{Opt,Value}]).
- chgopts(S, Opts) when is_port(S), is_list(Opts) ->
- case getopts(S, need_template(Opts)) of
- {ok,Templates} ->
- try merge_options(Opts, Templates) of
- NewOpts ->
- setopts(S, NewOpts)
- catch
- Reason -> {error,Reason}
- end;
- Error -> Error
- end.
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason}
- %%
- %% IfAddrsList = [{Name,[Opts]}]
- %% Name = string()
- %% Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr}
- %% | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()}
- %% Flag = up | broadcast | loopback | running | multicast
- %% Addr = ipv4addr() | ipv6addr()
- %% HwAddr = ethernet_addr()
- %%
- %% get interface name and addresses list
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getifaddrs(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
- {ok, Data} ->
- {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())};
- {error,enotsup} ->
- case getiflist(S) of
- {ok, IFs} ->
- {ok, getifaddrs_ifget(S, IFs)};
- Err1 -> Err1
- end;
- Err2 -> Err2
- end.
- %% Restructure interface properties per interface and remove duplicates
- comp_ifaddrs([{If,Opts}|IfOpts], T) ->
- case ktree_is_defined(If, T) of
- true ->
- OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts),
- comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T));
- false ->
- OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
- comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
- end;
- comp_ifaddrs([], T) ->
- [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
- comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
- case ktree_is_defined(Opt, OptSet) of
- true
- when element(1, Opt) =:= flags;
- element(1, Opt) =:= hwaddr ->
- comp_ifaddrs_add(OptSet, Opts);
- _ ->
- comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
- end;
- comp_ifaddrs_add(OptSet, []) -> OptSet.
- %% Legacy emulation of getifaddrs
- getifaddrs_ifget(_, []) -> [];
- getifaddrs_ifget(S, [IF|IFs]) ->
- case ifget(S, IF, [flags]) of
- {ok,[{flags,Flags}]=FlagsVals} ->
- BroadOpts =
- case member(broadcast, Flags) of
- true ->
- [broadaddr,hwaddr];
- false ->
- [hwaddr]
- end,
- P2POpts =
- case member(pointtopoint, Flags) of
- true ->
- [dstaddr|BroadOpts];
- false ->
- BroadOpts
- end,
- getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]);
- _ ->
- getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
- end.
- getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) ->
- OptVals =
- case ifget(S, IF, Opts) of
- {ok,OVs} -> OVs;
- _ -> []
- end,
- [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)].
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% getiflist(insock()) -> {ok,IfNameList} | {error, Reason}
- %%
- %% get interface name list
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getiflist(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_GETIFLIST, []) of
- {ok, Data} -> {ok, build_iflist(Data)};
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% ifget(insock(), IFOpts) -> {ok,IfNameList} | {error, Reason}
- %%
- %% get interface name list
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- ifget(S, Name, Opts) ->
- case encode_ifname(Name) of
- {ok, Buf1} ->
- case encode_ifopts(Opts,[]) of
- {ok, Buf2} ->
- case ctl_cmd(S, ?INET_REQ_IFGET, [Buf1,Buf2]) of
- {ok, Data} -> decode_ifopts(Data,[]);
- {error,_}=Error -> Error
- end;
- Error -> Error
- end;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% ifset(insock(), Name, IFOptVals) -> {ok,IfNameList} | {error, Reason}
- %%
- %% set interface parameters
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- ifset(S, Name, Opts) ->
- case encode_ifname(Name) of
- {ok, Buf1} ->
- case encode_ifopt_val(Opts,[]) of
- {ok, Buf2} ->
- case ctl_cmd(S, ?INET_REQ_IFSET, [Buf1,Buf2]) of
- {ok, _} -> ok;
- {error,_}=Error -> Error
- end;
- Error -> Error
- end;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% subscribe(insock(), SubsList) -> {ok,StatReply} | {error, Reason}
- %%
- %% Subscribe on socket events (from driver)
- %%
- %% Available event subscriptions:
- %% subs_empty_out_q: StatReply = [{subs_empty_out_q, N}], where N
- %% is current queue length. When the queue becomes empty
- %% a {empty_out_q, insock()} message will be sent to
- %% subscribing process and the subscription will be
- %% removed. If N = 0, the queue is empty and no
- %% subscription is made.
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- subscribe(S, Sub) when is_port(S), is_list(Sub) ->
- case encode_subs(Sub) of
- {ok, Bytes} ->
- case ctl_cmd(S, ?INET_REQ_SUBSCRIBE, Bytes) of
- {ok, Data} -> decode_subs(Data);
- {error,_}=Error -> Error
- end;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETSTAT(insock(), StatList) -> {ok,StatReply} | {error, Reason}
- %%
- %% get socket statistics (from driver)
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getstat(S, Stats) when is_port(S), is_list(Stats) ->
- case encode_stats(Stats) of
- {ok, Bytes} ->
- case ctl_cmd(S, ?INET_REQ_GETSTAT, Bytes) of
- {ok, Data} -> decode_stats(Data);
- {error,_}=Error -> Error
- end;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETFD(insock()) -> {ok,integer()} | {error, Reason}
- %%
- %% get internal file descriptor
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getfd(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_GETFD, []) of
- {ok, [S3,S2,S1,S0]} -> {ok, ?u32(S3,S2,S1,S0)};
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% IGNOREFD(insock(),boolean()) -> {ok,integer()} | {error, Reason}
- %%
- %% steal internal file descriptor
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- ignorefd(S,Bool) when is_port(S) ->
- Val = if Bool -> 1; true -> 0 end,
- case ctl_cmd(S, ?INET_REQ_IGNOREFD, [Val]) of
- {ok, _} -> ok;
- Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETIX(insock()) -> {ok,integer()} | {error, Reason}
- %%
- %% get internal socket index
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getindex(S) when is_port(S) ->
- %% NOT USED ANY MORE
- {error, einval}.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETTYPE(insock()) -> {ok,{Family,Type}} | {error, Reason}
- %%
- %% get family/type of a socket
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- gettype(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_GETTYPE, []) of
- {ok, [F3,F2,F1,F0,T3,T2,T1,T0]} ->
- Family = case ?u32(F3,F2,F1,F0) of
- ?INET_AF_INET -> inet;
- ?INET_AF_INET6 -> inet6;
- _ -> undefined
- end,
- Type = case ?u32(T3,T2,T1,T0) of
- ?INET_TYPE_STREAM -> stream;
- ?INET_TYPE_DGRAM -> dgram;
- ?INET_TYPE_SEQPACKET -> seqpacket;
- _ -> undefined
- end,
- {ok, {Family, Type}};
- {error,_}=Error -> Error
- end.
- getprotocol(S) when is_port(S) ->
- {name,Drv} = erlang:port_info(S, name),
- drv2protocol(Drv).
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% IS_SCTP(insock()) -> true | false
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% is_sctp(S) when is_port(S) ->
- %% case gettype(S) of
- %% {ok, {_, seqpacket}} -> true;
- %% _ -> false
- %% end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETSTATUS(insock()) -> {ok,Status} | {error, Reason}
- %%
- %% get socket status
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getstatus(S) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_GETSTATUS, []) of
- {ok, [S3,S2,S1,S0]} ->
- {ok, dec_status(?u32(S3,S2,S1,S0))};
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETHOSTNAME(insock()) -> {ok,HostName} | {error, Reason}
- %%
- %% get host name
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- gethostname(S) when is_port(S) ->
- ctl_cmd(S, ?INET_REQ_GETHOSTNAME, []).
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETSERVBYNAME(insock(),Name,Proto) -> {ok,Port} | {error, Reason}
- %%
- %% get service port
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_atom(Proto) ->
- getservbyname1(S, atom_to_list(Name), atom_to_list(Proto));
- getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_list(Proto) ->
- getservbyname1(S, atom_to_list(Name), Proto);
- getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_atom(Proto) ->
- getservbyname1(S, Name, atom_to_list(Proto));
- getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_list(Proto) ->
- getservbyname1(S, Name, Proto);
- getservbyname(_,_, _) ->
- {error, einval}.
- getservbyname1(S,Name,Proto) ->
- L1 = length(Name),
- L2 = length(Proto),
- if L1 > 255 -> {error, einval};
- L2 > 255 -> {error, einval};
- true ->
- case ctl_cmd(S, ?INET_REQ_GETSERVBYNAME, [L1,Name,L2,Proto]) of
- {ok, [P1,P0]} ->
- {ok, ?u16(P1,P0)};
- {error,_}=Error ->
- Error
- end
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% GETSERVBYPORT(insock(),Port,Proto) -> {ok,Port} | {error, Reason}
- %%
- %% get service port from portnumber and protocol
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- getservbyport(S,Port,Proto) when is_port(S), is_atom(Proto) ->
- getservbyport1(S, Port, atom_to_list(Proto));
- getservbyport(S,Port,Proto) when is_port(S), is_list(Proto) ->
- getservbyport1(S, Port, Proto);
- getservbyport(_, _, _) ->
- {error, einval}.
- getservbyport1(S,Port,Proto) ->
- L = length(Proto),
- if Port < 0 -> {error, einval};
- Port > 16#ffff -> {error, einval};
- L > 255 -> {error, einval};
- true ->
- case ctl_cmd(S, ?INET_REQ_GETSERVBYPORT, [?int16(Port),L,Proto]) of
- {ok, Name} -> {ok, Name};
- {error,_}=Error -> Error
- end
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% UNRECV(insock(), data) -> ok | {error, Reason}
- %%
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- unrecv(S, Data) ->
- case ctl_cmd(S, ?TCP_REQ_UNRECV, Data) of
- {ok, _} -> ok;
- {error,_}=Error -> Error
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% DETACH(insock()) -> ok
- %%
- %% unlink from a socket
- %%
- %% ATTACH(insock()) -> ok | {error, Reason}
- %%
- %% link and connect to a socket
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- detach(S) when is_port(S) ->
- unlink(S),
- ok.
- attach(S) when is_port(S) ->
- try erlang:port_connect(S, self()) of
- true -> link(S), ok
- catch
- error:Reason -> {error,Reason}
- end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%
- %% INTERNAL FUNCTIONS
- %%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- is_sockopt_val(Opt, Val) ->
- Type = type_opt(set, Opt),
- try type_value(set, Type, Val)
- catch
- _ -> false
- end.
- %%
- %% Socket options processing: Encoding option NAMES:
- %%
- enc_opt(reuseaddr) -> ?INET_OPT_REUSEADDR;
- enc_opt(keepalive) -> ?INET_OPT_KEEPALIVE;
- enc_opt(dontroute) -> ?INET_OPT_DONTROUTE;
- enc_opt(linger) -> ?INET_OPT_LINGER;
- enc_opt(broadcast) -> ?INET_OPT_BROADCAST;
- enc_opt(sndbuf) -> ?INET_OPT_SNDBUF;
- enc_opt(recbuf) -> ?INET_OPT_RCVBUF;
- enc_opt(priority) -> ?INET_OPT_PRIORITY;
- enc_opt(tos) -> ?INET_OPT_TOS;
- enc_opt(tclass) -> ?INET_OPT_TCLASS;
- enc_opt(nodelay) -> ?TCP_OPT_NODELAY;
- enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF;
- enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
- enc_opt(multicast_loop) -> ?UDP_OPT_MULTICAST_LOOP;
- enc_opt(add_membership) -> ?UDP_OPT_ADD_MEMBERSHIP;
- enc_opt(drop_membership) -> ?UDP_OPT_DROP_MEMBERSHIP;
- enc_opt(ipv6_v6only) -> ?INET_OPT_IPV6_V6ONLY;
- enc_opt(buffer) -> ?INET_LOPT_BUFFER;
- enc_opt(header) -> ?INET_LOPT_HEADER;
- enc_opt(active) -> ?INET_LOPT_ACTIVE;
- enc_opt(packet) -> ?INET_LOPT_PACKET;
- enc_opt(mode) -> ?INET_LOPT_MODE;
- enc_opt(deliver) -> ?INET_LOPT_DELIVER;
- enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE;
- enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK;
- enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK;
- enc_opt(high_msgq_watermark) -> ?INET_LOPT_MSGQ_HIWTRMRK;
- enc_opt(low_msgq_watermark) -> ?INET_LOPT_MSGQ_LOWTRMRK;
- enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT;
- enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
- enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND;
- enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE;
- enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS;
- enc_opt(netns) -> ?INET_LOPT_NETNS;
- enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET;
- enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM;
- enc_opt(raw) -> ?INET_OPT_RAW;
- enc_opt(bind_to_device) -> ?INET_OPT_BIND_TO_DEVICE;
- % Names of SCTP opts:
- enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO;
- enc_opt(sctp_associnfo) -> ?SCTP_OPT_ASSOCINFO;
- enc_opt(sctp_initmsg) -> ?SCTP_OPT_INITMSG;
- enc_opt(sctp_autoclose) -> ?SCTP_OPT_AUTOCLOSE;
- enc_opt(sctp_nodelay) -> ?SCTP_OPT_NODELAY;
- enc_opt(sctp_disable_fragments) -> ?SCTP_OPT_DISABLE_FRAGMENTS;
- enc_opt(sctp_i_want_mapped_v4_addr)-> ?SCTP_OPT_I_WANT_MAPPED_V4_ADDR;
- enc_opt(sctp_maxseg) -> ?SCTP_OPT_MAXSEG;
- enc_opt(sctp_set_peer_primary_addr)-> ?SCTP_OPT_SET_PEER_PRIMARY_ADDR;
- enc_opt(sctp_primary_addr) -> ?SCTP_OPT_PRIMARY_ADDR;
- enc_opt(sctp_adaptation_layer) -> ?SCTP_OPT_ADAPTATION_LAYER;
- enc_opt(sctp_peer_addr_params) -> ?SCTP_OPT_PEER_ADDR_PARAMS;
- enc_opt(sctp_default_send_param) -> ?SCTP_OPT_DEFAULT_SEND_PARAM;
- enc_opt(sctp_events) -> ?SCTP_OPT_EVENTS;
- enc_opt(sctp_delayed_ack_time) -> ?SCTP_OPT_DELAYED_ACK_TIME;
- enc_opt(sctp_status) -> ?SCTP_OPT_STATUS;
- enc_opt(sctp_get_peer_addr_info) -> ?SCTP_OPT_GET_PEER_ADDR_INFO.
- %%
- %%
- %% Decoding option NAMES:
- %%
- dec_opt(?INET_OPT_REUSEADDR) -> reuseaddr;
- dec_opt(?INET_OPT_KEEPALIVE) -> keepalive;
- dec_opt(?INET_OPT_DONTROUTE) -> dontroute;
- dec_opt(?INET_OPT_LINGER) -> linger;
- dec_opt(?INET_OPT_BROADCAST) -> broadcast;
- dec_opt(?INET_OPT_SNDBUF) -> sndbuf;
- dec_opt(?INET_OPT_RCVBUF) -> recbuf;
- dec_opt(?INET_OPT_PRIORITY) -> priority;
- dec_opt(?INET_OPT_TOS) -> tos;
- dec_opt(?INET_OPT_TCLASS) -> tclass;
- dec_opt(?TCP_OPT_NODELAY) -> nodelay;
- dec_opt(?UDP_OPT_MULTICAST_IF) -> multicast_if;
- dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl;
- dec_opt(?UDP_OPT_MULTICAST_LOOP) -> multicast_loop;
- dec_opt(?UDP_OPT_ADD_MEMBERSHIP) -> add_membership;
- dec_opt(?UDP_OPT_DROP_MEMBERSHIP) -> drop_membership;
- dec_opt(?INET_OPT_IPV6_V6ONLY) -> ipv6_v6only;
- dec_opt(?INET_LOPT_BUFFER) -> buffer;
- dec_opt(?INET_LOPT_HEADER) -> header;
- dec_opt(?INET_LOPT_ACTIVE) -> active;
- dec_opt(?INET_LOPT_PACKET) -> packet;
- dec_opt(?INET_LOPT_MODE) -> mode;
- dec_opt(?INET_LOPT_DELIVER) -> deliver;
- dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close;
- dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark;
- dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark;
- dec_opt(?INET_LOPT_MSGQ_HIWTRMRK) -> high_msgq_watermark;
- dec_opt(?INET_LOPT_MSGQ_LOWTRMRK) -> low_msgq_watermark;
- dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
- dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
- dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send;
- dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size;
- dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets;
- dec_opt(?INET_LOPT_NETNS) -> netns;
- dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset;
- dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter;
- dec_opt(?INET_OPT_RAW) -> raw;
- dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device;
- dec_opt(I) when is_integer(I) -> undefined.
- %% Metatypes:
- %% [] Value must be 'undefined' or nonexistent
- %% for setopts and getopts.
- %% [Type] Value required for setopts and getopts,
- %% will be encoded for both.
- %% [Type,Default] Default used if value is 'undefined'.
- %% [[Type,Default]] A combination of the two above.
- %% Type Value must be 'undefined' or nonexistent for getops,
- %% required for setopts.
- %%
- %% The use of [] and [[Type,Default]] is commented out in enc_value/2
- %% and type_value/2 below since they are only used in record fields.
- %% And record fields does not call enc_value/2 nor type_value/2.
- %% Anyone introducing these metatypes otherwhere will have to activate
- %% those clauses in enc_value/2 and type_value/2. You have been warned!
- type_opt(get, raw) -> [{[int],[int],[binary_or_uint]}];
- type_opt(_, raw) -> {int,int,binary};
- %% NB: "sctp_status" and "sctp_get_peer_addr_info" are read-only options,
- %% so they should not be NOT encoded for use with "setopt".
- type_opt(get, sctp_status) ->
- [{record,#sctp_status{
- assoc_id = [sctp_assoc_id],
- _ = []}}];
- type_opt(get, sctp_get_peer_addr_info) ->
- [{record,#sctp_paddrinfo{
- assoc_id = [[sctp_assoc_id,0]],
- address = [[addr,{any,0}]],
- _ = []}}];
- type_opt(_, Opt) ->
- type_opt_1(Opt).
- %% Types of option values, by option name:
- %%
- type_opt_1(reuseaddr) -> bool;
- type_opt_1(keepalive) -> bool;
- type_opt_1(dontroute) -> bool;
- type_opt_1(linger) -> {bool,int};
- type_opt_1(broadcast) -> bool;
- type_opt_1(sndbuf) -> int;
- type_opt_1(recbuf) -> int;
- type_opt_1(priority) -> int;
- type_opt_1(tos) -> int;
- type_opt_1(tclass) -> int;
- type_opt_1(nodelay) -> bool;
- type_opt_1(ipv6_v6only) -> bool;
- %% multicast
- type_opt_1(multicast_ttl) -> int;
- type_opt_1(multicast_loop) -> bool;
- type_opt_1(multicast_if) -> ip;
- type_opt_1(add_membership) -> {ip,ip};
- type_opt_1(drop_membership) -> {ip,ip};
- %% driver options
- type_opt_1(header) -> uint;
- type_opt_1(buffer) -> int;
- type_opt_1(active) ->
- {enum,[{false, ?INET_PASSIVE},
- {true, ?INET_ACTIVE},
- {once, ?INET_ONCE},
- {multi, ?INET_MULTI}]};
- type_opt_1(packet) ->
- {enum,[{0, ?TCP_PB_RAW},
- {1, ?TCP_PB_1},
- {2, ?TCP_PB_2},
- {4, ?TCP_PB_4},
- {raw,?TCP_PB_RAW},
- {sunrm, ?TCP_PB_RM},
- {asn1, ?TCP_PB_ASN1},
- {cdr, ?TCP_PB_CDR},
- {fcgi, ?TCP_PB_FCGI},
- {line, ?TCP_PB_LINE_LF},
- {tpkt, ?TCP_PB_TPKT},
- {http, ?TCP_PB_HTTP},
- {httph,?TCP_PB_HTTPH},
- {http_bin, ?TCP_PB_HTTP_BIN},
- {httph_bin,?TCP_PB_HTTPH_BIN},
- {ssl, ?TCP_PB_SSL_TLS}, % obsolete
- {ssl_tls, ?TCP_PB_SSL_TLS}]};
- type_opt_1(line_delimiter) -> int;
- type_opt_1(mode) ->
- {enum,[{list, ?INET_MODE_LIST},
- {binary, ?INET_MODE_BINARY}]};
- type_opt_1(deliver) ->
- {enum,[{port, ?INET_DELIVER_PORT},
- {term, ?INET_DELIVER_TERM}]};
- type_opt_1(exit_on_close) -> bool;
- type_opt_1(low_watermark) -> int;
- type_opt_1(high_watermark) -> int;
- type_opt_1(low_msgq_watermark) -> int;
- type_opt_1(high_msgq_watermark) -> int;
- type_opt_1(send_timeout) -> time;
- type_opt_1(send_timeout_close) -> bool;
- type_opt_1(delay_send) -> bool;
- type_opt_1(packet_size) -> uint;
- type_opt_1(read_packets) -> uint;
- type_opt_1(netns) -> binary;
- type_opt_1(show_econnreset) -> bool;
- type_opt_1(bind_to_device) -> binary;
- %%
- %% SCTP options (to be set). If the type is a record type, the corresponding
- %% record signature is returned, otherwise, an "elementary" type tag
- %% is returned:
- %%
- %% for SCTP_OPT_RTOINFO
- type_opt_1(sctp_rtoinfo) ->
- [{record,#sctp_rtoinfo{
- assoc_id = [[sctp_assoc_id,0]],
- initial = [uint32,0],
- max = [uint32,0],
- min = [uint32,0]}}];
- %% for SCTP_OPT_ASSOCINFO
- type_opt_1(sctp_associnfo) ->
- [{record,#sctp_assocparams{
- assoc_id = [[sctp_assoc_id,0]],
- asocmaxrxt = [uint16,0],
- number_peer_destinations = [uint16,0],
- peer_rwnd = [uint32,0],
- local_rwnd = [uint32,0],
- cookie_life = [uint32,0]}}];
- %% for SCTP_OPT_INITMSG and SCTP_TAG_SEND_ANC_INITMSG (send*)
- type_opt_1(sctp_initmsg) ->
- [{record,#sctp_initmsg{
- num_ostreams = [uint16,0],
- max_instreams = [uint16,0],
- max_attempts = [uint16,0],
- max_init_timeo = [uint16,0]}}];
- %%
- type_opt_1(sctp_nodelay) -> bool;
- type_opt_1(sctp_autoclose) -> uint;
- type_opt_1(sctp_disable_fragments) -> bool;
- type_opt_1(sctp_i_want_mapped_v4_addr) -> bool;
- type_opt_1(sctp_maxseg) -> uint;
- %% for SCTP_OPT_PRIMARY_ADDR
- type_opt_1(sctp_primary_addr) ->
- [{record,#sctp_prim{
- assoc_id = [sctp_assoc_id],
- addr = addr}}];
- %% for SCTP_OPT_SET_PEER_PRIMARY_ADDR
- type_opt_1(sctp_set_peer_primary_addr) ->
- [{record,#sctp_setpeerprim{
- assoc_id = [sctp_assoc_id],
- addr = addr}}];
- %% for SCTP_OPT_ADAPTATION_LAYER
- type_opt_1(sctp_adaptation_layer) ->
- [{record,#sctp_setadaptation{
- adaptation_ind = [uint32,0]}}];
- %% for SCTP_OPT_PEER_ADDR_PARAMS
- type_opt_1(sctp_peer_addr_params) ->
- [{record,#sctp_paddrparams{
- assoc_id = [[sctp_assoc_id,0]],
- address = [[addr,{any,0}]],
- hbinterval = [uint32,0],
- pathmaxrxt = [uint16,0],
- pathmtu = [uint32,0],
- sackdelay = [uint32,0],
- flags =
- [{bitenumlist,
- [{hb_enable, ?SCTP_FLAG_HB_ENABLE},
- {hb_disable, ?SCTP_FLAG_HB_DISABLE},
- {hb_demand, ?SCTP_FLAG_HB_DEMAND},
- {pmtud_enable, ?SCTP_FLAG_PMTUD_ENABLE},
- {pmtud_disable, ?SCTP_FLAG_PMTUD_DISABLE},
- {sackdelay_enable, ?SCTP_FLAG_SACKDELAY_ENABLE},
- {sackdelay_disable, ?SCTP_FLAG_SACKDELAY_DISABLE}],
- uint32},[]]}}];
- %% for SCTP_OPT_DEFAULT_SEND_PARAM and SCTP_TAG_SEND_ANC_PARAMS (on send*)
- type_opt_1(sctp_default_send_param) ->
- [{record,#sctp_sndrcvinfo{
- stream = [uint16,0],
- ssn = [],
- flags =
- [{bitenumlist,
- [{unordered, ?SCTP_FLAG_UNORDERED},
- {addr_over, ?SCTP_FLAG_ADDR_OVER},
- {abort, ?SCTP_FLAG_ABORT},
- {eof, ?SCTP_FLAG_EOF}],
- uint16},[]],
- ppid = [uint32,0],
- context = [uint32,0],
- timetolive = [uint32,0],
- tsn = [],
- cumtsn = [],
- assoc_id = [[sctp_assoc_id,0]]}}];
- %% for SCTP_OPT_EVENTS
- type_opt_1(sctp_events) ->
- [{record,#sctp_event_subscribe{
- data_io_event = [bool8,true],
- association_event = [bool8,true],
- address_event = [bool8,true],
- send_failure_event = [bool8,true],
- peer_error_event = [bool8,true],
- shutdown_event = [bool8,true],
- partial_delivery_event = [bool8,true],
- adaptation_layer_event = [bool8,false],
- authentication_event = [bool8,false]}}];
- %% for SCTP_OPT_DELAYED_ACK_TIME
- type_opt_1(sctp_delayed_ack_time) ->
- [{record,#sctp_assoc_value{
- assoc_id = [[sctp_assoc_id,0]],
- assoc_value = [uint32,0]}}];
- %%
- type_opt_1(undefined) -> undefined;
- type_opt_1(O) when is_atom(O) -> undefined.
- %% Get. No supplied value.
- type_value(get, undefined) -> false; % Undefined type
- %% These two clauses can not happen since they are only used
- %% in record fields - from record fields they must have a
- %% value though it might be 'undefined', so record fields
- %% calls type_value/3, not type_value/2.
- %% type_value(get, []) -> true; % Ignored
- %% type_value(get, [[Type,Default]]) -> % Required field, default value
- %% type_value(get, Type, Default);
- type_value(get, [{record,Types}]) -> % Implied default value for record
- type_value_record(get, Types,
- erlang:make_tuple(tuple_size(Types), undefined), 2);
- type_value(get, [_]) -> false; % Required value missing
- type_value(get, _) -> true. % Field is supposed to be undefined
- %% Get and set. Value supplied.
- type_value(_, undefined, _) -> false; % Undefined type
- type_value(_, [], undefined) -> true; % Ignored
- type_value(_, [], _) -> false; % Value should not be supplied
- type_value(Q, [Type], Value) -> % Required field, proceed
- type_value_default(Q, Type, Value);
- type_value(set, Type, Value) -> % Required for setopts
- type_value…
Large files files are truncated, but you can click here to view the full file