/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * A service that exchanges time synchronization information between * a master that defines a timeline and clients that follow the timeline. */ #define LOG_TAG "common_time" #include <utils/Log.h> #include <arpa/inet.h> #include <stdint.h> #include "common_time_server_packets.h" namespace android { const uint32_t TimeServicePacketHeader::kMagic = (static_cast<uint32_t>('c') << 24) | (static_cast<uint32_t>('c') << 16) | (static_cast<uint32_t>('l') << 8) | static_cast<uint32_t>('k'); const uint16_t TimeServicePacketHeader::kCurVersion = 1; #define SERIALIZE_FIELD(field_name, type, converter) \ do { \ if ((offset + sizeof(field_name)) > length) \ return -1; \ *((type*)(data + offset)) = converter(field_name); \ offset += sizeof(field_name); \ } while (0) #define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons) #define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl) #define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq) #define DESERIALIZE_FIELD(field_name, type, converter) \ do { \ if ((offset + sizeof(field_name)) > length) \ return -1; \ field_name = converter(*((type*)(data + offset))); \ offset += sizeof(field_name); \ } while (0) #define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs) #define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl) #define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq) #define kDevicePriorityShift 56 #define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1) inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) { return (devID & kDeviceIDMask) | (static_cast<uint64_t>(prio) << kDevicePriorityShift); } inline uint64_t unpackDeviceID(uint64_t packed) { return (packed & kDeviceIDMask); } inline uint8_t unpackDevicePriority(uint64_t packed) { return static_cast<uint8_t>(packed >> kDevicePriorityShift); } ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data, uint32_t length) { ssize_t offset = 0; int16_t pktType = static_cast<int16_t>(packetType); SERIALIZE_INT32(magic); SERIALIZE_INT16(version); SERIALIZE_INT16(pktType); SERIALIZE_INT64(timelineID); SERIALIZE_INT64(syncGroupID); return offset; } ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data, uint32_t length) { ssize_t offset = 0; int16_t tmp; DESERIALIZE_INT32(magic); DESERIALIZE_INT16(version); DESERIALIZE_INT16(tmp); DESERIALIZE_INT64(timelineID); DESERIALIZE_INT64(syncGroupID); packetType = static_cast<TimeServicePacketType>(tmp); return offset; } ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data, uint32_t length) { ssize_t ret, tmp; ret = serializeHeader(data, length); if (ret < 0) return ret; data += ret; length -= ret; switch (packetType) { case TIME_PACKET_WHO_IS_MASTER_REQUEST: tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data, length); break; case TIME_PACKET_WHO_IS_MASTER_RESPONSE: tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data, length); break; case TIME_PACKET_SYNC_REQUEST: tmp =((SyncRequestPacket*)(this))->serializePacket(data, length); break; case TIME_PACKET_SYNC_RESPONSE: tmp =((SyncResponsePacket*)(this))->serializePacket(data, length); break; case TIME_PACKET_MASTER_ANNOUNCEMENT: tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data, length); break; default: return -1; } if (tmp < 0) return tmp; return ret + tmp; } ssize_t UniversalTimeServicePacket::deserializePacket( const uint8_t* data, uint32_t length, uint64_t expectedSyncGroupID) { ssize_t ret; TimeServicePacketHeader* header; if (length < 8) return -1; packetType = ntohs(*((uint16_t*)(data + 6))); switch (packetType) { case TIME_PACKET_WHO_IS_MASTER_REQUEST: ret = p.who_is_master_request.deserializePacket(data, length); header = &p.who_is_master_request; break; case TIME_PACKET_WHO_IS_MASTER_RESPONSE: ret = p.who_is_master_response.deserializePacket(data, length); header = &p.who_is_master_response; break; case TIME_PACKET_SYNC_REQUEST: ret = p.sync_request.deserializePacket(data, length); header = &p.sync_request; break; case TIME_PACKET_SYNC_RESPONSE: ret = p.sync_response.deserializePacket(data, length); header = &p.sync_response; break; case TIME_PACKET_MASTER_ANNOUNCEMENT: ret = p.master_announcement.deserializePacket(data, length); header = &p.master_announcement; break; default: return -1; } if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID)) ret = -1; return ret; } ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data, uint32_t length) { ssize_t offset = serializeHeader(data, length); if (offset > 0) { uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority); SERIALIZE_INT64(packed); } return offset; } ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data, uint32_t length) { ssize_t offset = deserializeHeader(data, length); if (offset > 0) { uint64_t packed; DESERIALIZE_INT64(packed); senderDeviceID = unpackDeviceID(packed); senderDevicePriority = unpackDevicePriority(packed); } return offset; } ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data, uint32_t length) { ssize_t offset = serializeHeader(data, length); if (offset > 0) { uint64_t packed = packDeviceID(deviceID, devicePriority); SERIALIZE_INT64(packed); } return offset; } ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data, uint32_t length) { ssize_t offset = deserializeHeader(data, length); if (offset > 0) { uint64_t packed; DESERIALIZE_INT64(packed); deviceID = unpackDeviceID(packed); devicePriority = unpackDevicePriority(packed); } return offset; } ssize_t SyncRequestPacket::serializePacket(uint8_t* data, uint32_t length) { ssize_t offset = serializeHeader(data, length); if (offset > 0) { SERIALIZE_INT64(clientTxLocalTime); } return offset; } ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data, uint32_t length) { ssize_t offset = deserializeHeader(data, length); if (offset > 0) { DESERIALIZE_INT64(clientTxLocalTime); } return offset; } ssize_t SyncResponsePacket::serializePacket(uint8_t* data, uint32_t length) { ssize_t offset = serializeHeader(data, length); if (offset > 0) { SERIALIZE_INT64(clientTxLocalTime); SERIALIZE_INT64(masterRxCommonTime); SERIALIZE_INT64(masterTxCommonTime); SERIALIZE_INT32(nak); } return offset; } ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data, uint32_t length) { ssize_t offset = deserializeHeader(data, length); if (offset > 0) { DESERIALIZE_INT64(clientTxLocalTime); DESERIALIZE_INT64(masterRxCommonTime); DESERIALIZE_INT64(masterTxCommonTime); DESERIALIZE_INT32(nak); } return offset; } ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data, uint32_t length) { ssize_t offset = serializeHeader(data, length); if (offset > 0) { uint64_t packed = packDeviceID(deviceID, devicePriority); SERIALIZE_INT64(packed); } return offset; } ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data, uint32_t length) { ssize_t offset = deserializeHeader(data, length); if (offset > 0) { uint64_t packed; DESERIALIZE_INT64(packed); deviceID = unpackDeviceID(packed); devicePriority = unpackDevicePriority(packed); } return offset; } } // namespace android