internal async Task <SocketError> SendDatagramAsync(UdpConnection connection, Datagram datagram) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (datagram == null) { throw new ArgumentNullException(nameof(datagram)); } if (datagram.IsDisposed) { Logger.Error("Got disposed datagram on Send. Perhaps race condition"); return(SocketError.InvalidArgument); } if (configuration.ConnectionSimulation != null) { if (random.NextDouble() < configuration.ConnectionSimulation.PacketLoss) { Logger.Debug($"We're sending datadram to {connection.EndPoint.EndPoint}, but according to connection simulation rules we dropped it"); return(SocketError.Success); } int delay = configuration.ConnectionSimulation.GetHalfDelay(); if (delay > 0) { await Task.Delay(delay).ConfigureAwait(false); } } SendDatagramAsyncResult operationInfo = new SendDatagramAsyncResult(connection, datagram); SocketAsyncEventArgs arg = socketArgsPool.Pop(); int bytes = datagram.WriteTo(new ArraySegment <byte>(arg.Buffer, 0, arg.Buffer.Length)); arg.SetBuffer(arg.Buffer, 0, bytes); arg.RemoteEndPoint = connection.EndPoint.EndPoint; arg.UserToken = operationInfo; Logger.Debug($"Sending {datagram} to {arg.RemoteEndPoint}"); if (!socket.SendToAsync(arg)) { IO_Complete(this, arg); } return(await operationInfo.Task.ConfigureAwait(false)); }
void EndSend(SocketAsyncEventArgs e) { try { SendDatagramAsyncResult opInfo = (SendDatagramAsyncResult)e.UserToken; if (e.SocketError != SocketError.Success) { switch (e.SocketError) { case SocketError.WouldBlock: // send buffer full? // LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration"); Logger.Error("Send error SocketError.WouldBlock: probably buffer is full"); break; case SocketError.ConnectionReset: Logger.Debug($"Remote peer responded with connection reset"); (e.UserToken as UdpConnection).CloseImmidiately(DisconnectReason.ClosedByOtherPeer); // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" break; default: Logger.Error($"Sending {opInfo.Datagram} failed: {e.SocketError}"); break; } } opInfo.SetComplete(e.SocketError); if (!opInfo.Datagram.DontDisposeOnSend) { opInfo.Datagram.Dispose(); } } finally { e.UserToken = null; } }