Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket.Send misses data on Windows #6464

Closed
joncham opened this issue Jan 9, 2018 · 2 comments
Closed

Socket.Send misses data on Windows #6464

joncham opened this issue Jan 9, 2018 · 2 comments

Comments

@joncham
Copy link
Contributor

@joncham joncham commented Jan 9, 2018

Steps to Reproduce

  1. This is related to #6453
  2. Run the following test case
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class Foo
{
    public static int Main(string[] args)
    {
        var serverThread = new Thread(SynchronousSocketListener.StartListening);
        serverThread.Start();

        Thread.Sleep(1000);

        var clientThread = new Thread(SynchronousSocketClient.StartClient);
        clientThread.Start();

        clientThread.Join();
        serverThread.Join();

        return 0;
    }
}

public class SynchronousSocketClient
{
    public const int kSendRequests = 10000;

    public static void StartClient()
    {
        try
        {
            var ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
            var ipAddress = ipHostInfo.AddressList[0];
            var remoteEP = new IPEndPoint(ipAddress, 11000);

            var sender = new Socket(ipAddress.AddressFamily,
                SocketType.Stream, ProtocolType.Tcp);

            try
            {
                sender.Connect(remoteEP);

                Console.WriteLine("Socket connected");

                var msg2 = new byte[256];
                for (var j = 0; j < 256; j++)
                    msg2[j] = (byte)j;

                for (var i = 0; i < kSendRequests; i++)
                    sender.Send(msg2);
 
                var bytes = new byte[1024];
                
                var bytesRec = sender.Receive(bytes);
                Console.WriteLine("Response = {0}",
                    Encoding.ASCII.GetString(bytes, 0, bytesRec));
                
                sender.Shutdown(SocketShutdown.Both);
                sender.Close();

            }
            catch (ArgumentNullException ane)
            {
                Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception : {0}", e.ToString());
            }

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
}

public class SynchronousSocketListener
{
    public static void StartListening()
    {
        
        var ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        var ipAddress = ipHostInfo.AddressList[0];
        var localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket.  
        var listener = new Socket(ipAddress.AddressFamily,
            SocketType.Stream, ProtocolType.Tcp);
        
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(10);

            Console.WriteLine("Waiting for a connection...");
            var handler = listener.Accept();

            var total = 256 * SynchronousSocketClient.kSendRequests;
            var prev = 0;

            try
            {
                while (total > 0)
                {
                    Thread.Sleep(5);
                    var bytes = new byte[1024];
                    var bytesRec = handler.Receive(bytes);
                    total -= bytesRec;
                    for (var i = 0; i < bytesRec; i++)
                    {
                        if (bytes[i] != prev)
                            throw new Exception($"Error! Expected {bytes[i]} got {prev}");

                        prev++;
                        prev %= 256;
                    }
                }
            }
            finally
            {
                var msg = Encoding.ASCII.GetBytes("Completed successfully!");

                handler.Send(msg);
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

    }
}

Current Behavior

Waiting for a connection...
Socket connected
System.Exception: Error! Expected 0 got 1
at SynchronousSocketListener.StartListening () [0x000bd] in <5fca9061c115454492cf78911edd23d5>:0
SocketException : System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host.

at System.Net.Sockets.Socket.Send (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags) [0x00016] in <644914626cdf4027a0ef51443842d7a9>:0
at System.Net.Sockets.Socket.Send (System.Byte[] buffer) [0x00000] in <644914626cdf4027a0ef51443842d7a9>:0
at SynchronousSocketClient.StartClient () [0x00077] in <5fca9061c115454492cf78911edd23d5>:0
Press any key to continue . . .

Expected Behavior

Waiting for a connection...
Socket connected
Response = Completed successfully!

On which platforms did you notice this

[ ] macOS
[ ] Linux
[ X] Windows

Version Used:

Recent master

Stacktrace

@joncham
Copy link
Contributor Author

@joncham joncham commented Jan 9, 2018

You need to send enough data for the OS network buffer to fill up. This cases the Mono on Windows code path to go through the alertable_socket_wait code path.

joncham added a commit to Unity-Technologies/mono that referenced this issue Jan 9, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
joncham added a commit to Unity-Technologies/mono that referenced this issue Jan 10, 2018
This matches behavior of receive variants. Fixes blocking send call
where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
luhenry added a commit that referenced this issue Jan 11, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK. (#6453)

Related to issue #6464
@joncham
Copy link
Contributor Author

@joncham joncham commented Jan 11, 2018

Fixed by #6464

@joncham joncham closed this Jan 11, 2018
joncham added a commit to Unity-Technologies/mono that referenced this issue Jan 16, 2018
This matches behavior of receive variants. Fixes blocking send call
where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
joncham added a commit to Unity-Technologies/mono that referenced this issue Jan 16, 2018
This matches behavior of receive variants. Fixes blocking send call
where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
joncham added a commit to Unity-Technologies/mono that referenced this issue Jan 16, 2018
This matches behavior of receive variants. Fixes blocking send call
where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
monojenkins added a commit to monojenkins/mono that referenced this issue Feb 6, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
lewurm added a commit that referenced this issue Feb 7, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK.

Related to issue #6464
monojenkins added a commit to monojenkins/mono that referenced this issue Feb 8, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK.

Related to issue mono#6464
marek-safar added a commit that referenced this issue Feb 8, 2018
…eive variants. Fixes blocking send call where Win32 returns WSAEWOULDBLOCK.

Related to issue #6464
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants