public void AgentCompletingMove(NetworkInfo userInfo) { libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket(); mov.AgentData.SessionID = userInfo.User.SessionID; mov.AgentData.AgentID = userInfo.User.AgentID; mov.Data.RegionHandle = Globals.Instance.RegionHandle; mov.Data.Timestamp = 1169838966; mov.Data.Position = new LLVector3(100f, 100f, 22f); mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0); _server.SendPacket(mov, true, userInfo); }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> /// <param name="layer"></param> /// <param name="name"></param> private void SendLayerData(NetworkInfo userInfo, LayerDataPacket layer, string fileName) { FileInfo fInfo = new FileInfo(fileName); long numBytes = fInfo.Length; FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fStream); byte [] data1 = br.ReadBytes((int)numBytes); br.Close(); fStream.Close(); layer.LayerData.Data = data1; _server.SendPacket(layer, true, userInfo); }
private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) { if (connected) { //TODO for each user_agent_info for (int i = 0; i < this.User_agents.Count; i++) { NetworkInfo user = (NetworkInfo)this.User_agents[i]; SendAcks(user); ResendUnacked(user); } } }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> public void SendTerrainData(NetworkInfo userInfo) { lock (this._sendTerrainSync) { string data_path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"layer_data"); //send layerdata LayerDataPacket layerpack = new LayerDataPacket(); layerpack.LayerID.Type = 76; this.SendLayerData(userInfo, layerpack, Path.Combine(data_path, "layerdata0.dat")); Console.WriteLine("Sent terrain data"); //test this.SendAvatarData(userInfo); } }
/// <summary> /// /// </summary> /// <param name="UserInfo"></param> public void RequestMapLayer(NetworkInfo userInfo) { //send a layer covering the 800,800 - 1200,1200 area MapLayerReplyPacket MapReply = new MapLayerReplyPacket(); MapReply.AgentData.AgentID = userInfo.User.AgentID; MapReply.AgentData.Flags = 0; MapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1]; MapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock(); MapReply.LayerData[0].Bottom = 800; MapReply.LayerData[0].Left = 800; MapReply.LayerData[0].Top = 1200; MapReply.LayerData[0].Right = 1200; MapReply.LayerData[0].ImageID = new LLUUID("00000000-0000-0000-7007-000000000006"); _server.SendPacket(MapReply, true, userInfo); }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> /// <param name="first"></param> /// <param name="last"></param> /// <param name="baseFolder"></param> /// <param name="inventoryFolder"></param> /// <returns></returns> public virtual bool NewAgent(NetworkInfo userInfo, string first, string last, LLUUID baseFolder, LLUUID inventoryFolder) { AgentProfile agent = new AgentProfile(); agent.Avatar.FullID = userInfo.User.AgentID; agent.Avatar.NetInfo = userInfo; agent.Avatar.NetInfo.User.FirstName = first; agent.Avatar.NetInfo.User.LastName = last; agent.Avatar.Position = new LLVector3(100, 100, 22); agent.Avatar.BaseFolder = baseFolder; agent.Avatar.InventoryFolder = inventoryFolder; agent.Avatar.LocalID = 8880000 + this._localNumber; this._localNumber++; this.AgentList.Add(agent.Avatar.FullID, agent); //Create new Wearable Assets and place in Inventory //this.assetManager.CreateNewInventorySet(ref agent, userInfo); return(true); }
/// <summary> /// Resend unacknowledged packets /// </summary> private void ResendUnacked(NetworkInfo User_info) { if (connected) { int now = Environment.TickCount; lock (User_info.NeedAck) { foreach (Packet packet in User_info.NeedAck.Values) { if (now - packet.TickCount > Settings.RESEND_TIMEOUT) { // Client.Log("Resending " + packet.Type.ToString() + " packet, " + // (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info); packet.Header.Resent = true; SendPacket(packet, false, User_info); } } } } }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> /// <param name="imageID"></param> public void AddTextureRequest(NetworkInfo userInfo, LLUUID imageID) { //check to see if texture is in local cache, if not request from asset server }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> /// <param name="transferRequest"></param> public void AddAssetRequest(NetworkInfo userInfo, TransferRequestPacket transferRequest) { LLUUID RequestID = new LLUUID(transferRequest.TransferInfo.Params, 0); //check to see if asset is in local cache, if not we need to request it from asset server. }
/// <summary> /// Callback handler for incomming data /// </summary> /// <param name="result"></param> private void OnReceivedData(IAsyncResult result) { ipeSender = new IPEndPoint(IPAddress.Any, 0); epSender = (EndPoint)ipeSender; Packet packet = null; int numBytes; // If we're receiving data the sim connection is open connected = true; // Update the disconnect flag so this sim doesn't time out DisconnectCandidate = false; NetworkInfo User_info = null; lock (RecvBuffer) { // Retrieve the incoming packet try { numBytes = Connection.EndReceiveFrom(result, ref epSender); //find user_agent_info int packetEnd = numBytes - 1; packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer); //should check if login/useconnection packet first if (packet.Type == PacketType.UseCircuitCode) { //new connection //TODO check that this circuit and session is expected UseCircuitCodePacket cir_pack = (UseCircuitCodePacket)packet; NetworkInfo new_user = new NetworkInfo(); new_user.CircuitCode = cir_pack.CircuitCode.Code; new_user.User.AgentID = cir_pack.CircuitCode.ID; new_user.User.SessionID = cir_pack.CircuitCode.SessionID; new_user.endpoint = epSender; new_user.Inbox = new Queue <uint>(Settings.INBOX_SIZE); new_user.Connection = new ClientConnection(); new_user.Connection.NetInfo = new_user; new_user.Connection.Start(); //this.CallbackObject.NewUserCallback(new_user); this.User_agents.Add(new_user); } NetworkInfo temp_agent = null; IPEndPoint send_ip = (IPEndPoint)epSender; // this.callback_object.error("incoming: address is "+send_ip.Address +"port number is: "+send_ip.Port.ToString()); for (int ii = 0; ii < this.User_agents.Count; ii++) { temp_agent = (NetworkInfo)this.User_agents[ii]; IPEndPoint ag_ip = (IPEndPoint)temp_agent.endpoint; //this.callback_object.error("searching: address is "+ag_ip.Address +"port number is: "+ag_ip.Port.ToString()); if ((ag_ip.Address.ToString() == send_ip.Address.ToString()) && (ag_ip.Port.ToString() == send_ip.Port.ToString())) { //this.callback_object.error("found user"); User_info = temp_agent; break; } } Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); } catch (SocketException) { // Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.Region.Name, // Helpers.LogLevel.Info); connected = false; //Network.DisconnectSim(this); return; } } if (User_info == null) { //error finding agent //this.CallbackObject.ErrorCallback("no user found"); return; } // Fail-safe check if (packet == null) { //this.CallbackObject.ErrorCallback("couldn't build packet"); // Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning); return; } //this.callback_object.error("past tests"); // Track the sequence number for this packet if it's marked as reliable if (packet.Header.Reliable) { if (User_info.PendingAcks.Count > Settings.MAX_PENDING_ACKS) { SendAcks(User_info); } // Check if we already received this packet if (User_info.Inbox.Contains(packet.Header.Sequence)) { //Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" + // packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") + // ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count, // Helpers.LogLevel.Info); // Send an ACK for this packet immediately //SendAck(packet.Header.Sequence); // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK lock (User_info.PendingAcks) { uint sequence = (uint)packet.Header.Sequence; if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } } // Avoid firing a callback twice for the same packet // this.callback_object.error("avoiding callback"); return; } else { lock (User_info.PendingAcks) { uint sequence = (uint)packet.Header.Sequence; if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } } } } // Add this packet to our inbox lock (User_info.Inbox) { while (User_info.Inbox.Count >= Settings.INBOX_SIZE) { User_info.Inbox.Dequeue(); } User_info.Inbox.Enqueue(packet.Header.Sequence); } // Handle appended ACKs if (packet.Header.AppendedAcks) { lock (User_info.NeedAck) { foreach (uint ack in packet.Header.AckList) { User_info.NeedAck.Remove(ack); } } } // Handle PacketAck packets if (packet.Type == PacketType.PacketAck) { PacketAckPacket ackPacket = (PacketAckPacket)packet; lock (User_info.NeedAck) { foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) { User_info.NeedAck.Remove(block.ID); } } } //if it is a ping check send return if ((packet.Type == PacketType.StartPingCheck)) { //reply to pingcheck libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)packet; libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket(); endPing.PingID.PingID = startPing.PingID.PingID; SendPacket(endPing, true, User_info); } else if (packet.Type != PacketType.PacketAck) { User_info.Connection.InQueue.Enqueue(packet); } }
public void RequestWearables(NetworkInfo userInfo) { AgentProfile Agent = this.AgentList[userInfo.User.AgentID]; AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket(); aw.AgentData.AgentID = userInfo.User.AgentID; aw.AgentData.SerialNum = 0; aw.AgentData.SessionID = userInfo.User.SessionID; aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13]; AgentWearablesUpdatePacket.WearableDataBlock awb = null; awb = new AgentWearablesUpdatePacket.WearableDataBlock(); awb.WearableType = (byte)0; awb.AssetID = Agent.Avatar.Wearables[0].AssetID; awb.ItemID = Agent.Avatar.Wearables[0].ItemID; aw.WearableData[0] = awb; awb = new AgentWearablesUpdatePacket.WearableDataBlock(); awb.WearableType =(byte)1; awb.AssetID = Agent.Avatar.Wearables[1].AssetID; awb.ItemID = Agent.Avatar.Wearables[1].ItemID; aw.WearableData[1] = awb; for(int i=2; i<13; i++) { awb = new AgentWearablesUpdatePacket.WearableDataBlock(); awb.WearableType = (byte)i; awb.AssetID = new LLUUID("00000000-0000-0000-0000-000000000000"); awb.ItemID = new LLUUID("00000000-0000-0000-0000-000000000000"); aw.WearableData[i] = awb; } _server.SendPacket(aw, true, userInfo); }
/// <summary> /// /// </summary> /// <param name="UserInfo"></param> /// <param name="Request"></param> public void RequestTeleport(NetworkInfo userInfo, TeleportLocationRequestPacket request) { if(Grid.ContainsKey(request.Info.RegionHandle)) { RegionInfo Region = Grid[request.Info.RegionHandle]; libsecondlife.Packets.TeleportStartPacket TeleportStart = new TeleportStartPacket(); TeleportStart.Info.TeleportFlags = 16; _server.SendPacket(TeleportStart, true, userInfo); libsecondlife.Packets.TeleportFinishPacket Teleport = new TeleportFinishPacket(); Teleport.Info.AgentID = userInfo.User.AgentID; Teleport.Info.RegionHandle = request.Info.RegionHandle; Teleport.Info.SimAccess = 13; Teleport.Info.SeedCapability = new byte[0]; System.Net.IPAddress oIP = System.Net.IPAddress.Parse(Region.IPAddress.Address); byte[] byteIP = oIP.GetAddressBytes(); uint ip=(uint)byteIP[3]<<24; ip+=(uint)byteIP[2]<<16; ip+=(uint)byteIP[1]<<8; ip+=(uint)byteIP[0]; Teleport.Info.SimIP = ip; Teleport.Info.SimPort = Region.IPAddress.Port; Teleport.Info.LocationID = 4; Teleport.Info.TeleportFlags = 1 << 4;; _server.SendPacket(Teleport, true, userInfo); //this._agentManager.RemoveAgent(userInfo); } }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> /// <param name="first"></param> /// <param name="last"></param> /// <param name="baseFolder"></param> /// <param name="inventoryFolder"></param> /// <returns></returns> public virtual bool NewAgent(NetworkInfo userInfo, string first, string last, LLUUID baseFolder, LLUUID inventoryFolder) { AgentProfile agent = new AgentProfile(); agent.Avatar.FullID = userInfo.User.AgentID; agent.Avatar.NetInfo = userInfo; agent.Avatar.NetInfo.User.FirstName =first; agent.Avatar.NetInfo.User.LastName = last; agent.Avatar.Position = new LLVector3(100, 100, 22); agent.Avatar.BaseFolder = baseFolder; agent.Avatar.InventoryFolder = inventoryFolder; agent.Avatar.LocalID = 8880000 + this._localNumber; this._localNumber++; this.AgentList.Add(agent.Avatar.FullID, agent); //Create new Wearable Assets and place in Inventory //this.assetManager.CreateNewInventorySet(ref agent, userInfo); return(true); }
/// <summary> /// /// </summary> /// <param name="UserInfo"></param> /// <param name="MinX"></param> /// <param name="MinY"></param> /// <param name="MaxX"></param> /// <param name="MaxY"></param> public void RequestMapBlock(NetworkInfo userInfo, int minX, int minY,int maxX,int maxY) { foreach (KeyValuePair<ulong, RegionInfo> regionPair in this.Grid) { //check Region is inside the requested area RegionInfo Region = regionPair.Value; if(((Region.X > minX) && (Region.X < maxX)) && ((Region.Y > minY) && (Region.Y < maxY))) { MapBlockReplyPacket MapReply = new MapBlockReplyPacket(); MapReply.AgentData.AgentID = userInfo.User.AgentID; MapReply.AgentData.Flags = 0; MapReply.Data = new MapBlockReplyPacket.DataBlock[1]; MapReply.Data[0] = new MapBlockReplyPacket.DataBlock(); MapReply.Data[0].MapImageID = Region.ImageID; MapReply.Data[0].X = Region.X; MapReply.Data[0].Y = Region.Y; MapReply.Data[0].WaterHeight = Region.WaterHeight; MapReply.Data[0].Name = _enc.GetBytes( Region.Name); MapReply.Data[0].RegionFlags = 72458694; MapReply.Data[0].Access = 13; MapReply.Data[0].Agents = 1; _server.SendPacket(MapReply, true, userInfo); } } }
/// <summary> /// /// </summary> /// <param name="UserInfo"></param> public void RemoveAgent(NetworkInfo userInfo) { this.AgentList.Remove(userInfo.User.AgentID); //tell other clients to delete this avatar }
//test only private void SendAvatarData(NetworkInfo userInfo) { ObjectUpdatePacket objupdate = new ObjectUpdatePacket(); objupdate.RegionData.RegionHandle = Globals.Instance.RegionHandle; objupdate.RegionData.TimeDilation = 64096; objupdate.ObjectData = new libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock[1]; objupdate.ObjectData[0] = _avatarTemplate; //give this avatar object a local id and assign the user a name objupdate.ObjectData[0].ID = 8880000;// + this._localNumber; userInfo.User.AvatarLocalID = objupdate.ObjectData[0].ID; //User_info.name="Test"+this.local_numer+" User"; //this.GetAgent(userInfo.UserAgentID).Started = true; objupdate.ObjectData[0].FullID = userInfo.User.AgentID; objupdate.ObjectData[0].NameValue = _enc.GetBytes("FirstName STRING RW SV " + userInfo.User.FirstName + "\nLastName STRING RW SV " + userInfo.User.LastName + " \0"); //userInfo.User.FullName = "FirstName STRING RW SV " + userInfo.first_name + "\nLastName STRING RW SV " + userInfo.last_name + " \0"; libsecondlife.LLVector3 pos2 = new LLVector3(100f, 100.0f, 22.0f); byte[] pb = pos2.GetBytes(); Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); //this._localNumber++; _server.SendPacket(objupdate, true, userInfo); }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> public void SendTerrainData(NetworkInfo userInfo) { lock(this._sendTerrainSync) { string data_path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory ,@"layer_data" ); //send layerdata LayerDataPacket layerpack = new LayerDataPacket(); layerpack.LayerID.Type = 76; this.SendLayerData(userInfo, layerpack, Path.Combine(data_path,"layerdata0.dat")); Console.WriteLine("Sent terrain data"); //test this.SendAvatarData(userInfo); } }
/// <summary> /// Sends a packet /// </summary> /// <param name="packet">Packet to be sent</param> /// <param name="incrementSequence">Increment sequence number?</param> public void SendPacket(Packet packet, bool incrementSequence, NetworkInfo User_info) { lock(this._sendPacketSync) { byte[] buffer; int bytes; if (!connected && packet.Type != PacketType.UseCircuitCode) { // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", // Helpers.LogLevel.Info); return; } if (packet.Header.AckList.Length > 0) { // Scrub any appended ACKs since all of the ACK handling is done here packet.Header.AckList = new uint[0]; } packet.Header.AppendedAcks = false; // Keep track of when this packet was sent out packet.TickCount = Environment.TickCount; if (incrementSequence) { // Set the sequence number lock (SequenceLock) { if (Sequence > Settings.MAX_SEQUENCE) Sequence = 1; else Sequence++; packet.Header.Sequence = Sequence; } if (packet.Header.Reliable) { lock (User_info.NeedAck) { if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) { User_info.NeedAck.Add(packet.Header.Sequence, packet); } else { // Client.Log("Attempted to add a duplicate sequence number (" + // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + // packet.Type.ToString(), Helpers.LogLevel.Warning); } } // Don't append ACKs to resent packets, in case that's what was causing the // delivery to fail if (!packet.Header.Resent) { // Append any ACKs that need to be sent out to this packet lock (User_info.PendingAcks) { if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && packet.Type != PacketType.PacketAck && packet.Type != PacketType.LogoutRequest) { packet.Header.AckList = new uint[User_info.PendingAcks.Count]; int i = 0; foreach (uint ack in User_info.PendingAcks.Values) { packet.Header.AckList[i] = ack; i++; } User_info.PendingAcks.Clear(); packet.Header.AppendedAcks = true; } } } } } // Serialize the packet buffer = packet.ToBytes(); bytes = buffer.Length; try { // Zerocode if needed if (packet.Header.Zerocoded) { lock (ZeroOutBuffer) { bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint); } } else { Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint); } } catch (SocketException) { //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", // Helpers.LogLevel.Warning); Disconnect(); } } }
/// <summary> /// Callback handler for incomming data /// </summary> /// <param name="result"></param> private void OnReceivedData(IAsyncResult result) { ipeSender = new IPEndPoint(IPAddress.Any, 0); epSender = (EndPoint)ipeSender; Packet packet = null; int numBytes; // If we're receiving data the sim connection is open connected = true; // Update the disconnect flag so this sim doesn't time out DisconnectCandidate = false; NetworkInfo User_info=null; lock (RecvBuffer) { // Retrieve the incoming packet try { numBytes = Connection.EndReceiveFrom(result, ref epSender); //find user_agent_info int packetEnd = numBytes - 1; packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer); //should check if login/useconnection packet first if (packet.Type == PacketType.UseCircuitCode) { //new connection //TODO check that this circuit and session is expected UseCircuitCodePacket cir_pack=(UseCircuitCodePacket)packet; NetworkInfo new_user=new NetworkInfo(); new_user.CircuitCode=cir_pack.CircuitCode.Code; new_user.User.AgentID=cir_pack.CircuitCode.ID; new_user.User.SessionID=cir_pack.CircuitCode.SessionID; new_user.endpoint=epSender; new_user.Inbox = new Queue<uint>(Settings.INBOX_SIZE); new_user.Connection = new ClientConnection(); new_user.Connection.NetInfo = new_user; new_user.Connection.Start(); //this.CallbackObject.NewUserCallback(new_user); this.User_agents.Add(new_user); } NetworkInfo temp_agent=null; IPEndPoint send_ip=(IPEndPoint)epSender; // this.callback_object.error("incoming: address is "+send_ip.Address +"port number is: "+send_ip.Port.ToString()); for(int ii=0; ii<this.User_agents.Count ; ii++) { temp_agent=(NetworkInfo)this.User_agents[ii]; IPEndPoint ag_ip=(IPEndPoint)temp_agent.endpoint; //this.callback_object.error("searching: address is "+ag_ip.Address +"port number is: "+ag_ip.Port.ToString()); if((ag_ip.Address.ToString()==send_ip.Address.ToString()) && (ag_ip.Port.ToString()==send_ip.Port.ToString())) { //this.callback_object.error("found user"); User_info=temp_agent; break; } } Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); } catch (SocketException) { // Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.Region.Name, // Helpers.LogLevel.Info); connected = false; //Network.DisconnectSim(this); return; } } if(User_info==null) { //error finding agent //this.CallbackObject.ErrorCallback("no user found"); return; } // Fail-safe check if (packet == null) { //this.CallbackObject.ErrorCallback("couldn't build packet"); // Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning); return; } //this.callback_object.error("past tests"); // Track the sequence number for this packet if it's marked as reliable if (packet.Header.Reliable) { if (User_info.PendingAcks.Count > Settings.MAX_PENDING_ACKS) { SendAcks(User_info); } // Check if we already received this packet if (User_info.Inbox.Contains(packet.Header.Sequence)) { //Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" + // packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") + // ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count, // Helpers.LogLevel.Info); // Send an ACK for this packet immediately //SendAck(packet.Header.Sequence); // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK lock (User_info.PendingAcks) { uint sequence = (uint)packet.Header.Sequence; if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } } // Avoid firing a callback twice for the same packet // this.callback_object.error("avoiding callback"); return; } else { lock (User_info.PendingAcks) { uint sequence = (uint)packet.Header.Sequence; if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } } } } // Add this packet to our inbox lock (User_info.Inbox) { while (User_info.Inbox.Count >= Settings.INBOX_SIZE) { User_info.Inbox.Dequeue(); } User_info.Inbox.Enqueue(packet.Header.Sequence); } // Handle appended ACKs if (packet.Header.AppendedAcks) { lock (User_info.NeedAck) { foreach (uint ack in packet.Header.AckList) { User_info.NeedAck.Remove(ack); } } } // Handle PacketAck packets if (packet.Type == PacketType.PacketAck) { PacketAckPacket ackPacket = (PacketAckPacket)packet; lock (User_info.NeedAck) { foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) { User_info.NeedAck.Remove(block.ID); } } } //if it is a ping check send return if( ( packet.Type == PacketType.StartPingCheck ) ) { //reply to pingcheck libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)packet; libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket(); endPing.PingID.PingID = startPing.PingID.PingID; SendPacket(endPing, true, User_info ); } else if(packet.Type != PacketType.PacketAck) { User_info.Connection.InQueue.Enqueue(packet); } }
/// <summary> /// Resend unacknowledged packets /// </summary> private void ResendUnacked(NetworkInfo User_info) { if (connected) { int now = Environment.TickCount; lock (User_info.NeedAck) { foreach (Packet packet in User_info.NeedAck.Values) { if (now - packet.TickCount > Settings.RESEND_TIMEOUT) { // Client.Log("Resending " + packet.Type.ToString() + " packet, " + // (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info); packet.Header.Resent = true; SendPacket(packet, false,User_info); } } } } }
/// <summary> /// Sends out pending acknowledgements /// </summary> private void SendAcks(NetworkInfo User_info) { lock (User_info.PendingAcks) { if (connected && User_info.PendingAcks.Count > 0) { if (User_info.PendingAcks.Count > 250) { // FIXME: Handle the odd case where we have too many pending ACKs queued up //Client.Log("Too many ACKs queued up!", Helpers.LogLevel.Error); return; } int i = 0; PacketAckPacket acks = new PacketAckPacket(); acks.Packets = new PacketAckPacket.PacketsBlock[User_info.PendingAcks.Count]; foreach (uint ack in User_info.PendingAcks.Values) { acks.Packets[i] = new PacketAckPacket.PacketsBlock(); acks.Packets[i].ID = ack; i++; } acks.Header.Reliable = false; SendPacket(acks, true,User_info); User_info.PendingAcks.Clear(); } } }
/// <summary> /// /// </summary> /// <param name="userInfo"></param> public void AgentJoin(NetworkInfo userInfo) { //inform client of join comlete libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket(); mov.AgentData.SessionID = userInfo.User.SessionID; mov.AgentData.AgentID = userInfo.User.AgentID; mov.Data.RegionHandle = Globals.Instance.RegionHandle; mov.Data.Timestamp = 1169838966; mov.Data.Position = new LLVector3(100f, 100f, 22f); mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0); _server.SendPacket(mov, true, userInfo); }
/// <summary> /// Sends a packet /// </summary> /// <param name="packet">Packet to be sent</param> /// <param name="incrementSequence">Increment sequence number?</param> public void SendPacket(Packet packet, bool incrementSequence, NetworkInfo User_info) { lock (this._sendPacketSync) { byte[] buffer; int bytes; if (!connected && packet.Type != PacketType.UseCircuitCode) { // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", // Helpers.LogLevel.Info); return; } if (packet.Header.AckList.Length > 0) { // Scrub any appended ACKs since all of the ACK handling is done here packet.Header.AckList = new uint[0]; } packet.Header.AppendedAcks = false; // Keep track of when this packet was sent out packet.TickCount = Environment.TickCount; if (incrementSequence) { // Set the sequence number lock (SequenceLock) { if (Sequence > Settings.MAX_SEQUENCE) { Sequence = 1; } else { Sequence++; } packet.Header.Sequence = Sequence; } if (packet.Header.Reliable) { lock (User_info.NeedAck) { if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) { User_info.NeedAck.Add(packet.Header.Sequence, packet); } else { // Client.Log("Attempted to add a duplicate sequence number (" + // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + // packet.Type.ToString(), Helpers.LogLevel.Warning); } } // Don't append ACKs to resent packets, in case that's what was causing the // delivery to fail if (!packet.Header.Resent) { // Append any ACKs that need to be sent out to this packet lock (User_info.PendingAcks) { if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && packet.Type != PacketType.PacketAck && packet.Type != PacketType.LogoutRequest) { packet.Header.AckList = new uint[User_info.PendingAcks.Count]; int i = 0; foreach (uint ack in User_info.PendingAcks.Values) { packet.Header.AckList[i] = ack; i++; } User_info.PendingAcks.Clear(); packet.Header.AppendedAcks = true; } } } } } // Serialize the packet buffer = packet.ToBytes(); bytes = buffer.Length; try { // Zerocode if needed if (packet.Header.Zerocoded) { lock (ZeroOutBuffer) { bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None, User_info.endpoint); } } else { Connection.SendTo(buffer, bytes, SocketFlags.None, User_info.endpoint); } } catch (SocketException) { //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", // Helpers.LogLevel.Warning); Disconnect(); } } }