{"action":"closed","issue":{"url":"https://api.github.com/repos/dotnet/corefx/issues/21865","repository_url":"https://api.github.com/repos/dotnet/corefx","labels_url":"https://api.github.com/repos/dotnet/corefx/issues/21865/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/21865/comments","events_url":"https://api.github.com/repos/dotnet/corefx/issues/21865/events","html_url":"https://github.com/dotnet/corefx/issues/21865","id":240459560,"number":21865,"title":"Zero byte Socket.ReceiveAsync does not complete when peer disconnects on Unix","user":{"login":"tmds","id":1025424,"avatar_url":"https://avatars2.githubusercontent.com/u/1025424?v=3","gravatar_id":"","url":"https://api.github.com/users/tmds","html_url":"https://github.com/tmds","followers_url":"https://api.github.com/users/tmds/followers","following_url":"https://api.github.com/users/tmds/following{/other_user}","gists_url":"https://api.github.com/users/tmds/gists{/gist_id}","starred_url":"https://api.github.com/users/tmds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tmds/subscriptions","organizations_url":"https://api.github.com/users/tmds/orgs","repos_url":"https://api.github.com/users/tmds/repos","events_url":"https://api.github.com/users/tmds/events{/privacy}","received_events_url":"https://api.github.com/users/tmds/received_events","type":"User","site_admin":false},"labels":[{"id":497898539,"url":"https://api.github.com/repos/dotnet/corefx/labels/area-System.Net.Sockets","name":"area-System.Net.Sockets","color":"d4c5f9","default":false},{"id":145399955,"url":"https://api.github.com/repos/dotnet/corefx/labels/bug","name":"bug","color":"207de5","default":true}],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/dotnet/corefx/milestones/4","html_url":"https://github.com/dotnet/corefx/milestone/4","labels_url":"https://api.github.com/repos/dotnet/corefx/milestones/4/labels","id":1248719,"number":4,"title":"2.0.0","description":".NET Core 2.0, next major release. See [official release dates](https://github.com/dotnet/core/blob/master/roadmap.md) for details.","creator":{"login":"joshfree","id":1302850,"avatar_url":"https://avatars2.githubusercontent.com/u/1302850?v=3","gravatar_id":"","url":"https://api.github.com/users/joshfree","html_url":"https://github.com/joshfree","followers_url":"https://api.github.com/users/joshfree/followers","following_url":"https://api.github.com/users/joshfree/following{/other_user}","gists_url":"https://api.github.com/users/joshfree/gists{/gist_id}","starred_url":"https://api.github.com/users/joshfree/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshfree/subscriptions","organizations_url":"https://api.github.com/users/joshfree/orgs","repos_url":"https://api.github.com/users/joshfree/repos","events_url":"https://api.github.com/users/joshfree/events{/privacy}","received_events_url":"https://api.github.com/users/joshfree/received_events","type":"User","site_admin":false},"open_issues":12,"closed_issues":8433,"state":"open","created_at":"2015-08-10T18:04:00Z","updated_at":"2017-07-06T14:48:38Z","due_on":"2017-07-07T07:00:00Z","closed_at":null},"comments":15,"created_at":"2017-07-04T16:04:53Z","updated_at":"2017-07-06T14:48:38Z","closed_at":"2017-07-06T14:48:38Z","body":"When there is a pending Socket.ReceiveAsync for count==0 and the peer disconnects, the Completed event does not fire.\r\n\r\nThis is caused by a workaround for macOS. When the peer disconnects, GetBytesAvailable returns 0.\r\nhttps://github.com/dotnet/corefx/blob/29fb3994aa493d68bb080063287f200a3a50167d/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs#L619-L640.\r\n\r\nCC @stephentoub \r\n\r\nrepro:\r\n```C#\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Net;\r\nusing System.Net.Sockets;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace ConsoleApplication\r\n{\r\n    public class Program\r\n    {\r\n        public static void Main(string[] args)\r\n        {\r\n            new Program().Run();\r\n        }\r\n\r\n        Thread _serverThread;\r\n        Thread _clientThread;\r\n\r\n        // used to synchronize between the threads\r\n        TaskCompletionSource<IPEndPoint> _serverListening = new TaskCompletionSource<IPEndPoint>();\r\n        TaskCompletionSource<object> _clientCompleted = new TaskCompletionSource<object>();\r\n\r\n        public void Run()\r\n        {\r\n            _serverThread = new Thread(ServerThread);\r\n            _clientThread = new Thread(ClientThread);\r\n\r\n            var threads = new [] { _serverThread, _clientThread };\r\n            foreach (var thread in threads)\r\n            {\r\n                thread.Start();\r\n            }\r\n\r\n            foreach (var thread in threads)\r\n            {\r\n                thread.Join();\r\n            }\r\n        }\r\n\r\n        public void ServerThread(object state) => ServerThreadAsync().Wait();\r\n        public void ClientThread(object state) => ClientThreadAsync().Wait();\r\n\r\n        public async Task ServerThreadAsync()\r\n        {\r\n            var listener = new TcpListener(IPAddress.Loopback, 0);\r\n            listener.Start();\r\n\r\n            // clients can connect\r\n            _serverListening.SetResult(listener.LocalEndpoint as IPEndPoint);\r\n            \r\n            var socket = await listener.AcceptSocketAsync();\r\n            System.Console.WriteLine($\"{DateTime.Now}: Server: accept client\");\r\n\r\n            socket.Dispose();\r\n            System.Console.WriteLine($\"{DateTime.Now}: Server: dispose client\");\r\n        }\r\n\r\n        public async Task ClientThreadAsync()\r\n        {\r\n            // wait for the server to start\r\n            var endpoint = await _serverListening.Task;\r\n\r\n            Socket socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);\r\n            socket.Connect(endpoint);\r\n\r\n            var sea = new SocketAsyncEventArgs();\r\n            sea.Completed += ReceiveCompleted;\r\n            sea.SetBuffer(new byte[0], 0, 0);\r\n            if (socket.ReceiveAsync(sea))\r\n            {\r\n                System.Console.WriteLine($\"{DateTime.Now}: Client: receive pending\");\r\n            }\r\n            else\r\n            {\r\n                System.Console.WriteLine($\"{DateTime.Now}: Client: receive completed\");\r\n                _clientCompleted.SetResult(null);\r\n            }\r\n            // wait for the client to complete\r\n            await _clientCompleted.Task;\r\n        }\r\n\r\n        public void ReceiveCompleted(object sender, SocketAsyncEventArgs ae)\r\n        {\r\n            System.Console.WriteLine($\"{DateTime.Now}: Client: receive completed\");\r\n            _clientCompleted.SetResult(null);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\noutputs\r\n```\r\n7/4/17 5:59:56 PM: Client: receive pending\r\n7/4/17 5:59:56 PM: Server: accept client\r\n7/4/17 5:59:56 PM: Server: dispose client\r\n```"}}
{"actor":{"display_login":"stephentoub"}}