From 944a57a11a79c5a9bb2f554c921e2e00e7d56c91 Mon Sep 17 00:00:00 2001
From: Ricardo
Date: Sat, 4 Feb 2012 16:32:21 +0100
Subject: Fix port leaking after controlling_process(Port, self())
Add case to handle the situation when someone call
{gen_tcp,gen_udp}:controlling_process(Port, self()). Also improve spec
and doc from gen_udp and gen_sctp for controlling_process/2.
To reproduce the issue, open an UDP port:
4> {ok,Port} = gen_udp:open(9000, [binary]).
{ok,#Port<0.587>}
5> gen_udp:controlling_process(Port, self()).
ok
Simulate error:
6> 1=2.
** exception error: no match of right hand side value 2
Here is the leak:
7> inet:i().
Port Module Recv Sent Owner Local Address Foreign Address State
Type
581 inet_udp 0 0 <0.31.0> *:cslistener *:* BOUND
DGRAM
ok
---
lib/kernel/doc/src/gen_tcp.xml | 2 +-
lib/kernel/doc/src/gen_udp.xml | 4 +++-
lib/kernel/src/gen_sctp.erl | 5 +++--
lib/kernel/src/gen_udp.erl | 5 +++--
lib/kernel/src/inet.erl | 4 ++++
5 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 8a5d40bb16..27c454afba 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -297,7 +297,7 @@ do_recv(Sock, Bs) ->
Socket. The controlling process is the process which
receives messages from the socket. If called by any other
process than the current controlling process,
- {error, eperm} is returned.
+ {error, not_owner} is returned.
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index daa9b7d887..9882d3fab1 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -136,7 +136,9 @@
Assigns a new controlling process Pid to
Socket. The controlling process is the process which
- receives messages from the socket.
+ receives messages from the socket. If called by any other
+ process than the current controlling process,
+ {error, not_owner} is returned.
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index d8954f0cf7..8fa963ec78 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -425,9 +425,10 @@ error_string(X) ->
erlang:error(badarg, [X]).
--spec controlling_process(Socket, Pid) -> ok when
+-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: sctp_socket(),
- Pid :: pid().
+ Pid :: pid(),
+ Reason :: closed | not_owner | inet:posix().
controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 8688799ae9..914854c65c 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -185,9 +185,10 @@ connect(S, Address, Port) when is_port(S) ->
Error
end.
--spec controlling_process(Socket, Pid) -> ok when
+-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: socket(),
- Pid :: pid().
+ Pid :: pid(),
+ Reason :: closed | not_owner | inet:posix().
controlling_process(S, NewOwner) ->
inet:udp_controlling_process(S, NewOwner).
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 49f64a9236..3356fb55d7 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1244,6 +1244,8 @@ udp_close(S) when is_port(S) ->
%% Set controlling process for TCP socket.
tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
case erlang:port_info(S, connected) of
+ {connected, NewOwner} ->
+ ok;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
undefined ->
@@ -1295,6 +1297,8 @@ tcp_sync_input(S, Owner, Flag) ->
%% Set controlling process for UDP or SCTP socket.
udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
case erlang:port_info(S, connected) of
+ {connected, NewOwner} ->
+ ok;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
_ ->
--
cgit v1.2.3