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