4 커밋 800f47d718 ... 943ea29419

작성자 SHA1 메시지 날짜
  UbitUmarov 943ea29419 missing c&p 3 주 전
  UbitUmarov 620859c10e replace stream.beginread 3 주 전
  UbitUmarov 8e6eeb1931 let the socketAddress cache be global 3 주 전
  UbitUmarov 16fa47e4d3 lludp replace BeginReceiveFrom/AsyncEndReceive 3 주 전

+ 38 - 49
OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs

@@ -9,6 +9,7 @@ using OSHttpServer.Parser;
 using System.Net.Security;
 using System.Security.Cryptography.X509Certificates;
 using OpenMetaverse;
+using System.Threading.Tasks;
 
 namespace OSHttpServer
 {
@@ -208,14 +209,7 @@ namespace OSHttpServer
         /// </remarks>
         public virtual void Start()
         {
-            try
-            {
-                m_stream.BeginRead(m_ReceiveBuffer, 0, m_ReceiveBuffer.Length, OnReceive, null);
-            }
-            catch (Exception err)
-            {
-                LogWriter.Write(this, LogPrio.Debug, err.ToString());
-            }
+            Task.Run(ReceiveLoop).ConfigureAwait(false);
         }
 
         /// <summary>
@@ -348,63 +342,58 @@ namespace OSHttpServer
             }
         }
 
-        private void OnReceive(IAsyncResult ar)
+        private async void ReceiveLoop()
         {
             try
             {
-                int bytesRead = 0;
-                if (m_stream is null)
-                    return;
-                try
-                {
-                    bytesRead = m_stream.EndRead(ar);
-                }
-                catch (NullReferenceException)
+                while (true)
                 {
-                    Disconnect(SocketError.ConnectionReset);
-                    return;
-                }
+                    if (m_stream == null || !m_stream.CanRead)
+                        return;
 
-                if (bytesRead == 0)
-                {
-                    Disconnect(SocketError.Success);
-                    return;
-                }
+                    int bytesRead = 
+                        await m_stream.ReadAsync(m_ReceiveBuffer, m_ReceiveBytesLeft, m_ReceiveBuffer.Length - m_ReceiveBytesLeft).ConfigureAwait(false);
 
-                if (m_isClosing)
-                    return;
+                    if (bytesRead == 0)
+                    {
+                        Disconnect(SocketError.Success);
+                        return;
+                    }
 
-                m_ReceiveBytesLeft += bytesRead;
+                    if (m_isClosing)
+                        return;
 
-                int offset = m_parser.Parse(m_ReceiveBuffer, 0, m_ReceiveBytesLeft);
-                if (m_stream is null)
-                    return; // "Connection: Close" in effect.
+                    m_ReceiveBytesLeft += bytesRead;
 
-                if(offset > 0)
-                {
-                    int nextBytesleft, nextOffset;
-                    while ((nextBytesleft = m_ReceiveBytesLeft - offset) > 0)
+                    int offset = m_parser.Parse(m_ReceiveBuffer, 0, m_ReceiveBytesLeft);
+                    if (m_stream is null)
+                        return; // "Connection: Close" in effect.
+
+                    if(offset > 0)
                     {
-                        nextOffset = m_parser.Parse(m_ReceiveBuffer, offset, nextBytesleft);
+                        int nextBytesleft, nextOffset;
+                        while ((nextBytesleft = m_ReceiveBytesLeft - offset) > 0)
+                        {
+                            nextOffset = m_parser.Parse(m_ReceiveBuffer, offset, nextBytesleft);
 
-                        if (m_stream is null)
-                            return; // "Connection: Close" in effect.
+                            if (m_stream is null)
+                                return; // "Connection: Close" in effect.
 
-                        if (nextOffset == 0)
-                            break;
+                            if (nextOffset == 0)
+                                break;
 
-                        offset = nextOffset;
+                            offset = nextOffset;
+                        }
                     }
-                }
 
-                // copy unused bytes to the beginning of the array
-                if (offset > 0 && m_ReceiveBytesLeft > offset)
-                    Buffer.BlockCopy(m_ReceiveBuffer, offset, m_ReceiveBuffer, 0, m_ReceiveBytesLeft - offset);
+                    // copy unused bytes to the beginning of the array
+                    if (offset > 0 && m_ReceiveBytesLeft > offset)
+                        Buffer.BlockCopy(m_ReceiveBuffer, offset, m_ReceiveBuffer, 0, m_ReceiveBytesLeft - offset);
 
-                m_ReceiveBytesLeft -= offset;
-                if (StreamPassedOff)
-                    return; //?
-                m_stream.BeginRead(m_ReceiveBuffer, m_ReceiveBytesLeft, m_ReceiveBuffer.Length - m_ReceiveBytesLeft, OnReceive, null);
+                    m_ReceiveBytesLeft -= offset;
+                    if (StreamPassedOff)
+                        return; //?
+                }
             }
             catch (BadRequestException err)
             {

+ 17 - 5
OpenSim/Framework/Util.cs

@@ -1617,7 +1617,21 @@ namespace OpenSim.Framework
             return output.ToString();
         }
 
