Changed the folder structure and changed the shared library to static library
[platform/upstream/iotivity.git] / service / easy-setup / sdk / mediator / src / provisioninghandler.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <unistd.h>
26
27 #include "provisioninghandler.h"
28
29 // External includes
30 #include "cJSON.h"
31 #include "camutex.h"
32 #include "cathreadpool.h"
33 #include "logger.h"
34 #include "oic_malloc.h"
35
36
37 /**
38  * @var g_provisioningMutex
39  * @brief Mutex to synchronize access to g_caDtlsContext.
40  */
41 static ca_mutex g_provisioningMutex = NULL;
42 static ca_cond g_provisioningCond = NULL;
43 bool g_provisioningCondFlag = false;
44
45 static EnrolleeNWProvInfo_t* netProvInfo;
46
47 /**
48  * @var cbData
49  * @brief Callback for providing provisioning status callback to application
50  */
51 static OCProvisioningStatusCB cbData = NULL;
52 static ca_thread_pool_t g_threadPoolHandle = NULL;
53
54 OCStackResult InitProvisioningHandler() {
55     OCStackResult ret = OC_STACK_ERROR;
56     /* Initialize OCStack*/
57     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK) {
58         OIC_LOG(ERROR, TAG, "OCStack init error");
59         return ret;
60     }
61
62     g_provisioningMutex = ca_mutex_new();
63
64     OIC_LOG(DEBUG, TAG, "ca_thread_pool_init initializing");
65
66     if (CA_STATUS_OK != ca_thread_pool_init(2, &g_threadPoolHandle)) {
67         OIC_LOG(DEBUG, TAG, "thread_pool_init failed");
68         return OC_STACK_ERROR;
69     }
70
71     g_provisioningCond = ca_cond_new();
72     if (NULL == g_provisioningCond) {
73         OIC_LOG(DEBUG, TAG, "Failed to create condition");
74         ca_mutex_free(g_provisioningMutex);
75         ca_thread_pool_free(g_threadPoolHandle);
76         return OC_STACK_ERROR;
77     }
78
79     char *string = "listeningFunc invoked in a thread";
80     if (CA_STATUS_OK
81             != ca_thread_pool_add_task(g_threadPoolHandle, listeningFunc,
82                     (void *) string)) {
83         OIC_LOG(DEBUG, TAG, "thread_pool_add_task failed");
84         ca_thread_pool_free(g_threadPoolHandle);
85         ca_mutex_unlock(g_provisioningMutex);
86         ca_mutex_free(g_provisioningMutex);
87         ca_cond_free(g_provisioningCond);
88         return OC_STACK_ERROR;
89     }
90     return OC_STACK_OK;
91 }
92
93 OCStackResult TerminateProvisioningHandler() {
94     OCStackResult ret = OC_STACK_ERROR;
95     if (OCStop() != OC_STACK_OK) {
96         OIC_LOG(ERROR, TAG, "OCStack stop error");
97     }
98
99     ca_mutex_lock(g_provisioningMutex);
100     g_provisioningCondFlag = true;
101     //ca_cond_signal(g_provisioningCond);
102     ca_mutex_unlock(g_provisioningMutex);
103
104     ca_mutex_free(g_provisioningMutex);
105     g_provisioningMutex = NULL;
106
107     ca_thread_pool_free(g_threadPoolHandle);
108     g_threadPoolHandle = NULL;
109
110     ret = OC_STACK_OK;
111     return ret;
112 }
113
114 void listeningFunc(void *data) {
115     while (!g_provisioningCondFlag) {
116         OCStackResult result;
117
118         ca_mutex_lock(g_provisioningMutex);
119         result = OCProcess();
120         ca_mutex_unlock(g_provisioningMutex);
121
122         if (result != OC_STACK_OK) {
123             OIC_LOG(ERROR, TAG, "OCStack stop error");
124         }
125
126         // To minimize CPU utilization we may wish to do this with sleep
127         sleep(1);
128     }
129 }
130
131 OCStackApplicationResult ProvisionEnrolleeResponse(void* ctx, OCDoHandle handle,
132         OCClientResponse * clientResponse) {
133     ProvisioningInfo provInfo;
134
135     if (clientResponse) {
136         OIC_LOG_V(INFO, TAG, "Put Response JSON = %s",
137                 clientResponse->resJSONPayload);
138     } else {
139         OIC_LOG_V(INFO, TAG,
140                 "ProvisionEnrolleeResponse received Null clientResponse");
141         PrepareProvisioingStatusCB(&provInfo, clientResponse,
142                 DEVICE_NOT_PROVISIONED);
143         cbData(provInfo);
144         return OC_STACK_DELETE_TRANSACTION;
145     }
146
147     uint16_t remotePortNum;
148
149     OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNum);
150
151     char sourceaddr[OIC_STRING_MAX_VALUE] = { '\0' };
152     snprintf(sourceaddr, sizeof(sourceaddr), "%d.%d.%d.%d:%d%s",
153             clientResponse->addr->addr[0], clientResponse->addr->addr[1],
154             clientResponse->addr->addr[2], clientResponse->addr->addr[3],
155             remotePortNum, OIC_PROVISIONING_URI);
156
157     OIC_LOG_V(DEBUG, TAG, "ProvisionEnrolleeResponse %s @ %s",
158             clientResponse->resJSONPayload, sourceaddr);
159
160     if (clientResponse->resJSONPayload) {
161         cJSON *observeJson = cJSON_CreateObject();
162         observeJson = cJSON_Parse(clientResponse->resJSONPayload);
163
164         cJSON *ocArray = cJSON_GetObjectItem(observeJson, "oic");
165         cJSON *ocArray_sub = cJSON_GetArrayItem(ocArray, 0);
166
167         cJSON *representationArray = cJSON_GetObjectItem(ocArray_sub, "rep");
168         char *ocArray_str = cJSON_PrintUnformatted(representationArray);
169
170         if (strstr(ocArray_str, "[{}") == ocArray_str) {
171             OIC_LOG_V(DEBUG, TAG, "invalid payload : %s", ocArray_str);
172             cJSON_Delete(observeJson);
173             return OC_STACK_DELETE_TRANSACTION;
174         }
175
176         int countofrep = cJSON_GetArraySize(representationArray);
177
178         for (int i = 0; i < countofrep; ++i) {
179             cJSON *arrayJSON = cJSON_GetArrayItem(representationArray, i);
180             OIC_LOG_V(DEBUG, TAG, "rep#%d's name : %s", i, arrayJSON->string);
181
182             switch (arrayJSON->type) {
183             case cJSON_False:
184             case cJSON_True:
185                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %d", i,
186                         arrayJSON->valueint);
187                 break;
188             case cJSON_Number:
189                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %f", i,
190                         arrayJSON->valuedouble);
191                 break;
192             case cJSON_String:
193                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %s", i,
194                         arrayJSON->valuestring);
195                 break;
196             case cJSON_NULL:
197             default:
198                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : NULL", i);
199                 break;
200             }
201         }
202
203         cJSON_Delete(observeJson);
204
205         PrepareProvisioingStatusCB(&provInfo, clientResponse,
206                 DEVICE_PROVISIONED);
207         cbData(provInfo);
208
209         return OC_STACK_KEEP_TRANSACTION;
210     } else {
211         OIC_LOG(INFO, TAG,
212                 "ProvisionEnrolleeResponse received NULL clientResponse. \
213                                 Invoking Provisioing Status Callback");
214         PrepareProvisioingStatusCB(&provInfo, clientResponse,
215                 DEVICE_NOT_PROVISIONED);
216         cbData(provInfo);
217         return OC_STACK_DELETE_TRANSACTION;
218     }
219 }
220
221 OCStackResult ProvisionEnrollee(OCQualityOfService qos, const char* query) {
222     OIC_LOG_V(INFO, TAG, "\n\nExecuting ProvisionEnrollee%s", __func__);
223
224     cJSON *jsonFinal = cJSON_CreateObject();
225     cJSON *json = cJSON_CreateObject();
226     cJSON *jsonArray;
227     cJSON *format;
228     char* payload = NULL;
229
230     char nodeData[OIC_STRING_MAX_VALUE] = { '\0' };
231     snprintf(nodeData, sizeof(nodeData), "%s", OIC_PROVISIONING_URI);
232
233     cJSON_AddStringToObject(json, "href", nodeData);
234     cJSON_AddItemToObject(json, "rep", format = cJSON_CreateObject());
235     cJSON_AddStringToObject(format, "tnn", netProvInfo->netAddressInfo.WIFI.ssid);
236     cJSON_AddStringToObject(format, "cd", netProvInfo->netAddressInfo.WIFI.pwd);
237     cJSON_AddItemToObject(jsonFinal, "oic", jsonArray = cJSON_CreateArray());
238     cJSON_AddItemToArray(jsonArray, json);
239
240     OIC_LOG_V(DEBUG, TAG, "ProvisionEnrollee : %s",
241             cJSON_PrintUnformatted(jsonFinal));
242     payload = cJSON_Print(jsonFinal);
243     OIC_LOG_V(DEBUG, TAG, "Payload : %s", payload);
244
245     OCStackResult ret = InvokeOCDoResource(query, OC_REST_PUT, OC_HIGH_QOS,
246             ProvisionEnrolleeResponse, payload, NULL, 0);
247
248     cJSON_Delete(json);
249     return ret;
250 }
251
252 OCStackApplicationResult GetProvisioningStatusResponse(void* ctx,
253         OCDoHandle handle, OCClientResponse * clientResponse) {
254     ProvisioningInfo provInfo;
255
256     if (clientResponse == NULL) {
257         OIC_LOG(INFO, TAG,
258                 "getReqCB received NULL clientResponse. \
259             Invoking Provisioing Status Callback");
260         PrepareProvisioingStatusCB(&provInfo, clientResponse,
261                 DEVICE_NOT_PROVISIONED);
262         cbData(provInfo);
263         return OC_STACK_DELETE_TRANSACTION;
264     }
265
266     if (clientResponse->rcvdVendorSpecificHeaderOptions
267             && clientResponse->numRcvdVendorSpecificHeaderOptions) {
268         OIC_LOG(INFO, TAG, "Received vendor specific options");
269         uint8_t i = 0;
270         OCHeaderOption * rcvdOptions =
271                 clientResponse->rcvdVendorSpecificHeaderOptions;
272         for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions;
273                 i++) {
274             if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID) {
275                 OIC_LOG_V(INFO, TAG,
276                         "Received option with OC_COAP_ID and ID %u with",
277                         ((OCHeaderOption) rcvdOptions[i]).optionID);
278
279                 OIC_LOG_BUFFER(INFO, TAG,
280                         ((OCHeaderOption) rcvdOptions[i]).optionData,
281                         MAX_HEADER_OPTION_DATA_LENGTH);
282             }
283         }
284     }
285
286     char sourceaddr[OIC_STRING_MAX_VALUE] = { '\0' };
287     snprintf(sourceaddr, sizeof(sourceaddr), "%d.%d.%d.%d:%d%s",
288             clientResponse->addr->addr[0], clientResponse->addr->addr[1],
289             clientResponse->addr->addr[2], clientResponse->addr->addr[3],
290             6298, OIC_PROVISIONING_URI);
291
292     if (clientResponse->resJSONPayload) {
293         cJSON *observeJson = cJSON_CreateObject();
294         observeJson = cJSON_Parse(clientResponse->resJSONPayload);
295
296         cJSON *ocArray = cJSON_GetObjectItem(observeJson, "oic");
297         cJSON *ocArray_sub = cJSON_GetArrayItem(ocArray, 0);
298
299         cJSON *representationArray = cJSON_GetObjectItem(ocArray_sub, "rep");
300         char *ocArray_str = cJSON_PrintUnformatted(representationArray);
301
302         if (strstr(ocArray_str, "[{}") == ocArray_str) {
303             OIC_LOG_V(DEBUG, TAG, "invalid payload : %s", ocArray_str);
304             cJSON_Delete(observeJson);
305             return OC_STACK_DELETE_TRANSACTION;
306         }
307
308         int countofrep = cJSON_GetArraySize(representationArray);
309
310         for (int i = 0; i < countofrep; ++i) {
311             cJSON *arrayJSON = cJSON_GetArrayItem(representationArray, i);
312             OIC_LOG_V(DEBUG, TAG, "rep#%d's name : %s", i, arrayJSON->string);
313
314             switch (arrayJSON->type) {
315             case cJSON_False:
316             case cJSON_True:
317                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %d", i,
318                         arrayJSON->valueint);
319                 break;
320             case cJSON_Number:
321                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %f", i,
322                         arrayJSON->valuedouble);
323                 break;
324             case cJSON_String:
325                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : %s", i,
326                         arrayJSON->valuestring);
327                 break;
328             case cJSON_NULL:
329             default:
330                 OIC_LOG_V(DEBUG, TAG, "rep#%d's value : NULL", i);
331                 break;
332             }
333         }
334         cJSON_Delete(observeJson);
335
336         if (ProvisionEnrollee(OC_HIGH_QOS, sourceaddr) != OC_STACK_OK) {
337             OIC_LOG(INFO, TAG,
338                     "GetProvisioningStatusResponse received NULL clientResponse. \
339                 Invoking Provisioing Status Callback");
340             PrepareProvisioingStatusCB(&provInfo, clientResponse,
341                     DEVICE_NOT_PROVISIONED);
342             cbData(provInfo);
343
344             return OC_STACK_DELETE_TRANSACTION;
345         }
346     } else {
347         OIC_LOG(INFO, TAG,
348                 "GetProvisioningStatusResponse received NULL clientResponse. \
349             Invoking Provisioing Status Callback");
350         PrepareProvisioingStatusCB(&provInfo, clientResponse,
351                 DEVICE_NOT_PROVISIONED);
352         cbData(provInfo);
353         return OC_STACK_DELETE_TRANSACTION;
354     }
355     return OC_STACK_DELETE_TRANSACTION;
356 }
357
358 OCStackResult InvokeOCDoResource(const char* query, OCMethod method,
359         OCQualityOfService qos, OCClientResponseHandler cb, const char* request,
360         OCHeaderOption * options, uint8_t numOptions) {
361     OCStackResult ret;
362     OCCallbackData cbData;
363
364     cbData.cb = cb;
365     cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
366     cbData.cd = NULL;
367
368     ret = OCDoResource(NULL, method, query, 0, request, OC_CONNTYPE, qos,
369             &cbData, options, numOptions);
370
371     if (ret != OC_STACK_OK) {
372         OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
373                 ret, method);
374     }
375
376     return ret;
377 }
378
379 OCStackResult GetProvisioningStatus(OCQualityOfService qos, const char* query) {
380     OCStackResult ret = OC_STACK_ERROR;
381     OCHeaderOption options[MAX_HEADER_OPTIONS];
382
383     OIC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
384
385     uint8_t option0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
386     uint8_t option1[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
387     memset(options, 0, sizeof(OCHeaderOption) * MAX_HEADER_OPTIONS);
388     options[0].protocolID = OC_COAP_ID;
389     options[0].optionID = 2048;
390     memcpy(options[0].optionData, option0, sizeof(option0));
391     options[0].optionLength = 10;
392     options[1].protocolID = OC_COAP_ID;
393     options[1].optionID = 3000;
394     memcpy(options[1].optionData, option1, sizeof(option1));
395     options[1].optionLength = 10;
396
397     ret = InvokeOCDoResource(query, OC_REST_GET, OC_HIGH_QOS,
398             GetProvisioningStatusResponse, NULL, options, 2);
399     return ret;
400 }
401
402 OCStackResult StartProvisioningProcess(const EnrolleeNWProvInfo_t *netInfo,
403         OCProvisioningStatusCB provisioningStatusCallback) {
404     OCStackResult result = OC_STACK_ERROR;
405     ProvisioningInfo provInfo;
406
407     if (netInfo->netAddressInfo.WIFI.ipAddress == NULL) {
408         OIC_LOG(ERROR, TAG, "Request URI is NULL");
409         return result;
410     }
411
412     if (provisioningStatusCallback == NULL) {
413         OIC_LOG(ERROR, TAG, "ProvisioningStatusCallback is NULL");
414         return result;
415     }
416
417     cbData = provisioningStatusCallback;
418
419     //Copy Network Provisioning  Information
420     netProvInfo = (EnrolleeNWProvInfo_t *)OICCalloc(1, sizeof(EnrolleeNWProvInfo_t));
421
422     if (NULL == netProvInfo)
423     {
424         OIC_LOG(ERROR, TAG, "Invalid input..");
425         return OC_STACK_ERROR;
426     }
427     memcpy(netProvInfo, netInfo, sizeof(EnrolleeNWProvInfo_t));
428
429     OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. SSID = %s",
430         netProvInfo->netAddressInfo.WIFI.ssid);
431
432     OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. PWD = %s",
433         netProvInfo->netAddressInfo.WIFI.pwd);
434
435     /* Start a discovery query*/
436     char szQueryUri[64] = { 0 };
437
438     snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY,
439             netProvInfo->netAddressInfo.WIFI.ipAddress, IP_PORT);
440
441     OIC_LOG_V(DEBUG, TAG, "szQueryUri = %s", szQueryUri);
442
443     if (FindProvisioningResource(OC_HIGH_QOS, szQueryUri) != OC_STACK_OK) {
444         OIC_LOG(ERROR, TAG,
445                 "FindProvisioningResource failed. \
446             Invoking Provisioing Status Callback");
447
448         ProvDeviceInfo provDeviceIndo;
449         OCDevAddr dst = { };
450
451         dst.addr[0] = netProvInfo->netAddressInfo.WIFI.ipAddress[0];
452         dst.addr[1] = netProvInfo->netAddressInfo.WIFI.ipAddress[1];
453         dst.addr[2] = netProvInfo->netAddressInfo.WIFI.ipAddress[2];
454         dst.addr[3] = netProvInfo->netAddressInfo.WIFI.ipAddress[3];
455         dst.addr[4] = (uint8_t) IP_PORT;
456         dst.addr[5] = (uint8_t)(IP_PORT >> 8);
457
458         provInfo.provStatus = DEVICE_NOT_PROVISIONED;
459         provDeviceIndo.addr = &dst;
460         provDeviceIndo.connType = OC_IPV4;
461         provInfo.provDeviceInfo = provDeviceIndo;
462
463         cbData(provInfo);
464         return result;
465     }
466     result = OC_STACK_OK;
467
468     return result;
469 }
470
471 void StopProvisioningProcess() {
472     cbData = NULL;
473 }
474
475 // This is a function called back when a device is discovered
476 OCStackApplicationResult FindProvisioningResourceResponse(void* ctx,
477         OCDoHandle handle, OCClientResponse * clientResponse) {
478     OIC_LOG(INFO, TAG, PCF("Entering FindProvisioningResourceResponse"));
479
480     OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
481
482     ProvisioningInfo provInfo;
483
484     if (clientResponse->result != OC_STACK_OK) {
485         OIC_LOG(ERROR, TAG,
486                 "OCStack stop error. Calling Provisioing Status Callback");
487
488         PrepareProvisioingStatusCB(&provInfo, clientResponse,
489                 DEVICE_NOT_PROVISIONED);
490
491         cbData(provInfo);
492         return response;
493     }
494
495     if (clientResponse) {
496         // Parse header options from server
497         uint16_t optionID;
498         uint8_t* optionData;
499         const char* payload;
500
501         for (int i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions;
502                 i++) {
503             optionID =
504                     clientResponse->rcvdVendorSpecificHeaderOptions[i].optionID;
505             optionData =
506                     clientResponse->rcvdVendorSpecificHeaderOptions[i].optionData;
507             payload = clientResponse->resJSONPayload;
508         }
509
510         cJSON *discoveryJson = cJSON_CreateObject();
511         discoveryJson = cJSON_Parse((char *) clientResponse->resJSONPayload);
512
513         cJSON *ocArray = cJSON_GetObjectItem(discoveryJson, "oic");
514         char *ocArray_str = cJSON_PrintUnformatted(ocArray);
515
516         if (strstr(ocArray_str, "[{}") == ocArray_str) {
517             OIC_LOG_V(DEBUG, TAG, "invalid payload : %s", ocArray_str);
518             cJSON_Delete(discoveryJson);
519
520             PrepareProvisioingStatusCB(&provInfo, clientResponse,
521                     DEVICE_NOT_PROVISIONED);
522             cbData(provInfo);
523             return response;
524         }
525
526         char sourceaddr[OIC_STRING_MAX_VALUE] = { '\0' };
527         snprintf(sourceaddr, sizeof(sourceaddr), "%d.%d.%d.%d:%d%s",
528                 clientResponse->addr->addr[0], clientResponse->addr->addr[1],
529                 clientResponse->addr->addr[2], clientResponse->addr->addr[3],
530                 IP_PORT, OIC_PROVISIONING_URI);
531
532         OIC_LOG_V(DEBUG, TAG, "Discovered %s @ %s",
533                 clientResponse->resJSONPayload, sourceaddr);
534
535         if (GetProvisioningStatus(OC_HIGH_QOS, sourceaddr) != OC_STACK_OK) {
536             OIC_LOG(INFO, TAG,
537                     "GetProvisioningStatus returned error. \
538                                 Invoking Provisioing Status Callback");
539             PrepareProvisioingStatusCB(&provInfo, clientResponse,
540                     DEVICE_NOT_PROVISIONED);
541             cbData(provInfo);
542
543             return OC_STACK_DELETE_TRANSACTION;
544         }
545     } else {
546         // clientResponse is invalid
547         OIC_LOG(ERROR, TAG,
548                 "Invalid response for Provisioning Discovery request. \
549         Invoking Provisioing Status Callback");
550         PrepareProvisioingStatusCB(&provInfo, clientResponse,
551                 DEVICE_NOT_PROVISIONED);
552         cbData(provInfo);
553         return response;
554     }
555     return OC_STACK_KEEP_TRANSACTION;
556 }
557
558 OCStackResult FindProvisioningResource(OCQualityOfService qos,
559         const char* requestURI) {
560     OCStackResult ret = OC_STACK_ERROR;
561
562     OCCallbackData cbData;
563
564     cbData.cb = FindProvisioningResourceResponse;
565     cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
566     cbData.cd = NULL;
567
568     ret = OCDoResource(NULL, OC_REST_GET, requestURI, 0, 0, OC_CONNTYPE,
569             OC_LOW_QOS, &cbData, NULL, 0);
570
571     if (ret != OC_STACK_OK) {
572         OIC_LOG(ERROR, TAG, "OCStack resource error");
573     }
574
575     return ret;
576 }
577
578 OCStackApplicationResult SubscribeProvPresenceCallback(void* ctx, OCDoHandle handle,
579         OCClientResponse* clientResponse) {
580     OIC_LOG(INFO, TAG, PCF("Entering SubscribeProvPresenceCallback"));
581
582     OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
583
584     if (clientResponse->result != OC_STACK_OK) {
585         OIC_LOG(ERROR, TAG, "OCStack stop error");
586         return response;
587     }
588
589     if (clientResponse) {
590         OIC_LOG(INFO, TAG, PCF("Client Response exists"));
591         // Parse header options from server
592         uint16_t optionID;
593         uint8_t* optionData;
594         const char* payload;
595
596         for (int i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions;
597                 i++) {
598             optionID =
599                     clientResponse->rcvdVendorSpecificHeaderOptions[i].optionID;
600             optionData =
601                     clientResponse->rcvdVendorSpecificHeaderOptions[i].optionData;
602             payload = clientResponse->resJSONPayload;
603         }
604
605         cJSON *discoveryJson = cJSON_CreateObject();
606         discoveryJson = cJSON_Parse((char *) clientResponse->resJSONPayload);
607
608         cJSON *ocArray = cJSON_GetObjectItem(discoveryJson, "oic");
609         char *ocArray_str = cJSON_PrintUnformatted(ocArray);
610
611         if (strstr(ocArray_str, "[{}") == ocArray_str) {
612             OIC_LOG_V(DEBUG, TAG, "invalid payload : %s", ocArray_str);
613             cJSON_Delete(discoveryJson);
614             return response;
615         }
616
617         char sourceIPAddr[OIC_STRING_MAX_VALUE] = { '\0' };
618         snprintf(sourceIPAddr, sizeof(sourceIPAddr), "%d.%d.%d.%d",
619                 clientResponse->addr->addr[0], clientResponse->addr->addr[1],
620                 clientResponse->addr->addr[2], clientResponse->addr->addr[3]);
621
622         OIC_LOG_V(DEBUG, TAG, "Discovered %s @ %s",
623                 clientResponse->resJSONPayload, sourceIPAddr);
624
625         /* Start a discovery query*/
626         char szQueryUri[64] = { 0 };
627         OCQualityOfService qos = OC_NA_QOS;
628
629         snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY,
630                 sourceIPAddr, IP_PORT);
631
632         if (FindProvisioningResource(qos, szQueryUri) != OC_STACK_OK) {
633             OIC_LOG(ERROR, TAG, "FindProvisioningResource failed");
634             return OC_STACK_KEEP_TRANSACTION;
635         }
636     } else {
637         // clientResponse is invalid
638         OIC_LOG(ERROR, TAG, PCF("Client Response is NULL!"));
639     }
640     return OC_STACK_KEEP_TRANSACTION;
641 }
642
643 OCStackResult SubscribeProvPresence(OCQualityOfService qos,
644         const char* requestURI) {
645     OCStackResult ret = OC_STACK_ERROR;
646
647     OCCallbackData cbData;
648
649     cbData.cb = &SubscribeProvPresenceCallback;
650     cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
651     cbData.cd = NULL;
652
653     ret = OCDoResource(NULL, OC_REST_PRESENCE, requestURI, 0, 0, OC_CONNTYPE,
654             OC_LOW_QOS, &cbData, NULL, 0);
655
656     if (ret != OC_STACK_OK) {
657         OIC_LOG(ERROR, TAG, "OCStack resource error");
658     }
659
660     return ret;
661 }
662
663 OCStackResult FindNetworkResource() {
664     OCStackResult ret = OC_STACK_ERROR;
665     if (OCStop() != OC_STACK_OK) {
666         OIC_LOG(ERROR, TAG, "OCStack stop error");
667     }
668
669     return ret;
670 }
671
672 void PrepareProvisioingStatusCB(ProvisioningInfo *provInfo,
673         OCClientResponse * clientResponse, ProvStatus provStatus) {
674     ProvDeviceInfo provDeviceIndo;
675     OCDevAddr dst = { };
676
677     uint16_t remotePortNum;
678     OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNum);
679
680     dst.addr[0] = clientResponse->addr->addr[0];
681     dst.addr[1] = clientResponse->addr->addr[1];
682     dst.addr[2] = clientResponse->addr->addr[2];
683     dst.addr[3] = clientResponse->addr->addr[3];
684     dst.addr[4] = (uint8_t) remotePortNum;
685     dst.addr[5] = (uint8_t)(remotePortNum >> 8);
686
687     provInfo->provStatus = provStatus;
688
689     provDeviceIndo.addr = &dst;
690     provDeviceIndo.connType = OC_IPV4;
691
692     provInfo->provDeviceInfo = provDeviceIndo;
693 }
694