1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH 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 steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
25 #include "iotivity_config.h"
35 #include <condition_variable>
37 #include "OCPlatform.h"
45 namespace PH = std::placeholders;
47 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_server.dat";
49 void * ChangeLightRepresentation (void *param);
50 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
52 // Specifies where to notify all observers or list of observers
53 // false: notifies all observers
54 // true: notifies list of observers
55 bool isListOfObservers = false;
57 // Specifies secure or non-secure
58 // false: non-secure resource
59 // true: secure resource
60 bool isSecure = false;
62 /// Specifies whether Entity handler is going to do slow response or not
63 bool isSlowResponse = false;
65 // Forward declaring the entityHandler
67 /// This class represents a single resource named 'lightResource'. This resource has
68 /// two simple properties named 'state' and 'power'
74 /// Access this property from a TB client
78 std::string m_lightUri;
79 OCResourceHandle m_resourceHandle;
80 OCRepresentation m_lightRep;
81 ObservationIds m_interestedObservers;
86 :m_name("John's light"), m_state(false), m_power(0), m_lightUri("/a/light"),
87 m_resourceHandle(nullptr) {
88 // Initialize representation
89 m_lightRep.setUri(m_lightUri);
91 m_lightRep.setValue("state", m_state);
92 m_lightRep.setValue("power", m_power);
93 m_lightRep.setValue("name", m_name);
96 /* Note that this does not need to be a member function: for classes you do not have
97 access to, you can accomplish this with a free function: */
99 /// This function internally calls registerResource API.
100 void createResource()
102 //URI of the resource
103 std::string resourceURI = m_lightUri;
104 //resource type name. In this case, it is light
105 std::string resourceTypeName = "core.light";
106 // resource interface.
107 std::string resourceInterface = DEFAULT_INTERFACE;
109 // OCResourceProperty is defined ocstack.h
110 uint8_t resourceProperty;
113 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
117 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
119 EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
121 // This will internally create and register the resource.
122 OCStackResult result = OCPlatform::registerResource(
123 m_resourceHandle, resourceURI, resourceTypeName,
124 resourceInterface, cb, resourceProperty);
126 if (OC_STACK_OK != result)
128 cout << "Resource creation was unsuccessful\n";
132 OCStackResult createResource1()
134 // URI of the resource
135 std::string resourceURI = "/a/light1";
136 // resource type name. In this case, it is light
137 std::string resourceTypeName = "core.light";
138 // resource interface.
139 std::string resourceInterface = DEFAULT_INTERFACE;
141 // OCResourceProperty is defined ocstack.h
142 uint8_t resourceProperty;
145 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
149 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
151 EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
153 OCResourceHandle resHandle;
155 // This will internally create and register the resource.
156 OCStackResult result = OCPlatform::registerResource(
157 resHandle, resourceURI, resourceTypeName,
158 resourceInterface, cb, resourceProperty);
160 if (OC_STACK_OK != result)
162 cout << "Resource creation was unsuccessful\n";
168 OCResourceHandle getHandle()
170 return m_resourceHandle;
173 // Puts representation.
174 // Gets values from the representation and
175 // updates the internal state
176 void put(OCRepresentation& rep)
179 if (rep.getValue("state", m_state))
181 cout << "\t\t\t\t" << "state: " << m_state << endl;
185 cout << "\t\t\t\t" << "state not found in the representation" << endl;
188 if (rep.getValue("power", m_power))
190 cout << "\t\t\t\t" << "power: " << m_power << endl;
194 cout << "\t\t\t\t" << "power not found in the representation" << endl;
199 cout << e.what() << endl;
204 // Post representation.
205 // Post can create new resource or simply act like put.
206 // Gets values from the representation and
207 // updates the internal state
208 OCRepresentation post(OCRepresentation& rep)
210 static int first = 1;
212 // for the first time it tries to create a resource
217 if(OC_STACK_OK == createResource1())
219 OCRepresentation rep1;
220 rep1.setValue("createduri", std::string("/a/light1"));
226 // from second time onwards it just puts
232 // gets the updated representation.
233 // Updates the representation with latest internal state before
235 OCRepresentation get()
237 m_lightRep.setValue("state", m_state);
238 m_lightRep.setValue("power", m_power);
243 void addType(const std::string& type) const
245 OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
246 if (OC_STACK_OK != result)
248 cout << "Binding TypeName to Resource was unsuccessful\n";
252 void addInterface(const std::string& iface) const
254 OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, iface);
255 if (OC_STACK_OK != result)
257 cout << "Binding TypeName to Resource was unsuccessful\n";
262 // This is just a sample implementation of entity handler.
263 // Entity handler can be implemented in several ways by the manufacturer
264 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
266 cout << "\tIn Server CPP entity handler:\n";
267 OCEntityHandlerResult ehResult = OC_EH_ERROR;
270 // Get the request type and request flag
271 std::string requestType = request->getRequestType();
272 int requestFlag = request->getRequestHandlerFlag();
274 if(requestFlag & RequestHandlerFlag::RequestFlag)
276 cout << "\t\trequestFlag : Request\n";
277 auto pResponse = std::make_shared<OC::OCResourceResponse>();
278 pResponse->setRequestHandle(request->getRequestHandle());
279 pResponse->setResourceHandle(request->getResourceHandle());
281 // Check for query params (if any)
282 QueryParamsMap queries = request->getQueryParameters();
284 if (!queries.empty())
286 std::cout << "\nQuery processing upto entityHandler" << std::endl;
288 for (auto it : queries)
290 std::cout << "Query key: " << it.first << " value : " << it.second
294 // If the request type is GET
295 if(requestType == "GET")
297 cout << "\t\t\trequestType : GET\n";
298 if(isSlowResponse) // Slow response case
300 static int startedThread = 0;
303 std::thread t(handleSlowResponse, (void *)this, request);
307 ehResult = OC_EH_SLOW;
309 else // normal response case.
311 pResponse->setErrorCode(200);
312 pResponse->setResponseResult(OC_EH_OK);
313 pResponse->setResourceRepresentation(get());
314 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
320 else if(requestType == "PUT")
322 cout << "\t\t\trequestType : PUT\n";
323 OCRepresentation rep = request->getResourceRepresentation();
325 // Do related operations related to PUT request
326 // Update the lightResource
328 pResponse->setErrorCode(200);
329 pResponse->setResponseResult(OC_EH_OK);
330 pResponse->setResourceRepresentation(get());
331 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
336 else if(requestType == "POST")
338 cout << "\t\t\trequestType : POST\n";
340 OCRepresentation rep = request->getResourceRepresentation();
342 // Do related operations related to POST request
343 OCRepresentation rep_post = post(rep);
344 pResponse->setResourceRepresentation(rep_post);
345 pResponse->setErrorCode(200);
346 if(rep_post.hasAttribute("createduri"))
348 pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
349 pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
353 pResponse->setResponseResult(OC_EH_OK);
356 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
361 else if(requestType == "DELETE")
363 cout << "Delete request received" << endl;
367 if(requestFlag & RequestHandlerFlag::ObserverFlag)
369 ObservationInfo observationInfo = request->getObservationInfo();
370 if(ObserveAction::ObserveRegister == observationInfo.action)
372 m_interestedObservers.push_back(observationInfo.obsId);
374 else if(ObserveAction::ObserveUnregister == observationInfo.action)
376 m_interestedObservers.erase(std::remove(
377 m_interestedObservers.begin(),
378 m_interestedObservers.end(),
379 observationInfo.obsId),
380 m_interestedObservers.end());
385 HANDLE threadHandle = INVALID_HANDLE_VALUE;
390 cout << "\t\trequestFlag : Observer\n";
392 static int startedThread = 0;
394 // Observation happens on a different thread in ChangeLightRepresentation function.
395 // If we have not created the thread already, we will create one here.
399 threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ChangeLightRepresentation, (void*)this, 0, &threadId);
401 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this);
410 std::cout << "Request invalid" << std::endl;
418 // ChangeLightRepresentaion is an observation function,
419 // which notifies any changes to the resource to stack
420 // via notifyObservers
421 void * ChangeLightRepresentation (void *param)
423 LightResource* lightPtr = (LightResource*) param;
425 // This function continuously monitors for the changes
432 // If under observation if there are any changes to the light resource
433 // we call notifyObservors
435 // For demostration we are changing the power value and notifying.
436 lightPtr->m_power += 10;
438 cout << "\nPower updated to : " << lightPtr->m_power << endl;
439 cout << "Notifying observers with resource handle: " << lightPtr->getHandle() << endl;
441 OCStackResult result = OC_STACK_OK;
443 if(isListOfObservers)
445 std::shared_ptr<OCResourceResponse> resourceResponse =
446 {std::make_shared<OCResourceResponse>()};
448 resourceResponse->setErrorCode(200);
449 resourceResponse->setResourceRepresentation(lightPtr->get(), DEFAULT_INTERFACE);
451 result = OCPlatform::notifyListOfObservers( lightPtr->getHandle(),
452 lightPtr->m_interestedObservers,
457 result = OCPlatform::notifyAllObservers(lightPtr->getHandle());
460 if(OC_STACK_NO_OBSERVERS == result)
462 cout << "No More observers, stopping notifications" << endl;
471 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
473 // This function handles slow response case
474 LightResource* lightPtr = (LightResource*) param;
475 // Induce a case for slow response by using sleep
476 std::cout << "SLOW response" << std::endl;
479 auto pResponse = std::make_shared<OC::OCResourceResponse>();
480 pResponse->setRequestHandle(pRequest->getRequestHandle());
481 pResponse->setResourceHandle(pRequest->getResourceHandle());
482 pResponse->setResourceRepresentation(lightPtr->get());
483 pResponse->setErrorCode(200);
484 pResponse->setResponseResult(OC_EH_OK);
486 // Set the slow response flag back to false
487 isSlowResponse = false;
488 OCPlatform::sendResponse(pResponse);
494 std::cout << std::endl;
495 std::cout << "Usage : simpleserver <value>\n";
496 std::cout << " Default - Non-secure resource and notify all observers\n";
497 std::cout << " 1 - Non-secure resource and notify list of observers\n\n";
498 std::cout << " 2 - Secure resource and notify all observers\n";
499 std::cout << " 3 - Secure resource and notify list of observers\n\n";
500 std::cout << " 4 - Non-secure resource, GET slow response, notify all observers\n";
503 static FILE* client_open(const char* /*path*/, const char *mode)
505 return fopen(SVR_DB_FILE_NAME, mode);
508 int main(int argc, char* argv[])
511 OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
515 isListOfObservers = false;
520 int value = atoi(argv[1]);
524 isListOfObservers = true;
528 isListOfObservers = false;
532 isListOfObservers = true;
536 isSlowResponse = true;
547 // Create PlatformConfig object
549 OC::ServiceType::InProc,
550 OC::ModeType::Server,
551 "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
552 0, // Uses randomly available port
553 OC::QualityOfService::LowQos,
557 OCPlatform::Configure(cfg);
560 // Create the instance of the resource class
561 // (in this case instance of class 'LightResource').
562 LightResource myLight;
564 // Invoke createResource function of class light.
565 myLight.createResource();
566 std::cout << "Created resource." << std::endl;
568 myLight.addType(std::string("core.brightlight"));
569 myLight.addInterface(std::string(LINK_INTERFACE));
570 std::cout << "Added Interface and Type" << std::endl;
573 // A condition variable will free the mutex it is given, then do a non-
574 // intensive block until 'notify' is called on it. In this case, since we
575 // don't ever call cv.notify, this should be a non-processor intensive version
578 std::condition_variable cv;
579 std::unique_lock<std::mutex> lock(blocker);
580 std::cout <<"Waiting" << std::endl;
581 cv.wait(lock, []{return false;});
583 catch(OCException &e)
585 std::cout << "OCException in main : " << e.what() << endl;
588 // No explicit call to stop the platform.
589 // When OCPlatform::destructor is invoked, internally we do platform cleanup