diff options
Diffstat (limited to 'lib/kernel/src/gen_tcp.erl')
-rw-r--r-- | lib/kernel/src/gen_tcp.erl | 190 |
1 files changed, 177 insertions, 13 deletions
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 7401b06a64..8ab18c01b4 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,12 +28,109 @@ -include("inet_int.hrl"). +-type option() :: + {active, true | false | once} | + {bit8, clear | set | on | off} | + {buffer, non_neg_integer()} | + {delay_send, boolean()} | + {deliver, port | term} | + {dontroute, boolean()} | + {exit_on_close, boolean()} | + {header, non_neg_integer()} | + {high_watermark, non_neg_integer()} | + {keepalive, boolean()} | + {linger, {boolean(), non_neg_integer()}} | + {low_watermark, non_neg_integer()} | + {mode, list | binary} | list | binary | + {nodelay, boolean()} | + {packet, + 0 | 1 | 2 | 4 | raw | sunrm | asn1 | + cdr | fcgi | line | tpkt | http | httph | http_bin | httph_bin } | + {packet_size, non_neg_integer()} | + {priority, non_neg_integer()} | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueBin :: binary()} | + {recbuf, non_neg_integer()} | + {reuseaddr, boolean()} | + {send_timeout, non_neg_integer() | infinity} | + {send_timeout_close, boolean()} | + {sndbuf, non_neg_integer()} | + {tos, non_neg_integer()}. +-type option_name() :: + active | + bit8 | + buffer | + delay_send | + deliver | + dontroute | + exit_on_close | + header | + high_watermark | + keepalive | + linger | + low_watermark | + mode | + nodelay | + packet | + packet_size | + priority | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueSpec :: (ValueSize :: non_neg_integer()) | + (ValueBin :: binary())} | + recbuf | + reuseaddr | + send_timeout | + send_timeout_close | + sndbuf | + tos. +-type connect_option() :: + {ip, inet:ip_address()} | + {fd, Fd :: non_neg_integer()} | + {ifaddr, inet:ip_address()} | + inet:address_family() | + {port, inet:port_number()} | + {tcp_module, module()} | + option(). +-type listen_option() :: + {ip, inet:ip_address()} | + {fd, Fd :: non_neg_integer()} | + {ifaddr, inet:ip_address()} | + inet:address_family() | + {port, inet:port_number()} | + {backlog, B :: non_neg_integer()} | + {tcp_module, module()} | + option(). +-type socket() :: port(). + +-export_type([option/0, option_name/0, connect_option/0, listen_option/0]). + %% %% Connect a socket %% + +-spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when + Address :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Options :: [connect_option()], + Socket :: socket(), + Reason :: inet:posix(). + connect(Address, Port, Opts) -> connect(Address,Port,Opts,infinity). +-spec connect(Address, Port, Options, Timeout) -> + {ok, Socket} | {error, Reason} when + Address :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Options :: [connect_option()], + Timeout :: timeout(), + Socket :: socket(), + Reason :: inet:posix(). + connect(Address, Port, Opts, Time) -> Timer = inet:start_timer(Time), Res = (catch connect1(Address,Port,Opts,Timer)), @@ -46,7 +143,7 @@ connect(Address, Port, Opts, Time) -> end. connect1(Address,Port,Opts,Timer) -> - Mod = mod(Opts), + Mod = mod(Opts, Address), case Mod:getaddrs(Address,Timer) of {ok,IPs} -> case Mod:getserv(Port) of @@ -72,8 +169,15 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) -> %% %% Listen on a tcp port %% + +-spec listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} when + Port :: inet:port_number(), + Options :: [listen_option()], + ListenSocket :: socket(), + Reason :: inet:posix(). + listen(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:getserv(Port) of {ok,TP} -> Mod:listen(TP, Opts); @@ -85,6 +189,12 @@ listen(Port, Opts) -> %% %% Generic tcp accept %% + +-spec accept(ListenSocket) -> {ok, Socket} | {error, Reason} when + ListenSocket :: socket(), + Socket :: socket(), + Reason :: closed | timeout | inet:posix(). + accept(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -93,6 +203,12 @@ accept(S) -> Error end. +-spec accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason} when + ListenSocket :: socket(), + Timeout :: timeout(), + Socket :: socket(), + Reason :: closed | timeout | inet:posix(). + accept(S, Time) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -104,6 +220,12 @@ accept(S, Time) when is_port(S) -> %% %% Generic tcp shutdown %% + +-spec shutdown(Socket, How) -> ok | {error, Reason} when + Socket :: socket(), + How :: read | write | read_write, + Reason :: inet:posix(). + shutdown(S, How) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -115,12 +237,22 @@ shutdown(S, How) when is_port(S) -> %% %% Close %% + +-spec close(Socket) -> ok when + Socket :: socket(). + close(S) -> inet:tcp_close(S). %% %% Send %% + +-spec send(Socket, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Packet :: iodata(), + Reason :: inet:posix(). + send(S, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -132,6 +264,14 @@ send(S, Packet) when is_port(S) -> %% %% Receive data from a socket (passive mode) %% + +-spec recv(Socket, Length) -> {ok, Packet} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Packet :: string() | binary() | HttpPacket, + Reason :: closed | inet:posix(), + HttpPacket :: term(). + recv(S, Length) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -140,6 +280,14 @@ recv(S, Length) when is_port(S) -> Error end. +-spec recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Timeout :: timeout(), + Packet :: string() | binary() | HttpPacket, + Reason :: closed | inet:posix(), + HttpPacket :: term(). + recv(S, Length, Time) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -159,6 +307,12 @@ unrecv(S, Data) when is_port(S) -> %% %% Set controlling process %% + +-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when + Socket :: socket(), + Pid :: pid(), + Reason :: closed | not_owner | inet:posix(). + controlling_process(S, NewOwner) -> case inet_db:lookup_socket(S) of {ok, _Mod} -> % Just check that this is an open socket @@ -173,20 +327,30 @@ controlling_process(S, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), Mod:fdopen(Fd, Opts). -%% Get the tcp_module -mod() -> inet_db:tcp_module(). +%% Get the tcp_module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:tcp_module() of + inet_tcp when tuple_size(Address) =:= 8 -> + inet6_tcp; + Mod -> + Mod + end. %% Get the tcp_module, but option tcp_module|inet|inet6 overrides -mod([{tcp_module,Mod}|_]) -> +mod([{tcp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_tcp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_tcp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). |