public static OSD GetLLSD(Packet packet) { OSDMap body = new OSDMap(); Type type = packet.GetType(); foreach (FieldInfo field in type.GetFields()) { if (field.IsPublic) { Type blockType = field.FieldType; if (blockType.IsArray) { object blockArray = field.GetValue(packet); Array array = (Array)blockArray; OSDArray blockList = new OSDArray(array.Length); IEnumerator ie = array.GetEnumerator(); while (ie.MoveNext()) { object block = ie.Current; blockList.Add(BuildLLSDBlock(block)); } body[field.Name] = blockList; } else { object block = field.GetValue(packet); body[field.Name] = BuildLLSDBlock(block); } } } return body; }
/// <summary> /// Sends a packet directly to the simulator without queuing /// </summary> /// <param name="packet">Packet to be sent</param> /// <param name="setSequence">True to set the sequence number, false to /// leave it as is</param> public void SendPacketUnqueued(Packet packet, bool setSequence) { byte[] buffer; int bytes; // Set sequence implies that this is not a resent packet if (setSequence) { // Reset to zero if we've hit the upper sequence number limit Interlocked.CompareExchange(ref Sequence, 0, Settings.MAX_SEQUENCE); // Increment and fetch the current sequence number packet.Header.Sequence = (uint)Interlocked.Increment(ref Sequence); if (packet.Header.Reliable) { // Wrap this packet in a struct to track timeouts and resends NetworkManager.OutgoingPacket outgoing = new NetworkManager.OutgoingPacket(this, packet, true); // Keep track of when this packet was first sent out (right now) outgoing.TickCount = Environment.TickCount; // Add this packet to the list of ACK responses we are waiting on from the server lock (NeedAck) { NeedAck[packet.Header.Sequence] = outgoing; } if (packet.Header.Resent) { // This packet has already been sent out once, strip any appended ACKs // off it and reinsert them into the outgoing ACK queue under the // assumption that this packet will continually be rejected from the // server or that the appended ACKs are possibly making the delivery fail if (packet.Header.AckList.Length > 0) { Logger.DebugLog(String.Format("Purging ACKs from packet #{0} ({1}) which will be resent.", packet.Header.Sequence, packet.GetType())); lock (PendingAcks) { foreach (uint sequence in packet.Header.AckList) { if (!PendingAcks.ContainsKey(sequence)) PendingAcks[sequence] = sequence; } } packet.Header.AppendedAcks = false; packet.Header.AckList = new uint[0]; } // Update the sent time for this packet SetResentTime(packet.Header.Sequence); } else { // This packet is not a resend, check if the conditions are favorable // to ACK appending if (packet.Type != PacketType.PacketAck && packet.Type != PacketType.LogoutRequest) { lock (PendingAcks) { if (PendingAcks.Count > 0 && PendingAcks.Count < Client.Settings.MAX_APPENDED_ACKS) { // Append all of the queued up outgoing ACKs to this packet packet.Header.AckList = new uint[PendingAcks.Count]; for (int i = 0; i < PendingAcks.Count; i++) packet.Header.AckList[i] = PendingAcks.Values[i]; PendingAcks.Clear(); packet.Header.AppendedAcks = true; } } } } } else if (packet.Header.AckList.Length > 0) { // Sanity check for ACKS appended on an unreliable packet, this is bad form Logger.Log("Sending appended ACKs on an unreliable packet", Helpers.LogLevel.Warning); } } // Serialize the packet buffer = packet.ToBytes(); bytes = buffer.Length; Stats.SentBytes += (ulong)bytes; ++Stats.SentPackets; UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint); // Zerocode if needed if (packet.Header.Zerocoded) bytes = Helpers.ZeroEncode(buffer, bytes, buf.Data); else Buffer.BlockCopy(buffer, 0, buf.Data, 0, bytes); buf.DataLength = bytes; AsyncBeginSend(buf); }
/// <summary> /// Creates a formatted string containing the values of a Packet /// </summary> /// <param name="packet">The Packet</param> /// <returns>A formatted string of values of the nested items in the Packet object</returns> public static string PacketToString(Packet packet) { StringBuilder result = new StringBuilder(); result.AppendFormat("Packet Type: {0} http://lib.openmetaverse.co/wiki/{0} http://wiki.secondlife.com/wiki/{0}" + Environment.NewLine, packet.Type); result.AppendLine("[Packet Header]"); // payload result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence); result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header)); result.AppendLine(); result.AppendLine("[Packet Payload]"); FieldInfo[] fields = packet.GetType().GetFields(); for (int i = 0; i < fields.Length; i++) { // we're not interested in any of these here if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks") continue; if (fields[i].FieldType.IsArray) { result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); RecursePacketArray(fields[i], packet, ref result); } else { result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); RecursePacketField(fields[i], packet, ref result); } } return result.ToString(); }
/// <summary> /// Parse a packet into human readable formatted key/value pairs /// </summary> /// <param name="packet">the Packet to parse</param> /// <returns>A string containing the packet block name, and key/value pairs of the data fields</returns> public static string PacketToString(Packet packet) { StringBuilder result = new StringBuilder(); foreach(FieldInfo packetField in packet.GetType().GetFields()) { object packetDataObject = packetField.GetValue(packet); result.AppendFormat("-- {0} --" + System.Environment.NewLine, packetField.Name); foreach(FieldInfo packetValueField in packetField.GetValue(packet).GetType().GetFields()) { result.AppendFormat("{0}: {1}" + System.Environment.NewLine, packetValueField.Name, packetValueField.GetValue(packetDataObject)); } // handle blocks that are arrays if (packetDataObject.GetType().IsArray) { foreach (object nestedArrayRecord in packetDataObject as Array) { foreach (FieldInfo packetArrayField in nestedArrayRecord.GetType().GetFields()) { result.AppendFormat("{0} {1}" + System.Environment.NewLine, packetArrayField.Name, packetArrayField.GetValue(nestedArrayRecord)); } } } else { // handle non array data blocks foreach (PropertyInfo packetPropertyField in packetField.GetValue(packet).GetType().GetProperties()) { // Handle fields named "Data" specifically, this is generally binary data, we'll display it as hex values if (packetPropertyField.PropertyType.Equals(typeof(System.Byte[])) && packetPropertyField.Name.Equals("Data")) { result.AppendFormat("{0}: {1}" + System.Environment.NewLine, packetPropertyField.Name, Utils.BytesToHexString((byte[])packetPropertyField.GetValue(packetDataObject, null), packetPropertyField.Name)); } // decode bytes into strings else if (packetPropertyField.PropertyType.Equals(typeof(System.Byte[]))) { result.AppendFormat("{0}: {1}" + System.Environment.NewLine, packetPropertyField.Name, Utils.BytesToString((byte[])packetPropertyField.GetValue(packetDataObject, null))); } else { result.AppendFormat("{0}: {1}" + System.Environment.NewLine, packetPropertyField.Name, packetPropertyField.GetValue(packetDataObject, null)); } } } } return result.ToString(); }
public void SendPacket(Packet packet, bool setSequence) { byte[] buffer; int bytes; // Keep track of when this packet was sent out packet.TickCount = Environment.TickCount; if (setSequence) { // Reset to zero if we've hit the upper sequence number limit Interlocked.CompareExchange(ref currentSequence, 0, 0xFFFFFF); // Increment and fetch the current sequence number uint sequence = (uint)Interlocked.Increment(ref currentSequence); packet.Header.Sequence = sequence; if (packet.Header.Reliable) { // Add this packet to the list of ACK responses we are waiting on from the client lock (needAcks) needAcks[sequence] = packet; if (packet.Header.Resent) { // This packet has already been sent out once, strip any appended ACKs // off it and reinsert them into the outgoing ACK queue under the // assumption that this packet will continually be rejected from the // client or that the appended ACKs are possibly making the delivery fail if (packet.Header.AckList.Length > 0) { Logger.DebugLog(String.Format("Purging ACKs from packet #{0} ({1}) which will be resent.", packet.Header.Sequence, packet.GetType())); lock (pendingAcks) { foreach (uint ack in packet.Header.AckList) { if (!pendingAcks.ContainsKey(ack)) pendingAcks[ack] = ack; } } packet.Header.AppendedAcks = false; packet.Header.AckList = new uint[0]; } } else { // This packet is not a resend, check if the conditions are favorable // to ACK appending if (packet.Type != PacketType.PacketAck) { lock (pendingAcks) { if (pendingAcks.Count > 0 && pendingAcks.Count < 10) { // Append all of the queued up outgoing ACKs to this packet packet.Header.AckList = new uint[pendingAcks.Count]; for (int i = 0; i < pendingAcks.Count; i++) packet.Header.AckList[i] = pendingAcks.Values[i]; pendingAcks.Clear(); packet.Header.AppendedAcks = true; } } } } } else if (packet.Header.AckList.Length > 0) { // Sanity check for ACKS appended on an unreliable packet, this is bad form Logger.Log("Sending appended ACKs on an unreliable packet", Helpers.LogLevel.Warning); } } // Serialize the packet buffer = packet.ToBytes(); bytes = buffer.Length; //Stats.SentBytes += (ulong)bytes; //++Stats.SentPackets; UDPPacketBuffer buf; // Zerocode if needed if (packet.Header.Zerocoded) { buf = new UDPPacketBuffer(address, true, false); bytes = Helpers.ZeroEncode(buffer, bytes, buf.Data); buf.DataLength = bytes; } else { buf = new UDPPacketBuffer(address, false, false); buf.Data = buffer; buf.DataLength = bytes; } udpServer.AsyncBeginSend(buf); }