/*
* 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.
*/
#ifndef ANDROID_COMMON_TIME_SERVER_PACKETS_H
#define ANDROID_COMMON_TIME_SERVER_PACKETS_H
#include <stdint.h>
#include <common_time/ICommonClock.h>
namespace android {
/***** time sync protocol packets *****/
enum TimeServicePacketType {
TIME_PACKET_WHO_IS_MASTER_REQUEST = 1,
TIME_PACKET_WHO_IS_MASTER_RESPONSE,
TIME_PACKET_SYNC_REQUEST,
TIME_PACKET_SYNC_RESPONSE,
TIME_PACKET_MASTER_ANNOUNCEMENT,
};
class TimeServicePacketHeader {
public:
friend class UniversalTimeServicePacket;
// magic number identifying the protocol
uint32_t magic;
// protocol version of the packet
uint16_t version;
// type of the packet
TimeServicePacketType packetType;
// the timeline ID
uint64_t timelineID;
// synchronization group this packet belongs to (used to operate multiple
// synchronization domains which all use the same master election endpoint)
uint64_t syncGroupID;
ssize_t serializePacket(uint8_t* data, uint32_t length);
protected:
void initHeader(TimeServicePacketType type,
const uint64_t tlID,
const uint64_t groupID) {
magic = kMagic;
version = kCurVersion;
packetType = type;
timelineID = tlID;
syncGroupID = groupID;
}
bool checkPacket(uint64_t expectedSyncGroupID) const {
return ((magic == kMagic) &&
(version == kCurVersion) &&
(!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID)));
}
ssize_t serializeHeader(uint8_t* data, uint32_t length);
ssize_t deserializeHeader(const uint8_t* data, uint32_t length);
private:
static const uint32_t kMagic;
static const uint16_t kCurVersion;
};
// packet querying for a suitable master
class WhoIsMasterRequestPacket : public TimeServicePacketHeader {
public:
uint64_t senderDeviceID;
uint8_t senderDevicePriority;
void initHeader(const uint64_t groupID) {
TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST,
ICommonClock::kInvalidTimelineID,
groupID);
}
ssize_t serializePacket(uint8_t* data, uint32_t length);
ssize_t deserializePacket(const uint8_t* data, uint32_t length);
};
// response to a WhoIsMaster request
class WhoIsMasterResponsePacket : public TimeServicePacketHeader {
public:
uint64_t deviceID;
uint8_t devicePriority;
void initHeader(const uint64_t tlID, const uint64_t groupID) {
TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE,
tlID, groupID);
}
ssize_t serializePacket(uint8_t* data, uint32_t length);
ssize_t deserializePacket(const uint8_t* data, uint32_t length);
};
// packet sent by a client requesting correspondence between local
// and common time
class SyncRequestPacket : public TimeServicePacketHeader {
public:
// local time when this request was transmitted
int64_t clientTxLocalTime;
void initHeader(const uint64_t tlID, const uint64_t groupID) {
TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST,
tlID, groupID);
}
ssize_t serializePacket(uint8_t* data, uint32_t length);
ssize_t deserializePacket(const uint8_t* data, uint32_t length);
};
// response to a sync request sent by the master
class SyncResponsePacket : public TimeServicePacketHeader {
public:
// local time when this request was transmitted by the client
int64_t clientTxLocalTime;
// common time when the master received the request
int64_t masterRxCommonTime;
// common time when the master transmitted the response
int64_t masterTxCommonTime;
// flag that is set if the recipient of the sync request is not acting
// as a master for the requested timeline
uint32_t nak;
void initHeader(const uint64_t tlID, const uint64_t groupID) {
TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE,
tlID, groupID);
}
ssize_t serializePacket(uint8_t* data, uint32_t length);
ssize_t deserializePacket(const uint8_t* data, uint32_t length);
};
// announcement of the master's presence
class MasterAnnouncementPacket : public TimeServicePacketHeader {
public:
// the master's device ID
uint64_t deviceID;
uint8_t devicePriority;
void initHeader(const uint64_t tlID, const uint64_t groupID) {
TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT,
tlID, groupID);
}
ssize_t serializePacket(uint8_t* data, uint32_t length);
ssize_t deserializePacket(const uint8_t* data, uint32_t length);
};
class UniversalTimeServicePacket {
public:
uint16_t packetType;
union {
WhoIsMasterRequestPacket who_is_master_request;
WhoIsMasterResponsePacket who_is_master_response;
SyncRequestPacket sync_request;
SyncResponsePacket sync_response;
MasterAnnouncementPacket master_announcement;
} p;
ssize_t deserializePacket(const uint8_t* data,
uint32_t length,
uint64_t expectedSyncGroupID);
};
}; // namespace android
#endif // ANDROID_COMMON_TIME_SERVER_PACKETS_H