blob: 9c906f98be4cc797292dbf646c312bd9cfeaeadb [file] [log] [blame]
/*
*
* 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
* Declarations for the Weave Service Directory Profile and the
* corresponding protocol. See ServiceDirectory.cpp for more
* details and the document:
*
* Nest Weave - Service Directory Protocol
*
* for a protocol description.
*/
#ifndef _WSD_PROFILE_H
#define _WSD_PROFILE_H
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveMessageLayer.h>
#include <Weave/Profiles/ProfileCommon.h>
#include <Weave/Support/NLDLLUtil.h>
#include <Weave/Support/logging/WeaveLogging.h>
#include <Weave/Support/ErrorStr.h>
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
/**
* @namespace nl::Weave::Profiles::ServiceDirectory
*
* @brief
* This namespace includes all interfaces within Weave for the
* Weave Service Directory profile, which includes the
* corresponding, protocol of the same name.
*/
namespace nl {
namespace Weave {
namespace Profiles {
namespace ServiceDirectory {
/**
* Weave message types used in this profile
*
*/
enum
{
kMsgType_ServiceEndpointQuery = 0x00, ///< Service Endpoint Query message type
kMsgType_ServiceEndpointResponse = 0x01 ///< Service Endpoint Response message type
};
enum
{
kConnectRequestPoolSize = 4, ///< the number of simultaneous connect requests
};
/**
* Masks for the control byte of the service endpoint response frame
*
*/
enum
{
kMask_DirectoryLen = 0x0F, ///< Length of the directory
kMask_Redirect = 0x10, ///< Redirect flag
kMask_SuffixTablePresent = 0x20, ///< Suffix table present flag
kMask_TimeFieldsPresent = 0x40, ///< Time fields present flag
};
/**
* Masks and values for the control byte of the directory
* list field of the service endpoint response frame.
*
*/
enum
{
kMask_HostPortListLen = 0x07, ///< Length of the host/port list
kMask_DirectoryEntryType = 0xC0, ///< Entry Type
kDirectoryEntryType_SingleNode = 0x00, ///< A zero value means this entry is a node ID
kDirectoryEntryType_HostPortList = 0x40, ///< This entry is a list of host/port pairs
};
/**
* Masks and values for the control byte in each host/port
* list item
*
*/
enum
{
kMask_HostIdType = 0x03, ///< The type of host ID
kHostIdType_FullyQualified = 0x00, ///< The host ID is all there
kHostIdType_Composite = 0x01, ///< The host ID needs to be matched with a suffix
kMask_SuffixIndexPresent = 0x04, ///< A suffix index is present
kMask_PortIdPresent = 0x08 ///< A port ID is present
};
/**
* Status code
*
*/
enum
{
kStatus_DirectoryUnavailable = 0x0051 ///< Directory is not available
};
/**
* Manager states
*
*/
enum
{
kServiceMgrState_Initial = 0,
kServiceMgrState_Resolving = 1,
kServiceMgrState_Waiting = 2,
kServiceMgrState_Resolved = 3
};
#define kServiceEndpoint_Directory (0x18B4300200000001ull) ///< Directory profile endpoint
#define kServiceEndpoint_SoftwareUpdate (0x18B4300200000002ull) ///< Software update profile endpoint
#define kServiceEndpoint_Data_Management (0x18B4300200000003ull) ///< Core Weave data management protocol endpoint
#define kServiceEndpoint_Log_Upload (0x18B4300200000004ull) ///< Bulk data transfer profile endpoint for log uploads
#define kServiceEndpoint_TimeService (0x18B4300200000005ull) ///< Time service endpoint
#define kServiceEndpoint_ServiceProvisioning (0x18B4300200000010ull) ///< Service provisioning profile endpoint
#define kServiceEndpoint_WeaveTunneling (0x18B4300200000011ull) ///< Weave tunneling endpoint
#define kServiceEndpoint_CoreRouter (0x18B4300200000012ull) ///< Core router endpoint
#define kServiceEndpoint_FileDownload (0x18B4300200000013ull) ///< File download profile endpoint
#define kServiceEndpoint_Bastion (0x18B4300200000014ull) ///< Nest Bastion service endpoint
/**
* @class WeaveServiceManager
*
* @brief The manager object for the Weave service directory.
*
* The Weave service manager is the main interface for
* applications to the directory service. As such, it hides the
* complications inherent in looking up the directory entry
* associated with a service endpoint, doing DNS lookup on one or
* more of the host names found there, attempting to connect,
* securing the connection and so on. It may also manage a cache
* of service directory information.
*/
class NL_DLL_EXPORT WeaveServiceManager
{
public:
/**
* @typedef RootDirectoryAccessor
*
* @brief An accessor function for the root directory info.
*
* You gotta start somewhere and with the service directory
* you gotta start with a stub directory that contains the
* address of a server you can hit to get at everything
* else. Since the disposition and provenance of this
* information is likely to vary from device to device, we
* provide an accessor callback here.
*
* @param [out] aDirectory A pointer to a buffer to write
* the directory information.
*
* @param [in] aLength The length of the given buffer in bytes.
*
* @return #WEAVE_NO_ERROR on success, otherwise the loading process
* would be aborted.
*/
typedef WEAVE_ERROR(*RootDirectoryAccessor)(uint8_t *aDirectory, uint16_t aLength);
/**
* @typedef StatusHandler
*
* @brief A handler for error and status conditions.
*
* A user of the service manager may be informed of problems in trying
* to execute a connect request in one of two ways. It may receive a
* status report from the service or it may recieve an internally
* generated WEAVE_ERROR. In either case, the information comes through
* this callback.
*
* @param [in] anAppState A pointer to an application object that was
* passed in to the corresponding conect() call.
*
* @param [in] anError An Weave error code indicating error happened
* in the process of trying to execute the connect request. This
* shall be #WEAVE_NO_ERROR in the case where no error arose and a
* status report is available.
*
* @param [in] aStatusReport A pointer to a status report generated
* by the remote directory service. This argument shall be NULL in
* the case where there was no status report and an internal error
* is passed in the previous argument.
*
*/
typedef void (*StatusHandler)(void * anAppState, WEAVE_ERROR anError, StatusReport *aStatusReport);
/**
* @typedef OnServiceEndpointQueryEndWithTimeInfo
*
* @brief An application callback to deliver time values from a service
* directory response.
*
* This is called when we get time information from service directory
* query response Note this callback would only happen if a response is
* successfully parsed and time information is included
*
* @param [in] timeQueryReceiptMsec The number of msec since POSIX epoch,
* when the query was received at server side.
*
* @param [in] timeProcessMsec The number of msec spent on processing
* this query.
*/
typedef void (*OnServiceEndpointQueryEndWithTimeInfo)(uint64_t timeQueryReceiptMsec, uint32_t timeProcessMsec);
/**
* @typedef OnServiceEndpointQueryBegin
*
* @brief An application callback to mark the time of an outgoing service
* directory query.
*
* This is called when we are about to send out service endpoint query
* request. This is used to match with OnServiceEndpointQueryEnd to
* compensate for message flight time.
*
*/
typedef void (*OnServiceEndpointQueryBegin)(void);
WeaveServiceManager(void);
~WeaveServiceManager(void);
WEAVE_ERROR init(WeaveExchangeManager *aExchangeMgr,
uint8_t *aCache,
uint16_t aCacheLen,
RootDirectoryAccessor aAccessor,
WeaveAuthMode aDirAuthMode = kWeaveAuthMode_Unauthenticated,
OnServiceEndpointQueryBegin aServiceEndpointQueryBegin = NULL,
OnServiceEndpointQueryEndWithTimeInfo aServiceEndpointQueryEndWithTimeInfo = NULL);
WEAVE_ERROR connect(uint64_t aServiceEp,
WeaveAuthMode aAuthMode,
void *aAppState,
StatusHandler aStatusHandler,
WeaveConnection::ConnectionCompleteFunct aConnectionCompleteHandler,
const uint32_t aConnectTimeoutMsecs = 0,
const InterfaceId aConnectIntf = INET_NULL_INTERFACEID);
WEAVE_ERROR lookup(uint64_t aServiceEp, uint8_t *aControlByte, uint8_t **aDirectoryEntry);
WEAVE_ERROR replaceOrAddCacheEntry(uint16_t port,
const char *hostName,
uint8_t hostLen,
uint64_t serviceEndpointId);
void cancel(uint64_t aServiceEp, void *aAppState);
void unresolve(WEAVE_ERROR aError);
void unresolve(void);
void reset(WEAVE_ERROR aError);
void reset(void);
void relocate(WEAVE_ERROR aError);
void relocate(void);
// Handler methods for the query/response transaction
void onConnectionComplete(WEAVE_ERROR aError);
void onConnectionClosed(WEAVE_ERROR aError);
void onResponseReceived(uint32_t aProfileId, uint8_t aMsgType, PacketBuffer *aMsg);
void onResponseTimeout(void);
// Clear cache and reset state so that the next connect request
// goes to the service directory endpoint first
void clearCache(void);
enum
{
/**
* @brief
* Number of milliseconds a response must be received for the
* directory query before the exchange context times out.
*/
kWeave_DefaultSendTimeout = 15000
};
/**
* @class ConnectRequest
*
* @brief This class represents a single transaction managed by the service manager.
*/
class ConnectRequest
{
public:
WEAVE_ERROR init(WeaveServiceManager *aManager,
const uint64_t &aServiceEp,
WeaveAuthMode aAuthMode,
void *aAppState,
StatusHandler aStatusHandler,
WeaveConnection::ConnectionCompleteFunct aCompleteHandler,
const uint32_t aConnectTimeoutMsecs,
const InterfaceId aConnIntf);
void free(void);
void finalize(void);
/**
* This function tests if this connect request is currently in use to
* connect to a particular service endpoint for a particualr
* application entity.
*
* @param[in] aServiceEp A service endpoint ID to be compared with
* what this connect request holds.
*
* @param[in] aAppState A pointer to application state, which is
* used to compare with what this connect request holds.
*
* @return true if the test passes, false otherwise.
*/
inline bool isAllocatedTo(const uint64_t &aServiceEp, void *aAppState)
{
return (mServiceEp == aServiceEp && mAppState == aAppState);
}
/**
* This function tests if the connect request is not currently
* allocated.
*
* @return true if the test passes, false otherwise.
*/
inline bool isFree(void)
{
return (mServiceEp == 0 && !mAppState);
}
void onConnectionComplete(WEAVE_ERROR aError);
// data members (basically the connect call arguments)
uint64_t mServiceEp;
WeaveAuthMode mAuthMode;
void *mAppState;
/// A connection to stash here while it's awaiting completion.
WeaveConnection *mConnection;
uint32_t mConnectTimeoutMsecs; ///< the timeout for the Connect call to succeed or return an error.
InterfaceId mConnIntf; ///< the interface over which the connection is to be set up.
/// A pointer to a function which would be called when a status report is
/// received.
StatusHandler mStatusHandler;
/// A pointer to a function which would be called when a connection to
/// destination service endpoint has been completed.
WeaveConnection::ConnectionCompleteFunct mConnectionCompleteHandler;
};
private:
struct Extent
{
uint8_t *base;
size_t length;
};
void freeConnectRequests(void);
void finalizeConnectRequests(void);
ConnectRequest *getAvailableRequest(void);
WEAVE_ERROR lookupAndConnect(WeaveConnection *aConnection,
uint64_t aServiceEp,
WeaveAuthMode aAuthMode,
void *aAppState,
WeaveConnection::ConnectionCompleteFunct aHandler,
const uint32_t aConnectTimeoutMsecs = 0,
const InterfaceId aConnectIntf = INET_NULL_INTERFACEID);
WEAVE_ERROR cacheDirectory(MessageIterator &, uint8_t, uint8_t *&);
WEAVE_ERROR cacheSuffixes(MessageIterator &, uint8_t, uint8_t *&);
WEAVE_ERROR calculateEntryLength(uint8_t *entryStart, uint8_t entryCtrlByte, uint16_t *entryLen);
/*
* A group of methods that clear up working state and free
* resources - generally in the case of a failure. one of
* them calls the error handler and the other calls the
* status handler.
*
*/
void fail(WEAVE_ERROR aError);
void transactionsErrorOut(WEAVE_ERROR);
void transactionsReportStatus(StatusReport &aReport);
void cleanupExchangeContext(void);
void cleanupExchangeContext(WEAVE_ERROR aErr);
void clearWorkingState(void);
/**
* This method clears the cache state of the manager including the
* "relocated" flag.
*/
inline void clearCacheState(void)
{
mCacheState = kServiceMgrState_Initial;
mWasRelocated = false;
}
WEAVE_ERROR handleTimeInfo(MessageIterator &itMsg);
// data members
ConnectRequest mConnectRequestPool[kConnectRequestPoolSize];
WeaveExchangeManager *mExchangeManager; ///< the exchange manager to use for everything
WeaveConnection *mConnection; ///< a connection to stash here while it's awaiting completion
ExchangeContext *mExchangeContext; ///< the exchange context specifically for directory profile exchanges
RootDirectoryAccessor mAccessor; ///< how to get at the root directory
Extent mDirectory; ///< the working directory
Extent mSuffixTable; ///< the (optional) suffix table
Extent mCache; ///< all of this stuff needs to be cached somewhere in memory
uint8_t mCacheState; ///< and the state of the cache | initial, resolving, resolved |
bool mWasRelocated; ///< true iff the service manager has been relocated once.
WeaveAuthMode mDirAuthMode; ///< the authentication mode to use when talking to the directory service.
uint32_t mDirAndSuffTableSize; ///< the size of the directory and suffix table in the cache.
/**
* Callback happens right before we send out the service endpoing query request
*/
OnServiceEndpointQueryBegin mServiceEndpointQueryBegin;
/**
* Callback happens right after we receive a service endpoing query response with time
* information
*/
OnServiceEndpointQueryEndWithTimeInfo mServiceEndpointQueryEndWithTimeInfo;
};
}; // ServiceDirectory
}; // Profiles
}; // Weave
}; // nl
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
#endif // _WSD_PROFILE_H