294 lines
9.9 KiB
C++
294 lines
9.9 KiB
C++
/*
|
|
* 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
|
|
|