aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded/src/prim_inet.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/preloaded/src/prim_inet.erl')
-rw-r--r--erts/preloaded/src/prim_inet.erl154
1 files changed, 111 insertions, 43 deletions
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index b746aab049..ff83976cf5 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -520,13 +520,35 @@ sendfile(S, FileHandle, Offset, Length)
sendfile(S, FileHandle, Offset, Length) ->
case erlang:port_info(S, connected) of
{connected, Pid} when Pid =:= self() ->
- sendfile_1(S, FileHandle, Offset, Length);
+ Uncork = sendfile_maybe_cork(S),
+ Result = sendfile_1(S, FileHandle, Offset, Length),
+ sendfile_maybe_uncork(S, Uncork),
+ Result;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
_Other ->
{error, einval}
end.
+sendfile_maybe_cork(S) ->
+ case getprotocol(S) of
+ tcp ->
+ case getopts(S, [nopush]) of
+ {ok, [{nopush,false}]} ->
+ _ = setopts(S, [{nopush,true}]),
+ true;
+ _ ->
+ false
+ end;
+ _ -> false
+ end.
+
+sendfile_maybe_uncork(S, true) ->
+ _ = setopts(S, [{nopush,false}]),
+ ok;
+sendfile_maybe_uncork(_, false) ->
+ ok.
+
sendfile_1(S, FileHandle, Offset, 0) ->
sendfile_1(S, FileHandle, Offset, (1 bsl 63) - 1);
sendfile_1(_S, _FileHandle, Offset, Length) when
@@ -870,9 +892,9 @@ chgopts(S, Opts) when is_port(S), is_list(Opts) ->
getifaddrs(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
- {ok, Data} ->
- {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())};
- {error,enotsup} ->
+ {ok, Data} ->
+ {ok, comp_ifaddrs(build_ifaddrs(Data))};
+ {error,enotsup} ->
case getiflist(S) of
{ok, IFs} ->
{ok, getifaddrs_ifget(S, IFs)};
@@ -881,30 +903,75 @@ getifaddrs(S) when is_port(S) ->
Err2 -> Err2
end.
-%% Restructure interface properties per interface and remove duplicates
-
-comp_ifaddrs([{If,Opts}|IfOpts], T) ->
- case ktree_is_defined(If, T) of
- true ->
- OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts),
- comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T));
- false ->
- OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
- comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
- end;
-comp_ifaddrs([], T) ->
- [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
-
-comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
- case ktree_is_defined(Opt, OptSet) of
- true
- when element(1, Opt) =:= flags;
- element(1, Opt) =:= hwaddr ->
- comp_ifaddrs_add(OptSet, Opts);
- _ ->
- comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
+%% Restructure interface properties per interface
+
+comp_ifaddrs(IfOpts) ->
+ comp_ifaddrs(IfOpts, ktree_empty()).
+%%
+comp_ifaddrs([{If,[{flags,Flags}|Opts]}|IfOpts], IfT) ->
+ case ktree_is_defined(If, IfT) of
+ true ->
+ comp_ifaddrs(
+ IfOpts,
+ ktree_update(
+ If,
+ comp_ifaddrs_flags(Flags, Opts, ktree_get(If, IfT)),
+ IfT));
+ false ->
+ comp_ifaddrs(
+ IfOpts,
+ ktree_insert(
+ If,
+ comp_ifaddrs_flags(Flags, Opts, ktree_empty()),
+ IfT))
end;
-comp_ifaddrs_add(OptSet, []) -> OptSet.
+comp_ifaddrs([], IfT) ->
+ comp_ifaddrs_2(ktree_keys(IfT), IfT).
+
+comp_ifaddrs_flags(Flags, Opts, FlagsT) ->
+ case ktree_is_defined(Flags, FlagsT) of
+ true ->
+ ktree_update(
+ Flags,
+ rev(Opts, ktree_get(Flags, FlagsT)),
+ FlagsT);
+ false ->
+ ktree_insert(Flags, rev(Opts), FlagsT)
+ end.
+
+comp_ifaddrs_2([If|Ifs], IfT) ->
+ FlagsT = ktree_get(If, IfT),
+ [{If,comp_ifaddrs_3(ktree_keys(FlagsT), FlagsT)}
+ | comp_ifaddrs_2(Ifs, IfT)];
+comp_ifaddrs_2([], _IfT) ->
+ [].
+%%
+comp_ifaddrs_3([Flags|FlagsL], FlagsT) ->
+ [{flags,Flags}|hwaddr_last(rev(ktree_get(Flags, FlagsT)))]
+ ++ hwaddr_last(comp_ifaddrs_3(FlagsL, FlagsT));
+comp_ifaddrs_3([], _FlagsT) ->
+ [].
+
+%% Place hwaddr last to look more like legacy emulation
+hwaddr_last(Opts) ->
+ hwaddr_last(Opts, Opts, []).
+%%
+hwaddr_last([{hwaddr,_} = Opt|Opts], L, R) ->
+ hwaddr_last(Opts, L, [Opt|R]);
+hwaddr_last([_|Opts], L, R) ->
+ hwaddr_last(Opts, L, R);
+hwaddr_last([], L, []) ->
+ L;
+hwaddr_last([], L, R) ->
+ rev(hwaddr_last(L, []), rev(R)).
+%%
+hwaddr_last([{hwaddr,_}|Opts], R) ->
+ hwaddr_last(Opts, R);
+hwaddr_last([Opt|Opts], R) ->
+ hwaddr_last(Opts, [Opt|R]);
+hwaddr_last([], R) ->
+ R.
+
%% Legacy emulation of getifaddrs
@@ -912,21 +979,19 @@ getifaddrs_ifget(_, []) -> [];
getifaddrs_ifget(S, [IF|IFs]) ->
case ifget(S, IF, [flags]) of
{ok,[{flags,Flags}]=FlagsVals} ->
- BroadOpts =
- case member(broadcast, Flags) of
- true ->
- [broadaddr,hwaddr];
- false ->
- [hwaddr]
- end,
- P2POpts =
- case member(pointtopoint, Flags) of
- true ->
- [dstaddr|BroadOpts];
- false ->
- BroadOpts
- end,
- getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]);
+ GetOpts =
+ case member(pointtopoint, Flags) of
+ true ->
+ [dstaddr,hwaddr];
+ false ->
+ case member(broadcast, Flags) of
+ true ->
+ [broadaddr,hwaddr];
+ false ->
+ [hwaddr]
+ end
+ end,
+ getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|GetOpts]);
_ ->
getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
end.
@@ -1275,6 +1340,7 @@ enc_opt(pktoptions) -> ?INET_OPT_PKTOPTIONS;
enc_opt(ttl) -> ?INET_OPT_TTL;
enc_opt(recvttl) -> ?INET_OPT_RECVTTL;
enc_opt(nodelay) -> ?TCP_OPT_NODELAY;
+enc_opt(nopush) -> ?TCP_OPT_NOPUSH;
enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF;
enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
enc_opt(multicast_loop) -> ?UDP_OPT_MULTICAST_LOOP;
@@ -1336,6 +1402,7 @@ dec_opt(?INET_OPT_PRIORITY) -> priority;
dec_opt(?INET_OPT_TOS) -> tos;
dec_opt(?INET_OPT_TCLASS) -> tclass;
dec_opt(?TCP_OPT_NODELAY) -> nodelay;
+dec_opt(?TCP_OPT_NOPUSH) -> nopush;
dec_opt(?INET_OPT_RECVTOS) -> recvtos;
dec_opt(?INET_OPT_RECVTCLASS) -> recvtclass;
dec_opt(?INET_OPT_PKTOPTIONS) -> pktoptions;
@@ -1422,6 +1489,7 @@ type_opt_1(pktoptions) -> opts;
type_opt_1(ttl) -> int;
type_opt_1(recvttl) -> bool;
type_opt_1(nodelay) -> bool;
+type_opt_1(nopush) -> bool;
type_opt_1(ipv6_v6only) -> bool;
%% multicast
type_opt_1(multicast_ttl) -> int;
@@ -2500,7 +2568,7 @@ get_addrs([F|Addrs]) ->
[Addr|get_addrs(Rest)].
get_addr(?INET_AF_LOCAL, [N|Addr]) ->
- {A,Rest} = lists:split(N, Addr),
+ {A,Rest} = split(N, Addr),
{{local,iolist_to_binary(A)},Rest};
get_addr(?INET_AF_UNSPEC, Rest) ->
{{unspec,<<>>},Rest};