-        private static readonly ExpiringCacheOS<string, IPAddress> dnscache = new(10000);
+        private static IPEndPoint dummyIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
+        private static readonly ExpiringCacheOS<string, IPAddress> dnscache = new(30000);
+        private static readonly ExpiringCacheOS<SocketAddress, EndPoint> EndpointsCache = new(300000);
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static EndPoint GetEndPoint(SocketAddress sckaddr)
+        {
+            if (!EndpointsCache.TryGetValue(sckaddr, 300000, out EndPoint ep))
+            {
+                ep = dummyIPEndPoint.Create(sckaddr);
+                EndpointsCache.AddOrUpdate(sckaddr, ep, 300);
+            }
+            return ep;
+        }
+
 
         /// <summary>
         /// Converts a URL to a IPAddress
@@ -1686,16 +1700,14 @@ namespace OpenSim.Framework
             if (ia == null)
                 return null;
 
-            IPEndPoint newEP;
             try
             {
-                newEP = new IPEndPoint(ia, port);
+                return  new IPEndPoint(ia, port);
             }
             catch
             {
-                newEP = null;
+                return null;
             }
-            return newEP;
         }
 
         public static IPEndPoint getEndPoint(string hostname, int port)

+ 37 - 98
OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs

@@ -32,6 +32,8 @@ using log4net;
 using OpenSim.Framework;
 using OpenMetaverse;
 using OpenMetaverse.Packets;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace OpenSim.Region.ClientStack.LindenUDP
 {
@@ -72,6 +74,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
         /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
         public bool IsRunningInbound { get; private set; }
+        public CancellationTokenSource InboundCancellationSource = new();
+
 
         /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
         /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
@@ -240,10 +244,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
                 IsRunningInbound = true;
 
-                // kick off an async receive.  The Start() method will return, the
-                // actual receives will occur asynchronously and will be caught in
-                // AsyncEndRecieve().
-                AsyncBeginReceive();
+                // kick start the receiver tasks dance.
+                Task.Run(AsyncBeginReceive).ConfigureAwait(false);
             }
         }
 
@@ -264,6 +266,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
 
                 IsRunningInbound = false;
+                InboundCancellationSource.Cancel();
                 m_udpSocket.Close();
                 m_udpSocket = null;
             }
@@ -276,119 +279,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             IsRunningOutbound = false;
         }
 
