| /* |
| * |
| * 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. |
| */ |
| |
| #include "Server.h" |
| |
| #include "FreeRTOS.h" |
| #include "nrf_log.h" |
| #include "task.h" |
| #include <string.h> |
| #include <sys/param.h> |
| |
| #include "lwip/err.h" |
| #include "lwip/sockets.h" |
| #include "lwip/sys.h" |
| #include <lwip/netdb.h> |
| |
| #include <inet/IPAddress.h> |
| #include <inet/InetError.h> |
| #include <inet/InetLayer.h> |
| #include <platform/CHIPDeviceLayer.h> |
| #include <support/CodeUtils.h> |
| #include <support/ErrorStr.h> |
| #include <system/SystemPacketBuffer.h> |
| #include <transport/SecureSessionMgr.h> |
| #include <transport/UDP.h> |
| |
| #if CHIP_ENABLE_OPENTHREAD |
| #include <openthread/message.h> |
| #include <openthread/udp.h> |
| #include <platform/OpenThread/OpenThreadUtils.h> |
| #include <platform/ThreadStackManager.h> |
| #include <platform/internal/DeviceNetworkInfo.h> |
| #include <platform/nRF5/ThreadStackManagerImpl.h> |
| #endif |
| |
| #include "attribute-storage.h" |
| #include "gen/znet-bookkeeping.h" |
| #include "util.h" |
| #include <app/chip-zcl-zpro-codec.h> |
| |
| using namespace ::chip; |
| using namespace ::chip::Inet; |
| using namespace ::chip::Transport; |
| using namespace ::chip::DeviceLayer; |
| |
| // Transport Callbacks |
| namespace { |
| |
| #ifndef EXAMPLE_SERVER_NODEID |
| // "nRF5" |
| #define EXAMPLE_SERVER_NODEID 0x3546526e |
| #endif // EXAMPLE_SERVER_NODEID |
| |
| char deviceName[128]; |
| constexpr uint16_t kUDPBroadcastPort = 23367; |
| |
| const uint8_t local_private_key[] = { 0xc6, 0x1a, 0x2f, 0x89, 0x36, 0x67, 0x2b, 0x26, 0x12, 0x47, 0x4f, |
| 0x11, 0x0e, 0x34, 0x15, 0x81, 0x81, 0x12, 0xfc, 0x36, 0xeb, 0x65, |
| 0x61, 0x07, 0xaa, 0x63, 0xe8, 0xc5, 0x22, 0xac, 0x52, 0xa1 }; |
| |
| const uint8_t remote_public_key[] = { 0x04, 0x30, 0x77, 0x2c, 0xe7, 0xd4, 0x0a, 0xf2, 0xf3, 0x19, 0xbd, 0xfb, 0x1f, |
| 0xcc, 0x88, 0xd9, 0x83, 0x25, 0x89, 0xf2, 0x09, 0xf3, 0xab, 0xe4, 0x33, 0xb6, |
| 0x7a, 0xff, 0x73, 0x3b, 0x01, 0x35, 0x34, 0x92, 0x73, 0x14, 0x59, 0x0b, 0xbd, |
| 0x44, 0x72, 0x1b, 0xcd, 0xb9, 0x02, 0x53, 0xd9, 0xaf, 0xcc, 0x1a, 0xcd, 0xae, |
| 0xe8, 0x87, 0x2e, 0x52, 0x3b, 0x98, 0xf0, 0xa1, 0x88, 0x4a, 0xe3, 0x03, 0x75 }; |
| |
| class ServerCallback : public SecureSessionMgrCallback |
| { |
| public: |
| virtual void OnMessageReceived(const MessageHeader & header, Transport::PeerConnectionState * state, |
| System::PacketBuffer * buffer, SecureSessionMgrBase * mgr) |
| { |
| const size_t data_len = buffer->DataLength(); |
| char src_addr[PeerAddress::kMaxToStringSize]; |
| |
| // as soon as a client connects, assume it is connected |
| VerifyOrExit(buffer != NULL, NRF_LOG_INFO("Received data but couldn't process it...")); |
| VerifyOrExit(header.GetSourceNodeId().HasValue(), NRF_LOG_INFO("Unknown source for received message")); |
| |
| VerifyOrExit(state->GetPeerNodeId() != kUndefinedNodeId, NRF_LOG_INFO("Unknown source for received message")); |
| |
| state->GetPeerAddress().ToString(src_addr, sizeof(src_addr)); |
| |
| NRF_LOG_INFO("Packet received from %s: %zu bytes", src_addr, static_cast<size_t>(data_len)); |
| |
| HandleDataModelMessage(header, buffer, mgr); |
| buffer = NULL; |
| |
| exit: |
| // SendTo calls Free on the buffer without an AddRef, if SendTo was not called, free the buffer. |
| if (buffer != NULL) |
| { |
| System::PacketBuffer::Free(buffer); |
| } |
| } |
| |
| virtual void OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) |
| { |
| CHIP_ERROR err; |
| |
| NRF_LOG_INFO("Received a new connection."); |
| |
| err = state->GetSecureSession().TemporaryManualKeyExchange(remote_public_key, sizeof(remote_public_key), local_private_key, |
| sizeof(local_private_key)); |
| VerifyOrExit(err == CHIP_NO_ERROR, NRF_LOG_INFO("Failed to setup encryption")); |
| |
| exit: |
| return; |
| } |
| |
| private: |
| /** |
| * Handle a message that should be processed via our data model processing |
| * codepath. |
| * |
| * @param [in] buffer The buffer holding the message. This function guarantees |
| * that it will free the buffer before returning. |
| */ |
| void HandleDataModelMessage(const MessageHeader & header, System::PacketBuffer * buffer, SecureSessionMgrBase * mgr) |
| { |
| EmberApsFrame frame; |
| bool ok = extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) > 0; |
| if (ok) |
| { |
| NRF_LOG_INFO("APS frame processing success!"); |
| } |
| else |
| { |
| NRF_LOG_INFO("APS frame processing failure!"); |
| System::PacketBuffer::Free(buffer); |
| return; |
| } |
| |
| ChipResponseDestination responseDest(header.GetSourceNodeId().Value(), mgr); |
| uint8_t * message; |
| uint16_t messageLen = extractMessage(buffer->Start(), buffer->DataLength(), &message); |
| ok = emberAfProcessMessage(&frame, |
| 0, // type |
| message, messageLen, |
| &responseDest, // source identifier |
| NULL); |
| |
| System::PacketBuffer::Free(buffer); |
| |
| if (ok) |
| { |
| NRF_LOG_INFO("Data model processing success!"); |
| } |
| else |
| { |
| NRF_LOG_INFO("Data model processing failure!"); |
| } |
| } |
| }; |
| |
| static ServerCallback gCallbacks; |
| |
| } // namespace |
| |
| void SetDeviceName(const char * newDeviceName) |
| { |
| strncpy(deviceName, newDeviceName, sizeof(deviceName) - 1); |
| } |
| |
| void PublishService() |
| { |
| chip::Inet::IPAddress addr; |
| if (!ConnectivityMgrImpl().IsThreadAttached()) |
| { |
| return; |
| } |
| ThreadStackMgrImpl().LockThreadStack(); |
| otError error = OT_ERROR_NONE; |
| otMessageInfo messageInfo; |
| otUdpSocket mSocket; |
| otMessage * message = nullptr; |
| |
| memset(&mSocket, 0, sizeof(mSocket)); |
| memset(&messageInfo, 0, sizeof(messageInfo)); |
| |
| // Use mesh local EID by default, if we have GUA, use that IP address. |
| memcpy(&messageInfo.mSockAddr, otThreadGetMeshLocalEid(ThreadStackMgrImpl().OTInstance()), sizeof(messageInfo.mSockAddr)); |
| |
| // Select a address to send |
| const otNetifAddress * otAddrs = otIp6GetUnicastAddresses(ThreadStackMgrImpl().OTInstance()); |
| for (const otNetifAddress * otAddr = otAddrs; otAddr != NULL; otAddr = otAddr->mNext) |
| { |
| addr = chip::DeviceLayer::Internal::ToIPAddress(otAddr->mAddress); |
| if (otAddr->mValid && addr.IsIPv6GlobalUnicast()) |
| { |
| memcpy(&messageInfo.mSockAddr, &(otAddr->mAddress), sizeof(otAddr->mAddress)); |
| break; |
| } |
| } |
| |
| message = otUdpNewMessage(ThreadStackMgrImpl().OTInstance(), nullptr); |
| otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr); |
| messageInfo.mPeerPort = kUDPBroadcastPort; |
| otMessageAppend(message, deviceName, static_cast<uint16_t>(strlen(deviceName))); |
| |
| error = otUdpSend(ThreadStackMgrImpl().OTInstance(), &mSocket, message, &messageInfo); |
| |
| if (error != OT_ERROR_NONE && message != nullptr) |
| { |
| otMessageFree(message); |
| NRF_LOG_INFO("Failed to otUdpSend: %d", error); |
| } |
| ThreadStackMgrImpl().UnlockThreadStack(); |
| } |
| |
| void InitDataModelHandler() |
| { |
| emberAfEndpointConfigure(); |
| emAfInit(); |
| } |
| |
| // The echo server assumes the platform's networking has been setup already |
| void StartServer(DemoSessionManager * sessions) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| err = sessions->Init(EXAMPLE_SERVER_NODEID, &DeviceLayer::SystemLayer, |
| UdpListenParameters(&DeviceLayer::InetLayer).SetAddressType(kIPAddressType_IPv6)); |
| SuccessOrExit(err); |
| |
| sessions->SetDelegate(&gCallbacks); |
| |
| exit: |
| if (err != CHIP_NO_ERROR) |
| { |
| NRF_LOG_ERROR("ERROR setting up transport: %s", ErrorStr(err)); |
| } |
| else |
| { |
| NRF_LOG_INFO("Lock Server Listening..."); |
| } |
| } |