aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/OpenSimClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/OpenSimClient.cs')
-rw-r--r--src/OpenSimClient.cs510
1 files changed, 0 insertions, 510 deletions
diff --git a/src/OpenSimClient.cs b/src/OpenSimClient.cs
deleted file mode 100644
index 497df00..0000000
--- a/src/OpenSimClient.cs
+++ /dev/null
@@ -1,510 +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;
37
38namespace OpenSim
39{
40 /// <summary>
41 /// Handles new client connections
42 /// Constructor takes a single Packet and authenticates everything
43 /// </summary>
44 public class OpenSimClient
45 {
46
47 public LLUUID AgentID;
48 public LLUUID SessionID;
49 public uint CircuitCode;
50 public world.Avatar ClientAvatar;
51 private UseCircuitCodePacket cirpack;
52 private Thread ClientThread;
53 public EndPoint userEP;
54 private BlockingQueue<QueItem> PacketQueue;
55 private BlockingQueue<TransferRequestPacket> AssetRequests;
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 //private Queue<uint> Inbox;
65
66 public void ack_pack(Packet Pack)
67 {
68 //libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
69 //ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
70 //ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
71 //ack_it.Packets[0].ID = Pack.Header.ID;
72 //ack_it.Header.Reliable = false;
73
74 //OutPacket(ack_it);
75
76 if (Pack.Header.Reliable)
77 {
78 lock (PendingAcks)
79 {
80 uint sequence = (uint)Pack.Header.Sequence;
81 if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
82 }
83 }
84 }
85
86 public void AssetLoader()
87 {
88 if (OpenSim_Main.cfg.sandbox == false)
89 {
90 WebResponse AssetResponse;
91 byte[] idata;
92
93 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread");
94 TransferRequestPacket reqPacket = AssetRequests.Dequeue();
95 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it");
96 LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0);
97
98 try
99 {
100 WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data");
101 AssetResponse = AssetLoad.GetResponse();
102 idata = new byte[(int)AssetResponse.ContentLength];
103 BinaryReader br = new BinaryReader(AssetResponse.GetResponseStream());
104 idata = br.ReadBytes((int)AssetResponse.ContentLength);
105 br.Close();
106 }
107 catch (Exception e)
108 {
109 Console.WriteLine(e.ToString());
110 return;
111 }
112
113 TransferInfoPacket Transfer = new TransferInfoPacket();
114 Transfer.TransferInfo.ChannelType = 2;
115 Transfer.TransferInfo.Status = 0;
116 Transfer.TransferInfo.TargetType = 0;
117 Transfer.TransferInfo.Params = reqPacket.TransferInfo.Params;
118 Transfer.TransferInfo.Size = (int)AssetResponse.ContentLength;
119 Transfer.TransferInfo.TransferID = reqPacket.TransferInfo.TransferID;
120
121 OutPacket(Transfer);
122
123 TransferPacketPacket TransferPacket = new TransferPacketPacket();
124 TransferPacket.TransferData.Packet = 0;
125 TransferPacket.TransferData.ChannelType = 2;
126 TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID;
127
128 if (AssetResponse.ContentLength > 1000)
129 {
130 byte[] chunk = new byte[1000];
131 Array.Copy(idata, chunk, 1000);
132 TransferPacket.TransferData.Data = chunk;
133 TransferPacket.TransferData.Status = 0;
134 OutPacket(TransferPacket);
135
136 TransferPacket = new TransferPacketPacket();
137 TransferPacket.TransferData.Packet = 1;
138 TransferPacket.TransferData.ChannelType = 2;
139 TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID;
140 byte[] chunk1 = new byte[(idata.Length - 1000)];
141 Array.Copy(idata, 1000, chunk1, 0, chunk1.Length);
142 TransferPacket.TransferData.Data = chunk1;
143 TransferPacket.TransferData.Status = 1;
144 OutPacket(TransferPacket);
145 }
146 else
147 {
148 TransferPacket.TransferData.Status = 1;
149 TransferPacket.TransferData.Data = idata;
150 OutPacket(TransferPacket);
151 }
152 AssetResponse.Close();
153 }
154 }
155
156 public void Logout()
157 {
158 // TODO - kill any AssetLoaders
159 ClientThread.Abort();
160 }
161
162 public void ProcessInPacket(Packet Pack)
163 {
164 ack_pack(Pack);
165 switch (Pack.Type)
166 {
167 case PacketType.CompleteAgentMovement:
168 ClientAvatar.CompleteMovement(OpenSim_Main.local_world);
169 ClientAvatar.SendInitialPosition();
170 break;
171 case PacketType.RegionHandshakeReply:
172 OpenSim_Main.local_world.SendLayerData(this);
173 break;
174 case PacketType.AgentWearablesRequest:
175 ClientAvatar.SendInitialAppearance();
176 break;
177 case PacketType.TransferRequest:
178 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
179 // We put transfer requests into a big queue and then spawn a thread for each new one
180 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
181 AssetRequests.Enqueue(transfer);
182 Thread AssetLoaderThread = new Thread(new ThreadStart(AssetLoader));
183 AssetLoaderThread.Start();
184 break;
185 case PacketType.LogoutRequest:
186 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
187 lock (OpenSim_Main.local_world.Entities)
188 {
189 OpenSim_Main.local_world.Entities.Remove(this.AgentID);
190 }
191
192 if (OpenSim_Main.cfg.sandbox == false)
193 {
194 WebRequest DeleteSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + this.AgentID.ToString() + this.CircuitCode.ToString() + "/delete");
195 WebResponse GridResponse = DeleteSession.GetResponse();
196 StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
197 String grTest = sr.ReadLine();
198 sr.Close();
199 GridResponse.Close();
200 OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest);
201 }
202 this.ClientThread.Abort();
203 break;
204 case PacketType.AgentUpdate:
205 ClientAvatar.HandleAgentUpdate((AgentUpdatePacket)Pack);
206 break;
207 case PacketType.ChatFromViewer:
208 ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
209 if (Helpers.FieldToString(inchatpack.ChatData.Message) == "") break;
210
211 System.Text.Encoding _enc = System.Text.Encoding.ASCII;
212 libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
213 reply.ChatData.Audible = 1;
214 reply.ChatData.Message = inchatpack.ChatData.Message;
215 reply.ChatData.ChatType = 1;
216 reply.ChatData.SourceType = 1;
217 reply.ChatData.Position = this.ClientAvatar.position;
218 reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0");
219 reply.ChatData.OwnerID = this.AgentID;
220 reply.ChatData.SourceID = this.AgentID;
221
222
223
224 foreach (OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values)
225 {
226 client.OutPacket(reply);
227 }
228 break;
229 }
230 }
231
232 private void ResendUnacked()
233 {
234 int now = Environment.TickCount;
235
236 lock (NeedAck)
237 {
238 foreach (Packet packet in NeedAck.Values)
239 {
240 if (now - packet.TickCount > RESEND_TIMEOUT)
241 {
242
243 packet.Header.Resent = true;
244 OutPacket(packet);
245 }
246 }
247 }
248 }
249
250 private void SendAcks()
251 {
252 lock (PendingAcks)
253 {
254 if (PendingAcks.Count > 0)
255 {
256 if (PendingAcks.Count > 250)
257 {
258 return;
259 }
260
261
262
263 int i = 0;
264 PacketAckPacket acks = new PacketAckPacket();
265 acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
266
267 foreach (uint ack in PendingAcks.Values)
268 {
269 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
270 acks.Packets[i].ID = ack;
271 i++;
272 }
273
274 acks.Header.Reliable = false;
275 OutPacket(acks);
276
277 PendingAcks.Clear();
278 }
279 }
280 }
281
282 private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
283 {
284 SendAcks();
285 ResendUnacked();
286 }
287
288 public void ProcessOutPacket(Packet Pack)
289 {
290
291 // Keep track of when this packet was sent out
292 Pack.TickCount = Environment.TickCount;
293
294 if (!Pack.Header.Resent)
295 {
296 // Set the sequence number
297 lock (SequenceLock)
298 {
299 if (Sequence >= MAX_SEQUENCE)
300 Sequence = 1;
301 else
302 Sequence++;
303 Pack.Header.Sequence = Sequence;
304 }
305
306 if (Pack.Header.Reliable) //DIRTY HACK
307 {
308 lock (NeedAck)
309 {
310 if (!NeedAck.ContainsKey(Pack.Header.Sequence))
311 {
312 NeedAck.Add(Pack.Header.Sequence, Pack);
313 }
314 else
315 {
316 // Client.Log("Attempted to add a duplicate sequence number (" +
317 // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
318 // packet.Type.ToString(), Helpers.LogLevel.Warning);
319 }
320 }
321
322 // Don't append ACKs to resent packets, in case that's what was causing the
323 // delivery to fail
324 if (!Pack.Header.Resent)
325 {
326 // Append any ACKs that need to be sent out to this packet
327 lock (PendingAcks)
328 {
329 if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
330 Pack.Type != PacketType.PacketAck &&
331 Pack.Type != PacketType.LogoutRequest)
332 {
333 Pack.Header.AckList = new uint[PendingAcks.Count];
334 int i = 0;
335
336 foreach (uint ack in PendingAcks.Values)
337 {
338 Pack.Header.AckList[i] = ack;
339 i++;
340 }
341
342 PendingAcks.Clear();
343 Pack.Header.AppendedAcks = true;
344 }
345 }
346 }
347 }
348 }
349
350
351 byte[] ZeroOutBuffer = new byte[4096];
352 byte[] sendbuffer;
353 sendbuffer = Pack.ToBytes();
354
355 try
356 {
357 if (Pack.Header.Zerocoded)
358 {
359 int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
360 OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None, userEP);
361 }
362 else
363 {
364 OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None, userEP);
365 }
366 }
367 catch (Exception)
368 {
369 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
370 ClientThread.Abort();
371 }
372
373 }
374
375 public void InPacket(Packet NewPack)
376 {
377 // Handle appended ACKs
378 if (NewPack.Header.AppendedAcks)
379 {
380 lock (NeedAck)
381 {
382 foreach (uint ack in NewPack.Header.AckList)
383 {
384 OpenSim_Main.localcons.WriteLine("Got appended ack: " + ack);
385 NeedAck.Remove(ack);
386 }
387 }
388 }
389
390 // Handle PacketAck packets
391 if (NewPack.Type == PacketType.PacketAck)
392 {
393 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
394
395 lock (NeedAck)
396 {
397 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
398 {
399 NeedAck.Remove(block.ID);
400 }
401 }
402 }
403 else if ((NewPack.Type == PacketType.StartPingCheck))
404 {
405 //reply to pingcheck
406 libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
407 libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
408 endPing.PingID.PingID = startPing.PingID.PingID;
409 OutPacket(endPing);
410 }
411 else
412 {
413 QueItem item = new QueItem();
414 item.Packet = NewPack;
415 item.Incoming = true;
416 this.PacketQueue.Enqueue(item);
417 }
418
419 }
420
421 public void OutPacket(Packet NewPack)
422 {
423 QueItem item = new QueItem();
424 item.Packet = NewPack;
425 item.Incoming = false;
426 this.PacketQueue.Enqueue(item);
427 }
428
429 public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack)
430 {
431 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
432 cirpack = initialcirpack;
433 userEP = remoteEP;
434 PacketQueue = new BlockingQueue<QueItem>();
435 AssetRequests = new BlockingQueue<TransferRequestPacket>();
436 AckTimer = new System.Timers.Timer(500);
437 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
438 AckTimer.Start();
439
440 ClientThread = new Thread(new ThreadStart(AuthUser));
441 ClientThread.IsBackground = true;
442 ClientThread.Start();
443 }
444
445 private void ClientLoop()
446 {
447 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
448 while (true)
449 {
450 QueItem nextPacket = PacketQueue.Dequeue();
451 if (nextPacket.Incoming)
452 {
453 //is a incoming packet
454 ProcessInPacket(nextPacket.Packet);
455 }
456 else
457 {
458 //is a out going packet
459 ProcessOutPacket(nextPacket.Packet);
460 }
461 }
462 }
463
464 private void InitNewClient()
465 {
466 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
467 OpenSim_Main.local_world.AddViewerAgent(this);
468 world.Entity tempent = OpenSim_Main.local_world.Entities[this.AgentID];
469 this.ClientAvatar = (world.Avatar)tempent;
470 }
471
472 private void AuthUser()
473 {
474 if (OpenSim_Main.cfg.sandbox == false)
475 {
476 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid");
477 WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists");
478 OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL);
479 WebResponse GridResponse = CheckSession.GetResponse();
480 StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
481 String grTest = sr.ReadLine();
482 sr.Close();
483 GridResponse.Close();
484 if (String.IsNullOrEmpty(grTest) || grTest.Equals("1"))
485 { // YAY! Valid login
486 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
487 this.AgentID = cirpack.CircuitCode.ID;
488 this.SessionID = cirpack.CircuitCode.SessionID;
489 this.CircuitCode = cirpack.CircuitCode.Code;
490 InitNewClient();
491 ClientLoop();
492 }
493 else
494 { // Invalid
495 OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
496 ClientThread.Abort();
497 }
498 }
499 else
500 {
501 this.AgentID = cirpack.CircuitCode.ID;
502 this.SessionID = cirpack.CircuitCode.SessionID;
503 this.CircuitCode = cirpack.CircuitCode.Code;
504 InitNewClient();
505 ClientLoop();
506 }
507 }
508 }
509
510}