blob: 0d78186c5ce9639cb16c8efca0c7d94bcbeeecce [file] [log] [blame]
/*
*
* Copyright (c) 2016-2018 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
* Defines the Weave Binding class and its supporting types.
*
*/
// Include WeaveCore.h OUTSIDE of the include guard for WeaveBinding.h.
// This allows WeaveCore.h to enforce a canonical include order for core
// header files, making it easier to manage dependencies between these files.
#include <Weave/Core/WeaveCore.h>
#ifndef WEAVE_BINDING_H_
#define WEAVE_BINDING_H_
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif // __STDC_FORMAT_MACROS
#include <Weave/Core/WeaveWRMPConfig.h>
namespace nl {
namespace Weave {
class WeaveExchangeManager;
class ExchangeContext;
class WeaveSecurityManager;
namespace Profiles {
namespace StatusReporting {
class StatusReport;
}
namespace Security {
namespace TAKE {
class WeaveTAKEChallengerAuthDelegate;
}
}
}
/**
* @class Binding
*
* @brief
* Captures the intended target of a Weave communication and associated configuration
* information.
*
* A Binding object identifies the intended target of a Weave communication (also known as the
* "peer"), along with a set of configuration parameters describing how communication with the
* peer should take place. Bindings are independent of the application protocol being spoken
* between the two parties. As such, they capture the "who" and the "how" of a communication,
* but not the "what."
*
* ## Configuration
*
* Applications must configure a Binding with parameters specific to the type of communication
* channel desired. Bindings provide support for a range of network transports, including
* TCP, UDP, UDP with Weave Reliable Messaging, and Weave over BLE (WoBLE). Applications can
* also request the use of specific security mechanisms to protect messages sent between the
* parties. These include CASE and PASE sessions, and application group keys. The interface for
* configuring a Binding uses a declarative API style that allows applications to state their
* requirements for the communication in simple terms.
*
* See the documentation for Binding::Configuration for further details.
*
* ## Preparation
*
* Prior to communication taking place, a Binding must be "prepared." The act of preparing a
* Binding involves establishing the necessary state for communication to take place. This can
* include things such as: resolving the network address of the peer, establishing a network
* connection, and negotiating security keys. Once configured by the application, the Binding
* takes care of all the steps necessary to prepare for communication, calling back to the
* application when the process is complete. In this way, Bindings hide the mechanics of
* communication, allowing applications to concentrate on the high-level interactions.
*
* ## Communication
*
* Once a Binding has been prepared it becomes ready for use. In this state, applications (or
* more commonly, protocol layer code working on behalf of an application) request the Binding
* to allocate a Weave exchange context. The resultant exchange context comes pre-configured
* for communication, allowing the application to immediately initiate a Weave exchange with
* the peer. The application can continue to request exchange contexts from the Binding until
* such time as the Binding is closed, or some event, e.g., a network failure, terminates the
* underlying communication channel.
*
* ## Binding State Changes
*
* Over the course of its use, a Binding will deliver API events to the application informing it
* of changes in the Binding's state. For example, when preparation succeeds, the application
* will receive an event informing it that the Binding is ready for use. Similarly, if the
* underlying communication channel fails, an event is delivered to the application informing
* it that the Binding is no longer in the ready state.
*
* API events are delivered to the application via an event callback function supplied when
* the Binding is allocated.
*
* ## Binding Lifetime
*
* Binding are reference counted to allow shared use across multiple software components.
* When a Binding is allocated, a single reference to the binding is created. The application
* is responsible for releasing this reference at some point in the future such that the
* Binding is free for subsequent reuse.
*
* When an application is done with a Binding it may call Close() on the binding. This
* releases the application's reference to the Binding and blocks all further delivery of API
* events. When the last reference to a Binding is released, it is automatically closed.
*
*/
class Binding
{
public:
class Configuration;
struct InEventParam;
struct OutEventParam;
enum State
{
kState_NotAllocated = 0,
kState_NotConfigured = 1,
kState_Configuring = 2,
kState_Preparing = 3,
kState_PreparingAddress = 4,
kState_PreparingAddress_ResolveHostName = 5,
kState_PreparingTransport = 6,
kState_PreparingTransport_TCPConnect = 7,
kState_PreparingSecurity = 8,
kState_PreparingSecurity_EstablishSession = 9,
kState_PreparingSecurity_WaitSecurityMgr = 10,
kState_Ready = 11,
kState_Resetting = 12,
kState_Closed = 13,
kState_Failed = 14,
kState_MaxState = 15, // limited to 4 bits
};
enum EventType
{
kEvent_ConnectionEstablished = 1, ///< The requested Weave connection has been established.
kEvent_BindingReady = 2, ///< The prepare action on the binding succeeded and the binding may now be used to communicate with the peer.
kEvent_PrepareFailed = 3, ///< The prepare action on the binding failed.
kEvent_BindingFailed = 4, ///< The binding failed and can no longer be used to communicate with the peer.
kEvent_PrepareRequested = 5, ///< The application is requested to configure and prepare the binding for use by the network stack.
kEvent_PASEParametersRequested = 6, ///< The application is requested to supply parameters to be used during PASE session establishment.
kEvent_TAKEParametersRequested = 7, ///< The application is requested to supply parameters to be used during TAKE session establishment.
kEvent_DefaultCheck = 100, ///< Used to verify correct default event handling in the application.
};
typedef void (*EventCallback)(void *apAppState, EventType aEvent, const InEventParam& aInParam, OutEventParam& aOutParam);
void *AppState;
void AddRef(void);
void Release(void);
void Close(void);
void Reset(void);
Configuration BeginConfiguration();
WEAVE_ERROR RequestPrepare();
State GetState(void) const;
bool IsPreparing(void) const;
bool IsReady(void) const;
bool CanBePrepared(void) const;
uint16_t GetLogId(void) const;
uint64_t GetPeerNodeId(void) const;
void GetPeerIPAddress(nl::Inet::IPAddress & address, uint16_t & port, InterfaceId & interfaceId) const;
uint32_t GetKeyId(void) const;
uint8_t GetEncryptionType(void) const;
uint32_t GetDefaultResponseTimeout() const;
void SetDefaultResponseTimeout(uint32_t msec);
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
const WRMPConfig& GetDefaultWRMPConfig(void) const;
void SetDefaultWRMPConfig(const WRMPConfig& wrmpConfig);
#endif // #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
EventCallback GetEventCallback() const;
void SetEventCallback(EventCallback aEventCallback);
WeaveConnection *GetConnection() const;
WeaveExchangeManager *GetExchangeManager() const;
bool IsConnectionTransport() const;
bool IsUDPTransport() const;
bool IsWRMTransport() const;
bool IsUnreliableUDPTransport() const;
enum
{
kGetPeerDescription_MaxLength = nl::Weave::kWeavePeerDescription_MaxLength,
/**< Maximum length of string (including NUL character)
returned by GetPeerDescription(). */
};
void GetPeerDescription(char * buf, uint32_t bufSize) const;
void GetProtocolLayerCallback(EventCallback& callback, void *& state) const;
void SetProtocolLayerCallback(EventCallback callback, void *state);
WEAVE_ERROR NewExchangeContext(ExchangeContext *& appExchangeContext);
WEAVE_ERROR AdjustResponseTimeout(ExchangeContext * apExchangeContext) const;
bool IsAuthenticMessageFromPeer(const WeaveMessageInfo *msgInfo);
uint32_t GetMaxWeavePayloadSize(const System::PacketBuffer *msgBuf);
static void DefaultEventHandler(void *apAppState, EventType aEvent, const InEventParam& aInParam, OutEventParam& aOutParam);
WEAVE_ERROR AllocateRightSizedBuffer(PacketBuffer *& buf,
const uint32_t desiredSize,
const uint32_t minSize,
uint32_t & outMaxPayloadSize);
private:
friend class WeaveExchangeManager;
enum AddressingOption
{
kAddressing_NotSpecified = 0,
kAddressing_UnicastIP = 1,
kAddressing_HostName = 2,
kAddressing_WeaveFabric = 3,
kAddressing_ServiceDirectory = 4,
kAddressing_MulticastIP = 5,
};
enum TransportOption
{
kTransport_NotSpecified = 0,
kTransport_UDP = 1,
kTransport_UDP_WRM = 2,
kTransport_TCP = 3,
kTransport_ExistingConnection = 4,
};
enum SecurityOption
{
kSecurityOption_NotSpecified = 0,
kSecurityOption_None = 1,
kSecurityOption_SpecificKey = 2,
kSecurityOption_CASESession = 3,
kSecurityOption_SharedCASESession = 4,
kSecurityOption_PASESession = 5,
kSecurityOption_TAKESession = 6,
};
enum Flags
{
kFlag_KeyReserved = 0x1,
kFlag_ConnectionReferenced = 0x2,
};
WeaveExchangeManager * mExchangeManager;
uint8_t mRefCount;
State mState : 4;
SecurityOption mSecurityOption : 3;
AddressingOption mAddressingOption : 3;
TransportOption mTransportOption : 3;
unsigned mFlags : 3;
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
uint8_t mDNSOptions;
#endif
EventCallback mAppEventCallback;
EventCallback mProtocolLayerCallback;
void *mProtocolLayerState;
uint64_t mPeerNodeId;
// Addressing-specific configuration
InterfaceId mInterfaceId;
uint16_t mPeerPort;
// Transport-specific configuration
nl::Inet::IPAddress mPeerAddress;
const char *mHostName;
WeaveConnection *mCon;
uint32_t mDefaultResponseTimeoutMsec;
uint32_t mUDPPathMTU;
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
WRMPConfig mDefaultWRMPConfig;
#endif
uint8_t mHostNameLen;
// Security-specific configuration
uint8_t mEncType;
WeaveAuthMode mAuthMode;
uint32_t mKeyId;
WEAVE_ERROR Init(void * apAppState, EventCallback aEventCallback);
bool GetFlag(uint8_t flag) const;
void SetFlag(uint8_t flag);
void ClearFlag(uint8_t flag);
WEAVE_ERROR DoPrepare(WEAVE_ERROR configErr);
void DoReset(State newState);
void DoClose(void);
void ResetConfig(void);
void PrepareAddress(void);
void PrepareTransport(void);
void PrepareSecurity(void);
void HandleBindingReady(void);
void HandleBindingFailed(WEAVE_ERROR err, Profiles::StatusReporting::StatusReport *statusReport, bool raiseEvent);
void OnKeyFailed(uint64_t peerNodeId, uint32_t keyId, WEAVE_ERROR keyErr);
void OnSecurityManagerAvailable(void);
void OnConnectionClosed(WeaveConnection *con, WEAVE_ERROR conErr);
uint32_t GetWeaveTrailerSize(void);
uint32_t GetWeaveHeaderSize(void);
static void OnSecureSessionReady(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState,
uint16_t keyId, uint64_t peerNodeId, uint8_t encType);
static void OnSecureSessionFailed(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState,
WEAVE_ERROR localErr, uint64_t peerNodeId, Profiles::StatusReporting::StatusReport *statusReport);
void OnSecureSessionReady(uint64_t peerNodeId, uint8_t encType, WeaveAuthMode authMode, uint16_t keyId);
void OnKeyError(const uint32_t aKeyId, const uint64_t aPeerNodeId, const WEAVE_ERROR aKeyErr);
static void OnResolveComplete(void *appState, INET_ERROR err, uint8_t addrCount, IPAddress *addrArray);
static void OnConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr);
};
/**
* Provides a declarative-style interface for configuring and preparing a Binding object.
*
* When configuring a Binding, applications must call at least one method from each of the
* following configuration groups: Target, Transport, and Security. Other methods may be
* called as needed to override default behavior.
*
* If mutually exclusive configurations are invoked (e.g., Transport_TCP() followed by
* Transport_UDP()), the last one to be called wins.
*/
class Binding::Configuration
{
public:
// NOTE TO IMPLEMENTERS: Binding::Configuration uses a declarative-style interface. This means
// the application is free to call the object's configuration methods IN ANY ORDER. Any new
// methods added to the class must follow this pattern.
Configuration& Target_NodeId(uint64_t aPeerNodeId);
Configuration& Target_ServiceEndpoint(uint64_t aPeerNodeId);
Configuration& TargetAddress_WeaveService(void);
Configuration& TargetAddress_WeaveFabric(uint16_t aSubnetId);
Configuration& TargetAddress_IP(nl::Inet::IPAddress aPeerAddress, uint16_t aPeerPort = WEAVE_PORT, InterfaceId aInterfaceId = INET_NULL_INTERFACEID);
Configuration& TargetAddress_IP(const char *aHostName, uint16_t aPeerPort = WEAVE_PORT, InterfaceId aInterfaceId = INET_NULL_INTERFACEID);
Configuration& TargetAddress_IP(const char *aHostName, size_t aHostNameLen, uint16_t aPeerPort = WEAVE_PORT, InterfaceId aInterfaceId = INET_NULL_INTERFACEID);
Configuration& DNS_Options(uint8_t dnsOptions);
Configuration& Transport_TCP(void);
Configuration& Transport_UDP(void);
Configuration& Transport_UDP_WRM(void);
Configuration& Transport_UDP_PathMTU(uint32_t aPathMTU);
Configuration& Transport_DefaultWRMPConfig(const WRMPConfig& aWRMPConfig);
Configuration& Transport_ExistingConnection(WeaveConnection *apConnection);
Configuration& Exchange_ResponseTimeoutMsec(uint32_t aResponseTimeoutMsec);
Configuration& Security_None(void);
Configuration& Security_CASESession(void);
Configuration& Security_SharedCASESession(void);
Configuration& Security_SharedCASESession(uint64_t aRouterNodeId);
Configuration& Security_PASESession(uint8_t aPasswordSource);
Configuration& Security_TAKESession();
Configuration& Security_Key(uint32_t aKeyId);
Configuration& Security_AppGroupKey(uint32_t aAppGroupGlobalId, uint32_t aRootKeyId, bool aUseRotatingKey);
Configuration& Security_EncryptionType(uint8_t aEncType);
Configuration& Security_AuthenticationMode(WeaveAuthMode aAuthMode);
Configuration& ConfigureFromMessage(const WeaveMessageInfo *aMsgInfo, const Inet::IPPacketInfo *aPacketInfo);
WEAVE_ERROR PrepareBinding(void);
WEAVE_ERROR GetError(void) const;
private:
friend class Binding;
Binding& mBinding;
WEAVE_ERROR mError;
Configuration(Binding& aBinding);
};
/**
* Input parameters to a Binding API event.
*/
struct Binding::InEventParam
{
Binding *Source;
union
{
struct
{
WEAVE_ERROR Reason;
Profiles::StatusReporting::StatusReport *StatusReport;
} PrepareFailed;
struct
{
WEAVE_ERROR Reason;
} BindingFailed;
struct
{
uint8_t PasswordSource;
} PASEParametersRequested;
};
void Clear() { memset(this, 0, sizeof(*this)); }
};
/**
* Output parameters to a Binding API event.
*/
struct Binding::OutEventParam
{
bool DefaultHandlerCalled;
union
{
struct
{
WEAVE_ERROR PrepareError;
} PrepareRequested;
struct
{
const uint8_t * Password;
uint16_t PasswordLength;
} PASEParametersRequested;
struct
{
bool EncryptAuthPhase;
bool EncryptCommPhase;
bool TimeLimitedIK;
bool SendChallengerId;
nl::Weave::Profiles::Security::TAKE::WeaveTAKEChallengerAuthDelegate *AuthDelegate;
} TAKEParametersRequested;
};
void Clear() { memset(this, 0, sizeof(*this)); }
};
/*
* Inline Functions
*
* Documentation for these functions can be found in the .cpp file.
*/
inline Binding::State Binding::GetState(void) const
{
return mState;
}
inline bool Binding::IsPreparing() const
{
return mState >= kState_Preparing && mState < kState_Ready;
}
inline bool Binding::IsReady() const
{
return mState == kState_Ready;
}
inline bool Binding::CanBePrepared(void) const
{
return mState == kState_NotConfigured || mState == kState_Failed;
}
inline uint64_t Binding::GetPeerNodeId() const
{
return mPeerNodeId;
}
inline void Binding::GetPeerIPAddress(nl::Inet::IPAddress & address, uint16_t & port, InterfaceId & interfaceId) const
{
address = mPeerAddress;
port = mPeerPort;
interfaceId = mInterfaceId;
}
inline uint32_t Binding::GetKeyId(void) const
{
return mKeyId;
}
inline uint8_t Binding::GetEncryptionType(void) const
{
return mEncType;
}
inline uint32_t Binding::GetDefaultResponseTimeout() const
{
return mDefaultResponseTimeoutMsec;
}
inline void Binding::SetDefaultResponseTimeout(uint32_t timeout)
{
mDefaultResponseTimeoutMsec = timeout;
}
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
inline const WRMPConfig& Binding::GetDefaultWRMPConfig(void) const
{
return mDefaultWRMPConfig;
}
inline void Binding::SetDefaultWRMPConfig(const WRMPConfig& aWRMPConfig)
{
mDefaultWRMPConfig = aWRMPConfig;
}
#endif // #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
inline Binding::EventCallback Binding::GetEventCallback() const
{
return mAppEventCallback;
}
inline void Binding::SetEventCallback(EventCallback aEventCallback)
{
mAppEventCallback = aEventCallback;
}
inline void Binding::GetProtocolLayerCallback(EventCallback& callback, void *& state) const
{
callback = mProtocolLayerCallback;
state = mProtocolLayerState;
}
inline void Binding::SetProtocolLayerCallback(EventCallback callback, void *state)
{
mProtocolLayerCallback = callback;
mProtocolLayerState = state;
}
inline WeaveConnection *Binding::GetConnection() const
{
return mCon;
}
inline bool Binding::GetFlag(uint8_t flag) const
{
return (mFlags & flag) != 0;
}
inline void Binding::SetFlag(uint8_t flag)
{
mFlags |= flag;
}
inline void Binding::ClearFlag(uint8_t flag)
{
mFlags &= ~flag;
}
inline WeaveExchangeManager *Binding::GetExchangeManager() const
{
return mExchangeManager;
}
inline bool Binding::IsConnectionTransport() const
{
return mTransportOption == kTransport_TCP || mTransportOption == kTransport_ExistingConnection;
}
inline bool Binding::IsUDPTransport() const
{
return mTransportOption == kTransport_UDP || mTransportOption == kTransport_UDP_WRM;
}
inline bool Binding::IsWRMTransport() const
{
return mTransportOption == kTransport_UDP_WRM;
}
inline bool Binding::IsUnreliableUDPTransport() const
{
return mTransportOption == kTransport_UDP;
}
inline Binding::Configuration Binding::BeginConfiguration()
{
return Configuration(*this);
}
inline WEAVE_ERROR Binding::Configuration::PrepareBinding(void)
{
return mBinding.DoPrepare(mError);
}
inline WEAVE_ERROR Binding::Configuration::GetError(void) const
{
return mError;
}
}; // Weave
}; // nl
#endif // WEAVE_BINDING_H_