예제 #1
0
        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));
        }
예제 #2
0
        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;
            }
        }