| /* |
| * |
| * Copyright (c) 2013-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * 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. |
| */ |
| |
| /** |
| * @file |
| * This file implements the WeaveExchangeManager class. |
| * |
| */ |
| |
| |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS |
| #endif |
| |
| #ifndef __STDC_LIMIT_MACROS |
| #define __STDC_LIMIT_MACROS |
| #endif |
| |
| #include <Weave/Core/WeaveCore.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include <Weave/Profiles/common/CommonProfile.h> |
| #include <Weave/Profiles/security/WeaveSecurity.h> |
| #include <Weave/Core/WeaveEncoding.h> |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Support/RandUtils.h> |
| #include <Weave/Support/logging/WeaveLogging.h> |
| #include <Weave/Support/WeaveFaultInjection.h> |
| #include <SystemLayer/SystemTimer.h> |
| #include <SystemLayer/SystemStats.h> |
| |
| namespace nl { |
| namespace Weave { |
| |
| using namespace nl::Weave::Profiles; |
| using namespace nl::Weave::Encoding; |
| |
| /** |
| * Constructor for the WeaveExchangeManager class. |
| * It sets the state to kState_NotInitialized. |
| * |
| * @note |
| * The class must be initialized via WeaveExchangeManager::Init() |
| * prior to use. |
| * |
| */ |
| WeaveExchangeManager::WeaveExchangeManager() |
| { |
| State = kState_NotInitialized; |
| } |
| |
| /** |
| * Initialize the WeaveExchangeManager object. Within the lifetime |
| * of this instance, this method is invoked once after object |
| * construction until a call to Shutdown is made to terminate the |
| * instance. |
| * |
| * @param[in] msgLayer A pointer to the WeaveMessageLayer object. |
| * |
| * @retval #WEAVE_ERROR_INCORRECT_STATE If the state is not equal to |
| * kState_NotInitialized. |
| * @retval #WEAVE_NO_ERROR On success. |
| * |
| */ |
| WEAVE_ERROR WeaveExchangeManager::Init(WeaveMessageLayer *msgLayer) |
| { |
| if (State != kState_NotInitialized) |
| return WEAVE_ERROR_INCORRECT_STATE; |
| |
| MessageLayer = msgLayer; |
| FabricState = msgLayer->FabricState; |
| |
| NextExchangeId = GetRandU16(); |
| |
| memset(ContextPool, 0, sizeof(ContextPool)); |
| mContextsInUse = 0; |
| |
| InitBindingPool(); |
| |
| memset(UMHandlerPool, 0, sizeof(UMHandlerPool)); |
| OnExchangeContextChanged = NULL; |
| |
| msgLayer->ExchangeMgr = this; |
| msgLayer->OnMessageReceived = HandleMessageReceived; |
| msgLayer->OnAcceptError = HandleAcceptError; |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mWRMPTimerInterval = WEAVE_CONFIG_WRMP_TIMER_DEFAULT_PERIOD; //WRMP Timer tick period |
| |
| memset(RetransTable, 0, sizeof(RetransTable)); |
| |
| mWRMPTimeStampBase = System::Timer::GetCurrentEpoch(); |
| #endif |
| |
| State = kState_Initialized; |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| /** |
| * Shutdown the WeaveExchangeManager. This terminates this instance |
| * of the object and releases all held resources. |
| * |
| * @note |
| * The application should only call this function after ensuring that |
| * there are no active ExchangeContext objects. Furthermore, it is the |
| * onus of the application to de-allocate the WeaveExchangeManager |
| * object after calling WeaveExchangeManager::Shutdown(). |
| * |
| * @return #WEAVE_NO_ERROR unconditionally. |
| * |
| */ |
| WEAVE_ERROR WeaveExchangeManager::Shutdown() |
| { |
| if (MessageLayer != NULL) |
| { |
| if (MessageLayer->ExchangeMgr == this) |
| { |
| MessageLayer->ExchangeMgr = NULL; |
| MessageLayer->OnMessageReceived = NULL; |
| MessageLayer->OnAcceptError = NULL; |
| } |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| WRMPStopTimer(); |
| |
| //Clear the retransmit table |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| ClearRetransmitTable(RetransTable[i]); |
| } |
| #endif |
| MessageLayer = NULL; |
| } |
| |
| OnExchangeContextChanged = NULL; |
| |
| FabricState = NULL; |
| |
| State = kState_NotInitialized; |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| /** |
| * Creates a new ExchangeContext with a given peer Weave node specified by the peer node identifier. |
| * |
| * @param[in] peerNodeId The node identifier of the peer with which the ExchangeContext is being set up. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @return A pointer to the created ExchangeContext object On success. Otherwise NULL if no object |
| * can be allocated or is available. |
| * |
| */ |
| ExchangeContext *WeaveExchangeManager::NewContext(const uint64_t &peerNodeId, void *appState) |
| { |
| return NewContext(peerNodeId, FabricState->SelectNodeAddress(peerNodeId), WEAVE_PORT, INET_NULL_INTERFACEID, appState); |
| } |
| |
| /** |
| * Creates a new ExchangeContext with a given peer Weave node specified by the peer node identifier |
| * and peer IP address. |
| * |
| * @param[in] peerNodeId The node identifier of the peer with which the ExchangeContext is being set up. |
| * |
| * @param[in] peerAddr The IP address of the peer node. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @return A pointer to the created ExchangeContext object On success. Otherwise, NULL if no object |
| * can be allocated or is available. |
| * |
| */ |
| ExchangeContext *WeaveExchangeManager::NewContext(const uint64_t &peerNodeId, const IPAddress &peerAddr, void *appState) |
| { |
| return NewContext(peerNodeId, peerAddr, WEAVE_PORT, INET_NULL_INTERFACEID, appState); |
| } |
| |
| /** |
| * Creates a new ExchangeContext with a given peer Weave node specified by the peer node identifier, peer IP address, |
| * and destination port on a specified interface. |
| * |
| * @param[in] peerNodeId The node identifier of the peer with which the ExchangeContext is being set up. |
| * |
| * @param[in] peerAddr The IP address of the peer node. |
| * |
| * @param[in] peerPort The port of the peer node. |
| * |
| * @param[in] sendIntfId The interface to use for sending Weave messages on this exchange. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @return A pointer to the created ExchangeContext object On success. Otherwise, NULL if no object |
| * can be allocated or is available. |
| * |
| */ |
| ExchangeContext *WeaveExchangeManager::NewContext(const uint64_t &peerNodeId, const IPAddress &peerAddr, uint16_t peerPort, InterfaceId sendIntfId, void *appState) |
| { |
| ExchangeContext *ec = AllocContext(); |
| if (ec != NULL) |
| { |
| ec->ExchangeId = NextExchangeId++; |
| ec->PeerNodeId = peerNodeId; |
| ec->PeerAddr = peerAddr; |
| ec->PeerPort = (peerPort != 0) ? peerPort : WEAVE_PORT; |
| ec->PeerIntf = sendIntfId; |
| ec->AppState = appState; |
| ec->SetInitiator(true); |
| //Initialize WRMP variables |
| ec->mMsgProtocolVersion = 0; |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // No need to set WRMP timer, this will be done when we add to retrans table |
| ec->mWRMPNextAckTime = 0; |
| ec->SetAckPending(false); |
| ec->SetMsgRcvdFromPeer(false); |
| ec->mWRMPConfig = gDefaultWRMPConfig; |
| ec->mWRMPThrottleTimeout = 0; |
| //Internal and for Debug Only; When set, Exchange Layer does not send Ack. |
| ec->SetDropAck(false); |
| //Initialize the App callbacks to NULL |
| ec->OnThrottleRcvd = NULL; |
| ec->OnDDRcvd = NULL; |
| ec->OnAckRcvd = NULL; |
| ec->OnSendError = NULL; |
| #endif |
| WeaveLogProgress(ExchangeManager, "ec id: %d, AppState: 0x%x", EXCHANGE_CONTEXT_ID(ec - ContextPool), ec->AppState); |
| } |
| return ec; |
| } |
| |
| /** |
| * Creates a new ExchangeContext with a given peer Weave node over a specified WeaveConnection. |
| * |
| * @param[in] con A pointer to the WeaveConnection object representing the TCP connection |
| * with the peer. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @return A pointer to the created ExchangeContext object On success. Otherwise, NULL if no object |
| * can be allocated or is available. |
| * |
| */ |
| ExchangeContext *WeaveExchangeManager::NewContext(WeaveConnection *con, void *appState) |
| { |
| ExchangeContext *ec = NewContext(con->PeerNodeId, con->PeerAddr, con->PeerPort, INET_NULL_INTERFACEID, appState); |
| if (ec != NULL) |
| { |
| ec->Con = con; |
| ec->KeyId = con->DefaultKeyId; |
| ec->EncryptionType = con->DefaultEncryptionType; |
| } |
| return ec; |
| } |
| |
| /** |
| * Find the ExchangeContext from a pool matching a given set of parameters. |
| * |
| * @param[in] peerNodeId The node identifier of the peer with which the ExchangeContext has been set up. |
| * |
| * @param[in] con A pointer to the WeaveConnection object representing the TCP connection |
| * with the peer. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @param[in] isInitiator Boolean indicator of whether the local node is the initiator of the exchange. |
| * |
| * @return A pointer to the ExchangeContext object matching the provided parameters On success, NULL on no match. |
| * |
| */ |
| ExchangeContext *WeaveExchangeManager::FindContext(uint64_t peerNodeId, WeaveConnection *con, void *appState, bool isInitiator) |
| { |
| ExchangeContext *ec = (ExchangeContext *) ContextPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| if (ec->ExchangeMgr != NULL && ec->PeerNodeId == peerNodeId && |
| ec->Con == con && ec->AppState == appState && |
| ec->IsInitiator() == isInitiator) |
| return ec; |
| return NULL; |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier. This handler would be |
| * invoked for all messages of the given profile. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, |
| ExchangeContext::MessageReceiveFunct handler, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) -1, NULL, false, handler, appState); |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier. This handler would be invoked for all messages of the given profile. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] allowDups Boolean indicator of whether duplicate messages are allowed for a given profile. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, |
| ExchangeContext::MessageReceiveFunct handler, bool allowDups, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) -1, NULL, allowDups, handler, appState); |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier and message type. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType, |
| ExchangeContext::MessageReceiveFunct handler, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) msgType, NULL, false, handler, appState); |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier and message type. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] allowDups Boolean indicator of whether duplicate messages are allowed for a given |
| * profile identifier and message type. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType, |
| ExchangeContext::MessageReceiveFunct handler, bool allowDups, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) msgType, NULL, allowDups, handler, appState); |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier, message type on a specified Weave |
| * connection. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @param[in] con A pointer to the WeaveConnection object representing the TCP connection |
| * with the peer. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType, WeaveConnection *con, |
| ExchangeContext::MessageReceiveFunct handler, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) msgType, con, false, handler, appState); |
| } |
| |
| /** |
| * Register an unsolicited message handler for a given profile identifier, message type on a specified Weave |
| * connection. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @param[in] con A pointer to the WeaveConnection object representing the TCP connection |
| * with the peer. |
| * |
| * @param[in] handler The unsolicited message handler. |
| * |
| * @param[in] allowDups Boolean indicator of whether duplicate messages are allowed for a given |
| * profile identifier, message type on a specified Weave connection. |
| * |
| * @param[in] appState A pointer to a higher layer object that holds context state. |
| * |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool |
| * is full and a new one cannot be allocated. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType, WeaveConnection *con, |
| ExchangeContext::MessageReceiveFunct handler, bool allowDups, void *appState) |
| { |
| return RegisterUMH(profileId, (int16_t) msgType, con, allowDups, handler, appState); |
| } |
| |
| /** |
| * Unregister an unsolicited message handler for a given profile identifier. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @retval #WEAVE_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER If the matching unsolicited message handler |
| * is not found. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::UnregisterUnsolicitedMessageHandler(uint32_t profileId) |
| { |
| return UnregisterUMH(profileId, (int16_t) -1, NULL); |
| } |
| |
| /** |
| * Unregister an unsolicited message handler for a given profile identifier and message type. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @retval #WEAVE_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER If the matching unsolicited message handler |
| * is not found. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::UnregisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType) |
| { |
| return UnregisterUMH(profileId, (int16_t) msgType, NULL); |
| } |
| |
| /** |
| * Unregister an unsolicited message handler for a given profile identifier, message type, and Weave connection. |
| * |
| * @param[in] profileId The profile identifier of the received message. |
| * |
| * @param[in] msgType The message type of the corresponding profile. |
| * |
| * @param[in] con A pointer to the WeaveConnection object representing the TCP connection |
| * with the peer. |
| * |
| * @retval #WEAVE_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER If the matching unsolicited message handler |
| * is not found. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR WeaveExchangeManager::UnregisterUnsolicitedMessageHandler(uint32_t profileId, uint8_t msgType, WeaveConnection *con) |
| { |
| return UnregisterUMH(profileId, (int16_t) msgType, con); |
| } |
| |
| void WeaveExchangeManager::HandleAcceptError(WeaveMessageLayer *msgLayer, WEAVE_ERROR err) |
| { |
| WeaveLogError(ExchangeManager, "Accept FAILED, err = %s", ErrorStr(err)); |
| } |
| |
| void WeaveExchangeManager::HandleConnectionReceived(WeaveConnection *con) |
| { |
| // Hook the OnMessageReceived callback for new inbound connections. |
| con->OnMessageReceived = HandleMessageReceived; |
| } |
| |
| void WeaveExchangeManager::HandleConnectionClosed(WeaveConnection *con, WEAVE_ERROR conErr) |
| { |
| ExchangeContext *ec = (ExchangeContext *) ContextPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| if (ec->ExchangeMgr != NULL && ec->Con == con) |
| { |
| ec->SetConnectionClosed(true); |
| ec->Con = NULL; |
| if (ec->OnConnectionClosed != NULL) |
| ec->OnConnectionClosed(ec, con, conErr); |
| } |
| |
| UnsolicitedMessageHandler *umh = (UnsolicitedMessageHandler *) UMHandlerPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++) |
| if (umh->Handler != NULL && umh->Con == con) |
| { |
| SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kExchangeMgr_NumUMHandlers); |
| umh->Handler = NULL; |
| } |
| } |
| |
| /** |
| * Expire the timers started by ExchangeContext instances. |
| * This function is not meant to be used in production code. |
| * |
| * @return Number of timers found running. |
| */ |
| #if WEAVE_CONFIG_TEST |
| size_t WeaveExchangeManager::ExpireExchangeTimers(void) |
| { |
| size_t retval = 0; |
| ExchangeContext *ec = (ExchangeContext *) ContextPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL) |
| { |
| if (ec->ResponseTimeout) |
| { |
| ec->CancelResponseTimer(); |
| ec->ResponseTimeout = 1; |
| ec->StartResponseTimer(); |
| retval++; |
| } |
| } |
| } |
| return retval; |
| } |
| #endif |
| |
| ExchangeContext *WeaveExchangeManager::AllocContext() |
| { |
| ExchangeContext *ec = (ExchangeContext *) ContextPool; |
| |
| WEAVE_FAULT_INJECT(FaultInjection::kFault_AllocExchangeContext, |
| return NULL); |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| if (ec->ExchangeMgr == NULL) |
| { |
| memset(ec, 0, sizeof(ExchangeContext)); |
| ec->ExchangeMgr = this; |
| ec->mRefCount = 1; |
| mContextsInUse++; |
| MessageLayer->SignalMessageLayerActivityChanged(); |
| #if defined(WEAVE_EXCHANGE_CONTEXT_DETAIL_LOGGING) |
| WeaveLogProgress(ExchangeManager, "ec++ id: %d, inUse: %d, addr: 0x%x", EXCHANGE_CONTEXT_ID(ec - ContextPool), mContextsInUse, ec); |
| #endif |
| SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kExchangeMgr_NumContexts); |
| |
| return ec; |
| } |
| WeaveLogError(ExchangeManager, "Alloc ctxt FAILED"); |
| return NULL; |
| } |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| void WeaveExchangeManager::WRMPProcessDDMessage(uint32_t PauseTimeMillis, uint64_t DelayedNodeId) |
| { |
| // Expire any virtual ticks that have expired so all wakeup sources reflect the current time |
| WRMPExpireTicks(); |
| |
| //Go through the retrans table entries for that node and adjust the timer. |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| //Exchcontext is the sentinel object to ascertain validity of the element |
| if (RetransTable[i].exchContext) |
| { |
| //Adjust the retrans timer value if Delayed Node identifier matches Peer in ExchangeContext |
| if (DelayedNodeId == RetransTable[i].exchContext->PeerNodeId) |
| { |
| |
| //Paustime is specified in milliseconds; Update retrans values |
| RetransTable[i].nextRetransTime += (PauseTimeMillis / mWRMPTimerInterval); |
| |
| //Call the application callback |
| if (RetransTable[i].exchContext->OnDDRcvd) |
| { |
| RetransTable[i].exchContext->OnDDRcvd(RetransTable[i].exchContext, |
| PauseTimeMillis); |
| } |
| else |
| { |
| WeaveLogError(ExchangeManager, |
| "No App Handler for Delayed Delivery for ExchangeContext with Id %04" PRIX16, |
| RetransTable[i].exchContext->ExchangeId); |
| |
| } |
| }//DelayedNodeId == PeerNodeId |
| }//exchContext |
| }//for loop in table entry |
| |
| // Schedule next physical wakeup |
| WRMPStartTimer(); |
| } |
| #endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| |
| static void DefaultOnMessageReceived(ExchangeContext *ec, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t profileId, |
| uint8_t msgType, PacketBuffer *payload) |
| { |
| WeaveLogError(ExchangeManager, |
| "Dropping unexpected message %08" PRIX32 ":%d %04" PRIX16 " MsgId:%08" PRIX32, |
| profileId, msgType, ec->ExchangeId, msgInfo->MessageId); |
| |
| PacketBuffer::Free(payload); |
| } |
| |
| void WeaveExchangeManager::DispatchMessage(WeaveMessageInfo *msgInfo, PacketBuffer *msgBuf) |
| { |
| WeaveExchangeHeader exchangeHeader; |
| UnsolicitedMessageHandler *umh = NULL; |
| UnsolicitedMessageHandler *matchingUMH = NULL; |
| ExchangeContext *ec = NULL; |
| WeaveConnection *msgCon = NULL; |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| const uint8_t *p = NULL; |
| uint32_t PauseTimeMillis = 0; |
| uint64_t DelayedNodeId = 0; |
| bool dupMsg; |
| bool msgNeedsAck; |
| bool sendAckAndCloseExchange; |
| #endif |
| #if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC |
| bool isMsgCounterSyncResp; |
| bool peerGroupMsgIdNotSynchronized; |
| #endif |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| // Decode the exchange header. |
| err = DecodeHeader(&exchangeHeader, msgBuf); |
| SuccessOrExit(err); |
| |
| //Check if the version is supported |
| if ((msgInfo->MessageVersion != kWeaveMessageVersion_V1) && |
| (msgInfo->MessageVersion != kWeaveMessageVersion_V2)) |
| { |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_MESSAGE_VERSION); |
| } |
| |
| // Notify Weave Security Manager that encrypted message has been received. |
| if (msgInfo->EncryptionType != kWeaveEncryptionType_None) |
| { |
| MessageLayer->SecurityMgr->OnEncryptedMsgRcvd(msgInfo->KeyId, msgInfo->SourceNodeId, msgInfo->EncryptionType); |
| } |
| |
| msgCon = msgInfo->InCon; |
| |
| #if defined(DEBUG) |
| WeaveLogRetain(ExchangeManager, "Msg %s %08" PRIX32 ":%d %d %016" PRIX64 " %04" PRIX16 " %04" PRIX16 " %ld MsgId:%08" PRIX32, |
| "rcvd", exchangeHeader.ProfileId, exchangeHeader.MessageType, |
| (int)msgBuf->DataLength(), msgInfo->SourceNodeId, msgCon->LogId(), exchangeHeader.ExchangeId, |
| (long)err, msgInfo->MessageId); |
| #else |
| WeaveLogRetain(ExchangeManager, "Msg %s %08" PRIX32 ":%d %d %016" PRIX64 " %04" PRIX16 " %04" PRIX16 " %ld", |
| "rcvd", exchangeHeader.ProfileId, exchangeHeader.MessageType, |
| (int)msgBuf->DataLength(), msgInfo->SourceNodeId, msgCon->LogId(), exchangeHeader.ExchangeId, (long)err); |
| #endif |
| |
| #if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC |
| isMsgCounterSyncResp = exchangeHeader.ProfileId == nl::Weave::Profiles::kWeaveProfile_Security && |
| exchangeHeader.MessageType == nl::Weave::Profiles::Security::kMsgType_MsgCounterSyncResp; |
| peerGroupMsgIdNotSynchronized = (msgInfo->Flags & kWeaveMessageFlag_PeerGroupMsgIdNotSynchronized) != 0; |
| |
| // If received message is a MsgCounterSyncResp process it first. |
| if (isMsgCounterSyncResp) |
| { |
| MessageLayer->SecurityMgr->HandleMsgCounterSyncRespMsg(msgInfo, msgBuf); |
| msgBuf = NULL; |
| } |
| |
| // If message counter synchronization was requested. |
| if ((msgInfo->Flags & kWeaveMessageFlag_MsgCounterSyncReq) != 0) |
| { |
| MessageLayer->SecurityMgr->SendMsgCounterSyncResp(msgInfo, msgInfo->InPacketInfo); |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Retransmit all pending messages that were encrypted with application group key. |
| RetransPendingAppGroupMsgs(msgInfo->SourceNodeId); |
| #endif |
| } |
| // Otherwise, if received message is not MsgCounterSyncResp and peer's message counter synchronization is needed. |
| else if (!isMsgCounterSyncResp && peerGroupMsgIdNotSynchronized) |
| { |
| MessageLayer->SecurityMgr->SendSolitaryMsgCounterSyncReq(msgInfo, msgInfo->InPacketInfo); |
| } |
| |
| // Exit now without error if received MsgCounterSyncResp message. |
| if (isMsgCounterSyncResp) |
| { |
| ExitNow(); |
| } |
| #endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| //Received Delayed Delivery Message: Extend time for pending retrans objects |
| if (exchangeHeader.ProfileId == nl::Weave::Profiles::kWeaveProfile_Common && |
| exchangeHeader.MessageType == nl::Weave::Profiles::Common::kMsgType_WRMP_Delayed_Delivery) |
| { |
| // Process Delayed Delivery message if it is not a duplicate. |
| if ((msgInfo->Flags & kWeaveMessageFlag_DuplicateMessage) == 0) |
| { |
| p = msgBuf->Start(); |
| |
| PauseTimeMillis = LittleEndian::Read32(p); |
| DelayedNodeId = LittleEndian::Read64(p); |
| |
| WRMPProcessDDMessage(PauseTimeMillis, DelayedNodeId); |
| } |
| |
| //Return after processing Delayed Delivery message |
| ExitNow(err = WEAVE_NO_ERROR); |
| }//If delayed delivery Msg |
| #endif |
| |
| // Search for an existing exchange that the message applies to. If a match is found... |
| ec = (ExchangeContext *) ContextPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL && ec->MatchExchange(msgCon, msgInfo, &exchangeHeader)) |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Found a matching exchange. Set flag for correct subsequent WRM |
| // retransmission timeout selection. |
| if (!ec->HasRcvdMsgFromPeer()) |
| { |
| ec->SetMsgRcvdFromPeer(true); |
| } |
| #endif |
| |
| //Matched ExchangeContext; send to message handler. |
| ec->HandleMessage(msgInfo, &exchangeHeader, msgBuf); |
| |
| msgBuf = NULL; |
| |
| ExitNow(err = WEAVE_NO_ERROR); |
| } |
| } |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Is message a duplicate that needs ack. |
| msgNeedsAck = exchangeHeader.Flags & kWeaveExchangeFlag_NeedsAck; |
| dupMsg = (msgInfo->Flags & kWeaveMessageFlag_DuplicateMessage); |
| #endif |
| |
| // Search for an unsolicited message handler if it marked as being sent by an initiator. Since we didn't |
| // find an existing exchange that matches the message, it must be an unsolicited message. However all |
| // unsolicited messages must be marked as being from an initiator. |
| if (exchangeHeader.Flags & kWeaveExchangeFlag_Initiator) |
| { |
| // Search for an unsolicited message handler that can handle the message. Prefer handlers that can explicitly |
| // handle the message type over handlers that handle all messages for a profile. |
| umh = (UnsolicitedMessageHandler *) UMHandlerPool; |
| |
| matchingUMH = NULL; |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++) |
| if (umh->Handler != NULL && umh->ProfileId == exchangeHeader.ProfileId && (umh->Con == NULL || umh->Con == msgCon) |
| && (!(msgInfo->Flags & kWeaveMessageFlag_DuplicateMessage) || umh->AllowDuplicateMsgs)) |
| { |
| if (umh->MessageType == exchangeHeader.MessageType) |
| { |
| matchingUMH = umh; |
| break; |
| } |
| |
| if (umh->MessageType == -1) |
| matchingUMH = umh; |
| } |
| } |
| // Discard the message if it isn't marked as being sent by an initiator and the message is not a duplicate |
| // that needs to send ack to the peer. |
| else |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| if (!msgNeedsAck) |
| #endif |
| ExitNow(err = WEAVE_ERROR_UNSOLICITED_MSG_NO_ORIGINATOR); |
| } |
| |
| // If no existing exchange that the message applies to was found we need to create |
| // a new exchange context (EC) in the following cases: |
| // |
| // (Dup.) Msg | UMH is | Allow | Need Peer | Action |
| // Needs Ack | Found | Dup. | MsgIdSync | |
| // ---------------------------------------------------------------------------------------------------------- |
| // Y | Y | Y | - | Create EC, ec->HandleMessage() sends Dup ack and App callback. |
| // Y | Y | N | N | Create EC; ec->HandleMessage() sends Dup ack; Close EC. |
| // Y | N | - | N | Create EC, ec->HandleMessage() sends Dup ack; Close EC. |
| // N | Y | - | - | Create EC, ec->HandleMessage() sends ack (if needed) and App callback. |
| // N | N | - | - | Do nothing. |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Create new exchange to send ack for a duplicate message and then close this exchange. |
| sendAckAndCloseExchange = msgNeedsAck && (matchingUMH == NULL || (dupMsg && !matchingUMH->AllowDuplicateMsgs)); |
| |
| #if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC |
| // Don't create new EC only to send an ack if Peer's message counter synchronization is required. |
| if (peerGroupMsgIdNotSynchronized) |
| sendAckAndCloseExchange = false; |
| #endif |
| #endif |
| |
| // If we found a handler or we need to open a new exchange to send ack for a duplicate message. |
| if (matchingUMH != NULL |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| || sendAckAndCloseExchange |
| #endif |
| ) |
| { |
| ExchangeContext::MessageReceiveFunct umhandler = NULL; |
| |
| ec = AllocContext(); |
| VerifyOrExit(ec != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| |
| ec->Con = msgCon; |
| ec->ExchangeId = exchangeHeader.ExchangeId; |
| ec->PeerNodeId = msgInfo->SourceNodeId; |
| if (msgInfo->InPacketInfo != NULL) |
| { |
| ec->PeerAddr = msgInfo->InPacketInfo->SrcAddress; |
| ec->PeerPort = msgInfo->InPacketInfo->SrcPort; |
| ec->PeerIntf = msgInfo->InPacketInfo->Interface; |
| } |
| ec->EncryptionType = msgInfo->EncryptionType; |
| ec->KeyId = msgInfo->KeyId; |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // No need to set WRMP timer, this will be done when we add to retrans table |
| ec->mWRMPNextAckTime = 0; |
| ec->SetAckPending(false); |
| ec->SetMsgRcvdFromPeer(true); |
| ec->mWRMPConfig = gDefaultWRMPConfig; |
| ec->mWRMPThrottleTimeout = 0; |
| //Internal and for Debug Only; When set, Exchange Layer does not send Ack. |
| ec->SetDropAck(false); |
| #endif |
| |
| //Set the ExchangeContext version from the Message header version |
| ec->mMsgProtocolVersion = msgInfo->MessageVersion; |
| |
| // If UMH was found and the exchange is created not just for sending ack. |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| if (!sendAckAndCloseExchange) |
| #endif |
| { |
| umhandler = matchingUMH->Handler; |
| |
| ec->SetInitiator(false); |
| ec->AppState = matchingUMH->AppState; |
| ec->OnMessageReceived = DefaultOnMessageReceived; |
| ec->AllowDuplicateMsgs = matchingUMH->AllowDuplicateMsgs; |
| |
| WeaveLogProgress(ExchangeManager, "ec id: %d, AppState: 0x%x", EXCHANGE_CONTEXT_ID(ec - ContextPool), ec->AppState); |
| } |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // If the exchange is created only to send ack. |
| else |
| { |
| // If rcvd msg is from initiator then this exchange is created as not Initiator (argument to SetInitiator() is false). |
| // If rcvd msg is not from initiator then this exchange is created as Initiator (argument to SetInitiator() is true). |
| ec->SetInitiator((exchangeHeader.Flags & kWeaveExchangeFlag_Initiator) == 0); |
| } |
| #endif |
| |
| // Add a reservation for the message encryption key. This will ensure the key is not removed until the exchange is freed. |
| MessageLayer->SecurityMgr->ReserveKey(ec->PeerNodeId, ec->KeyId); |
| |
| // Arrange to automatically release the encryption key when the exchange is freed. |
| ec->SetAutoReleaseKey(true); |
| |
| ec->HandleMessage(msgInfo, &exchangeHeader, msgBuf, umhandler); |
| msgBuf = NULL; |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Close exchange if it was created only to send ack for a duplicate message. |
| if (sendAckAndCloseExchange) |
| ec->Close(); |
| #endif |
| } |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogError(ExchangeManager, "DispatchMessage failed, err = %d", err); |
| } |
| |
| if (msgBuf != NULL) |
| { |
| PacketBuffer::Free(msgBuf); |
| } |
| |
| return; |
| } |
| |
| WEAVE_ERROR WeaveExchangeManager::RegisterUMH(uint32_t profileId, int16_t msgType, WeaveConnection *con, bool allowDups, |
| ExchangeContext::MessageReceiveFunct handler, void *appState) |
| { |
| UnsolicitedMessageHandler *umh = (UnsolicitedMessageHandler *) UMHandlerPool; |
| UnsolicitedMessageHandler *selected = NULL; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++) |
| { |
| if (umh->Handler == NULL) |
| { |
| if (selected == NULL) |
| selected = umh; |
| } |
| else if (umh->ProfileId == profileId && umh->MessageType == msgType && umh->Con == con) |
| { |
| umh->Handler = handler; |
| umh->AppState = appState; |
| return WEAVE_NO_ERROR; |
| } |
| } |
| |
| if (selected == NULL) |
| return WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS; |
| |
| selected->Handler = handler; |
| selected->AppState = appState; |
| selected->ProfileId = profileId; |
| selected->Con = con; |
| selected->MessageType = msgType; |
| selected->AllowDuplicateMsgs = allowDups; |
| |
| SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kExchangeMgr_NumUMHandlers); |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| WEAVE_ERROR WeaveExchangeManager::UnregisterUMH(uint32_t profileId, int16_t msgType, WeaveConnection *con) |
| { |
| UnsolicitedMessageHandler *umh = (UnsolicitedMessageHandler *) UMHandlerPool; |
| for (int i = 0; i < WEAVE_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++) |
| { |
| if (umh->Handler != NULL && umh->ProfileId == profileId && umh->MessageType == msgType && umh->Con == con) |
| { |
| umh->Handler = NULL; |
| SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kExchangeMgr_NumUMHandlers); |
| return WEAVE_NO_ERROR; |
| } |
| } |
| return WEAVE_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER; |
| } |
| |
| void WeaveExchangeManager::HandleMessageReceived(WeaveMessageLayer *msgLayer, WeaveMessageInfo *msgInfo, PacketBuffer *msgBuf) |
| { |
| msgLayer->ExchangeMgr->DispatchMessage(msgInfo, msgBuf); |
| } |
| |
| void WeaveExchangeManager::HandleMessageReceived(WeaveConnection *con, WeaveMessageInfo *msgInfo, PacketBuffer *msgBuf) |
| { |
| con->MessageLayer->ExchangeMgr->DispatchMessage(msgInfo, msgBuf); |
| } |
| |
| WEAVE_ERROR WeaveExchangeManager::PrependHeader(WeaveExchangeHeader *exchangeHeader, PacketBuffer *buf) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| uint16_t headLen = 8; //Constant part: Version/Flags + Msg Type + Exch Id + Profile Id |
| uint8_t *p = NULL; |
| |
| // Make sure the buffer has a reserved size big enough to hold the full Weave header. |
| if (!buf->EnsureReservedSize(WEAVE_HEADER_RESERVE_SIZE)) |
| ExitNow(err = WEAVE_ERROR_BUFFER_TOO_SMALL); |
| |
| // Verify the right application version is selected. |
| if (exchangeHeader->Version != kWeaveExchangeVersion_V1) |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_EXCHANGE_VERSION); |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| //Compute the Header Len |
| if (exchangeHeader->Flags & kWeaveExchangeFlag_AckId) |
| { |
| headLen += 4; |
| } |
| #endif |
| |
| p = buf->Start(); |
| |
| //Move the buffer start pointer back by the size of the app header. |
| p -= headLen; |
| |
| // Adjust the buffer so that the start points to the start of the encoded message. |
| buf->SetStart(p); |
| |
| // Encode the Weave application header |
| Write8(p, ((exchangeHeader->Version << 4) | (exchangeHeader->Flags & 0xF))); |
| Write8(p, exchangeHeader->MessageType); |
| LittleEndian::Write16(p, exchangeHeader->ExchangeId); |
| LittleEndian::Write32(p, exchangeHeader->ProfileId); |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| if (exchangeHeader->Flags & kWeaveExchangeFlag_AckId) |
| { |
| LittleEndian::Write32(p, exchangeHeader->AckMsgId); |
| } |
| #endif |
| |
| WEAVE_FAULT_INJECT_MAX_ARG(FaultInjection::kFault_FuzzExchangeHeaderTx, |
| // The FuzzExchangeHeader function takes as argument an index (0 to n-1) into a |
| // (logical) array of fuzzing cases, because every field of the header can be fuzzed in 3 |
| // different ways. Therefore, the max index that can be used for the |
| // message being sent depends on the number of fields in the header. |
| // There are 4 fields, unless the AckMsgId field is present as |
| // well, for a total of 5. |
| ((exchangeHeader->Flags & kWeaveExchangeFlag_AckId ? |
| WEAVE_FAULT_INJECTION_EXCH_HEADER_NUM_FIELDS : |
| WEAVE_FAULT_INJECTION_EXCH_HEADER_NUM_FIELDS_WRMP) * WEAVE_FAULT_INJECTION_NUM_FUZZ_VALUES) -1, |
| int32_t arg = 0; |
| if (numFaultArgs > 0) |
| { |
| arg = faultArgs[0]; |
| } |
| , |
| // Code executed withouth the Manager's lock: |
| nl::Weave::FaultInjection::FuzzExchangeHeader(buf->Start(), arg); |
| ); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR WeaveExchangeManager::DecodeHeader(WeaveExchangeHeader *exchangeHeader, PacketBuffer *buf) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| uint8_t *p = NULL; |
| uint8_t versionFlags; |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| uint16_t msgLen = buf->DataLength(); |
| uint8_t *msgEnd = buf->Start() + msgLen; |
| #endif |
| |
| if (buf->DataLength() < 8) |
| ExitNow(err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| p = buf->Start(); |
| |
| versionFlags = Read8(p); |
| exchangeHeader->Version = versionFlags >> 4; |
| exchangeHeader->Flags = versionFlags & 0xF; |
| |
| if (exchangeHeader->Version != kWeaveExchangeVersion_V1) |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_EXCHANGE_VERSION); |
| |
| exchangeHeader->MessageType = Read8(p); |
| |
| exchangeHeader->ExchangeId = LittleEndian::Read16(p); |
| |
| exchangeHeader->ProfileId = LittleEndian::Read32(p); |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| if ((exchangeHeader->Flags & kWeaveExchangeFlag_AckId)) |
| { |
| if ((p + 4) > msgEnd) |
| ExitNow(err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| exchangeHeader->AckMsgId = LittleEndian::Read32(p); |
| } |
| #endif |
| |
| buf->SetStart(p); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * Allow unsolicited messages to be received on the specified connection. This |
| * method sets the message reception handler on the given Weave connection. |
| * |
| * @param[in] con A pointer to the Weave connection object. |
| * |
| */ |
| void WeaveExchangeManager::AllowUnsolicitedMessages(WeaveConnection *con) |
| { |
| // Hook the OnMessageReceived callback. |
| con->OnMessageReceived = HandleMessageReceived; |
| } |
| |
| /** |
| * Invoked when a message encryption key has been rejected by a peer (via a KeyError), or a key has |
| * otherwise become invalid (e.g. by ending a session). |
| * |
| * @param[in] peerNodeId The ID of the peer node with which the key is associated. |
| * @param[in] keyId The ID of the key that has failed. |
| * @param[in] keyErr A WEAVE_ERROR representing the reason the key is no longer valid. |
| * |
| */ |
| void WeaveExchangeManager::NotifyKeyFailed(uint64_t peerNodeId, uint16_t keyId, WEAVE_ERROR keyErr) |
| { |
| ExchangeContext *ec = (ExchangeContext *) ContextPool; |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL && ec->KeyId == keyId && ec->PeerNodeId == peerNodeId) |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Ensure the exchange context stays around until we're done with it. |
| ec->AddRef(); |
| |
| // Fail entries matching ec. |
| FailRetransmitTableEntries(ec, keyErr); |
| #endif |
| |
| // Application callback function in key error case. |
| if (ec->OnKeyError) |
| ec->OnKeyError(ec, keyErr); |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| // Release reference to the exchange context. |
| ec->Release(); |
| #endif |
| } |
| } |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_BINDINGS; i++) |
| { |
| BindingPool[i].OnKeyFailed(peerNodeId, keyId, keyErr); |
| } |
| } |
| |
| /** |
| * Invoked when the security manager becomes available for initiating new secure sessions. |
| */ |
| void WeaveExchangeManager::NotifySecurityManagerAvailable() |
| { |
| // Notify each binding that the security manager is now available. |
| // |
| // Note that this algorithm is unfair to bindings that are positioned later in the pool. |
| // In practice, however, this is unlikely to cause any problems. |
| for (int i = 0; i < WEAVE_CONFIG_MAX_BINDINGS; i++) |
| { |
| BindingPool[i].OnSecurityManagerAvailable(); |
| } |
| } |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| /** |
| * Clear MsgCounterSyncReq flag for all pending messages to that peer. |
| * |
| * @param[in] peerNodeId Node ID of the destination node. |
| * |
| */ |
| void WeaveExchangeManager::ClearMsgCounterSyncReq(uint64_t peerNodeId) |
| { |
| RetransTableEntry *re = (RetransTableEntry *) RetransTable; |
| |
| // Find all retransmit entries (re) matching peerNodeId and using application group key. |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++, re++) |
| { |
| if (re->exchContext != NULL && re->exchContext->PeerNodeId == peerNodeId && WeaveKeyId::IsAppGroupKey(re->exchContext->KeyId)) |
| { |
| // Clear MsgCounterSyncReq flag. |
| uint16_t headerField = LittleEndian::Get16(re->msgBuf->Start()); |
| headerField &= ~kWeaveMessageFlag_MsgCounterSyncReq; |
| LittleEndian::Put16(re->msgBuf->Start(), headerField); |
| } |
| } |
| } |
| |
| /** |
| * Retransmit all pending messages that were encrypted with application |
| * group key and were addressed to the specified node. |
| * |
| * @param[in] peerNodeId Node ID of the destination node. |
| * |
| */ |
| void WeaveExchangeManager::RetransPendingAppGroupMsgs(uint64_t peerNodeId) |
| { |
| RetransTableEntry *re = (RetransTableEntry *) RetransTable; |
| |
| // Find all retransmit entries (re) matching peerNodeId and using application group key. |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++, re++) |
| { |
| if (re->exchContext != NULL && re->exchContext->PeerNodeId == peerNodeId && WeaveKeyId::IsAppGroupKey(re->exchContext->KeyId)) |
| { |
| // Decrement counter to discount the first sent message, which |
| // was ignored by receiver due to un-synchronized message counter. |
| re->sendCount--; |
| |
| // Retramsmit message. |
| SendFromRetransTable(re); |
| } |
| } |
| } |
| |
| /** |
| * Return a tick counter value given a time difference and a tick interval. |
| * The difference in time is not expected to exceed (2^32 - 1) within the |
| * scope of two timestamp comparisons in WRMP and, thus, it makes sense to cast |
| * the time delta to uint32_t. This also avoids invocation of 64 bit divisions |
| * in constrained platforms that do not support them. |
| * |
| * @param[in] newTime Timestamp value of in milliseconds. |
| * @param[in] oldTime Timestamp value of in milliseconds. |
| * @param[in] tickInterval Timer tick interval in milliseconds. |
| * |
| * @return Tick count for the time delta. |
| */ |
| uint32_t WeaveExchangeManager::GetTickCounterFromTimeDelta (uint64_t newTime, |
| uint64_t oldTime) |
| { |
| uint32_t timeDelta = static_cast<uint32_t>(newTime - oldTime); |
| |
| return (timeDelta / mWRMPTimerInterval); |
| } |
| |
| #if defined(WRMP_TICKLESS_DEBUG) |
| void WeaveExchangeManager::TicklessDebugDumpRetransTable(const char *log) |
| { |
| WeaveLogProgress(ExchangeManager, log); |
| |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| if (RetransTable[i].exchContext) |
| { |
| WeaveLogProgress(ExchangeManager, "EC:%04" PRIX16 " MsgId:%08" PRIX32 " NextRetransTimeCtr:%04" PRIX16, |
| RetransTable[i].exchContext, |
| RetransTable[i].msgId, |
| RetransTable[i].nextRetransTime); |
| } |
| } |
| } |
| #else |
| void WeaveExchangeManager::TicklessDebugDumpRetransTable(const char *log) { return; } |
| #endif // WRMP_TICKLESS_DEBUG |
| |
| /** |
| * Iterate through active exchange contexts and retrans table entries. |
| * If an action needs to be triggered by WRMP time facilities, execute |
| * that action. |
| * |
| */ |
| void WeaveExchangeManager::WRMPExecuteActions(void) |
| { |
| ExchangeContext *ec = NULL; |
| |
| //Process Ack Tables for all ExchangeContexts |
| ec = (ExchangeContext *)ContextPool; |
| |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExecuteActions"); |
| #endif |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL && ec->IsAckPending()) |
| { |
| if (0 == ec->mWRMPNextAckTime) |
| { |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExecuteActions sending ACK"); |
| #endif |
| //Send the Ack in a Common::Null message |
| ec->SendCommonNullMessage(); |
| ec->SetAckPending(false); |
| } |
| } |
| } |
| |
| TicklessDebugDumpRetransTable("WRMPExecuteActions Dumping RetransTable entries before processing"); |
| |
| // Retransmit / cancel anything in the retrans table whose retrans timeout |
| // has expired |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| ec = RetransTable[i].exchContext; |
| if (ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| if (0 == RetransTable[i].nextRetransTime) |
| { |
| uint8_t sendCount = RetransTable[i].sendCount; |
| void * msgCtxt = RetransTable[i].msgCtxt; |
| |
| if (sendCount > ec->mWRMPConfig.mMaxRetrans) |
| { |
| err = WEAVE_ERROR_MESSAGE_NOT_ACKNOWLEDGED; |
| |
| WeaveLogError(ExchangeManager, "Failed to Send Weave MsgId:%08" PRIX32 " sendCount: %" PRIu8 " max retries: %" PRIu8, |
| RetransTable[i].msgId, sendCount, ec->mWRMPConfig.mMaxRetrans); |
| |
| // Remove from Table |
| ClearRetransmitTable(RetransTable[i]); |
| } |
| |
| if (err == WEAVE_NO_ERROR) |
| { |
| // Resend from Table (if the operation fails, the entry is cleared) |
| err = SendFromRetransTable(&(RetransTable[i])); |
| } |
| |
| if (err == WEAVE_NO_ERROR) |
| { |
| // If the retransmission was successful, update the passive timer |
| RetransTable[i].nextRetransTime = ec->GetCurrentRetransmitTimeout() / mWRMPTimerInterval; |
| #if defined(DEBUG) |
| WeaveLogProgress(ExchangeManager, "Retransmit MsgId:%08" PRIX32 " Send Cnt %d", |
| RetransTable[i].msgId, RetransTable[i].sendCount); |
| #endif |
| } |
| |
| if (err != WEAVE_NO_ERROR) |
| { |
| if (ec->OnSendError) |
| { |
| ec->OnSendError(ec, err, msgCtxt); |
| } |
| } |
| } //nextRetransTime = 0 |
| } |
| } |
| |
| TicklessDebugDumpRetransTable("WRMPExecuteActions Dumping RetransTable entries after processing"); |
| } |
| |
| /** |
| * Calculate number of virtual WRMP ticks that have expired since we last |
| * called this function. Iterate through active exchange contexts and |
| * retrans table entries, subtracting expired virtual ticks to synchronize |
| * wakeup times with the current system time. Do not perform any actions |
| * beyond updating tick counts, actions will be performed by the physical |
| * WRMP timer tick expiry. |
| * |
| */ |
| void WeaveExchangeManager::WRMPExpireTicks(void) |
| { |
| uint64_t now = 0; |
| ExchangeContext* ec = NULL; |
| uint16_t deltaTicks; |
| |
| //Process Ack Tables for all ExchangeContexts |
| ec = (ExchangeContext *)ContextPool; |
| |
| now = System::Timer::GetCurrentEpoch(); |
| |
| // Number of full ticks elapsed since last timer processing. We always round down |
| // to the previous tick. If we are between tick boundaries, the extra time since the |
| // last virtual tick is not accounted for here (it will be accounted for when resetting |
| // the WRMP timer) |
| deltaTicks = GetTickCounterFromTimeDelta(now, mWRMPTimeStampBase); |
| |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExpireTicks at %" PRIu64 ", %" PRIu64 ", %u", now, mWRMPTimeStampBase, deltaTicks); |
| #endif |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL && ec->IsAckPending()) |
| { |
| //Decrement counter of Ack timestamp by the elapsed timer ticks |
| if (ec->mWRMPNextAckTime >= deltaTicks) |
| { |
| ec->mWRMPNextAckTime -= deltaTicks; |
| } |
| else |
| { |
| ec->mWRMPNextAckTime = 0; |
| } |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExpireTicks set mWRMPNextAckTime to %u", ec->mWRMPNextAckTime); |
| #endif |
| } |
| } |
| |
| //Process Throttle Time |
| //Check Throttle timeout stored in EC to set/unset Throttle flag |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| ec = RetransTable[i].exchContext; |
| if (ec) |
| { |
| //Process Retransmit Table |
| //Decrement Throttle timeout by elapsed timeticks |
| if (ec->mWRMPThrottleTimeout >= deltaTicks) |
| { |
| ec->mWRMPThrottleTimeout -= deltaTicks; |
| } |
| else |
| { |
| ec->mWRMPThrottleTimeout = 0; |
| } |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExpireTicks set mWRMPThrottleTimeout to %u", RetransTable[i].nextRetransTime); |
| #endif |
| |
| //Decrement Retransmit timeout by elapsed timeticks |
| if (RetransTable[i].nextRetransTime >= deltaTicks) |
| { |
| RetransTable[i].nextRetransTime -= deltaTicks; |
| } |
| else |
| { |
| RetransTable[i].nextRetransTime = 0; |
| } |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExpireTicks set nextRetransTime to %u", RetransTable[i].nextRetransTime); |
| #endif |
| } //ec entry is allocated |
| } |
| |
| // Re-Adjust the base time stamp to the most recent tick boundary |
| |
| // Note on math: because we're really multiplying two 16-bit |
| // unsigned numbers, we know that the result will fit in a 32-bit |
| // unsigned without overflow. Consequently, casting operands to |
| // 32-bit, and performing 32-bit multiplication is correct. |
| mWRMPTimeStampBase += static_cast<uint64_t>( static_cast<uint32_t>(deltaTicks) * static_cast<uint32_t>(mWRMPTimerInterval)); |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPExpireTicks mWRMPTimeStampBase to %" PRIu64, mWRMPTimeStampBase); |
| #endif |
| } |
| |
| /** |
| * Handle physical wakeup of system due to WRMP wakeup. |
| * |
| */ |
| void WeaveExchangeManager::WRMPTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError) |
| { |
| WeaveExchangeManager* exchangeMgr = reinterpret_cast<WeaveExchangeManager*>(aAppState); |
| |
| VerifyOrDie((aSystemLayer != NULL) && (exchangeMgr != NULL)); |
| |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPTimeout\n"); |
| #endif |
| |
| // Make sure all tick counts are sync'd to the current time |
| exchangeMgr->WRMPExpireTicks(); |
| |
| // Execute any actions that are due this tick |
| exchangeMgr->WRMPExecuteActions(); |
| |
| // Calculate next physical wakeup |
| exchangeMgr->WRMPStartTimer(); |
| } |
| |
| /** |
| * Add a Weave message into the retransmission table to be subsequently resent if a corresponding acknowledgment |
| * is not received within the retransmission timeout. |
| * |
| * @param[in] ec A pointer to the ExchangeContext object. |
| * |
| * @param[in] msgBuf A pointer to the message buffer holding the Weave message to be retransmitted. |
| * |
| * @param[in] messageId The message identifier of the stored Weave message. |
| * |
| * @param[in] msgCtxt A pointer to some application specific context object pertaining to this message. |
| * |
| * @param[out] rEntry A pointer to a pointer of a retransmission table entry added into the table. |
| * |
| * @retval #WEAVE_ERROR_RETRANS_TABLE_FULL If there is no empty slot left in the table for addition. |
| * @retval #WEAVE_NO_ERROR On success. |
| * |
| */ |
| WEAVE_ERROR WeaveExchangeManager::AddToRetransTable(ExchangeContext *ec, PacketBuffer *msgBuf, uint32_t messageId, void *msgCtxt, RetransTableEntry **rEntry) |
| { |
| bool added = false; |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| //Check the exchContext pointer for finding an empty slot in Table |
| if (!RetransTable[i].exchContext) |
| { |
| // Expire any virtual ticks that have expired so all wakeup sources reflect the current time |
| WRMPExpireTicks(); |
| |
| RetransTable[i].exchContext = ec; |
| RetransTable[i].msgId = messageId; |
| RetransTable[i].msgBuf = msgBuf; |
| RetransTable[i].sendCount = 0; |
| RetransTable[i].nextRetransTime = GetTickCounterFromTimeDelta(ec->GetCurrentRetransmitTimeout() + System::Timer::GetCurrentEpoch(), mWRMPTimeStampBase); |
| |
| RetransTable[i].msgCtxt = msgCtxt; |
| *rEntry = &RetransTable[i]; |
| //Increment the reference count |
| ec->AddRef(); |
| added = true; |
| |
| //Check if the timer needs to be started and start it. |
| WRMPStartTimer(); |
| break; |
| } |
| } |
| |
| if (!added) |
| { |
| WeaveLogError(ExchangeManager, "RetransTable Already Full"); |
| err = WEAVE_ERROR_RETRANS_TABLE_FULL; |
| } |
| |
| return err; |
| } |
| |
| /** |
| * Send the specified entry from the retransmission table. |
| * |
| * @param[in] entry A pointer to a retransmission table entry object that needs to be sent. |
| * |
| * @return #WEAVE_NO_ERROR On success, else corresponding WEAVE_ERROR returned from SendMessage. |
| * |
| */ |
| WEAVE_ERROR WeaveExchangeManager::SendFromRetransTable(RetransTableEntry *entry) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| uint16_t msgSendFlags = 0; |
| uint8_t *p = NULL; |
| uint32_t len = 0; |
| ExchangeContext *ec = entry->exchContext; |
| |
| // To trigger a call to OnSendError, set the number of transmissions so |
| // that the next call to WRMPExecuteActions will abort this entry, |
| // restart the timer immediately, and ExitNow. |
| |
| WEAVE_FAULT_INJECT(FaultInjection::kFault_WRMSendError, |
| entry->sendCount = (ec->mWRMPConfig.mMaxRetrans + 1); |
| entry->nextRetransTime = 0; |
| WRMPStartTimer(); |
| ExitNow()); |
| |
| if (ec) |
| { |
| msgSendFlags |= kWeaveMessageFlag_RetainBuffer; |
| //Locally store the start and length; |
| p = entry->msgBuf->Start(); |
| len = entry->msgBuf->DataLength(); |
| |
| //Send the message through |
| err = MessageLayer->SendMessage(ec->PeerAddr, ec->PeerPort, ec->PeerIntf, |
| entry->msgBuf, |
| msgSendFlags); |
| //Reset the msgBuf start pointer and data length after sending |
| entry->msgBuf->SetStart(p); |
| entry->msgBuf->SetDataLength(len); |
| |
| //Update the counters |
| entry->sendCount++; |
| } |
| else |
| { |
| WeaveLogError(ExchangeManager, "Table entry invalid"); |
| } |
| |
| VerifyOrExit(err != WEAVE_NO_ERROR, err = WEAVE_NO_ERROR); |
| |
| //Any error generated during initial sending is evaluated for criticality which would |
| //qualify it to be reportable back to the caller. If it is non-critical then |
| //err is set to WEAVE_NO_ERROR. |
| if (WeaveMessageLayer::IsSendErrorNonCritical(err)) |
| { |
| WeaveLogError(ExchangeManager, "Non-crit err %ld sending Weave MsgId:%08" PRIX32 " from retrans table", |
| long(err), entry->msgId); |
| err = WEAVE_NO_ERROR; |
| } |
| else |
| { |
| //Remove from table |
| WeaveLogError(ExchangeManager, "Crit-err %ld when sending Weave MsgId:%08" PRIX32 ", send tries: %d", |
| long(err), entry->msgId, entry->sendCount); |
| |
| ClearRetransmitTable(*entry); |
| } |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * Clear entries matching a specified ExchangeContext. |
| * |
| * @param[in] ec A pointer to the ExchangeContext object. |
| * |
| */ |
| void WeaveExchangeManager::ClearRetransmitTable(ExchangeContext *ec) |
| { |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| if (RetransTable[i].exchContext == ec) |
| { |
| //Clear the retransmit table entry. |
| ClearRetransmitTable(RetransTable[i]); |
| } |
| } |
| } |
| |
| /** |
| * Clear an entry in the retransmission table. |
| * |
| * @param[in] rEntry A reference to the RetransTableEntry object. |
| * |
| */ |
| void WeaveExchangeManager::ClearRetransmitTable(RetransTableEntry &rEntry) |
| { |
| if (rEntry.exchContext) |
| { |
| // Expire any virtual ticks that have expired so all wakeup sources reflect the current time |
| WRMPExpireTicks(); |
| |
| rEntry.exchContext->Release(); |
| rEntry.exchContext = NULL; |
| |
| if (rEntry.msgBuf) |
| { |
| PacketBuffer::Free(rEntry.msgBuf); |
| rEntry.msgBuf = NULL; |
| } |
| |
| // Clear all other fields |
| memset(&rEntry, 0, sizeof(rEntry)); |
| |
| // Schedule next physical wakeup |
| WRMPStartTimer(); |
| |
| } |
| } |
| |
| /** |
| * Fail entries matching a specified ExchangeContext. |
| * |
| * @param[in] ec A pointer to the ExchangeContext object. |
| * |
| * @param[in] err The error for failing table entries. |
| * |
| */ |
| void WeaveExchangeManager::FailRetransmitTableEntries(ExchangeContext *ec, WEAVE_ERROR err) |
| { |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| if (RetransTable[i].exchContext == ec) |
| { |
| void *msgCtxt = RetransTable[i].msgCtxt; |
| |
| // Remove the entry from the retransmission table. |
| ClearRetransmitTable(RetransTable[i]); |
| |
| // Application callback OnSendError. |
| if (ec->OnSendError) |
| ec->OnSendError(ec, err, msgCtxt); |
| } |
| } |
| } |
| |
| /** |
| * Iterate through active exchange contexts and retrans table entries. |
| * Determine how many WRMP ticks we need to sleep before we need to physically |
| * wake the CPU to perform an action. Set a timer to go off when we |
| * next need to wake the system. |
| * |
| */ |
| void WeaveExchangeManager::WRMPStartTimer() |
| { |
| WEAVE_ERROR res = WEAVE_NO_ERROR; |
| uint32_t nextWakeTime = UINT32_MAX; |
| bool foundWake = false; |
| ExchangeContext *ec = NULL; |
| |
| // Stop any active timers, we are about to set a new timer |
| // based on the most up to date contents of the retrans |
| // table |
| WRMPStopTimer(); |
| |
| // When do we need to next wake up to send an ACK? |
| ec = (ExchangeContext *)ContextPool; |
| |
| for (int i = 0; i < WEAVE_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++) |
| { |
| if (ec->ExchangeMgr != NULL && ec->IsAckPending() && ec->mWRMPNextAckTime < nextWakeTime) { |
| nextWakeTime = ec->mWRMPNextAckTime; |
| foundWake = true; |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPStartTimer next ACK time %u", nextWakeTime); |
| #endif |
| } |
| } |
| |
| for (int i = 0; i < WEAVE_CONFIG_WRMP_RETRANS_TABLE_SIZE; i++) |
| { |
| ec = RetransTable[i].exchContext; |
| if (ec) |
| { |
| // When do we need to next wake up for throttle retransmission? |
| if (ec->mWRMPThrottleTimeout != 0 && ec->mWRMPThrottleTimeout < nextWakeTime) { |
| nextWakeTime = ec->mWRMPThrottleTimeout; |
| foundWake = true; |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPStartTimer throttle timeout %u", nextWakeTime); |
| #endif |
| } |
| |
| // When do we need to next wake up for WRMP retransmit? |
| if (RetransTable[i].nextRetransTime < nextWakeTime) { |
| nextWakeTime = RetransTable[i].nextRetransTime; |
| foundWake = true; |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "WRMPStartTimer RetransTime %u", nextWakeTime); |
| #endif |
| } |
| } |
| } |
| |
| if (foundWake) { |
| // Set timer for next tick boundary - subtract the elapsed time from the current tick |
| int32_t timerArmValue = nextWakeTime * mWRMPTimerInterval - (System::Timer::GetCurrentEpoch() - mWRMPTimeStampBase); |
| #if defined(WRMP_TICKLESS_DEBUG) |
| WeaveLogProgress(ExchangeManager, "Setting WRMP timer for %d ms (%u %" PRIu64 " %" PRIu64 ")", |
| timerArmValue, |
| nextWakeTime, System::Timer::GetCurrentEpoch(), mWRMPTimeStampBase); |
| #endif |
| // If the tick boundary has expired in the past (delayed processing of event due to other system activity), |
| // expire the timer immediately |
| if (timerArmValue < 0) { |
| timerArmValue = 0; |
| } |
| res = MessageLayer->SystemLayer->StartTimer((uint32_t)timerArmValue, WRMPTimeout, this); |
| |
| VerifyOrDieWithMsg(res == WEAVE_NO_ERROR, ExchangeManager, "Cannot start WRMPTimeout\n"); |
| #if defined(WRMP_TICKLESS_DEBUG) |
| } else { |
| WeaveLogProgress(ExchangeManager, "Not setting WRMP timeout at %" PRIu64, System::Timer::GetCurrentEpoch()); |
| #endif |
| } |
| |
| TicklessDebugDumpRetransTable("WRMPStartTimer Dumping RetransTable entries after setting wakeup times"); |
| |
| } |
| |
| void WeaveExchangeManager::WRMPStopTimer() |
| { |
| MessageLayer->SystemLayer->CancelTimer(WRMPTimeout, this); |
| } |
| #endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| |
| /** |
| * Initialize the shared pool of Bindings. |
| * |
| */ |
| void WeaveExchangeManager::InitBindingPool(void) |
| { |
| memset(BindingPool, 0, sizeof(BindingPool)); |
| for (size_t i = 0; i < WEAVE_CONFIG_MAX_BINDINGS; ++i) |
| { |
| BindingPool[i].mState = Binding::kState_NotAllocated; |
| BindingPool[i].mExchangeManager = this; |
| } |
| mBindingsInUse = 0; |
| } |
| |
| /** |
| * Allocate a new Binding |
| * |
| * @retval A pointer to the newly allocated Binding, or NULL if the pool has been exhausted |
| * |
| */ |
| Binding * WeaveExchangeManager::AllocBinding(void) |
| { |
| Binding * pResult = NULL; |
| |
| WEAVE_FAULT_INJECT(FaultInjection::kFault_AllocBinding, |
| return NULL); |
| |
| for (size_t i = 0; i < WEAVE_CONFIG_MAX_BINDINGS; ++i) |
| { |
| if (Binding::kState_NotAllocated == BindingPool[i].mState) |
| { |
| pResult = &BindingPool[i]; |
| ++mBindingsInUse; |
| SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kWDMNext_NumBindings); |
| break; |
| } |
| } |
| |
| return pResult; |
| } |
| |
| /** |
| * Deallocate the binding object so it could be reused later |
| * |
| * @param[in] binding A pointer to the binding object to be deallocated. The object |
| * must be previously allocated from this #WeaveExchangeManager. |
| * |
| */ |
| void WeaveExchangeManager::FreeBinding(Binding * binding) |
| { |
| binding->mState = Binding::kState_NotAllocated; |
| --mBindingsInUse; |
| SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kWDMNext_NumBindings); |
| } |
| |
| /** |
| * Allocate a new Binding with the arguments supplied |
| * |
| * @param[in] eventCallback A function pointer to be used for event callback |
| * @param[in] appState A pointer to some context which would be carried in event callback later |
| * |
| * @retval A pointer to the newly allocated Binding, or NULL if the pool has been exhausted |
| * |
| */ |
| Binding * WeaveExchangeManager::NewBinding(Binding::EventCallback eventCallback, void *appState) |
| { |
| Binding * pResult = AllocBinding(); |
| if (NULL != pResult) |
| { |
| pResult->Init(appState, eventCallback); |
| } |
| return pResult; |
| } |
| |
| /** |
| * Get an ID suitable for identifying a binding in log messages. |
| * |
| * @param[in] binding A pointer to a Binding object |
| * |
| * @retval An unsigned integer identifying the binding |
| * |
| */ |
| uint16_t WeaveExchangeManager::GetBindingLogId(const Binding * const binding) const |
| { |
| // note that the result of pointer subtraction should be ptrdiff_t |
| return static_cast<uint16_t>(binding - BindingPool); |
| } |
| |
| } // namespace nl |
| } // namespace Weave |