aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/OpenSimClient.cs
diff options
context:
space:
mode:
authorgareth2007-03-22 10:11:15 +0000
committergareth2007-03-22 10:11:15 +0000
commit7daa3955bc3a1918e40962851f9e8d38597a245e (patch)
treebee3e1372a7eed0c1b220a8a49f7bee7d29a6b91 /src/OpenSimClient.cs
parentLoad XML for neighbourinfo from grid (diff)
downloadopensim-SC-7daa3955bc3a1918e40962851f9e8d38597a245e.zip
opensim-SC-7daa3955bc3a1918e40962851f9e8d38597a245e.tar.gz
opensim-SC-7daa3955bc3a1918e40962851f9e8d38597a245e.tar.bz2
opensim-SC-7daa3955bc3a1918e40962851f9e8d38597a245e.tar.xz
brought zircon branch into trunk
Diffstat (limited to '')
-rw-r--r--src/OpenSimClient.cs471
1 files changed, 0 insertions, 471 deletions
diff --git a/src/OpenSimClient.cs b/src/OpenSimClient.cs
deleted file mode 100644
index dd698e4..0000000
--- a/src/OpenSimClient.cs
+++ /dev/null
@@ -1,471 +0,0 @@
1/*
2Copyright (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
27using System;
28using System.Collections;
29using System.Collections.Generic;
30using libsecondlife;
31using libsecondlife.Packets;
32using System.Net;
33using System.Net.Sockets;
34using System.IO;
35using System.Threading;
36using System.Timers;
37using OpenSim.GridServers;
38using OpenSim.world;
39
40namespace OpenSim
41{
42 /// <summary>
43 /// Handles new client connections
44 /// Constructor takes a single Packet and authenticates everything
45 /// </summary>
46 public class OpenSimClient {
47
48 public LLUUID AgentID;
49 public LLUUID SessionID;
50 public uint CircuitCode;
51 public world.Avatar ClientAvatar;
52 private UseCircuitCodePacket cirpack;
53 private Thread ClientThread;
54 public EndPoint userEP;
55 private BlockingQueue<QueItem> PacketQueue;
56 private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
57 private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
58 private System.Timers.Timer AckTimer;
59 private uint Sequence = 0;
60 private object SequenceLock = new object();
61 private const int MAX_APPENDED_ACKS = 10;
62 private const int RESEND_TIMEOUT = 4000;
63 private const int MAX_SEQUENCE = 0xFFFFFF;
64
65 public void ack_pack(Packet Pack) {
66 //libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
67 //ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
68 //ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
69 //ack_it.Packets[0].ID = Pack.Header.ID;
70 //ack_it.Header.Reliable = false;
71
72 //OutPacket(ack_it);
73
74 if (Pack.Header.Reliable) {
75 lock (PendingAcks) {
76 uint sequence = (uint)Pack.Header.Sequence;
77 if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
78 }
79 }
80 }
81
82 public void ProcessInPacket(Packet Pack) {
83 ack_pack(Pack);
84 switch(Pack.Type) {
85 case PacketType.CompleteAgentMovement:
86 ClientAvatar.CompleteMovement(OpenSim_Main.local_world);
87 ClientAvatar.SendInitialPosition();
88 break;
89 case PacketType.RegionHandshakeReply:
90 OpenSim_Main.local_world.SendLayerData(this);
91 break;
92 case PacketType.AgentWearablesRequest:
93 ClientAvatar.SendInitialAppearance();
94 foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) {
95 if(client.AgentID != this.AgentID)
96 {
97 ObjectUpdatePacket objupdate = client.ClientAvatar.CreateUpdatePacket();
98 this.OutPacket(objupdate);
99 client.ClientAvatar.SendAppearanceToOtherAgent(this);
100 }
101 }
102 OpenSim_Main.local_world.GetInitialPrims(this);
103 break;
104 case PacketType.ObjectAdd:
105 OpenSim_Main.local_world.AddNewPrim((ObjectAddPacket)Pack, this);
106 break;
107 case PacketType.ObjectLink:
108 ServerConsole.MainConsole.Instance.WriteLine(Pack.ToString());
109 break;
110 case PacketType.ObjectScale:
111 ServerConsole.MainConsole.Instance.WriteLine(Pack.ToString());
112 break;
113 case PacketType.ObjectShape:
114 ObjectShapePacket shape = (ObjectShapePacket)Pack;
115 for(int i =0; i <shape.ObjectData.Length; i++)
116 {
117 foreach (Entity ent in OpenSim_Main.local_world.Entities.Values)
118 {
119 if(ent.localid == shape.ObjectData[i].ObjectLocalID)
120 {
121 ((OpenSim.world.Primitive)ent).UpdateShape(shape.ObjectData[i]);
122 }
123 }
124 }
125 break;
126 case PacketType.MultipleObjectUpdate :
127 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)Pack;
128
129 for( int i = 0; i < multipleupdate.ObjectData.Length; i++ )
130 {
131 if( multipleupdate.ObjectData[ i ].Type == 9 ) //change position
132 {
133 libsecondlife.LLVector3 pos = new LLVector3(multipleupdate.ObjectData[ i ].Data, 0 );
134 foreach (Entity ent in OpenSim_Main.local_world.Entities.Values)
135 {
136 if(ent.localid == multipleupdate.ObjectData[ i ].ObjectLocalID)
137 {
138 ((OpenSim.world.Primitive)ent).UpdatePosition( pos);
139
140 }
141 }
142
143 //should update stored position of the prim
144 }
145 else if(multipleupdate.ObjectData[i].Type == 10 )//rotation
146 {
147 libsecondlife.LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true);
148 foreach (Entity ent in OpenSim_Main.local_world.Entities.Values)
149 {
150 if(ent.localid == multipleupdate.ObjectData[ i ].ObjectLocalID)
151 {
152 ent.rotation = new Axiom.MathLib.Quaternion(rot.W, rot.X, rot.Y, rot.W);
153 ((OpenSim.world.Primitive)ent).UpdateFlag = true;
154 }
155 }
156 }
157 else if(multipleupdate.ObjectData[i].Type == 13 )//scale
158 {
159
160 libsecondlife.LLVector3 scale = new LLVector3(multipleupdate.ObjectData[ i ].Data, 12 );
161 foreach (Entity ent in OpenSim_Main.local_world.Entities.Values)
162 {
163 if(ent.localid == multipleupdate.ObjectData[ i ].ObjectLocalID)
164 {
165 ((OpenSim.world.Primitive)ent).Scale = scale;
166 }
167 }
168 }
169 }
170 break;
171 case PacketType.TransferRequest:
172 //Console.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
173 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
174 OpenSim_Main.sim.assetCache.AddAssetRequest(this, transfer);
175 break;
176 case PacketType.AgentUpdate:
177 ClientAvatar.HandleUpdate((AgentUpdatePacket)Pack);
178 break;
179 case PacketType.LogoutRequest:
180 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
181 //tell all clients to kill our object
182 KillObjectPacket kill = new KillObjectPacket();
183 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
184 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
185 kill.ObjectData[0].ID = this.ClientAvatar.localid;
186 foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) {
187 client.OutPacket(kill);
188 }
189 OpenSim_Main.gridServers.GridServer.LogoutSession(this.SessionID, this.AgentID, this.CircuitCode);
190 lock(OpenSim_Main.local_world.Entities) {
191 OpenSim_Main.local_world.Entities.Remove(this.AgentID);
192 }
193 //need to do other cleaning up here too
194 OpenSim_Main.sim.ClientThreads.Remove(this.userEP);
195 this.ClientThread.Abort();
196 break;
197 case PacketType.ChatFromViewer:
198 ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
199 if(Helpers.FieldToString(inchatpack.ChatData.Message)=="") break;
200
201 System.Text.Encoding _enc = System.Text.Encoding.ASCII;
202 libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
203 reply.ChatData.Audible = 1;
204 reply.ChatData.Message = inchatpack.ChatData.Message;
205 reply.ChatData.ChatType = 1;
206 reply.ChatData.SourceType = 1;
207 reply.ChatData.Position = this.ClientAvatar.position;
208 reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0");
209 reply.ChatData.OwnerID = this.AgentID;
210 reply.ChatData.SourceID = this.AgentID;
211 foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) {
212 client.OutPacket(reply);
213 }
214 break;
215 }
216 }
217
218 private void ResendUnacked()
219 {
220 int now = Environment.TickCount;
221
222 lock (NeedAck)
223 {
224 foreach (Packet packet in NeedAck.Values)
225 {
226 if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
227 {
228 ServerConsole.MainConsole.Instance.WriteLine("Resending " + packet.Type.ToString() + " packet, " +
229 (now - packet.TickCount) + "ms have passed");
230
231 packet.Header.Resent = true;
232 OutPacket(packet);
233 }
234 }
235 }
236 }
237
238 private void SendAcks()
239 {
240 lock (PendingAcks)
241 {
242 if (PendingAcks.Count > 0)
243 {
244 if (PendingAcks.Count > 250)
245 {
246 // FIXME: Handle the odd case where we have too many pending ACKs queued up
247 ServerConsole.MainConsole.Instance.WriteLine("Too many ACKs queued up!");
248 return;
249 }
250
251 ServerConsole.MainConsole.Instance.WriteLine("Sending PacketAck");
252
253
254 int i = 0;
255 PacketAckPacket acks = new PacketAckPacket();
256 acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
257
258 foreach (uint ack in PendingAcks.Values)
259 {
260 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
261 acks.Packets[i].ID = ack;
262 i++;
263 }
264
265 acks.Header.Reliable = false;
266 OutPacket(acks);
267
268 PendingAcks.Clear();
269 }
270 }
271 }
272
273 private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
274 {
275 SendAcks();
276 ResendUnacked();
277 }
278
279 public void ProcessOutPacket(Packet Pack) {
280
281 // Keep track of when this packet was sent out
282 Pack.TickCount = Environment.TickCount;
283
284 if (!Pack.Header.Resent)
285 {
286 // Set the sequence number
287 lock (SequenceLock)
288 {
289 if (Sequence >= MAX_SEQUENCE)
290 Sequence = 1;
291 else
292 Sequence++;
293 Pack.Header.Sequence = Sequence;
294 }
295
296 if (Pack.Header.Reliable) //DIRTY HACK
297 {
298 lock (NeedAck)
299 {
300 if (!NeedAck.ContainsKey(Pack.Header.Sequence))
301 {
302 NeedAck.Add(Pack.Header.Sequence, Pack);
303 }
304 else
305 {
306 // Client.Log("Attempted to add a duplicate sequence number (" +
307 // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
308 // packet.Type.ToString(), Helpers.LogLevel.Warning);
309 }
310 }
311
312 // Don't append ACKs to resent packets, in case that's what was causing the
313 // delivery to fail
314 if (!Pack.Header.Resent)
315 {
316 // Append any ACKs that need to be sent out to this packet
317 lock (PendingAcks)
318 {
319 if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
320 Pack.Type != PacketType.PacketAck &&
321 Pack.Type != PacketType.LogoutRequest)
322 {
323 Pack.Header.AckList = new uint[PendingAcks.Count];
324 int i = 0;
325
326 foreach (uint ack in PendingAcks.Values)
327 {
328 Pack.Header.AckList[i] = ack;
329 i++;
330 }
331
332 PendingAcks.Clear();
333 Pack.Header.AppendedAcks = true;
334 }
335 }
336 }
337 }
338 }
339
340 //ServerConsole.MainConsole.Instance.WriteLine("OUT: \n" + Pack.ToString());
341
342 byte[] ZeroOutBuffer = new byte[4096];
343 byte[] sendbuffer;
344 sendbuffer = Pack.ToBytes();
345
346 try {
347 if (Pack.Header.Zerocoded) {
348 int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
349 OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None,userEP);
350 } else {
351 OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None,userEP);
352 }
353 } catch (Exception) {
354 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
355 ClientThread.Abort();
356 }
357
358 }
359
360 public void InPacket(Packet NewPack) {
361 // Handle appended ACKs
362 if (NewPack.Header.AppendedAcks)
363 {
364 lock (NeedAck)
365 {
366 foreach (uint ack in NewPack.Header.AckList)
367 {
368 NeedAck.Remove(ack);
369 }
370 }
371 }
372
373 // Handle PacketAck packets
374 if (NewPack.Type == PacketType.PacketAck)
375 {
376 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
377
378 lock (NeedAck)
379 {
380 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
381 {
382 NeedAck.Remove(block.ID);
383 }
384 }
385 } else if( ( NewPack.Type == PacketType.StartPingCheck ) ) {
386 //reply to pingcheck
387 libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
388 libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
389 endPing.PingID.PingID = startPing.PingID.PingID;
390 OutPacket(endPing);
391 }
392 else
393 {
394 QueItem item = new QueItem();
395 item.Packet = NewPack;
396 item.Incoming = true;
397 this.PacketQueue.Enqueue(item);
398 }
399
400 }
401
402 public void OutPacket(Packet NewPack) {
403 QueItem item = new QueItem();
404 item.Packet = NewPack;
405 item.Incoming = false;
406 this.PacketQueue.Enqueue(item);
407 }
408
409 public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) {
410 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
411 cirpack = initialcirpack;
412 userEP = remoteEP;
413 PacketQueue = new BlockingQueue<QueItem>();
414 AckTimer = new System.Timers.Timer(500);
415 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
416 AckTimer.Start();
417
418 ClientThread = new Thread(new ThreadStart(AuthUser));
419 ClientThread.IsBackground = true;
420 ClientThread.Start();
421 }
422
423 private void ClientLoop() {
424 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
425 while(true) {
426 QueItem nextPacket = PacketQueue.Dequeue();
427 if(nextPacket.Incoming)
428 {
429 //is a incoming packet
430 ProcessInPacket(nextPacket.Packet);
431 }
432 else
433 {
434 //is a out going packet
435 ProcessOutPacket(nextPacket.Packet);
436 }
437 }
438 }
439
440 private void InitNewClient() {
441 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
442 OpenSim_Main.local_world.AddViewerAgent(this);
443 world.Entity tempent=OpenSim_Main.local_world.Entities[this.AgentID];
444 this.ClientAvatar=(world.Avatar)tempent;
445 }
446
447 private void AuthUser()
448 {
449 AuthenticateResponse sessionInfo = OpenSim_Main.gridServers.GridServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
450 if(!sessionInfo.Authorised)
451 {
452 //session/circuit not authorised
453 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
454 ClientThread.Abort();
455 }
456 else
457 {
458 ServerConsole.MainConsole.Instance.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
459 //session is authorised
460 this.AgentID=cirpack.CircuitCode.ID;
461 this.SessionID=cirpack.CircuitCode.SessionID;
462 this.CircuitCode=cirpack.CircuitCode.Code;
463 InitNewClient();
464 this.ClientAvatar.firstname = sessionInfo.LoginInfo.First;
465 this.ClientAvatar.lastname = sessionInfo.LoginInfo.Last;
466 ClientLoop();
467 }
468 }
469 }
470
471}