PageRenderTime 110ms CodeModel.GetById 3ms app.highlight 93ms RepoModel.GetById 2ms app.codeStats 0ms

/erts/preloaded/src/prim_inet.erl

https://github.com/cobusc/otp
Erlang | 2505 lines | 1719 code | 238 blank | 548 comment | 12 complexity | 0c6571e8d208a25767f00072b03c17fd MD5 | raw file

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

   1%%
   2%% %CopyrightBegin%
   3%% 
   4%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
   5%% 
   6%% Licensed under the Apache License, Version 2.0 (the "License");
   7%% you may not use this file except in compliance with the License.
   8%% You may obtain a copy of the License at
   9%%
  10%%     http://www.apache.org/licenses/LICENSE-2.0
  11%%
  12%% Unless required by applicable law or agreed to in writing, software
  13%% distributed under the License is distributed on an "AS IS" BASIS,
  14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15%% See the License for the specific language governing permissions and
  16%% limitations under the License.
  17%% 
  18%% %CopyrightEnd%
  19%%
  20%% The SCTP protocol was added 2006
  21%% by Leonid Timochouk <l.timochouk@gmail.com>
  22%% and Serge Aleynikov  <saleyn@gmail.com>
  23%% at IDT Corp. Adapted by the OTP team at Ericsson AB.
  24%%
  25-module(prim_inet).
  26
  27%% Primitive inet_drv interface
  28
  29-export([open/3, open/4, fdopen/4, fdopen/5, close/1]).
  30-export([bind/3, listen/1, listen/2, peeloff/2]).
  31-export([connect/3, connect/4, async_connect/4]).
  32-export([accept/1, accept/2, async_accept/2]).
  33-export([shutdown/2]).
  34-export([send/2, send/3, sendto/4, sendmsg/3, sendfile/4]).
  35-export([recv/2, recv/3, async_recv/3]).
  36-export([unrecv/2]).
  37-export([recvfrom/2, recvfrom/3]).
  38-export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]).
  39-export([chgopt/3, chgopts/2]).
  40-export([getstat/2, getfd/1, ignorefd/2,
  41	 getindex/1, getstatus/1, gettype/1,
  42	 getifaddrs/1, getiflist/1, ifget/3, ifset/3,
  43	 gethostname/1]).
  44-export([getservbyname/3, getservbyport/3]).
  45-export([peername/1, setpeername/2, peernames/1, peernames/2]).
  46-export([sockname/1, setsockname/2, socknames/1, socknames/2]).
  47-export([attach/1, detach/1]).
  48
  49-include("inet_sctp.hrl").
  50-include("inet_int.hrl").
  51
  52%-define(DEBUG, 1).
  53-ifdef(DEBUG).
  54-define(DBG_FORMAT(Format, Args), (io:format((Format), (Args)))).
  55-else.
  56-define(DBG_FORMAT(Format, Args), ok).
  57-endif.
  58
  59%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  60%%
  61%% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket)  ->
  62%%       {ok, insock()} |
  63%%       {error, Reason}
  64%%
  65%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  66
  67open(Protocol, Family, Type) ->
  68    open(Protocol, Family, Type, [], ?INET_REQ_OPEN, []).
  69
  70open(Protocol, Family, Type, Opts) ->
  71    open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []).
  72
  73%% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer())
  74
  75fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
  76    fdopen(Protocol, Family, Type, Fd, true).
  77
  78fdopen(Protocol, Family, Type, Fd, Bound)
  79  when is_integer(Fd), is_boolean(Bound) ->
  80    open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN,
  81         [?int32(Fd), enc_value_2(bool, Bound)]).
  82
  83open(Protocol, Family, Type, Opts, Req, Data) ->
  84    Drv = protocol2drv(Protocol),
  85    AF = enc_family(Family),
  86    T = enc_type(Type),
  87    try erlang:open_port({spawn_driver,Drv}, [binary]) of
  88	S ->
  89	    case setopts(S, Opts) of
  90		ok ->
  91		    case ctl_cmd(S, Req, [AF,T,Data]) of
  92			{ok,_} -> {ok,S};
  93			{error,_}=E1 ->
  94			    close(S),
  95			    E1
  96		    end;
  97		{error,_}=E2 ->
  98		    close(S),
  99		    E2
 100	    end
 101    catch
 102	%% The only (?) way to get here is to try to open
 103	%% the sctp driver when it does not exist (badarg)
 104	error:badarg       -> {error, eprotonosupport};
 105	%% system_limit if out of port slots
 106	error:system_limit -> {error, system_limit}
 107    end.
 108
 109enc_family(inet)  -> ?INET_AF_INET;
 110enc_family(inet6) -> ?INET_AF_INET6;
 111enc_family(local) -> ?INET_AF_LOCAL.
 112
 113enc_type(stream) -> ?INET_TYPE_STREAM;
 114enc_type(dgram) -> ?INET_TYPE_DGRAM;
 115enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET.
 116
 117protocol2drv(tcp)  -> "tcp_inet";
 118protocol2drv(udp)  -> "udp_inet";
 119protocol2drv(sctp) -> "sctp_inet".
 120
 121drv2protocol("tcp_inet")  -> tcp;
 122drv2protocol("udp_inet")  -> udp;
 123drv2protocol("sctp_inet") -> sctp;
 124drv2protocol(_)           -> undefined.
 125
 126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 127%%
 128%% Shutdown(insock(), atom()) -> ok
 129%%
 130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 131%% TODO: shutdown equivalent for SCTP
 132%%
 133shutdown(S, read) when is_port(S) ->
 134    shutdown_1(S, 0);
 135shutdown(S, write) when is_port(S) ->
 136    shutdown_1(S, 1);
 137shutdown(S, read_write) when is_port(S) ->
 138    shutdown_1(S, 2).
 139
 140shutdown_1(S, How) ->
 141    case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of
 142	{ok, []} -> ok;
 143	{error,_}=Error -> Error
 144    end.
 145
 146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 147%%
 148%% CLOSE(insock()) -> ok
 149%%
 150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 151
 152close(S) when is_port(S) ->
 153    case getopt(S, linger) of
 154    	{ok,{true,0}} -> 
 155	    close_port(S);
 156	_ ->
 157	    case subscribe(S, [subs_empty_out_q]) of
 158		{ok, [{subs_empty_out_q,N}]} when N > 0 ->
 159		    close_pend_loop(S, N);   %% wait for pending output to be sent
 160		_ ->
 161		    close_port(S)
 162	    end
 163    end.
 164
 165close_pend_loop(S, N) ->
 166    receive
 167	{empty_out_q,S} ->
 168	    close_port(S)
 169    after ?INET_CLOSE_TIMEOUT ->
 170	    case getstat(S, [send_pend]) of
 171                {ok, [{send_pend,N1}]} ->
 172                    if
 173			N1 =:= N ->
 174			    close_port(S);
 175                       true ->
 176			    close_pend_loop(S, N1)
 177                    end;
 178		_ ->
 179		    close_port(S)
 180	    end
 181    end.
 182
 183close_port(S) ->
 184    catch erlang:port_close(S),
 185    receive {'EXIT',S,_} -> ok after 0 -> ok end.
 186
 187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 188%%
 189%% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}
 190%%
 191%% bind the insock() to the interface address given by IP and Port
 192%%
 193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 194
 195%% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
 196%% If no addrs are specified, it just does nothing.
 197%% Function returns {ok, S} on success, unlike TCP/UDP "bind":
 198bind(S, add, Addrs) when is_port(S), is_list(Addrs) ->
 199    bindx(S, 1, Addrs);
 200bind(S, remove, Addrs) when is_port(S), is_list(Addrs) ->
 201    bindx(S, 0, Addrs);
 202bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 ->
 203    case type_value(set, addr, Addr) of
 204	true ->
 205	    case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of
 206		{ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
 207		{error, _} = Error -> Error
 208	    end;
 209	false ->
 210	    {error, einval}
 211    end;
 212bind(S, IP, Port) ->
 213    bind(S, {IP, Port}, 0).
 214
 215bindx(S, AddFlag, Addrs) ->
 216    case getprotocol(S) of
 217	sctp ->
 218	    case bindx_check_addrs(Addrs) of
 219		true ->
 220		    %% Really multi-homed "bindx". Stringified args:
 221		    %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
 222		    Args =
 223			[?int8(AddFlag)|
 224			 [enc_value(set, addr, Addr) || Addr <- Addrs]],
 225		    case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
 226			{ok, _} -> {ok, S};
 227			{error, _}=Error  -> Error
 228		    end;
 229		false ->
 230		    {error, einval}
 231	    end;
 232	_ ->
 233	    {error, einval}
 234    end.
 235
 236bindx_check_addrs([Addr|Addrs]) ->
 237    type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs);
 238bindx_check_addrs([]) ->
 239    true.
 240
 241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 242%%
 243%% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason}
 244%%
 245%% connect the insock() to the address given by IP and Port
 246%% if timeout is given:
 247%%       timeout < 0  -> infinity
 248%%                 0  -> immediate connect (mostly works for loopback)
 249%%               > 0  -> wait for timeout ms if not connected then 
 250%%                       return {error, timeout} 
 251%%
 252%% ASYNC_CONNECT(insock(), IP, Port, Timeout) -> {ok, S, Ref} | {error, Reason}
 253%%
 254%%  a {inet_async,S,Ref,Status} will be sent on socket condition
 255%%
 256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 257%% For TCP, UDP or SCTP sockets.
 258%%
 259
 260connect(S, IP, Port) ->
 261    connect(S, IP, Port, infinity).
 262%%
 263connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
 264    case type_value(set, addr, Addr) of
 265	true when Time =:= infinity ->
 266	    connect0(S, Addr, -1);
 267	true when is_integer(Time) ->
 268	    connect0(S, Addr, Time);
 269	false ->
 270	    {error, einval}
 271    end;
 272connect(S, IP, Port, Time) ->
 273    connect(S, {IP, Port}, 0, Time).
 274
 275connect0(S, Addr, Time) ->
 276    case async_connect0(S, Addr, Time) of
 277	{ok, S, Ref} ->
 278	    receive
 279		{inet_async, S, Ref, Status} ->
 280		    Status
 281	    end;
 282	Error -> Error
 283    end.
 284
 285
 286async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
 287    case type_value(set, addr, Addr) of
 288	true when Time =:= infinity ->
 289	    async_connect0(S, Addr, -1);
 290	true when is_integer(Time) ->
 291	    async_connect0(S, Addr, Time);
 292	false ->
 293	    {error, einval}
 294    end;
 295%%
 296async_connect(S, IP, Port, Time) ->
 297    async_connect(S, {IP, Port}, 0, Time).
 298
 299async_connect0(S, Addr, Time) ->
 300    case ctl_cmd(
 301	   S, ?INET_REQ_CONNECT,
 302	   [enc_time(Time),enc_value(set, addr, Addr)])
 303    of
 304	{ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
 305	{error, _}=Error -> Error
 306    end.
 307
 308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 309%%
 310%% ACCEPT(insock() [,Timeout] ) -> {ok,insock()} | {error, Reason}
 311%%
 312%% accept incoming connection on listen socket 
 313%% if timeout is given:
 314%%       timeout < 0  -> infinity
 315%%                 0  -> immediate accept (poll)
 316%%               > 0  -> wait for timeout ms for accept if no accept then 
 317%%                       return {error, timeout}
 318%%
 319%% ASYNC_ACCEPT(insock(), Timeout)
 320%%
 321%%  async accept. return {ok,S,Ref} or {error, Reason}
 322%%  the owner of socket S will receive an {inet_async,S,Ref,Status} on 
 323%%  socket condition
 324%%
 325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 326%% For TCP sockets only.
 327%%
 328accept(L)            -> accept0(L, -1).
 329
 330accept(L, infinity)  -> accept0(L, -1);
 331accept(L, Time)      -> accept0(L, Time).
 332
 333accept0(L, Time) when is_port(L), is_integer(Time) ->
 334    case async_accept(L, Time) of
 335	{ok, Ref} ->
 336	    receive 
 337		{inet_async, L, Ref, {ok,S}} ->
 338		    accept_opts(L, S);
 339		{inet_async, L, Ref, Error} ->
 340		    Error
 341	    end;
 342	Error -> Error
 343    end.
 344
 345%% setup options from listen socket on the connected socket
 346accept_opts(L, S) ->
 347    case getopts(L, [active, nodelay, keepalive, delay_send, priority, tos]) of
 348	{ok, Opts} ->
 349	    case setopts(S, Opts) of
 350		ok ->
 351		    case getopts(L, [tclass]) of
 352			{ok, []} ->
 353			    {ok, S};
 354			{ok, TClassOpts} ->
 355			    case setopts(S, TClassOpts) of
 356				ok ->
 357				    {ok, S};
 358				Error -> close(S), Error
 359			    end
 360		    end;
 361		Error -> close(S), Error
 362	    end;
 363	Error ->
 364	    close(S), Error
 365    end.
 366
 367async_accept(L, Time) ->
 368    case ctl_cmd(L,?INET_REQ_ACCEPT, [enc_time(Time)]) of
 369	{ok, [R1,R0]} -> {ok, ?u16(R1,R0)};
 370	{error,_}=Error -> Error
 371    end.
 372
 373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 374%%
 375%% LISTEN(insock() [,Backlog]) -> ok | {error, Reason}
 376%%
 377%% set listen mode on socket
 378%%
 379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 380%% For TCP or SCTP sockets. For SCTP, Boolean backlog value (enable/disable
 381%% listening) is also accepted:
 382
 383listen(S) -> listen(S, ?LISTEN_BACKLOG).
 384
 385listen(S, true) -> listen(S, ?LISTEN_BACKLOG);
 386listen(S, false) -> listen(S, 0);
 387listen(S, BackLog) when is_port(S), is_integer(BackLog) ->
 388    case ctl_cmd(S, ?INET_REQ_LISTEN, [?int16(BackLog)]) of
 389	{ok, _} -> ok;
 390	{error,_}=Error   -> Error
 391    end.
 392
 393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 394%%
 395%% PEELOFF(insock(), AssocId) -> {ok,outsock()} | {error, Reason}
 396%%
 397%% SCTP: Peel off one association into a type stream socket
 398%%
 399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 400
 401peeloff(S, AssocId) ->
 402    case ctl_cmd(S, ?SCTP_REQ_PEELOFF, [?int32(AssocId)]) of
 403	inet_reply ->
 404	    receive
 405		{inet_reply,S,Res} -> Res
 406	    end;
 407	{error,_}=Error -> Error
 408    end.
 409
 410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 411%%
 412%% SEND(insock(), Data) -> ok | {error, Reason}
 413%%
 414%% send Data on the socket (io-list)
 415%%
 416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 417%% This is a generic "port_command" interface used by TCP, UDP, SCTP, depending
 418%% on the driver it is mapped to, and the "Data". It actually sends out data,--
 419%% NOT delegating this task to any back-end.  For SCTP, this function MUST NOT
 420%% be called directly -- use "sendmsg" instead:
 421%%
 422send(S, Data, OptList) when is_port(S), is_list(OptList) ->
 423    ?DBG_FORMAT("prim_inet:send(~p, ~p)~n", [S,Data]),
 424    try erlang:port_command(S, Data, OptList) of
 425	false -> % Port busy and nosuspend option passed
 426	    ?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
 427	    {error,busy};
 428	true ->
 429	    receive
 430		{inet_reply,S,Status} ->
 431		    ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Status]),
 432		    Status
 433	    end
 434    catch
 435	error:_Error ->
 436	    ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
 437	     {error,einval}
 438    end.
 439
 440send(S, Data) ->
 441    send(S, Data, []).
 442
 443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 444%%
 445%% SENDTO(insock(), IP, Port, Data) -> ok | {error, Reason}
 446%%
 447%% send Datagram to the IP at port (Should add sync send!)
 448%%
 449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 450%% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
 451%% is known to be connected.
 452
 453sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
 454    case type_value(set, addr, Addr) of
 455	true ->
 456	    ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
 457	    try
 458		erlang:port_command(S, [enc_value(set, addr, Addr),Data])
 459	    of
 460		true ->
 461		    receive
 462			{inet_reply,S,Reply} ->
 463			    ?DBG_FORMAT(
 464			       "prim_inet:sendto() -> ~p~n", [Reply]),
 465			    Reply
 466		    end
 467	    catch
 468		error:_ ->
 469		    ?DBG_FORMAT(
 470		       "prim_inet:sendto() -> {error,einval}~n", []),
 471		    {error,einval}
 472	    end;
 473	false ->
 474	    ?DBG_FORMAT(
 475	       "prim_inet:sendto() -> {error,einval}~n", []),
 476	    {error,einval}
 477    end;
 478sendto(S, IP, Port, Data) ->
 479    sendto(S, {IP, Port}, 0, Data).
 480
 481
 482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 483%%
 484%% SENDMSG(insock(), IP, Port, InitMsg, Data)   or
 485%% SENDMSG(insock(), SndRcvInfo,        Data)   -> ok | {error, Reason}
 486%%
 487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 488%% SCTP: Sending data over an existing association: no need for a destination
 489%% addr; uses SndRcvInfo:
 490%%
 491sendmsg(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) ->
 492    Type = type_opt(set, sctp_default_send_param),
 493    try type_value(set, Type, SRI) of
 494	true ->
 495	    send(S, [enc_value(set, Type, SRI)|Data]);
 496	false -> {error,einval}
 497    catch
 498	Reason -> {error,Reason}
 499    end.
 500
 501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 502%%
 503%% SENDFILE(outsock(), Fd, Offset, Length) -> {ok,BytesSent} | {error, Reason}
 504%%
 505%% send Length data bytes from a file handle, to a socket, starting at Offset
 506%%
 507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 508%% "sendfile" is for TCP:
 509
 510sendfile(S, FileHandle, Offset, Length)
 511        when not is_port(S);
 512             not is_binary(FileHandle);
 513             not is_integer(Offset);
 514             not is_integer(Length) ->
 515    {error, badarg};
 516sendfile(S, FileHandle, Offset, Length) ->
 517    case erlang:port_info(S, connected) of
 518        {connected, Pid} when Pid =:= self() ->
 519            sendfile_1(S, FileHandle, Offset, Length);
 520        {connected, Pid} when Pid =/= self() ->
 521            {error, not_owner};
 522        _Other ->
 523            {error, einval}
 524    end.
 525
 526sendfile_1(S, FileHandle, Offset, 0) ->
 527    sendfile_1(S, FileHandle, Offset, (1 bsl 63) - 1);
 528sendfile_1(_S, _FileHandle, Offset, Length) when
 529         Offset < 0; Offset > ((1 bsl 63) - 1);
 530         Length < 0; Length > ((1 bsl 63) - 1) ->
 531    {error, einval};
 532sendfile_1(S, FileHandle, Offset, Length) ->
 533    Args = [FileHandle,
 534            ?int64(Offset),
 535            ?int64(Length)],
 536    case ctl_cmd(S, ?TCP_REQ_SENDFILE, Args) of
 537        {ok, []} ->
 538            receive
 539                {sendfile, S, {ok, SentLow, SentHigh}} ->
 540                    {ok, SentLow bor (SentHigh bsl 32)};
 541                {sendfile, S, {error, Reason}} ->
 542                    {error, Reason};
 543                {'EXIT', S, _Reason} ->
 544                    {error, closed}
 545            end;
 546        {error, Reason} ->
 547            {error, Reason}
 548    end.
 549
 550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 551%%
 552%% RECV(insock(), Length, [Timeout]) -> {ok,Data} | {error, Reason}
 553%%
 554%% receive Length data bytes from a socket
 555%% if 0 is given then a Data packet is requested (see setopt (packet))
 556%%    N read N bytes
 557%%
 558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 559%% "recv" is for TCP:
 560
 561recv(S, Length) -> recv0(S, Length, -1).
 562
 563recv(S, Length, infinity) -> recv0(S, Length,-1);
 564
 565recv(S, Length, Time) when is_integer(Time) -> recv0(S, Length, Time).
 566
 567recv0(S, Length, Time) when is_port(S), is_integer(Length), Length >= 0 ->
 568    case async_recv(S, Length, Time) of
 569	{ok, Ref} ->
 570	    receive
 571		{inet_async, S, Ref, Status} -> Status;
 572		{'EXIT', S, _Reason} ->
 573		    {error, closed}
 574	    end;
 575	Error -> Error
 576    end.
 577	     
 578
 579async_recv(S, Length, Time) ->
 580    case ctl_cmd(S, ?TCP_REQ_RECV, [enc_time(Time), ?int32(Length)]) of
 581	{ok,[R1,R0]} -> {ok, ?u16(R1,R0)};
 582	{error,_}=Error -> Error
 583    end.	    
 584
 585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 586%%
 587%% RECVFROM(insock(), Lenth [Timeout]) -> {ok,{IP,Port,Data}} | {error, Reason}
 588%%                           For SCTP: -> {ok,{IP,Port,[AncData],Data}}
 589%%                                                            | {error, Reason}
 590%% receive Length data bytes from a datagram socket sent from IP at Port
 591%% if 0 is given then a Data packet is requested (see setopt (packet))
 592%%    N read N bytes
 593%%
 594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 595%% "recvfrom" is for both UDP and SCTP.
 596%% NB: "Length" is actually ignored for these protocols, since they are msg-
 597%% oriented: preserved here only for API compatibility.
 598%%
 599recvfrom(S, Length) ->
 600    recvfrom(S, Length, infinity).
 601
 602recvfrom(S, Length, infinity) when is_port(S) ->
 603    recvfrom0(S, Length, -1);
 604recvfrom(S, Length, Time) when is_port(S) ->
 605    if
 606	is_integer(Time), 0 =< Time, Time < 16#ffffffff ->
 607	    recvfrom0(S, Length, Time);
 608	true ->
 609	    {error, einval}
 610    end.
 611
 612recvfrom0(S, Length, Time)
 613  when is_integer(Length), 0 =< Length, Length =< 16#ffffffff ->
 614    case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of
 615	{ok,[R1,R0]} ->
 616	    Ref = ?u16(R1,R0),
 617	    receive
 618		% Success, UDP:
 619		{inet_async, S, Ref, {ok, [F | AddrData]}} ->
 620		    case get_addr(F, AddrData) of
 621			{{Family, _} = Addr, Data} when is_atom(Family) ->
 622			    {ok, {Addr, 0, Data}};
 623			{{IP, Port}, Data} ->
 624			    {ok, {IP, Port, Data}}
 625		    end;
 626
 627		% Success, SCTP:
 628		{inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} ->
 629		    {IP, _} = get_ip(F, Addr),
 630		    {ok, {IP, ?u16(P1, P0), AncData, DE}};
 631
 632		% Back-end error:
 633		{inet_async, S, Ref, Error={error, _}} ->
 634		    Error
 635	    end;
 636	{error,_}=Error ->
 637	    Error % Front-end error
 638    end;
 639recvfrom0(_, _, _) -> {error,einval}.
 640
 641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 642%%
 643%% PEERNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
 644%%
 645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 646
 647peername(S) when is_port(S) ->
 648    case ctl_cmd(S, ?INET_REQ_PEER, []) of
 649	{ok, [F | Addr]} ->
 650	    {A, _} = get_addr(F, Addr),
 651	    {ok, A};
 652	{error, _} = Error -> Error
 653    end.
 654
 655setpeername(S, undefined) when is_port(S) ->
 656    case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
 657	{ok, []} -> ok;
 658	{error, _} = Error -> Error
 659    end;
 660setpeername(S, Addr) when is_port(S) ->
 661    case type_value(set, addr, Addr) of
 662	true ->
 663	    case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of
 664		{ok, []} -> ok;
 665		{error, _} = Error -> Error
 666	    end;
 667	false ->
 668	    {error, einval}
 669    end.
 670
 671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 672%%
 673%% PEERNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
 674%%
 675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 676
 677peernames(S) when is_port(S) ->
 678    peernames(S, undefined).
 679
 680peernames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
 681    peernames(S, AssocId);
 682peernames(S, AssocId)
 683  when is_port(S), is_integer(AssocId);
 684       is_port(S), AssocId =:= undefined ->
 685    Q = get,
 686    Type = [[sctp_assoc_id,0]],
 687    case type_value(Q, Type, AssocId) of
 688	true ->
 689	    case ctl_cmd
 690		(S, ?INET_REQ_GETPADDRS,
 691		 enc_value(Q, Type, AssocId)) of
 692		{ok,Addrs} ->
 693		    {ok,get_addrs(Addrs)};
 694		Error ->
 695		    Error
 696	    end;
 697	false ->
 698	    {error,einval}
 699    end.
 700
 701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 702%%
 703%% SOCKNAME(insock()) -> {ok, {IP, Port}} | {error, Reason}
 704%%
 705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 706
 707sockname(S) when is_port(S) ->
 708    case ctl_cmd(S, ?INET_REQ_NAME, []) of
 709	{ok, [F | Addr]} ->
 710	    {A, _} = get_addr(F, Addr),
 711	    {ok, A};
 712	{error, _} = Error -> Error
 713    end.
 714
 715setsockname(S, undefined) when is_port(S) ->
 716    case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
 717	{ok, []} -> ok;
 718	{error, _} = Error -> Error
 719    end;
 720setsockname(S, Addr) when is_port(S) ->
 721    case type_value(set, addr, Addr) of
 722	true ->
 723	    case
 724		ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr))
 725	    of
 726		{ok, []} -> ok;
 727		{error, _} = Error -> Error
 728	    end;
 729	false ->
 730	    {error, einval}
 731    end.
 732
 733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 734%%
 735%% SOCKNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason}
 736%%
 737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 738
 739socknames(S) when is_port(S) ->
 740    socknames(S, undefined).
 741
 742socknames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
 743    socknames(S, AssocId);
 744socknames(S, AssocId)
 745  when is_port(S), is_integer(AssocId);
 746       is_port(S), AssocId =:= undefined ->
 747    Q = get,
 748    Type = [[sctp_assoc_id,0]],
 749    case type_value(Q, Type, AssocId) of
 750	true ->
 751	    case ctl_cmd
 752		(S, ?INET_REQ_GETLADDRS,
 753		 enc_value(Q, Type, AssocId)) of
 754		{ok,Addrs} ->
 755		    {ok,get_addrs(Addrs)};
 756		Error ->
 757		    Error
 758	    end;
 759	false ->
 760	    {error,einval}
 761    end.
 762
 763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 764%%
 765%% SETOPT(insock(), Opt, Value) -> ok | {error, Reason}
 766%% SETOPTS(insock(), [{Opt,Value}]) -> ok | {error, Reason}
 767%%
 768%% set socket, ip and driver option
 769%%
 770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 771
 772setopt(S, Opt, Value) when is_port(S) -> 
 773    setopts(S, [{Opt,Value}]).
 774
 775setopts(S, Opts) when is_port(S) ->
 776    case encode_opt_val(Opts) of
 777	{ok, Buf} ->
 778	    case ctl_cmd(S, ?INET_REQ_SETOPTS, Buf) of
 779		{ok, _} -> ok;
 780		{error,_}=Error -> Error
 781	    end;
 782	Error  -> Error
 783    end.	    
 784
 785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 786%%
 787%% GETOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
 788%% GETOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
 789%% get socket, ip and driver option
 790%%
 791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 792
 793getopt(S, Opt) when is_port(S), is_atom(Opt) ->
 794    case getopts(S, [Opt]) of
 795	{ok,[{_,Value}]} -> {ok, Value};
 796	Error -> Error
 797    end.
 798
 799getopts(S, Opts) when is_port(S), is_list(Opts) ->
 800    case encode_opts(Opts) of
 801	{ok,Buf} ->
 802	    case ctl_cmd(S, ?INET_REQ_GETOPTS, Buf) of
 803		{ok,Rep} ->
 804		    %% Non-SCTP: "Rep" contains the encoded option vals:
 805		    decode_opt_val(Rep);
 806		inet_reply ->
 807		    %% SCTP: Need to receive the full value:
 808		    receive
 809			{inet_reply,S,Res} -> Res
 810		    end;
 811		{error,_}=Error -> Error
 812	    end;
 813	Error -> Error
 814    end.
 815    
 816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 817%%
 818%% CHGOPT(insock(), Opt) -> {ok,Value} | {error, Reason}
 819%% CHGOPTS(insock(), [Opt]) -> {ok, [{Opt,Value}]} | {error, Reason}
 820%% change socket, ip and driver option
 821%%
 822%% Same as setopts except for record value options where undefined
 823%% fields are read with getopts before setting.
 824%%
 825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 826
 827chgopt(S, Opt, Value) when is_port(S) -> 
 828    chgopts(S, [{Opt,Value}]).
 829
 830chgopts(S, Opts) when is_port(S), is_list(Opts) ->
 831    case getopts(S, need_template(Opts)) of
 832	{ok,Templates} ->
 833	    try merge_options(Opts, Templates) of
 834		NewOpts ->
 835		    setopts(S, NewOpts)
 836	    catch
 837		Reason -> {error,Reason}
 838	    end;
 839	Error -> Error
 840    end.
 841    
 842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 843%%
 844%% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason}
 845%%
 846%%   IfAddrsList = [{Name,[Opts]}]
 847%%   Name = string()
 848%%   Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr}
 849%%        | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()}
 850%%   Flag = up | broadcast | loopback | running | multicast
 851%%   Addr = ipv4addr() | ipv6addr()
 852%%   HwAddr = ethernet_addr()
 853%%
 854%% get interface name and addresses list
 855%%
 856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 857
 858getifaddrs(S) when is_port(S) ->
 859    case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
 860	{ok, Data} ->
 861	    {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())};
 862	{error,enotsup} ->
 863	    case getiflist(S) of
 864		{ok, IFs} ->
 865		    {ok, getifaddrs_ifget(S, IFs)};
 866		Err1 -> Err1
 867	    end;
 868	Err2 -> Err2
 869    end.
 870
 871%% Restructure interface properties per interface and remove duplicates
 872
 873comp_ifaddrs([{If,Opts}|IfOpts], T) ->
 874    case ktree_is_defined(If, T) of
 875	true ->
 876	    OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts),
 877	    comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T));
 878	false ->
 879	    OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
 880	    comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
 881     end;
 882comp_ifaddrs([], T) ->
 883    [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
 884
 885comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
 886    case ktree_is_defined(Opt, OptSet) of
 887	true
 888	  when element(1, Opt) =:= flags;
 889	       element(1, Opt) =:= hwaddr ->
 890	    comp_ifaddrs_add(OptSet, Opts);
 891	_ ->
 892	    comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
 893    end;
 894comp_ifaddrs_add(OptSet, []) -> OptSet.
 895
 896%% Legacy emulation of getifaddrs
 897
 898getifaddrs_ifget(_, []) -> [];
 899getifaddrs_ifget(S, [IF|IFs]) ->
 900    case ifget(S, IF, [flags]) of
 901	{ok,[{flags,Flags}]=FlagsVals} ->
 902	    BroadOpts =
 903		case member(broadcast, Flags) of
 904		    true ->
 905			[broadaddr,hwaddr];
 906		    false ->
 907			[hwaddr]
 908		end,
 909	    P2POpts =
 910		case member(pointtopoint, Flags) of
 911		    true ->
 912			[dstaddr|BroadOpts];
 913		    false ->
 914			BroadOpts
 915		end,
 916	    getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]);
 917	_ ->
 918	    getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
 919    end.
 920
 921getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) ->
 922    OptVals =
 923	case ifget(S, IF, Opts) of
 924	    {ok,OVs} -> OVs;
 925	    _ -> []
 926	end,
 927    [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)].
 928
 929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 930%%
 931%% getiflist(insock()) -> {ok,IfNameList} | {error, Reason}
 932%%
 933%% get interface name list
 934%%
 935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 936
 937getiflist(S) when is_port(S) ->
 938    case ctl_cmd(S, ?INET_REQ_GETIFLIST, []) of
 939	{ok, Data} -> {ok, build_iflist(Data)};
 940	{error,_}=Error -> Error
 941    end.
 942
 943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 944%%
 945%% ifget(insock(), IFOpts) -> {ok,IfNameList} | {error, Reason}
 946%%
 947%% get interface name list
 948%%
 949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 950
 951ifget(S, Name, Opts) ->
 952    case encode_ifname(Name) of
 953	{ok, Buf1} ->
 954	    case encode_ifopts(Opts,[]) of
 955		{ok, Buf2} ->
 956		    case ctl_cmd(S, ?INET_REQ_IFGET, [Buf1,Buf2]) of
 957			{ok, Data} -> decode_ifopts(Data,[]);
 958			{error,_}=Error -> Error
 959		    end;
 960		Error -> Error
 961	    end;
 962	Error -> Error
 963    end.
 964
 965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 966%%
 967%% ifset(insock(), Name, IFOptVals) -> {ok,IfNameList} | {error, Reason}
 968%%
 969%% set interface parameters
 970%%
 971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 972
 973ifset(S, Name, Opts) ->
 974    case encode_ifname(Name) of
 975	{ok, Buf1} ->
 976	    case encode_ifopt_val(Opts,[]) of
 977		{ok, Buf2} ->
 978		    case ctl_cmd(S, ?INET_REQ_IFSET, [Buf1,Buf2]) of
 979			{ok, _} -> ok;
 980			{error,_}=Error -> Error
 981		    end;
 982		Error -> Error
 983	    end;
 984	Error -> Error
 985    end.
 986
 987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 988%%
 989%% subscribe(insock(), SubsList) -> {ok,StatReply} | {error, Reason}
 990%%
 991%% Subscribe on socket events (from driver)
 992%%
 993%% Available event subscriptions:
 994%%   subs_empty_out_q: StatReply = [{subs_empty_out_q, N}], where N
 995%%                     is current queue length. When the queue becomes empty
 996%%                     a {empty_out_q, insock()} message will be sent to
 997%%                     subscribing process and the subscription will be
 998%%                     removed. If N = 0, the queue is empty and no
 999%%                     subscription is made.
