| /* |
| * |
| * 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 a derived unsolicited responder |
| * (i.e., server) for the Weave Service Provisioning profile used |
| * for the Weave mock device command line functional testing |
| * tool. |
| * |
| */ |
| |
| #define __STDC_FORMAT_MACROS |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| |
| #include "ToolCommon.h" |
| #include "MockSPServer.h" |
| #include "MockDDServer.h" |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Core/WeaveTLV.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include <Weave/Profiles/device-description/DeviceDescription.h> |
| #include <Weave/Profiles/common/CommonProfile.h> |
| #include <Weave/Support/ErrorStr.h> |
| #include "CASEOptions.h" |
| |
| using namespace nl::Weave; |
| using namespace nl::Weave::TLV; |
| using namespace nl::Weave::Profiles; |
| using namespace nl::Weave::Profiles::ServiceProvisioning; |
| using namespace nl::Weave::Profiles::DeviceDescription; |
| |
| extern MockDeviceDescriptionServer MockDDServer; |
| |
| MockServiceProvisioningServer::MockServiceProvisioningServer() |
| { |
| mPersistedServiceId = 0; |
| mPersistedAccountId = NULL; |
| mPersistedServiceConfig = NULL; |
| mPersistedServiceConfigLen = 0; |
| mPairingServerCon = NULL; |
| mPairingServerBinding = NULL; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::Init(WeaveExchangeManager *exchangeMgr) |
| { |
| WEAVE_ERROR err; |
| |
| // Initialize the base class. |
| err = this->ServiceProvisioningServer::Init(exchangeMgr); |
| SuccessOrExit(err); |
| |
| // Tell the base class that it should delegate service provisioning requests to us. |
| SetDelegate(this); |
| |
| static char defaultPairingServerAddr[64]; |
| strcpy(defaultPairingServerAddr, "127.0.0.1"); |
| |
| #if WEAVE_CONFIG_ENABLE_TARGETED_LISTEN |
| if (FabricState->ListenIPv4Addr == IPAddress::Any) |
| { |
| if (FabricState->ListenIPv6Addr != IPAddress::Any) |
| FabricState->ListenIPv6Addr.ToString(defaultPairingServerAddr, sizeof(defaultPairingServerAddr)); |
| } |
| else |
| FabricState->ListenIPv4Addr.ToString(defaultPairingServerAddr, sizeof(defaultPairingServerAddr)); |
| #endif |
| |
| PairingEndPointId = FabricState->LocalNodeId; |
| PairingServerAddr = defaultPairingServerAddr; |
| |
| // Clear our state. |
| mPersistedServiceId = 0; |
| mPersistedAccountId = NULL; |
| mPersistedServiceConfig = NULL; |
| mPersistedServiceConfigLen = 0; |
| mPairingServerCon = NULL; |
| mPairingServerBinding = NULL; |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::Shutdown() |
| { |
| ClearPersistedService(); |
| return this->ServiceProvisioningServer::Shutdown(); |
| } |
| |
| void MockServiceProvisioningServer::Reset() |
| { |
| ClearPersistedService(); |
| } |
| |
| void MockServiceProvisioningServer::Preconfig() |
| { |
| // This dummy service config object contains the following information: |
| // |
| // Trusted Certificates: |
| // The Nest Development Root Certificate |
| // A dummy "account" certificate with a common name of "DUMMY-ACCOUNT-ID" (see below) |
| // |
| // Directory End Point: |
| // Endpoint Id: 18B4300200000001 (the service directory endpoint) |
| // Endpoint Host Name: frontdoor.integration.nestlabs.com |
| // Endpoint Port: 11095 (the weave default port) |
| // |
| // The dummy account certificate is: |
| // |
| // 1QAABAABADABCE4vMktB1zrbJAIENwMsgRBEVU1NWS1BQ0NPVU5ULUlEGCYEy6j6GyYFSzVPQjcG |
| // LIEQRFVNTVktQUNDT1VOVC1JRBgkBwImCCUAWiMwCjkEK9nbWmLvurFTKg+ZY7eKMMWKQSmlGU5L |
| // C/N+2sXpszXwdRhtSV2GxEQlB0G006nv7rQq1gpdneA1gykBGDWCKQEkAgUYNYQpATYCBAIEARgY |
| // NYEwAghCPJVfRh5S2xg1gDACCEI8lV9GHlLbGDUMMAEdAIphhmI9F7LSz9JtOT3kJWngkeoFanXO |
| // 3UXrg88wAhx0tCukbRRlt7dxmlqvZNKIYG6zsaAxypJvyvJDGBg= |
| // |
| // The corresponding private key is: |
| // |
| // 1QAABAACACYBJQBaIzACHLr840+Gv3w4EnAr+aMQv0+b8+8wD6VETUI6Z2owAzkEK9nbWmLvurFT |
| // Kg+ZY7eKMMWKQSmlGU5LC/N+2sXpszXwdRhtSV2GxEQlB0G006nv7rQq1gpdneAY |
| // |
| // The following is a fabric access token containing the dummy account certificate and |
| // private key. This can be used to authenticate to the mock device when it has been |
| // configured to use the dummy service config. |
| // |
| // 1QAABAAJADUBMAEITi8yS0HXOtskAgQ3AyyBEERVTU1ZLUFDQ09VTlQtSUQYJgTLqPobJgVLNU9C |
| // NwYsgRBEVU1NWS1BQ0NPVU5ULUlEGCQHAiYIJQBaIzAKOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZ |
| // TksL837axemzNfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4DWDKQEYNYIpASQCBRg1hCkBNgIEAgQB |
| // GBg1gTACCEI8lV9GHlLbGDWAMAIIQjyVX0YeUtsYNQwwAR0AimGGYj0XstLP0m05PeQlaeCR6gVq |
| // dc7dReuDzzACHHS0K6RtFGW3t3GaWq9k0ohgbrOxoDHKkm/K8kMYGDUCJgElAFojMAIcuvzjT4a/ |
| // fDgScCv5oxC/T5vz7zAPpURNQjpnajADOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZTksL837axemz |
| // NfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4BgY |
| // |
| // |
| static const char dummyAccountId[] = "DUMMY-ACCOUNT-ID"; |
| static const uint8_t dummyServiceConfig[] = |
| { |
| 0xd5, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x36, 0x01, 0x15, 0x30, 0x01, 0x08, 0x4e, 0x2f, 0x32, |
| 0x4b, 0x41, 0xd7, 0x3a, 0xdb, 0x24, 0x02, 0x04, 0x37, 0x03, 0x2c, 0x81, 0x10, 0x44, 0x55, 0x4d, |
| 0x4d, 0x59, 0x2d, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2d, 0x49, 0x44, 0x18, 0x26, 0x04, |
| 0xcb, 0xa8, 0xfa, 0x1b, 0x26, 0x05, 0x4b, 0x35, 0x4f, 0x42, 0x37, 0x06, 0x2c, 0x81, 0x10, 0x44, |
| 0x55, 0x4d, 0x4d, 0x59, 0x2d, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2d, 0x49, 0x44, 0x18, |
| 0x24, 0x07, 0x02, 0x26, 0x08, 0x25, 0x00, 0x5a, 0x23, 0x30, 0x0a, 0x39, 0x04, 0x2b, 0xd9, 0xdb, |
| 0x5a, 0x62, 0xef, 0xba, 0xb1, 0x53, 0x2a, 0x0f, 0x99, 0x63, 0xb7, 0x8a, 0x30, 0xc5, 0x8a, 0x41, |
| 0x29, 0xa5, 0x19, 0x4e, 0x4b, 0x0b, 0xf3, 0x7e, 0xda, 0xc5, 0xe9, 0xb3, 0x35, 0xf0, 0x75, 0x18, |
| 0x6d, 0x49, 0x5d, 0x86, 0xc4, 0x44, 0x25, 0x07, 0x41, 0xb4, 0xd3, 0xa9, 0xef, 0xee, 0xb4, 0x2a, |
| 0xd6, 0x0a, 0x5d, 0x9d, 0xe0, 0x35, 0x83, 0x29, 0x01, 0x18, 0x35, 0x82, 0x29, 0x01, 0x24, 0x02, |
| 0x05, 0x18, 0x35, 0x84, 0x29, 0x01, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01, 0x18, 0x18, 0x35, 0x81, |
| 0x30, 0x02, 0x08, 0x42, 0x3c, 0x95, 0x5f, 0x46, 0x1e, 0x52, 0xdb, 0x18, 0x35, 0x80, 0x30, 0x02, |
| 0x08, 0x42, 0x3c, 0x95, 0x5f, 0x46, 0x1e, 0x52, 0xdb, 0x18, 0x35, 0x0c, 0x30, 0x01, 0x1d, 0x00, |
| 0x8a, 0x61, 0x86, 0x62, 0x3d, 0x17, 0xb2, 0xd2, 0xcf, 0xd2, 0x6d, 0x39, 0x3d, 0xe4, 0x25, 0x69, |
| 0xe0, 0x91, 0xea, 0x05, 0x6a, 0x75, 0xce, 0xdd, 0x45, 0xeb, 0x83, 0xcf, 0x30, 0x02, 0x1c, 0x74, |
| 0xb4, 0x2b, 0xa4, 0x6d, 0x14, 0x65, 0xb7, 0xb7, 0x71, 0x9a, 0x5a, 0xaf, 0x64, 0xd2, 0x88, 0x60, |
| 0x6e, 0xb3, 0xb1, 0xa0, 0x31, 0xca, 0x92, 0x6f, 0xca, 0xf2, 0x43, 0x18, 0x18, 0x15, 0x30, 0x01, |
| 0x09, 0x00, 0xa8, 0x34, 0x22, 0xe9, 0xd9, 0x75, 0xe4, 0x55, 0x24, 0x02, 0x04, 0x57, 0x03, 0x00, |
| 0x27, 0x13, 0x01, 0x00, 0x00, 0xee, 0xee, 0x30, 0xb4, 0x18, 0x18, 0x26, 0x04, 0x95, 0x23, 0xa9, |
| 0x19, 0x26, 0x05, 0x15, 0xc1, 0xd2, 0x2c, 0x57, 0x06, 0x00, 0x27, 0x13, 0x01, 0x00, 0x00, 0xee, |
| 0xee, 0x30, 0xb4, 0x18, 0x18, 0x24, 0x07, 0x02, 0x24, 0x08, 0x15, 0x30, 0x0a, 0x31, 0x04, 0x78, |
| 0x52, 0xe2, 0x9c, 0x92, 0xba, 0x70, 0x19, 0x58, 0x46, 0x6d, 0xae, 0x18, 0x72, 0x4a, 0xfb, 0x43, |
| 0x0d, 0xf6, 0x07, 0x29, 0x33, 0x0d, 0x61, 0x55, 0xe5, 0x65, 0x46, 0x8e, 0xba, 0x0d, 0xa5, 0x3f, |
| 0xb5, 0x17, 0xc0, 0x47, 0x64, 0x44, 0x02, 0x18, 0x4f, 0xa8, 0x11, 0x24, 0x50, 0xd4, 0x7b, 0x35, |
| 0x83, 0x29, 0x01, 0x29, 0x02, 0x18, 0x35, 0x82, 0x29, 0x01, 0x24, 0x02, 0x60, 0x18, 0x35, 0x81, |
| 0x30, 0x02, 0x08, 0x42, 0x0c, 0xac, 0xf6, 0xb4, 0x64, 0x71, 0xe6, 0x18, 0x35, 0x80, 0x30, 0x02, |
| 0x08, 0x42, 0x0c, 0xac, 0xf6, 0xb4, 0x64, 0x71, 0xe6, 0x18, 0x35, 0x0c, 0x30, 0x01, 0x19, 0x00, |
| 0xbe, 0x0e, 0xda, 0xa1, 0x63, 0x5a, 0x8e, 0xf1, 0x52, 0x17, 0x45, 0x80, 0xbd, 0xdc, 0x94, 0x12, |
| 0xd4, 0xcc, 0x1c, 0x2c, 0x33, 0x4e, 0x29, 0xdc, 0x30, 0x02, 0x19, 0x00, 0x8b, 0xe7, 0xee, 0x2e, |
| 0x11, 0x17, 0x14, 0xae, 0x92, 0xda, 0x2b, 0x3b, 0x6d, 0x2f, 0xd7, 0x5d, 0x9e, 0x5f, 0xcd, 0xb8, |
| 0xba, 0x2f, 0x65, 0x76, 0x18, 0x18, 0x18, 0x35, 0x02, 0x27, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, |
| 0x30, 0xb4, 0x18, 0x36, 0x02, 0x15, 0x2c, 0x01, 0x22, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x64, 0x6f, |
| 0x6f, 0x72, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6e, |
| 0x65, 0x73, 0x74, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x18, 0x18, 0x18 |
| }; |
| |
| ClearPersistedService(); |
| PersistNewService(0x18B4300100000001ULL, dummyAccountId, strlen(dummyAccountId), dummyServiceConfig, sizeof(dummyServiceConfig)); |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::HandleRegisterServicePairAccount(RegisterServicePairAccountMessage& msg) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| char ipAddrStr[64]; |
| mCurClientOp->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| |
| // NOTE: The arguments to HandleRegisterServicePairAccount() are temporary copies which |
| // must be copied or discarded by the time the function returns. |
| |
| printf("RegisterServicePairAccount request received from node %" PRIX64 " (%s)\n", mCurClientOp->PeerNodeId, ipAddrStr); |
| printf(" Service Id: %016" PRIX64 "\n", msg.ServiceId); |
| printf(" Account Id: "); fwrite(msg.AccountId, 1, msg.AccountIdLen, stdout); printf("\n"); |
| printf(" Service Config (%d bytes): \n", (int)msg.ServiceConfigLen); |
| DumpMemory(msg.ServiceConfig, msg.ServiceConfigLen, " ", 16); |
| printf(" Pairing Token (%d bytes): \n", (int)msg.PairingTokenLen); |
| DumpMemory(msg.PairingToken, msg.PairingTokenLen, " ", 16); |
| printf(" Pairing Init Data (%d bytes): \n", (int)msg.PairingInitDataLen); |
| DumpMemory(msg.PairingInitData, msg.PairingInitDataLen, " ", 16); |
| |
| // Verify that the new service id does not match an existing service. |
| // |
| // Services cannot be re-registered; they must be updated or unregistered. |
| if (mPersistedServiceId == msg.ServiceId) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_ServiceAlreadyRegistered); |
| ExitNow(); |
| } |
| |
| // If we've reached the maximum number of provisioned services return a TooManyServices error. |
| // |
| // The Mock device only supports a single provisioned service. This will be true for Topaz 1.0 as well. However other |
| // types of devices may support multiple provisioned services up to some limit. |
| if (mPersistedServiceConfig != NULL) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_TooManyServices); |
| ExitNow(); |
| } |
| |
| // Validate the service config. We don't want to get any further along before making sure the data is good. |
| if (!ServiceProvisioningServer::IsValidServiceConfig(msg.ServiceConfig, msg.ServiceConfigLen)) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_InvalidServiceConfig); |
| ExitNow(); |
| } |
| |
| if (kPairingTransport_TCP == PairingTransport) |
| { |
| // At this point, the device must send a PairDeviceToAccount request to the service endpoint that handles |
| // device pairing. The process for doing this is roughly as follows... |
| // |
| // 1 - Use the directory endpoint address in the service config to connect and authenticate to the service's |
| // directory server. Once connected, request the pairing service endpoint using the Directory Protocol. |
| // |
| // 2 - Connect and authenticate to the pairing server and issue a PairDeviceToAccount request containing: |
| // -- Account Id |
| // -- Device's Fabric Id |
| // -- Service Pairing Token |
| // -- Pairing Initialization Data |
| // |
| // 3 - Pairing service will respond with a StatusReport message indicating success or error. If an error is |
| // returned, the StatusReport is returned to the application that made the RegisterServicePairAccount |
| // request. |
| // |
| // NOTE that the steps above that require authentication will require the device to extract and use the service |
| // CA certificates contained in the supplied service configuration data. |
| |
| // Initiate a connection to the configured pairing server. |
| err = StartConnectToPairingServer(); |
| SuccessOrExit(err); |
| } |
| else if (kPairingTransport_WRM == PairingTransport) |
| { |
| err = PrepareBindingForPairingServer(); |
| SuccessOrExit(err); |
| } |
| else |
| { |
| err = WEAVE_ERROR_INCORRECT_STATE; |
| } |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::PrepareBindingForPairingServer() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| IPAddress endPointAddr; |
| |
| VerifyOrExit(IPAddress::FromString(PairingServerAddr, endPointAddr), err = WEAVE_ERROR_INVALID_ADDRESS); |
| |
| mPairingServerBinding = ExchangeMgr->NewBinding(HandlePairingServerBindingEvent, this); |
| VerifyOrExit(mPairingServerBinding != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| |
| // Prepare the binding. Will finish asynchronously. |
| // TODO: [TT] PairingEndPointId appears to default to the local node id. |
| // Shouldn't it default to kServiceEndpoint_ServiceProvisioning instead, |
| // if this is how it's used? |
| err = mPairingServerBinding->BeginConfiguration() |
| .Target_NodeId(PairingEndPointId) |
| .TargetAddress_IP(endPointAddr) |
| .Transport_UDP_WRM() |
| .Security_None() |
| .PrepareBinding(); |
| SuccessOrExit(err); |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| if (mPairingServerBinding != NULL) |
| { |
| mPairingServerBinding->Release(); |
| mPairingServerBinding = NULL; |
| } |
| } |
| return err; |
| } |
| |
| void MockServiceProvisioningServer::HandlePairingServerBindingEvent(void *const appState, |
| const nl::Weave::Binding::EventType event, |
| const nl::Weave::Binding::InEventParam &inParam, |
| nl::Weave::Binding::OutEventParam &outParam) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WeaveDeviceDescriptor deviceDesc; |
| uint8_t deviceInitData[256]; |
| uint32_t deviceInitDataLen; |
| MockServiceProvisioningServer *server = (MockServiceProvisioningServer *) appState; |
| |
| // Retrieve the original RegisterServicePairAccount message from the client. |
| RegisterServicePairAccountMessage &msg = server->mCurClientOpMsg.RegisterServicePairAccount; |
| |
| switch (event) |
| { |
| case nl::Weave::Binding::kEvent_BindingReady: |
| printf("Pairing server binding ready\n"); |
| // Continues below. |
| break; |
| case nl::Weave::Binding::kEvent_PrepareFailed: |
| printf("Pairing server binding prepare failed: %s\n", nl::ErrorStr(inParam.PrepareFailed.Reason)); |
| ExitNow(err = inParam.PrepareFailed.Reason); |
| break; |
| case nl::Weave::Binding::kEvent_BindingFailed: |
| printf("Pairing server binding failed: %s\n", nl::ErrorStr(inParam.BindingFailed.Reason)); |
| ExitNow(err = inParam.BindingFailed.Reason); |
| break; |
| default: |
| nl::Weave::Binding::DefaultEventHandler(appState, event, inParam, outParam); |
| ExitNow(err = WEAVE_NO_ERROR); |
| break; |
| } |
| |
| printf("Sending WRM PairDeviceToAccount request to pairing server\n"); |
| |
| // Encode device descriptor and send as device init data. |
| gDeviceDescOptions.GetDeviceDesc(deviceDesc); |
| WeaveDeviceDescriptor::EncodeTLV(deviceDesc, deviceInitData, sizeof(deviceInitData), deviceInitDataLen); |
| |
| // Send a PairDeviceToAccount request to the pairing server via WRM. |
| err = server->SendPairDeviceToAccountRequest(server->mPairingServerBinding, |
| msg.ServiceId, server->FabricState->FabricId, |
| msg.AccountId, msg.AccountIdLen, |
| msg.PairingToken, msg.PairingTokenLen, |
| msg.PairingInitData, msg.PairingInitDataLen, |
| deviceInitData, deviceInitDataLen); |
| SuccessOrExit(err); |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| server->SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_PairingServerError, err); |
| if (server->mPairingServerBinding != NULL) |
| { |
| server->mPairingServerBinding->Release(); |
| server->mPairingServerBinding = NULL; |
| } |
| } |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::StartConnectToPairingServer() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WeaveConnection *con = NULL; |
| IPAddress endPointAddr; |
| |
| printf("Initiating connection to pairing server at %s\n", PairingServerAddr); |
| |
| if (!IPAddress::FromString(PairingServerAddr, endPointAddr)) |
| ExitNow(err = WEAVE_ERROR_INVALID_ADDRESS); |
| |
| con = ExchangeMgr->MessageLayer->NewConnection(); |
| VerifyOrExit(con != NULL, err = WEAVE_ERROR_TOO_MANY_CONNECTIONS); |
| |
| con->AppState = this; |
| con->OnConnectionComplete = HandlePairingServerConnectionComplete; |
| con->OnConnectionClosed = HandlePairingServerConnectionClosed; |
| |
| // TODO: [TT] PairingEndPointId appears to default to the local node id. |
| // Shouldn't it default to kServiceEndpoint_ServiceProvisioning instead, |
| // if this is how it's used? |
| err = con->Connect(PairingEndPointId, endPointAddr); |
| SuccessOrExit(err); |
| |
| mPairingServerCon = con; |
| con = NULL; |
| |
| exit: |
| if (con != NULL) |
| con->Close(); |
| return err; |
| } |
| |
| void MockServiceProvisioningServer::HandlePairingServerConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr) |
| { |
| WEAVE_ERROR err; |
| MockServiceProvisioningServer *server = (MockServiceProvisioningServer *) con->AppState; |
| |
| // If the connection failed, clean-up and deliver a failure back to the client. |
| if (conErr != WEAVE_NO_ERROR) |
| { |
| printf("Connection to pairing server failed: %s\n", nl::ErrorStr(conErr)); |
| |
| server->mPairingServerCon->Close(); |
| server->mPairingServerCon = NULL; |
| server->SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_PairingServerError, conErr); |
| return; |
| } |
| |
| printf("Connection to pairing server established\n"); |
| |
| // Retrieve the original RegisterServicePairAccount message from the client. |
| RegisterServicePairAccountMessage &clientMsg = server->mCurClientOpMsg.RegisterServicePairAccount; |
| |
| printf("Sending TCP PairDeviceToAccount request to pairing server\n"); |
| |
| // Encode device descriptor and send as device init data. |
| WeaveDeviceDescriptor deviceDesc; |
| gDeviceDescOptions.GetDeviceDesc(deviceDesc); |
| uint8_t deviceInitData[256]; |
| uint32_t deviceInitDataLen; |
| WeaveDeviceDescriptor::EncodeTLV(deviceDesc, deviceInitData, sizeof(deviceInitData), deviceInitDataLen); |
| |
| // Send a PairDeviceToAccount request to the pairing server. |
| err = server->SendPairDeviceToAccountRequest(server->mPairingServerCon, clientMsg.ServiceId, server->FabricState->FabricId, |
| clientMsg.AccountId, clientMsg.AccountIdLen, |
| clientMsg.PairingToken, clientMsg.PairingTokenLen, |
| clientMsg.PairingInitData, clientMsg.PairingInitDataLen, |
| deviceInitData, deviceInitDataLen |
| ); |
| |
| if (err != WEAVE_NO_ERROR) |
| { |
| server->mPairingServerCon->Close(); |
| server->mPairingServerCon = NULL; |
| server->SendStatusReport(kWeaveProfile_Common, Common::kStatus_InternalError, err); |
| return; |
| } |
| } |
| |
| void MockServiceProvisioningServer::HandlePairDeviceToAccountResult(WEAVE_ERROR err, uint32_t serverStatusProfileId, uint16_t serverStatusCode) |
| { |
| if (mPairingServerCon) |
| { |
| // The server operation is now complete so close the connection. |
| mPairingServerCon->Close(); |
| mPairingServerCon = NULL; |
| } |
| else if (mPairingServerBinding) |
| { |
| // The server operation is now complete, so release the binding. |
| mPairingServerBinding->Release(); |
| mPairingServerBinding = NULL; |
| } |
| |
| // If the PairDeviceToAccount request was successful... |
| if (err == WEAVE_NO_ERROR) |
| { |
| printf("Received success response from pairing server\n"); |
| |
| // Retrieve the original RegisterServicePairAccount message from the client. |
| RegisterServicePairAccountMessage &clientMsg = mCurClientOpMsg.RegisterServicePairAccount; |
| |
| // Save the service information in device persistent storage. |
| // (On the mock device we merely store it in memory). |
| // |
| err = PersistNewService(clientMsg.ServiceId, clientMsg.AccountId, clientMsg.AccountIdLen, clientMsg.ServiceConfig, clientMsg.ServiceConfigLen); |
| if (err != WEAVE_NO_ERROR) |
| { |
| SendStatusReport(kWeaveProfile_Common, Common::kStatus_InternalError, err); |
| return; |
| } |
| |
| SendSuccessResponse(); |
| } |
| |
| // Otherwwise, relay the result from the pairing server back to the client. |
| else if (err == WEAVE_ERROR_STATUS_REPORT_RECEIVED) |
| { |
| printf("Received StatusReport from pairing server: %s\n", nl::StatusReportStr(serverStatusProfileId, serverStatusCode)); |
| SendStatusReport(serverStatusProfileId, serverStatusCode, WEAVE_NO_ERROR); |
| } |
| else |
| { |
| printf("Error talking to pairing server: %s\n", nl::ErrorStr(err)); |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_PairingServerError, err); |
| } |
| } |
| |
| #if WEAVE_CONFIG_ENABLE_IFJ_SERVICE_FABRIC_JOIN |
| void MockServiceProvisioningServer::HandleIFJServiceFabricJoinResult(WEAVE_ERROR err, uint32_t serverStatusProfileId, uint16_t serverStatusCode) |
| { |
| if (mPairingServerBinding) |
| { |
| // The server operation is now complete, so release the binding. |
| mPairingServerBinding->Release(); |
| mPairingServerBinding = NULL; |
| } |
| |
| // If the IFJServiceFabricJoin request was successful... |
| if (err == WEAVE_NO_ERROR) |
| { |
| printf("Received success response from server\n"); |
| |
| } |
| |
| // Otherwwise, relay the result from the pairing server back to the client. |
| else if (err == WEAVE_ERROR_STATUS_REPORT_RECEIVED) |
| { |
| printf("Received StatusReport from server: %s\n", nl::StatusReportStr(serverStatusProfileId, serverStatusCode)); |
| } |
| else |
| { |
| printf("Error talking to server: %s\n", nl::ErrorStr(err)); |
| } |
| } |
| #endif // WEAVE_CONFIG_ENABLE_IFJ_SERVICE_FABRIC_JOIN |
| |
| void MockServiceProvisioningServer::EnforceAccessControl(nl::Weave::ExchangeContext *ec, uint32_t msgProfileId, uint8_t msgType, |
| const nl::Weave::WeaveMessageInfo *msgInfo, AccessControlResult& result) |
| { |
| if (sSuppressAccessControls) |
| { |
| result = kAccessControlResult_Accepted; |
| } |
| |
| ServiceProvisioningDelegate::EnforceAccessControl(ec, msgProfileId, msgType, msgInfo, result); |
| } |
| |
| bool MockServiceProvisioningServer::IsPairedToAccount() const |
| { |
| return (gCASEOptions.ServiceConfig != NULL); |
| } |
| |
| void MockServiceProvisioningServer::HandlePairingServerConnectionClosed(WeaveConnection *con, WEAVE_ERROR conErr) |
| { |
| MockServiceProvisioningServer *server = (MockServiceProvisioningServer *) con->AppState; |
| if (server->mPairingServerCon != NULL) |
| { |
| server->mPairingServerCon->Close(); |
| server->mPairingServerCon = NULL; |
| } |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::HandleUpdateService(UpdateServiceMessage& msg) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| char ipAddrStr[64]; |
| mCurClientOp->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| |
| // NOTE: The arguments to HandleUpdateService() are temporary copies which |
| // must be copied or discarded by the time the function returns. |
| |
| printf("UpdateService request received from node %" PRIX64 " (%s)\n", mCurClientOp->PeerNodeId, ipAddrStr); |
| printf(" Service Id: %016" PRIX64 "\n", msg.ServiceId); |
| printf(" Service Config (%d bytes): \n", (int)msg.ServiceConfigLen); |
| DumpMemory(msg.ServiceConfig, msg.ServiceConfigLen, " ", 16); |
| |
| // Verify that the service id matches an existing service. |
| // |
| if (mPersistedServiceId != msg.ServiceId) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_NoSuchService); |
| ExitNow(); |
| } |
| |
| // Validate the service config. We don't want to get any further along before making sure the data is good. |
| if (!ServiceProvisioningServer::IsValidServiceConfig(msg.ServiceConfig, msg.ServiceConfigLen)) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_InvalidServiceConfig); |
| ExitNow(); |
| } |
| |
| // Save the new service configuration in device persistent storage, replacing the existing value. |
| // (On the mock device we merely store it in memory). |
| err = UpdatedPersistedService(msg.ServiceConfig, msg.ServiceConfigLen); |
| SuccessOrExit(err); |
| |
| // Send a success StatusReport back to the requestor. |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::HandleUnregisterService(uint64_t serviceId) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| char ipAddrStr[64]; |
| mCurClientOp->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| |
| printf("UnregisterService request received from node %" PRIX64 " (%s)\n", mCurClientOp->PeerNodeId, ipAddrStr); |
| printf(" Service Id: %016" PRIX64 "\n", serviceId); |
| |
| // Verify that the service id matches an existing service. |
| // |
| if (mPersistedServiceId != serviceId) |
| { |
| SendStatusReport(kWeaveProfile_ServiceProvisioning, kStatusCode_NoSuchService); |
| ExitNow(); |
| } |
| |
| // Clear the persisted service. |
| ClearPersistedService(); |
| |
| // Send a success StatusReport back to the requestor. |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::PersistNewService(uint64_t serviceId, |
| const char *accountId, uint16_t accountIdLen, |
| const uint8_t *serviceConfig, uint16_t serviceConfigLen) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| char *accountIdCopy = NULL; |
| uint8_t *serviceConfigCopy = NULL; |
| |
| accountIdCopy = (char *)malloc(accountIdLen + 1); |
| VerifyOrExit(accountIdCopy != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| memcpy(accountIdCopy, accountId, accountIdLen); |
| accountIdCopy[accountIdLen] = 0; |
| |
| serviceConfigCopy = (uint8_t *)malloc(serviceConfigLen); |
| VerifyOrExit(serviceConfigCopy != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| memcpy(serviceConfigCopy, serviceConfig, serviceConfigLen); |
| |
| mPersistedServiceId = serviceId; |
| mPersistedAccountId = accountIdCopy; |
| mPersistedServiceConfig = serviceConfigCopy; |
| mPersistedServiceConfigLen = serviceConfigLen; |
| |
| // Setup to use service config in subsequence CASE sessions. |
| gCASEOptions.ServiceConfig = mPersistedServiceConfig; |
| gCASEOptions.ServiceConfigLength = mPersistedServiceConfigLen; |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| if (accountIdCopy != NULL) |
| free(accountIdCopy); |
| if (serviceConfigCopy != NULL) |
| free(serviceConfigCopy); |
| } |
| return err; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::UpdatedPersistedService(const uint8_t *serviceConfig, uint16_t serviceConfigLen) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| uint8_t *serviceConfigCopy = NULL; |
| |
| serviceConfigCopy = (uint8_t *)malloc(serviceConfigLen); |
| VerifyOrExit(serviceConfigCopy != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| memcpy(serviceConfigCopy, serviceConfig, serviceConfigLen); |
| |
| free(mPersistedServiceConfig); |
| mPersistedServiceConfig = serviceConfigCopy; |
| mPersistedServiceConfigLen = serviceConfigLen; |
| |
| // Setup to use service config in subsequence CASE sessions. |
| gCASEOptions.ServiceConfig = mPersistedServiceConfig; |
| gCASEOptions.ServiceConfigLength = mPersistedServiceConfigLen; |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && serviceConfigCopy != NULL) |
| free(serviceConfigCopy); |
| return err; |
| } |
| |
| void MockServiceProvisioningServer::ClearPersistedService() |
| { |
| mPersistedServiceId = 0; |
| if (mPersistedAccountId != NULL) |
| { |
| free(mPersistedAccountId); |
| mPersistedAccountId = NULL; |
| } |
| if (mPersistedServiceConfig != NULL) |
| { |
| free(mPersistedServiceConfig); |
| mPersistedServiceConfig = NULL; |
| } |
| mPersistedServiceConfigLen = 0; |
| |
| gCASEOptions.ServiceConfig = NULL; |
| gCASEOptions.ServiceConfigLength = 0; |
| } |
| |
| WEAVE_ERROR MockServiceProvisioningServer::SendStatusReport(uint32_t statusProfileId, uint16_t statusCode, WEAVE_ERROR sysError) |
| { |
| if (statusProfileId == kWeaveProfile_Common && statusCode == Common::kStatus_Success) |
| printf("Sending StatusReport: Success\n"); |
| else |
| { |
| printf("Sending StatusReport: %s\n", nl::StatusReportStr(statusProfileId, statusCode)); |
| if (sysError != WEAVE_NO_ERROR) |
| printf(" System error: %s\n", nl::ErrorStr(sysError)); |
| } |
| return this->ServiceProvisioningServer::SendStatusReport(statusProfileId, statusCode, sysError); |
| } |