diff options
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Framework/Pool.cs | 76 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 42 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 31 |
3 files changed, 125 insertions, 24 deletions
diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs new file mode 100644 index 0000000..1ca06c3 --- /dev/null +++ b/OpenSim/Framework/Pool.cs | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace OpenSim.Framework | ||
32 | { | ||
33 | /// <summary> | ||
34 | /// Naive pool implementation. | ||
35 | /// </summary> | ||
36 | /// <remarks> | ||
37 | /// Currently assumes that objects are in a useable state when returned. | ||
38 | /// </remarks> | ||
39 | public class Pool<T> | ||
40 | { | ||
41 | private Stack<T> m_pool; | ||
42 | |||
43 | private int m_maxPoolSize; | ||
44 | |||
45 | private Func<T> m_createFunction; | ||
46 | |||
47 | public Pool(Func<T> createFunction, int maxSize) | ||
48 | { | ||
49 | m_maxPoolSize = maxSize; | ||
50 | m_createFunction = createFunction; | ||
51 | m_pool = new Stack<T>(m_maxPoolSize); | ||
52 | } | ||
53 | |||
54 | public T GetObject() | ||
55 | { | ||
56 | lock (m_pool) | ||
57 | { | ||
58 | if (m_pool.Count > 0) | ||
59 | return m_pool.Pop(); | ||
60 | else | ||
61 | return m_createFunction(); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | public void ReturnObject(T obj) | ||
66 | { | ||
67 | lock (m_pool) | ||
68 | { | ||
69 | if (m_pool.Count >= m_maxPoolSize) | ||
70 | return; | ||
71 | else | ||
72 | m_pool.Push(obj); | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index fc6dd4d..42247ca 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -188,7 +188,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
188 | /// </summary> | 188 | /// </summary> |
189 | private IClientAPI m_currentIncomingClient; | 189 | private IClientAPI m_currentIncomingClient; |
190 | 190 | ||
191 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 191 | public LLUDPServer( |
192 | IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, | ||
193 | IConfigSource configSource, AgentCircuitManager circuitManager) | ||
192 | : base(listenIP, (int)port) | 194 | : base(listenIP, (int)port) |
193 | { | 195 | { |
194 | #region Environment.TickCount Measurement | 196 | #region Environment.TickCount Measurement |
@@ -242,6 +244,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
242 | { | 244 | { |
243 | PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); | 245 | PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); |
244 | PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); | 246 | PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); |
247 | UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false); | ||
245 | } | 248 | } |
246 | 249 | ||
247 | #region BinaryStats | 250 | #region BinaryStats |
@@ -284,8 +287,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
284 | private void StartInbound() | 287 | private void StartInbound() |
285 | { | 288 | { |
286 | m_log.InfoFormat( | 289 | m_log.InfoFormat( |
287 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode", | 290 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", |
288 | m_asyncPacketHandling ? "asynchronous" : "synchronous"); | 291 | m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools); |
289 | 292 | ||
290 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); | 293 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); |
291 | 294 | ||
@@ -300,7 +303,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
300 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); | 303 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); |
301 | } | 304 | } |
302 | 305 | ||
303 | private void StartOutbound() | 306 | private new void StartOutbound() |
304 | { | 307 | { |
305 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); | 308 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); |
306 | 309 | ||
@@ -317,7 +320,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
317 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); | 320 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); |
318 | } | 321 | } |
319 | 322 | ||
320 | public new void Stop() | 323 | public void Stop() |
321 | { | 324 | { |
322 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); | 325 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); |
323 | base.StopOutbound(); | 326 | base.StopOutbound(); |
@@ -806,7 +809,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
806 | LLUDPClient udpClient = null; | 809 | LLUDPClient udpClient = null; |
807 | Packet packet = null; | 810 | Packet packet = null; |
808 | int packetEnd = buffer.DataLength - 1; | 811 | int packetEnd = buffer.DataLength - 1; |
809 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; | 812 | IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint; |
810 | 813 | ||
811 | #region Decoding | 814 | #region Decoding |
812 | 815 | ||
@@ -816,7 +819,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
816 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 819 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
817 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 820 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
818 | 821 | ||
819 | return; // Drop undersizd packet | 822 | return; // Drop undersized packet |
820 | } | 823 | } |
821 | 824 | ||
822 | int headerLen = 7; | 825 | int headerLen = 7; |
@@ -842,6 +845,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
842 | // packet = Packet.BuildPacket(buffer.Data, ref packetEnd, | 845 | // packet = Packet.BuildPacket(buffer.Data, ref packetEnd, |
843 | // // Only allocate a buffer for zerodecoding if the packet is zerocoded | 846 | // // Only allocate a buffer for zerodecoding if the packet is zerocoded |
844 | // ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 847 | // ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
848 | // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we | ||
849 | // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all | ||
850 | // bytes are copied out). | ||
845 | packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, | 851 | packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, |
846 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 852 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
847 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 853 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
@@ -884,7 +890,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
884 | // UseCircuitCode handling | 890 | // UseCircuitCode handling |
885 | if (packet.Type == PacketType.UseCircuitCode) | 891 | if (packet.Type == PacketType.UseCircuitCode) |
886 | { | 892 | { |
887 | object[] array = new object[] { buffer, packet }; | 893 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
894 | // buffer. | ||
895 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
888 | 896 | ||
889 | Util.FireAndForget(HandleUseCircuitCode, array); | 897 | Util.FireAndForget(HandleUseCircuitCode, array); |
890 | 898 | ||
@@ -893,7 +901,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
893 | 901 | ||
894 | // Determine which agent this packet came from | 902 | // Determine which agent this packet came from |
895 | IClientAPI client; | 903 | IClientAPI client; |
896 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | 904 | if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) |
897 | { | 905 | { |
898 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 906 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
899 | return; | 907 | return; |
@@ -1091,21 +1099,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1091 | 1099 | ||
1092 | private void HandleUseCircuitCode(object o) | 1100 | private void HandleUseCircuitCode(object o) |
1093 | { | 1101 | { |
1094 | IPEndPoint remoteEndPoint = null; | 1102 | IPEndPoint endPoint = null; |
1095 | IClientAPI client = null; | 1103 | IClientAPI client = null; |
1096 | 1104 | ||
1097 | try | 1105 | try |
1098 | { | 1106 | { |
1099 | // DateTime startTime = DateTime.Now; | 1107 | // DateTime startTime = DateTime.Now; |
1100 | object[] array = (object[])o; | 1108 | object[] array = (object[])o; |
1101 | UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; | 1109 | endPoint = (IPEndPoint)array[0]; |
1102 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; | 1110 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; |
1103 | 1111 | ||
1104 | m_log.DebugFormat( | 1112 | m_log.DebugFormat( |
1105 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", | 1113 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", |
1106 | uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); | 1114 | uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint); |
1107 | |||
1108 | remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; | ||
1109 | 1115 | ||
1110 | AuthenticateResponse sessionInfo; | 1116 | AuthenticateResponse sessionInfo; |
1111 | if (IsClientAuthorized(uccp, out sessionInfo)) | 1117 | if (IsClientAuthorized(uccp, out sessionInfo)) |
@@ -1116,13 +1122,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1116 | uccp.CircuitCode.Code, | 1122 | uccp.CircuitCode.Code, |
1117 | uccp.CircuitCode.ID, | 1123 | uccp.CircuitCode.ID, |
1118 | uccp.CircuitCode.SessionID, | 1124 | uccp.CircuitCode.SessionID, |
1119 | remoteEndPoint, | 1125 | endPoint, |
1120 | sessionInfo); | 1126 | sessionInfo); |
1121 | 1127 | ||
1122 | // Send ack straight away to let the viewer know that the connection is active. | 1128 | // Send ack straight away to let the viewer know that the connection is active. |
1123 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | 1129 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use |
1124 | // circuit code to the existing child agent. This is not particularly obvious. | 1130 | // circuit code to the existing child agent. This is not particularly obvious. |
1125 | SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); | 1131 | SendAckImmediate(endPoint, uccp.Header.Sequence); |
1126 | 1132 | ||
1127 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1133 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1128 | if (client != null) | 1134 | if (client != null) |
@@ -1133,7 +1139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1133 | // Don't create clients for unauthorized requesters. | 1139 | // Don't create clients for unauthorized requesters. |
1134 | m_log.WarnFormat( | 1140 | m_log.WarnFormat( |
1135 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1141 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1136 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); | 1142 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1137 | } | 1143 | } |
1138 | 1144 | ||
1139 | // m_log.DebugFormat( | 1145 | // m_log.DebugFormat( |
@@ -1145,7 +1151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1145 | { | 1151 | { |
1146 | m_log.ErrorFormat( | 1152 | m_log.ErrorFormat( |
1147 | "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | 1153 | "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", |
1148 | remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", | 1154 | endPoint != null ? endPoint.ToString() : "n/a", |
1149 | client != null ? client.Name : "unknown", | 1155 | client != null ? client.Name : "unknown", |
1150 | client != null ? client.AgentId.ToString() : "unknown", | 1156 | client != null ? client.AgentId.ToString() : "unknown", |
1151 | e.Message, | 1157 | e.Message, |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 828c23c..6e6b3ef 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -30,6 +30,7 @@ using System.Net; | |||
30 | using System.Net.Sockets; | 30 | using System.Net.Sockets; |
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | ||
33 | 34 | ||
34 | namespace OpenMetaverse | 35 | namespace OpenMetaverse |
35 | { | 36 | { |
@@ -58,6 +59,16 @@ namespace OpenMetaverse | |||
58 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | 59 | /// <summary>Flag to process packets asynchronously or synchronously</summary> |
59 | private bool m_asyncPacketHandling; | 60 | private bool m_asyncPacketHandling; |
60 | 61 | ||
62 | /// <summary> | ||
63 | /// Pool to use for handling data. May be null if UsePools = false; | ||
64 | /// </summary> | ||
65 | protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool; | ||
66 | |||
67 | /// <summary> | ||
68 | /// Are we to use object pool(s) to reduce memory churn when receiving data? | ||
69 | /// </summary> | ||
70 | public bool UsePools { get; protected set; } | ||
71 | |||
61 | /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary> | 72 | /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary> |
62 | public bool IsRunningInbound { get; private set; } | 73 | public bool IsRunningInbound { get; private set; } |
63 | 74 | ||
@@ -70,6 +81,7 @@ namespace OpenMetaverse | |||
70 | /// </summary> | 81 | /// </summary> |
71 | /// <param name="bindAddress">Local IP address to bind the server to</param> | 82 | /// <param name="bindAddress">Local IP address to bind the server to</param> |
72 | /// <param name="port">Port to listening for incoming UDP packets on</param> | 83 | /// <param name="port">Port to listening for incoming UDP packets on</param> |
84 | /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param> | ||
73 | public OpenSimUDPBase(IPAddress bindAddress, int port) | 85 | public OpenSimUDPBase(IPAddress bindAddress, int port) |
74 | { | 86 | { |
75 | m_localBindAddress = bindAddress; | 87 | m_localBindAddress = bindAddress; |
@@ -94,6 +106,11 @@ namespace OpenMetaverse | |||
94 | /// necessary</remarks> | 106 | /// necessary</remarks> |
95 | public void StartInbound(int recvBufferSize, bool asyncPacketHandling) | 107 | public void StartInbound(int recvBufferSize, bool asyncPacketHandling) |
96 | { | 108 | { |
109 | if (UsePools) | ||
110 | m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500); | ||
111 | else | ||
112 | m_pool = null; | ||
113 | |||
97 | m_asyncPacketHandling = asyncPacketHandling; | 114 | m_asyncPacketHandling = asyncPacketHandling; |
98 | 115 | ||
99 | if (!IsRunningInbound) | 116 | if (!IsRunningInbound) |
@@ -165,9 +182,12 @@ namespace OpenMetaverse | |||
165 | 182 | ||
166 | private void AsyncBeginReceive() | 183 | private void AsyncBeginReceive() |
167 | { | 184 | { |
168 | // allocate a packet buffer | 185 | UDPPacketBuffer buf; |
169 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | 186 | |
170 | UDPPacketBuffer buf = new UDPPacketBuffer(); | 187 | if (UsePools) |
188 | buf = m_pool.GetObject(); | ||
189 | else | ||
190 | buf = new UDPPacketBuffer(); | ||
171 | 191 | ||
172 | if (IsRunningInbound) | 192 | if (IsRunningInbound) |
173 | { | 193 | { |
@@ -231,8 +251,6 @@ namespace OpenMetaverse | |||
231 | 251 | ||
232 | // get the buffer that was created in AsyncBeginReceive | 252 | // get the buffer that was created in AsyncBeginReceive |
233 | // this is the received data | 253 | // this is the received data |
234 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState; | ||
235 | //UDPPacketBuffer buffer = wrappedBuffer.Instance; | ||
236 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | 254 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; |
237 | 255 | ||
238 | try | 256 | try |
@@ -249,7 +267,8 @@ namespace OpenMetaverse | |||
249 | catch (ObjectDisposedException) { } | 267 | catch (ObjectDisposedException) { } |
250 | finally | 268 | finally |
251 | { | 269 | { |
252 | //wrappedBuffer.Dispose(); | 270 | if (UsePools) |
271 | m_pool.ReturnObject(buffer); | ||
253 | 272 | ||
254 | // Synchronous mode waits until the packet callback completes | 273 | // Synchronous mode waits until the packet callback completes |
255 | // before starting the receive to fetch another packet | 274 | // before starting the receive to fetch another packet |