ApnsServerNotification Parse(List <byte> data) { // COMMAND FRAME LENGTH FRAME // 1 byte (0x02) 4 bytes ITEM ... ITEM ... ITEM ... // ITEM ID ITEM LENGTH ITEM DATA // 1 byte 2 bytes variable length // ITEMS: // 1: 32 bytes Device Token // 2: 2048 bytes (up to) Payload // 3: 4 bytes Notification identifier // 4: 4 bytes Expiration // 5: 1 byte Priority (10 - immediate, or 5 - normal) var notification = new ApnsServerNotification(); ApnsNotificationException exception = null; // If there aren't even 5 bytes, we can't even check if the length of notification is correct if (data.Count < 5) { return(null); } // Let's check to see if the notification is all here in the buffer var apnsCmd = data [0]; var apnsFrameLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.GetRange(1, 4).ToArray(), 0)); // If we don't have all of the notification's frame data that we should have, we need to keep waiting if (data.Count - 5 < apnsFrameLength) { return(null); } var frameData = data.GetRange(5, apnsFrameLength); // Remove the data we are processing data.RemoveRange(0, apnsFrameLength + 5); // Now process each item from the frame while (frameData.Count > 0) { // We need at least 4 bytes to count as a full item (1 byte id + 2 bytes length + at least 1 byte data) if (frameData.Count < 4) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.ProcessingError, "Invalid Frame Data"); break; } var itemId = frameData [0]; var itemLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frameData.GetRange(1, 2).ToArray(), 0)); // Make sure the item data is all there if (frameData.Count - 3 < itemLength) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.ProcessingError, "Invalid Item Data"); break; } var itemData = frameData.GetRange(3, itemLength); frameData.RemoveRange(0, itemLength + 3); if (itemId == 1) // Device Token { notification.DeviceToken = BitConverter.ToString(itemData.ToArray()).Replace("-", ""); if (notification.DeviceToken.Length != 64) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.InvalidTokenSize, "Invalid Token Size"); } } else if (itemId == 2) // Payload { notification.Payload = BitConverter.ToString(itemData.ToArray()); if (notification.Payload.Length > 2048) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.InvalidPayloadSize, "Invalid Payload Size"); } } else if (itemId == 3) // Identifier { if (itemData.Count > 4) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.ProcessingError, "Identifier too long"); } else { notification.Identifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(itemData.ToArray(), 0)); } } else if (itemId == 4) // Expiration { int secondsSinceEpoch = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(itemData.ToArray(), 0)); var expire = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(secondsSinceEpoch); notification.Expiration = expire; } else if (itemId == 5) // Priority { notification.Priority = itemData [0]; } } if (exception == null && string.IsNullOrEmpty(notification.DeviceToken)) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.MissingDeviceToken, "Missing Device Token"); } if (exception == null && string.IsNullOrEmpty(notification.Payload)) { exception = new ApnsNotificationException(ApnsNotificationErrorStatusCode.MissingPayload, "Missing Payload"); } // See if there was an error and we can assign an ID to it if (exception != null) { exception.NotificationId = notification.Identifier; throw exception; } return(notification); }
ApnsServerNotification Parse (List<byte> data) { // COMMAND FRAME LENGTH FRAME // 1 byte (0x02) 4 bytes ITEM ... ITEM ... ITEM ... // ITEM ID ITEM LENGTH ITEM DATA // 1 byte 2 bytes variable length // ITEMS: // 1: 32 bytes Device Token // 2: 2048 bytes (up to) Payload // 3: 4 bytes Notification identifier // 4: 4 bytes Expiration // 5: 1 byte Priority (10 - immediate, or 5 - normal) var notification = new ApnsServerNotification (); ApnsNotificationException exception = null; // If there aren't even 5 bytes, we can't even check if the length of notification is correct if (data.Count < 5) return null; // Let's check to see if the notification is all here in the buffer var apnsCmd = data [0]; var apnsFrameLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.GetRange (1, 4).ToArray (), 0)); // If we don't have all of the notification's frame data that we should have, we need to keep waiting if (data.Count - 5 < apnsFrameLength) return null; var frameData = data.GetRange (5, apnsFrameLength); // Remove the data we are processing data.RemoveRange (0, apnsFrameLength + 5); // Now process each item from the frame while (frameData.Count > 0) { // We need at least 4 bytes to count as a full item (1 byte id + 2 bytes length + at least 1 byte data) if (frameData.Count < 4) { exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.ProcessingError, "Invalid Frame Data"); break; } var itemId = frameData [0]; var itemLength = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (frameData.GetRange (1, 2).ToArray (), 0)); // Make sure the item data is all there if (frameData.Count - 3 < itemLength) { exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.ProcessingError, "Invalid Item Data"); break; } var itemData = frameData.GetRange (3, itemLength); frameData.RemoveRange (0, itemLength + 3); if (itemId == 1) { // Device Token notification.DeviceToken = BitConverter.ToString(itemData.ToArray()).Replace("-", ""); if (notification.DeviceToken.Length != 64) exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.InvalidTokenSize, "Invalid Token Size"); } else if (itemId == 2) { // Payload notification.Payload = BitConverter.ToString(itemData.ToArray()); if (notification.Payload.Length > 2048) exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.InvalidPayloadSize, "Invalid Payload Size"); } else if (itemId == 3) { // Identifier if (itemData.Count > 4) exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.ProcessingError, "Identifier too long"); else notification.Identifier = IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (itemData.ToArray (), 0)); } else if (itemId == 4) { // Expiration int secondsSinceEpoch = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(itemData.ToArray (), 0)); var expire = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds (secondsSinceEpoch); notification.Expiration = expire; } else if (itemId == 5) { // Priority notification.Priority = itemData [0]; } } if (exception == null && string.IsNullOrEmpty (notification.DeviceToken)) exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.MissingDeviceToken, "Missing Device Token"); if (exception == null && string.IsNullOrEmpty (notification.Payload)) exception = new ApnsNotificationException (ApnsNotificationErrorStatusCode.MissingPayload, "Missing Payload"); // See if there was an error and we can assign an ID to it if (exception != null) { exception.NotificationId = notification.Identifier; throw exception; } return notification; }