1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
26 #include "ocpayload.h"
27 #include "provisioninghandler.h"
32 #include "cathreadpool.h"
34 #include "oic_malloc.h"
37 * @var g_provisioningMutex
38 * @brief Mutex to synchronize access to g_caDtlsContext.
40 static ca_mutex g_provisioningMutex = NULL;
41 static ca_cond g_provisioningCond = NULL;
42 bool g_provisioningCondFlag = false;
44 static EnrolleeNWProvInfo_t* netProvInfo;
48 * @brief Callback for providing provisioning status callback to application
50 static OCProvisioningStatusCB cbData = NULL;
51 static ca_thread_pool_t g_threadPoolHandle = NULL;
53 void ErrorCallback(ProvStatus status)
55 ProvisioningInfo *provInfo = GetCallbackObjectOnError(status);
60 OCStackResult InitProvisioningHandler()
62 OCStackResult ret = OC_STACK_ERROR;
63 /* Initialize OCStack*/
64 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
66 OIC_LOG(ERROR, TAG, "OCStack init error");
70 g_provisioningMutex = ca_mutex_new();
72 OIC_LOG(DEBUG, TAG, "ca_thread_pool_init initializing");
74 if (CA_STATUS_OK != ca_thread_pool_init(2, &g_threadPoolHandle))
76 OIC_LOG(DEBUG, TAG, "thread_pool_init failed");
77 return OC_STACK_ERROR;
80 g_provisioningCond = ca_cond_new();
81 if (NULL == g_provisioningCond)
83 OIC_LOG(DEBUG, TAG, "Failed to create condition");
84 ca_mutex_free(g_provisioningMutex);
85 ca_thread_pool_free(g_threadPoolHandle);
86 return OC_STACK_ERROR;
89 char *string = "listeningFunc invoked in a thread";
90 if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, listeningFunc, (void *) string))
92 OIC_LOG(DEBUG, TAG, "thread_pool_add_task failed");
93 ca_thread_pool_free(g_threadPoolHandle);
94 ca_mutex_unlock(g_provisioningMutex);
95 ca_mutex_free(g_provisioningMutex);
96 ca_cond_free(g_provisioningCond);
97 return OC_STACK_ERROR;
105 OCStackResult TerminateProvisioningHandler()
107 OCStackResult ret = OC_STACK_ERROR;
108 if (OCStop() != OC_STACK_OK)
110 OIC_LOG(ERROR, TAG, "OCStack stop error");
113 ca_mutex_lock(g_provisioningMutex);
114 g_provisioningCondFlag = true;
115 //ca_cond_signal(g_provisioningCond);
116 ca_mutex_unlock(g_provisioningMutex);
118 ca_mutex_free(g_provisioningMutex);
119 g_provisioningMutex = NULL;
121 ca_thread_pool_free(g_threadPoolHandle);
122 g_threadPoolHandle = NULL;
128 void listeningFunc(void *data)
130 while (!g_provisioningCondFlag)
132 OCStackResult result;
134 ca_mutex_lock(g_provisioningMutex);
135 result = OCProcess();
136 ca_mutex_unlock(g_provisioningMutex);
138 if (result != OC_STACK_OK)
140 OIC_LOG(ERROR, TAG, "OCStack stop error");
143 // To minimize CPU utilization we may wish to do this with sleep
148 OCStackApplicationResult ProvisionEnrolleeResponse(void* ctx, OCDoHandle handle,
149 OCClientResponse * clientResponse)
152 ProvisioningInfo *provInfo;
154 if (!ValidateEnrolleResponse(clientResponse))
156 ErrorCallback( DEVICE_NOT_PROVISIONED);
157 return OC_STACK_DELETE_TRANSACTION;
163 OCRepPayload* input = (OCRepPayload*) (clientResponse->payload);
169 if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_PS, &ps))
174 OIC_LOG_V(DEBUG, TAG, "PS is proper");
180 OIC_LOG_V(DEBUG, TAG, "PS is NOT proper");
186 if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_TNN, &tnn))
188 if (!strcmp(tnn, netProvInfo->netAddressInfo.WIFI.ssid))
190 OIC_LOG_V(DEBUG, TAG, "SSID is proper");
196 OIC_LOG_V(DEBUG, TAG, "SSID is NOT proper");
201 if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CD, &cd))
203 if (!strcmp(cd, netProvInfo->netAddressInfo.WIFI.pwd))
205 OIC_LOG_V(DEBUG, TAG, "Password is proper");
211 OIC_LOG_V(DEBUG, TAG, "Password is NOT proper");
216 LogProvisioningResponse(input->values);
222 SuccessCallback(clientResponse);
224 return OC_STACK_KEEP_TRANSACTION;
229 ErrorCallback( DEVICE_NOT_PROVISIONED);
231 return OC_STACK_DELETE_TRANSACTION;
236 OCStackResult ProvisionEnrollee(OCQualityOfService qos, const char* query, const char* resUri,
237 OCDevAddr *destination)
239 OIC_LOG_V(INFO, TAG, "\n\nExecuting ProvisionEnrollee%s", __func__);
241 OCRepPayload* payload = OCRepPayloadCreate();
243 OCRepPayloadSetUri(payload, resUri);
244 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_TNN, netProvInfo->netAddressInfo.WIFI.ssid);
245 OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CD, netProvInfo->netAddressInfo.WIFI.pwd);
247 OIC_LOG_V(DEBUG, TAG, "OCPayload ready for ProvisionEnrollee");
249 OCStackResult ret = InvokeOCDoResource(query, OC_REST_PUT, destination, OC_HIGH_QOS,
250 ProvisionEnrolleeResponse, payload, NULL, 0);
255 OCStackApplicationResult GetProvisioningStatusResponse(void* ctx, OCDoHandle handle,
256 OCClientResponse * clientResponse)
259 ProvisioningInfo *provInfo;
261 if (!ValidateEnrolleResponse(clientResponse))
263 ErrorCallback( DEVICE_NOT_PROVISIONED);
265 return OC_STACK_DELETE_TRANSACTION;
268 OCRepPayload* input = (OCRepPayload*) (clientResponse->payload);
270 char query[OIC_STRING_MAX_VALUE] =
272 char resURI[MAX_URI_LENGTH] =
275 OIC_LOG_V(DEBUG, TAG, "resUri = %s", input->uri);
277 strncpy(resURI, input->uri, sizeof(resURI));
279 snprintf(query, sizeof(query), UNICAST_PROV_STATUS_QUERY, clientResponse->addr->addr, IP_PORT,
282 //OCPayloadLogRep(DEBUG,TAG,input);
284 if (ProvisionEnrollee(OC_HIGH_QOS, query, OC_RSRVD_ES_URI_PROV, clientResponse->addr)
288 "GetProvisioningStatusResponse received NULL clientResponse.Invoking Provisioing Status Callback");
290 ErrorCallback( DEVICE_NOT_PROVISIONED);
292 return OC_STACK_DELETE_TRANSACTION;
295 return OC_STACK_KEEP_TRANSACTION;
299 OCStackResult InvokeOCDoResource(const char* query, OCMethod method, const OCDevAddr *dest,
300 OCQualityOfService qos, OCClientResponseHandler cb, OCRepPayload* payload,
301 OCHeaderOption * options, uint8_t numOptions)
304 OCCallbackData cbData;
307 cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
310 ret = OCDoResource(NULL, method, query, dest, (OCPayload*) payload, OC_CONNTYPE, qos, &cbData,
311 options, numOptions);
313 if (ret != OC_STACK_OK)
315 OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
321 OCStackResult GetProvisioningStatus(OCQualityOfService qos, const char* query,
322 const OCDevAddr *destination)
324 OCStackResult ret = OC_STACK_ERROR;
325 OCHeaderOption options[MAX_HEADER_OPTIONS];
327 OIC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
330 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
332 { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
333 memset(options, 0, sizeof(OCHeaderOption) * MAX_HEADER_OPTIONS);
334 options[0].protocolID = OC_COAP_ID;
335 options[0].optionID = 2048;
336 memcpy(options[0].optionData, option0, sizeof(option0));
337 options[0].optionLength = 10;
338 options[1].protocolID = OC_COAP_ID;
339 options[1].optionID = 3000;
340 memcpy(options[1].optionData, option1, sizeof(option1));
341 options[1].optionLength = 10;
343 ret = InvokeOCDoResource(query, OC_REST_GET, destination, OC_HIGH_QOS,
344 GetProvisioningStatusResponse, NULL, options, 2);
348 OCStackResult StartProvisioningProcess(const EnrolleeNWProvInfo_t *netInfo,
349 OCProvisioningStatusCB provisioningStatusCallback)
352 OCStackResult result = OC_STACK_ERROR;
354 if (!ValidateEasySetupParams(netInfo, provisioningStatusCallback))
359 //Only basis test is done for below API
360 if (!SetProgress(provisioningStatusCallback))
362 // Device provisioning session is running already.
363 OIC_LOG(INFO, TAG, PCF("Device provisioning session is running already"));
367 if (!ConfigEnrolleeObject(netInfo))
372 if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, FindProvisioningResource,
382 ErrorCallback( DEVICE_NOT_PROVISIONED);
384 return OC_STACK_ERROR;
389 void StopProvisioningProcess()
391 //Only basis test is done for below API
395 // This is a function called back when a device is discovered
396 OCStackApplicationResult FindProvisioningResourceResponse(void* ctx, OCDoHandle handle,
397 OCClientResponse * clientResponse)
400 OIC_LOG(INFO, TAG, PCF("Entering FindProvisioningResourceResponse"));
402 if (!ValidateFinddResourceResponse(clientResponse))
404 ErrorCallback( DEVICE_NOT_PROVISIONED);
405 return OC_STACK_DELETE_TRANSACTION;
408 OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
410 ProvisioningInfo *provInfo;
411 char szQueryUri[64] =
414 OCDiscoveryPayload* discoveryPayload = (OCDiscoveryPayload*) (clientResponse->payload);
416 // Need to conform if below check is required or not. As Null check of clientResponse->payload is already performed above
417 if (!discoveryPayload)
419 OIC_LOG_V(DEBUG, TAG, "Failed To parse");
420 ErrorCallback( DEVICE_NOT_PROVISIONED);
421 return OC_STACK_DELETE_TRANSACTION;
424 OIC_LOG_V(DEBUG, TAG, "resUri = %s", discoveryPayload->resources->uri);
426 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROV_STATUS_QUERY,
427 clientResponse->devAddr.addr, IP_PORT, discoveryPayload->resources->uri);
429 OIC_LOG_V(DEBUG, TAG, "query before GetProvisioningStatus call = %s", szQueryUri);
431 if (GetProvisioningStatus(OC_HIGH_QOS, szQueryUri, &clientResponse->devAddr) != OC_STACK_OK)
433 ErrorCallback( DEVICE_NOT_PROVISIONED);
434 return OC_STACK_DELETE_TRANSACTION;
437 return OC_STACK_KEEP_TRANSACTION;
441 void FindProvisioningResource(void *data)
443 OCStackResult ret = OC_STACK_ERROR;
445 /* Start a discovery query*/
446 char szQueryUri[64] =
449 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY,
450 netProvInfo->netAddressInfo.WIFI.ipAddress, IP_PORT);
452 OIC_LOG_V(DEBUG, TAG, "szQueryUri = %s", szQueryUri);
454 OCCallbackData ocCBData;
456 ocCBData.cb = FindProvisioningResourceResponse;
457 ocCBData.context = (void*) DEFAULT_CONTEXT_VALUE;
460 ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, NULL, OC_CONNTYPE, OC_LOW_QOS,
463 if (ret != OC_STACK_OK)
465 ErrorCallback( DEVICE_NOT_PROVISIONED);
470 OCStackApplicationResult SubscribeProvPresenceCallback(void* ctx, OCDoHandle handle,
471 OCClientResponse* clientResponse)
473 OIC_LOG(INFO, TAG, PCF("Entering SubscribeProvPresenceCallback"));
475 OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
477 if (clientResponse->result != OC_STACK_OK)
479 OIC_LOG(ERROR, TAG, "OCStack stop error");
485 OIC_LOG(INFO, TAG, PCF("Client Response exists"));
487 if (clientResponse->payload && clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
489 OIC_LOG_V(DEBUG, TAG, "Incoming payload not a representation");
493 OCRepPayload* discoveryPayload = (OCRepPayload*) (clientResponse->payload);
494 if (!discoveryPayload)
496 OIC_LOG_V(DEBUG, TAG, "invalid payload");
500 char sourceIPAddr[OIC_STRING_MAX_VALUE] =
502 snprintf(sourceIPAddr, sizeof(sourceIPAddr), "%s", clientResponse->addr->addr);
504 OIC_LOG_V(DEBUG, TAG, "Discovered %s @ %s", discoveryPayload->uri, sourceIPAddr);
506 /* Start a discovery query*/
507 char szQueryUri[64] =
510 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY, sourceIPAddr, IP_PORT);
512 /*if (FindProvisioningResource(qos, szQueryUri) != OC_STACK_OK) {
513 OIC_LOG(ERROR, TAG, "FindProvisioningResource failed");
514 return OC_STACK_KEEP_TRANSACTION;
519 // clientResponse is invalid
520 OIC_LOG(ERROR, TAG, PCF("Client Response is NULL!"));
522 return OC_STACK_KEEP_TRANSACTION;
525 OCStackResult SubscribeProvPresence(OCQualityOfService qos, const char* requestURI)
527 OCStackResult ret = OC_STACK_ERROR;
529 OCCallbackData cbData;
531 cbData.cb = &SubscribeProvPresenceCallback;
532 cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
535 ret = OCDoResource(NULL, OC_REST_PRESENCE, requestURI, 0, 0, OC_CONNTYPE, OC_LOW_QOS, &cbData,
538 if (ret != OC_STACK_OK)
540 OIC_LOG(ERROR, TAG, "OCStack resource error");
546 OCStackResult FindNetworkResource()
548 OCStackResult ret = OC_STACK_ERROR;
549 if (OCStop() != OC_STACK_OK)
551 OIC_LOG(ERROR, TAG, "OCStack stop error");
557 ProvisioningInfo* PrepareProvisioingStatusCB(OCClientResponse * clientResponse,
558 ProvStatus provStatus)
561 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
563 if (provInfo == NULL)
565 OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
569 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
573 OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
577 strncpy(devAddr->addr, clientResponse->addr->addr, sizeof(devAddr->addr));
578 devAddr->port = clientResponse->addr->port;
580 provInfo->provDeviceInfo.addr = devAddr;
582 provInfo->provStatus = provStatus;
587 bool ValidateEasySetupParams(const EnrolleeNWProvInfo_t *netInfo,
588 OCProvisioningStatusCB provisioningStatusCallback)
591 if (netInfo == NULL || netInfo->netAddressInfo.WIFI.ipAddress == NULL)
593 OIC_LOG(ERROR, TAG, "Request URI is NULL");
597 if (provisioningStatusCallback == NULL)
599 OIC_LOG(ERROR, TAG, "ProvisioningStatusCallback is NULL");
610 // It means already Easy Setup provisioning session is going on.
613 OIC_LOG(ERROR, TAG, "Easy setup session is already in progress");
620 bool SetProgress(OCProvisioningStatusCB provisioningStatusCallback)
622 ca_mutex_lock(g_provisioningMutex);
627 cbData = provisioningStatusCallback;
629 ca_mutex_unlock(g_provisioningMutex);
636 ca_mutex_lock(g_provisioningMutex);
640 ca_mutex_unlock(g_provisioningMutex);
643 ProvisioningInfo* CreateCallBackObject()
646 ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
648 if (provInfo == NULL)
650 OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
654 OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
658 OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
662 provInfo->provDeviceInfo.addr = devAddr;
668 ProvisioningInfo* GetCallbackObjectOnError(ProvStatus status)
671 ProvisioningInfo *provInfo = CreateCallBackObject();
672 strncpy(provInfo->provDeviceInfo.addr->addr, netProvInfo->netAddressInfo.WIFI.ipAddress,
673 sizeof(provInfo->provDeviceInfo.addr->addr));
674 provInfo->provDeviceInfo.addr->port = IP_PORT;
675 provInfo->provStatus = status;
679 ProvisioningInfo* GetCallbackObjectOnSuccess(OCClientResponse * clientResponse,
680 ProvStatus provStatus)
682 ProvisioningInfo *provInfo = CreateCallBackObject();
683 strncpy(provInfo->provDeviceInfo.addr->addr, clientResponse->addr->addr,
684 sizeof(provInfo->provDeviceInfo.addr->addr));
685 provInfo->provDeviceInfo.addr->port = clientResponse->addr->port;
686 provInfo->provStatus = provStatus;
690 bool ValidateFinddResourceResponse(OCClientResponse * clientResponse)
693 if (!(clientResponse) || !(clientResponse->payload))
696 OIC_LOG_V(INFO, TAG, "ProvisionEnrolleeResponse received Null clientResponse");
704 bool ValidateEnrolleResponse(OCClientResponse * clientResponse)
707 if (!(clientResponse) || !(clientResponse->payload))
710 OIC_LOG_V(INFO, TAG, "ProvisionEnrolleeResponse received Null clientResponse");
716 if (clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
719 OIC_LOG_V(DEBUG, TAG, "Incoming payload not a representation");
724 // If flow reachese here means no error condition hit.
730 void SuccessCallback(OCClientResponse * clientResponse)
732 ProvisioningInfo *provInfo = GetCallbackObjectOnSuccess(clientResponse, DEVICE_PROVISIONED);
740 OIC_LOG(DEBUG, TAG, "thread_pool_add_task of FindProvisioningResource failed");
741 ca_thread_pool_free(g_threadPoolHandle);
742 ca_mutex_unlock(g_provisioningMutex);
743 ca_mutex_free(g_provisioningMutex);
744 ca_cond_free(g_provisioningCond);
750 bool ConfigEnrolleeObject(const EnrolleeNWProvInfo_t *netInfo)
753 //Copy Network Provisioning Information
754 netProvInfo = (EnrolleeNWProvInfo_t *) OICCalloc(1, sizeof(EnrolleeNWProvInfo_t));
756 if (netProvInfo == NULL)
758 OIC_LOG(ERROR, TAG, "Invalid input..");
762 memcpy(netProvInfo, netInfo, sizeof(EnrolleeNWProvInfo_t));
764 OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. SSID = %s",
765 netProvInfo->netAddressInfo.WIFI.ssid);
767 OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. PWD = %s",
768 netProvInfo->netAddressInfo.WIFI.pwd);
774 void LogProvisioningResponse(OCRepPayloadValue* val)
779 case OCREP_PROP_NULL:
780 OIC_LOG_V(DEBUG, TAG, "\t\t%s: NULL", val->name);
783 OIC_LOG_V(DEBUG, TAG, "\t\t%s(int):%lld", val->name, val->i);
785 case OCREP_PROP_DOUBLE:
786 OIC_LOG_V(DEBUG, TAG, "\t\t%s(double):%f", val->name, val->d);
788 case OCREP_PROP_BOOL:
789 OIC_LOG_V(DEBUG, TAG, "\t\t%s(bool):%s", val->name, val->b ? "true" : "false");
791 case OCREP_PROP_STRING:
792 OIC_LOG_V(DEBUG, TAG, "\t\t%s(string):%s", val->name, val->str);
794 case OCREP_PROP_OBJECT:
795 // Note: Only prints the URI (if available), to print further, you'll
796 // need to dig into the object better!
797 OIC_LOG_V(DEBUG, TAG, "\t\t%s(OCRep):%s", val->name, val->obj->uri);
799 case OCREP_PROP_ARRAY:
800 switch (val->arr.type)
803 OIC_LOG_V(DEBUG, TAG, "\t\t%s(int array):%lld x %lld x %lld", val->name,
804 val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
806 case OCREP_PROP_DOUBLE:
807 OIC_LOG_V(DEBUG, TAG, "\t\t%s(double array):%lld x %lld x %lld", val->name,
808 val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
810 case OCREP_PROP_BOOL:
811 OIC_LOG_V(DEBUG, TAG, "\t\t%s(bool array):%lld x %lld x %lld", val->name,
812 val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
814 case OCREP_PROP_STRING:
815 OIC_LOG_V(DEBUG, TAG, "\t\t%s(string array):%lld x %lld x %lld", val->name,
816 val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
818 case OCREP_PROP_OBJECT:
819 OIC_LOG_V(DEBUG, TAG, "\t\t%s(OCRep array):%lld x %lld x %lld", val->name,
820 val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
823 //OIC_LOG_V(ERROR, TAG, "\t\t%s <-- Unknown/unsupported array type!",
829 /*OC_LOG_V(ERROR, TAG
830 , "\t\t%s <-- Unknown type!", val->name);*/