/// <summary> /// Request the ping from the server (pingReceived will be triggered if it receives it) /// /// This is not a reliable call /// </summary> public override void Ping() { BMSByte payload = new BMSByte(); long ticks = DateTime.UtcNow.Ticks; payload.BlockCopy <long>(ticks, sizeof(long)); Ping pingFrame = new Ping(Time.Timestep, false, payload, Receivers.Server, MessageGroupIds.PING, false); Send(pingFrame); }
/// <summary> /// Collect all of the data from all of the packets in this sequence and return it /// </summary> /// <returns>The complete packet sequence data</returns> public BMSByte GetData() { data.Clear(); for (int i = 0; i < End; i++) { data.BlockCopy(packets[i].rawBytes, 0, packets[i].rawBytes.Length); } return(data); }
/// <summary> /// Gets the bytes for the Instance of an Object and appends them to a <c>BMSByte</c>. /// </summary> /// <param name="o">The Instance of the Object.</param> /// <param name="type">The Type of the Object.</param> /// <param name="bytes"><c>BMSByte</c> to which the bytes should be added.</param> protected virtual void GetBytes(object o, Type type, ref BMSByte bytes) { if (type == typeof(string)) { var strBytes = Encoding.UTF8.GetBytes(o == null ? string.Empty : (string)o); // TODO: Need to make custom string serialization to binary bytes.Append(BitConverter.GetBytes(strBytes.Length)); if (strBytes.Length > 0) { bytes.Append(strBytes); } } else if (type == typeof(Vector)) { Vector vec = (Vector)o; bytes.Append(BitConverter.GetBytes(vec.x)); bytes.Append(BitConverter.GetBytes(vec.y)); bytes.Append(BitConverter.GetBytes(vec.z)); } else if (type == null) //TODO: Check if this causes other issues { bytes.Append(new byte[1] { 0 }); } else if (type == typeof(sbyte)) { bytes.BlockCopy <sbyte>(o, 1); } else if (type == typeof(byte)) { bytes.BlockCopy <byte>(o, 1); } else if (type == typeof(char)) { bytes.BlockCopy <char>(o, 1); } else if (type == typeof(bool)) { bytes.Append(BitConverter.GetBytes((bool)o)); } else if (type == typeof(short)) { bytes.Append(BitConverter.GetBytes((short)o)); } else if (type == typeof(ushort)) { bytes.Append(BitConverter.GetBytes((ushort)o)); } else if (type == typeof(int)) { bytes.Append(BitConverter.GetBytes((int)o)); } else if (type == typeof(uint)) { bytes.Append(BitConverter.GetBytes((uint)o)); } else if (type == typeof(long)) { bytes.Append(BitConverter.GetBytes((long)o)); } else if (type == typeof(ulong)) { bytes.Append(BitConverter.GetBytes((ulong)o)); } else if (type == typeof(float)) { bytes.Append(BitConverter.GetBytes((float)o)); } else if (type == typeof(double)) { bytes.Append(BitConverter.GetBytes((double)o)); } else if (type.IsArray) { int rank = type.GetArrayRank(); Type targetType = type.GetElementType(); if (targetType != typeof(byte)) { throw new Exception("Currently only byte arrays can be sent as arrays"); } if (rank > 4) { throw new Exception("Currently the system only supports up to 4 dimensions in an array"); } int i, j, k, l; // Write each dimension length first int[] lengths = new int[rank]; for (i = 0; i < rank; i++) { lengths[i] = ((Array)o).GetLength(i); bytes.Append(BitConverter.GetBytes(lengths[i])); } switch (rank) { case 1: for (i = 0; i < lengths[0]; i++) { GetBytes(((Array)o).GetValue(i), targetType, ref bytes); } break; case 2: for (i = 0; i < lengths[0]; i++) { for (j = 0; j < lengths[1]; j++) { GetBytes(((Array)o).GetValue(i, j), targetType, ref bytes); } } break; case 3: for (i = 0; i < lengths[0]; i++) { for (j = 0; j < lengths[1]; j++) { for (k = 0; k < lengths[2]; k++) { GetBytes(((Array)o).GetValue(i, j, k), targetType, ref bytes); } } } break; case 4: for (i = 0; i < lengths[0]; i++) { for (j = 0; j < lengths[1]; j++) { for (k = 0; k < lengths[2]; k++) { for (l = 0; l < lengths[3]; l++) { GetBytes(((Array)o).GetValue(i, j, k, l), targetType, ref bytes); } } } } break; } } else if (type == typeof(BMSByte)) { bytes.Append(BitConverter.GetBytes(((BMSByte)o).Size)); bytes.BlockCopy(((BMSByte)o).byteArr, ((BMSByte)o).StartIndex(), ((BMSByte)o).Size); } else if (type.IsEnum) { GetBytes(o, Enum.GetUnderlyingType(type), ref bytes); } else { // TODO: Make this a more appropriate exception throw new BaseNetworkException("The type " + type.ToString() + " is not allowed to be sent over the Network (yet)"); } }
/// <summary> /// Creates the frame data using the passed in payload /// </summary> private void CreateFrame(bool useMask, ulong timestep, byte[] payload, Receivers receivers, int groupId, byte routerId, bool isStream) { // If we are to use a mask then generate a random mask if (useMask) { mask = new byte[4]; new Random().NextBytes(mask); } StreamData = new BMSByte(); TimeStep = timestep; GroupId = groupId; RouterId = routerId; Receivers = receivers; UniqueId = UniqueMessageIdCounter++; // Generate the frame identity byte[] frame = new byte[10]; // The first byte of the data is always the control byte, which dictates the message type frame[0] = ControlByte; int length = payload.Length; if (isStream) { length += 21; // Group id (4), receivers (1), time step (8), unique id (8) } else { length += 16; // time step (8), unique id (8) } if (frame[0] == Binary.CONTROL_BYTE) { length += 1; } // Determine the length of the payload int dataStartIndex = 0; if (length <= 125) { frame[1] = (byte)(useMask ? length | 128 : length); dataStartIndex = 2; } else if (length >= 126 && length <= 65535) { dataStartIndex = 4; frame[1] = (byte)(useMask ? 254 : 126); } else { dataStartIndex = 10; frame[1] = (byte)(useMask ? 255 : 127); } // If the payload is greater than a byte (255) then set the order of the bytes for the length if (dataStartIndex > 2) { int i = 0, j = 2, largestBitIndex = (dataStartIndex - 3) * 8; // Little endian / Big endian reversal based on mask //if (mask.Length == 0) //{ for (i = largestBitIndex; i >= 0; i -= 8) { frame[j++] = (byte)((((long)length) >> i) & 255); } //} else //{ // for (i = 0; i <= largestBitIndex; i += 8) // frame[j++] = (byte)((payload.Length >> i) & 255); //} } // Prepare the stream data with the size so that it doesn't have to keep resizing StreamData.SetSize(dataStartIndex + mask.Length + length); StreamData.Clear(); // Add the frame bytes StreamData.BlockCopy(frame, 0, dataStartIndex); // Add the mask bytes StreamData.BlockCopy(mask, 0, mask.Length); // Setup the int that tracks where the payload begins payloadStart = dataStartIndex + mask.Length; // If we are on a stream then use groupId if (isStream) { StreamData.BlockCopy(BitConverter.GetBytes(groupId), 0, sizeof(int)); payloadStart += sizeof(int); } // Copy the routerId if this is a binary frame if (frame[0] == Binary.CONTROL_BYTE) { StreamData.BlockCopy(new byte[1] { routerId }, 0, sizeof(byte)); payloadStart += 1; } // Add the initial payload bytes StreamData.BlockCopy(payload, 0, payload.Length); if (isStream) { StreamData.BlockCopy(new byte[1] { (byte)Receivers }, 0, sizeof(byte)); } // Add the time step to the end of the frame StreamData.BlockCopy <ulong>(TimeStep, sizeof(ulong)); // Add the unique message id for this frame just before the timestep frame StreamData.BlockCopy <ulong>(UniqueId, sizeof(ulong)); if (mask.Length > 0) { for (int i = dataStartIndex + mask.Length, j = 0; i < StreamData.Size; i++, j++) { StreamData.byteArr[i] = (byte)(StreamData.byteArr[i] ^ mask[j % 4]); } } }