-        private void AsyncBeginReceive()
+        private async void AsyncBeginReceive()
         {
+            SocketAddress workSktAddress = new(m_udpSocket.AddressFamily);
             while (IsRunningInbound)
             {
-                UDPPacketBuffer buf = GetNewUDPBuffer(new IPEndPoint(IPAddress.Any, 0)); // we need a fresh one here, for now at least
+                UDPPacketBuffer buf = GetNewUDPBuffer(null); // we need a fresh one here, for now at least
                 try
                 {
-                    // kick off an async read
-                    IAsyncResult iar = m_udpSocket.BeginReceiveFrom(
-                        buf.Data,
-                        0,
-                        buf.Data.Length,
-                        SocketFlags.None,
-                        ref buf.RemoteEndPoint,
-                        AsyncEndReceive,
-                        buf);
-
-                    if (!iar.CompletedSynchronously)
-                        return;
-                }
-                catch (SocketException e)
-                {
-                    if (e.SocketErrorCode == SocketError.ConnectionReset)
+                    int nbytes = 
+                        await m_udpSocket.ReceiveFromAsync(buf.Data.AsMemory(), SocketFlags.None, workSktAddress, InboundCancellationSource.Token).ConfigureAwait(false);
+                    if (!IsRunningInbound)
                     {
-                        m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
-                        {
-                            try
-                            {
-                                IAsyncResult iar = m_udpSocket.BeginReceiveFrom(
-                                    buf.Data,
-                                    0,
-                                    buf.Data.Length,
-                                    SocketFlags.None,
-                                    ref buf.RemoteEndPoint,
-                                    AsyncEndReceive,
-                                    buf);
-
-                                if (!iar.CompletedSynchronously)
-                                    return;
-                            }
-                            catch (SocketException) { }
-                            catch (ObjectDisposedException) { return; }
-                        }
-                        m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
+                        FreeUDPBuffer(buf);
+                        return;
                     }
-                }
-                catch (Exception e)
-                {
-                    m_log.Error(
-                        string.Format("[UDPBASE]: Error processing UDP begin receive {0}.  Exception  ", UdpReceives), e);
-                }
-            }
-        }
-
-        private void AsyncEndReceive(IAsyncResult iar)
-        {
-            if (IsRunningInbound)
-            {
-                bool sync = iar.CompletedSynchronously;
-                try
-                {
-                    // get the buffer that was created in AsyncBeginReceive
-                    // this is the received data
-                    UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
-
-                    int startTick = Util.EnvironmentTickCount();
-
-                    // get the length of data actually read from the socket, store it with the
-                    // buffer
-                    buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
 
+                    if (nbytes > 0)
+                    {
+                        int startTick = Util.EnvironmentTickCount();
 
-                    UdpReceives++;
+                        buf.RemoteEndPoint = Util.GetEndPoint(workSktAddress);;
+                        buf.DataLength = nbytes;
+                        UdpReceives++;
 
-                    // call the abstract method PacketReceived(), passing the buffer that
-                    // has just been filled from the socket read.
-                    PacketReceived(buffer);
+                        PacketReceived(buf);
 
-                    // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
-                    // then a particular stat may be inaccurate due to a race condition.  We won't worry about this
-                    // since this should be rare and  won't cause a runtime problem.
-                    if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
-                    {
-                        AverageReceiveTicksForLastSamplePeriod
-                            = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
+                        if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
+                        {
+                            AverageReceiveTicksForLastSamplePeriod
+                                = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
 
-                        m_receiveTicksInCurrentSamplePeriod = 0;
-                        m_currentReceiveTimeSamples = 0;
+                            m_receiveTicksInCurrentSamplePeriod = 0;
+                            m_currentReceiveTimeSamples = 0;
+                        }
+                        else
+                        {
+                            m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
+                            m_currentReceiveTimeSamples++;
+                        }
                     }
                     else
-                    {
-                        m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
-                        m_currentReceiveTimeSamples++;
-                    }
+                        FreeUDPBuffer(buf);
                 }
-                catch (SocketException se)
+                catch (OperationCanceledException)
                 {
-                    m_log.Error(
-                        string.Format(
-                            "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}.  Exception  ",
-                            UdpReceives, se.ErrorCode),
-                        se);
                 }
-                catch(ObjectDisposedException) { }
                 catch (Exception e)
                 {
-                    m_log.Error(
-                        string.Format("[UDPBASE]: Error processing UDP end receive {0}.  Exception  ", UdpReceives), e);
-                }
-                finally
-                {
-                    if (IsRunningInbound && !sync)
-                        AsyncBeginReceive();
+                    m_log.Error($"[UDPBASE]: Error processing UDP receiveFrom. Exception ", e);
                 }
             }
         }