| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * 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 contains definitions for Device class. The objects of this |
| * class will be used by Controller applications to interact with CHIP |
| * devices. The class provides mechanism to construct, send and receive |
| * messages to and from the corresponding CHIP devices. |
| */ |
| |
| #pragma once |
| |
| #include <app/util/basic-types.h> |
| #include <core/CHIPCallback.h> |
| #include <core/CHIPCore.h> |
| #include <support/Base64.h> |
| #include <support/DLLUtil.h> |
| #include <transport/SecurePairingSession.h> |
| #include <transport/SecureSessionMgr.h> |
| #include <transport/TransportMgr.h> |
| #include <transport/raw/MessageHeader.h> |
| #include <transport/raw/UDP.h> |
| |
| namespace chip { |
| namespace Controller { |
| |
| class DeviceController; |
| class DeviceStatusDelegate; |
| struct SerializedDevice; |
| |
| using DeviceTransportMgr = TransportMgr<Transport::UDP>; |
| |
| class DLL_EXPORT Device |
| { |
| public: |
| Device() : mActive(false), mState(ConnectionState::NotConnected) {} |
| ~Device() {} |
| |
| /** |
| * @brief |
| * Set the delegate object which will be called when a message is received. |
| * The user of this Device object must reset the delegate (by calling |
| * SetDelegate(nullptr)) before releasing their delegate object. |
| * |
| * @param[in] delegate The pointer to the delegate object. |
| */ |
| void SetDelegate(DeviceStatusDelegate * delegate) { mStatusDelegate = delegate; } |
| |
| // ----- Messaging ----- |
| /** |
| * @brief |
| * Send the provided message to the device |
| * |
| * @param[in] message The message to be sent. The ownership of the message buffer |
| * is handed over to Device object. SendMessage() will |
| * decrement the reference count of the message buffer before |
| * returning. |
| * |
| * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error |
| */ |
| CHIP_ERROR SendMessage(System::PacketBuffer * message); |
| |
| /** |
| * @brief |
| * Send the provided message to the device |
| * |
| * @param[in] message The message to be sent. |
| * |
| * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error |
| */ |
| CHIP_ERROR SendMessage(System::PacketBufferHandle message); |
| |
| /** |
| * @brief |
| * Get the IP address assigned to the device. |
| * |
| * @param[out] addr The reference to the IP address. |
| * |
| * @return true, if the IP address was filled in the out parameter, false otherwise |
| */ |
| bool GetIpAddress(Inet::IPAddress & addr) const; |
| |
| /** |
| * @brief |
| * Initialize the device object with secure session manager and inet layer object |
| * references. This variant of function is typically used when the device object |
| * is created from a serialized device information. The other parameters (address, port, |
| * interface etc) are part of the serialized device, so those are not required to be |
| * initialized. |
| * |
| * Note: The lifetime of session manager and inet layer objects must be longer than |
| * that of this device object. If these objects are freed, while the device object is |
| * still using them, it can lead to unknown behavior and crashes. |
| * |
| * @param[in] transportMgr Transport manager object pointer |
| * @param[in] sessionMgr Secure session manager object pointer |
| * @param[in] inetLayer InetLayer object pointer |
| */ |
| void Init(DeviceTransportMgr * transportMgr, SecureSessionMgr * sessionMgr, Inet::InetLayer * inetLayer) |
| { |
| mTransportMgr = transportMgr; |
| mSessionManager = sessionMgr; |
| mInetLayer = inetLayer; |
| } |
| |
| /** |
| * @brief |
| * Initialize a new device object with secure session manager, inet layer object, |
| * and other device specific parameters. This variant of function is typically used when |
| * a new device is paired, and the corresponding device object needs to updated with |
| * all device specifc parameters (address, port, interface etc). |
| * |
| * This is not done as part of constructor so that the controller can have a list of |
| * uninitialzed/unpaired device objects. The object is initialized only when the device |
| * is actually paired. |
| * |
| * @param[in] transportMgr Transport manager object pointer |
| * @param[in] sessionMgr Secure session manager object pointer |
| * @param[in] inetLayer InetLayer object pointer |
| * @param[in] deviceId Node ID of the device |
| * @param[in] devicePort Port on which device is listening (typically CHIP_PORT) |
| * @param[in] interfaceId Local Interface ID that should be used to talk to the device |
| */ |
| void Init(DeviceTransportMgr * transportMgr, SecureSessionMgr * sessionMgr, Inet::InetLayer * inetLayer, NodeId deviceId, |
| uint16_t devicePort, Inet::InterfaceId interfaceId) |
| { |
| Init(transportMgr, sessionMgr, inetLayer); |
| mDeviceId = deviceId; |
| mDevicePort = devicePort; |
| mInterface = interfaceId; |
| mState = ConnectionState::Connecting; |
| } |
| |
| /** @brief Serialize the Pairing Session to a string. It's guaranteed that the string |
| * will be null terminated, and there won't be any embedded null characters. |
| * |
| * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| **/ |
| CHIP_ERROR Serialize(SerializedDevice & output); |
| |
| /** @brief Deserialize the Pairing Session from the string. It's expected that the string |
| * will be null terminated, and there won't be any embedded null characters. |
| * |
| * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| **/ |
| CHIP_ERROR Deserialize(const SerializedDevice & input); |
| |
| /** |
| * @brief |
| * This function is called when a message is received from the corresponding CHIP |
| * device. The message ownership is transferred to the function, and it is expected |
| * to release the message buffer before returning. |
| * |
| * @param[in] header Reference to common packet header of the received message |
| * @param[in] payloadHeader Reference to payload header in the message |
| * @param[in] state Pointer to the peer connection state on which message is received |
| * @param[in] msgBuf The message buffer |
| * @param[in] mgr Pointer to secure session manager which received the message |
| */ |
| void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, |
| const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr); |
| |
| /** |
| * @brief |
| * Return whether the current device object is actively associated with a paired CHIP |
| * device. An active object can be used to communicate with the corresponding device. |
| */ |
| bool IsActive() const { return mActive; } |
| |
| void SetActive(bool active) { mActive = active; } |
| |
| void Reset() |
| { |
| SetActive(false); |
| mState = ConnectionState::NotConnected; |
| mSessionManager = nullptr; |
| mStatusDelegate = nullptr; |
| mInetLayer = nullptr; |
| } |
| |
| NodeId GetDeviceId() const { return mDeviceId; } |
| |
| void SetAddress(const Inet::IPAddress & deviceAddr) { mDeviceAddr = deviceAddr; } |
| |
| SecurePairingSessionSerializable & GetPairing() { return mPairing; } |
| |
| void AddResponseHandler(EndpointId endpoint, ClusterId cluster, Callback::Callback<> * onResponse); |
| void AddReportHandler(EndpointId endpoint, ClusterId cluster, Callback::Callback<> * onReport); |
| |
| private: |
| enum class ConnectionState |
| { |
| NotConnected, |
| Connecting, |
| SecureConnected, |
| }; |
| |
| struct CallbackInfo |
| { |
| EndpointId endpoint; |
| ClusterId cluster; |
| }; |
| |
| /* Node ID assigned to the CHIP device */ |
| NodeId mDeviceId; |
| |
| /* IP Address of the CHIP device */ |
| Inet::IPAddress mDeviceAddr; |
| |
| /* Port on which the CHIP device is receiving messages. Typically it is CHIP_PORT */ |
| uint16_t mDevicePort; |
| |
| /* Local network interface that should be used to communicate with the device */ |
| Inet::InterfaceId mInterface; |
| |
| Inet::InetLayer * mInetLayer; |
| |
| bool mActive; |
| ConnectionState mState; |
| |
| SecurePairingSessionSerializable mPairing; |
| |
| DeviceStatusDelegate * mStatusDelegate; |
| |
| SecureSessionMgr * mSessionManager; |
| |
| DeviceTransportMgr * mTransportMgr; |
| |
| /* Track all outstanding response callbacks for this device. The callbacks are |
| registered when a command is sent to the device, to get notified with the results. */ |
| Callback::CallbackDeque mResponses; |
| |
| /* Track all outstanding callbacks for attribute reports from this device. The callbacks are |
| registered when the user requests attribute reporting for device attributes. */ |
| Callback::CallbackDeque mReports; |
| |
| /** |
| * @brief |
| * This function loads the secure session object from the serialized operational |
| * credentials corresponding to the device. This is typically done when the device |
| * does not have an active secure channel. |
| */ |
| CHIP_ERROR LoadSecureSessionParameters(); |
| }; |
| |
| /** |
| * This class defines an interface for an object that the user of Device |
| * can register as a delegate. The delegate object will be called by the |
| * Device when a new message or status update is received from the corresponding |
| * CHIP device. |
| */ |
| class DLL_EXPORT DeviceStatusDelegate |
| { |
| public: |
| virtual ~DeviceStatusDelegate() {} |
| |
| /** |
| * @brief |
| * Called when a message is received from the device. |
| * |
| * @param[in] msg Received message buffer. |
| */ |
| virtual void OnMessage(System::PacketBufferHandle msg) = 0; |
| |
| /** |
| * @brief |
| * Called when device status is updated. |
| * |
| */ |
| virtual void OnStatusChange(void){}; |
| }; |
| |
| typedef struct SerializableDevice |
| { |
| SecurePairingSessionSerializable mOpsCreds; |
| uint64_t mDeviceId; /* This field is serialized in LittleEndian byte order */ |
| uint8_t mDeviceAddr[INET6_ADDRSTRLEN]; |
| uint16_t mDevicePort; /* This field is serealized in LittelEndian byte order */ |
| } SerializableDevice; |
| |
| typedef struct SerializedDevice |
| { |
| // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads) |
| // The encoder may not include a NULL character, and there are maximum 2 bytes of padding. |
| // So extra 8 bytes should be sufficient to absorb this overhead. |
| uint8_t inner[BASE64_ENCODED_LEN(sizeof(SerializableDevice) + sizeof(uint64_t))]; |
| } SerializedDevice; |
| |
| } // namespace Controller |
| } // namespace chip |