diff options
Diffstat (limited to 'OpenSim.RegionServer/SimClient.cs')
-rw-r--r-- | OpenSim.RegionServer/SimClient.cs | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/OpenSim.RegionServer/SimClient.cs b/OpenSim.RegionServer/SimClient.cs new file mode 100644 index 0000000..210e0d9 --- /dev/null +++ b/OpenSim.RegionServer/SimClient.cs | |||
@@ -0,0 +1,621 @@ | |||
1 | /* | ||
2 | Copyright (c) OpenSim project, http://osgrid.org/ | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions are met: | ||
6 | * * Redistributions of source code must retain the above copyright | ||
7 | * notice, this list of conditions and the following disclaimer. | ||
8 | * * Redistributions in binary form must reproduce the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer in the | ||
10 | * documentation and/or other materials provided with the distribution. | ||
11 | * * Neither the name of the <organization> nor the | ||
12 | * names of its contributors may be used to endorse or promote products | ||
13 | * derived from this software without specific prior written permission. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY | ||
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
18 | * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY | ||
19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using libsecondlife; | ||
31 | using libsecondlife.Packets; | ||
32 | using System.Net; | ||
33 | using System.Net.Sockets; | ||
34 | using System.IO; | ||
35 | using System.Threading; | ||
36 | using System.Timers; | ||
37 | using OpenSim.Framework.Interfaces; | ||
38 | using OpenSim.Framework.Assets; | ||
39 | using OpenSim.Framework.Inventory; | ||
40 | using OpenSim.Framework.Utilities; | ||
41 | using OpenSim.world; | ||
42 | using OpenSim.Assets; | ||
43 | |||
44 | namespace OpenSim | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// Handles new client connections | ||
48 | /// Constructor takes a single Packet and authenticates everything | ||
49 | /// </summary> | ||
50 | public class SimClient | ||
51 | { | ||
52 | |||
53 | public LLUUID AgentID; | ||
54 | public LLUUID SessionID; | ||
55 | public LLUUID SecureSessionID = LLUUID.Zero; | ||
56 | public uint CircuitCode; | ||
57 | public world.Avatar ClientAvatar; | ||
58 | private UseCircuitCodePacket cirpack; | ||
59 | private Thread ClientThread; | ||
60 | public EndPoint userEP; | ||
61 | private BlockingQueue<QueItem> PacketQueue; | ||
62 | private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | ||
63 | private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | ||
64 | //private Dictionary<LLUUID, AssetBase> UploadedAssets = new Dictionary<LLUUID, AssetBase>(); | ||
65 | private System.Timers.Timer AckTimer; | ||
66 | private uint Sequence = 0; | ||
67 | private object SequenceLock = new object(); | ||
68 | private const int MAX_APPENDED_ACKS = 10; | ||
69 | private const int RESEND_TIMEOUT = 4000; | ||
70 | private const int MAX_SEQUENCE = 0xFFFFFF; | ||
71 | private LLUUID newAssetFolder = LLUUID.Zero; | ||
72 | private bool debug = false; | ||
73 | |||
74 | private void ack_pack(Packet Pack) | ||
75 | { | ||
76 | //libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket(); | ||
77 | //ack_it.Packets = new PacketAckPacket.PacketsBlock[1]; | ||
78 | //ack_it.Packets[0] = new PacketAckPacket.PacketsBlock(); | ||
79 | //ack_it.Packets[0].ID = Pack.Header.ID; | ||
80 | //ack_it.Header.Reliable = false; | ||
81 | |||
82 | //OutPacket(ack_it); | ||
83 | |||
84 | if (Pack.Header.Reliable) | ||
85 | { | ||
86 | lock (PendingAcks) | ||
87 | { | ||
88 | uint sequence = (uint)Pack.Header.Sequence; | ||
89 | if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; } | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | protected virtual void ProcessInPacket(Packet Pack) | ||
95 | { | ||
96 | ack_pack(Pack); | ||
97 | if (debug) | ||
98 | { | ||
99 | if (Pack.Type != PacketType.AgentUpdate) | ||
100 | { | ||
101 | Console.WriteLine(Pack.Type.ToString()); | ||
102 | } | ||
103 | } | ||
104 | switch (Pack.Type) | ||
105 | { | ||
106 | case PacketType.CompleteAgentMovement: | ||
107 | ClientAvatar.CompleteMovement(OpenSimRoot.Instance.LocalWorld); | ||
108 | ClientAvatar.SendInitialPosition(); | ||
109 | break; | ||
110 | case PacketType.RegionHandshakeReply: | ||
111 | OpenSimRoot.Instance.LocalWorld.SendLayerData(this); | ||
112 | break; | ||
113 | case PacketType.AgentWearablesRequest: | ||
114 | ClientAvatar.SendInitialAppearance(); | ||
115 | foreach (SimClient client in OpenSimRoot.Instance.ClientThreads.Values) | ||
116 | { | ||
117 | if (client.AgentID != this.AgentID) | ||
118 | { | ||
119 | ObjectUpdatePacket objupdate = client.ClientAvatar.CreateUpdatePacket(); | ||
120 | this.OutPacket(objupdate); | ||
121 | client.ClientAvatar.SendAppearanceToOtherAgent(this); | ||
122 | } | ||
123 | } | ||
124 | OpenSimRoot.Instance.LocalWorld.GetInitialPrims(this); | ||
125 | break; | ||
126 | case PacketType.ObjectAdd: | ||
127 | OpenSimRoot.Instance.LocalWorld.AddNewPrim((ObjectAddPacket)Pack, this); | ||
128 | break; | ||
129 | case PacketType.ObjectLink: | ||
130 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine(Pack.ToString()); | ||
131 | break; | ||
132 | case PacketType.ObjectScale: | ||
133 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine(Pack.ToString()); | ||
134 | break; | ||
135 | case PacketType.ObjectShape: | ||
136 | ObjectShapePacket shape = (ObjectShapePacket)Pack; | ||
137 | for (int i = 0; i < shape.ObjectData.Length; i++) | ||
138 | { | ||
139 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
140 | { | ||
141 | if (ent.localid == shape.ObjectData[i].ObjectLocalID) | ||
142 | { | ||
143 | ((OpenSim.world.Primitive)ent).UpdateShape(shape.ObjectData[i]); | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | break; | ||
148 | case PacketType.MultipleObjectUpdate: | ||
149 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)Pack; | ||
150 | |||
151 | for (int i = 0; i < multipleupdate.ObjectData.Length; i++) | ||
152 | { | ||
153 | if (multipleupdate.ObjectData[i].Type == 9) //change position | ||
154 | { | ||
155 | libsecondlife.LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0); | ||
156 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
157 | { | ||
158 | if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) | ||
159 | { | ||
160 | ((OpenSim.world.Primitive)ent).UpdatePosition(pos); | ||
161 | |||
162 | } | ||
163 | } | ||
164 | |||
165 | //should update stored position of the prim | ||
166 | } | ||
167 | else if (multipleupdate.ObjectData[i].Type == 10)//rotation | ||
168 | { | ||
169 | libsecondlife.LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true); | ||
170 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
171 | { | ||
172 | if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) | ||
173 | { | ||
174 | ent.rotation = new Axiom.MathLib.Quaternion(rot.W, rot.X, rot.Y, rot.W); | ||
175 | ((OpenSim.world.Primitive)ent).UpdateFlag = true; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | else if (multipleupdate.ObjectData[i].Type == 13)//scale | ||
180 | { | ||
181 | |||
182 | libsecondlife.LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12); | ||
183 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
184 | { | ||
185 | if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) | ||
186 | { | ||
187 | ((OpenSim.world.Primitive)ent).Scale = scale; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | break; | ||
193 | case PacketType.RequestImage: | ||
194 | RequestImagePacket imageRequest = (RequestImagePacket)Pack; | ||
195 | for (int i = 0; i < imageRequest.RequestImage.Length; i++) | ||
196 | { | ||
197 | OpenSimRoot.Instance.AssetCache.AddTextureRequest(this, imageRequest.RequestImage[i].Image); | ||
198 | } | ||
199 | break; | ||
200 | case PacketType.TransferRequest: | ||
201 | //Console.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request"); | ||
202 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | ||
203 | OpenSimRoot.Instance.AssetCache.AddAssetRequest(this, transfer); | ||
204 | break; | ||
205 | case PacketType.AgentUpdate: | ||
206 | ClientAvatar.HandleUpdate((AgentUpdatePacket)Pack); | ||
207 | break; | ||
208 | case PacketType.LogoutRequest: | ||
209 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request"); | ||
210 | //send reply to let the client logout | ||
211 | LogoutReplyPacket logReply = new LogoutReplyPacket(); | ||
212 | logReply.AgentData.AgentID = this.AgentID; | ||
213 | logReply.AgentData.SessionID = this.SessionID; | ||
214 | logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1]; | ||
215 | logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock(); | ||
216 | logReply.InventoryData[0].ItemID = LLUUID.Zero; | ||
217 | OutPacket(logReply); | ||
218 | //tell all clients to kill our object | ||
219 | KillObjectPacket kill = new KillObjectPacket(); | ||
220 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; | ||
221 | kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); | ||
222 | kill.ObjectData[0].ID = this.ClientAvatar.localid; | ||
223 | foreach (SimClient client in OpenSimRoot.Instance.ClientThreads.Values) | ||
224 | { | ||
225 | client.OutPacket(kill); | ||
226 | } | ||
227 | OpenSimRoot.Instance.GridServers.GridServer.LogoutSession(this.SessionID, this.AgentID, this.CircuitCode); | ||
228 | lock (OpenSimRoot.Instance.LocalWorld.Entities) | ||
229 | { | ||
230 | OpenSimRoot.Instance.LocalWorld.Entities.Remove(this.AgentID); | ||
231 | } | ||
232 | //need to do other cleaning up here too | ||
233 | OpenSimRoot.Instance.ClientThreads.Remove(this.CircuitCode); //this.userEP); | ||
234 | OpenSimRoot.Instance.Application.RemoveClientCircuit(this.CircuitCode); | ||
235 | this.ClientThread.Abort(); | ||
236 | break; | ||
237 | case PacketType.ChatFromViewer: | ||
238 | ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack; | ||
239 | if (Helpers.FieldToString(inchatpack.ChatData.Message) == "") break; | ||
240 | |||
241 | System.Text.Encoding _enc = System.Text.Encoding.ASCII; | ||
242 | libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket(); | ||
243 | reply.ChatData.Audible = 1; | ||
244 | reply.ChatData.Message = inchatpack.ChatData.Message; | ||
245 | reply.ChatData.ChatType = 1; | ||
246 | reply.ChatData.SourceType = 1; | ||
247 | reply.ChatData.Position = this.ClientAvatar.position; | ||
248 | reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0"); | ||
249 | reply.ChatData.OwnerID = this.AgentID; | ||
250 | reply.ChatData.SourceID = this.AgentID; | ||
251 | foreach (SimClient client in OpenSimRoot.Instance.ClientThreads.Values) | ||
252 | { | ||
253 | client.OutPacket(reply); | ||
254 | } | ||
255 | break; | ||
256 | case PacketType.ObjectImage: | ||
257 | ObjectImagePacket imagePack = (ObjectImagePacket)Pack; | ||
258 | for (int i = 0; i < imagePack.ObjectData.Length; i++) | ||
259 | { | ||
260 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
261 | { | ||
262 | if (ent.localid == imagePack.ObjectData[i].ObjectLocalID) | ||
263 | { | ||
264 | ((OpenSim.world.Primitive)ent).UpdateTexture(imagePack.ObjectData[i].TextureEntry); | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | break; | ||
269 | case PacketType.ObjectFlagUpdate: | ||
270 | ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack; | ||
271 | foreach (Entity ent in OpenSimRoot.Instance.LocalWorld.Entities.Values) | ||
272 | { | ||
273 | if (ent.localid == flags.AgentData.ObjectLocalID) | ||
274 | { | ||
275 | ((OpenSim.world.Primitive)ent).UpdateObjectFlags(flags); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | break; | ||
280 | case PacketType.AssetUploadRequest: | ||
281 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | ||
282 | Console.WriteLine("upload request "+ request.AssetBlock.TransactionID); | ||
283 | AssetBase newAsset = OpenSimRoot.Instance.AssetCache.UploadPacket(request, LLUUID.Random()); | ||
284 | if (newAsset != null) | ||
285 | { | ||
286 | OpenSimRoot.Instance.InventoryCache.AddNewInventoryItem(this, this.newAssetFolder, newAsset); | ||
287 | } | ||
288 | Console.WriteLine(request.ToString()); | ||
289 | Console.WriteLine("combined uuid is " + request.AssetBlock.TransactionID.Combine(this.SecureSessionID).ToStringHyphenated()); | ||
290 | |||
291 | AssetUploadCompletePacket response = new AssetUploadCompletePacket(); | ||
292 | response.AssetBlock.Type =request.AssetBlock.Type; | ||
293 | response.AssetBlock.Success = true; | ||
294 | response.AssetBlock.UUID = request.AssetBlock.TransactionID.Combine(this.SecureSessionID); | ||
295 | |||
296 | this.OutPacket(response); | ||
297 | break; | ||
298 | case PacketType.CreateInventoryFolder: | ||
299 | //Console.WriteLine(Pack.ToString()); | ||
300 | break; | ||
301 | case PacketType.CreateInventoryItem: | ||
302 | //Console.WriteLine(Pack.ToString()); | ||
303 | break; | ||
304 | case PacketType.FetchInventory: | ||
305 | Console.WriteLine("fetch item packet"); | ||
306 | FetchInventoryPacket FetchInventory = (FetchInventoryPacket)Pack; | ||
307 | OpenSimRoot.Instance.InventoryCache.FetchInventory(this, FetchInventory); | ||
308 | break; | ||
309 | case PacketType.FetchInventoryDescendents: | ||
310 | FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack; | ||
311 | OpenSimRoot.Instance.InventoryCache.FetchInventoryDescendents(this, Fetch); | ||
312 | break; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | private void ResendUnacked() | ||
317 | { | ||
318 | int now = Environment.TickCount; | ||
319 | |||
320 | lock (NeedAck) | ||
321 | { | ||
322 | foreach (Packet packet in NeedAck.Values) | ||
323 | { | ||
324 | if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent)) | ||
325 | { | ||
326 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Resending " + packet.Type.ToString() + " packet, " + | ||
327 | (now - packet.TickCount) + "ms have passed"); | ||
328 | |||
329 | packet.Header.Resent = true; | ||
330 | OutPacket(packet); | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | private void SendAcks() | ||
337 | { | ||
338 | lock (PendingAcks) | ||
339 | { | ||
340 | if (PendingAcks.Count > 0) | ||
341 | { | ||
342 | if (PendingAcks.Count > 250) | ||
343 | { | ||
344 | // FIXME: Handle the odd case where we have too many pending ACKs queued up | ||
345 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Too many ACKs queued up!"); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Sending PacketAck"); | ||
350 | |||
351 | |||
352 | int i = 0; | ||
353 | PacketAckPacket acks = new PacketAckPacket(); | ||
354 | acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count]; | ||
355 | |||
356 | foreach (uint ack in PendingAcks.Values) | ||
357 | { | ||
358 | acks.Packets[i] = new PacketAckPacket.PacketsBlock(); | ||
359 | acks.Packets[i].ID = ack; | ||
360 | i++; | ||
361 | } | ||
362 | |||
363 | acks.Header.Reliable = false; | ||
364 | OutPacket(acks); | ||
365 | |||
366 | PendingAcks.Clear(); | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) | ||
372 | { | ||
373 | SendAcks(); | ||
374 | ResendUnacked(); | ||
375 | } | ||
376 | |||
377 | protected virtual void ProcessOutPacket(Packet Pack) | ||
378 | { | ||
379 | |||
380 | // Keep track of when this packet was sent out | ||
381 | Pack.TickCount = Environment.TickCount; | ||
382 | |||
383 | if (!Pack.Header.Resent) | ||
384 | { | ||
385 | // Set the sequence number | ||
386 | lock (SequenceLock) | ||
387 | { | ||
388 | if (Sequence >= MAX_SEQUENCE) | ||
389 | Sequence = 1; | ||
390 | else | ||
391 | Sequence++; | ||
392 | Pack.Header.Sequence = Sequence; | ||
393 | } | ||
394 | |||
395 | if (Pack.Header.Reliable) //DIRTY HACK | ||
396 | { | ||
397 | lock (NeedAck) | ||
398 | { | ||
399 | if (!NeedAck.ContainsKey(Pack.Header.Sequence)) | ||
400 | { | ||
401 | NeedAck.Add(Pack.Header.Sequence, Pack); | ||
402 | } | ||
403 | else | ||
404 | { | ||
405 | // Client.Log("Attempted to add a duplicate sequence number (" + | ||
406 | // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + | ||
407 | // packet.Type.ToString(), Helpers.LogLevel.Warning); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | // Don't append ACKs to resent packets, in case that's what was causing the | ||
412 | // delivery to fail | ||
413 | if (!Pack.Header.Resent) | ||
414 | { | ||
415 | // Append any ACKs that need to be sent out to this packet | ||
416 | lock (PendingAcks) | ||
417 | { | ||
418 | if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS && | ||
419 | Pack.Type != PacketType.PacketAck && | ||
420 | Pack.Type != PacketType.LogoutRequest) | ||
421 | { | ||
422 | Pack.Header.AckList = new uint[PendingAcks.Count]; | ||
423 | int i = 0; | ||
424 | |||
425 | foreach (uint ack in PendingAcks.Values) | ||
426 | { | ||
427 | Pack.Header.AckList[i] = ack; | ||
428 | i++; | ||
429 | } | ||
430 | |||
431 | PendingAcks.Clear(); | ||
432 | Pack.Header.AppendedAcks = true; | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | //ServerConsole.MainConsole.Instance.WriteLine("OUT: \n" + Pack.ToString()); | ||
440 | |||
441 | byte[] ZeroOutBuffer = new byte[4096]; | ||
442 | byte[] sendbuffer; | ||
443 | sendbuffer = Pack.ToBytes(); | ||
444 | |||
445 | try | ||
446 | { | ||
447 | if (Pack.Header.Zerocoded) | ||
448 | { | ||
449 | int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer); | ||
450 | OpenSimRoot.Instance.Application.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, CircuitCode);//userEP); | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | OpenSimRoot.Instance.Application.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, CircuitCode); //userEP); | ||
455 | } | ||
456 | } | ||
457 | catch (Exception) | ||
458 | { | ||
459 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread"); | ||
460 | ClientThread.Abort(); | ||
461 | } | ||
462 | |||
463 | } | ||
464 | |||
465 | public virtual void InPacket(Packet NewPack) | ||
466 | { | ||
467 | // Handle appended ACKs | ||
468 | if (NewPack.Header.AppendedAcks) | ||
469 | { | ||
470 | lock (NeedAck) | ||
471 | { | ||
472 | foreach (uint ack in NewPack.Header.AckList) | ||
473 | { | ||
474 | NeedAck.Remove(ack); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | |||
479 | // Handle PacketAck packets | ||
480 | if (NewPack.Type == PacketType.PacketAck) | ||
481 | { | ||
482 | PacketAckPacket ackPacket = (PacketAckPacket)NewPack; | ||
483 | |||
484 | lock (NeedAck) | ||
485 | { | ||
486 | foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) | ||
487 | { | ||
488 | NeedAck.Remove(block.ID); | ||
489 | } | ||
490 | } | ||
491 | } | ||
492 | else if ((NewPack.Type == PacketType.StartPingCheck)) | ||
493 | { | ||
494 | //reply to pingcheck | ||
495 | libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack; | ||
496 | libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket(); | ||
497 | endPing.PingID.PingID = startPing.PingID.PingID; | ||
498 | OutPacket(endPing); | ||
499 | } | ||
500 | else | ||
501 | { | ||
502 | QueItem item = new QueItem(); | ||
503 | item.Packet = NewPack; | ||
504 | item.Incoming = true; | ||
505 | this.PacketQueue.Enqueue(item); | ||
506 | } | ||
507 | |||
508 | } | ||
509 | |||
510 | public virtual void OutPacket(Packet NewPack) | ||
511 | { | ||
512 | QueItem item = new QueItem(); | ||
513 | item.Packet = NewPack; | ||
514 | item.Incoming = false; | ||
515 | this.PacketQueue.Enqueue(item); | ||
516 | } | ||
517 | |||
518 | public SimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) | ||
519 | { | ||
520 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request"); | ||
521 | cirpack = initialcirpack; | ||
522 | userEP = remoteEP; | ||
523 | PacketQueue = new BlockingQueue<QueItem>(); | ||
524 | AckTimer = new System.Timers.Timer(500); | ||
525 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); | ||
526 | AckTimer.Start(); | ||
527 | |||
528 | ClientThread = new Thread(new ThreadStart(AuthUser)); | ||
529 | ClientThread.IsBackground = true; | ||
530 | ClientThread.Start(); | ||
531 | } | ||
532 | |||
533 | protected virtual void ClientLoop() | ||
534 | { | ||
535 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop"); | ||
536 | while (true) | ||
537 | { | ||
538 | QueItem nextPacket = PacketQueue.Dequeue(); | ||
539 | if (nextPacket.Incoming) | ||
540 | { | ||
541 | //is a incoming packet | ||
542 | ProcessInPacket(nextPacket.Packet); | ||
543 | } | ||
544 | else | ||
545 | { | ||
546 | //is a out going packet | ||
547 | ProcessOutPacket(nextPacket.Packet); | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | protected virtual void InitNewClient() | ||
553 | { | ||
554 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world"); | ||
555 | OpenSimRoot.Instance.LocalWorld.AddViewerAgent(this); | ||
556 | world.Entity tempent = OpenSimRoot.Instance.LocalWorld.Entities[this.AgentID]; | ||
557 | this.ClientAvatar = (world.Avatar)tempent; | ||
558 | } | ||
559 | |||
560 | protected virtual void AuthUser() | ||
561 | { | ||
562 | AuthenticateResponse sessionInfo = OpenSimRoot.Instance.GridServers.GridServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code); | ||
563 | if (!sessionInfo.Authorised) | ||
564 | { | ||
565 | //session/circuit not authorised | ||
566 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString()); | ||
567 | ClientThread.Abort(); | ||
568 | } | ||
569 | else | ||
570 | { | ||
571 | OpenSim.Framework.Console.MainConsole.Instance.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString()); | ||
572 | //session is authorised | ||
573 | this.AgentID = cirpack.CircuitCode.ID; | ||
574 | this.SessionID = cirpack.CircuitCode.SessionID; | ||
575 | this.CircuitCode = cirpack.CircuitCode.Code; | ||
576 | InitNewClient(); //shouldn't be called here as we might be a child agent and not want a full avatar | ||
577 | this.ClientAvatar.firstname = sessionInfo.LoginInfo.First; | ||
578 | this.ClientAvatar.lastname = sessionInfo.LoginInfo.Last; | ||
579 | if (sessionInfo.LoginInfo.SecureSession != LLUUID.Zero) | ||
580 | { | ||
581 | this.SecureSessionID = sessionInfo.LoginInfo.SecureSession; | ||
582 | } | ||
583 | |||
584 | // Create Inventory, currently only works for sandbox mode | ||
585 | if (OpenSimRoot.Instance.Sandbox) | ||
586 | { | ||
587 | if (sessionInfo.LoginInfo.InventoryFolder != null) | ||
588 | { | ||
589 | this.CreateInventory(sessionInfo.LoginInfo.InventoryFolder); | ||
590 | if (sessionInfo.LoginInfo.BaseFolder != null) | ||
591 | { | ||
592 | OpenSimRoot.Instance.InventoryCache.CreateNewInventoryFolder(this, sessionInfo.LoginInfo.BaseFolder); | ||
593 | this.newAssetFolder = sessionInfo.LoginInfo.BaseFolder; | ||
594 | AssetBase[] inventorySet = OpenSimRoot.Instance.AssetCache.CreateNewInventorySet(this.AgentID); | ||
595 | if (inventorySet != null) | ||
596 | { | ||
597 | for (int i = 0; i < inventorySet.Length; i++) | ||
598 | { | ||
599 | if (inventorySet[i] != null) | ||
600 | { | ||
601 | OpenSimRoot.Instance.InventoryCache.AddNewInventoryItem(this, sessionInfo.LoginInfo.BaseFolder, inventorySet[i]); | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | } | ||
608 | |||
609 | ClientLoop(); | ||
610 | } | ||
611 | } | ||
612 | |||
613 | private void CreateInventory(LLUUID baseFolder) | ||
614 | { | ||
615 | AgentInventory inventory = new AgentInventory(); | ||
616 | inventory.AgentID = this.AgentID; | ||
617 | OpenSimRoot.Instance.InventoryCache.AddNewAgentsInventory(inventory); | ||
618 | OpenSimRoot.Instance.InventoryCache.CreateNewInventoryFolder(this, baseFolder); | ||
619 | } | ||
620 | } | ||
621 | } | ||