1 //******************************************************************
3 // Copyright 2016 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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 /// This sample provides the way to create cloud sample
27 #include <condition_variable>
35 #include "ocpayload.h"
36 #include "oicresourcedirectory.h"
38 #define DEFAULT_CONTEXT_VALUE 0x99
39 #define DEFAULT_AUTH_SIGNUP "/oic/account"
40 #define DEFAULT_AUTH_SESSION "/oic/account/session"
41 #define DEFAULT_AUTH_REFRESH "/oic/account/tokenrefresh"
44 OCStackResult OCCloudSignup(const char *host, const char *deviceId,
45 const char *authprovider,
46 const char *authcode, OCClientResponseHandler response)
48 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
49 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_SIGNUP);
51 OCCallbackData cbData;
52 memset(&cbData, 0, sizeof(OCCallbackData));
55 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
57 OCRepPayload *registerPayload = OCRepPayloadCreate();
63 OCRepPayloadSetPropString(registerPayload, "di", deviceId);
64 OCRepPayloadSetPropString(registerPayload, "authprovider", authprovider);
65 OCRepPayloadSetPropString(registerPayload, "authcode", authcode);
67 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)registerPayload,
68 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
71 OCRepPayloadDestroy(registerPayload);
72 return OC_STACK_NO_MEMORY;
75 OCStackResult OCCloudSession(const char *host, const char *query, const char *uId,
77 const char *accesstoken,
78 bool isLogin, OCClientResponseHandler response)
80 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
81 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
83 OCCallbackData cbData;
84 memset(&cbData, 0, sizeof(OCCallbackData));
87 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
89 OCRepPayload *loginoutPayload = OCRepPayloadCreate();
97 OCRepPayloadSetPropString(loginoutPayload, "uid", uId);
100 if (deviceId != NULL)
102 OCRepPayloadSetPropString(loginoutPayload, "di", deviceId);
105 if (accesstoken != NULL)
107 OCRepPayloadSetPropString(loginoutPayload, "accesstoken", accesstoken);
109 OCRepPayloadSetPropBool(loginoutPayload, "login", isLogin);
111 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)loginoutPayload,
112 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
115 OCRepPayloadDestroy(loginoutPayload);
116 return OC_STACK_NO_MEMORY;
119 //Client should call refresh before expiresin or when receive 4.01 during sign-in
120 OCStackResult OCCloudRefresh(const char *host, const char *query, const char *uId,
121 const char *deviceId, const char *refreshtoken, OCClientResponseHandler response)
123 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
124 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
126 OCCallbackData cbData;
127 memset(&cbData, 0, sizeof(OCCallbackData));
128 cbData.cb = response;
130 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
132 OCRepPayload *refreshPayload = OCRepPayloadCreate();
138 OCRepPayloadSetPropString(refreshPayload, "uid", uId);
139 OCRepPayloadSetPropString(refreshPayload, "di", deviceId);
140 OCRepPayloadSetPropString(refreshPayload, "granttype", "refresh_token");
141 OCRepPayloadSetPropString(refreshPayload, "refreshtoken", refreshtoken);
143 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)refreshPayload,
144 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
147 OCRepPayloadDestroy(refreshPayload);
148 return OC_STACK_NO_MEMORY;
151 OCStackResult OCCloudLogin(const char *host, const char *uId, const char *deviceId,
152 const char *accesstoken, OCClientResponseHandler response)
154 return OCCloudSession(host, DEFAULT_AUTH_SESSION, uId, deviceId, accesstoken, true, response);
157 OCStackResult OCCloudLogout(const char *host, OCClientResponseHandler response)
159 return OCCloudSession(host, DEFAULT_AUTH_SESSION, NULL, NULL, NULL, false, response);
162 ////////////////////////////////////////Device Sample
164 #define SAMPLE_MAX_NUM_POST_INSTANCE 1
165 typedef struct LIGHTRESOURCE
167 OCResourceHandle handle;
171 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
174 OCRepPayload *responsePayload(int64_t power, bool state)
176 OCRepPayload *payload = OCRepPayloadCreate();
179 std::cout << "Failed to allocate Payload" << std::endl;
183 OCRepPayloadSetPropBool(payload, "state", state);
184 OCRepPayloadSetPropInt(payload, "power", power);
189 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
191 if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
193 std::cout << "Incoming payload not a representation" << std::endl;
197 LightResource *currLightResource = NULL;
199 if (ehRequest->resource == gLightInstance[0].handle)
201 currLightResource = &gLightInstance[0];
203 else if (ehRequest->resource == gLightInstance[1].handle)
205 currLightResource = &gLightInstance[1];
208 if (OC_REST_PUT == ehRequest->method)
210 // Get pointer to query
212 OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
214 if (OCRepPayloadGetPropInt(input, "power", &pow))
216 currLightResource->power = pow;
220 if (OCRepPayloadGetPropBool(input, "state", &state))
222 currLightResource->state = state;
226 return responsePayload(currLightResource->power, currLightResource->state);
229 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
230 OCRepPayload **payload)
232 OCRepPayload *getResp = constructResponse(ehRequest);
235 std::cout << "constructResponse failed" << std::endl;
244 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
245 OCRepPayload **payload)
247 OCEntityHandlerResult ehResult;
248 OCRepPayload *putResp = constructResponse(ehRequest);
252 std::cout << "Failed to construct Json response" << std::endl;
262 #define SAMPLE_MAX_NUM_OBSERVATIONS 2
263 static bool observeThreadStarted = false;
264 int gLightUnderObservation = 0;
265 pthread_t threadId_observe;
268 OCObservationId observationId;
270 OCResourceHandle resourceHandle;
272 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
274 void *ChangeLightRepresentation(void *param)
277 OCStackResult result = OC_STACK_ERROR;
282 gLightInstance[0].power += 1;
283 gLightInstance[1].power += 3;
285 if (gLightUnderObservation)
287 std::cout << " =====> Notifying stack of new power level " << gLightInstance[0].power << std::endl;
288 std::cout << " =====> Notifying stack of new power level " << gLightInstance[1].power << std::endl;
289 // Notifying all observers
290 result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
291 result = OCNotifyAllObservers(gLightInstance[1].handle, OC_NA_QOS);
293 std::cout << " =====> Notifying result " << result << std::endl;
299 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
301 std::cout << "Received observation registration request with observation Id " <<
302 ehRequest->obsInfo.obsId << std::endl;
304 if (!observeThreadStarted)
306 pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *)NULL);
307 observeThreadStarted = 1;
309 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
311 if (interestedObservers[i].valid == false)
313 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
314 interestedObservers[i].valid = true;
315 gLightUnderObservation = 1;
321 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
323 bool clientStillObserving = false;
325 std::cout << "Received observation deregistration request for observation Id " <<
326 ehRequest->obsInfo.obsId << std::endl;
327 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
329 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
331 interestedObservers[i].valid = false;
333 if (interestedObservers[i].valid == true)
335 // Even if there is one single client observing we continue notifying entity handler
336 clientStillObserving = true;
339 if (clientStillObserving == false)
340 gLightUnderObservation = 0;
343 OCEntityHandlerResult
344 OCEntityHandlerCb(OCEntityHandlerFlag flag,
345 OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
347 OCEntityHandlerResult ehResult = OC_EH_OK;
348 OCEntityHandlerResponse response = { 0, 0, OC_EH_ERROR, 0, 0, {}, { 0 }, false };
351 if (!entityHandlerRequest)
353 std::cout << "Invalid request pointer" << std::endl;
357 // Initialize certain response fields
358 response.numSendVendorSpecificHeaderOptions = 0;
359 memset(response.sendVendorSpecificHeaderOptions,
360 0, sizeof response.sendVendorSpecificHeaderOptions);
361 memset(response.resourceUri, 0, sizeof response.resourceUri);
362 OCRepPayload *payload = nullptr;
364 if (flag & OC_REQUEST_FLAG)
366 std::cout << "Flag includes OC_REQUEST_FLAG" << std::endl;
368 if (OC_REST_GET == entityHandlerRequest->method)
370 std::cout << "Received OC_REST_GET from client" << std::endl;
371 ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
373 else if (OC_REST_PUT == entityHandlerRequest->method)
375 std::cout << "Received OC_REST_PUT from client" << std::endl;
376 ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
380 std::cout << "Received unsupported method %d from client " << entityHandlerRequest->method <<
382 ehResult = OC_EH_ERROR;
384 // If the result isn't an error or forbidden, send response
385 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
387 // Format the response. Note this requires some info about the request
388 response.requestHandle = entityHandlerRequest->requestHandle;
389 response.resourceHandle = entityHandlerRequest->resource;
390 response.ehResult = ehResult;
391 response.payload = reinterpret_cast<OCPayload *>(payload);
392 // Indicate that response is NOT in a persistent buffer
393 response.persistentBufferFlag = 0;
396 if (OCDoResponse(&response) != OC_STACK_OK)
398 std::cout << "Error sending response" << std::endl;
399 ehResult = OC_EH_ERROR;
404 if (flag & OC_OBSERVE_FLAG)
406 std::cout << "Flag includes OC_OBSERVE_FLAG" << std::endl;
407 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
409 std::cout << "Received OC_OBSERVE_REGISTER from client" << std::endl;
410 ProcessObserveRegister(entityHandlerRequest);
412 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
414 std::cout << "Received OC_OBSERVE_DEREGISTER from client" << std::endl;
415 ProcessObserveDeregister(entityHandlerRequest);
419 OCPayloadDestroy(response.payload);
423 int createLightResource(char *uri, LightResource *lightResource)
427 std::cout << "Resource URI cannot be NULL" << std::endl;
431 lightResource->state = false;
432 lightResource->power = 0;
433 OCStackResult res = OCCreateResource(&(lightResource->handle),
439 OC_DISCOVERABLE | OC_OBSERVABLE);
440 std::cout << "Created Light resource with result:" << res << std::endl;
445 OCStackApplicationResult handlePublishCB(void *ctx,
446 OCDoHandle /*handle*/,
447 OCClientResponse *clientResponse)
449 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
451 std::cout << "Invalid Publish callback received" << std::endl;
454 std::cout << "Publish resource response received, code: " << clientResponse->result << std::endl;
456 return OC_STACK_KEEP_TRANSACTION;
459 void PublishResources(std::string host)
461 std::cout << "Publishing resources..." << std::endl;
463 if (createLightResource((char *)"/a/light/0", &gLightInstance[0]) != 0)
465 std::cout << "Unable to create sample resource" << std::endl;
468 OCResourceHandle resourceHandles[1] = { gLightInstance[0].handle,
470 OCCallbackData cbData;
471 cbData.cb = handlePublishCB;
472 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
475 std::cout << "Publish default resources" << std::endl;
477 OCDeviceInfo devInfoRoomLight;
478 OCStringLL deviceType;
480 deviceType.value = "oic.d.light";
481 deviceType.next = NULL;
482 devInfoRoomLight.deviceName = "Living Room Light";
483 devInfoRoomLight.types = &deviceType;
484 devInfoRoomLight.specVersion = NULL;
485 devInfoRoomLight.dataModelVersions = NULL;
487 OCStackResult res = OCSetDeviceInfo(devInfoRoomLight);
489 if (res != OC_STACK_OK)
491 std::cout << "Setting device info failed" << std::endl;
494 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData,
496 if (res != OC_STACK_OK)
498 std::cout << "Unable to publish default resources to cloud" << std::endl;
501 std::cout << "Publish user resources" << std::endl;
503 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData,
505 if (res != OC_STACK_OK)
507 std::cout << "Unable to publish user resources to cloud" << std::endl;
511 /////////////////////////////////////////////Common sample
512 void printRepresentation(OCRepPayloadValue *value)
516 std::cout << "Key: " << value->name;
519 case OCREP_PROP_NULL:
520 std::cout << " Value: None" << std::endl;
523 std::cout << " Value: " << value->i << std::endl;
525 case OCREP_PROP_DOUBLE:
526 std::cout << " Value: " << value->d << std::endl;
528 case OCREP_PROP_BOOL:
529 std::cout << " Value: " << value->b << std::endl;
531 case OCREP_PROP_STRING:
532 std::cout << " Value: " << value->str << std::endl;
534 case OCREP_PROP_BYTE_STRING:
535 std::cout << " Value: Byte String" << std::endl;
537 case OCREP_PROP_OBJECT:
538 std::cout << " Value: Object" << std::endl;
540 case OCREP_PROP_ARRAY:
541 std::cout << " Value: Array" << std::endl;
548 std::string g_host = "coap+tcp://";
550 OCStackApplicationResult handleLoginoutCB(void *ctx,
551 OCDoHandle /*handle*/,
552 OCClientResponse *clientResponse)
554 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
556 std::cout << "Invalid Login/out callback received" << std::endl;
559 std::cout << "Login/out response received code: " << clientResponse->result << std::endl;
561 if (clientResponse->payload != NULL &&
562 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
564 std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
566 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
568 printRepresentation(val);
571 if (clientResponse->result < 5)
573 PublishResources(g_host);
576 return OC_STACK_KEEP_TRANSACTION;
579 OCStackApplicationResult handleRegisterCB(void *ctx,
580 OCDoHandle /*handle*/,
581 OCClientResponse *clientResponse)
583 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
585 std::cout << "Invalid Register callback received" << std::endl;
588 std::cout << "Register response received code: " << clientResponse->result << std::endl;
590 if (clientResponse->payload != NULL &&
591 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
593 std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
594 std::cout << "You can Sign-In using retrieved accesstoken when disconnected or reboot" <<
597 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
599 printRepresentation(val);
602 return OC_STACK_KEEP_TRANSACTION;
607 std::cout << std::endl;
608 std::cout << "Usage : thin_cloud_device <addr:port> <uid> <accesstoken>\n";
609 std::cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
611 "<accesstoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
613 "sample: \"cloud_device 127.0.0.1:5683\"\n\t-Sign-Up mode\n\n";
615 "sample: \"cloud_device 127.0.0.1:5683 abcdefg 1234567890123456\"\n\t-Sign-in and Publish resource to registered account\n\n";
618 static FILE *client_open(const char * /*path*/, const char *mode)
620 return fopen("./thin_resource_server.dat", mode);
623 int main(int argc, char *argv[])
626 std::string accessToken;
628 std::string authProvider;
629 std::string authCode;
631 OCMode stackMode = OC_CLIENT_SERVER;
636 std::cout << "Put auth provider name(ex: github)" << std::endl;
637 std::cin >> authProvider;
638 std::cout << "Put auth code(provided by auth provider)" << std::endl;
639 std::cin >> authCode;
644 accessToken = argv[3];
654 std::cout << "Host " << g_host.c_str() << std::endl;
656 OCPersistentStorage ps{ client_open, fread, fwrite, fclose, unlink };
657 if (OCRegisterPersistentStorageHandler(&ps) != OC_STACK_OK)
659 std::cout << "OCStack init persistent storage error" << std::endl;
663 if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
665 std::cout << "OCStack init error" << std::endl;
669 OCStackResult res = OC_STACK_ERROR;
674 std::cout << "Sign-Up to cloud using " << authProvider << " " << authCode << std::endl;
675 res = OCCloudSignup(g_host.c_str(), OCGetServerInstanceIDString(), authProvider.c_str(),
676 authCode.c_str(), handleRegisterCB);
677 std::cout << "OCCloudSignup return " << res << std::endl;
681 std::cout << "Sign-In to cloud using " << accessToken << std::endl;
682 res = OCCloudLogin(g_host.c_str(), uId.c_str(), OCGetServerInstanceIDString(), accessToken.c_str(),
684 std::cout << "OCCloudLogin return " << res << std::endl;
694 std::cout << "Waiting response.." << std::endl;
698 if (OCProcess() != OC_STACK_OK)
700 std::cout << "OCProcess process error" << std::endl;
706 if (OCStop() != OC_STACK_OK)
708 std::cout << "OCStop process error" << std::endl;