Bug 43902 - NetworkStream.Write does not send all bytes to the socket
Summary: NetworkStream.Write does not send all bytes to the socket
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: mscorlib ()
Version: 4.4.1 (C7SR0)
Hardware: Other Linux
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-08-31 15:00 UTC by Kai Ruhnau
Modified: 2016-10-03 07:59 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Repeat the Socket.Send until all bytes are written (869 bytes, patch)
2016-08-31 15:22 UTC, Kai Ruhnau
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Kai Ruhnau 2016-08-31 15:00:35 UTC
The NetworkStream.Write() function doesn't transmit the entire buffer since I updated from 4.0.4 to 4.4.1.

My setup is a program that saturates a network link by Write'ing byte[] buffers of length 16384 until exactly 10 MiB are written. Those are transported via an IPv6 based TcpClient from a Linux kernel 3.14.58 USB RNDIS interface to a connected Windows machine. On the Windows machine, I use ncat to write the transported data to a file and verify that exactly 10485760 bytes have been received. The latter sometimes fails for Mono 4.4.1.

I have changed the code around the chkStreamSocket.Send call in the NetworkStream.Write method to actually check the return value. I can see that the returned number of bytes written is not the length of the buffer (I've seen 4512 or 12736 instead of 16384). The comment above the Send call seems to assume that this doesn't happen for blocking sockets, however this isn't true for this Blocking==true socket.

The amount of failures seems to be directly correlated to the speed of the network connection. On my main development machine, the USB network connection saturates above 100Mbit and the issues are very seldom. On another computer, the saturation is already at 35Mbit and there are multiple occurrences in each 10 MiB blob, so this looks like the socket's internal buffer might not have enough room for all data and only accepts less than the full buffer.

This issue looks like #3844, but that bug hasn't been updated for a really long time.
Comment 1 Kai Ruhnau 2016-08-31 15:22:11 UTC
Created attachment 17274 [details]
Repeat the Socket.Send until all bytes are written

I've recompiled 4.4.1 with this patch and the issue is gone. I'm aware though, that this code is from the shared source...
Comment 2 Kai Ruhnau 2016-08-31 15:36:02 UTC
There's now also a corresponding GitHub issue for the corefx repository.

https://github.com/dotnet/corefx/issues/11296
Comment 3 dinonet 2016-09-05 11:31:34 UTC
This fix looks like bandaid and not like its fixing the cause, Socket.Send should indeed block until all data is sent (i.e. the comment should be correct). See documentation of Socket.Send

https://msdn.microsoft.com/en-us/library/4t14718h(v=vs.110).aspx

> If you are using a connection-oriented protocol, Send will block until
> the requested number of bytes are sent, unless a time-out was set by using
> Socket.SendTimeout. If the time-out value was exceeded, the Send call will
> throw a SocketException.

Since there are plenty of applications which rely on that behavior it'd be much better to fix the bug in Socket.Send instead of applying bandaid on the calling side.
Comment 4 Kai Ruhnau 2016-09-13 07:56:38 UTC
You are right, my patch of course is a sledge hammer approach.

The Corefx team concluded that they already have the necessary loop around the send system call: 

https://github.com/dotnet/corefx/blob/master/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs#L573

Mono doesn't:
https://github.com/mono/mono/blob/d70777a3332af2d630d24adf620c2e548b92b56a/mcs/class/referencesource/System/net/System/Net/Sockets/Socket.cs#L1547
Comment 5 Geir Ludvigsen 2016-09-15 21:07:49 UTC
We suspect we're experiencing the same problem with an ftp client that relies on NetworkStream using socket.

After releasing our app with Xamarin 6.1 (mono 4.4) everything looks normal from the client side. No exceptions and correct bytes are written to the stream. But the resulting file on the ftp server is from time to time smaller than the source file on the client side. We have not been able to repro it ourselves and it takes some time before our test clients hit the problem.

This was never a problem with Mono 3.x (Xamarin 4).

We're now going to try to override the networkstream.write with similar workaround as mentioned above. Hopefully this makes sure all bytes are actually sent with the socket.
Comment 6 Marek Safar 2016-10-03 07:59:08 UTC
Fixed by https://github.com/mono/mono/pull/3603