diff options
Diffstat (limited to 'services/common_time/common_time_server.cpp')
-rw-r--r-- | services/common_time/common_time_server.cpp | 1506 |
1 files changed, 0 insertions, 1506 deletions
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp deleted file mode 100644 index 21e706f..0000000 --- a/services/common_time/common_time_server.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -/* - * 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 <assert.h> -#include <fcntl.h> -#include <linux/if_ether.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <netinet/ip.h> -#include <poll.h> -#include <stdio.h> -#include <sys/eventfd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <common_time/local_clock.h> -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <utils/Timers.h> - -#include "common_clock_service.h" -#include "common_time_config_service.h" -#include "common_time_server.h" -#include "common_time_server_packets.h" -#include "clock_recovery.h" -#include "common_clock.h" - -#define MAX_INT ((int)0x7FFFFFFF) - -namespace android { - -const char* CommonTimeServer::kDefaultMasterElectionAddr = "255.255.255.255"; -const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8886; -const uint64_t CommonTimeServer::kDefaultSyncGroupID = 1; -const uint8_t CommonTimeServer::kDefaultMasterPriority = 1; -const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000; -const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000; -const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000; -const bool CommonTimeServer::kDefaultAutoDisable = true; -const int CommonTimeServer::kSetupRetryTimeoutMs = 30000; -const int64_t CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll; -const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5; - -// timeout value representing an infinite timeout -const int CommonTimeServer::kInfiniteTimeout = -1; - -/*** Initial state constants ***/ - -// number of WhoIsMaster attempts sent before giving up -const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6; - -// timeout used when waiting for a response to a WhoIsMaster request -const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500; - -/*** Client state constants ***/ - -// number of sync requests that can fail before a client assumes its master -// is dead -const int CommonTimeServer::kClient_NumSyncRequestRetries = 10; - -/*** Master state constants ***/ - -/*** Ronin state constants ***/ - -// number of WhoIsMaster attempts sent before declaring ourselves master -const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 20; - -// timeout used when waiting for a response to a WhoIsMaster request -const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500; - -/*** WaitForElection state constants ***/ - -// how long do we wait for an announcement from a master before -// trying another election? -const int CommonTimeServer::kWaitForElection_TimeoutMs = 12500; - -CommonTimeServer::CommonTimeServer() - : Thread(false) - , mState(ICommonClock::STATE_INITIAL) - , mClockRecovery(&mLocalClock, &mCommonClock) - , mSocket(-1) - , mLastPacketRxLocalTime(0) - , mTimelineID(ICommonClock::kInvalidTimelineID) - , mClockSynced(false) - , mCommonClockHasClients(false) - , mStateChangeLog("Recent State Change Events", 30) - , mElectionLog("Recent Master Election Traffic", 30) - , mBadPktLog("Recent Bad Packet RX Info", 8) - , mInitial_WhoIsMasterRequestTimeouts(0) - , mClient_MasterDeviceID(0) - , mClient_MasterDevicePriority(0) - , mRonin_WhoIsMasterRequestTimeouts(0) { - // zero out sync stats - resetSyncStats(); - - // Setup the master election endpoint to use the default. - struct sockaddr_in* meep = - reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); - memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP)); - inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr); - meep->sin_family = AF_INET; - meep->sin_port = htons(kDefaultMasterElectionPort); - - // Zero out the master endpoint. - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mBindIfaceValid = false; - setForceLowPriority(false); - - // Set all remaining configuration parameters to their defaults. - mDeviceID = 0; - mSyncGroupID = kDefaultSyncGroupID; - mMasterPriority = kDefaultMasterPriority; - mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs; - mSyncRequestIntervalMs = kDefaultSyncRequestIntervalMs; - mPanicThresholdUsec = kDefaultPanicThresholdUsec; - mAutoDisable = kDefaultAutoDisable; - - // Create the eventfd we will use to signal our thread to wake up when - // needed. - mWakeupThreadFD = eventfd(0, EFD_NONBLOCK); - - // seed the random number generator (used to generated timeline IDs) - srand48(static_cast<unsigned int>(systemTime())); -} - -CommonTimeServer::~CommonTimeServer() { - shutdownThread(); - - // No need to grab the lock here. We are in the destructor; if the the user - // has a thread in any of the APIs while the destructor is being called, - // there is a threading problem a the application level we cannot reasonably - // do anything about. - cleanupSocket_l(); - - if (mWakeupThreadFD >= 0) { - close(mWakeupThreadFD); - mWakeupThreadFD = -1; - } -} - -bool CommonTimeServer::startServices() { - // start the ICommonClock service - mICommonClock = CommonClockService::instantiate(*this); - if (mICommonClock == NULL) - return false; - - // start the ICommonTimeConfig service - mICommonTimeConfig = CommonTimeConfigService::instantiate(*this); - if (mICommonTimeConfig == NULL) - return false; - - return true; -} - -bool CommonTimeServer::threadLoop() { - // Register our service interfaces. - if (!startServices()) - return false; - - // Hold the lock while we are in the main thread loop. It will release the - // lock when it blocks, and hold the lock at all other times. - mLock.lock(); - runStateMachine_l(); - mLock.unlock(); - - IPCThreadState::self()->stopProcess(); - return false; -} - -bool CommonTimeServer::runStateMachine_l() { - if (!mLocalClock.initCheck()) - return false; - - if (!mCommonClock.init(mLocalClock.getLocalFreq())) - return false; - - // Enter the initial state. - becomeInitial("startup"); - - // run the state machine - while (!exitPending()) { - struct pollfd pfds[2]; - int rc, timeout; - int eventCnt = 0; - int64_t wakeupTime; - uint32_t t1, t2; - bool needHandleTimeout = false; - - // We are always interested in our wakeup FD. - pfds[eventCnt].fd = mWakeupThreadFD; - pfds[eventCnt].events = POLLIN; - pfds[eventCnt].revents = 0; - eventCnt++; - - // If we have a valid socket, then we are interested in what it has to - // say as well. - if (mSocket >= 0) { - pfds[eventCnt].fd = mSocket; - pfds[eventCnt].events = POLLIN; - pfds[eventCnt].revents = 0; - eventCnt++; - } - - t1 = static_cast<uint32_t>(mCurTimeout.msecTillTimeout()); - t2 = static_cast<uint32_t>(mClockRecovery.applyRateLimitedSlew()); - timeout = static_cast<int>(t1 < t2 ? t1 : t2); - - // Note, we were holding mLock when this function was called. We - // release it only while we are blocking and hold it at all other times. - mLock.unlock(); - rc = poll(pfds, eventCnt, timeout); - wakeupTime = mLocalClock.getLocalTime(); - mLock.lock(); - - // Is it time to shutdown? If so, don't hesitate... just do it. - if (exitPending()) - break; - - // Did the poll fail? This should never happen and is fatal if it does. - if (rc < 0) { - ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - if (rc == 0) { - needHandleTimeout = !mCurTimeout.msecTillTimeout(); - if (needHandleTimeout) - mCurTimeout.setTimeout(kInfiniteTimeout); - } - - // Were we woken up on purpose? If so, clear the eventfd with a read. - if (pfds[0].revents) - clearPendingWakeupEvents_l(); - - // Is out bind address dirty? If so, clean up our socket (if any). - // Alternatively, do we have an active socket but should be auto - // disabled? If so, release the socket and enter the proper sync state. - bool droppedSocket = false; - if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) { - cleanupSocket_l(); - mBindIfaceDirty = false; - droppedSocket = true; - } - - // Do we not have a socket but should have one? If so, try to set one - // up. - if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) { - if (setupSocket_l()) { - // Success! We are now joining a new network (either coming - // from no network, or coming from a potentially different - // network). Force our priority to be lower so that we defer to - // any other masters which may already be on the network we are - // joining. Later, when we enter either the client or the - // master state, we will clear this flag and go back to our - // normal election priority. - setForceLowPriority(true); - switch (mState) { - // If we were in initial (whether we had a immediately - // before this network or not) we want to simply reset the - // system and start again. Forcing a transition from - // INITIAL to INITIAL should do the job. - case CommonClockService::STATE_INITIAL: - becomeInitial("bound interface"); - break; - - // If we were in the master state, then either we were the - // master in a no-network situation, or we were the master - // of a different network and have moved to a new interface. - // In either case, immediately transition to Ronin at low - // priority. If there is no one in the network we just - // joined, we will become master soon enough. If there is, - // we want to be certain to defer master status to the - // existing timeline currently running on the network. - // - case CommonClockService::STATE_MASTER: - becomeRonin("leaving networkless mode"); - break; - - // If we were in any other state (CLIENT, RONIN, or - // WAIT_FOR_ELECTION) then we must be moving from one - // network to another. We have lost our old master; - // transition to RONIN in an attempt to find a new master. - // If there are none out there, we will just assume - // responsibility for the timeline we used to be a client - // of. - default: - becomeRonin("bound interface"); - break; - } - } else { - // That's odd... we failed to set up our socket. This could be - // due to some transient network change which will work itself - // out shortly; schedule a retry attempt in the near future. - mCurTimeout.setTimeout(kSetupRetryTimeoutMs); - } - - // One way or the other, we don't have any data to process at this - // point (since we just tried to bulid a new socket). Loop back - // around and wait for the next thing to do. - continue; - } else if (droppedSocket) { - // We just lost our socket, and for whatever reason (either no - // config, or auto disable engaged) we are not supposed to rebuild - // one at this time. We are not going to rebuild our socket until - // something about our config/auto-disabled status changes, so we - // are basically in network-less mode. If we are already in either - // INITIAL or MASTER, just stay there until something changes. If - // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION), - // then transition to either INITIAL or MASTER depending on whether - // or not our timeline is valid. - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Entering networkless mode interface is %s, " - "shouldAutoDisable = %s", - mBindIfaceValid ? "valid" : "invalid", - shouldAutoDisable() ? "true" : "false"); - if ((mState != ICommonClock::STATE_INITIAL) && - (mState != ICommonClock::STATE_MASTER)) { - if (mTimelineID == ICommonClock::kInvalidTimelineID) - becomeInitial("network-less mode"); - else - becomeMaster("network-less mode"); - } - - continue; - } - - // Time to handle the timeouts? - if (needHandleTimeout) { - if (!handleTimeout()) - ALOGE("handleTimeout failed"); - continue; - } - - // Does our socket have data for us (assuming we still have one, we - // may have RXed a packet at the same time as a config change telling us - // to shut our socket down)? If so, process its data. - if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) { - mLastPacketRxLocalTime = wakeupTime; - if (!handlePacket()) - ALOGE("handlePacket failed"); - } - } - - cleanupSocket_l(); - return true; -} - -void CommonTimeServer::clearPendingWakeupEvents_l() { - int64_t tmp; - read(mWakeupThreadFD, &tmp, sizeof(tmp)); -} - -void CommonTimeServer::wakeupThread_l() { - int64_t tmp = 1; - write(mWakeupThreadFD, &tmp, sizeof(tmp)); -} - -void CommonTimeServer::cleanupSocket_l() { - if (mSocket >= 0) { - close(mSocket); - mSocket = -1; - } -} - -void CommonTimeServer::shutdownThread() { - // Flag the work thread for shutdown. - this->requestExit(); - - // Signal the thread in case its sleeping. - mLock.lock(); - wakeupThread_l(); - mLock.unlock(); - - // Wait for the thread to exit. - this->join(); -} - -bool CommonTimeServer::setupSocket_l() { - int rc; - bool ret_val = false; - struct sockaddr_in* ipv4_addr = NULL; - char masterElectionEPStr[64]; - const int one = 1; - - // This should never be needed, but if we happened to have an old socket - // lying around, be sure to not leak it before proceeding. - cleanupSocket_l(); - - // If we don't have a valid endpoint to bind to, then how did we get here in - // the first place? Regardless, we know that we are going to fail to bind, - // so don't even try. - if (!mBindIfaceValid) - return false; - - sockaddrToString(mMasterElectionEP, true, masterElectionEPStr, - sizeof(masterElectionEPStr)); - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Building socket :: bind = %s master election = %s", - mBindIface.string(), masterElectionEPStr); - - // TODO: add proper support for IPv6. Right now, we block IPv6 addresses at - // the configuration interface level. - if (AF_INET != mMasterElectionEP.ss_family) { - mStateChangeLog.log(ANDROID_LOG_WARN, LOG_TAG, - "TODO: add proper IPv6 support"); - goto bailout; - } - - // open a UDP socket for the timeline serivce - mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (mSocket < 0) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to create socket (errno = %d)", errno); - goto bailout; - } - - // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE. - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string()); - ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0; - rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, - (void *)&ifr, sizeof(ifr)); - if (rc) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to bind socket at to interface %s " - "(errno = %d)", ifr.ifr_name, errno); - goto bailout; - } - - // Bind our socket to INADDR_ANY and the master election port. The - // interface binding we made using SO_BINDTODEVICE should limit us to - // traffic only on the interface we are interested in. We need to bind to - // INADDR_ANY and the specific master election port in order to be able to - // receive both unicast traffic and master election multicast traffic with - // just a single socket. - struct sockaddr_in bindAddr; - ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); - memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr)); - bindAddr.sin_addr.s_addr = INADDR_ANY; - rc = bind(mSocket, - reinterpret_cast<const sockaddr *>(&bindAddr), - sizeof(bindAddr)); - if (rc) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to bind socket to port %hu (errno = %d)", - ntohs(bindAddr.sin_port), errno); - goto bailout; - } - - if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) { - // If our master election endpoint is a multicast address, be sure to join - // the multicast group. - struct ip_mreq mreq; - mreq.imr_multiaddr = ipv4_addr->sin_addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)); - if (rc == -1) { - ALOGE("Failed to join multicast group at %s. (errno = %d)", - masterElectionEPStr, errno); - goto bailout; - } - - // disable loopback of multicast packets - const int zero = 0; - rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP, - &zero, sizeof(zero)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to disable multicast loopback " - "(errno = %d)", errno); - goto bailout; - } - } else - if (ntohl(ipv4_addr->sin_addr.s_addr) == 0xFFFFFFFF) { - // If the master election address is the broadcast address, then enable - // the broadcast socket option - rc = setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to enable broadcast (errno = %d)", - errno); - goto bailout; - } - } else { - // If the master election address is neither broadcast, nor multicast, - // then we are misconfigured. The config API layer should prevent this - // from ever happening. - goto bailout; - } - - // Set the TTL of sent packets to 1. (Time protocol sync should never leave - // the local subnet) - rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to set TTL to %d (errno = %d)", one, errno); - goto bailout; - } - - // get the device's unique ID - if (!assignDeviceID()) - goto bailout; - - ret_val = true; - -bailout: - if (!ret_val) - cleanupSocket_l(); - return ret_val; -} - -// generate a unique device ID that can be used for arbitration -bool CommonTimeServer::assignDeviceID() { - if (!mBindIfaceValid) - return false; - - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_addr.sa_family = AF_INET; - strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ); - - int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr); - if (rc) { - ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) { - ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - mDeviceID = 0; - for (int i = 0; i < ETH_ALEN; i++) { - mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i]; - } - - return true; -} - -// generate a new timeline ID -void CommonTimeServer::assignTimelineID() { - do { - mTimelineID = (static_cast<uint64_t>(lrand48()) << 32) - | static_cast<uint64_t>(lrand48()); - } while (mTimelineID == ICommonClock::kInvalidTimelineID); -} - -// Select a preference between the device IDs of two potential masters. -// Returns true if the first ID wins, or false if the second ID wins. -bool CommonTimeServer::arbitrateMaster( - uint64_t deviceID1, uint8_t devicePrio1, - uint64_t deviceID2, uint8_t devicePrio2) { - return ((devicePrio1 > devicePrio2) || - ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2))); -} - -static void hexDumpToString(const uint8_t* src, size_t src_len, - char* dst, size_t dst_len) { - size_t offset = 0; - size_t i; - - for (i = 0; (i < src_len) && (offset < dst_len); ++i) { - int res; - if (0 == (i % 16)) { - res = snprintf(dst + offset, dst_len - offset, "\n%04x :", i); - if (res < 0) - break; - offset += res; - if (offset >= dst_len) - break; - } - - res = snprintf(dst + offset, dst_len - offset, " %02x", src[i]); - if (res < 0) - break; - offset += res; - } - - dst[dst_len - 1] = 0; -} - -bool CommonTimeServer::handlePacket() { - uint8_t buf[256]; - struct sockaddr_storage srcAddr; - socklen_t srcAddrLen = sizeof(srcAddr); - - ssize_t recvBytes = recvfrom( - mSocket, buf, sizeof(buf), 0, - reinterpret_cast<const sockaddr *>(&srcAddr), &srcAddrLen); - - if (recvBytes < 0) { - mBadPktLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "recvfrom failed (res %d, errno %d)", - recvBytes, errno); - return false; - } - - UniversalTimeServicePacket pkt; - if (pkt.deserializePacket(buf, recvBytes, mSyncGroupID) < 0) { - char hex[256]; - char srcEPStr[64]; - - hexDumpToString(buf, static_cast<size_t>(recvBytes), hex, sizeof(hex)); - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - - mBadPktLog.log("Failed to parse %d byte packet from %s.%s", - recvBytes, srcEPStr, hex); - return false; - } - - bool result; - switch (pkt.packetType) { - case TIME_PACKET_WHO_IS_MASTER_REQUEST: - result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request, - srcAddr); - break; - - case TIME_PACKET_WHO_IS_MASTER_RESPONSE: - result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response, - srcAddr); - break; - - case TIME_PACKET_SYNC_REQUEST: - result = handleSyncRequest(&pkt.p.sync_request, srcAddr); - break; - - case TIME_PACKET_SYNC_RESPONSE: - result = handleSyncResponse(&pkt.p.sync_response, srcAddr); - break; - - case TIME_PACKET_MASTER_ANNOUNCEMENT: - result = handleMasterAnnouncement(&pkt.p.master_announcement, - srcAddr); - break; - - default: { - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - - mBadPktLog.log(ANDROID_LOG_WARN, LOG_TAG, - "unknown packet type (%d) from %s", - pkt.packetType, srcEPStr); - - result = false; - } break; - } - - return result; -} - -bool CommonTimeServer::handleTimeout() { - // If we have no socket, then this must be a timeout to retry socket setup. - if (mSocket < 0) - return true; - - switch (mState) { - case ICommonClock::STATE_INITIAL: - return handleTimeoutInitial(); - case ICommonClock::STATE_CLIENT: - return handleTimeoutClient(); - case ICommonClock::STATE_MASTER: - return handleTimeoutMaster(); - case ICommonClock::STATE_RONIN: - return handleTimeoutRonin(); - case ICommonClock::STATE_WAIT_FOR_ELECTION: - return handleTimeoutWaitForElection(); - } - - return false; -} - -bool CommonTimeServer::handleTimeoutInitial() { - if (++mInitial_WhoIsMasterRequestTimeouts == - kInitial_NumWhoIsMasterRetries) { - // none of our attempts to discover a master succeeded, so make - // this device the master - return becomeMaster("initial timeout"); - } else { - // retry the WhoIsMaster request - return sendWhoIsMasterRequest(); - } -} - -bool CommonTimeServer::handleTimeoutClient() { - if (shouldPanicNotGettingGoodData()) - return becomeInitial("timeout panic, no good data"); - - if (mClient_SyncRequestPending) { - mClient_SyncRequestPending = false; - - if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) { - // a sync request has timed out, so retry - return sendSyncRequest(); - } else { - // The master has failed to respond to a sync request for too many - // times in a row. Assume the master is dead and start electing - // a new master. - return becomeRonin("master not responding"); - } - } else { - // initiate the next sync request - return sendSyncRequest(); - } -} - -bool CommonTimeServer::handleTimeoutMaster() { - // send another announcement from the master - return sendMasterAnnouncement(); -} - -bool CommonTimeServer::handleTimeoutRonin() { - if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) { - // no other master is out there, so we won the election - return becomeMaster("no better masters detected"); - } else { - return sendWhoIsMasterRequest(); - } -} - -bool CommonTimeServer::handleTimeoutWaitForElection() { - return becomeRonin("timeout waiting for election conclusion"); -} - -bool CommonTimeServer::handleWhoIsMasterRequest( - const WhoIsMasterRequestPacket* request, - const sockaddr_storage& srcAddr) { - // Skip our own messages which come back via broadcast loopback. - if (request->senderDeviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed WhoIs master request while in state %s. " - "src %s reqTID %016llx ourTID %016llx", - stateToString(mState), srcEPStr, - request->timelineID, mTimelineID); - - if (mState == ICommonClock::STATE_MASTER) { - // is this request related to this master's timeline? - if (request->timelineID != ICommonClock::kInvalidTimelineID && - request->timelineID != mTimelineID) - return true; - - WhoIsMasterResponsePacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.deviceID = mDeviceID; - pkt.devicePriority = effectivePriority(); - - mElectionLog.log("TXing WhoIs master resp to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - srcEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.deviceID, pkt.devicePriority); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz < 0) - return false; - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&srcAddr), - sizeof(srcAddr)); - if (sendBytes == -1) { - ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - } else if (mState == ICommonClock::STATE_RONIN) { - // if we hear a WhoIsMaster request from another device following - // the same timeline and that device wins arbitration, then we will stop - // trying to elect ourselves master and will instead wait for an - // announcement from the election winner - if (request->timelineID != mTimelineID) - return true; - - if (arbitrateMaster(request->senderDeviceID, - request->senderDevicePriority, - mDeviceID, - effectivePriority())) - return becomeWaitForElection("would lose election"); - - return true; - } else if (mState == ICommonClock::STATE_INITIAL) { - // If a group of devices booted simultaneously (e.g. after a power - // outage) and all of them are in the initial state and there is no - // master, then each device may time out and declare itself master at - // the same time. To avoid this, listen for - // WhoIsMaster(InvalidTimeline) requests from peers. If we would lose - // arbitration against that peer, reset our timeout count so that the - // peer has a chance to become master before we time out. - if (request->timelineID == ICommonClock::kInvalidTimelineID && - arbitrateMaster(request->senderDeviceID, - request->senderDevicePriority, - mDeviceID, - effectivePriority())) { - mInitial_WhoIsMasterRequestTimeouts = 0; - } - } - - return true; -} - -bool CommonTimeServer::handleWhoIsMasterResponse( - const WhoIsMasterResponsePacket* response, - const sockaddr_storage& srcAddr) { - // Skip our own messages which come back via broadcast loopback. - if (response->deviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed WhoIs master response while in state %s. " - "src %s respTID %016llx respDID %016llx respPrio %u " - "ourTID %016llx", - stateToString(mState), srcEPStr, - response->timelineID, - response->deviceID, - static_cast<uint32_t>(response->devicePriority), - mTimelineID); - - if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) { - return becomeClient(srcAddr, - response->deviceID, - response->devicePriority, - response->timelineID, - "heard whois response"); - } else if (mState == ICommonClock::STATE_CLIENT) { - // if we get multiple responses because there are multiple devices - // who believe that they are master, then follow the master that - // wins arbitration - if (arbitrateMaster(response->deviceID, - response->devicePriority, - mClient_MasterDeviceID, - mClient_MasterDevicePriority)) { - return becomeClient(srcAddr, - response->deviceID, - response->devicePriority, - response->timelineID, - "heard whois response"); - } - } - - return true; -} - -bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request, - const sockaddr_storage& srcAddr) { - SyncResponsePacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - - if ((mState == ICommonClock::STATE_MASTER) && - (mTimelineID == request->timelineID)) { - int64_t rxLocalTime = mLastPacketRxLocalTime; - int64_t rxCommonTime; - - // If we are master on an actual network and have actual clients, then - // we are no longer low priority. - setForceLowPriority(false); - - if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) { - return false; - } - - int64_t txLocalTime = mLocalClock.getLocalTime();; - int64_t txCommonTime; - if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) { - return false; - } - - pkt.nak = 0; - pkt.clientTxLocalTime = request->clientTxLocalTime; - pkt.masterRxCommonTime = rxCommonTime; - pkt.masterTxCommonTime = txCommonTime; - } else { - pkt.nak = 1; - pkt.clientTxLocalTime = 0; - pkt.masterRxCommonTime = 0; - pkt.masterTxCommonTime = 0; - } - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz < 0) - return false; - - ssize_t sendBytes = sendto( - mSocket, &buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&srcAddr), - sizeof(srcAddr)); - if (sendBytes == -1) { - ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - return true; -} - -bool CommonTimeServer::handleSyncResponse( - const SyncResponsePacket* response, - const sockaddr_storage& srcAddr) { - if (mState != ICommonClock::STATE_CLIENT) - return true; - - assert(mMasterEPValid); - if (!sockaddrMatch(srcAddr, mMasterEP, true)) { - char srcEP[64], expectedEP[64]; - sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP)); - sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP)); - ALOGI("Dropping sync response from unexpected address." - " Expected %s Got %s", expectedEP, srcEP); - return true; - } - - if (response->nak) { - // if our master is no longer accepting requests, then we need to find - // a new master - return becomeRonin("master NAK'ed"); - } - - mClient_SyncRequestPending = 0; - mClient_SyncRequestTimeouts = 0; - mClient_PacketRTTLog.logRX(response->clientTxLocalTime, - mLastPacketRxLocalTime); - - bool result; - if (!(mClient_SyncRespsRXedFromCurMaster++)) { - // the first request/response exchange between a client and a master - // may take unusually long due to ARP, so discard it. - result = true; - } else { - int64_t clientTxLocalTime = response->clientTxLocalTime; - int64_t clientRxLocalTime = mLastPacketRxLocalTime; - int64_t masterTxCommonTime = response->masterTxCommonTime; - int64_t masterRxCommonTime = response->masterRxCommonTime; - - int64_t rtt = (clientRxLocalTime - clientTxLocalTime); - int64_t avgLocal = (clientTxLocalTime + clientRxLocalTime) >> 1; - int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1; - - // if the RTT of the packet is significantly larger than the panic - // threshold, we should simply discard it. Its better to do nothing - // than to take cues from a packet like that. - int rttCommon = mCommonClock.localDurationToCommonDuration(rtt); - if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * - kRTTDiscardPanicThreshMultiplier)) { - ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon); - mClient_ExpiredSyncRespsRXedFromCurMaster++; - if (shouldPanicNotGettingGoodData()) - return becomeInitial("RX panic, no good data"); - } else { - result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon); - mClient_LastGoodSyncRX = clientRxLocalTime; - - if (result) { - // indicate to listeners that we've synced to the common timeline - notifyClockSync(); - } else { - ALOGE("Panic! Observed clock sync error is too high to tolerate," - " resetting state machine and starting over."); - notifyClockSyncLoss(); - return becomeInitial("panic"); - } - } - } - - mCurTimeout.setTimeout(mSyncRequestIntervalMs); - return result; -} - -bool CommonTimeServer::handleMasterAnnouncement( - const MasterAnnouncementPacket* packet, - const sockaddr_storage& srcAddr) { - uint64_t newDeviceID = packet->deviceID; - uint8_t newDevicePrio = packet->devicePriority; - uint64_t newTimelineID = packet->timelineID; - - // Skip our own messages which come back via broadcast loopback. - if (newDeviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed master announcement while in state %s. " - "src %s srcDevID %lld srcPrio %u srcTID %016llx", - stateToString(mState), srcEPStr, - newDeviceID, static_cast<uint32_t>(newDevicePrio), - newTimelineID); - - if (mState == ICommonClock::STATE_INITIAL || - mState == ICommonClock::STATE_RONIN || - mState == ICommonClock::STATE_WAIT_FOR_ELECTION) { - // if we aren't currently following a master, then start following - // this new master - return becomeClient(srcAddr, - newDeviceID, - newDevicePrio, - newTimelineID, - "heard master announcement"); - } else if (mState == ICommonClock::STATE_CLIENT) { - // if the new master wins arbitration against our current master, - // then become a client of the new master - if (arbitrateMaster(newDeviceID, - newDevicePrio, - mClient_MasterDeviceID, - mClient_MasterDevicePriority)) - return becomeClient(srcAddr, - newDeviceID, - newDevicePrio, - newTimelineID, - "heard master announcement"); - } else if (mState == ICommonClock::STATE_MASTER) { - // two masters are competing - if the new one wins arbitration, then - // cease acting as master - if (arbitrateMaster(newDeviceID, newDevicePrio, - mDeviceID, effectivePriority())) - return becomeClient(srcAddr, newDeviceID, - newDevicePrio, newTimelineID, - "heard master announcement"); - } - - return true; -} - -bool CommonTimeServer::sendWhoIsMasterRequest() { - assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN); - - // If we have no socket, then we must be in the unconfigured initial state. - // Don't report any errors, just don't try to send the initial who-is-master - // query. Eventually, our network will either become configured, or we will - // be forced into network-less master mode by higher level code. - if (mSocket < 0) { - assert(mState == ICommonClock::STATE_INITIAL); - return true; - } - - bool ret = false; - WhoIsMasterRequestPacket pkt; - pkt.initHeader(mSyncGroupID); - pkt.senderDeviceID = mDeviceID; - pkt.senderDevicePriority = effectivePriority(); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - char dstEPStr[64]; - sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr)); - mElectionLog.log("TXing WhoIs master request to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - dstEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.senderDeviceID, pkt.senderDevicePriority); - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterElectionEP), - sizeof(mMasterElectionEP)); - if (sendBytes < 0) - ALOGE("WhoIsMaster sendto failed (errno %d)", errno); - ret = true; - } - - if (mState == ICommonClock::STATE_INITIAL) { - mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs); - } else { - mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs); - } - - return ret; -} - -bool CommonTimeServer::sendSyncRequest() { - // If we are sending sync requests, then we must be in the client state and - // we must have a socket (when we have no network, we are only supposed to - // be in INITIAL or MASTER) - assert(mState == ICommonClock::STATE_CLIENT); - assert(mSocket >= 0); - - bool ret = false; - SyncRequestPacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.clientTxLocalTime = mLocalClock.getLocalTime(); - - if (!mClient_FirstSyncTX) - mClient_FirstSyncTX = pkt.clientTxLocalTime; - - mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterEP), - sizeof(mMasterEP)); - if (sendBytes < 0) - ALOGE("SyncRequest sendto failed (errno %d)", errno); - ret = true; - } - - mClient_SyncsSentToCurMaster++; - mCurTimeout.setTimeout(mSyncRequestIntervalMs); - mClient_SyncRequestPending = true; - - return ret; -} - -bool CommonTimeServer::sendMasterAnnouncement() { - bool ret = false; - assert(mState == ICommonClock::STATE_MASTER); - - // If we are being asked to send a master announcement, but we have no - // socket, we must be in network-less master mode. Don't bother to send the - // announcement, and don't bother to schedule a timeout. When the network - // comes up, the work thread will get poked and start the process of - // figuring out who the current master should be. - if (mSocket < 0) { - mCurTimeout.setTimeout(kInfiniteTimeout); - return true; - } - - MasterAnnouncementPacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.deviceID = mDeviceID; - pkt.devicePriority = effectivePriority(); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - char dstEPStr[64]; - sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr)); - mElectionLog.log("TXing Master announcement to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - dstEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.deviceID, pkt.devicePriority); - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterElectionEP), - sizeof(mMasterElectionEP)); - if (sendBytes < 0) - ALOGE("MasterAnnouncement sendto failed (errno %d)", errno); - ret = true; - } - - mCurTimeout.setTimeout(mMasterAnnounceIntervalMs); - return ret; -} - -bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP, - uint64_t masterDeviceID, - uint8_t masterDevicePriority, - uint64_t timelineID, - const char* cause) { - char newEPStr[64], oldEPStr[64]; - sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr)); - sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); - - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> CLIENT (%s) :%s" - " OldMaster: %02x-%014llx::%016llx::%s" - " NewMaster: %02x-%014llx::%016llx::%s", - stateToString(mState), cause, - (mTimelineID != timelineID) ? " (new timeline)" : "", - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - masterDevicePriority, masterDeviceID, - timelineID, newEPStr); - - if (mTimelineID != timelineID) { - // start following a new timeline - mTimelineID = timelineID; - mClockRecovery.reset(true, true); - notifyClockSyncLoss(); - } else { - // start following a new master on the existing timeline - mClockRecovery.reset(false, true); - } - - mMasterEP = masterEP; - mMasterEPValid = true; - - // If we are on a real network as a client of a real master, then we should - // no longer force low priority. If our master disappears, we should have - // the high priority bit set during the election to replace the master - // because this group was a real group and not a singleton created in - // networkless mode. - setForceLowPriority(false); - - mClient_MasterDeviceID = masterDeviceID; - mClient_MasterDevicePriority = masterDevicePriority; - resetSyncStats(); - - setState(ICommonClock::STATE_CLIENT); - - // add some jitter to when the various clients send their requests - // in order to reduce the likelihood that a group of clients overload - // the master after receiving a master announcement - usleep((lrand48() % 100) * 1000); - - return sendSyncRequest(); -} - -bool CommonTimeServer::becomeMaster(const char* cause) { - uint64_t oldTimelineID = mTimelineID; - if (mTimelineID == ICommonClock::kInvalidTimelineID) { - // this device has not been following any existing timeline, - // so it will create a new timeline and declare itself master - assert(!mCommonClock.isValid()); - - // set the common time basis - mCommonClock.setBasis(mLocalClock.getLocalTime(), 0); - - // assign an arbitrary timeline iD - assignTimelineID(); - - // notify listeners that we've created a common timeline - notifyClockSync(); - } - - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> MASTER (%s) : %s timeline %016llx", - stateToString(mState), cause, - (oldTimelineID == mTimelineID) ? "taking ownership of" - : "creating new", - mTimelineID); - - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mClient_MasterDevicePriority = effectivePriority(); - mClient_MasterDeviceID = mDeviceID; - mClockRecovery.reset(false, true); - resetSyncStats(); - - setState(ICommonClock::STATE_MASTER); - return sendMasterAnnouncement(); -} - -bool CommonTimeServer::becomeRonin(const char* cause) { - // If we were the client of a given timeline, but had never received even a - // single time sync packet, then we transition back to Initial instead of - // Ronin. If we transition to Ronin and end up becoming the new Master, we - // will be unable to service requests for other clients because we never - // actually knew what time it was. By going to initial, we ensure that - // other clients who know what time it is, but would lose master arbitration - // in the Ronin case, will step up and become the proper new master of the - // old timeline. - - char oldEPStr[64]; - sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - - if (mCommonClock.isValid()) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> RONIN (%s) : lost track of previously valid timeline " - "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", - stateToString(mState), cause, - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - mClient_SyncsSentToCurMaster, - mClient_SyncRespsRXedFromCurMaster, - mClient_ExpiredSyncRespsRXedFromCurMaster); - - mRonin_WhoIsMasterRequestTimeouts = 0; - setState(ICommonClock::STATE_RONIN); - return sendWhoIsMasterRequest(); - } else { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> INITIAL (%s) : never synced timeline " - "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", - stateToString(mState), cause, - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - mClient_SyncsSentToCurMaster, - mClient_SyncRespsRXedFromCurMaster, - mClient_ExpiredSyncRespsRXedFromCurMaster); - - return becomeInitial("ronin, no timeline"); - } -} - -bool CommonTimeServer::becomeWaitForElection(const char* cause) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> WAIT_FOR_ELECTION (%s) : dropping out of election," - " waiting %d mSec for completion.", - stateToString(mState), cause, kWaitForElection_TimeoutMs); - - setState(ICommonClock::STATE_WAIT_FOR_ELECTION); - mCurTimeout.setTimeout(kWaitForElection_TimeoutMs); - return true; -} - -bool CommonTimeServer::becomeInitial(const char* cause) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Entering INITIAL (%s), total reset.", - cause); - - setState(ICommonClock::STATE_INITIAL); - - // reset clock recovery - mClockRecovery.reset(true, true); - - // reset internal state bookkeeping. - mCurTimeout.setTimeout(kInfiniteTimeout); - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mLastPacketRxLocalTime = 0; - mTimelineID = ICommonClock::kInvalidTimelineID; - mClockSynced = false; - mInitial_WhoIsMasterRequestTimeouts = 0; - mClient_MasterDeviceID = 0; - mClient_MasterDevicePriority = 0; - mRonin_WhoIsMasterRequestTimeouts = 0; - resetSyncStats(); - - // send the first request to discover the master - return sendWhoIsMasterRequest(); -} - -void CommonTimeServer::notifyClockSync() { - if (!mClockSynced) { - mClockSynced = true; - mICommonClock->notifyOnTimelineChanged(mTimelineID); - } -} - -void CommonTimeServer::notifyClockSyncLoss() { - if (mClockSynced) { - mClockSynced = false; - mICommonClock->notifyOnTimelineChanged( - ICommonClock::kInvalidTimelineID); - } -} - -void CommonTimeServer::setState(ICommonClock::State s) { - mState = s; -} - -const char* CommonTimeServer::stateToString(ICommonClock::State s) { - switch(s) { - case ICommonClock::STATE_INITIAL: - return "INITIAL"; - case ICommonClock::STATE_CLIENT: - return "CLIENT"; - case ICommonClock::STATE_MASTER: - return "MASTER"; - case ICommonClock::STATE_RONIN: - return "RONIN"; - case ICommonClock::STATE_WAIT_FOR_ELECTION: - return "WAIT_FOR_ELECTION"; - default: - return "unknown"; - } -} - -void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr, - bool addrValid, - char* buf, size_t bufLen) { - if (!bufLen || !buf) - return; - - if (addrValid) { - switch (addr.ss_family) { - case AF_INET: { - const struct sockaddr_in* sa = - reinterpret_cast<const struct sockaddr_in*>(&addr); - unsigned long a = ntohl(sa->sin_addr.s_addr); - uint16_t p = ntohs(sa->sin_port); - snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu", - ((a >> 24) & 0xFF), ((a >> 16) & 0xFF), - ((a >> 8) & 0xFF), (a & 0xFF), p); - } break; - - case AF_INET6: { - const struct sockaddr_in6* sa = - reinterpret_cast<const struct sockaddr_in6*>(&addr); - const uint8_t* a = sa->sin6_addr.s6_addr; - uint16_t p = ntohs(sa->sin6_port); - snprintf(buf, bufLen, - "%02X%02X:%02X%02X:%02X%02X:%02X%02X:" - "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd", - a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7], - a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], - p); - } break; - - default: - snprintf(buf, bufLen, - "<unknown sockaddr family %d>", addr.ss_family); - break; - } - } else { - snprintf(buf, bufLen, "<none>"); - } - - buf[bufLen - 1] = 0; -} - -bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1, - const sockaddr_storage& a2, - bool matchAddressOnly) { - if (a1.ss_family != a2.ss_family) - return false; - - switch (a1.ss_family) { - case AF_INET: { - const struct sockaddr_in* sa1 = - reinterpret_cast<const struct sockaddr_in*>(&a1); - const struct sockaddr_in* sa2 = - reinterpret_cast<const struct sockaddr_in*>(&a2); - - if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr) - return false; - - return (matchAddressOnly || (sa1->sin_port == sa2->sin_port)); - } break; - - case AF_INET6: { - const struct sockaddr_in6* sa1 = - reinterpret_cast<const struct sockaddr_in6*>(&a1); - const struct sockaddr_in6* sa2 = - reinterpret_cast<const struct sockaddr_in6*>(&a2); - - if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr))) - return false; - - return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port)); - } break; - - // Huh? We don't deal in non-IPv[46] addresses. Not sure how we got - // here, but we don't know how to comapre these addresses and simply - // default to a no-match decision. - default: return false; - } -} - -bool CommonTimeServer::shouldPanicNotGettingGoodData() { - if (mClient_FirstSyncTX) { - int64_t now = mLocalClock.getLocalTime(); - int64_t delta = now - (mClient_LastGoodSyncRX - ? mClient_LastGoodSyncRX - : mClient_FirstSyncTX); - int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta); - - if (deltaUsec >= kNoGoodDataPanicThresholdUsec) - return true; - } - - return false; -} - -void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) { - txTimes[wrPtr] = txTime; - rxTimes[wrPtr] = 0; - wrPtr = (wrPtr + 1) % RTT_LOG_SIZE; - if (!wrPtr) - logFull = true; -} - -void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) { - if (!logFull && !wrPtr) - return; - - uint32_t i = logFull ? wrPtr : 0; - do { - if (txTimes[i] == txTime) { - rxTimes[i] = rxTime; - break; - } - i = (i + 1) % RTT_LOG_SIZE; - } while (i != wrPtr); -} - -} // namespace android |