Deprecate OCSetDeviceInfo and registerDeviceInfo
[platform/upstream/iotivity.git] / resource / examples / simpleserver.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
24 ///
25 #include "iotivity_config.h"
26
27 #include <functional>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_PTHREAD_H
32 #include <pthread.h>
33 #endif
34 #include <mutex>
35 #include <condition_variable>
36
37 #include "OCPlatform.h"
38 #include "OCApi.h"
39 #ifdef HAVE_WINDOWS_H
40 #include <windows.h>
41 #endif
42
43 #include "ocpayload.h"
44
45 using namespace OC;
46 using namespace std;
47 namespace PH = std::placeholders;
48
49 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_server.dat";
50 int gObservation = 0;
51 void * ChangeLightRepresentation (void *param);
52 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
53
54 // Set of strings for each of platform Info fields
55 std::string  platformId = "0A3E0D6F-DBF5-404E-8719-D6880042463A";
56 std::string  manufacturerName = "OCF";
57 std::string  manufacturerLink = "https://www.iotivity.org";
58 std::string  modelNumber = "myModelNumber";
59 std::string  dateOfManufacture = "2016-01-15";
60 std::string  platformVersion = "myPlatformVersion";
61 std::string  operatingSystemVersion = "myOS";
62 std::string  hardwareVersion = "myHardwareVersion";
63 std::string  firmwareVersion = "1.0";
64 std::string  supportLink = "https://www.iotivity.org";
65 std::string  systemTime = "2016-01-15T11.01";
66
67 // Set of strings for each of device info fields
68 std::string  deviceName = "IoTivity Simple Server";
69 std::string  deviceType = "oic.wk.tv";
70 std::string  specVersion = "core.1.1.0";
71 std::vector<std::string> dataModelVersions = {"res.1.1.0", "sh.1.1.0"};
72
73 // OCPlatformInfo Contains all the platform info to be stored
74 OCPlatformInfo platformInfo;
75
76 // Specifies where to notify all observers or list of observers
77 // false: notifies all observers
78 // true: notifies list of observers
79 bool isListOfObservers = false;
80
81 // Specifies secure or non-secure
82 // false: non-secure resource
83 // true: secure resource
84 bool isSecure = false;
85
86 /// Specifies whether Entity handler is going to do slow response or not
87 bool isSlowResponse = false;
88
89 // Forward declaring the entityHandler
90
91 /// This class represents a single resource named 'lightResource'. This resource has
92 /// two simple properties named 'state' and 'power'
93
94 class LightResource
95 {
96
97 public:
98     /// Access this property from a TB client
99     std::string m_name;
100     bool m_state;
101     int m_power;
102     std::string m_lightUri;
103     OCResourceHandle m_resourceHandle;
104     OCRepresentation m_lightRep;
105     ObservationIds m_interestedObservers;
106
107 public:
108     /// Constructor
109     LightResource()
110         :m_name("John's light"), m_state(false), m_power(0), m_lightUri("/a/light"),
111                 m_resourceHandle(nullptr) {
112         // Initialize representation
113         m_lightRep.setUri(m_lightUri);
114
115         m_lightRep.setValue("state", m_state);
116         m_lightRep.setValue("power", m_power);
117         m_lightRep.setValue("name", m_name);
118     }
119
120     /* Note that this does not need to be a member function: for classes you do not have
121     access to, you can accomplish this with a free function: */
122
123     /// This function internally calls registerResource API.
124     void createResource()
125     {
126         //URI of the resource
127         std::string resourceURI = m_lightUri;
128         //resource type name. In this case, it is light
129         std::string resourceTypeName = "core.light";
130         // resource interface.
131         std::string resourceInterface = DEFAULT_INTERFACE;
132
133         // OCResourceProperty is defined ocstack.h
134         uint8_t resourceProperty;
135         if(isSecure)
136         {
137             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
138         }
139         else
140         {
141             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
142         }
143         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
144
145         // This will internally create and register the resource.
146         OCStackResult result = OCPlatform::registerResource(
147                                     m_resourceHandle, resourceURI, resourceTypeName,
148                                     resourceInterface, cb, resourceProperty);
149
150         if (OC_STACK_OK != result)
151         {
152             cout << "Resource creation was unsuccessful\n";
153         }
154     }
155
156     OCStackResult createResource1()
157     {
158         // URI of the resource
159         std::string resourceURI = "/a/light1";
160         // resource type name. In this case, it is light
161         std::string resourceTypeName = "core.light";
162         // resource interface.
163         std::string resourceInterface = DEFAULT_INTERFACE;
164
165         // OCResourceProperty is defined ocstack.h
166         uint8_t resourceProperty;
167         if(isSecure)
168         {
169             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
170         }
171         else
172         {
173             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
174         }
175         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
176
177         OCResourceHandle resHandle;
178
179         // This will internally create and register the resource.
180         OCStackResult result = OCPlatform::registerResource(
181                                     resHandle, resourceURI, resourceTypeName,
182                                     resourceInterface, cb, resourceProperty);
183
184         if (OC_STACK_OK != result)
185         {
186             cout << "Resource creation was unsuccessful\n";
187         }
188
189         return result;
190     }
191
192     OCResourceHandle getHandle()
193     {
194         return m_resourceHandle;
195     }
196
197     // Puts representation.
198     // Gets values from the representation and
199     // updates the internal state
200     void put(OCRepresentation& rep)
201     {
202         try {
203             if (rep.getValue("state", m_state))
204             {
205                 cout << "\t\t\t\t" << "state: " << m_state << endl;
206             }
207             else
208             {
209                 cout << "\t\t\t\t" << "state not found in the representation" << endl;
210             }
211
212             if (rep.getValue("power", m_power))
213             {
214                 cout << "\t\t\t\t" << "power: " << m_power << endl;
215             }
216             else
217             {
218                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
219             }
220         }
221         catch (exception& e)
222         {
223             cout << e.what() << endl;
224         }
225
226     }
227
228     // Post representation.
229     // Post can create new resource or simply act like put.
230     // Gets values from the representation and
231     // updates the internal state
232     OCRepresentation post(OCRepresentation& rep)
233     {
234         static int first = 1;
235
236         // for the first time it tries to create a resource
237         if(first)
238         {
239             first = 0;
240
241             if(OC_STACK_OK == createResource1())
242             {
243                 OCRepresentation rep1;
244                 rep1.setValue("createduri", std::string("/a/light1"));
245
246                 return rep1;
247             }
248         }
249
250         // from second time onwards it just puts
251         put(rep);
252         return get();
253     }
254
255
256     // gets the updated representation.
257     // Updates the representation with latest internal state before
258     // sending out.
259     OCRepresentation get()
260     {
261         m_lightRep.setValue("state", m_state);
262         m_lightRep.setValue("power", m_power);
263
264         return m_lightRep;
265     }
266
267     void addType(const std::string& type) const
268     {
269         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
270         if (OC_STACK_OK != result)
271         {
272             cout << "Binding TypeName to Resource was unsuccessful\n";
273         }
274     }
275
276     void addInterface(const std::string& iface) const
277     {
278         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, iface);
279         if (OC_STACK_OK != result)
280         {
281             cout << "Binding TypeName to Resource was unsuccessful\n";
282         }
283     }
284
285 private:
286 // This is just a sample implementation of entity handler.
287 // Entity handler can be implemented in several ways by the manufacturer
288 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
289 {
290     cout << "\tIn Server CPP entity handler:\n";
291     OCEntityHandlerResult ehResult = OC_EH_ERROR;
292     if(request)
293     {
294         // Get the request type and request flag
295         std::string requestType = request->getRequestType();
296         int requestFlag = request->getRequestHandlerFlag();
297
298         if(requestFlag & RequestHandlerFlag::RequestFlag)
299         {
300             cout << "\t\trequestFlag : Request\n";
301             auto pResponse = std::make_shared<OC::OCResourceResponse>();
302             pResponse->setRequestHandle(request->getRequestHandle());
303             pResponse->setResourceHandle(request->getResourceHandle());
304
305             // Check for query params (if any)
306             QueryParamsMap queries = request->getQueryParameters();
307
308             if (!queries.empty())
309             {
310                 std::cout << "\nQuery processing upto entityHandler" << std::endl;
311             }
312             for (auto it : queries)
313             {
314                 std::cout << "Query key: " << it.first << " value : " << it.second
315                         << std:: endl;
316             }
317
318             // If the request type is GET
319             if(requestType == "GET")
320             {
321                 cout << "\t\t\trequestType : GET\n";
322                 if(isSlowResponse) // Slow response case
323                 {
324                     static int startedThread = 0;
325                     if(!startedThread)
326                     {
327                         std::thread t(handleSlowResponse, (void *)this, request);
328                         startedThread = 1;
329                         t.detach();
330                     }
331                     ehResult = OC_EH_SLOW;
332                 }
333                 else // normal response case.
334                 {
335
336                     pResponse->setResponseResult(OC_EH_OK);
337                     pResponse->setResourceRepresentation(get());
338                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
339                     {
340                         ehResult = OC_EH_OK;
341                     }
342                 }
343             }
344             else if(requestType == "PUT")
345             {
346                 cout << "\t\t\trequestType : PUT\n";
347                 OCRepresentation rep = request->getResourceRepresentation();
348
349                 // Do related operations related to PUT request
350                 // Update the lightResource
351                 put(rep);
352
353                 pResponse->setResponseResult(OC_EH_OK);
354                 pResponse->setResourceRepresentation(get());
355                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
356                 {
357                     ehResult = OC_EH_OK;
358                 }
359             }
360             else if(requestType == "POST")
361             {
362                 cout << "\t\t\trequestType : POST\n";
363
364                 OCRepresentation rep = request->getResourceRepresentation();
365
366                 // Do related operations related to POST request
367                 OCRepresentation rep_post = post(rep);
368                 pResponse->setResourceRepresentation(rep_post);
369
370                 if(rep_post.hasAttribute("createduri"))
371                 {
372                     pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
373                     pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
374                 }
375                 else
376                 {
377                     pResponse->setResponseResult(OC_EH_OK);
378                 }
379
380                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
381                 {
382                     ehResult = OC_EH_OK;
383                 }
384             }
385             else if(requestType == "DELETE")
386             {
387                 cout << "Delete request received" << endl;
388             }
389         }
390
391         if(requestFlag & RequestHandlerFlag::ObserverFlag)
392         {
393             ObservationInfo observationInfo = request->getObservationInfo();
394             if(ObserveAction::ObserveRegister == observationInfo.action)
395             {
396                 m_interestedObservers.push_back(observationInfo.obsId);
397             }
398             else if(ObserveAction::ObserveUnregister == observationInfo.action)
399             {
400                 m_interestedObservers.erase(std::remove(
401                                                             m_interestedObservers.begin(),
402                                                             m_interestedObservers.end(),
403                                                             observationInfo.obsId),
404                                                             m_interestedObservers.end());
405             }
406
407 #if defined(_WIN32)
408             DWORD threadId = 0;
409             HANDLE threadHandle = INVALID_HANDLE_VALUE;
410 #else
411             pthread_t threadId;
412 #endif
413
414             cout << "\t\trequestFlag : Observer\n";
415             gObservation = 1;
416             static int startedThread = 0;
417
418             // Observation happens on a different thread in ChangeLightRepresentation function.
419             // If we have not created the thread already, we will create one here.
420             if(!startedThread)
421             {
422 #if defined(_WIN32)
423                 threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ChangeLightRepresentation, (void*)this, 0, &threadId);
424 #else
425                 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this);
426 #endif
427                 startedThread = 1;
428             }
429             ehResult = OC_EH_OK;
430         }
431     }
432     else
433     {
434         std::cout << "Request invalid" << std::endl;
435     }
436
437     return ehResult;
438 }
439
440 };
441
442 // ChangeLightRepresentaion is an observation function,
443 // which notifies any changes to the resource to stack
444 // via notifyObservers
445 void * ChangeLightRepresentation (void *param)
446 {
447     LightResource* lightPtr = (LightResource*) param;
448
449     // This function continuously monitors for the changes
450     while (1)
451     {
452         sleep (3);
453
454         if (gObservation)
455         {
456             // If under observation if there are any changes to the light resource
457             // we call notifyObservors
458             //
459             // For demostration we are changing the power value and notifying.
460             lightPtr->m_power += 10;
461
462             cout << "\nPower updated to : " << lightPtr->m_power << endl;
463             cout << "Notifying observers with resource handle: " << lightPtr->getHandle() << endl;
464
465             OCStackResult result = OC_STACK_OK;
466
467             if(isListOfObservers)
468             {
469                 std::shared_ptr<OCResourceResponse> resourceResponse =
470                             {std::make_shared<OCResourceResponse>()};
471
472                 resourceResponse->setResourceRepresentation(lightPtr->get(), DEFAULT_INTERFACE);
473
474                 result = OCPlatform::notifyListOfObservers(  lightPtr->getHandle(),
475                                                              lightPtr->m_interestedObservers,
476                                                              resourceResponse);
477             }
478             else
479             {
480                 result = OCPlatform::notifyAllObservers(lightPtr->getHandle());
481             }
482
483             if(OC_STACK_NO_OBSERVERS == result)
484             {
485                 cout << "No More observers, stopping notifications" << endl;
486                 gObservation = 0;
487             }
488         }
489     }
490
491     return NULL;
492 }
493
494 void DeletePlatformInfo()
495 {
496     delete[] platformInfo.platformID;
497     delete[] platformInfo.manufacturerName;
498     delete[] platformInfo.manufacturerUrl;
499     delete[] platformInfo.modelNumber;
500     delete[] platformInfo.dateOfManufacture;
501     delete[] platformInfo.platformVersion;
502     delete[] platformInfo.operatingSystemVersion;
503     delete[] platformInfo.hardwareVersion;
504     delete[] platformInfo.firmwareVersion;
505     delete[] platformInfo.supportUrl;
506     delete[] platformInfo.systemTime;
507 }
508
509 void DuplicateString(char ** targetString, std::string sourceString)
510 {
511     *targetString = new char[sourceString.length() + 1];
512     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
513 }
514
515 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
516         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
517         std::string platformVersion, std::string operatingSystemVersion,
518         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
519         std::string systemTime)
520 {
521     DuplicateString(&platformInfo.platformID, platformID);
522     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
523     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
524     DuplicateString(&platformInfo.modelNumber, modelNumber);
525     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
526     DuplicateString(&platformInfo.platformVersion, platformVersion);
527     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
528     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
529     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
530     DuplicateString(&platformInfo.supportUrl, supportUrl);
531     DuplicateString(&platformInfo.systemTime, systemTime);
532
533     return OC_STACK_OK;
534 }
535
536 OCStackResult SetDeviceInfo()
537 {
538     OCStackResult result = OC_STACK_ERROR;
539
540     OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI);
541     if (handle == NULL)
542     {
543         cout << "Failed to find resource " << OC_RSRVD_DEVICE_URI << endl;
544         return result;
545     }
546
547     result = OCBindResourceTypeToResource(handle, deviceType.c_str());
548     if (result != OC_STACK_OK)
549     {
550         cout << "Failed to add device type" << endl;
551         return result;
552     }
553
554     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, deviceName);
555     if (result != OC_STACK_OK)
556     {
557         cout << "Failed to set device name" << endl;
558         return result;
559     }
560
561     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
562                                           dataModelVersions);
563     if (result != OC_STACK_OK)
564     {
565         cout << "Failed to set data model versions" << endl;
566         return result;
567     }
568
569     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, specVersion);
570     if (result != OC_STACK_OK)
571     {
572         cout << "Failed to set spec version" << endl;
573         return result;
574     }
575
576     return OC_STACK_OK;
577 }
578
579 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
580 {
581     // This function handles slow response case
582     LightResource* lightPtr = (LightResource*) param;
583     // Induce a case for slow response by using sleep
584     std::cout << "SLOW response" << std::endl;
585     sleep (10);
586
587     auto pResponse = std::make_shared<OC::OCResourceResponse>();
588     pResponse->setRequestHandle(pRequest->getRequestHandle());
589     pResponse->setResourceHandle(pRequest->getResourceHandle());
590     pResponse->setResourceRepresentation(lightPtr->get());
591
592     pResponse->setResponseResult(OC_EH_OK);
593
594     // Set the slow response flag back to false
595     isSlowResponse = false;
596     OCPlatform::sendResponse(pResponse);
597     return NULL;
598 }
599
600 void PrintUsage()
601 {
602     std::cout << std::endl;
603     std::cout << "Usage : simpleserver <value>\n";
604     std::cout << "    Default - Non-secure resource and notify all observers\n";
605     std::cout << "    1 - Non-secure resource and notify list of observers\n\n";
606     std::cout << "    2 - Secure resource and notify all observers\n";
607     std::cout << "    3 - Secure resource and notify list of observers\n\n";
608     std::cout << "    4 - Non-secure resource, GET slow response, notify all observers\n";
609 }
610
611 static FILE* client_open(const char* /*path*/, const char *mode)
612 {
613     return fopen(SVR_DB_FILE_NAME, mode);
614 }
615
616 int main(int argc, char* argv[])
617 {
618     PrintUsage();
619     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
620
621     if (argc == 1)
622     {
623         isListOfObservers = false;
624         isSecure = false;
625     }
626     else if (argc == 2)
627     {
628         int value = atoi(argv[1]);
629         switch (value)
630         {
631             case 1:
632                 isListOfObservers = true;
633                 isSecure = false;
634                 break;
635             case 2:
636                 isListOfObservers = false;
637                 isSecure = true;
638                 break;
639             case 3:
640                 isListOfObservers = true;
641                 isSecure = true;
642                 break;
643             case 4:
644                 isSlowResponse = true;
645                 break;
646             default:
647                 break;
648        }
649      }
650     else
651     {
652         return -1;
653     }
654
655     // Create PlatformConfig object
656     PlatformConfig cfg {
657         OC::ServiceType::InProc,
658         OC::ModeType::Server,
659         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
660         0,         // Uses randomly available port
661         OC::QualityOfService::LowQos,
662         &ps
663     };
664
665     OCPlatform::Configure(cfg);
666     std::cout << "Starting server & setting platform info\n";
667
668     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
669             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
670             hardwareVersion, firmwareVersion, supportLink, systemTime);
671
672     result = OCPlatform::registerPlatformInfo(platformInfo);
673
674     if (result != OC_STACK_OK)
675     {
676         std::cout << "Platform Registration failed\n";
677         return -1;
678     }
679
680     result = SetDeviceInfo();
681     if (result != OC_STACK_OK)
682     {
683         std::cout << "Device Registration failed\n";
684         return -1;
685     }
686
687     try
688     {
689         // Create the instance of the resource class
690         // (in this case instance of class 'LightResource').
691         LightResource myLight;
692
693         // Invoke createResource function of class light.
694         myLight.createResource();
695         std::cout << "Created resource." << std::endl;
696
697         myLight.addType(std::string("core.brightlight"));
698         myLight.addInterface(std::string(LINK_INTERFACE));
699         std::cout << "Added Interface and Type" << std::endl;
700
701         DeletePlatformInfo();
702
703         // A condition variable will free the mutex it is given, then do a non-
704         // intensive block until 'notify' is called on it.  In this case, since we
705         // don't ever call cv.notify, this should be a non-processor intensive version
706         // of while(true);
707         std::mutex blocker;
708         std::condition_variable cv;
709         std::unique_lock<std::mutex> lock(blocker);
710         std::cout <<"Waiting" << std::endl;
711         cv.wait(lock, []{return false;});
712     }
713     catch(OCException &e)
714     {
715         std::cout << "OCException in main : " << e.what() << endl;
716     }
717
718     // No explicit call to stop the platform.
719     // When OCPlatform::destructor is invoked, internally we do platform cleanup
720
721     return 0;
722 }