diff options
Diffstat (limited to 'OpenSim/Region/ClientStack')
7 files changed, 624 insertions, 1288 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index d64f655..cfc1ebc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -59,6 +59,209 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// </summary> | 59 | /// </summary> |
60 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector | 60 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector |
61 | { | 61 | { |
62 | #region Events | ||
63 | |||
64 | public event GenericMessage OnGenericMessage; | ||
65 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
66 | public event Action<IClientAPI> OnLogout; | ||
67 | public event ObjectPermissions OnObjectPermissions; | ||
68 | public event Action<IClientAPI> OnConnectionClosed; | ||
69 | public event ViewerEffectEventHandler OnViewerEffect; | ||
70 | public event ImprovedInstantMessage OnInstantMessage; | ||
71 | public event ChatMessage OnChatFromClient; | ||
72 | public event TextureRequest OnRequestTexture; | ||
73 | public event RezObject OnRezObject; | ||
74 | public event DeRezObject OnDeRezObject; | ||
75 | public event ModifyTerrain OnModifyTerrain; | ||
76 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
77 | public event GenericCall2 OnRequestWearables; | ||
78 | public event SetAppearance OnSetAppearance; | ||
79 | public event AvatarNowWearing OnAvatarNowWearing; | ||
80 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
81 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
82 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
83 | public event ObjectAttach OnObjectAttach; | ||
84 | public event ObjectDeselect OnObjectDetach; | ||
85 | public event ObjectDrop OnObjectDrop; | ||
86 | public event GenericCall2 OnCompleteMovementToRegion; | ||
87 | public event UpdateAgent OnAgentUpdate; | ||
88 | public event AgentRequestSit OnAgentRequestSit; | ||
89 | public event AgentSit OnAgentSit; | ||
90 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
91 | public event StartAnim OnStartAnim; | ||
92 | public event StopAnim OnStopAnim; | ||
93 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
94 | public event LinkObjects OnLinkObjects; | ||
95 | public event DelinkObjects OnDelinkObjects; | ||
96 | public event GrabObject OnGrabObject; | ||
97 | public event DeGrabObject OnDeGrabObject; | ||
98 | public event SpinStart OnSpinStart; | ||
99 | public event SpinStop OnSpinStop; | ||
100 | public event ObjectDuplicate OnObjectDuplicate; | ||
101 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
102 | public event MoveObject OnGrabUpdate; | ||
103 | public event SpinObject OnSpinUpdate; | ||
104 | public event AddNewPrim OnAddPrim; | ||
105 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
106 | public event GodKickUser OnGodKickUser; | ||
107 | public event ObjectExtraParams OnUpdateExtraParams; | ||
108 | public event UpdateShape OnUpdatePrimShape; | ||
109 | public event ObjectRequest OnObjectRequest; | ||
110 | public event ObjectSelect OnObjectSelect; | ||
111 | public event ObjectDeselect OnObjectDeselect; | ||
112 | public event GenericCall7 OnObjectDescription; | ||
113 | public event GenericCall7 OnObjectName; | ||
114 | public event GenericCall7 OnObjectClickAction; | ||
115 | public event GenericCall7 OnObjectMaterial; | ||
116 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
117 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
118 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
119 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
120 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
121 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
122 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
123 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
124 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
125 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
126 | public event UpdateVector OnUpdatePrimScale; | ||
127 | public event UpdateVector OnUpdatePrimGroupScale; | ||
128 | public event StatusChange OnChildAgentStatus; | ||
129 | public event GenericCall2 OnStopMovement; | ||
130 | public event Action<UUID> OnRemoveAvatar; | ||
131 | public event RequestMapBlocks OnRequestMapBlocks; | ||
132 | public event RequestMapName OnMapNameRequest; | ||
133 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
134 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
135 | public event DisconnectUser OnDisconnectUser; | ||
136 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
137 | public event SetAlwaysRun OnSetAlwaysRun; | ||
138 | public event FetchInventory OnAgentDataUpdateRequest; | ||
139 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
140 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
141 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
142 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
143 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
144 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
145 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
146 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
147 | public event FetchInventory OnFetchInventory; | ||
148 | public event RequestTaskInventory OnRequestTaskInventory; | ||
149 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
150 | public event CopyInventoryItem OnCopyInventoryItem; | ||
151 | public event MoveInventoryItem OnMoveInventoryItem; | ||
152 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
153 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
154 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
155 | public event XferReceive OnXferReceive; | ||
156 | public event RequestXfer OnRequestXfer; | ||
157 | public event ConfirmXfer OnConfirmXfer; | ||
158 | public event AbortXfer OnAbortXfer; | ||
159 | public event RequestTerrain OnRequestTerrain; | ||
160 | public event RezScript OnRezScript; | ||
161 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
162 | public event MoveTaskInventory OnMoveTaskItem; | ||
163 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
164 | public event RequestAsset OnRequestAsset; | ||
165 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
166 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
167 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
168 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
169 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
170 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
171 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
172 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
173 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
174 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
175 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
176 | public event ParcelReclaim OnParcelReclaim; | ||
177 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
178 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
179 | public event RegionInfoRequest OnRegionInfoRequest; | ||
180 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
181 | public event FriendActionDelegate OnApproveFriendRequest; | ||
182 | public event FriendActionDelegate OnDenyFriendRequest; | ||
183 | public event FriendshipTermination OnTerminateFriendship; | ||
184 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
185 | public event EconomyDataRequest OnEconomyDataRequest; | ||
186 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
187 | public event ParcelBuy OnParcelBuy; | ||
188 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
189 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
190 | public event ScriptAnswer OnScriptAnswer; | ||
191 | public event RequestPayPrice OnRequestPayPrice; | ||
192 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
193 | public event ObjectBuy OnObjectBuy; | ||
194 | public event BuyObjectInventory OnBuyObjectInventory; | ||
195 | public event AgentSit OnUndo; | ||
196 | public event ForceReleaseControls OnForceReleaseControls; | ||
197 | public event GodLandStatRequest OnLandStatRequest; | ||
198 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
199 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
200 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
201 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
202 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
203 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
204 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
205 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
206 | public event BakeTerrain OnBakeTerrain; | ||
207 | public event RequestTerrain OnUploadTerrain; | ||
208 | public event EstateChangeInfo OnEstateChangeInfo; | ||
209 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
210 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
211 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
212 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
213 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
214 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
215 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
216 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
217 | public event RegionHandleRequest OnRegionHandleRequest; | ||
218 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
219 | public event ScriptReset OnScriptReset; | ||
220 | public event GetScriptRunning OnGetScriptRunning; | ||
221 | public event SetScriptRunning OnSetScriptRunning; | ||
222 | public event UpdateVector OnAutoPilotGo; | ||
223 | public event TerrainUnacked OnUnackedTerrain; | ||
224 | public event ActivateGesture OnActivateGesture; | ||
225 | public event DeactivateGesture OnDeactivateGesture; | ||
226 | public event ObjectOwner OnObjectOwner; | ||
227 | public event DirPlacesQuery OnDirPlacesQuery; | ||
228 | public event DirFindQuery OnDirFindQuery; | ||
229 | public event DirLandQuery OnDirLandQuery; | ||
230 | public event DirPopularQuery OnDirPopularQuery; | ||
231 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
232 | public event EventInfoRequest OnEventInfoRequest; | ||
233 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
234 | public event MapItemRequest OnMapItemRequest; | ||
235 | public event OfferCallingCard OnOfferCallingCard; | ||
236 | public event AcceptCallingCard OnAcceptCallingCard; | ||
237 | public event DeclineCallingCard OnDeclineCallingCard; | ||
238 | public event SoundTrigger OnSoundTrigger; | ||
239 | public event StartLure OnStartLure; | ||
240 | public event TeleportLureRequest OnTeleportLureRequest; | ||
241 | public event NetworkStats OnNetworkStatsUpdate; | ||
242 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
243 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
244 | public event ClassifiedDelete OnClassifiedDelete; | ||
245 | public event ClassifiedDelete OnClassifiedGodDelete; | ||
246 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
247 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
248 | public event EventGodDelete OnEventGodDelete; | ||
249 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
250 | public event UserInfoRequest OnUserInfoRequest; | ||
251 | public event UpdateUserInfo OnUpdateUserInfo; | ||
252 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
253 | public event PickDelete OnPickDelete; | ||
254 | public event PickGodDelete OnPickGodDelete; | ||
255 | public event PickInfoUpdate OnPickInfoUpdate; | ||
256 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
257 | public event MuteListRequest OnMuteListRequest; | ||
258 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
259 | public event PlacesQuery OnPlacesQuery; | ||
260 | |||
261 | #endregion Events | ||
262 | |||
263 | #region Class Members | ||
264 | |||
62 | // LLClientView Only | 265 | // LLClientView Only |
63 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); | 266 | public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); |
64 | 267 | ||
@@ -115,13 +318,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
115 | protected int m_textureDataLimit = 10; | 318 | protected int m_textureDataLimit = 10; |
116 | protected int m_avatarTerseUpdateRate = 50; | 319 | protected int m_avatarTerseUpdateRate = 50; |
117 | protected int m_avatarTerseUpdatesPerPacket = 5; | 320 | protected int m_avatarTerseUpdatesPerPacket = 5; |
118 | protected int m_packetMTU = 1400; | ||
119 | protected IAssetService m_assetService; | 321 | protected IAssetService m_assetService; |
120 | private IHyperAssetService m_hyperAssets; | 322 | private IHyperAssetService m_hyperAssets; |
121 | 323 | ||
122 | 324 | ||
325 | #endregion Class Members | ||
326 | |||
123 | #region Properties | 327 | #region Properties |
124 | 328 | ||
329 | public LLUDPClient UDPClient { get { return m_udpClient; } } | ||
330 | public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } } | ||
125 | public UUID SecureSessionId { get { return m_secureSessionId; } } | 331 | public UUID SecureSessionId { get { return m_secureSessionId; } } |
126 | public IScene Scene { get { return m_scene; } } | 332 | public IScene Scene { get { return m_scene; } } |
127 | public UUID SessionId { get { return m_sessionId; } } | 333 | public UUID SessionId { get { return m_sessionId; } } |
@@ -202,51 +408,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
202 | #region Client Methods | 408 | #region Client Methods |
203 | 409 | ||
204 | /// <summary> | 410 | /// <summary> |
205 | /// Close down the client view. This *must* be the last method called, since the last # | 411 | /// Shut down the client view |
206 | /// statement of CloseCleanup() aborts the thread. | ||
207 | /// </summary> | 412 | /// </summary> |
208 | /// <param name="shutdownCircuit"></param> | 413 | public void Close() |
209 | public void Close(bool shutdownCircuit) | ||
210 | { | 414 | { |
211 | m_log.DebugFormat( | 415 | m_log.DebugFormat( |
212 | "[CLIENT]: Close has been called with shutdownCircuit = {0} for {1} attached to scene {2}", | 416 | "[CLIENT]: Close has been called for {0} attached to scene {1}", |
213 | shutdownCircuit, Name, m_scene.RegionInfo.RegionName); | 417 | Name, m_scene.RegionInfo.RegionName); |
214 | 418 | ||
419 | // Send the STOP packet | ||
420 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
421 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
422 | |||
423 | IsActive = false; | ||
424 | |||
425 | // Shutdown the image manager | ||
215 | if (m_imageManager != null) | 426 | if (m_imageManager != null) |
216 | m_imageManager.Close(); | 427 | m_imageManager.Close(); |
217 | 428 | ||
429 | // Fire the callback for this connection closing | ||
430 | if (OnConnectionClosed != null) | ||
431 | OnConnectionClosed(this); | ||
432 | |||
433 | // Flush all of the packets out of the UDP server for this client | ||
218 | if (m_udpServer != null) | 434 | if (m_udpServer != null) |
219 | m_udpServer.Flush(); | 435 | m_udpServer.Flush(m_udpClient); |
220 | |||
221 | // raise an event on the packet server to Shutdown the circuit | ||
222 | // Now, if we raise the event then the packet server will call this method itself, so don't try cleanup | ||
223 | // here otherwise we'll end up calling it twice. | ||
224 | // FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks | ||
225 | // horribly tangly. Hopefully it should be possible to greatly simplify it. | ||
226 | if (shutdownCircuit) | ||
227 | { | ||
228 | if (OnConnectionClosed != null) | ||
229 | OnConnectionClosed(this); | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | CloseCleanup(shutdownCircuit); | ||
234 | } | ||
235 | } | ||
236 | 436 | ||
237 | private void CloseCleanup(bool shutdownCircuit) | 437 | // Remove ourselves from the scene |
238 | { | ||
239 | m_scene.RemoveClient(AgentId); | 438 | m_scene.RemoveClient(AgentId); |
240 | 439 | ||
241 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
242 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
243 | |||
244 | // Send the STOP packet | ||
245 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
246 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
247 | |||
248 | Thread.Sleep(2000); | ||
249 | |||
250 | // Shut down timers. Thread Context of this method is murky. Lock all timers | 440 | // Shut down timers. Thread Context of this method is murky. Lock all timers |
251 | if (m_avatarTerseUpdateTimer.Enabled) | 441 | if (m_avatarTerseUpdateTimer.Enabled) |
252 | lock (m_avatarTerseUpdateTimer) | 442 | lock (m_avatarTerseUpdateTimer) |
@@ -258,43 +448,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
258 | lock (m_primFullUpdateTimer) | 448 | lock (m_primFullUpdateTimer) |
259 | m_primFullUpdateTimer.Stop(); | 449 | m_primFullUpdateTimer.Stop(); |
260 | 450 | ||
261 | // This is just to give the client a reasonable chance of | ||
262 | // flushing out all it's packets. There should probably | ||
263 | // be a better mechanism here | ||
264 | |||
265 | // We can't reach into other scenes and close the connection | 451 | // We can't reach into other scenes and close the connection |
266 | // We need to do this over grid communications | 452 | // We need to do this over grid communications |
267 | //m_scene.CloseAllAgents(CircuitCode); | 453 | //m_scene.CloseAllAgents(CircuitCode); |
268 | 454 | ||
269 | // If we're not shutting down the circuit, then this is the last time we'll go here. | 455 | m_avatarTerseUpdateTimer.Dispose(); |
270 | // If we are shutting down the circuit, the UDP Server will come back here with | 456 | m_primTerseUpdateTimer.Dispose(); |
271 | // ShutDownCircuit = false | 457 | m_primFullUpdateTimer.Dispose(); |
272 | if (!(shutdownCircuit)) | ||
273 | { | ||
274 | GC.Collect(); | ||
275 | m_imageManager = null; | ||
276 | // Sends a KillPacket object, with which, the | ||
277 | // blockingqueue dequeues and sees it's a killpacket | ||
278 | // and terminates within the context of the client thread. | ||
279 | // This ensures that it's done from within the context | ||
280 | // of the client thread regardless of where Close() is called. | ||
281 | KillEndDone(); | ||
282 | } | ||
283 | |||
284 | IsActive = false; | ||
285 | |||
286 | m_avatarTerseUpdateTimer.Close(); | ||
287 | m_primTerseUpdateTimer.Close(); | ||
288 | m_primFullUpdateTimer.Close(); | ||
289 | 458 | ||
290 | //m_udpServer.OnPacketStats -= PopulateStats; | 459 | // Disable UDP handling for this client |
291 | m_udpClient.Shutdown(); | 460 | m_udpClient.Shutdown(); |
292 | 461 | ||
293 | // wait for thread stoped | 462 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); |
294 | // m_clientThread.Join(); | 463 | //GC.Collect(); |
295 | 464 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | |
296 | // delete circuit code | ||
297 | //m_networkServer.CloseClient(this); | ||
298 | } | 465 | } |
299 | 466 | ||
300 | public void Kick(string message) | 467 | public void Kick(string message) |
@@ -416,43 +583,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
416 | return result; | 583 | return result; |
417 | } | 584 | } |
418 | 585 | ||
419 | /*protected void DebugPacket(string direction, Packet packet) | ||
420 | { | ||
421 | string info; | ||
422 | |||
423 | if (m_debugPacketLevel < 255 && packet.Type == PacketType.AgentUpdate) | ||
424 | return; | ||
425 | if (m_debugPacketLevel < 254 && packet.Type == PacketType.ViewerEffect) | ||
426 | return; | ||
427 | if (m_debugPacketLevel < 253 && ( | ||
428 | packet.Type == PacketType.CompletePingCheck || | ||
429 | packet.Type == PacketType.StartPingCheck | ||
430 | )) | ||
431 | return; | ||
432 | if (m_debugPacketLevel < 252 && packet.Type == PacketType.PacketAck) | ||
433 | return; | ||
434 | |||
435 | if (m_debugPacketLevel > 1) | ||
436 | { | ||
437 | info = packet.ToString(); | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | info = packet.Type.ToString(); | ||
442 | } | ||
443 | |||
444 | Console.WriteLine(m_circuitCode + ":" + direction + ": " + info); | ||
445 | }*/ | ||
446 | |||
447 | #endregion Packet Handling | 586 | #endregion Packet Handling |
448 | 587 | ||
449 | # region Setup | 588 | # region Setup |
450 | 589 | ||
451 | /// <summary> | 590 | public virtual void Start() |
452 | /// Starts up the timers to check the client and resend unacked packets | ||
453 | /// Adds the client to the OpenSim.Region.Framework.Scenes.Scene | ||
454 | /// </summary> | ||
455 | protected virtual void InitNewClient() | ||
456 | { | 591 | { |
457 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); | 592 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); |
458 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); | 593 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); |
@@ -471,262 +606,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
471 | RefreshGroupMembership(); | 606 | RefreshGroupMembership(); |
472 | } | 607 | } |
473 | 608 | ||
474 | public virtual void Start() | ||
475 | { | ||
476 | // This sets up all the timers | ||
477 | InitNewClient(); | ||
478 | } | ||
479 | |||
480 | /// <summary> | ||
481 | /// Run a user session. This method lies at the base of the entire client thread. | ||
482 | /// </summary> | ||
483 | protected void RunUserSession() | ||
484 | { | ||
485 | try | ||
486 | { | ||
487 | |||
488 | } | ||
489 | catch (Exception e) | ||
490 | { | ||
491 | if (e is ThreadAbortException) | ||
492 | throw; | ||
493 | |||
494 | if (StatsManager.SimExtraStats != null) | ||
495 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
496 | |||
497 | // Don't let a failure in an individual client thread crash the whole sim. | ||
498 | m_log.ErrorFormat( | ||
499 | "[CLIENT]: Client thread for {0} {1} crashed. Logging them out.", Name, AgentId); | ||
500 | m_log.Error(e.ToString()); | ||
501 | |||
502 | try | ||
503 | { | ||
504 | // Make an attempt to alert the user that their session has crashed | ||
505 | AgentAlertMessagePacket packet | ||
506 | = BuildAgentAlertPacket( | ||
507 | "Unfortunately the session for this client on the server has crashed.\n" | ||
508 | + "Any further actions taken will not be processed.\n" | ||
509 | + "Please relog", true); | ||
510 | |||
511 | m_udpServer.SendPacket(m_agentId, packet, ThrottleOutPacketType.Unknown, false); | ||
512 | |||
513 | // There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to | ||
514 | // listeners yet, though. | ||
515 | Logout(this); | ||
516 | } | ||
517 | catch (Exception e2) | ||
518 | { | ||
519 | if (e2 is ThreadAbortException) | ||
520 | throw; | ||
521 | |||
522 | m_log.ErrorFormat("[CLIENT]: Further exception thrown on forced session logout. {0}", e2); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | # endregion | 609 | # endregion |
528 | 610 | ||
529 | #region Events | ||
530 | |||
531 | public event GenericMessage OnGenericMessage; | ||
532 | public event BinaryGenericMessage OnBinaryGenericMessage; | ||
533 | public event Action<IClientAPI> OnLogout; | ||
534 | public event ObjectPermissions OnObjectPermissions; | ||
535 | public event Action<IClientAPI> OnConnectionClosed; | ||
536 | public event ViewerEffectEventHandler OnViewerEffect; | ||
537 | public event ImprovedInstantMessage OnInstantMessage; | ||
538 | public event ChatMessage OnChatFromClient; | ||
539 | public event TextureRequest OnRequestTexture; | ||
540 | public event RezObject OnRezObject; | ||
541 | public event DeRezObject OnDeRezObject; | ||
542 | public event ModifyTerrain OnModifyTerrain; | ||
543 | public event Action<IClientAPI> OnRegionHandShakeReply; | ||
544 | public event GenericCall2 OnRequestWearables; | ||
545 | public event SetAppearance OnSetAppearance; | ||
546 | public event AvatarNowWearing OnAvatarNowWearing; | ||
547 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | ||
548 | public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; | ||
549 | public event UUIDNameRequest OnDetachAttachmentIntoInv; | ||
550 | public event ObjectAttach OnObjectAttach; | ||
551 | public event ObjectDeselect OnObjectDetach; | ||
552 | public event ObjectDrop OnObjectDrop; | ||
553 | public event GenericCall2 OnCompleteMovementToRegion; | ||
554 | public event UpdateAgent OnAgentUpdate; | ||
555 | public event AgentRequestSit OnAgentRequestSit; | ||
556 | public event AgentSit OnAgentSit; | ||
557 | public event AvatarPickerRequest OnAvatarPickerRequest; | ||
558 | public event StartAnim OnStartAnim; | ||
559 | public event StopAnim OnStopAnim; | ||
560 | public event Action<IClientAPI> OnRequestAvatarsData; | ||
561 | public event LinkObjects OnLinkObjects; | ||
562 | public event DelinkObjects OnDelinkObjects; | ||
563 | public event GrabObject OnGrabObject; | ||
564 | public event DeGrabObject OnDeGrabObject; | ||
565 | public event SpinStart OnSpinStart; | ||
566 | public event SpinStop OnSpinStop; | ||
567 | public event ObjectDuplicate OnObjectDuplicate; | ||
568 | public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; | ||
569 | public event MoveObject OnGrabUpdate; | ||
570 | public event SpinObject OnSpinUpdate; | ||
571 | public event AddNewPrim OnAddPrim; | ||
572 | public event RequestGodlikePowers OnRequestGodlikePowers; | ||
573 | public event GodKickUser OnGodKickUser; | ||
574 | public event ObjectExtraParams OnUpdateExtraParams; | ||
575 | public event UpdateShape OnUpdatePrimShape; | ||
576 | public event ObjectRequest OnObjectRequest; | ||
577 | public event ObjectSelect OnObjectSelect; | ||
578 | public event ObjectDeselect OnObjectDeselect; | ||
579 | public event GenericCall7 OnObjectDescription; | ||
580 | public event GenericCall7 OnObjectName; | ||
581 | public event GenericCall7 OnObjectClickAction; | ||
582 | public event GenericCall7 OnObjectMaterial; | ||
583 | public event ObjectIncludeInSearch OnObjectIncludeInSearch; | ||
584 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | ||
585 | public event UpdatePrimFlags OnUpdatePrimFlags; | ||
586 | public event UpdatePrimTexture OnUpdatePrimTexture; | ||
587 | public event UpdateVector OnUpdatePrimGroupPosition; | ||
588 | public event UpdateVector OnUpdatePrimSinglePosition; | ||
589 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | ||
590 | public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; | ||
591 | public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; | ||
592 | public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; | ||
593 | public event UpdateVector OnUpdatePrimScale; | ||
594 | public event UpdateVector OnUpdatePrimGroupScale; | ||
595 | public event StatusChange OnChildAgentStatus; | ||
596 | public event GenericCall2 OnStopMovement; | ||
597 | public event Action<UUID> OnRemoveAvatar; | ||
598 | public event RequestMapBlocks OnRequestMapBlocks; | ||
599 | public event RequestMapName OnMapNameRequest; | ||
600 | public event TeleportLocationRequest OnTeleportLocationRequest; | ||
601 | public event TeleportLandmarkRequest OnTeleportLandmarkRequest; | ||
602 | public event DisconnectUser OnDisconnectUser; | ||
603 | public event RequestAvatarProperties OnRequestAvatarProperties; | ||
604 | public event SetAlwaysRun OnSetAlwaysRun; | ||
605 | public event FetchInventory OnAgentDataUpdateRequest; | ||
606 | public event TeleportLocationRequest OnSetStartLocationRequest; | ||
607 | public event UpdateAvatarProperties OnUpdateAvatarProperties; | ||
608 | public event CreateNewInventoryItem OnCreateNewInventoryItem; | ||
609 | public event CreateInventoryFolder OnCreateNewInventoryFolder; | ||
610 | public event UpdateInventoryFolder OnUpdateInventoryFolder; | ||
611 | public event MoveInventoryFolder OnMoveInventoryFolder; | ||
612 | public event FetchInventoryDescendents OnFetchInventoryDescendents; | ||
613 | public event PurgeInventoryDescendents OnPurgeInventoryDescendents; | ||
614 | public event FetchInventory OnFetchInventory; | ||
615 | public event RequestTaskInventory OnRequestTaskInventory; | ||
616 | public event UpdateInventoryItem OnUpdateInventoryItem; | ||
617 | public event CopyInventoryItem OnCopyInventoryItem; | ||
618 | public event MoveInventoryItem OnMoveInventoryItem; | ||
619 | public event RemoveInventoryItem OnRemoveInventoryItem; | ||
620 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | ||
621 | public event UDPAssetUploadRequest OnAssetUploadRequest; | ||
622 | public event XferReceive OnXferReceive; | ||
623 | public event RequestXfer OnRequestXfer; | ||
624 | public event ConfirmXfer OnConfirmXfer; | ||
625 | public event AbortXfer OnAbortXfer; | ||
626 | public event RequestTerrain OnRequestTerrain; | ||
627 | public event RezScript OnRezScript; | ||
628 | public event UpdateTaskInventory OnUpdateTaskInventory; | ||
629 | public event MoveTaskInventory OnMoveTaskItem; | ||
630 | public event RemoveTaskInventory OnRemoveTaskItem; | ||
631 | public event RequestAsset OnRequestAsset; | ||
632 | public event UUIDNameRequest OnNameFromUUIDRequest; | ||
633 | public event ParcelAccessListRequest OnParcelAccessListRequest; | ||
634 | public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; | ||
635 | public event ParcelPropertiesRequest OnParcelPropertiesRequest; | ||
636 | public event ParcelDivideRequest OnParcelDivideRequest; | ||
637 | public event ParcelJoinRequest OnParcelJoinRequest; | ||
638 | public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; | ||
639 | public event ParcelSelectObjects OnParcelSelectObjects; | ||
640 | public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; | ||
641 | public event ParcelAbandonRequest OnParcelAbandonRequest; | ||
642 | public event ParcelGodForceOwner OnParcelGodForceOwner; | ||
643 | public event ParcelReclaim OnParcelReclaim; | ||
644 | public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; | ||
645 | public event ParcelDeedToGroup OnParcelDeedToGroup; | ||
646 | public event RegionInfoRequest OnRegionInfoRequest; | ||
647 | public event EstateCovenantRequest OnEstateCovenantRequest; | ||
648 | public event FriendActionDelegate OnApproveFriendRequest; | ||
649 | public event FriendActionDelegate OnDenyFriendRequest; | ||
650 | public event FriendshipTermination OnTerminateFriendship; | ||
651 | public event MoneyTransferRequest OnMoneyTransferRequest; | ||
652 | public event EconomyDataRequest OnEconomyDataRequest; | ||
653 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | ||
654 | public event ParcelBuy OnParcelBuy; | ||
655 | public event UUIDNameRequest OnTeleportHomeRequest; | ||
656 | public event UUIDNameRequest OnUUIDGroupNameRequest; | ||
657 | public event ScriptAnswer OnScriptAnswer; | ||
658 | public event RequestPayPrice OnRequestPayPrice; | ||
659 | public event ObjectSaleInfo OnObjectSaleInfo; | ||
660 | public event ObjectBuy OnObjectBuy; | ||
661 | public event BuyObjectInventory OnBuyObjectInventory; | ||
662 | public event AgentSit OnUndo; | ||
663 | public event ForceReleaseControls OnForceReleaseControls; | ||
664 | public event GodLandStatRequest OnLandStatRequest; | ||
665 | public event RequestObjectPropertiesFamily OnObjectGroupRequest; | ||
666 | public event DetailedEstateDataRequest OnDetailedEstateDataRequest; | ||
667 | public event SetEstateFlagsRequest OnSetEstateFlagsRequest; | ||
668 | public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; | ||
669 | public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; | ||
670 | public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; | ||
671 | public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; | ||
672 | public event SetRegionTerrainSettings OnSetRegionTerrainSettings; | ||
673 | public event BakeTerrain OnBakeTerrain; | ||
674 | public event RequestTerrain OnUploadTerrain; | ||
675 | public event EstateChangeInfo OnEstateChangeInfo; | ||
676 | public event EstateRestartSimRequest OnEstateRestartSimRequest; | ||
677 | public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; | ||
678 | public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; | ||
679 | public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; | ||
680 | public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; | ||
681 | public event EstateDebugRegionRequest OnEstateDebugRegionRequest; | ||
682 | public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; | ||
683 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | ||
684 | public event RegionHandleRequest OnRegionHandleRequest; | ||
685 | public event ParcelInfoRequest OnParcelInfoRequest; | ||
686 | public event ScriptReset OnScriptReset; | ||
687 | public event GetScriptRunning OnGetScriptRunning; | ||
688 | public event SetScriptRunning OnSetScriptRunning; | ||
689 | public event UpdateVector OnAutoPilotGo; | ||
690 | public event TerrainUnacked OnUnackedTerrain; | ||
691 | public event ActivateGesture OnActivateGesture; | ||
692 | public event DeactivateGesture OnDeactivateGesture; | ||
693 | public event ObjectOwner OnObjectOwner; | ||
694 | public event DirPlacesQuery OnDirPlacesQuery; | ||
695 | public event DirFindQuery OnDirFindQuery; | ||
696 | public event DirLandQuery OnDirLandQuery; | ||
697 | public event DirPopularQuery OnDirPopularQuery; | ||
698 | public event DirClassifiedQuery OnDirClassifiedQuery; | ||
699 | public event EventInfoRequest OnEventInfoRequest; | ||
700 | public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; | ||
701 | public event MapItemRequest OnMapItemRequest; | ||
702 | public event OfferCallingCard OnOfferCallingCard; | ||
703 | public event AcceptCallingCard OnAcceptCallingCard; | ||
704 | public event DeclineCallingCard OnDeclineCallingCard; | ||
705 | public event SoundTrigger OnSoundTrigger; | ||
706 | public event StartLure OnStartLure; | ||
707 | public event TeleportLureRequest OnTeleportLureRequest; | ||
708 | public event NetworkStats OnNetworkStatsUpdate; | ||
709 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | ||
710 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | ||
711 | public event ClassifiedDelete OnClassifiedDelete; | ||
712 | public event ClassifiedDelete OnClassifiedGodDelete; | ||
713 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | ||
714 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | ||
715 | public event EventGodDelete OnEventGodDelete; | ||
716 | public event ParcelDwellRequest OnParcelDwellRequest; | ||
717 | public event UserInfoRequest OnUserInfoRequest; | ||
718 | public event UpdateUserInfo OnUpdateUserInfo; | ||
719 | public event RetrieveInstantMessages OnRetrieveInstantMessages; | ||
720 | public event PickDelete OnPickDelete; | ||
721 | public event PickGodDelete OnPickGodDelete; | ||
722 | public event PickInfoUpdate OnPickInfoUpdate; | ||
723 | public event AvatarNotesUpdate OnAvatarNotesUpdate; | ||
724 | public event MuteListRequest OnMuteListRequest; | ||
725 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | ||
726 | public event PlacesQuery OnPlacesQuery; | ||
727 | |||
728 | #endregion Events | ||
729 | |||
730 | public void ActivateGesture(UUID assetId, UUID gestureId) | 611 | public void ActivateGesture(UUID assetId, UUID gestureId) |
731 | { | 612 | { |
732 | } | 613 | } |
@@ -1346,7 +1227,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1346 | kill.ObjectData[0].ID = localID; | 1227 | kill.ObjectData[0].ID = localID; |
1347 | kill.Header.Reliable = true; | 1228 | kill.Header.Reliable = true; |
1348 | kill.Header.Zerocoded = true; | 1229 | kill.Header.Zerocoded = true; |
1349 | OutPacket(kill, ThrottleOutPacketType.Task); | 1230 | OutPacket(kill, ThrottleOutPacketType.State); |
1350 | } | 1231 | } |
1351 | 1232 | ||
1352 | /// <summary> | 1233 | /// <summary> |
@@ -1940,7 +1821,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1940 | sendXfer.XferID.ID = xferID; | 1821 | sendXfer.XferID.ID = xferID; |
1941 | sendXfer.XferID.Packet = packet; | 1822 | sendXfer.XferID.Packet = packet; |
1942 | sendXfer.DataPacket.Data = data; | 1823 | sendXfer.DataPacket.Data = data; |
1943 | OutPacket(sendXfer, ThrottleOutPacketType.Task); | 1824 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); |
1944 | } | 1825 | } |
1945 | 1826 | ||
1946 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, | 1827 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, |
@@ -2222,7 +2103,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2222 | packet.AgentData.SessionID = SessionId; | 2103 | packet.AgentData.SessionID = SessionId; |
2223 | packet.Header.Reliable = false; | 2104 | packet.Header.Reliable = false; |
2224 | packet.Header.Zerocoded = true; | 2105 | packet.Header.Zerocoded = true; |
2225 | OutPacket(packet, ThrottleOutPacketType.Task); | 2106 | OutPacket(packet, ThrottleOutPacketType.State); |
2226 | } | 2107 | } |
2227 | 2108 | ||
2228 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2109 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, |
@@ -3245,7 +3126,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3245 | 3126 | ||
3246 | avp.Sender.IsTrial = false; | 3127 | avp.Sender.IsTrial = false; |
3247 | avp.Sender.ID = agentID; | 3128 | avp.Sender.ID = agentID; |
3248 | OutPacket(avp, ThrottleOutPacketType.Task); | 3129 | OutPacket(avp, ThrottleOutPacketType.State); |
3249 | } | 3130 | } |
3250 | 3131 | ||
3251 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3132 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3370,7 +3251,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3370 | int length = 0; | 3251 | int length = 0; |
3371 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3252 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3372 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3253 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3373 | if (size + length > m_packetMTU) | 3254 | if (size + length > Packet.MTU) |
3374 | break; | 3255 | break; |
3375 | size += length; | 3256 | size += length; |
3376 | } | 3257 | } |
@@ -3385,6 +3266,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3385 | 3266 | ||
3386 | terse.Header.Reliable = false; | 3267 | terse.Header.Reliable = false; |
3387 | terse.Header.Zerocoded = true; | 3268 | terse.Header.Zerocoded = true; |
3269 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | ||
3388 | OutPacket(terse, ThrottleOutPacketType.Task); | 3270 | OutPacket(terse, ThrottleOutPacketType.Task); |
3389 | 3271 | ||
3390 | if (m_avatarTerseUpdates.Count == 0) | 3272 | if (m_avatarTerseUpdates.Count == 0) |
@@ -3614,7 +3496,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3614 | int length = 0; | 3496 | int length = 0; |
3615 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); | 3497 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); |
3616 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3498 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3617 | if (size + length > m_packetMTU) | 3499 | if (size + length > Packet.MTU) |
3618 | break; | 3500 | break; |
3619 | size += length; | 3501 | size += length; |
3620 | } | 3502 | } |
@@ -3629,7 +3511,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3629 | } | 3511 | } |
3630 | 3512 | ||
3631 | outPacket.Header.Zerocoded = true; | 3513 | outPacket.Header.Zerocoded = true; |
3632 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3514 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3633 | 3515 | ||
3634 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | 3516 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) |
3635 | lock (m_primFullUpdateTimer) | 3517 | lock (m_primFullUpdateTimer) |
@@ -3702,7 +3584,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3702 | int length = 0; | 3584 | int length = 0; |
3703 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3585 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); |
3704 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3586 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
3705 | if (size + length > m_packetMTU) | 3587 | if (size + length > Packet.MTU) |
3706 | break; | 3588 | break; |
3707 | size += length; | 3589 | size += length; |
3708 | } | 3590 | } |
@@ -3719,7 +3601,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3719 | 3601 | ||
3720 | outPacket.Header.Reliable = false; | 3602 | outPacket.Header.Reliable = false; |
3721 | outPacket.Header.Zerocoded = true; | 3603 | outPacket.Header.Zerocoded = true; |
3722 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3604 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3723 | 3605 | ||
3724 | if (m_primTerseUpdates.Count == 0) | 3606 | if (m_primTerseUpdates.Count == 0) |
3725 | lock (m_primTerseUpdateTimer) | 3607 | lock (m_primTerseUpdateTimer) |
@@ -4805,7 +4687,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4805 | 4687 | ||
4806 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) | 4688 | public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) |
4807 | { | 4689 | { |
4808 | |||
4809 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; | 4690 | ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; |
4810 | if (ogpack.AgentData.SessionID != SessionId) return false; | 4691 | if (ogpack.AgentData.SessionID != SessionId) return false; |
4811 | 4692 | ||
@@ -10252,7 +10133,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10252 | 10133 | ||
10253 | public void KillEndDone() | 10134 | public void KillEndDone() |
10254 | { | 10135 | { |
10255 | m_udpClient.Shutdown(); | ||
10256 | } | 10136 | } |
10257 | 10137 | ||
10258 | #region IClientCore | 10138 | #region IClientCore |
@@ -10295,15 +10175,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10295 | { | 10175 | { |
10296 | Kick(reason); | 10176 | Kick(reason); |
10297 | Thread.Sleep(1000); | 10177 | Thread.Sleep(1000); |
10298 | Close(true); | 10178 | Close(); |
10299 | } | 10179 | } |
10300 | 10180 | ||
10301 | public void Disconnect() | 10181 | public void Disconnect() |
10302 | { | 10182 | { |
10303 | Close(true); | 10183 | Close(); |
10304 | } | 10184 | } |
10305 | 10185 | ||
10306 | |||
10307 | #endregion | 10186 | #endregion |
10308 | 10187 | ||
10309 | public void RefreshGroupMembership() | 10188 | public void RefreshGroupMembership() |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index 56d34e6..681562b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -172,39 +172,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
172 | J2KImage imagereq; | 172 | J2KImage imagereq; |
173 | int numCollected = 0; | 173 | int numCollected = 0; |
174 | 174 | ||
175 | //lock (m_syncRoot) | 175 | m_lastloopprocessed = DateTime.Now.Ticks; |
176 | //{ | 176 | |
177 | m_lastloopprocessed = DateTime.Now.Ticks; | 177 | // This can happen during Close() |
178 | 178 | if (m_client == null) | |
179 | // This can happen during Close() | 179 | return false; |
180 | if (m_client == null) | 180 | |
181 | return false; | 181 | while ((imagereq = GetHighestPriorityImage()) != null) |
182 | 182 | { | |
183 | while ((imagereq = GetHighestPriorityImage()) != null) | 183 | if (imagereq.IsDecoded == true) |
184 | { | 184 | { |
185 | if (imagereq.IsDecoded == true) | 185 | ++numCollected; |
186 | { | ||
187 | ++numCollected; | ||
188 | 186 | ||
189 | if (imagereq.SendPackets(m_client, maxpack)) | 187 | if (imagereq.SendPackets(m_client, maxpack)) |
190 | { | 188 | { |
191 | // Send complete. Destroy any knowledge of this transfer | 189 | // Send complete. Destroy any knowledge of this transfer |
192 | RemoveImageFromQueue(imagereq); | 190 | RemoveImageFromQueue(imagereq); |
193 | } | ||
194 | } | 191 | } |
195 | |||
196 | if (numCollected == count) | ||
197 | break; | ||
198 | } | 192 | } |
199 | //} | 193 | |
194 | if (numCollected == count) | ||
195 | break; | ||
196 | } | ||
200 | 197 | ||
201 | return m_priorityQueue.Count > 0; | 198 | return m_priorityQueue.Count > 0; |
202 | } | 199 | } |
203 | 200 | ||
204 | //Faux destructor | 201 | /// <summary> |
202 | /// Faux destructor | ||
203 | /// </summary> | ||
205 | public void Close() | 204 | public void Close() |
206 | { | 205 | { |
207 | m_shuttingdown = true; | 206 | m_shuttingdown = true; |
207 | m_priorityQueue = null; | ||
208 | m_j2kDecodeModule = null; | 208 | m_j2kDecodeModule = null; |
209 | m_assetCache = null; | 209 | m_assetCache = null; |
210 | m_client = null; | 210 | m_client = null; |
@@ -218,13 +218,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
218 | 218 | ||
219 | lock (m_syncRoot) | 219 | lock (m_syncRoot) |
220 | { | 220 | { |
221 | |||
222 | if (m_priorityQueue.Count > 0) | 221 | if (m_priorityQueue.Count > 0) |
223 | { | 222 | { |
224 | try | 223 | try { image = m_priorityQueue.FindMax(); } |
225 | { | ||
226 | image = m_priorityQueue.FindMax(); | ||
227 | } | ||
228 | catch (Exception) { } | 224 | catch (Exception) { } |
229 | } | 225 | } |
230 | } | 226 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 871e8e8..e7707a9 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -59,9 +59,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// </summary> | 59 | /// </summary> |
60 | public sealed class LLUDPClient | 60 | public sealed class LLUDPClient |
61 | { | 61 | { |
62 | // FIXME: Make this a config setting | ||
63 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim | ||
64 | /// state updates</summary> | ||
65 | const float STATE_TASK_PERCENTAGE = 0.8f; | ||
66 | |||
62 | /// <summary>The number of packet categories to throttle on. If a throttle category is added | 67 | /// <summary>The number of packet categories to throttle on. If a throttle category is added |
63 | /// or removed, this number must also change</summary> | 68 | /// or removed, this number must also change</summary> |
64 | const int THROTTLE_CATEGORY_COUNT = 7; | 69 | const int THROTTLE_CATEGORY_COUNT = 8; |
65 | 70 | ||
66 | /// <summary>Fired when updated networking stats are produced for this client</summary> | 71 | /// <summary>Fired when updated networking stats are produced for this client</summary> |
67 | public event PacketStats OnPacketStats; | 72 | public event PacketStats OnPacketStats; |
@@ -80,10 +85,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 85 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
81 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 86 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 87 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
83 | public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); | 88 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); |
84 | 89 | ||
85 | /// <summary>Reference to the IClientAPI for this client</summary> | ||
86 | public LLClientView ClientAPI; | ||
87 | /// <summary>Current packet sequence number</summary> | 90 | /// <summary>Current packet sequence number</summary> |
88 | public int CurrentSequence; | 91 | public int CurrentSequence; |
89 | /// <summary>Current ping sequence number</summary> | 92 | /// <summary>Current ping sequence number</summary> |
@@ -129,7 +132,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
129 | /// <summary>Throttle rate defaults and limits</summary> | 132 | /// <summary>Throttle rate defaults and limits</summary> |
130 | private readonly ThrottleRates defaultThrottleRates; | 133 | private readonly ThrottleRates defaultThrottleRates; |
131 | /// <summary>Outgoing queues for throttled packets</summary> | 134 | /// <summary>Outgoing queues for throttled packets</summary> |
132 | private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 135 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
133 | /// <summary>A container that can hold one packet for each outbox, used to store | 136 | /// <summary>A container that can hold one packet for each outbox, used to store |
134 | /// dequeued packets that are being held for throttling</summary> | 137 | /// dequeued packets that are being held for throttling</summary> |
135 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 138 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
@@ -158,7 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
158 | defaultThrottleRates = rates; | 161 | defaultThrottleRates = rates; |
159 | 162 | ||
160 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 163 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
161 | packetOutboxes[i] = new LocklessQueue<OutgoingPacket>(); | 164 | packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
162 | 165 | ||
163 | throttle = new TokenBucket(parentThrottle, 0, 0); | 166 | throttle = new TokenBucket(parentThrottle, 0, 0); |
164 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 167 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
@@ -166,9 +169,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
166 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); | 169 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); |
167 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); | 170 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); |
168 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); | 171 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); |
169 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task); | ||
170 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); | 172 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); |
171 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); | 173 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); |
174 | // State and Transaction are actually sub-categories of the LLUDP generic "Task" category | ||
175 | TokenBucket stateBucket = new TokenBucket(throttle, (int)((float)rates.TaskLimit * STATE_TASK_PERCENTAGE), (int)((float)rates.Task * STATE_TASK_PERCENTAGE)); | ||
176 | throttleCategories[(int)ThrottleOutPacketType.State] = stateBucket; | ||
177 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit - stateBucket.MaxBurst, rates.Task - stateBucket.DripRate); | ||
172 | 178 | ||
173 | // Set the granularity variable used for retransmission calculations to | 179 | // Set the granularity variable used for retransmission calculations to |
174 | // the measured resolution of Environment.TickCount | 180 | // the measured resolution of Environment.TickCount |
@@ -176,6 +182,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
176 | 182 | ||
177 | // Default the retransmission timeout to three seconds | 183 | // Default the retransmission timeout to three seconds |
178 | RTO = 3000; | 184 | RTO = 3000; |
185 | |||
186 | // Initialize this to a sane value to prevent early disconnects | ||
187 | TickLastPacketReceived = Environment.TickCount; | ||
179 | } | 188 | } |
180 | 189 | ||
181 | /// <summary> | 190 | /// <summary> |
@@ -183,8 +192,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
183 | /// </summary> | 192 | /// </summary> |
184 | public void Shutdown() | 193 | public void Shutdown() |
185 | { | 194 | { |
186 | // TODO: Do we need to invalidate the circuit? | ||
187 | IsConnected = false; | 195 | IsConnected = false; |
196 | NeedAcks.Clear(); | ||
197 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
198 | { | ||
199 | packetOutboxes[i].Clear(); | ||
200 | nextPackets[i] = null; | ||
201 | } | ||
202 | OnPacketStats = null; | ||
203 | OnQueueEmpty = null; | ||
188 | } | 204 | } |
189 | 205 | ||
190 | /// <summary> | 206 | /// <summary> |
@@ -204,7 +220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
204 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 220 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
205 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 221 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
206 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 222 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
207 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 223 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.State].DripRate + throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
208 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 224 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
209 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 225 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
210 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 226 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
@@ -301,7 +317,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
301 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 317 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; |
302 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 318 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; |
303 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 319 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; |
304 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4; | 320 | Buffer.BlockCopy(Utils.FloatToBytes((float)(throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + |
321 | throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; | ||
305 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 322 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; |
306 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | 323 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; |
307 | 324 | ||
@@ -310,12 +327,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
310 | 327 | ||
311 | public void SetThrottle(ThrottleOutPacketType category, int rate) | 328 | public void SetThrottle(ThrottleOutPacketType category, int rate) |
312 | { | 329 | { |
313 | int i = (int)category; | 330 | if (category == ThrottleOutPacketType.Task) |
314 | if (i >= 0 && i < throttleCategories.Length) | ||
315 | { | 331 | { |
316 | TokenBucket bucket = throttleCategories[(int)category]; | 332 | TokenBucket stateBucket = throttleCategories[(int)ThrottleOutPacketType.State]; |
317 | bucket.MaxBurst = rate; | 333 | TokenBucket taskBucket = throttleCategories[(int)ThrottleOutPacketType.Task]; |
318 | bucket.DripRate = rate; | 334 | |
335 | stateBucket.MaxBurst = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
336 | stateBucket.DripRate = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
337 | |||
338 | taskBucket.MaxBurst = rate - stateBucket.MaxBurst; | ||
339 | taskBucket.DripRate = rate - stateBucket.DripRate; | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | int i = (int)category; | ||
344 | if (i >= 0 && i < throttleCategories.Length) | ||
345 | { | ||
346 | TokenBucket bucket = throttleCategories[(int)category]; | ||
347 | bucket.MaxBurst = rate; | ||
348 | bucket.DripRate = rate; | ||
349 | } | ||
319 | } | 350 | } |
320 | } | 351 | } |
321 | 352 | ||
@@ -325,7 +356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
325 | 356 | ||
326 | if (category >= 0 && category < packetOutboxes.Length) | 357 | if (category >= 0 && category < packetOutboxes.Length) |
327 | { | 358 | { |
328 | LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; | 359 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; |
329 | TokenBucket bucket = throttleCategories[category]; | 360 | TokenBucket bucket = throttleCategories[category]; |
330 | 361 | ||
331 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) | 362 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) |
@@ -357,7 +388,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | public bool DequeueOutgoing() | 388 | public bool DequeueOutgoing() |
358 | { | 389 | { |
359 | OutgoingPacket packet; | 390 | OutgoingPacket packet; |
360 | LocklessQueue<OutgoingPacket> queue; | 391 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; |
361 | TokenBucket bucket; | 392 | TokenBucket bucket; |
362 | bool packetSent = false; | 393 | bool packetSent = false; |
363 | 394 | ||
@@ -400,13 +431,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
400 | nextPackets[i] = packet; | 431 | nextPackets[i] = packet; |
401 | nextPacketLengths[i] = packet.Buffer.DataLength; | 432 | nextPacketLengths[i] = packet.Buffer.DataLength; |
402 | } | 433 | } |
434 | |||
435 | // If the queue is empty after this dequeue, fire the queue | ||
436 | // empty callback now so it has a chance to fill before we | ||
437 | // get back here | ||
438 | if (queue.Count == 0) | ||
439 | FireQueueEmpty(i); | ||
403 | } | 440 | } |
404 | else | 441 | else |
405 | { | 442 | { |
406 | // No packets in this queue. Fire the queue empty callback | 443 | // No packets in this queue. Fire the queue empty callback |
407 | QueueEmpty callback = OnQueueEmpty; | 444 | // if it has not been called recently |
408 | if (callback != null) | 445 | FireQueueEmpty(i); |
409 | callback((ThrottleOutPacketType)i); | ||
410 | } | 446 | } |
411 | } | 447 | } |
412 | } | 448 | } |
@@ -435,8 +471,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
435 | 471 | ||
436 | // Always round retransmission timeout up to two seconds | 472 | // Always round retransmission timeout up to two seconds |
437 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); | 473 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); |
438 | //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + | 474 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + |
439 | // RTTVAR + " based on new RTT of " + r + "ms"); | 475 | // RTTVAR + " based on new RTT of " + r + "ms"); |
440 | } | 476 | } |
477 | |||
478 | private void FireQueueEmpty(int queueIndex) | ||
479 | { | ||
480 | QueueEmpty callback = OnQueueEmpty; | ||
481 | if (callback != null) | ||
482 | Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex); | ||
483 | } | ||
441 | } | 484 | } |
442 | } | 485 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs deleted file mode 100644 index dbb9861..0000000 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
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 | using System.Net; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenMetaverse; | ||
33 | |||
34 | using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
37 | { | ||
38 | public sealed class UDPClientCollection | ||
39 | { | ||
40 | Dictionary<UUID, LLUDPClient> Dictionary1; | ||
41 | Dictionary<IPEndPoint, LLUDPClient> Dictionary2; | ||
42 | LLUDPClient[] Array; | ||
43 | ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); | ||
44 | object m_sync = new object(); | ||
45 | |||
46 | public UDPClientCollection() | ||
47 | { | ||
48 | Dictionary1 = new Dictionary<UUID, LLUDPClient>(); | ||
49 | Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(); | ||
50 | Array = new LLUDPClient[0]; | ||
51 | } | ||
52 | |||
53 | public UDPClientCollection(int capacity) | ||
54 | { | ||
55 | Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity); | ||
56 | Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity); | ||
57 | Array = new LLUDPClient[0]; | ||
58 | } | ||
59 | |||
60 | public void Add(UUID key1, IPEndPoint key2, LLUDPClient value) | ||
61 | { | ||
62 | //rwLock.EnterWriteLock(); | ||
63 | |||
64 | //try | ||
65 | //{ | ||
66 | // if (Dictionary1.ContainsKey(key1)) | ||
67 | // { | ||
68 | // if (!Dictionary2.ContainsKey(key2)) | ||
69 | // throw new ArgumentException("key1 exists in the dictionary but not key2"); | ||
70 | // } | ||
71 | // else if (Dictionary2.ContainsKey(key2)) | ||
72 | // { | ||
73 | // if (!Dictionary1.ContainsKey(key1)) | ||
74 | // throw new ArgumentException("key2 exists in the dictionary but not key1"); | ||
75 | // } | ||
76 | |||
77 | // Dictionary1[key1] = value; | ||
78 | // Dictionary2[key2] = value; | ||
79 | |||
80 | // LLUDPClient[] oldArray = Array; | ||
81 | // int oldLength = oldArray.Length; | ||
82 | |||
83 | // LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; | ||
84 | // for (int i = 0; i < oldLength; i++) | ||
85 | // newArray[i] = oldArray[i]; | ||
86 | // newArray[oldLength] = value; | ||
87 | |||
88 | // Array = newArray; | ||
89 | //} | ||
90 | //finally { rwLock.ExitWriteLock(); } | ||
91 | |||
92 | lock (m_sync) | ||
93 | { | ||
94 | if (Dictionary1.ContainsKey(key1)) | ||
95 | { | ||
96 | if (!Dictionary2.ContainsKey(key2)) | ||
97 | throw new ArgumentException("key1 exists in the dictionary but not key2"); | ||
98 | } | ||
99 | else if (Dictionary2.ContainsKey(key2)) | ||
100 | { | ||
101 | if (!Dictionary1.ContainsKey(key1)) | ||
102 | throw new ArgumentException("key2 exists in the dictionary but not key1"); | ||
103 | } | ||
104 | |||
105 | Dictionary1[key1] = value; | ||
106 | Dictionary2[key2] = value; | ||
107 | |||
108 | LLUDPClient[] oldArray = Array; | ||
109 | int oldLength = oldArray.Length; | ||
110 | |||
111 | LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; | ||
112 | for (int i = 0; i < oldLength; i++) | ||
113 | newArray[i] = oldArray[i]; | ||
114 | newArray[oldLength] = value; | ||
115 | |||
116 | Array = newArray; | ||
117 | } | ||
118 | |||
119 | } | ||
120 | |||
121 | public bool Remove(UUID key1, IPEndPoint key2) | ||
122 | { | ||
123 | //rwLock.EnterWriteLock(); | ||
124 | |||
125 | //try | ||
126 | //{ | ||
127 | // LLUDPClient value; | ||
128 | // if (Dictionary1.TryGetValue(key1, out value)) | ||
129 | // { | ||
130 | // Dictionary1.Remove(key1); | ||
131 | // Dictionary2.Remove(key2); | ||
132 | |||
133 | // LLUDPClient[] oldArray = Array; | ||
134 | // int oldLength = oldArray.Length; | ||
135 | |||
136 | // LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; | ||
137 | // int j = 0; | ||
138 | // for (int i = 0; i < oldLength; i++) | ||
139 | // { | ||
140 | // if (oldArray[i] != value) | ||
141 | // newArray[j++] = oldArray[i]; | ||
142 | // } | ||
143 | |||
144 | // Array = newArray; | ||
145 | // return true; | ||
146 | // } | ||
147 | //} | ||
148 | //finally { rwLock.ExitWriteLock(); } | ||
149 | |||
150 | //return false; | ||
151 | |||
152 | lock (m_sync) | ||
153 | { | ||
154 | LLUDPClient value; | ||
155 | if (Dictionary1.TryGetValue(key1, out value)) | ||
156 | { | ||
157 | Dictionary1.Remove(key1); | ||
158 | Dictionary2.Remove(key2); | ||
159 | |||
160 | LLUDPClient[] oldArray = Array; | ||
161 | int oldLength = oldArray.Length; | ||
162 | |||
163 | LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; | ||
164 | int j = 0; | ||
165 | for (int i = 0; i < oldLength; i++) | ||
166 | { | ||
167 | if (oldArray[i] != value) | ||
168 | newArray[j++] = oldArray[i]; | ||
169 | } | ||
170 | |||
171 | Array = newArray; | ||
172 | return true; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | return false; | ||
177 | |||
178 | } | ||
179 | |||
180 | public void Clear() | ||
181 | { | ||
182 | //rwLock.EnterWriteLock(); | ||
183 | |||
184 | //try | ||
185 | //{ | ||
186 | // Dictionary1.Clear(); | ||
187 | // Dictionary2.Clear(); | ||
188 | // Array = new LLUDPClient[0]; | ||
189 | //} | ||
190 | //finally { rwLock.ExitWriteLock(); } | ||
191 | |||
192 | lock (m_sync) | ||
193 | { | ||
194 | Dictionary1.Clear(); | ||
195 | Dictionary2.Clear(); | ||
196 | Array = new LLUDPClient[0]; | ||
197 | } | ||
198 | |||
199 | } | ||
200 | |||
201 | public int Count | ||
202 | { | ||
203 | get { return Array.Length; } | ||
204 | } | ||
205 | |||
206 | public bool ContainsKey(UUID key) | ||
207 | { | ||
208 | return Dictionary1.ContainsKey(key); | ||
209 | } | ||
210 | |||
211 | public bool ContainsKey(IPEndPoint key) | ||
212 | { | ||
213 | return Dictionary2.ContainsKey(key); | ||
214 | } | ||
215 | |||
216 | public bool TryGetValue(UUID key, out LLUDPClient value) | ||
217 | { | ||
218 | ////bool success; | ||
219 | ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
220 | ////if (doLock) rwLock.EnterReadLock(); | ||
221 | |||
222 | ////try { success = Dictionary1.TryGetValue(key, out value); } | ||
223 | ////finally { if (doLock) rwLock.ExitReadLock(); } | ||
224 | |||
225 | ////return success; | ||
226 | |||
227 | lock (m_sync) | ||
228 | return Dictionary1.TryGetValue(key, out value); | ||
229 | |||
230 | //try | ||
231 | //{ | ||
232 | // return Dictionary1.TryGetValue(key, out value); | ||
233 | //} | ||
234 | //catch { } | ||
235 | //value = null; | ||
236 | //return false; | ||
237 | } | ||
238 | |||
239 | public bool TryGetValue(IPEndPoint key, out LLUDPClient value) | ||
240 | { | ||
241 | ////bool success; | ||
242 | ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
243 | ////if (doLock) rwLock.EnterReadLock(); | ||
244 | |||
245 | ////try { success = Dictionary2.TryGetValue(key, out value); } | ||
246 | ////finally { if (doLock) rwLock.ExitReadLock(); } | ||
247 | |||
248 | ////return success; | ||
249 | |||
250 | lock (m_sync) | ||
251 | return Dictionary2.TryGetValue(key, out value); | ||
252 | |||
253 | //try | ||
254 | //{ | ||
255 | // return Dictionary2.TryGetValue(key, out value); | ||
256 | //} | ||
257 | //catch { } | ||
258 | //value = null; | ||
259 | //return false; | ||
260 | |||
261 | } | ||
262 | |||
263 | public void ForEach(Action<LLUDPClient> action) | ||
264 | { | ||
265 | //bool doLock = !rwLock.IsUpgradeableReadLockHeld; | ||
266 | //if (doLock) rwLock.EnterUpgradeableReadLock(); | ||
267 | |||
268 | //try { Parallel.ForEach<LLUDPClient>(Array, action); } | ||
269 | //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } | ||
270 | |||
271 | LLUDPClient[] localArray = null; | ||
272 | lock (m_sync) | ||
273 | { | ||
274 | localArray = new LLUDPClient[Array.Length]; | ||
275 | Array.CopyTo(localArray, 0); | ||
276 | } | ||
277 | |||
278 | Parallel.ForEach<LLUDPClient>(localArray, action); | ||
279 | |||
280 | } | ||
281 | } | ||
282 | } | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index c356f02..57fee59 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
96 | /// <summary>Incoming packets that are awaiting handling</summary> | 96 | /// <summary>Incoming packets that are awaiting handling</summary> |
97 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 97 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
98 | /// <summary></summary> | 98 | /// <summary></summary> |
99 | private UDPClientCollection clients = new UDPClientCollection(); | 99 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
100 | /// <summary>Bandwidth throttle for this UDP server</summary> | 100 | /// <summary>Bandwidth throttle for this UDP server</summary> |
101 | private TokenBucket m_throttle; | 101 | private TokenBucket m_throttle; |
102 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | 102 | /// <summary>Bandwidth throttle rates for this UDP server</summary> |
@@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
115 | public Socket Server { get { return null; } } | 115 | public Socket Server { get { return null; } } |
116 | 116 | ||
117 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 117 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) |
118 | : base((int)port) | 118 | : base(listenIP, (int)port) |
119 | { | 119 | { |
120 | #region Environment.TickCount Measurement | 120 | #region Environment.TickCount Measurement |
121 | 121 | ||
@@ -143,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
143 | public new void Start() | 143 | public new void Start() |
144 | { | 144 | { |
145 | if (m_scene == null) | 145 | if (m_scene == null) |
146 | throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); | 146 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); |
147 | 147 | ||
148 | base.Start(); | 148 | base.Start(); |
149 | 149 | ||
@@ -181,24 +181,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | return x == m_location; | 181 | return x == m_location; |
182 | } | 182 | } |
183 | 183 | ||
184 | public void RemoveClient(IClientAPI client) | ||
185 | { | ||
186 | m_scene.ClientManager.Remove(client.CircuitCode); | ||
187 | client.Close(false); | ||
188 | |||
189 | LLUDPClient udpClient; | ||
190 | if (clients.TryGetValue(client.AgentId, out udpClient)) | ||
191 | { | ||
192 | m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName); | ||
193 | udpClient.Shutdown(); | ||
194 | clients.Remove(client.AgentId, udpClient.RemoteEndPoint); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 184 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
203 | { | 185 | { |
204 | // CoarseLocationUpdate packets cannot be split in an automated way | 186 | // CoarseLocationUpdate packets cannot be split in an automated way |
@@ -216,30 +198,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | for (int i = 0; i < packetCount; i++) | 198 | for (int i = 0; i < packetCount; i++) |
217 | { | 199 | { |
218 | byte[] data = datas[i]; | 200 | byte[] data = datas[i]; |
219 | clients.ForEach( | 201 | m_scene.ClientManager.ForEach( |
220 | delegate(LLUDPClient client) | 202 | delegate(IClientAPI client) |
221 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 203 | { |
204 | if (client is LLClientView) | ||
205 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
206 | } | ||
207 | ); | ||
222 | } | 208 | } |
223 | } | 209 | } |
224 | else | 210 | else |
225 | { | 211 | { |
226 | byte[] data = packet.ToBytes(); | 212 | byte[] data = packet.ToBytes(); |
227 | clients.ForEach( | 213 | m_scene.ClientManager.ForEach( |
228 | delegate(LLUDPClient client) | 214 | delegate(IClientAPI client) |
229 | { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); | 215 | { |
216 | if (client is LLClientView) | ||
217 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | ||
218 | } | ||
219 | ); | ||
230 | } | 220 | } |
231 | } | 221 | } |
232 | 222 | ||
233 | public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 223 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) |
234 | { | ||
235 | LLUDPClient client; | ||
236 | if (clients.TryGetValue(agentID, out client)) | ||
237 | SendPacket(client, packet, category, allowSplitting); | ||
238 | else | ||
239 | m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID); | ||
240 | } | ||
241 | |||
242 | public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | ||
243 | { | 224 | { |
244 | // CoarseLocationUpdate packets cannot be split in an automated way | 225 | // CoarseLocationUpdate packets cannot be split in an automated way |
245 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 226 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
@@ -256,25 +237,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
256 | for (int i = 0; i < packetCount; i++) | 237 | for (int i = 0; i < packetCount; i++) |
257 | { | 238 | { |
258 | byte[] data = datas[i]; | 239 | byte[] data = datas[i]; |
259 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 240 | SendPacketData(udpClient, data, packet.Type, category); |
260 | } | 241 | } |
261 | } | 242 | } |
262 | else | 243 | else |
263 | { | 244 | { |
264 | byte[] data = packet.ToBytes(); | 245 | byte[] data = packet.ToBytes(); |
265 | SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); | 246 | SendPacketData(udpClient, data, packet.Type, category); |
266 | } | 247 | } |
267 | } | 248 | } |
268 | 249 | ||
269 | public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) | 250 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) |
270 | { | 251 | { |
252 | int dataLength = data.Length; | ||
253 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | ||
254 | |||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 255 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. |
272 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | 256 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting |
273 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | 257 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here |
274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 258 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 259 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; |
276 | 260 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); | 261 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 262 | ||
279 | // Zerocode if needed | 263 | // Zerocode if needed |
280 | if (doZerocode) | 264 | if (doZerocode) |
@@ -285,17 +269,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | // The packet grew larger than the bufferSize while zerocoding. | 269 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 270 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 271 | // instead |
288 | m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); | 272 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); |
289 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | 273 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); |
290 | // | ||
291 | buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength); | ||
292 | // | ||
293 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 274 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
294 | } | 275 | } |
295 | } | 276 | } |
296 | else | 277 | else |
297 | { | 278 | { |
298 | // ??? will it fit? | ||
299 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 279 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
300 | } | 280 | } |
301 | buffer.DataLength = dataLength; | 281 | buffer.DataLength = dataLength; |
@@ -303,7 +283,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
303 | #region Queue or Send | 283 | #region Queue or Send |
304 | 284 | ||
305 | // Look up the UDPClient this is going to | 285 | // Look up the UDPClient this is going to |
306 | OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); | 286 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
307 | 287 | ||
308 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 288 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
309 | SendPacketFinal(outgoingPacket); | 289 | SendPacketFinal(outgoingPacket); |
@@ -311,18 +291,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
311 | #endregion Queue or Send | 291 | #endregion Queue or Send |
312 | } | 292 | } |
313 | 293 | ||
314 | public void SendAcks(LLUDPClient client) | 294 | public void SendAcks(LLUDPClient udpClient) |
315 | { | 295 | { |
316 | uint ack; | 296 | uint ack; |
317 | 297 | ||
318 | if (client.PendingAcks.Dequeue(out ack)) | 298 | if (udpClient.PendingAcks.Dequeue(out ack)) |
319 | { | 299 | { |
320 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); | 300 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); |
321 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); | 301 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); |
322 | block.ID = ack; | 302 | block.ID = ack; |
323 | blocks.Add(block); | 303 | blocks.Add(block); |
324 | 304 | ||
325 | while (client.PendingAcks.Dequeue(out ack)) | 305 | while (udpClient.PendingAcks.Dequeue(out ack)) |
326 | { | 306 | { |
327 | block = new PacketAckPacket.PacketsBlock(); | 307 | block = new PacketAckPacket.PacketsBlock(); |
328 | block.ID = ack; | 308 | block.ID = ack; |
@@ -333,22 +313,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
333 | packet.Header.Reliable = false; | 313 | packet.Header.Reliable = false; |
334 | packet.Packets = blocks.ToArray(); | 314 | packet.Packets = blocks.ToArray(); |
335 | 315 | ||
336 | SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); | 316 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); |
337 | } | 317 | } |
338 | } | 318 | } |
339 | 319 | ||
340 | public void SendPing(LLUDPClient client) | 320 | public void SendPing(LLUDPClient udpClient) |
341 | { | 321 | { |
342 | IClientAPI api = client.ClientAPI; | 322 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
343 | if (api != null) | 323 | pc.Header.Reliable = false; |
344 | api.SendStartPingCheck(client.CurrentPingSequence++); | 324 | |
325 | OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); | ||
326 | |||
327 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | ||
328 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | ||
329 | |||
330 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | ||
345 | } | 331 | } |
346 | 332 | ||
347 | public void ResendUnacked(LLUDPClient client) | 333 | public void ResendUnacked(LLUDPClient udpClient) |
348 | { | 334 | { |
349 | if (client.NeedAcks.Count > 0) | 335 | if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) |
350 | { | 336 | { |
351 | List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); | 337 | // Disconnect an agent if no packets are received for some time |
338 | //FIXME: Make 60 an .ini setting | ||
339 | if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) | ||
340 | { | ||
341 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); | ||
342 | |||
343 | RemoveClient(udpClient); | ||
344 | return; | ||
345 | } | ||
346 | |||
347 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO | ||
348 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); | ||
352 | 349 | ||
353 | if (expiredPackets != null) | 350 | if (expiredPackets != null) |
354 | { | 351 | { |
@@ -357,54 +354,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | { | 354 | { |
358 | OutgoingPacket outgoingPacket = expiredPackets[i]; | 355 | OutgoingPacket outgoingPacket = expiredPackets[i]; |
359 | 356 | ||
360 | // FIXME: Make this an .ini setting | 357 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", |
361 | if (outgoingPacket.ResendCount < 3) | 358 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); |
362 | { | ||
363 | //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed", | ||
364 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount)); | ||
365 | |||
366 | // Set the resent flag | ||
367 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); | ||
368 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | ||
369 | |||
370 | // The TickCount will be set to the current time when the packet | ||
371 | // is actually sent out again | ||
372 | outgoingPacket.TickCount = 0; | ||
373 | |||
374 | // Bump up the resend count on this packet | ||
375 | Interlocked.Increment(ref outgoingPacket.ResendCount); | ||
376 | //Interlocked.Increment(ref Stats.ResentPackets); | ||
377 | |||
378 | // Queue or (re)send the packet | ||
379 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | ||
380 | SendPacketFinal(outgoingPacket); | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", | ||
385 | outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); | ||
386 | 359 | ||
387 | lock (client.NeedAcks.SyncRoot) | 360 | // Set the resent flag |
388 | client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); | 361 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); |
362 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | ||
389 | 363 | ||
390 | //Interlocked.Increment(ref Stats.DroppedPackets); | 364 | // The TickCount will be set to the current time when the packet |
365 | // is actually sent out again | ||
366 | outgoingPacket.TickCount = 0; | ||
391 | 367 | ||
392 | // Disconnect an agent if no packets are received for some time | 368 | // Bump up the resend count on this packet |
393 | //FIXME: Make 60 an .ini setting | 369 | Interlocked.Increment(ref outgoingPacket.ResendCount); |
394 | if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) | 370 | //Interlocked.Increment(ref Stats.ResentPackets); |
395 | { | ||
396 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); | ||
397 | 371 | ||
398 | RemoveClient(client.ClientAPI); | 372 | // Requeue or resend the packet |
399 | return; | 373 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
400 | } | 374 | SendPacketFinal(outgoingPacket); |
401 | } | ||
402 | } | 375 | } |
403 | } | 376 | } |
404 | } | 377 | } |
405 | } | 378 | } |
406 | 379 | ||
407 | public void Flush() | 380 | public void Flush(LLUDPClient udpClient) |
408 | { | 381 | { |
409 | // FIXME: Implement? | 382 | // FIXME: Implement? |
410 | } | 383 | } |
@@ -415,7 +388,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
415 | byte flags = buffer.Data[0]; | 388 | byte flags = buffer.Data[0]; |
416 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | 389 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; |
417 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | 390 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; |
418 | LLUDPClient client = outgoingPacket.Client; | 391 | LLUDPClient udpClient = outgoingPacket.Client; |
392 | |||
393 | if (!udpClient.IsConnected) | ||
394 | return; | ||
419 | 395 | ||
420 | // Keep track of when this packet was sent out (right now) | 396 | // Keep track of when this packet was sent out (right now) |
421 | outgoingPacket.TickCount = Environment.TickCount; | 397 | outgoingPacket.TickCount = Environment.TickCount; |
@@ -424,11 +400,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
424 | 400 | ||
425 | int dataLength = buffer.DataLength; | 401 | int dataLength = buffer.DataLength; |
426 | 402 | ||
427 | // Keep appending ACKs until there is no room left in the packet or there are | 403 | // Keep appending ACKs until there is no room left in the buffer or there are |
428 | // no more ACKs to append | 404 | // no more ACKs to append |
429 | uint ackCount = 0; | 405 | uint ackCount = 0; |
430 | uint ack; | 406 | uint ack; |
431 | while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) | 407 | while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) |
432 | { | 408 | { |
433 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); | 409 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); |
434 | dataLength += 4; | 410 | dataLength += 4; |
@@ -447,24 +423,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
447 | 423 | ||
448 | #endregion ACK Appending | 424 | #endregion ACK Appending |
449 | 425 | ||
426 | #region Sequence Number Assignment | ||
427 | |||
450 | if (!isResend) | 428 | if (!isResend) |
451 | { | 429 | { |
452 | // Not a resend, assign a new sequence number | 430 | // Not a resend, assign a new sequence number |
453 | uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); | 431 | uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); |
454 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 432 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
455 | outgoingPacket.SequenceNumber = sequenceNumber; | 433 | outgoingPacket.SequenceNumber = sequenceNumber; |
456 | 434 | ||
457 | if (isReliable) | 435 | if (isReliable) |
458 | { | 436 | { |
459 | // Add this packet to the list of ACK responses we are waiting on from the server | 437 | // Add this packet to the list of ACK responses we are waiting on from the server |
460 | client.NeedAcks.Add(outgoingPacket); | 438 | udpClient.NeedAcks.Add(outgoingPacket); |
461 | } | 439 | } |
462 | } | 440 | } |
463 | 441 | ||
442 | #endregion Sequence Number Assignment | ||
443 | |||
464 | // Stats tracking | 444 | // Stats tracking |
465 | Interlocked.Increment(ref client.PacketsSent); | 445 | Interlocked.Increment(ref udpClient.PacketsSent); |
466 | if (isReliable) | 446 | if (isReliable) |
467 | Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); | 447 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); |
468 | 448 | ||
469 | // Put the UDP payload on the wire | 449 | // Put the UDP payload on the wire |
470 | AsyncBeginSend(buffer); | 450 | AsyncBeginSend(buffer); |
@@ -473,10 +453,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
473 | protected override void PacketReceived(UDPPacketBuffer buffer) | 453 | protected override void PacketReceived(UDPPacketBuffer buffer) |
474 | { | 454 | { |
475 | // Debugging/Profiling | 455 | // Debugging/Profiling |
476 | //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } | 456 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } |
477 | //catch (Exception) { } | 457 | //catch (Exception) { } |
478 | 458 | ||
479 | LLUDPClient client = null; | 459 | LLUDPClient udpClient = null; |
480 | Packet packet = null; | 460 | Packet packet = null; |
481 | int packetEnd = buffer.DataLength - 1; | 461 | int packetEnd = buffer.DataLength - 1; |
482 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; | 462 | IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; |
@@ -491,61 +471,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
491 | } | 471 | } |
492 | catch (MalformedDataException) | 472 | catch (MalformedDataException) |
493 | { | 473 | { |
494 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", | 474 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}", |
495 | Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 475 | buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); |
496 | } | 476 | } |
497 | 477 | ||
498 | // Fail-safe check | 478 | // Fail-safe check |
499 | if (packet == null) | 479 | if (packet == null) |
500 | { | 480 | { |
501 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); | 481 | m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength + |
482 | " bytes long from " + buffer.RemoteEndPoint); | ||
502 | return; | 483 | return; |
503 | } | 484 | } |
504 | 485 | ||
505 | //Stats.RecvBytes += (ulong)buffer.DataLength; | ||
506 | //++Stats.RecvPackets; | ||
507 | |||
508 | #endregion Decoding | 486 | #endregion Decoding |
509 | 487 | ||
510 | #region UseCircuitCode Handling | 488 | #region Packet to Client Mapping |
511 | 489 | ||
490 | // UseCircuitCode handling | ||
512 | if (packet.Type == PacketType.UseCircuitCode) | 491 | if (packet.Type == PacketType.UseCircuitCode) |
513 | { | 492 | { |
514 | UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; | 493 | AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); |
515 | IClientAPI newuser; | ||
516 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
517 | |||
518 | // Check if the client is already established | ||
519 | if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser)) | ||
520 | { | ||
521 | AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint); | ||
522 | } | ||
523 | } | 494 | } |
524 | 495 | ||
525 | // Determine which agent this packet came from | 496 | // Determine which agent this packet came from |
526 | if (!clients.TryGetValue(address, out client)) | 497 | IClientAPI client; |
498 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | ||
527 | { | 499 | { |
528 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 500 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
501 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); | ||
529 | return; | 502 | return; |
530 | } | 503 | } |
531 | 504 | ||
532 | #endregion UseCircuitCode Handling | 505 | udpClient = ((LLClientView)client).UDPClient; |
506 | |||
507 | if (!udpClient.IsConnected) | ||
508 | return; | ||
509 | |||
510 | #endregion Packet to Client Mapping | ||
533 | 511 | ||
534 | // Stats tracking | 512 | // Stats tracking |
535 | Interlocked.Increment(ref client.PacketsReceived); | 513 | Interlocked.Increment(ref udpClient.PacketsReceived); |
536 | 514 | ||
537 | #region ACK Receiving | 515 | #region ACK Receiving |
538 | 516 | ||
539 | int now = Environment.TickCount; | 517 | int now = Environment.TickCount; |
540 | client.TickLastPacketReceived = now; | 518 | udpClient.TickLastPacketReceived = now; |
541 | 519 | ||
542 | // Handle appended ACKs | 520 | // Handle appended ACKs |
543 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | 521 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) |
544 | { | 522 | { |
545 | lock (client.NeedAcks.SyncRoot) | 523 | lock (udpClient.NeedAcks.SyncRoot) |
546 | { | 524 | { |
547 | for (int i = 0; i < packet.Header.AckList.Length; i++) | 525 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
548 | AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); | 526 | AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent); |
549 | } | 527 | } |
550 | } | 528 | } |
551 | 529 | ||
@@ -554,10 +532,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
554 | { | 532 | { |
555 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 533 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
556 | 534 | ||
557 | lock (client.NeedAcks.SyncRoot) | 535 | lock (udpClient.NeedAcks.SyncRoot) |
558 | { | 536 | { |
559 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 537 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
560 | AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); | 538 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); |
561 | } | 539 | } |
562 | } | 540 | } |
563 | 541 | ||
@@ -566,27 +544,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | #region ACK Sending | 544 | #region ACK Sending |
567 | 545 | ||
568 | if (packet.Header.Reliable) | 546 | if (packet.Header.Reliable) |
569 | client.PendingAcks.Enqueue((uint)packet.Header.Sequence); | 547 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); |
570 | 548 | ||
571 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 549 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, |
572 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | 550 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove |
573 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to | 551 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to |
574 | // client.BytesSinceLastACK. Lockless thread safety | 552 | // client.BytesSinceLastACK. Lockless thread safety |
575 | int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); | 553 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
576 | bytesSinceLastACK += buffer.DataLength; | 554 | bytesSinceLastACK += buffer.DataLength; |
577 | if (bytesSinceLastACK > Packet.MTU * 2) | 555 | if (bytesSinceLastACK > Packet.MTU * 2) |
578 | { | 556 | { |
579 | bytesSinceLastACK -= Packet.MTU * 2; | 557 | bytesSinceLastACK -= Packet.MTU * 2; |
580 | SendAcks(client); | 558 | SendAcks(udpClient); |
581 | } | 559 | } |
582 | Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); | 560 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); |
583 | 561 | ||
584 | #endregion ACK Sending | 562 | #endregion ACK Sending |
585 | 563 | ||
586 | #region Incoming Packet Accounting | 564 | #region Incoming Packet Accounting |
587 | 565 | ||
588 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 566 | // Check the archive of received reliable packet IDs to see whether we already received this packet |
589 | if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence)) | 567 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
590 | { | 568 | { |
591 | if (packet.Header.Resent) | 569 | if (packet.Header.Resent) |
592 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); | 570 | m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); |
@@ -603,7 +581,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
603 | if (packet.Type != PacketType.PacketAck) | 581 | if (packet.Type != PacketType.PacketAck) |
604 | { | 582 | { |
605 | // Inbox insertion | 583 | // Inbox insertion |
606 | packetInbox.Enqueue(new IncomingPacket(client, packet)); | 584 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); |
607 | } | 585 | } |
608 | } | 586 | } |
609 | 587 | ||
@@ -623,53 +601,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
623 | 601 | ||
624 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) | 602 | private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) |
625 | { | 603 | { |
626 | //Slave regions don't accept new clients | 604 | UUID agentID = useCircuitCode.CircuitCode.ID; |
605 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | ||
606 | uint circuitCode = useCircuitCode.CircuitCode.Code; | ||
607 | |||
627 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) | 608 | if (m_scene.RegionStatus != RegionStatus.SlaveScene) |
628 | { | 609 | { |
629 | AuthenticateResponse sessionInfo; | 610 | AuthenticateResponse sessionInfo; |
630 | bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); | 611 | if (IsClientAuthorized(useCircuitCode, out sessionInfo)) |
631 | |||
632 | if (!IsClientAuthorized(useCircuitCode, out sessionInfo)) | ||
633 | { | 612 | { |
634 | m_log.WarnFormat( | 613 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); |
635 | "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", | ||
636 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | ||
637 | return; | ||
638 | } | 614 | } |
639 | 615 | else | |
640 | if (isNewCircuit) | ||
641 | { | 616 | { |
642 | UUID agentID = useCircuitCode.CircuitCode.ID; | 617 | // Don't create circuits for unauthorized clients |
643 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | 618 | m_log.WarnFormat( |
644 | uint circuitCode = useCircuitCode.CircuitCode.Code; | 619 | "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", |
645 | 620 | useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); | |
646 | AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); | ||
647 | } | 621 | } |
648 | } | 622 | } |
623 | else | ||
624 | { | ||
625 | // Slave regions don't accept new clients | ||
626 | m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); | ||
627 | } | ||
649 | } | 628 | } |
650 | 629 | ||
651 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 630 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
652 | { | 631 | { |
653 | // Create the LLUDPClient | 632 | // Create the LLUDPClient |
654 | LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); | 633 | LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); |
655 | 634 | ||
656 | // Create the LLClientView | 635 | if (!m_scene.ClientManager.ContainsKey(agentID)) |
657 | LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode); | 636 | { |
658 | clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; | 637 | // Create the LLClientView |
659 | clientApi.OnLogout += LogoutHandler; | 638 | LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
660 | clientApi.OnConnectionClosed += RemoveClient; | 639 | client.OnLogout += LogoutHandler; |
661 | |||
662 | // Start the IClientAPI | ||
663 | m_scene.ClientManager.Add(circuitCode, clientApi); | ||
664 | clientApi.Start(); | ||
665 | |||
666 | // Give LLUDPClient a reference to IClientAPI | ||
667 | client.ClientAPI = clientApi; | ||
668 | 640 | ||
669 | // Add the new client to our list of tracked clients | 641 | // Start the IClientAPI |
670 | clients.Add(agentID, client.RemoteEndPoint, client); | 642 | client.Start(); |
643 | } | ||
644 | else | ||
645 | { | ||
646 | m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}", | ||
647 | udpClient.AgentID, remoteEndPoint, circuitCode); | ||
648 | } | ||
649 | } | ||
671 | 650 | ||
672 | m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); | 651 | private void RemoveClient(LLUDPClient udpClient) |
652 | { | ||
653 | // Remove this client from the scene | ||
654 | IClientAPI client; | ||
655 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) | ||
656 | client.Close(); | ||
673 | } | 657 | } |
674 | 658 | ||
675 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) | 659 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) |
@@ -747,20 +731,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
747 | elapsed500MS = 0; | 731 | elapsed500MS = 0; |
748 | } | 732 | } |
749 | 733 | ||
750 | clients.ForEach( | 734 | m_scene.ClientManager.ForEach( |
751 | delegate(LLUDPClient client) | 735 | delegate(IClientAPI client) |
752 | { | 736 | { |
753 | if (client.DequeueOutgoing()) | 737 | if (client is LLClientView) |
754 | packetSent = true; | ||
755 | if (resendUnacked) | ||
756 | ResendUnacked(client); | ||
757 | if (sendAcks) | ||
758 | { | 738 | { |
759 | SendAcks(client); | 739 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; |
760 | client.SendPacketStats(); | 740 | |
741 | if (udpClient.IsConnected) | ||
742 | { | ||
743 | if (udpClient.DequeueOutgoing()) | ||
744 | packetSent = true; | ||
745 | if (resendUnacked) | ||
746 | ResendUnacked(udpClient); | ||
747 | if (sendAcks) | ||
748 | { | ||
749 | SendAcks(udpClient); | ||
750 | udpClient.SendPacketStats(); | ||
751 | } | ||
752 | if (sendPings) | ||
753 | SendPing(udpClient); | ||
754 | } | ||
761 | } | 755 | } |
762 | if (sendPings) | ||
763 | SendPing(client); | ||
764 | } | 756 | } |
765 | ); | 757 | ); |
766 | 758 | ||
@@ -773,38 +765,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
773 | { | 765 | { |
774 | IncomingPacket incomingPacket = (IncomingPacket)state; | 766 | IncomingPacket incomingPacket = (IncomingPacket)state; |
775 | Packet packet = incomingPacket.Packet; | 767 | Packet packet = incomingPacket.Packet; |
776 | LLUDPClient client = incomingPacket.Client; | 768 | LLUDPClient udpClient = incomingPacket.Client; |
769 | IClientAPI client; | ||
777 | 770 | ||
778 | // Sanity check | 771 | // Sanity check |
779 | if (packet == null || client == null || client.ClientAPI == null) | 772 | if (packet == null || udpClient == null) |
780 | { | 773 | { |
781 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", | 774 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", |
782 | packet, client, (client != null) ? client.ClientAPI : null); | 775 | packet, udpClient); |
783 | } | 776 | } |
784 | 777 | ||
785 | try | 778 | // Make sure this client is still alive |
786 | { | 779 | if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) |
787 | // Process this packet | ||
788 | client.ClientAPI.ProcessInPacket(packet); | ||
789 | } | ||
790 | catch (ThreadAbortException) | ||
791 | { | 780 | { |
792 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | 781 | try |
793 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | 782 | { |
794 | Stop(); | 783 | // Process this packet |
784 | client.ProcessInPacket(packet); | ||
785 | } | ||
786 | catch (ThreadAbortException) | ||
787 | { | ||
788 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | ||
789 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
790 | Stop(); | ||
791 | } | ||
792 | catch (Exception e) | ||
793 | { | ||
794 | // Don't let a failure in an individual client thread crash the whole sim. | ||
795 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); | ||
796 | m_log.Error(e.Message, e); | ||
797 | } | ||
795 | } | 798 | } |
796 | catch (Exception e) | 799 | else |
797 | { | 800 | { |
798 | // Don't let a failure in an individual client thread crash the whole sim. | 801 | m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); |
799 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type); | ||
800 | m_log.Error(e.Message, e); | ||
801 | } | 802 | } |
802 | } | 803 | } |
803 | 804 | ||
804 | private void LogoutHandler(IClientAPI client) | 805 | private void LogoutHandler(IClientAPI client) |
805 | { | 806 | { |
806 | client.SendLogoutPacket(); | 807 | client.SendLogoutPacket(); |
807 | RemoveClient(client); | ||
808 | } | 808 | } |
809 | } | 809 | } |
810 | } | 810 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index 43a68ec..fad2ea8 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | |||
@@ -1,402 +1,100 @@ | |||
1 | //--------- Modified Version ------------------- | 1 | /* |
2 | ///* | 2 | * Copyright (c) 2006, Clutch, Inc. |
3 | // * Copyright (c) 2006, Clutch, Inc. | 3 | * Original Author: Jeff Cesnik |
4 | // * Original Author: Jeff Cesnik | 4 | * All rights reserved. |
5 | // * All rights reserved. | 5 | * |
6 | // * | 6 | * - Redistribution and use in source and binary forms, with or without |
7 | // * - Redistribution and use in source and binary forms, with or without | 7 | * modification, are permitted provided that the following conditions are met: |
8 | // * modification, are permitted provided that the following conditions are met: | 8 | * |
9 | // * | 9 | * - Redistributions of source code must retain the above copyright notice, this |
10 | // * - Redistributions of source code must retain the above copyright notice, this | 10 | * list of conditions and the following disclaimer. |
11 | // * list of conditions and the following disclaimer. | 11 | * - Neither the name of the openmetaverse.org nor the names |
12 | // * - Neither the name of the openmetaverse.org nor the names | 12 | * of its contributors may be used to endorse or promote products derived from |
13 | // * of its contributors may be used to endorse or promote products derived from | 13 | * this software without specific prior written permission. |
14 | // * this software without specific prior written permission. | 14 | * |
15 | // * | 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
16 | // * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | // * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | // * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | // * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | // * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | // * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | // * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | // * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | // * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 | // * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 25 | * POSSIBILITY OF SUCH DAMAGE. |
26 | // * POSSIBILITY OF SUCH DAMAGE. | 26 | */ |
27 | // */ | ||
28 | 27 | ||
29 | using System; | 28 | using System; |
30 | using System.Net; | 29 | using System.Net; |
31 | using System.Net.Sockets; | 30 | using System.Net.Sockets; |
32 | using System.Threading; | 31 | using System.Threading; |
33 | using OpenMetaverse; | 32 | using log4net; |
34 | 33 | ||
35 | //namespace OpenSim.Region.ClientStack.LindenUDP | 34 | namespace OpenMetaverse |
36 | //{ | ||
37 | // /// <summary> | ||
38 | // /// | ||
39 | // /// </summary> | ||
40 | // public abstract class OpenSimUDPBase | ||
41 | // { | ||
42 | // // these abstract methods must be implemented in a derived class to actually do | ||
43 | // // something with the packets that are sent and received. | ||
44 | // protected abstract void PacketReceived(UDPPacketBuffer buffer); | ||
45 | // protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); | ||
46 | |||
47 | // // the port to listen on | ||
48 | // internal int udpPort; | ||
49 | |||
50 | // // the UDP socket | ||
51 | // private Socket udpSocket; | ||
52 | |||
53 | // // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). | ||
54 | // // since there are potentially many "reader" threads in the internal .NET IOCP | ||
55 | // // thread pool, this is a cheaper synchronization primitive than using | ||
56 | // // a Mutex object. This allows many UDP socket "reads" concurrently - when | ||
57 | // // Stop() is called, it attempts to obtain a writer lock which will then | ||
58 | // // wait until all outstanding operations are completed before shutting down. | ||
59 | // // this avoids the problem of closing the socket with outstanding operations | ||
60 | // // and trying to catch the inevitable ObjectDisposedException. | ||
61 | // private ReaderWriterLock rwLock = new ReaderWriterLock(); | ||
62 | |||
63 | // // number of outstanding operations. This is a reference count | ||
64 | // // which we use to ensure that the threads exit cleanly. Note that | ||
65 | // // we need this because the threads will potentially still need to process | ||
66 | // // data even after the socket is closed. | ||
67 | // private int rwOperationCount = 0; | ||
68 | |||
69 | // // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. | ||
70 | // private volatile bool shutdownFlag = true; | ||
71 | |||
72 | // // the remote endpoint to communicate with | ||
73 | // protected IPEndPoint remoteEndPoint = null; | ||
74 | |||
75 | |||
76 | // /// <summary> | ||
77 | // /// Initialize the UDP packet handler in server mode | ||
78 | // /// </summary> | ||
79 | // /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
80 | // public OpenSimUDPBase(int port) | ||
81 | // { | ||
82 | // udpPort = port; | ||
83 | // } | ||
84 | |||
85 | // /// <summary> | ||
86 | // /// Initialize the UDP packet handler in client mode | ||
87 | // /// </summary> | ||
88 | // /// <param name="endPoint">Remote UDP server to connect to</param> | ||
89 | // public OpenSimUDPBase(IPEndPoint endPoint) | ||
90 | // { | ||
91 | // remoteEndPoint = endPoint; | ||
92 | // udpPort = 0; | ||
93 | // } | ||
94 | |||
95 | // /// <summary> | ||
96 | // /// | ||
97 | // /// </summary> | ||
98 | // public void Start() | ||
99 | // { | ||
100 | // if (shutdownFlag) | ||
101 | // { | ||
102 | // if (remoteEndPoint == null) | ||
103 | // { | ||
104 | // // Server mode | ||
105 | |||
106 | // // create and bind the socket | ||
107 | // IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | ||
108 | // udpSocket = new Socket( | ||
109 | // AddressFamily.InterNetwork, | ||
110 | // SocketType.Dgram, | ||
111 | // ProtocolType.Udp); | ||
112 | // udpSocket.Bind(ipep); | ||
113 | // } | ||
114 | // else | ||
115 | // { | ||
116 | // // Client mode | ||
117 | // IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | ||
118 | // udpSocket = new Socket( | ||
119 | // AddressFamily.InterNetwork, | ||
120 | // SocketType.Dgram, | ||
121 | // ProtocolType.Udp); | ||
122 | // udpSocket.Bind(ipep); | ||
123 | // //udpSocket.Connect(remoteEndPoint); | ||
124 | // } | ||
125 | |||
126 | // // we're not shutting down, we're starting up | ||
127 | // shutdownFlag = false; | ||
128 | |||
129 | // // kick off an async receive. The Start() method will return, the | ||
130 | // // actual receives will occur asynchronously and will be caught in | ||
131 | // // AsyncEndRecieve(). | ||
132 | // AsyncBeginReceive(); | ||
133 | // } | ||
134 | // } | ||
135 | |||
136 | // /// <summary> | ||
137 | // /// | ||
138 | // /// </summary> | ||
139 | // public void Stop() | ||
140 | // { | ||
141 | // if (!shutdownFlag) | ||
142 | // { | ||
143 | // // wait indefinitely for a writer lock. Once this is called, the .NET runtime | ||
144 | // // will deny any more reader locks, in effect blocking all other send/receive | ||
145 | // // threads. Once we have the lock, we set shutdownFlag to inform the other | ||
146 | // // threads that the socket is closed. | ||
147 | // rwLock.AcquireWriterLock(-1); | ||
148 | // shutdownFlag = true; | ||
149 | // udpSocket.Close(); | ||
150 | // rwLock.ReleaseWriterLock(); | ||
151 | |||
152 | // // wait for any pending operations to complete on other | ||
153 | // // threads before exiting. | ||
154 | // const int FORCE_STOP = 100; | ||
155 | // int i = 0; | ||
156 | // while (rwOperationCount > 0 && i < FORCE_STOP) | ||
157 | // { | ||
158 | // Thread.Sleep(10); | ||
159 | // ++i; | ||
160 | // } | ||
161 | |||
162 | // if (i >= FORCE_STOP) | ||
163 | // { | ||
164 | // Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", | ||
165 | // Helpers.LogLevel.Warning); | ||
166 | // } | ||
167 | // } | ||
168 | // } | ||
169 | |||
170 | // /// <summary> | ||
171 | // /// | ||
172 | // /// </summary> | ||
173 | // public bool IsRunning | ||
174 | // { | ||
175 | // get { return !shutdownFlag; } | ||
176 | // } | ||
177 | |||
178 | // private void AsyncBeginReceive() | ||
179 | // { | ||
180 | // // this method actually kicks off the async read on the socket. | ||
181 | // // we aquire a reader lock here to ensure that no other thread | ||
182 | // // is trying to set shutdownFlag and close the socket. | ||
183 | // rwLock.AcquireReaderLock(-1); | ||
184 | |||
185 | // if (!shutdownFlag) | ||
186 | // { | ||
187 | // // increment the count of pending operations | ||
188 | // Interlocked.Increment(ref rwOperationCount); | ||
189 | |||
190 | // // allocate a packet buffer | ||
191 | // //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | ||
192 | // UDPPacketBuffer buf = new UDPPacketBuffer(); | ||
193 | |||
194 | // try | ||
195 | // { | ||
196 | // // kick off an async read | ||
197 | // udpSocket.BeginReceiveFrom( | ||
198 | // //wrappedBuffer.Instance.Data, | ||
199 | // buf.Data, | ||
200 | // 0, | ||
201 | // UDPPacketBuffer.BUFFER_SIZE, | ||
202 | // SocketFlags.None, | ||
203 | // //ref wrappedBuffer.Instance.RemoteEndPoint, | ||
204 | // ref buf.RemoteEndPoint, | ||
205 | // new AsyncCallback(AsyncEndReceive), | ||
206 | // //wrappedBuffer); | ||
207 | // buf); | ||
208 | // } | ||
209 | // catch (SocketException) | ||
210 | // { | ||
211 | // // something bad happened | ||
212 | // //Logger.Log( | ||
213 | // // "A SocketException occurred in UDPServer.AsyncBeginReceive()", | ||
214 | // // Helpers.LogLevel.Error, se); | ||
215 | |||
216 | // // an error occurred, therefore the operation is void. Decrement the reference count. | ||
217 | // Interlocked.Decrement(ref rwOperationCount); | ||
218 | // } | ||
219 | // } | ||
220 | |||
221 | // // we're done with the socket for now, release the reader lock. | ||
222 | // rwLock.ReleaseReaderLock(); | ||
223 | // } | ||
224 | |||
225 | // private void AsyncEndReceive(IAsyncResult iar) | ||
226 | // { | ||
227 | // // Asynchronous receive operations will complete here through the call | ||
228 | // // to AsyncBeginReceive | ||
229 | |||
230 | // // aquire a reader lock | ||
231 | // rwLock.AcquireReaderLock(-1); | ||
232 | |||
233 | // if (!shutdownFlag) | ||
234 | // { | ||
235 | // // get the buffer that was created in AsyncBeginReceive | ||
236 | // // this is the received data | ||
237 | // //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState; | ||
238 | // //UDPPacketBuffer buffer = wrappedBuffer.Instance; | ||
239 | // UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
240 | |||
241 | // try | ||
242 | // { | ||
243 | // // get the length of data actually read from the socket, store it with the | ||
244 | // // buffer | ||
245 | // buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | ||
246 | |||
247 | // // this operation is now complete, decrement the reference count | ||
248 | // Interlocked.Decrement(ref rwOperationCount); | ||
249 | |||
250 | // // we're done with the socket, release the reader lock | ||
251 | // rwLock.ReleaseReaderLock(); | ||
252 | |||
253 | // // call the abstract method PacketReceived(), passing the buffer that | ||
254 | // // has just been filled from the socket read. | ||
255 | // PacketReceived(buffer); | ||
256 | // } | ||
257 | // catch (SocketException) | ||
258 | // { | ||
259 | // // an error occurred, therefore the operation is void. Decrement the reference count. | ||
260 | // Interlocked.Decrement(ref rwOperationCount); | ||
261 | |||
262 | // // we're done with the socket for now, release the reader lock. | ||
263 | // rwLock.ReleaseReaderLock(); | ||
264 | // } | ||
265 | // finally | ||
266 | // { | ||
267 | // // start another receive - this keeps the server going! | ||
268 | // AsyncBeginReceive(); | ||
269 | |||
270 | // //wrappedBuffer.Dispose(); | ||
271 | // } | ||
272 | // } | ||
273 | // else | ||
274 | // { | ||
275 | // // nothing bad happened, but we are done with the operation | ||
276 | // // decrement the reference count and release the reader lock | ||
277 | // Interlocked.Decrement(ref rwOperationCount); | ||
278 | // rwLock.ReleaseReaderLock(); | ||
279 | // } | ||
280 | // } | ||
281 | |||
282 | // public void AsyncBeginSend(UDPPacketBuffer buf) | ||
283 | // { | ||
284 | // rwLock.AcquireReaderLock(-1); | ||
285 | |||
286 | // if (!shutdownFlag) | ||
287 | // { | ||
288 | // try | ||
289 | // { | ||
290 | // Interlocked.Increment(ref rwOperationCount); | ||
291 | // udpSocket.BeginSendTo( | ||
292 | // buf.Data, | ||
293 | // 0, | ||
294 | // buf.DataLength, | ||
295 | // SocketFlags.None, | ||
296 | // buf.RemoteEndPoint, | ||
297 | // new AsyncCallback(AsyncEndSend), | ||
298 | // buf); | ||
299 | // } | ||
300 | // catch (SocketException) | ||
301 | // { | ||
302 | // //Logger.Log( | ||
303 | // // "A SocketException occurred in UDPServer.AsyncBeginSend()", | ||
304 | // // Helpers.LogLevel.Error, se); | ||
305 | // } | ||
306 | // } | ||
307 | |||
308 | // rwLock.ReleaseReaderLock(); | ||
309 | // } | ||
310 | |||
311 | // private void AsyncEndSend(IAsyncResult iar) | ||
312 | // { | ||
313 | // rwLock.AcquireReaderLock(-1); | ||
314 | |||
315 | // if (!shutdownFlag) | ||
316 | // { | ||
317 | // UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
318 | |||
319 | // try | ||
320 | // { | ||
321 | // int bytesSent = udpSocket.EndSendTo(iar); | ||
322 | |||
323 | // // note that call to the abstract PacketSent() method - we are passing the number | ||
324 | // // of bytes sent in a separate parameter, since we can't use buffer.DataLength which | ||
325 | // // is the number of bytes to send (or bytes received depending upon whether this | ||
326 | // // buffer was part of a send or a receive). | ||
327 | // PacketSent(buffer, bytesSent); | ||
328 | // } | ||
329 | // catch (SocketException) | ||
330 | // { | ||
331 | // //Logger.Log( | ||
332 | // // "A SocketException occurred in UDPServer.AsyncEndSend()", | ||
333 | // // Helpers.LogLevel.Error, se); | ||
334 | // } | ||
335 | // } | ||
336 | |||
337 | // Interlocked.Decrement(ref rwOperationCount); | ||
338 | // rwLock.ReleaseReaderLock(); | ||
339 | // } | ||
340 | // } | ||
341 | //} | ||
342 | |||
343 | //--------- Original Version ------------------- | ||
344 | |||
345 | |||
346 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
347 | { | 35 | { |
348 | /// <summary> | 36 | /// <summary> |
349 | /// | 37 | /// Base UDP server |
350 | /// </summary> | 38 | /// </summary> |
351 | public abstract class OpenSimUDPBase | 39 | public abstract class OpenSimUDPBase |
352 | { | 40 | { |
353 | // these abstract methods must be implemented in a derived class to actually do | 41 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
354 | // something with the packets that are sent and received. | 42 | |
43 | /// <summary> | ||
44 | /// This method is called when an incoming packet is received | ||
45 | /// </summary> | ||
46 | /// <param name="buffer">Incoming packet buffer</param> | ||
355 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | 47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); |
48 | |||
49 | /// <summary> | ||
50 | /// This method is called when an outgoing packet is sent | ||
51 | /// </summary> | ||
52 | /// <param name="buffer">Outgoing packet buffer</param> | ||
53 | /// <param name="bytesSent">Number of bytes written to the wire</param> | ||
356 | protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); | 54 | protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); |
357 | 55 | ||
358 | // the port to listen on | 56 | /// <summary>UDP port to bind to in server mode</summary> |
359 | internal int udpPort; | 57 | protected int m_udpPort; |
360 | 58 | ||
361 | // the UDP socket | 59 | /// <summary>Local IP address to bind to in server mode</summary> |
362 | private Socket udpSocket; | 60 | protected IPAddress m_localBindAddress; |
363 | 61 | ||
364 | // the all important shutdownFlag. | 62 | /// <summary>UDP socket, used in either client or server mode</summary> |
365 | private volatile bool shutdownFlag = true; | 63 | private Socket m_udpSocket; |
366 | 64 | ||
367 | // the remote endpoint to communicate with | 65 | /// <summary>The all important shutdown flag</summary> |
368 | protected IPEndPoint remoteEndPoint = null; | 66 | private volatile bool m_shutdownFlag = true; |
369 | 67 | ||
370 | /// <summary> | 68 | /// <summary>Returns true if the server is currently listening, otherwise false</summary> |
371 | /// Initialize the UDP packet handler in server mode | 69 | public bool IsRunning { get { return !m_shutdownFlag; } } |
372 | /// </summary> | ||
373 | /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
374 | public OpenSimUDPBase(int port) | ||
375 | { | ||
376 | udpPort = port; | ||
377 | } | ||
378 | 70 | ||
379 | /// <summary> | 71 | /// <summary> |
380 | /// Initialize the UDP packet handler in client mode | 72 | /// Default constructor |
381 | /// </summary> | 73 | /// </summary> |
382 | /// <param name="endPoint">Remote UDP server to connect to</param> | 74 | /// <param name="bindAddress">Local IP address to bind the server to</param> |
383 | public OpenSimUDPBase(IPEndPoint endPoint) | 75 | /// <param name="port">Port to listening for incoming UDP packets on</param> |
76 | public OpenSimUDPBase(IPAddress bindAddress, int port) | ||
384 | { | 77 | { |
385 | remoteEndPoint = endPoint; | 78 | m_localBindAddress = bindAddress; |
386 | udpPort = 0; | 79 | m_udpPort = port; |
387 | } | 80 | } |
388 | 81 | ||
389 | /// <summary> | 82 | /// <summary> |
390 | /// | 83 | /// Start the UDP server |
391 | /// </summary> | 84 | /// </summary> |
85 | /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag | ||
86 | /// on the socket to get newer versions of Windows to behave in a sane | ||
87 | /// manner (not throwing an exception when the remote side resets the | ||
88 | /// connection). This call is ignored on Mono where the flag is not | ||
89 | /// necessary</remarks> | ||
392 | public void Start() | 90 | public void Start() |
393 | { | 91 | { |
394 | if (shutdownFlag) | 92 | if (m_shutdownFlag) |
395 | { | 93 | { |
396 | const int SIO_UDP_CONNRESET = -1744830452; | 94 | const int SIO_UDP_CONNRESET = -1744830452; |
397 | 95 | ||
398 | IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); | 96 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
399 | udpSocket = new Socket( | 97 | m_udpSocket = new Socket( |
400 | AddressFamily.InterNetwork, | 98 | AddressFamily.InterNetwork, |
401 | SocketType.Dgram, | 99 | SocketType.Dgram, |
402 | ProtocolType.Udp); | 100 | ProtocolType.Udp); |
@@ -404,16 +102,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
404 | { | 102 | { |
405 | // this udp socket flag is not supported under mono, | 103 | // this udp socket flag is not supported under mono, |
406 | // so we'll catch the exception and continue | 104 | // so we'll catch the exception and continue |
407 | udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | 105 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); |
106 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
408 | } | 107 | } |
409 | catch (SocketException) | 108 | catch (SocketException) |
410 | { | 109 | { |
411 | Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); | 110 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
412 | } | 111 | } |
413 | udpSocket.Bind(ipep); | 112 | m_udpSocket.Bind(ipep); |
414 | 113 | ||
415 | // we're not shutting down, we're starting up | 114 | // we're not shutting down, we're starting up |
416 | shutdownFlag = false; | 115 | m_shutdownFlag = false; |
417 | 116 | ||
418 | // kick off an async receive. The Start() method will return, the | 117 | // kick off an async receive. The Start() method will return, the |
419 | // actual receives will occur asynchronously and will be caught in | 118 | // actual receives will occur asynchronously and will be caught in |
@@ -423,41 +122,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
423 | } | 122 | } |
424 | 123 | ||
425 | /// <summary> | 124 | /// <summary> |
426 | /// | 125 | /// Stops the UDP server |
427 | /// </summary> | 126 | /// </summary> |
428 | public void Stop() | 127 | public void Stop() |
429 | { | 128 | { |
430 | if (!shutdownFlag) | 129 | if (!m_shutdownFlag) |
431 | { | 130 | { |
432 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | 131 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime |
433 | // will deny any more reader locks, in effect blocking all other send/receive | 132 | // will deny any more reader locks, in effect blocking all other send/receive |
434 | // threads. Once we have the lock, we set shutdownFlag to inform the other | 133 | // threads. Once we have the lock, we set shutdownFlag to inform the other |
435 | // threads that the socket is closed. | 134 | // threads that the socket is closed. |
436 | shutdownFlag = true; | 135 | m_shutdownFlag = true; |
437 | udpSocket.Close(); | 136 | m_udpSocket.Close(); |
438 | } | 137 | } |
439 | } | 138 | } |
440 | 139 | ||
441 | /// <summary> | ||
442 | /// | ||
443 | /// </summary> | ||
444 | public bool IsRunning | ||
445 | { | ||
446 | get { return !shutdownFlag; } | ||
447 | } | ||
448 | |||
449 | private void AsyncBeginReceive() | 140 | private void AsyncBeginReceive() |
450 | { | 141 | { |
451 | // allocate a packet buffer | 142 | // allocate a packet buffer |
452 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | 143 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); |
453 | UDPPacketBuffer buf = new UDPPacketBuffer(); | 144 | UDPPacketBuffer buf = new UDPPacketBuffer(); |
454 | 145 | ||
455 | if (!shutdownFlag) | 146 | if (!m_shutdownFlag) |
456 | { | 147 | { |
457 | try | 148 | try |
458 | { | 149 | { |
459 | // kick off an async read | 150 | // kick off an async read |
460 | udpSocket.BeginReceiveFrom( | 151 | m_udpSocket.BeginReceiveFrom( |
461 | //wrappedBuffer.Instance.Data, | 152 | //wrappedBuffer.Instance.Data, |
462 | buf.Data, | 153 | buf.Data, |
463 | 0, | 154 | 0, |
@@ -472,13 +163,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
472 | { | 163 | { |
473 | if (e.SocketErrorCode == SocketError.ConnectionReset) | 164 | if (e.SocketErrorCode == SocketError.ConnectionReset) |
474 | { | 165 | { |
475 | Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); | 166 | m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); |
476 | bool salvaged = false; | 167 | bool salvaged = false; |
477 | while (!salvaged) | 168 | while (!salvaged) |
478 | { | 169 | { |
479 | try | 170 | try |
480 | { | 171 | { |
481 | udpSocket.BeginReceiveFrom( | 172 | m_udpSocket.BeginReceiveFrom( |
482 | //wrappedBuffer.Instance.Data, | 173 | //wrappedBuffer.Instance.Data, |
483 | buf.Data, | 174 | buf.Data, |
484 | 0, | 175 | 0, |
@@ -494,7 +185,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
494 | catch (ObjectDisposedException) { return; } | 185 | catch (ObjectDisposedException) { return; } |
495 | } | 186 | } |
496 | 187 | ||
497 | Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); | 188 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
498 | } | 189 | } |
499 | } | 190 | } |
500 | catch (ObjectDisposedException) { } | 191 | catch (ObjectDisposedException) { } |
@@ -505,7 +196,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
505 | { | 196 | { |
506 | // Asynchronous receive operations will complete here through the call | 197 | // Asynchronous receive operations will complete here through the call |
507 | // to AsyncBeginReceive | 198 | // to AsyncBeginReceive |
508 | if (!shutdownFlag) | 199 | if (!m_shutdownFlag) |
509 | { | 200 | { |
510 | // start another receive - this keeps the server going! | 201 | // start another receive - this keeps the server going! |
511 | AsyncBeginReceive(); | 202 | AsyncBeginReceive(); |
@@ -520,7 +211,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
520 | { | 211 | { |
521 | // get the length of data actually read from the socket, store it with the | 212 | // get the length of data actually read from the socket, store it with the |
522 | // buffer | 213 | // buffer |
523 | buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | 214 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); |
524 | 215 | ||
525 | // call the abstract method PacketReceived(), passing the buffer that | 216 | // call the abstract method PacketReceived(), passing the buffer that |
526 | // has just been filled from the socket read. | 217 | // has just been filled from the socket read. |
@@ -529,16 +220,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
529 | catch (SocketException) { } | 220 | catch (SocketException) { } |
530 | catch (ObjectDisposedException) { } | 221 | catch (ObjectDisposedException) { } |
531 | //finally { wrappedBuffer.Dispose(); } | 222 | //finally { wrappedBuffer.Dispose(); } |
223 | |||
532 | } | 224 | } |
533 | } | 225 | } |
534 | 226 | ||
535 | public void AsyncBeginSend(UDPPacketBuffer buf) | 227 | public void AsyncBeginSend(UDPPacketBuffer buf) |
536 | { | 228 | { |
537 | if (!shutdownFlag) | 229 | if (!m_shutdownFlag) |
538 | { | 230 | { |
539 | try | 231 | try |
540 | { | 232 | { |
541 | udpSocket.BeginSendTo( | 233 | m_udpSocket.BeginSendTo( |
542 | buf.Data, | 234 | buf.Data, |
543 | 0, | 235 | 0, |
544 | buf.DataLength, | 236 | buf.DataLength, |
@@ -557,7 +249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
557 | try | 249 | try |
558 | { | 250 | { |
559 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 251 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
560 | int bytesSent = udpSocket.EndSendTo(result); | 252 | int bytesSent = m_udpSocket.EndSendTo(result); |
561 | 253 | ||
562 | PacketSent(buf, bytesSent); | 254 | PacketSent(buf, bytesSent); |
563 | } | 255 | } |
@@ -566,4 +258,3 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
566 | } | 258 | } |
567 | } | 259 | } |
568 | } | 260 | } |
569 | |||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 195ca57..f3242c1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | |||
@@ -103,6 +103,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /// <summary> | 105 | /// <summary> |
106 | /// Removes all elements from the collection | ||
107 | /// </summary> | ||
108 | public void Clear() | ||
109 | { | ||
110 | lock (SyncRoot) | ||
111 | packets.Clear(); | ||
112 | } | ||
113 | |||
114 | /// <summary> | ||
106 | /// Gets the packet with the lowest sequence number | 115 | /// Gets the packet with the lowest sequence number |
107 | /// </summary> | 116 | /// </summary> |
108 | /// <returns>The packet with the lowest sequence number, or null if the | 117 | /// <returns>The packet with the lowest sequence number, or null if the |