From 8856a1444cfd58c84954387fa40aecdbaa64481b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 27 Jun 2013 17:32:12 +1200 Subject: [PATCH] Handle failure cases of Socket.Send. Fixes #3455. --- OpenRA.Game/Server/Server.cs | 41 ++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 7de0d3d445..3532b87ec0 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -200,13 +200,10 @@ namespace OpenRA.Server newConn.socket.Blocking = false; newConn.socket.NoDelay = true; - Log.Write("server", "Socket.ReceiveBufferSize: {0}.".F(newConn.socket.ReceiveBufferSize)); - Log.Write("server", "Socket.SendBufferSize: {0}.".F(newConn.socket.SendBufferSize)); - // assign the player number. newConn.PlayerIndex = ChooseFreePlayerIndex(); - newConn.socket.Send(BitConverter.GetBytes(ProtocolVersion.Version)); - newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex)); + SendData(newConn.socket, BitConverter.GetBytes(ProtocolVersion.Version)); + SendData(newConn.socket, BitConverter.GetBytes(newConn.PlayerIndex)); preConns.Add(newConn); // Dispatch a handshake order @@ -382,12 +379,10 @@ namespace OpenRA.Server { try { - var ms = new MemoryStream(); - ms.Write(BitConverter.GetBytes(data.Length + 4)); - ms.Write(BitConverter.GetBytes(client)); - ms.Write(BitConverter.GetBytes(frame)); - ms.Write(data); - c.socket.Send(ms.ToArray()); + SendData(c.socket, BitConverter.GetBytes(data.Length + 4)); + SendData(c.socket, BitConverter.GetBytes(client)); + SendData(c.socket, BitConverter.GetBytes(frame)); + SendData(c.socket, data); } catch (Exception e) { @@ -595,5 +590,29 @@ namespace OpenRA.Server gameTimeout.Enabled = true; } } + + void SendData(Socket s, byte[] data) + { + var start = 0; + var length = data.Length; + SocketError error; + + // Non-blocking sends are free to send only part of the data + while (start < length) + { + var sent = s.Send(data, start, length - start, SocketFlags.None, out error); + if (error == SocketError.WouldBlock) + { + Log.Write("server", "Non-blocking send of {0} bytes failed. Falling back to blocking send.", length - start); + s.Blocking = true; + sent = s.Send(data, start, length - start, SocketFlags.None); + s.Blocking = false; + } + else if (error != SocketError.Success) + throw new SocketException((int)error); + + start += sent; + } + } } }