/*
* 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