Add CHIP's controller API and update the standalone example to use it (#666)
* Add CHIP's controller API and update the standalone example to use it
* Fix class name in documentation
* Fix inclusion guards
* Address review comments and fix build
* Fix DIST
* Add tests for Chip Connection
* Actually fix distcheck
* Rename deviceMgr to deviceController
* Update test to follow new test structure
* Address review comments and clean up Ref counting
* Make DriveIO static
* Use an enum state for ChipConnection
* Add init guards for ChipDeviceController
* Fix compile
diff --git a/config/ios/CHIPProjectConfig.h b/config/ios/CHIPProjectConfig.h
index fec5a21..e33adb7 100644
--- a/config/ios/CHIPProjectConfig.h
+++ b/config/ios/CHIPProjectConfig.h
@@ -29,8 +29,8 @@
// Enable use of an ephemeral UDP source port for locally initiated CHIP exchanges.
#define CHIP_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 1
-// Enable UDP listening on demand in the CHIPDeviceManager
-#define CHIP_CONFIG_DEVICE_MGR_DEMAND_ENABLE_UDP 1
+// Enable UDP listening on demand in the CHIPDeviceController
+#define CHIP_CONFIG_DEVICE_CONTROLLER_DEMAND_ENABLE_UDP 1
#define INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT 0
diff --git a/examples/wifi-echo/standalone/CHIPManager.cpp b/examples/wifi-echo/standalone/CHIPManager.cpp
deleted file mode 100644
index 5964f2a..0000000
--- a/examples/wifi-echo/standalone/CHIPManager.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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
- * Implementation for the CHIP Manager class.
- *
- * This class provides various facilities through CHIP's inner
- * implementation
- *
- */
-
-#include <errno.h>
-
-#include "CHIPManager.h"
-
-#include <support/CodeUtils.h>
-#include <support/ErrorStr.h>
-
-CHIP_ERROR ChipManager::InitLayers()
-{
- CHIP_ERROR err = CHIP_NO_ERROR;
-
- // Initialize the CHIP System Layer.
- err = mSystem->Init(NULL);
- if (err != CHIP_SYSTEM_NO_ERROR)
- {
- ChipLogError(DeviceManager, "SystemLayer initialization failed: %s", ErrorStr(err));
- }
- SuccessOrExit(err);
-
- // Initialize the CHIP Inet layer.
- err = mInet->Init(*mSystem, NULL);
- if (err != INET_NO_ERROR)
- {
- ChipLogError(DeviceManager, "InetLayer initialization failed: %s", ErrorStr(err));
- }
- SuccessOrExit(err);
-
-exit:
- return err;
-}
-
-System::Layer * ChipManager::SystemLayer()
-{
- return this->mSystem;
-}
-
-Inet::InetLayer * ChipManager::InetLayer()
-{
- return this->mInet;
-}
-
-void ChipManager::ServiceEvents()
-{
-
- // Set the select timeout to 100ms
- struct timeval aSleepTime;
- aSleepTime.tv_sec = 0;
- aSleepTime.tv_usec = 100 * 1000;
-
- static bool printed = false;
-
- if (!printed)
- {
- {
- ChipLogProgress(DeviceManager, "CHIP node ready to service events; PID: %d; PPID: %d\n", getpid(), getppid());
- printed = true;
- }
- }
- fd_set readFDs, writeFDs, exceptFDs;
- int numFDs = 0;
-
- FD_ZERO(&readFDs);
- FD_ZERO(&writeFDs);
- FD_ZERO(&exceptFDs);
-
- if (mSystem->State() == System::kLayerState_Initialized)
- mSystem->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
-
- if (mInet->State == Inet::InetLayer::kState_Initialized)
- mInet->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
-
- int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
- if (selectRes < 0)
- {
- ChipLogError(DeviceManager, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
- return;
- }
-
- if (mSystem->State() == System::kLayerState_Initialized)
- {
- mSystem->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
- }
-
- if (mInet->State == Inet::InetLayer::kState_Initialized)
- {
- mInet->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
- }
-}
diff --git a/examples/wifi-echo/standalone/Makefile b/examples/wifi-echo/standalone/Makefile
index a5654c0..8951aa6 100644
--- a/examples/wifi-echo/standalone/Makefile
+++ b/examples/wifi-echo/standalone/Makefile
@@ -34,7 +34,6 @@
SRCS = \
$(PROJECT_ROOT)/main.cpp \
- $(PROJECT_ROOT)/CHIPManager.cpp \
$(NULL)
INC_DIRS = \
@@ -43,6 +42,7 @@
$(CHIP_ROOT)/src/lib \
$(CHIP_ROOT)/src/ \
$(CHIP_ROOT)/src/system \
+ $(CHIP_ROOT)/src/controller \
$(CHIP_ROOT)/config/standalone \
$(NULL)
diff --git a/examples/wifi-echo/standalone/include/CHIPManager.h b/examples/wifi-echo/standalone/include/CHIPManager.h
deleted file mode 100644
index 996313f..0000000
--- a/examples/wifi-echo/standalone/include/CHIPManager.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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
- * Header for the CHIP Manager class.
- *
- * This class provides various facilities through CHIP's inner
- * implementation. It should be removed when a more accessible
- * CHIP api is ready.
- *
- */
-
-#ifndef CHIP_MANAGER_H
-#define CHIP_MANAGER_H
-
-#include <new>
-
-#include <core/CHIPError.h>
-#include <inet/InetLayer.h>
-#include <inet/UDPEndPoint.h>
-#include <support/CHIPLogging.h>
-#include <system/SystemLayer.h>
-
-using namespace chip;
-
-class ChipManager
-{
-public:
- // Initialize the System Layer and Init Layer
- CHIP_ERROR InitLayers();
- System::Layer * SystemLayer();
- Inet::InetLayer * InetLayer();
- void ServiceEvents();
-
- ChipManager() : mSystem(new System::Layer()), mInet(new Inet::InetLayer()) {}
-
-private:
- System::Layer * mSystem;
- Inet::InetLayer * mInet;
-};
-
-#endif // CHIP_MANAGER_H
diff --git a/examples/wifi-echo/standalone/main.cpp b/examples/wifi-echo/standalone/main.cpp
index 2771ab8..7422624 100644
--- a/examples/wifi-echo/standalone/main.cpp
+++ b/examples/wifi-echo/standalone/main.cpp
@@ -18,7 +18,7 @@
#include <support/CodeUtils.h>
#include <inet/UDPEndPoint.h>
-#include "CHIPManager.h"
+#include <controller/CHIPDeviceController.h>
#define SEND_DELAY 5
@@ -27,51 +27,40 @@
static const char * PAYLOAD = "Message from Standalone CHIP echo client!";
-// UDP Endpoint Callbacks
-static void EchoResponse(IPEndPointBasis * endpoint, System::PacketBuffer * buffer, const IPPacketInfo * packet_info)
+// Device Manager Callbacks
+static void EchoResponse(chip::DeviceController::ChipDeviceController * deviceController, void * appReqState,
+ System::PacketBuffer * buffer, const IPPacketInfo * packet_info)
{
- bool status = endpoint != NULL && buffer != NULL && packet_info != NULL;
+ char src_addr[INET_ADDRSTRLEN];
+ char dest_addr[INET_ADDRSTRLEN];
+ size_t data_len = buffer->DataLength();
- if (status)
+ packet_info->SrcAddress.ToString(src_addr, sizeof(src_addr));
+ packet_info->DestAddress.ToString(dest_addr, sizeof(dest_addr));
+
+ printf("UDP packet received from %s:%u to %s:%u (%zu bytes)\n", src_addr, packet_info->SrcPort, dest_addr,
+ packet_info->DestPort, static_cast<size_t>(buffer->DataLength()));
+
+ // attempt to print the incoming message
+ char msg_buffer[data_len];
+ msg_buffer[data_len] = 0; // Null-terminate whatever we received and treat like a string...
+ memcpy(msg_buffer, buffer->Start(), data_len);
+ int compare = strncmp(msg_buffer, PAYLOAD, data_len);
+ if (compare == 0)
{
- char src_addr[INET_ADDRSTRLEN];
- char dest_addr[INET_ADDRSTRLEN];
- size_t data_len = buffer->DataLength();
-
- packet_info->SrcAddress.ToString(src_addr, sizeof(src_addr));
- packet_info->DestAddress.ToString(dest_addr, sizeof(dest_addr));
-
- printf("UDP packet received from %s:%u to %s:%u (%zu bytes)\n", src_addr, packet_info->SrcPort, dest_addr,
- packet_info->DestPort, static_cast<size_t>(buffer->DataLength()));
-
- // attempt to print the incoming message
- char msg_buffer[data_len];
- msg_buffer[data_len] = 0; // Null-terminate whatever we received and treat like a string...
- memcpy(msg_buffer, buffer->Start(), data_len);
- int compare = strncmp(msg_buffer, PAYLOAD, data_len);
- if (compare == 0)
- {
- printf("Got expected Message...\n");
- }
- else
- {
- printf("Didn't get the expected Echo. Compare: %d\n", compare);
- printf("\nSend: %s \nRecv: %s\n", PAYLOAD, msg_buffer);
- }
+ printf("Got expected Message...\n");
+ }
+ else
+ {
+ printf("Didn't get the expected Echo. Compare: %d\n", compare);
+ printf("\nSend: %s \nRecv: %s\n", PAYLOAD, msg_buffer);
}
- if (!status)
- {
- printf("Received data but couldn't process it...\n");
- }
-
- if (buffer != NULL)
- {
- System::PacketBuffer::Free(buffer);
- }
+ System::PacketBuffer::Free(buffer);
}
-static void Error(IPEndPointBasis * ep, INET_ERROR error, const IPPacketInfo * pi)
+static void ReceiveError(chip::DeviceController::ChipDeviceController * deviceController, void * appReqState, CHIP_ERROR error,
+ const IPPacketInfo * pi)
{
printf("ERROR: %s\n Got UDP error\n", ErrorStr(error));
}
@@ -88,9 +77,6 @@
snprintf((char *) buffer->Start(), payload_len + 1, "%s", PAYLOAD);
buffer->SetDataLength(payload_len);
- CHIP_ERROR err;
- UDPEndPoint * endpoint;
-
std::string host_ip;
std::cout << "Please, enter the Echo Host's IP Address: ";
std::getline(std::cin, host_ip);
@@ -116,42 +102,20 @@
return -1;
}
- ChipManager chipMgr = ChipManager();
- chipMgr.InitLayers();
+ chip::DeviceController::ChipDeviceController * controller = new chip::DeviceController::ChipDeviceController();
+ controller->Init();
- err = chipMgr.InetLayer()->NewUDPEndPoint(&endpoint);
- if (err != CHIP_NO_ERROR)
- {
- printf("ERROR: %s\n Couldn't create UDP Endpoint, server will not start\n", ErrorStr(err));
- return -1;
- }
-
- err = endpoint->Bind(kIPAddressType_IPv4, IPAddress::Any, port);
- if (err != CHIP_NO_ERROR)
- {
- printf("ERROR: %s\n Bind failed\n", ErrorStr(err));
- return -1;
- }
-
- err = endpoint->Listen();
- if (err != CHIP_NO_ERROR)
- {
- printf("ERROR: %s\n Listen failed\n", ErrorStr(err));
- return -1;
- }
-
- endpoint->OnMessageReceived = EchoResponse;
- endpoint->OnReceiveError = Error;
+ controller->ConnectDevice(1, host_addr, NULL, EchoResponse, ReceiveError, port);
// Run the client
while (1)
{
// Send calls release on this buffer, so bump up the ref because we want to reuse it
buffer->AddRef();
- endpoint->SendTo(host_addr, port, buffer);
+ controller->SendMessage(NULL, buffer);
printf("Msg sent to server at %s:%d\n", host_ip.c_str(), port);
- chipMgr.ServiceEvents();
+ controller->ServiceEvents();
sleep(SEND_DELAY);
}
diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp
new file mode 100644
index 0000000..8f89ad5
--- /dev/null
+++ b/src/controller/CHIPDeviceController.cpp
@@ -0,0 +1,276 @@
+/*
+ *
+ * Copyright (c) 2020 Project CHIP Authors
+ * 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
+ * Implementation of CHIP Device Controller, a common class
+ * that implements discovery, pairing and provisioning of Weave
+ * devices.
+ *
+ */
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <time.h>
+
+#include <core/CHIPCore.h>
+#include <support/Base64.h>
+#include <support/CodeUtils.h>
+#include <core/CHIPEncoding.h>
+
+#include <controller/CHIPDeviceController.h>
+#include <support/logging/CHIPLogging.h>
+#include <support/ErrorStr.h>
+#include <support/TimeUtils.h>
+
+namespace chip {
+namespace DeviceController {
+
+using namespace chip::Encoding;
+
+ChipDeviceController::ChipDeviceController()
+{
+ mState = kState_NotInitialized;
+ AppState = NULL;
+ mConState = kConnectionState_NotConnected;
+ mDeviceCon = NULL;
+ mCurReqMsg = NULL;
+ mOnError = NULL;
+ mDeviceAddr = IPAddress::Any;
+ mDevicePort = CHIP_PORT;
+ mDeviceId = 0;
+ memset(&mOnComplete, 0, sizeof(mOnComplete));
+}
+
+CHIP_ERROR ChipDeviceController::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);
+
+ mSystemLayer = new System::Layer();
+ mInetLayer = new Inet::InetLayer();
+
+ // Initialize the CHIP System Layer.
+ err = mSystemLayer->Init(NULL);
+ if (err != CHIP_SYSTEM_NO_ERROR)
+ {
+ ChipLogError(Controller, "SystemLayer initialization failed: %s", ErrorStr(err));
+ }
+ SuccessOrExit(err);
+
+ // Initialize the CHIP Inet layer.
+ err = mInetLayer->Init(*mSystemLayer, NULL);
+ if (err != INET_NO_ERROR)
+ {
+ ChipLogError(Controller, "InetLayer initialization failed: %s", ErrorStr(err));
+ }
+ SuccessOrExit(err);
+
+ mState = kState_Initialized;
+
+exit:
+ return err;
+}
+
+CHIP_ERROR ChipDeviceController::Shutdown()
+{
+ if (mState != kState_Initialized)
+ {
+ return CHIP_ERROR_INCORRECT_STATE;
+ }
+
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ mState = kState_NotInitialized;
+
+ if (mDeviceCon != NULL)
+ {
+ mDeviceCon->Close();
+ delete mDeviceCon;
+ mDeviceCon = NULL;
+ }
+ mSystemLayer->Shutdown();
+ mInetLayer->Shutdown();
+ delete mSystemLayer;
+ delete mInetLayer;
+ mSystemLayer = NULL;
+ mInetLayer = NULL;
+
+ mConState = kConnectionState_NotConnected;
+ memset(&mOnComplete, 0, sizeof(mOnComplete));
+ mOnError = NULL;
+
+ return err;
+}
+
+CHIP_ERROR ChipDeviceController::ConnectDevice(uint64_t deviceId, IPAddress deviceAddr, void * appReqState,
+ MessageReceiveHandler onMessageReceived, ErrorHandler onError, uint16_t devicePort)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ if (mState != kState_Initialized || mDeviceCon != NULL || mConState != kConnectionState_NotConnected)
+ {
+ return CHIP_ERROR_INCORRECT_STATE;
+ }
+
+ mDeviceId = deviceId;
+ mDeviceAddr = deviceAddr;
+ mDevicePort = devicePort;
+ mAppReqState = appReqState;
+ mDeviceCon = new ChipConnection();
+
+ mDeviceCon->Init(mInetLayer);
+ err = mDeviceCon->Connect(mDeviceId, mDeviceAddr, mDevicePort);
+ SuccessOrExit(err);
+
+ mDeviceCon->OnMessageReceived = OnReceiveMessage;
+ mDeviceCon->OnReceiveError = OnReceiveError;
+ mDeviceCon->AppState = this;
+
+ mOnComplete.Response = onMessageReceived;
+ mOnError = onError;
+
+ mConState = kConnectionState_Connected;
+
+exit:
+ if (err != CHIP_NO_ERROR && mDeviceCon != NULL)
+ {
+ mDeviceCon->Close();
+ delete mDeviceCon;
+ mDeviceCon = NULL;
+ }
+ return err;
+}
+
+CHIP_ERROR ChipDeviceController::DisconnectDevice()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ if (mState != kState_Initialized || mConState != kConnectionState_Connected)
+ {
+ return CHIP_ERROR_INCORRECT_STATE;
+ }
+
+ err = mDeviceCon->Close();
+ delete mDeviceCon;
+ mDeviceCon = NULL;
+ mConState = kConnectionState_NotConnected;
+ return err;
+};
+
+CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer)
+{
+ CHIP_ERROR err = CHIP_ERROR_INCORRECT_STATE;
+
+ mAppReqState = appReqState;
+ if (mConState == kConnectionState_Connected)
+ {
+ err = mDeviceCon->SendMessage(buffer);
+ }
+
+ return err;
+}
+
+void ChipDeviceController::ServiceEvents()
+{
+#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
+
+ if (mState != kState_Initialized)
+ {
+ return;
+ }
+ // Set the select timeout to 100ms
+ struct timeval aSleepTime;
+ aSleepTime.tv_sec = 0;
+ aSleepTime.tv_usec = 100 * 1000;
+
+ static bool printed = false;
+
+ if (!printed)
+ {
+ {
+ ChipLogProgress(Controller, "CHIP node ready to service events; PID: %d; PPID: %d\n", getpid(), getppid());
+ printed = true;
+ }
+ }
+ fd_set readFDs, writeFDs, exceptFDs;
+ int numFDs = 0;
+
+ FD_ZERO(&readFDs);
+ FD_ZERO(&writeFDs);
+ FD_ZERO(&exceptFDs);
+
+ if (mSystemLayer->State() == System::kLayerState_Initialized)
+ mSystemLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+
+ if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
+ mInetLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+
+ int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
+ if (selectRes < 0)
+ {
+ ChipLogError(Controller, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
+ return;
+ }
+
+ if (mSystemLayer->State() == System::kLayerState_Initialized)
+ {
+ mSystemLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+ }
+
+ if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
+ {
+ mInetLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+ }
+#endif
+}
+
+void ChipDeviceController::ClearRequestState()
+{
+ if (mCurReqMsg != NULL)
+ {
+ PacketBuffer::Free(mCurReqMsg);
+ mCurReqMsg = NULL;
+ }
+}
+
+void ChipDeviceController::OnReceiveMessage(ChipConnection * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo)
+{
+ ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
+ if (mgr->mConState == kConnectionState_Connected && mgr->mOnComplete.Response != NULL && pktInfo != NULL)
+ {
+ mgr->mOnComplete.Response(mgr, mgr->mAppReqState, msgBuf, pktInfo);
+ }
+}
+
+void ChipDeviceController::OnReceiveError(ChipConnection * con, CHIP_ERROR err, const IPPacketInfo * pktInfo)
+{
+ ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
+ if (mgr->mConState == kConnectionState_Connected && mgr->mOnError != NULL && pktInfo != NULL)
+ {
+ mgr->mOnError(mgr, mgr->mAppReqState, err, pktInfo);
+ }
+}
+
+} // namespace DeviceController
+} // namespace chip
diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h
new file mode 100644
index 0000000..9aacf8c
--- /dev/null
+++ b/src/controller/CHIPDeviceController.h
@@ -0,0 +1,147 @@
+/*
+ *
+ * Copyright (c) 2020 Project CHIP Authors
+ * 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
+ * Declaration of CHIP Device Controller, a common class
+ * that implements connecting and messaging and will later
+ * be expanded to support discovery, pairing and
+ * provisioning of CHIP devices.
+ *
+ */
+
+#ifndef __CHIPDEVICECONTROLLER_H
+#define __CHIPDEVICECONTROLLER_H
+
+#include <support/DLLUtil.h>
+#include <core/CHIPCore.h>
+#include <core/CHIPTLV.h>
+#include <core/CHIPConnection.h>
+
+namespace chip {
+namespace DeviceController {
+
+class ChipDeviceController;
+
+extern "C" {
+typedef void (*CompleteHandler)(ChipDeviceController * deviceController, void * appReqState);
+typedef void (*ErrorHandler)(ChipDeviceController * deviceController, void * appReqState, CHIP_ERROR err,
+ const IPPacketInfo * pktInfo);
+typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState, PacketBuffer * payload,
+ const IPPacketInfo * pktInfo);
+};
+
+class DLL_EXPORT ChipDeviceController
+{
+public:
+ ChipDeviceController();
+
+ void * AppState;
+
+ CHIP_ERROR Init();
+ CHIP_ERROR Shutdown();
+
+ // ----- Connection Management -----
+ /**
+ * @brief
+ * Connect to a CHIP device at a given address and an optional port
+ *
+ * @param deviceId A device identifier. Currently unused and can be set to any value
+ * @param deviceAddr The IPAddress of the requested Device
+ * @param appReqState Application specific context to be passed back when a message is received or on error
+ * @param onMessageReceived Callback for when a message is received
+ * @param onError Callback for when an error occurs
+ * @param devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT
+ * @return CHIP_ERROR The connection status
+ */
+ CHIP_ERROR ConnectDevice(uint64_t deviceId, IPAddress deviceAddr, void * appReqState, MessageReceiveHandler onMessageReceived,
+ ErrorHandler onError, uint16_t devicePort = CHIP_PORT);
+
+ // ----- Messaging -----
+ /**
+ * @brief
+ * Send a message to a connected CHIP device
+ *
+ * @param appReqState Application specific context to be passed back when a message is received or on error
+ * @param buffer The Data Buffer to trasmit to the deviec
+ * @return CHIP_ERROR The return status
+ */
+ CHIP_ERROR SendMessage(void * appReqState, PacketBuffer * buffer);
+
+ /**
+ * @brief
+ * Disconnect from a connected device
+ *
+ * @return CHIP_ERROR If the device was disconnected successfully
+ */
+ CHIP_ERROR DisconnectDevice();
+
+ // ----- IO -----
+ /**
+ * @brief
+ * Allow the CHIP Stack to process any pending events
+ * This can be called in an event handler loop to tigger callbacks within the CHIP stack
+ * Note - Some platforms might need to implement their own event handler
+ */
+ void ServiceEvents();
+
+private:
+ enum
+ {
+ kState_NotInitialized = 0,
+ kState_Initialized = 1
+ } mState;
+
+ enum ConnectionState
+ {
+ kConnectionState_NotConnected = 0,
+ kConnectionState_Connected = 1,
+ };
+
+ System::Layer * mSystemLayer;
+ Inet::InetLayer * mInetLayer;
+ ChipConnection * mDeviceCon;
+
+ ConnectionState mConState;
+ void * mAppReqState;
+
+ union
+ {
+ CompleteHandler General;
+ MessageReceiveHandler Response;
+ } mOnComplete;
+
+ ErrorHandler mOnError;
+ PacketBuffer * mCurReqMsg;
+
+ uint64_t mDeviceId;
+ IPAddress mDeviceAddr;
+ uint16_t mDevicePort;
+
+ void ClearRequestState();
+ void ClearOpState();
+
+ static void OnReceiveMessage(ChipConnection * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo);
+ static void OnReceiveError(ChipConnection * con, CHIP_ERROR err, const IPPacketInfo * pktInfo);
+};
+
+} // namespace DeviceController
+} // namespace chip
+
+#endif // __CHIPDEVICECONTROLLER_H
diff --git a/src/controller/DeviceController.am b/src/controller/DeviceController.am
new file mode 100644
index 0000000..306a5a6
--- /dev/null
+++ b/src/controller/DeviceController.am
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2020 Project CHIP Authors
+# Copyright (c) 2014-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.
+#
+
+#
+# Description:
+# This file is the GNU automake header for the CHIP DeviceController
+# library sources.
+#
+
+# The ChipDeviceController is designed for use in client applications (e.g.
+# mobiles) or within resource rich devices (typically linux based). As
+# such it depends on the presense of a generalized heap (malloc el al).
+# In contexts where this isn't available, simply skip building the Device
+# Controller code altogether.
+
+CHIP_BUILD_DEVICE_CONTROLLER_SOURCE_FILES = \
+ $(NULL)
+
+CHIP_BUILD_DEVICE_CONTROLLER_HEADER_FILES = \
+$(NULL)
+
+if CONFIG_HAVE_HEAP
+
+CHIP_BUILD_DEVICE_CONTROLLER_SOURCE_FILES += \
+ @top_builddir@/src/controller/CHIPDeviceController.cpp \
+ $(NULL)
+
+CHIP_BUILD_DEVICE_CONTROLLER_HEADER_FILES += \
+ @top_builddir@/src/controller/CHIPDeviceController.h \
+ $(NULL)
+
+endif # CONFIG_HAVE_HEAP
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 9104897..2d29d90 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -30,15 +30,17 @@
# Pull in the sources that comprise the CHIP library.
-include ../system/SystemLayer.am
-include ../inet/InetLayer.am
include ../ble/BleLayer.am
+include ../controller/DeviceController.am
+include ../inet/InetLayer.am
+include ../system/SystemLayer.am
include core/CoreLayer.am
include support/SupportLayer.am
EXTRA_DIST = \
$(CHIP_BUILD_CORE_LAYER_HEADER_FILES) \
- $(CHIP_BUILD_SUPPORT_LAYER_HEADER_FILES)
+ $(CHIP_BUILD_SUPPORT_LAYER_HEADER_FILES) \
+ $(CHIP_BUILD_DEVICE_CONTROLLER_HEADER_FILES)
lib_LIBRARIES = libCHIP.a
@@ -61,6 +63,7 @@
libCHIP_a_SOURCES += $(CHIP_BUILD_INET_LAYER_SOURCE_FILES)
libCHIP_a_SOURCES += $(CHIP_BUILD_CORE_LAYER_SOURCE_FILES)
libCHIP_a_SOURCES += $(CHIP_BUILD_SUPPORT_LAYER_SOURCE_FILES)
+libCHIP_a_SOURCES += $(CHIP_BUILD_DEVICE_CONTROLLER_SOURCE_FILES)
if CONFIG_NETWORK_LAYER_BLE
libCHIP_a_SOURCES += $(CHIP_BUILD_BLE_LAYER_SOURCE_FILES)
diff --git a/src/lib/core/CHIPConnection.cpp b/src/lib/core/CHIPConnection.cpp
new file mode 100644
index 0000000..5c0febe
--- /dev/null
+++ b/src/lib/core/CHIPConnection.cpp
@@ -0,0 +1,258 @@
+/*
+ *
+ * Copyright (c) 2020 Project CHIP Authors
+ * 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 CHIP Connection object that maintains a UDP connection.
+ * TODO This class should be extended to support TCP as well...
+ *
+ */
+
+#include <core/CHIPConnection.h>
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+#include <inttypes.h>
+
+namespace chip {
+
+ChipConnection::ChipConnection() : mState(kState_NotReady), mRefCount(1)
+{
+ mState = kState_NotReady;
+ mRefCount = 1;
+ mUDPEndPoint = NULL;
+ mRefCount = 1;
+ OnMessageReceived = NULL;
+ OnReceiveError = NULL;
+ mPeerNodeId = 0;
+ mPeerAddr = IPAddress::Any;
+ mPeerPort = 0;
+}
+
+void ChipConnection::Init(Inet::InetLayer * inetLayer)
+{
+ if (mState != kState_NotReady)
+ {
+ return;
+ }
+
+ mInetLayer = inetLayer;
+ mState = kState_ReadyToConnect;
+
+} // namespace chip
+
+CHIP_ERROR ChipConnection::Connect(uint64_t peerNodeId, const IPAddress & peerAddr, uint16_t peerPort)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ VerifyOrExit(mState == kState_ReadyToConnect, err = CHIP_ERROR_INCORRECT_STATE);
+
+ mPeerNodeId = peerNodeId;
+ mPeerAddr = peerAddr;
+ mPeerPort = (peerPort != 0) ? peerPort : CHIP_PORT;
+
+ // Bump the reference count when we start the connection process. The corresponding decrement happens when the
+ // DoClose() method is called. This ensures the object stays live while there's the possibility of a callback
+ // happening from an underlying layer.
+ mRefCount++;
+
+ ChipLogProgress(Inet, "Connection start %016llX", peerNodeId);
+ err = DoConnect();
+exit:
+ return err;
+}
+
+CHIP_ERROR ChipConnection::DoConnect()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ err = mInetLayer->NewUDPEndPoint(&mUDPEndPoint);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogProgress(Inet, "Error: %s\n Couldn't create connection\n", ErrorStr(err));
+ return err;
+ }
+
+ err = mUDPEndPoint->Bind(mPeerAddr.Type(), IPAddress::Any, CHIP_PORT);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogProgress(Inet, "Error: %s\n Bind failed\n", ErrorStr(err));
+ return err;
+ }
+
+ err = mUDPEndPoint->Listen();
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogProgress(Inet, "Error: %s\n Listen failed\n", ErrorStr(err));
+ return err;
+ }
+
+ mUDPEndPoint->AppState = this;
+ mUDPEndPoint->OnMessageReceived = HandleDataReceived;
+ mUDPEndPoint->OnReceiveError = HandleReceiveError;
+
+#if CHIP_PROGRESS_LOGGING
+ {
+ char ipAddrStr[64];
+ mPeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
+ ChipLogProgress(Inet, "Connection started %s %d", ipAddrStr, (int) mPeerPort);
+ }
+#endif
+ mState = kState_Connected;
+
+ return err;
+}
+
+CHIP_ERROR ChipConnection::SendMessage(PacketBuffer * msgBuf)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ VerifyOrExit(StateAllowsSend(), err = CHIP_ERROR_INCORRECT_STATE);
+
+ IPPacketInfo addrInfo;
+ addrInfo.Clear();
+ addrInfo.DestAddress = mPeerAddr;
+ addrInfo.DestPort = mPeerPort;
+
+ err = mUDPEndPoint->SendMsg(&addrInfo, msgBuf);
+ msgBuf = NULL;
+
+exit:
+ if (msgBuf != NULL)
+ {
+ PacketBuffer::Free(msgBuf);
+ msgBuf = NULL;
+ }
+
+ return err;
+}
+
+void ChipConnection::HandleDataReceived(IPEndPointBasis * endPoint, chip::System::PacketBuffer * msg, const IPPacketInfo * pktInfo)
+{
+ UDPEndPoint * udpEndPoint = static_cast<UDPEndPoint *>(endPoint);
+ ChipConnection * connection = (ChipConnection *) udpEndPoint->AppState;
+
+ // TODO this where where messages should be decoded
+ if (connection->StateAllowsReceive() && msg != NULL)
+ {
+ connection->OnMessageReceived(connection, msg, pktInfo);
+ }
+}
+
+void ChipConnection::HandleReceiveError(IPEndPointBasis * endPoint, CHIP_ERROR err, const IPPacketInfo * pktInfo)
+{
+ UDPEndPoint * udpEndPoint = static_cast<UDPEndPoint *>(endPoint);
+ ChipConnection * connection = (ChipConnection *) udpEndPoint->AppState;
+ if (connection->StateAllowsReceive())
+ {
+ connection->OnReceiveError(connection, err, pktInfo);
+ }
+}
+/**
+ * Performs a non-blocking graceful close of the UDP based ChipConnection, delivering any
+ * remaining outgoing data before resetting the connection.
+ *
+ * This method provides no strong guarantee that any outgoing message not acknowledged at the application
+ * protocol level has been received by the remote peer.
+ *
+ * Once Close() has been called, the ChipConnection object can no longer be used for further communication.
+ *
+ * Calling Close() decrements the reference count associated with the ChipConnection object, whether or not
+ * the connection is open/active at the time the method is called. If this results in the reference count
+ * reaching zero, the resources associated with the connection object are freed. When this happens, the
+ * application must have no further interactions with the object.
+ *
+ * @sa Shutdown(), Abort(), Retain() and Release().
+ *
+ * @return #CHIP_NO_ERROR unconditionally.
+ *
+ */
+CHIP_ERROR ChipConnection::Close()
+{
+ // Perform a graceful close.
+ DoClose(CHIP_NO_ERROR);
+
+ // Decrement the ref count that was added when the ChipConnection object
+ // was allocated.
+ VerifyOrDie(mRefCount != 0);
+ mRefCount--;
+
+ return CHIP_NO_ERROR;
+}
+
+void ChipConnection::DoClose(CHIP_ERROR err)
+{
+ if (mState != kState_Closed)
+ {
+ if (mUDPEndPoint != NULL)
+ {
+ if (err == CHIP_NO_ERROR)
+ {
+ mUDPEndPoint->Close();
+ }
+ mUDPEndPoint->Free();
+ mUDPEndPoint = NULL;
+ }
+ }
+ uint8_t oldState = mState;
+ mState = kState_Closed;
+ ChipLogProgress(Inet, "Connection closed %ld", (long) err);
+
+ // Decrement the ref count that was added when the connection started.
+ if (oldState != kState_ReadyToConnect && oldState != kState_Closed)
+ {
+ VerifyOrDie(mRefCount != 0);
+ mRefCount--;
+ }
+}
+
+/**
+ * Reserve a reference to the ChipConnection object.
+ *
+ * The Retain() method increments the reference count associated with the ChipConnection object. For every
+ * call to Retain(), the application is responsible for making a corresponding call to either Release(), Close()
+ * or Abort().
+ */
+void ChipConnection::Retain()
+{
+ VerifyOrDie(mRefCount < UINT8_MAX);
+ ++mRefCount;
+}
+
+/**
+ * Decrement the reference count on the ChipConnection object.
+ *
+ * The Release() method decrements the reference count associated with the ChipConnection object. If
+ * this results in the reference count reaching zero, the connection is closed and the connection object
+ * is freed. When this happens, the application must have no further interactions with the object.
+ */
+void ChipConnection::Release()
+{
+ // If the only reference that will remain after this call is the one that was automatically added
+ // when the connection started, close the connection.
+ if (mRefCount == 2 && mState != kState_ReadyToConnect && mState != kState_Closed)
+ {
+ DoClose(CHIP_NO_ERROR);
+ }
+
+ VerifyOrDie(mRefCount != 0);
+ mRefCount--;
+}
+
+} // namespace chip
\ No newline at end of file
diff --git a/src/lib/core/CHIPConnection.h b/src/lib/core/CHIPConnection.h
new file mode 100644
index 0000000..74e2f7f
--- /dev/null
+++ b/src/lib/core/CHIPConnection.h
@@ -0,0 +1,152 @@
+/*
+ *
+ * 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 defines the CHIP Connection object that maintains a UDP connection.
+ * It binds to any avaiable local addr and port and begins listening.
+ * TODO This class should be extended to support TCP as well...
+ *
+ */
+
+#ifndef __CHIPCONNECTION_H__
+#define __CHIPCONNECTION_H__
+
+#include <core/CHIPCore.h>
+#include <inet/IPAddress.h>
+#include <inet/IPEndPointBasis.h>
+
+namespace chip {
+
+using namespace System;
+
+class DLL_EXPORT ChipConnection
+{
+public:
+ /**
+ * @enum State
+ *
+ * @brief
+ * The State of the CHIP connection object.
+ *
+ */
+ enum State
+ {
+ // TODO need more modes when TCP support is added
+ kState_NotReady = 0, /**< State before initialization. */
+ kState_ReadyToConnect = 1, /**< State after initialization of the CHIP connection. */
+ kState_Connected = 2, /**< State when the connection has been established. */
+ kState_Closed = 3 /**< State when the connection is closed. */
+ };
+
+ void * AppState; /**< A pointer to the application-specific state object. */
+
+ /**
+ * @brief
+ * Initialize a CHIP Connection
+ *
+ * @param inetLayer A pointer to the <tt>chip::Inet::InetLayer</tt>
+ */
+ void Init(Inet::InetLayer * inetLayer);
+
+ /**
+ * @brief
+ * Attempt to establish a connection to the given peer
+ *
+ * @param peerNodeId Currently unused; a NodeId to identify this peer
+ * @param peerAddr The <tt>chip::Inet::IPAddress</tt> of the requested peer
+ * @param peerPort The port of the requested peer
+ * @return CHIP_ERROR The connection result
+ */
+ CHIP_ERROR Connect(uint64_t peerNodeId, const IPAddress & peerAddr, uint16_t peerPort = 0);
+
+ /**
+ * @brief
+ * Send a message to the currently connected peer
+ *
+ * @param msgBuf A PacketBuffer containing the message to be sent
+ * @return CHIP_ERROR The send result
+ *
+ * @details
+ * This method calls <tt>chip::System::PacketBuffer::Free</tt> on
+ * behalf of the caller regardless of the return status.
+ */
+ CHIP_ERROR SendMessage(PacketBuffer * msgBuf);
+
+ /**
+ * @brief
+ * Close an existing connection. Once close is called, the ChipConnection object can no longer be used
+ *
+ * @return CHIP_ERROR The close result
+ */
+ CHIP_ERROR Close(void);
+
+ void Retain(void);
+ void Release(void);
+
+ /**
+ * This function is the application callback that is invoked when a message is received over a
+ * Chip connection.
+ *
+ * @param[in] con A pointer to the ChipConnection object.
+ *
+ * @param[in] msgBuf A pointer to the PacketBuffer object holding the message.
+ *
+ * @param[in] pktInfo A pointer to the IPPacketInfo object carrying sender details.
+ *
+ */
+ typedef void (*MessageReceiveHandler)(ChipConnection * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo);
+ MessageReceiveHandler OnMessageReceived;
+
+ /**
+ * This function is the application callback invoked upon encountering an error when receiving
+ * a Chip message.
+ *
+ * @param[in] con A pointer to the ChipConnection object.
+ *
+ * @param[in] err The CHIP_ERROR encountered when receiving data over the connection.
+ *
+ * @param[in] pktInfo A pointer to the IPPacketInfo object carrying sender details.
+ *
+ */
+ typedef void (*ReceiveErrorHandler)(ChipConnection * con, CHIP_ERROR err, const IPPacketInfo * pktInfo);
+ ReceiveErrorHandler OnReceiveError;
+
+ ChipConnection();
+
+private:
+ Inet::InetLayer * mInetLayer;
+ UDPEndPoint * mUDPEndPoint;
+ uint64_t mPeerNodeId;
+ IPAddress mPeerAddr;
+ uint16_t mPeerPort;
+ State mState;
+ uint8_t mRefCount;
+
+ CHIP_ERROR DoConnect();
+ void DoClose(CHIP_ERROR err);
+ bool StateAllowsSend(void) const { return mState == kState_Connected; }
+ bool StateAllowsReceive(void) const { return mState == kState_Connected; }
+
+ static void HandleDataReceived(IPEndPointBasis * endPoint, chip::System::PacketBuffer * msg, const IPPacketInfo * pktInfo);
+ static void HandleReceiveError(IPEndPointBasis * endPoint, INET_ERROR err, const IPPacketInfo * pktInfo);
+};
+
+} // namespace chip
+
+#endif // __CHIPCONNECTION_H__
\ No newline at end of file
diff --git a/src/lib/core/CoreLayer.am b/src/lib/core/CoreLayer.am
index 4fd1b8c..4b2a4a5 100644
--- a/src/lib/core/CoreLayer.am
+++ b/src/lib/core/CoreLayer.am
@@ -32,6 +32,7 @@
core/CHIPTLVWriter.cpp \
core/CHIPTLVUpdater.cpp \
core/CHIPKeyIds.cpp \
+ core/CHIPConnection.cpp \
$(NULL)
CHIP_BUILD_CORE_LAYER_HEADER_FILES = \
@@ -50,4 +51,5 @@
core/CHIPTimeConfig.h \
core/CHIPTunnelConfig.h \
core/CHIPKeyIds.h \
+ core/CHIPConnection.h \
$(NULL)
diff --git a/src/lib/core/tests/Makefile.am b/src/lib/core/tests/Makefile.am
index b7c5d31..45a899b 100644
--- a/src/lib/core/tests/Makefile.am
+++ b/src/lib/core/tests/Makefile.am
@@ -43,6 +43,7 @@
libCoreTests_a_SOURCES = \
TestCHIPErrorStr.cpp \
TestCHIPTLV.cpp \
+ TestCHIPConnection.cpp \
$(NULL)
libCoreTests_adir = $(includedir)
@@ -86,6 +87,7 @@
check_PROGRAMS = \
TestCHIPErrorStr \
TestCHIPTLV \
+ TestCHIPConnection \
$(NULL)
# Test applications and scripts that should be built and run when the
@@ -109,6 +111,8 @@
TestCHIPTLV_SOURCES = TestCHIPTLVDriver.cpp
TestCHIPTLV_LDADD = $(COMMON_LDADD)
+TestCHIPConnection_SOURCES = TestCHIPConnectionDriver.cpp
+TestCHIPConnection_LDADD = $(COMMON_LDADD)
#
# Foreign make dependencies
#
diff --git a/src/lib/core/tests/TestCHIPConnection.cpp b/src/lib/core/tests/TestCHIPConnection.cpp
new file mode 100644
index 0000000..db9ffd2
--- /dev/null
+++ b/src/lib/core/tests/TestCHIPConnection.cpp
@@ -0,0 +1,260 @@
+/*
+ *
+ * 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 implements unit tests for the CHIPConnection implementation.
+ */
+
+#include "TestCore.h"
+
+#include <nlbyteorder.h>
+#include <nlunit-test.h>
+#include <errno.h>
+
+#include <core/CHIPCore.h>
+#include <core/CHIPConnection.h>
+
+#include <support/CodeUtils.h>
+
+using namespace chip;
+
+static int Initialize(void * aContext);
+static int Finalize(void * aContext);
+
+struct TestContext
+{
+ nlTestSuite * mSuite;
+ System::Layer mSystemLayer;
+ InetLayer mInetLayer;
+};
+
+struct TestContext sContext;
+
+static const char PAYLOAD[] = "Hello!";
+
+static void MessageReceiveHandler(ChipConnection * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo)
+{
+ size_t data_len = msgBuf->DataLength();
+
+ int compare = memcmp(msgBuf->Start(), PAYLOAD, data_len);
+ NL_TEST_ASSERT(reinterpret_cast<nlTestSuite *>(con->AppState), compare == 0);
+};
+
+static void ReceiveErrorHandler(ChipConnection * con, CHIP_ERROR err, const IPPacketInfo * pktInfo)
+{
+ NL_TEST_ASSERT(reinterpret_cast<nlTestSuite *>(con->AppState), false);
+};
+
+static void DriveIO(TestContext & ctx)
+{
+#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
+ // Set the select timeout to 100ms
+ struct timeval aSleepTime;
+ aSleepTime.tv_sec = 0;
+ aSleepTime.tv_usec = 100 * 1000;
+
+ fd_set readFDs, writeFDs, exceptFDs;
+ int numFDs = 0;
+
+ FD_ZERO(&readFDs);
+ FD_ZERO(&writeFDs);
+ FD_ZERO(&exceptFDs);
+
+ if (ctx.mSystemLayer.State() == System::kLayerState_Initialized)
+ ctx.mSystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+
+ if (ctx.mInetLayer.State == Inet::InetLayer::kState_Initialized)
+ ctx.mInetLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);
+
+ int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
+ if (selectRes < 0)
+ {
+ printf("select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
+ NL_TEST_ASSERT(ctx.mSuite, false);
+ return;
+ }
+
+ if (ctx.mSystemLayer.State() == System::kLayerState_Initialized)
+ {
+ ctx.mSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+ }
+
+ if (ctx.mInetLayer.State == Inet::InetLayer::kState_Initialized)
+ {
+ ctx.mInetLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
+ }
+#endif
+}
+
+CHIP_ERROR InitLayers(System::Layer & systemLayer, InetLayer & inetLayer)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ // Initialize the CHIP System Layer.
+ err = systemLayer.Init(NULL);
+ SuccessOrExit(err);
+
+ // Initialize the CHIP Inet layer.
+ err = inetLayer.Init(systemLayer, NULL);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+void CheckSimpleInitTest(nlTestSuite * inSuite, void * inContext)
+{
+ TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
+
+ ChipConnection conn;
+ conn.Init(&ctx.mInetLayer);
+ CHIP_ERROR err = conn.Close();
+ NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+}
+
+void CheckSimpleConnectTest(nlTestSuite * inSuite, void * inContext)
+{
+ TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
+
+ IPAddress addr;
+ IPAddress::FromString("127.0.0.1", addr);
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ ChipConnection conn;
+ conn.Init(&ctx.mInetLayer);
+ err = conn.Connect(0, addr, 0);
+ NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+ err = conn.Connect(0, addr, 0);
+ NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INCORRECT_STATE);
+
+ err = conn.Close();
+ NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+}
+
+void CheckMessageTest(nlTestSuite * inSuite, void * inContext)
+{
+ TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
+
+ size_t payload_len = sizeof(PAYLOAD);
+
+ chip::System::PacketBuffer * buffer = chip::System::PacketBuffer::NewWithAvailableSize(payload_len);
+ memmove(buffer->Start(), PAYLOAD, payload_len);
+ buffer->SetDataLength(payload_len);
+
+ IPAddress addr;
+ IPAddress::FromString("127.0.0.1", addr);
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ ChipConnection conn;
+ conn.Init(&ctx.mInetLayer);
+ conn.AppState = inSuite;
+ conn.OnMessageReceived = MessageReceiveHandler;
+ conn.OnReceiveError = ReceiveErrorHandler;
+
+ err = conn.Connect(0, addr, 0);
+ NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+
+ // Should be able to send a message to itself by just calling send.
+ conn.SendMessage(buffer);
+
+ // allow the send and recv enough time
+ DriveIO(ctx);
+ sleep(1);
+ DriveIO(ctx);
+
+ err = conn.Close();
+ NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
+}
+
+// Test Suite
+
+/**
+ * Test Suite that lists all the test functions.
+ */
+// clang-format off
+static const nlTest sTests[] =
+{
+ NL_TEST_DEF("Simple Init Test", CheckSimpleInitTest),
+ NL_TEST_DEF("Simple Connect Test", CheckSimpleConnectTest),
+ NL_TEST_DEF("Message Self Test", CheckMessageTest),
+
+ NL_TEST_SENTINEL()
+};
+// clang-format on
+
+// clang-format off
+static nlTestSuite sSuite =
+{
+ "Test-CHIP-Connection",
+ &sTests[0],
+ Initialize,
+ Finalize
+};
+// clang-format on
+
+/**
+ * Initialize the test suite.
+ */
+static int Initialize(void * aContext)
+{
+ TestContext & lContext = *reinterpret_cast<TestContext *>(aContext);
+
+ CHIP_ERROR err = InitLayers(lContext.mSystemLayer, lContext.mInetLayer);
+ if (err != CHIP_NO_ERROR)
+ {
+ return FAILURE;
+ }
+ lContext.mSuite = &sSuite;
+
+ return SUCCESS;
+}
+
+/**
+ * Finalize the test suite.
+ */
+static int Finalize(void * aContext)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ TestContext & lContext = *reinterpret_cast<TestContext *>(aContext);
+
+ lContext.mSuite = NULL;
+
+ err = lContext.mSystemLayer.Shutdown();
+ if (err != CHIP_NO_ERROR)
+ {
+ return FAILURE;
+ }
+ err = lContext.mInetLayer.Shutdown();
+ if (err != CHIP_NO_ERROR)
+ {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Main
+ */
+int TestCHIPConnection()
+{
+ // Run test suit against one context
+ nlTestRunner(&sSuite, &sContext);
+
+ return (nlTestRunnerStats(&sSuite));
+}
diff --git a/src/lib/core/tests/TestCHIPConnectionDriver.cpp b/src/lib/core/tests/TestCHIPConnectionDriver.cpp
new file mode 100644
index 0000000..09af2d8
--- /dev/null
+++ b/src/lib/core/tests/TestCHIPConnectionDriver.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright (c) 2020 Project CHIP Authors
+ *
+ * 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 a standalone/native program executable
+ * test driver for the CHIP core library CHIP Connection tests.
+ *
+ */
+
+#include "TestCore.h"
+
+#include <nlunit-test.h>
+
+int main(void)
+{
+ // Generate machine-readable, comma-separated value (CSV) output.
+ nlTestSetOutputStyle(OUTPUT_CSV);
+
+ return (TestCHIPConnection());
+}
\ No newline at end of file
diff --git a/src/lib/core/tests/TestCore.h b/src/lib/core/tests/TestCore.h
index ffb95d6..3426af0 100644
--- a/src/lib/core/tests/TestCore.h
+++ b/src/lib/core/tests/TestCore.h
@@ -31,6 +31,7 @@
int TestCHIPErrorStr(void);
int TestCHIPTLV(void);
+int TestCHIPConnection(void);
#ifdef __cplusplus
}
diff --git a/src/lib/support/logging/CHIPLogging.cpp b/src/lib/support/logging/CHIPLogging.cpp
index 8b31250..d5d176b 100644
--- a/src/lib/support/logging/CHIPLogging.cpp
+++ b/src/lib/support/logging/CHIPLogging.cpp
@@ -64,7 +64,7 @@
"TLV" // TLV
"ASN" // ASN1
"CR\0" // Crypto
- "DM\0" // DeviceManager
+ "CTL\0" // Controller
"AL\0" // Alarm
"BDX" // BulkDataTransfer
"DMG" // DataManagement
diff --git a/src/lib/support/logging/CHIPLogging.h b/src/lib/support/logging/CHIPLogging.h
index 5973a82..203eb12 100644
--- a/src/lib/support/logging/CHIPLogging.h
+++ b/src/lib/support/logging/CHIPLogging.h
@@ -86,7 +86,7 @@
kLogModule_TLV,
kLogModule_ASN1,
kLogModule_Crypto,
- kLogModule_DeviceManager,
+ kLogModule_Controller,
kLogModule_Alarm,
kLogModule_BDX,
kLogModule_DataManagement,