blob: dccbf3fac1bfd95e588ea3423e6501fcc19acc36 [file] [log] [blame]
/*
*
* Copyright (c) 2016-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
* Defines the Weave Binding class and its supporting types.
*
*/
#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>
#include <Weave/Core/WeaveCore.h>
namespace nl {
namespace Weave {
class WeaveExchangeManager;
class ExchangeContext;
class WeaveSecurityManager;
namespace Profiles {
namespace StatusReporting {
class StatusReport;
}
}
/**
* @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_PreparingTransport = 5,
kState_PreparingSecurity = 6,
kState_PreparingSecurity_EstablishSession = 7,
kState_PreparingSecurity_WaitSecurityMgr = 8,
kState_Ready = 9,
kState_Resetting = 10,
kState_Closed = 11,
kState_Failed = 12,
};
enum EventType
{
kEvent_BindingReady = 1, //< The prepare action on the binding succeeded and the binding may now be used to communicate with the peer.
kEvent_PrepareFailed = 2, //< The prepare action on the binding failed.
kEvent_BindingFailed = 3, //< The binding failed and can no longer be used to communicate with the peer.
kEvent_PrepareRequested = 4, //< The application is requested to configure and prepare the binding for use by the network stack.
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;
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);
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);
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,
};
enum Flags
{
kFlag_KeyReserved = 0x1,
};
WeaveExchangeManager * mExchangeManager;
uint8_t mRefCount;
State mState : 4;
SecurityOption mSecurityOption : 3;
AddressingOption mAddressingOption : 3;
TransportOption mTransportOption : 3;
unsigned mFlags : 3;
EventCallback mAppEventCallback;
EventCallback mProtocolLayerCallback;
void *mProtocolLayerState;
uint64_t mPeerNodeId;
// Addressing-specific configuration
InterfaceId mInterfaceId;
uint16_t mPeerPort;
// Security-specific configuration
uint8_t mEncType;
WeaveAuthMode mAuthMode;
uint32_t mKeyId;
uint32_t mDefaultResponseTimeoutMsec;
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
WRMPConfig mDefaultWRMPConfig;
#endif
// Note that IPAddress has a (redundant) copy assignment operator defined, so it cannot be part of any union pre C++11
// This is not a big deal, but peer address is not really needed in ServiceDirectory scenarios
nl::Inet::IPAddress mPeerAddress;
WEAVE_ERROR Init(void * apAppState, EventCallback aEventCallback);
bool GetFlag(uint8_t flag) const { return (mFlags & flag) != 0; }
void SetFlag(uint8_t flag) { mFlags |= 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, bool raiseEvent);
void OnKeyFailed(uint64_t peerNodeId, uint32_t keyId, WEAVE_ERROR keyErr);
void OnSecurityManagerAvailable(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);
};
/**
* 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& Transport_TCP(void);
Configuration& Transport_UDP(void);
Configuration& Transport_UDP_WRM(void);
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_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 *apMsgHeader,
const nl::Inet::IPPacketInfo *apPktInfo,
WeaveConnection *apConnection = NULL);
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;
} PrepareFailed;
struct
{
WEAVE_ERROR Reason;
} BindingFailed;
};
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;
};
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 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 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_