2680aba525c76605564f36879856e421b1e3926d
[platform/upstream/iotivity.git] / cloud / samples / client / thin_light / thin_room_light.cpp
1 //******************************************************************
2 //
3 // Copyright 2016 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 ///
22 /// This sample provides the way to create cloud sample
23 ///
24 #include <memory>
25 #include <iostream>
26 #include <stdexcept>
27 #include <condition_variable>
28 #include <map>
29 #include <vector>
30 #include <string>
31 #include <pthread.h>
32 #include <unistd.h>
33
34 #include "ocstack.h"
35 #include "ocpayload.h"
36 #include "oicresourcedirectory.h"
37
38 using namespace std;
39
40 #define DEFAULT_CONTEXT_VALUE 0x99
41 #define DEFAULT_AUTH_SIGNUP "/oic/account"
42 #define DEFAULT_AUTH_SESSION "/oic/account/session"
43 #define DEFAULT_AUTH_REFRESH "/oic/account/tokenrefresh"
44
45
46 OCStackResult OCCloudSignup(const char *host, const char *deviceId,
47                             const char *authprovider,
48                             const char *authcode, OCClientResponseHandler response)
49 {
50     char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
51     snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_SIGNUP);
52
53     OCCallbackData cbData;
54     memset(&cbData, 0, sizeof(OCCallbackData));
55     cbData.cb = response;
56     cbData.cd = NULL;
57     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
58
59     OCRepPayload *registerPayload = OCRepPayloadCreate();
60     if (!registerPayload)
61     {
62         goto no_memory;
63     }
64
65     OCRepPayloadSetPropString(registerPayload, "di", deviceId);
66     OCRepPayloadSetPropString(registerPayload, "authprovider", authprovider);
67     OCRepPayloadSetPropString(registerPayload, "authcode", authcode);
68
69     return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)registerPayload,
70                         CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
71
72 no_memory:
73     OCRepPayloadDestroy(registerPayload);
74     return OC_STACK_NO_MEMORY;
75 }
76
77 OCStackResult OCCloudSession(const char *host, const char *query, const char *uId,
78                              const char *deviceId,
79                              const char *accesstoken,
80                              bool isLogin, OCClientResponseHandler response)
81 {
82     char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
83     snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
84
85     OCCallbackData cbData;
86     memset(&cbData, 0, sizeof(OCCallbackData));
87     cbData.cb = response;
88     cbData.cd = NULL;
89     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
90
91     OCRepPayload *loginoutPayload = OCRepPayloadCreate();
92     if (!loginoutPayload)
93     {
94         goto no_memory;
95     }
96
97     if (uId != NULL)
98     {
99         OCRepPayloadSetPropString(loginoutPayload, "uid", uId);
100     }
101
102     if (deviceId != NULL)
103     {
104         OCRepPayloadSetPropString(loginoutPayload, "di", deviceId);
105     }
106
107     if (accesstoken != NULL)
108     {
109         OCRepPayloadSetPropString(loginoutPayload, "accesstoken", accesstoken);
110     }
111     OCRepPayloadSetPropBool(loginoutPayload, "login", isLogin);
112
113     return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)loginoutPayload,
114                         CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
115
116 no_memory:
117     OCRepPayloadDestroy(loginoutPayload);
118     return OC_STACK_NO_MEMORY;
119 }
120
121 //Client should call refresh before expiresin or when receive 4.01 during sign-in
122 OCStackResult OCCloudRefresh(const char *host, const char *query, const char *uId,
123                              const char *deviceId, const char *refreshtoken, OCClientResponseHandler response)
124 {
125     char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
126     snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
127
128     OCCallbackData cbData;
129     memset(&cbData, 0, sizeof(OCCallbackData));
130     cbData.cb = response;
131     cbData.cd = NULL;
132     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
133
134     OCRepPayload *refreshPayload = OCRepPayloadCreate();
135     if (!refreshPayload)
136     {
137         goto no_memory;
138     }
139
140     OCRepPayloadSetPropString(refreshPayload, "uid", uId);
141     OCRepPayloadSetPropString(refreshPayload, "di", deviceId);
142     OCRepPayloadSetPropString(refreshPayload, "granttype", "refresh_token");
143     OCRepPayloadSetPropString(refreshPayload, "refreshtoken", refreshtoken);
144
145     return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)refreshPayload,
146                         CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
147
148 no_memory:
149     OCRepPayloadDestroy(refreshPayload);
150     return OC_STACK_NO_MEMORY;
151 }
152
153 OCStackResult OCCloudLogin(const char *host, const char *uId, const char *deviceId,
154                            const char *accesstoken, OCClientResponseHandler response)
155 {
156     return OCCloudSession(host, DEFAULT_AUTH_SESSION, uId, deviceId, accesstoken, true, response);
157 }
158
159 OCStackResult OCCloudLogout(const char *host, OCClientResponseHandler response)
160 {
161     return OCCloudSession(host, DEFAULT_AUTH_SESSION, NULL, NULL, NULL, false, response);
162 }
163
164 ////////////////////////////////////////Device Sample
165
166 #define SAMPLE_MAX_NUM_POST_INSTANCE  1
167 typedef struct LIGHTRESOURCE
168 {
169     OCResourceHandle handle;
170     bool state;
171     int power;
172 } LightResource;
173 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
174
175
176 OCRepPayload *responsePayload(int64_t power, bool state)
177 {
178     OCRepPayload *payload = OCRepPayloadCreate();
179     if (!payload)
180     {
181         cout << "Failed to allocate Payload" << endl;
182         return nullptr;
183     }
184
185     OCRepPayloadSetPropBool(payload, "state", state);
186     OCRepPayloadSetPropInt(payload, "power", power);
187
188     return payload;
189 }
190
191 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
192 {
193     if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
194     {
195         cout << "Incoming payload not a representation" << endl;
196         return nullptr;
197     }
198
199     LightResource *currLightResource = NULL;
200
201     if (ehRequest->resource == gLightInstance[0].handle)
202     {
203         currLightResource = &gLightInstance[0];
204     }
205     else if (ehRequest->resource == gLightInstance[1].handle)
206     {
207         currLightResource = &gLightInstance[1];
208     }
209
210     if (OC_REST_PUT == ehRequest->method)
211     {
212         // Get pointer to query
213         int64_t pow;
214         OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
215
216         if (OCRepPayloadGetPropInt(input, "power", &pow))
217         {
218             currLightResource->power = pow;
219         }
220
221         bool state;
222         if (OCRepPayloadGetPropBool(input, "state", &state))
223         {
224             currLightResource->state = state;
225         }
226     }
227
228     return responsePayload(currLightResource->power, currLightResource->state);
229 }
230
231 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
232                                         OCRepPayload **payload)
233 {
234     OCRepPayload *getResp = constructResponse(ehRequest);
235     if (!getResp)
236     {
237         cout << "constructResponse failed" << endl;
238         return OC_EH_ERROR;
239     }
240
241     *payload = getResp;
242
243     return OC_EH_OK;
244 }
245
246 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
247                                         OCRepPayload **payload)
248 {
249     OCEntityHandlerResult ehResult;
250     OCRepPayload *putResp = constructResponse(ehRequest);
251
252     if (!putResp)
253     {
254         cout << "Failed to construct Json response" << endl;
255         return OC_EH_ERROR;
256     }
257
258     *payload = putResp;
259     ehResult = OC_EH_OK;
260
261     return ehResult;
262 }
263
264 #define SAMPLE_MAX_NUM_OBSERVATIONS  2
265 static bool observeThreadStarted = false;
266 int gLightUnderObservation = 0;
267 pthread_t threadId_observe;
268 typedef struct
269 {
270     OCObservationId observationId;
271     bool valid;
272     OCResourceHandle resourceHandle;
273 } Observers;
274 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
275
276 void *ChangeLightRepresentation(void *param)
277 {
278     (void)param;
279     OCStackResult result = OC_STACK_ERROR;
280
281     while (true)
282     {
283         sleep(3);
284         gLightInstance[0].power += 1;
285         gLightInstance[1].power += 3;
286
287         if (gLightUnderObservation)
288         {
289             cout << " =====> Notifying stack of new power level " << gLightInstance[0].power << endl;
290             cout << " =====> Notifying stack of new power level " << gLightInstance[1].power << endl;
291             // Notifying all observers
292             result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
293             result = OCNotifyAllObservers(gLightInstance[1].handle, OC_NA_QOS);
294
295             cout << " =====> Notifying result " << result << endl;
296         }
297     }
298     return NULL;
299 }
300
301 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
302 {
303     cout << "Received observation registration request with observation Id " <<
304          ehRequest->obsInfo.obsId << endl;
305
306     if (!observeThreadStarted)
307     {
308         pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *)NULL);
309         observeThreadStarted = 1;
310     }
311     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
312     {
313         if (interestedObservers[i].valid == false)
314         {
315             interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
316             interestedObservers[i].valid = true;
317             gLightUnderObservation = 1;
318             break;
319         }
320     }
321 }
322
323 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
324 {
325     bool clientStillObserving = false;
326
327     cout << "Received observation deregistration request for observation Id " <<
328          ehRequest->obsInfo.obsId << endl;
329     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
330     {
331         if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
332         {
333             interestedObservers[i].valid = false;
334         }
335         if (interestedObservers[i].valid == true)
336         {
337             // Even if there is one single client observing we continue notifying entity handler
338             clientStillObserving = true;
339         }
340     }
341     if (clientStillObserving == false)
342         gLightUnderObservation = 0;
343 }
344
345 OCEntityHandlerResult
346 OCEntityHandlerCb(OCEntityHandlerFlag flag,
347                   OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
348 {
349     OCEntityHandlerResult ehResult = OC_EH_OK;
350     OCEntityHandlerResponse response = { 0, 0, OC_EH_ERROR, 0, 0, {}, { 0 }, false };
351
352     // Validate pointer
353     if (!entityHandlerRequest)
354     {
355         cout << "Invalid request pointer" << endl;
356         return OC_EH_ERROR;
357     }
358
359     // Initialize certain response fields
360     response.numSendVendorSpecificHeaderOptions = 0;
361     memset(response.sendVendorSpecificHeaderOptions,
362            0, sizeof response.sendVendorSpecificHeaderOptions);
363     memset(response.resourceUri, 0, sizeof response.resourceUri);
364     OCRepPayload *payload = nullptr;
365
366     if (flag & OC_REQUEST_FLAG)
367     {
368         cout << "Flag includes OC_REQUEST_FLAG" << endl;
369
370         if (OC_REST_GET == entityHandlerRequest->method)
371         {
372             cout << "Received OC_REST_GET from client" << endl;
373             ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
374         }
375         else if (OC_REST_PUT == entityHandlerRequest->method)
376         {
377             cout << "Received OC_REST_PUT from client" << endl;
378             ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
379         }
380         else
381         {
382             cout << "Received unsupported method %d from client " << entityHandlerRequest->method <<
383                  endl;
384             ehResult = OC_EH_ERROR;
385         }
386         // If the result isn't an error or forbidden, send response
387         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
388         {
389             // Format the response.  Note this requires some info about the request
390             response.requestHandle = entityHandlerRequest->requestHandle;
391             response.resourceHandle = entityHandlerRequest->resource;
392             response.ehResult = ehResult;
393             response.payload = reinterpret_cast<OCPayload *>(payload);
394             // Indicate that response is NOT in a persistent buffer
395             response.persistentBufferFlag = 0;
396
397             // Send the response
398             if (OCDoResponse(&response) != OC_STACK_OK)
399             {
400                 cout << "Error sending response" << endl;
401                 ehResult = OC_EH_ERROR;
402             }
403         }
404     }
405
406     if (flag & OC_OBSERVE_FLAG)
407     {
408         cout << "Flag includes OC_OBSERVE_FLAG" << endl;
409         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
410         {
411             cout << "Received OC_OBSERVE_REGISTER from client" << endl;
412             ProcessObserveRegister(entityHandlerRequest);
413         }
414         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
415         {
416             cout << "Received OC_OBSERVE_DEREGISTER from client" << endl;
417             ProcessObserveDeregister(entityHandlerRequest);
418         }
419     }
420
421     OCPayloadDestroy(response.payload);
422     return ehResult;
423 }
424
425 int createLightResource(char *uri, LightResource *lightResource)
426 {
427     if (!uri)
428     {
429         cout << "Resource URI cannot be NULL" << endl;
430         return -1;
431     }
432
433     lightResource->state = false;
434     lightResource->power = 0;
435     OCStackResult res = OCCreateResource(&(lightResource->handle),
436                                          "core.light",
437                                          "oc.mi.def",
438                                          uri,
439                                          OCEntityHandlerCb,
440                                          NULL,
441                                          OC_DISCOVERABLE | OC_OBSERVABLE);
442     cout << "Created Light resource with result:" << res << endl;
443
444     return res;
445 }
446
447 OCStackApplicationResult handlePublishCB(void *ctx,
448         OCDoHandle /*handle*/,
449         OCClientResponse *clientResponse)
450 {
451     if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
452     {
453         cout << "Invalid Publish callback received" << endl;
454     }
455
456     cout << "Publish resource response received, code: " << clientResponse->result << endl;
457
458     return OC_STACK_KEEP_TRANSACTION;
459 }
460
461 void PublishResources(string host)
462 {
463     cout << "Publishing resources..." << endl;
464
465     if (createLightResource((char *)"/a/light/0", &gLightInstance[0]) != 0)
466     {
467         cout << "Unable to create sample resource" << endl;
468     }
469
470     OCResourceHandle    resourceHandles[1] = { gLightInstance[0].handle,
471                                              };
472     OCCallbackData cbData;
473     cbData.cb = handlePublishCB;
474     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
475     cbData.cd = NULL;
476
477     cout << "Publish default resources" << endl;
478
479     OCDeviceInfo        devInfoRoomLight;
480     OCStringLL          deviceType;
481
482     deviceType.value = "oic.d.light";
483     deviceType.next = NULL;
484     devInfoRoomLight.deviceName = "Living Room Light";
485     devInfoRoomLight.types = &deviceType;
486     devInfoRoomLight.specVersion = NULL;
487     devInfoRoomLight.dataModelVersions = NULL;
488
489     OCStackResult res = OCSetDeviceInfo(devInfoRoomLight);
490
491     if (res != OC_STACK_OK)
492     {
493         cout << "Setting device info failed" << endl;
494     }
495
496     res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData,
497                       OC_LOW_QOS);
498     if (res != OC_STACK_OK)
499     {
500         cout << "Unable to publish default resources to cloud" << endl;
501     }
502
503     cout << "Publish user resources" << endl;
504
505     res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData,
506                       OC_LOW_QOS);
507     if (res != OC_STACK_OK)
508     {
509         cout << "Unable to publish user resources to cloud" << endl;
510     }
511 }
512
513 /////////////////////////////////////////////Common sample
514 void printRepresentation(OCRepPayloadValue *value)
515 {
516     while (value)
517     {
518         cout << "Key: " << value->name;
519         switch (value->type)
520         {
521             case OCREP_PROP_NULL:
522                 cout << " Value: None" << endl;
523                 break;
524             case OCREP_PROP_INT:
525                 cout << " Value: " << value->i << endl;
526                 break;
527             case OCREP_PROP_DOUBLE:
528                 cout << " Value: " << value->d << endl;
529                 break;
530             case OCREP_PROP_BOOL:
531                 cout << " Value: " << value->b << endl;
532                 break;
533             case OCREP_PROP_STRING:
534                 cout << " Value: " << value->str << endl;
535                 break;
536             case OCREP_PROP_BYTE_STRING:
537                 cout << " Value: Byte String" << endl;
538                 break;
539             case OCREP_PROP_OBJECT:
540                 cout << " Value: Object" << endl;
541                 break;
542             case OCREP_PROP_ARRAY:
543                 cout << " Value: Array" << endl;
544                 break;
545         }
546         value = value->next;
547     }
548 }
549
550 string g_host = "coap+tcp://";
551
552 OCStackApplicationResult handleLoginoutCB(void *ctx,
553         OCDoHandle /*handle*/,
554         OCClientResponse *clientResponse)
555 {
556     if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
557     {
558         cout << "Invalid Login/out callback received" << endl;
559     }
560
561     cout << "Login/out response received code: " << clientResponse->result << endl;
562
563     if (clientResponse->payload != NULL &&
564         clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
565     {
566         cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
567
568         OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
569
570         printRepresentation(val);
571     }
572
573     if (clientResponse->result < 5)
574     {
575         PublishResources(g_host);
576     }
577
578     return OC_STACK_KEEP_TRANSACTION;
579 }
580
581 OCStackApplicationResult handleRegisterCB(void *ctx,
582         OCDoHandle /*handle*/,
583         OCClientResponse *clientResponse)
584 {
585     if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
586     {
587         cout << "Invalid Register callback received" << endl;
588     }
589
590     cout << "Register response received code: " << clientResponse->result << endl;
591
592     if (clientResponse->payload != NULL &&
593         clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
594     {
595         cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
596         cout << "You can Sign-In using retrieved accesstoken when disconnected or reboot" <<
597              endl;
598
599         OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
600
601         printRepresentation(val);
602     }
603
604     return OC_STACK_KEEP_TRANSACTION;
605 }
606
607 void PrintUsage()
608 {
609     cout << endl;
610     cout << "Usage : thin_cloud_device <addr:port> <uid> <accesstoken>\n";
611     cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
612     cout <<
613          "<accesstoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
614     cout <<
615          "sample: \"cloud_device 127.0.0.1:5683\"\n\t-Sign-Up mode\n\n";
616     cout <<
617          "sample: \"cloud_device 127.0.0.1:5683 abcdefg 1234567890123456\"\n\t-Sign-in and Publish resource to registered account\n\n";
618 }
619
620 static FILE *client_open(const char * /*path*/, const char *mode)
621 {
622     return fopen("./thin_resource_server.dat", mode);
623 }
624
625 int main(int argc, char *argv[])
626 {
627     string uId;
628     string accessToken;
629
630     string authProvider;
631     string authCode;
632
633     OCMode      stackMode = OC_CLIENT_SERVER;
634
635     switch (argc)
636     {
637         case 2:
638             cout << "Put auth provider name(ex: github)" << endl;
639             cin >> authProvider;
640             cout << "Put auth code(provided by auth provider)" << endl;
641             cin >> authCode;
642             break;
643
644         case 4:
645             uId = argv[2];
646             accessToken = argv[3];
647             break;
648
649         default:
650             PrintUsage();
651             return 0;
652     }
653
654     g_host += argv[1];
655
656     cout << "Host " << g_host.c_str() << endl;
657
658     OCPersistentStorage ps{ client_open, fread, fwrite, fclose, unlink };
659     if (OCRegisterPersistentStorageHandler(&ps) != OC_STACK_OK)
660     {
661         cout << "OCStack init persistent storage error" << endl;
662         return 0;
663     }
664
665     if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
666     {
667         cout << "OCStack init error" << endl;
668         return 0;
669     }
670
671     OCStackResult   res = OC_STACK_ERROR;
672
673     switch (argc)
674     {
675         case 2:
676             cout << "Sign-Up to cloud using " << authProvider << " " << authCode << endl;
677             res = OCCloudSignup(g_host.c_str(), OCGetServerInstanceIDString(), authProvider.c_str(),
678                                 authCode.c_str(), handleRegisterCB);
679             cout << "OCCloudSignup return " << res << endl;
680             break;
681
682         case 4:
683             cout << "Sign-In to cloud using " << accessToken << endl;
684             res = OCCloudLogin(g_host.c_str(), uId.c_str(), OCGetServerInstanceIDString(), accessToken.c_str(),
685                                handleLoginoutCB);
686             cout << "OCCloudLogin return " << res << endl;
687             break;
688
689         default:
690             PrintUsage();
691             return 0;
692     }
693
694
695
696     cout << "Waiting response.." << endl;
697
698     while (true)
699     {
700         if (OCProcess() != OC_STACK_OK)
701         {
702             cout << "OCProcess process error" << endl;
703         }
704
705         sleep(1);
706     }
707
708     if (OCStop() != OC_STACK_OK)
709     {
710         cout << "OCStop process error" << endl;
711     }
712
713     return 0;
714 }