1000%%
1001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002
1003subscribe(S, Sub) when is_port(S), is_list(Sub) ->
1004    case encode_subs(Sub) of
1005	{ok, Bytes} ->
1006	    case ctl_cmd(S, ?INET_REQ_SUBSCRIBE, Bytes) of
1007		{ok, Data} -> decode_subs(Data);
1008		{error,_}=Error -> Error
1009	    end;
1010	Error -> Error
1011    end.
1012
1013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014%%
1015%% GETSTAT(insock(), StatList) -> {ok,StatReply} | {error, Reason}
1016%%
1017%% get socket statistics (from driver)
1018%%
1019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020
1021getstat(S, Stats) when is_port(S), is_list(Stats) ->
1022    case encode_stats(Stats) of
1023	{ok, Bytes} ->
1024	    case ctl_cmd(S, ?INET_REQ_GETSTAT, Bytes) of
1025		{ok, Data} -> decode_stats(Data);
1026		{error,_}=Error -> Error
1027	    end;
1028	Error -> Error
1029    end.
1030
1031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032%%
1033%% GETFD(insock()) -> {ok,integer()} | {error, Reason}
1034%%
1035%% get internal file descriptor
1036%%
1037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038
1039getfd(S) when is_port(S) ->
1040    case ctl_cmd(S, ?INET_REQ_GETFD, []) of
1041	{ok, [S3,S2,S1,S0]} -> {ok, ?u32(S3,S2,S1,S0)};
1042	{error,_}=Error -> Error
1043    end.        
1044
1045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046%%
1047%% IGNOREFD(insock(),boolean()) -> {ok,integer()} | {error, Reason}
1048%%
1049%% steal internal file descriptor
1050%%
1051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1052
1053ignorefd(S,Bool) when is_port(S) ->
1054    Val = if Bool -> 1; true -> 0 end,
1055    case ctl_cmd(S, ?INET_REQ_IGNOREFD, [Val]) of
1056	{ok, _} -> ok;
1057	Error -> Error
1058    end.
1059
1060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1061%%
1062%% GETIX(insock()) -> {ok,integer()} | {error, Reason}
1063%%
1064%% get internal socket index
1065%%
1066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067
1068getindex(S) when is_port(S) ->
1069    %% NOT USED ANY MORE
1070    {error, einval}.
1071
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073%%
1074%% GETTYPE(insock()) -> {ok,{Family,Type}} | {error, Reason}
1075%%
1076%% get family/type of a socket
1077%%
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079
1080gettype(S) when is_port(S) ->
1081    case ctl_cmd(S, ?INET_REQ_GETTYPE, []) of
1082	{ok, [F3,F2,F1,F0,T3,T2,T1,T0]} ->
1083	    Family = case ?u32(F3,F2,F1,F0) of
1084			 ?INET_AF_INET  ->  inet;
1085			 ?INET_AF_INET6 ->  inet6;
1086			 _ -> undefined
1087		     end,
1088	    Type = case ?u32(T3,T2,T1,T0) of
1089			?INET_TYPE_STREAM    -> stream;
1090			?INET_TYPE_DGRAM     -> dgram;
1091			?INET_TYPE_SEQPACKET -> seqpacket;
1092			_		     -> undefined
1093		   end,
1094	    {ok, {Family, Type}};
1095	{error,_}=Error -> Error
1096    end.
1097
1098getprotocol(S) when is_port(S) ->
1099    {name,Drv} = erlang:port_info(S, name),
1100    drv2protocol(Drv).
1101
1102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103%%  IS_SCTP(insock()) -> true | false
1104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1105%% is_sctp(S) when is_port(S) ->
1106%%     case gettype(S) of
1107%% 	{ok, {_, seqpacket}} -> true;
1108%% 	_		     -> false
1109%%     end.
1110
1111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1112%%
1113%% GETSTATUS(insock()) -> {ok,Status} | {error, Reason}
1114%%
1115%% get socket status
1116%%
1117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118
1119getstatus(S) when is_port(S) ->
1120    case ctl_cmd(S, ?INET_REQ_GETSTATUS, []) of
1121	{ok, [S3,S2,S1,S0]} ->	
1122	    {ok, dec_status(?u32(S3,S2,S1,S0))};
1123	{error,_}=Error -> Error
1124    end.
1125
1126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127%%
1128%% GETHOSTNAME(insock()) -> {ok,HostName} | {error, Reason}
1129%%
1130%% get host name
1131%%
1132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133
1134gethostname(S) when is_port(S) ->
1135    ctl_cmd(S, ?INET_REQ_GETHOSTNAME, []).
1136
1137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138%%
1139%% GETSERVBYNAME(insock(),Name,Proto) -> {ok,Port} | {error, Reason}
1140%%
1141%% get service port
1142%%
1143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144
1145getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_atom(Proto) ->
1146    getservbyname1(S, atom_to_list(Name), atom_to_list(Proto));
1147getservbyname(S,Name,Proto) when is_port(S), is_atom(Name), is_list(Proto) ->
1148    getservbyname1(S, atom_to_list(Name), Proto);
1149getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_atom(Proto) ->
1150    getservbyname1(S, Name, atom_to_list(Proto));
1151getservbyname(S,Name,Proto) when is_port(S), is_list(Name), is_list(Proto) ->
1152    getservbyname1(S, Name, Proto);
1153getservbyname(_,_, _) ->
1154    {error, einval}.
1155
1156getservbyname1(S,Name,Proto) ->
1157    L1 = length(Name),
1158    L2 = length(Proto),
1159    if L1 > 255 -> {error, einval};
1160       L2 > 255 -> {error, einval};
1161       true ->
1162	    case ctl_cmd(S, ?INET_REQ_GETSERVBYNAME, [L1,Name,L2,Proto]) of
1163		{ok, [P1,P0]} ->
1164		    {ok, ?u16(P1,P0)};
1165		{error,_}=Error ->
1166		    Error
1167	    end
1168    end.
1169
1170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171%%
1172%% GETSERVBYPORT(insock(),Port,Proto) -> {ok,Port} | {error, Reason}
1173%%
1174%% get service port from portnumber and protocol
1175%%
1176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1177
1178getservbyport(S,Port,Proto) when is_port(S), is_atom(Proto) ->
1179    getservbyport1(S, Port, atom_to_list(Proto));
1180getservbyport(S,Port,Proto) when is_port(S), is_list(Proto) ->
1181    getservbyport1(S, Port, Proto);
1182getservbyport(_, _, _) ->
1183    {error, einval}.
1184
1185getservbyport1(S,Port,Proto) ->
1186    L = length(Proto),
1187    if Port < 0 -> {error, einval};
1188       Port > 16#ffff -> {error, einval};
1189       L > 255 -> {error, einval};
1190       true ->
1191	    case ctl_cmd(S, ?INET_REQ_GETSERVBYPORT, [?int16(Port),L,Proto]) of
1192		{ok, Name} -> {ok, Name};
1193		{error,_}=Error -> Error
1194	    end
1195    end.
1196
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198%% 
1199%% UNRECV(insock(), data) -> ok | {error, Reason}
1200%%
1201%%
1202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203
1204unrecv(S, Data) ->
1205    case ctl_cmd(S, ?TCP_REQ_UNRECV, Data) of
1206	{ok, _} -> ok;
1207	{error,_}=Error  -> Error
1208    end.
1209
1210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211%%
1212%% DETACH(insock()) -> ok
1213%%
1214%%   unlink from a socket 
1215%%
1216%% ATTACH(insock()) -> ok | {error, Reason}
1217%%
1218%%   link and connect to a socket 
1219%%
1220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221
1222detach(S) when is_port(S) ->
1223    unlink(S),
1224    ok.
1225
1226attach(S) when is_port(S) ->
1227    try erlang:port_connect(S, self()) of
1228	true -> link(S), ok
1229    catch
1230	error:Reason -> {error,Reason}
1231    end.
1232
1233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1234%%
1235%% INTERNAL FUNCTIONS
1236%%
1237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1238
1239is_sockopt_val(Opt, Val) ->
1240    Type = type_opt(set, Opt),
1241    try type_value(set, Type, Val)
1242    catch
1243	_ -> false
1244    end.
1245
1246%%
1247%% Socket options processing: Encoding option NAMES:
1248%%
1249enc_opt(reuseaddr)       -> ?INET_OPT_REUSEADDR;
1250enc_opt(keepalive)       -> ?INET_OPT_KEEPALIVE;
1251enc_opt(dontroute)       -> ?INET_OPT_DONTROUTE;
1252enc_opt(linger)          -> ?INET_OPT_LINGER;
1253enc_opt(broadcast)       -> ?INET_OPT_BROADCAST;
1254enc_opt(sndbuf)          -> ?INET_OPT_SNDBUF;
1255enc_opt(recbuf)          -> ?INET_OPT_RCVBUF;
1256enc_opt(priority)        -> ?INET_OPT_PRIORITY;
1257enc_opt(tos)             -> ?INET_OPT_TOS;
1258enc_opt(tclass)          -> ?INET_OPT_TCLASS;
1259enc_opt(nodelay)         -> ?TCP_OPT_NODELAY;
1260enc_opt(multicast_if)    -> ?UDP_OPT_MULTICAST_IF;
1261enc_opt(multicast_ttl)   -> ?UDP_OPT_MULTICAST_TTL;
1262enc_opt(multicast_loop)  -> ?UDP_OPT_MULTICAST_LOOP;
1263enc_opt(add_membership)  -> ?UDP_OPT_ADD_MEMBERSHIP;
1264enc_opt(drop_membership) -> ?UDP_OPT_DROP_MEMBERSHIP;
1265enc_opt(ipv6_v6only)     -> ?INET_OPT_IPV6_V6ONLY;
1266enc_opt(buffer)          -> ?INET_LOPT_BUFFER;
1267enc_opt(header)          -> ?INET_LOPT_HEADER;
1268enc_opt(active)          -> ?INET_LOPT_ACTIVE;
1269enc_opt(packet)          -> ?INET_LOPT_PACKET;
1270enc_opt(mode)            -> ?INET_LOPT_MODE;
1271enc_opt(deliver)         -> ?INET_LOPT_DELIVER;
1272enc_opt(exit_on_close)   -> ?INET_LOPT_EXITONCLOSE;
1273enc_opt(high_watermark)  -> ?INET_LOPT_TCP_HIWTRMRK;
1274enc_opt(low_watermark)   -> ?INET_LOPT_TCP_LOWTRMRK;
1275enc_opt(high_msgq_watermark)  -> ?INET_LOPT_MSGQ_HIWTRMRK;
1276enc_opt(low_msgq_watermark)   -> ?INET_LOPT_MSGQ_LOWTRMRK;
1277enc_opt(send_timeout)    -> ?INET_LOPT_TCP_SEND_TIMEOUT;
1278enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
1279enc_opt(delay_send)      -> ?INET_LOPT_TCP_DELAY_SEND;
1280enc_opt(packet_size)     -> ?INET_LOPT_PACKET_SIZE;
1281enc_opt(read_packets)    -> ?INET_LOPT_READ_PACKETS;
1282enc_opt(netns)           -> ?INET_LOPT_NETNS;
1283enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET;
1284enc_opt(line_delimiter)  -> ?INET_LOPT_LINE_DELIM;
1285enc_opt(raw)             -> ?INET_OPT_RAW;
1286enc_opt(bind_to_device)  -> ?INET_OPT_BIND_TO_DEVICE;
1287% Names of SCTP opts:
1288enc_opt(sctp_rtoinfo)	 	   -> ?SCTP_OPT_RTOINFO;
1289enc_opt(sctp_associnfo)	 	   -> ?SCTP_OPT_ASSOCINFO;
1290enc_opt(sctp_initmsg)	 	   -> ?SCTP_OPT_INITMSG;
1291enc_opt(sctp_autoclose)	 	   -> ?SCTP_OPT_AUTOCLOSE;
1292enc_opt(sctp_nodelay)		   -> ?SCTP_OPT_NODELAY;
1293enc_opt(sctp_disable_fragments)	   -> ?SCTP_OPT_DISABLE_FRAGMENTS;
1294enc_opt(sctp_i_want_mapped_v4_addr)-> ?SCTP_OPT_I_WANT_MAPPED_V4_ADDR;
1295enc_opt(sctp_maxseg)		   -> ?SCTP_OPT_MAXSEG;
1296enc_opt(sctp_set_peer_primary_addr)-> ?SCTP_OPT_SET_PEER_PRIMARY_ADDR;
1297enc_opt(sctp_primary_addr)	   -> ?SCTP_OPT_PRIMARY_ADDR;
1298enc_opt(sctp_adaptation_layer)	   -> ?SCTP_OPT_ADAPTATION_LAYER;
1299enc_opt(sctp_peer_addr_params)	   -> ?SCTP_OPT_PEER_ADDR_PARAMS;
1300enc_opt(sctp_default_send_param)   -> ?SCTP_OPT_DEFAULT_SEND_PARAM;
1301enc_opt(sctp_events)		   -> ?SCTP_OPT_EVENTS;
1302enc_opt(sctp_delayed_ack_time)	   -> ?SCTP_OPT_DELAYED_ACK_TIME;
1303enc_opt(sctp_status)		   -> ?SCTP_OPT_STATUS;
1304enc_opt(sctp_get_peer_addr_info)   -> ?SCTP_OPT_GET_PEER_ADDR_INFO.
1305%%
1306
1307%%
1308%% Decoding option NAMES:
1309%%
1310dec_opt(?INET_OPT_REUSEADDR)      -> reuseaddr;
1311dec_opt(?INET_OPT_KEEPALIVE)      -> keepalive;
1312dec_opt(?INET_OPT_DONTROUTE)      -> dontroute;
1313dec_opt(?INET_OPT_LINGER)         -> linger;
1314dec_opt(?INET_OPT_BROADCAST)      -> broadcast;
1315dec_opt(?INET_OPT_SNDBUF)         -> sndbuf;
1316dec_opt(?INET_OPT_RCVBUF)         -> recbuf;
1317dec_opt(?INET_OPT_PRIORITY)       -> priority;
1318dec_opt(?INET_OPT_TOS)            -> tos;
1319dec_opt(?INET_OPT_TCLASS)         -> tclass;
1320dec_opt(?TCP_OPT_NODELAY)         -> nodelay;
1321dec_opt(?UDP_OPT_MULTICAST_IF)    -> multicast_if;
1322dec_opt(?UDP_OPT_MULTICAST_TTL)   -> multicast_ttl;
1323dec_opt(?UDP_OPT_MULTICAST_LOOP)  -> multicast_loop;
1324dec_opt(?UDP_OPT_ADD_MEMBERSHIP)  -> add_membership;
1325dec_opt(?UDP_OPT_DROP_MEMBERSHIP) -> drop_membership;
1326dec_opt(?INET_OPT_IPV6_V6ONLY)    -> ipv6_v6only;
1327dec_opt(?INET_LOPT_BUFFER)        -> buffer;
1328dec_opt(?INET_LOPT_HEADER)        -> header;
1329dec_opt(?INET_LOPT_ACTIVE)        -> active;
1330dec_opt(?INET_LOPT_PACKET)        -> packet;
1331dec_opt(?INET_LOPT_MODE)          -> mode;
1332dec_opt(?INET_LOPT_DELIVER)       -> deliver;
1333dec_opt(?INET_LOPT_EXITONCLOSE)   -> exit_on_close;
1334dec_opt(?INET_LOPT_TCP_HIWTRMRK)  -> high_watermark;
1335dec_opt(?INET_LOPT_TCP_LOWTRMRK)  -> low_watermark;
1336dec_opt(?INET_LOPT_MSGQ_HIWTRMRK)  -> high_msgq_watermark;
1337dec_opt(?INET_LOPT_MSGQ_LOWTRMRK)  -> low_msgq_watermark;
1338dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
1339dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
1340dec_opt(?INET_LOPT_TCP_DELAY_SEND)   -> delay_send;
1341dec_opt(?INET_LOPT_PACKET_SIZE)      -> packet_size;
1342dec_opt(?INET_LOPT_READ_PACKETS)     -> read_packets;
1343dec_opt(?INET_LOPT_NETNS)           -> netns;
1344dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset;
1345dec_opt(?INET_LOPT_LINE_DELIM)      -> line_delimiter;
1346dec_opt(?INET_OPT_RAW)              -> raw;
1347dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device;
1348dec_opt(I) when is_integer(I)     -> undefined.
1349
1350
1351
1352%% Metatypes:
1353%% []              Value must be 'undefined' or nonexistent
1354%%                 for setopts and getopts.
1355%% [Type]          Value required for setopts and getopts,
1356%%                 will be encoded for both.
1357%% [Type,Default]  Default used if value is 'undefined'.
1358%% [[Type,Default]] A combination of the two above.
1359%% Type            Value must be 'undefined' or nonexistent for getops,
1360%%                 required for setopts.
1361%%
1362%% The use of [] and [[Type,Default]] is commented out in enc_value/2
1363%% and type_value/2 below since they are only used in record fields.
1364%% And record fields does not call enc_value/2 nor type_value/2.
1365%% Anyone introducing these metatypes otherwhere will have to activate
1366%% those clauses in enc_value/2 and type_value/2. You have been warned!
1367
1368type_opt(get, raw) -> [{[int],[int],[binary_or_uint]}];
1369type_opt(_,   raw) -> {int,int,binary};
1370%% NB: "sctp_status" and "sctp_get_peer_addr_info" are read-only options,
1371%% so they should not be NOT encoded for use with "setopt".
1372type_opt(get, sctp_status) ->
1373    [{record,#sctp_status{
1374	assoc_id = [sctp_assoc_id],
1375	_        = []}}];
1376type_opt(get, sctp_get_peer_addr_info) ->
1377    [{record,#sctp_paddrinfo{
1378	assoc_id = [[sctp_assoc_id,0]],
1379	address  = [[addr,{any,0}]],
1380	_        = []}}];
1381type_opt(_,   Opt) ->
1382    type_opt_1(Opt).
1383
1384%% Types of option values, by option name:
1385%%
1386type_opt_1(reuseaddr)       -> bool;
1387type_opt_1(keepalive)       -> bool;
1388type_opt_1(dontroute)       -> bool;
1389type_opt_1(linger)          -> {bool,int};
1390type_opt_1(broadcast)       -> bool;
1391type_opt_1(sndbuf)          -> int;
1392type_opt_1(recbuf)          -> int;
1393type_opt_1(priority)        -> int;
1394type_opt_1(tos)             -> int;
1395type_opt_1(tclass)          -> int;
1396type_opt_1(nodelay)         -> bool;
1397type_opt_1(ipv6_v6only)     -> bool;
1398%% multicast
1399type_opt_1(multicast_ttl)   -> int;
1400type_opt_1(multicast_loop)  -> bool;
1401type_opt_1(multicast_if)    -> ip;
1402type_opt_1(add_membership)  -> {ip,ip};
1403type_opt_1(drop_membership) -> {ip,ip};
1404%% driver options
1405type_opt_1(header)          -> uint;
1406type_opt_1(buffer)          -> int;
1407type_opt_1(active) ->
1408    {enum,[{false, ?INET_PASSIVE}, 
1409	   {true, ?INET_ACTIVE}, 
1410	   {once, ?INET_ONCE},
1411           {multi, ?INET_MULTI}]};
1412type_opt_1(packet) -> 
1413    {enum,[{0, ?TCP_PB_RAW},
1414	   {1, ?TCP_PB_1},
1415	   {2, ?TCP_PB_2},
1416	   {4, ?TCP_PB_4},
1417	   {raw,?TCP_PB_RAW},
1418	   {sunrm, ?TCP_PB_RM},
1419	   {asn1, ?TCP_PB_ASN1},
1420	   {cdr, ?TCP_PB_CDR},
1421	   {fcgi, ?TCP_PB_FCGI},
1422	   {line, ?TCP_PB_LINE_LF},
1423	   {tpkt, ?TCP_PB_TPKT},
1424	   {http, ?TCP_PB_HTTP},
1425	   {httph,?TCP_PB_HTTPH},
1426	   {http_bin, ?TCP_PB_HTTP_BIN},
1427	   {httph_bin,?TCP_PB_HTTPH_BIN},
1428	   {ssl, ?TCP_PB_SSL_TLS}, % obsolete
1429	   {ssl_tls, ?TCP_PB_SSL_TLS}]};
1430type_opt_1(line_delimiter)  -> int;
1431type_opt_1(mode) ->
1432    {enum,[{list, ?INET_MODE_LIST},
1433	   {binary, ?INET_MODE_BINARY}]};
1434type_opt_1(deliver) ->
1435    {enum,[{port, ?INET_DELIVER_PORT},
1436	   {term, ?INET_DELIVER_TERM}]};
1437type_opt_1(exit_on_close)   -> bool;
1438type_opt_1(low_watermark)   -> int;
1439type_opt_1(high_watermark)  -> int;
1440type_opt_1(low_msgq_watermark)   -> int;
1441type_opt_1(high_msgq_watermark)  -> int;
1442type_opt_1(send_timeout)    -> time;
1443type_opt_1(send_timeout_close) -> bool;
1444type_opt_1(delay_send)      -> bool;
1445type_opt_1(packet_size)     -> uint;
1446type_opt_1(read_packets)    -> uint;
1447type_opt_1(netns)           -> binary;
1448type_opt_1(show_econnreset) -> bool;
1449type_opt_1(bind_to_device)  -> binary;
1450%% 
1451%% SCTP options (to be set). If the type is a record type, the corresponding
1452%% record signature is returned, otherwise, an "elementary" type tag 
1453%% is returned:
1454%% 
1455%% for SCTP_OPT_RTOINFO
1456type_opt_1(sctp_rtoinfo) ->
1457    [{record,#sctp_rtoinfo{
1458	assoc_id = [[sctp_assoc_id,0]],
1459	initial  = [uint32,0],
1460	max      = [uint32,0],
1461	min      = [uint32,0]}}];
1462%% for SCTP_OPT_ASSOCINFO
1463type_opt_1(sctp_associnfo) ->
1464    [{record,#sctp_assocparams{
1465	assoc_id                 = [[sctp_assoc_id,0]],
1466	asocmaxrxt               = [uint16,0],
1467	number_peer_destinations = [uint16,0],
1468	peer_rwnd                = [uint32,0],
1469	local_rwnd               = [uint32,0],
1470	cookie_life              = [uint32,0]}}];
1471%% for SCTP_OPT_INITMSG and SCTP_TAG_SEND_ANC_INITMSG (send*)
1472type_opt_1(sctp_initmsg) ->
1473    [{record,#sctp_initmsg{
1474	num_ostreams   = [uint16,0],
1475	max_instreams  = [uint16,0],
1476	max_attempts   = [uint16,0],
1477	max_init_timeo = [uint16,0]}}];
1478%%
1479type_opt_1(sctp_nodelay)	       -> bool;
1480type_opt_1(sctp_autoclose)	       -> uint;
1481type_opt_1(sctp_disable_fragments)     -> bool;
1482type_opt_1(sctp_i_want_mapped_v4_addr) -> bool;
1483type_opt_1(sctp_maxseg)		       -> uint;
1484%% for SCTP_OPT_PRIMARY_ADDR
1485type_opt_1(sctp_primary_addr) ->
1486    [{record,#sctp_prim{
1487	assoc_id = [sctp_assoc_id],
1488	addr     = addr}}];
1489%% for SCTP_OPT_SET_PEER_PRIMARY_ADDR
1490type_opt_1(sctp_set_peer_primary_addr) ->
1491    [{record,#sctp_setpeerprim{
1492	assoc_id = [sctp_assoc_id],
1493	addr     = addr}}];
1494%% for SCTP_OPT_ADAPTATION_LAYER
1495type_opt_1(sctp_adaptation_layer) ->
1496    [{record,#sctp_setadaptation{
1497	adaptation_ind = [uint32,0]}}];
1498%% for SCTP_OPT_PEER_ADDR_PARAMS
1499type_opt_1(sctp_peer_addr_params) ->
1500    [{record,#sctp_paddrparams{
1501	assoc_id          = [[sctp_assoc_id,0]],
1502	address           = [[addr,{any,0}]],
1503	hbinterval        = [uint32,0],
1504	pathmaxrxt        = [uint16,0],
1505	pathmtu           = [uint32,0],
1506	sackdelay         = [uint32,0],
1507	flags             =
1508	[{bitenumlist,
1509	  [{hb_enable,         ?SCTP_FLAG_HB_ENABLE},
1510	   {hb_disable,        ?SCTP_FLAG_HB_DISABLE},
1511	   {hb_demand,         ?SCTP_FLAG_HB_DEMAND},
1512	   {pmtud_enable,      ?SCTP_FLAG_PMTUD_ENABLE},
1513	   {pmtud_disable,     ?SCTP_FLAG_PMTUD_DISABLE},
1514	   {sackdelay_enable,  ?SCTP_FLAG_SACKDELAY_ENABLE},
1515	   {sackdelay_disable, ?SCTP_FLAG_SACKDELAY_DISABLE}],
1516	  uint32},[]]}}];
1517%% for SCTP_OPT_DEFAULT_SEND_PARAM and SCTP_TAG_SEND_ANC_PARAMS (on send*)
1518type_opt_1(sctp_default_send_param) ->
1519    [{record,#sctp_sndrcvinfo{
1520	stream            = [uint16,0],
1521	ssn               = [],
1522	flags             =
1523	[{bitenumlist,
1524	  [{unordered,  ?SCTP_FLAG_UNORDERED},
1525	   {addr_over,  ?SCTP_FLAG_ADDR_OVER},
1526	   {abort,      ?SCTP_FLAG_ABORT},
1527	   {eof,        ?SCTP_FLAG_EOF}],
1528	  uint16},[]],
1529	ppid              = [uint32,0],
1530	context           = [uint32,0],
1531	timetolive        = [uint32,0],
1532	tsn               = [],
1533	cumtsn            = [],
1534	assoc_id          = [[sctp_assoc_id,0]]}}];
1535%% for SCTP_OPT_EVENTS
1536type_opt_1(sctp_events) ->
1537    [{record,#sctp_event_subscribe{
1538	data_io_event          = [bool8,true],
1539        association_event      = [bool8,true], 
1540	address_event          = [bool8,true], 
1541	send_failure_event     = [bool8,true], 
1542	peer_error_event       = [bool8,true], 
1543	shutdown_event         = [bool8,true], 
1544	partial_delivery_event = [bool8,true], 
1545	adaptation_layer_event = [bool8,false],
1546	authentication_event   = [bool8,false]}}];
1547%% for SCTP_OPT_DELAYED_ACK_TIME
1548type_opt_1(sctp_delayed_ack_time) ->
1549    [{record,#sctp_assoc_value{
1550	assoc_id    = [[sctp_assoc_id,0]],
1551	assoc_value = [uint32,0]}}];
1552%%
1553type_opt_1(undefined)         -> undefined;
1554type_opt_1(O) when is_atom(O) -> undefined.
1555
1556
1557
1558%% Get. No supplied value.
1559type_value(get, undefined)        -> false; % Undefined type
1560%% These two clauses can not happen since they are only used
1561%% in record fields - from record fields they must have a
1562%% value though it might be 'undefined', so record fields
1563%% calls type_value/3, not type_value/2.
1564%% type_value(get, [])               -> true;  % Ignored
1565%% type_value(get, [[Type,Default]]) ->        % Required field, default value
1566%%     type_value(get, Type, Default);
1567type_value(get, [{record,Types}]) ->        % Implied default value for record
1568    type_value_record(get, Types, 
1569		      erlang:make_tuple(tuple_size(Types), undefined), 2);
1570type_value(get, [_])              -> false; % Required value missing
1571type_value(get, _)                -> true.  % Field is supposed to be undefined
1572
1573%% Get and set. Value supplied.
1574type_value(_, undefined, _)   -> false;     % Undefined type
1575type_value(_, [], undefined)  -> true;      % Ignored
1576type_value(_, [], _)          -> false;     % Value should not be supplied
1577type_value(Q, [Type], Value)  ->            % Required field, proceed
1578    type_value_default(Q, Type, Value);
1579type_value(set, Type, Value)  ->            % Required for setopts
1580    type_value

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