Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
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
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.
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.
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...
There's now also a corresponding GitHub issue for the corefx repository.
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
> 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.
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:
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.
Fixed by https://github.com/mono/mono/pull/3603