blob: f9eb9b6aebc6a099e1998ecca3894f19b6a82b45 [file] [log] [blame]
/*
*
* 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);
}
}
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);
}