PageRenderTime 96ms CodeModel.GetById 3ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 1ms

/erts/preloaded/src/prim_inet.erl

https://github.com/bsmr-erlang/otp
Erlang | 2706 lines | 1880 code | 247 blank | 579 comment | 11 complexity | 39f297b743d9da24d2c77a35d48aa809 MD5 | raw file

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

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

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