Add logic for sending responses according to the interface of requests.
[platform/upstream/iotivity.git] / service / notification / src / provider / NSProviderTopic.c
1 //******************************************************************\r
2 //\r
3 // Copyright 2016 Samsung Electronics All Rights Reserved.\r
4 //\r
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
6 //\r
7 // Licensed under the Apache License, Version 2.0 (the "License");\r
8 // you may not use this file except in compliance with the License.\r
9 // You may obtain a copy of the License at\r
10 //\r
11 //      http://www.apache.org/licenses/LICENSE-2.0\r
12 //\r
13 // Unless required by applicable law or agreed to in writing, software\r
14 // distributed under the License is distributed on an "AS IS" BASIS,\r
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16 // See the License for the specific language governing permissions and\r
17 // limitations under the License.\r
18 //\r
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
20 \r
21 #include "NSProviderTopic.h"\r
22 #include "oic_string.h"\r
23 #include "oic_malloc.h"\r
24 #include <pthread.h>\r
25 \r
26 NSResult NSSendTopicUpdation();\r
27 \r
28 NSResult NSInitTopicList()\r
29 {\r
30     NS_LOG(DEBUG, "NSInitTopicList - IN");\r
31 \r
32     consumerTopicList = NSProviderStorageCreate();\r
33     NS_VERIFY_NOT_NULL(consumerTopicList, NS_FAIL);\r
34     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_NAME;\r
35 \r
36     registeredTopicList = NSProviderStorageCreate();\r
37     NS_VERIFY_NOT_NULL(registeredTopicList, NS_FAIL);\r
38     registeredTopicList->cacheType = NS_PROVIDER_CACHE_REGISTER_TOPIC;\r
39 \r
40     NS_LOG(DEBUG, "NSInitTopicList - OUT");\r
41     return NS_OK;\r
42 }\r
43 \r
44 size_t NSProviderGetTopicListSize(NSTopicLL * firstElement)\r
45 {\r
46     if (!firstElement)\r
47     {\r
48         return 0;\r
49     }\r
50 \r
51     int cnt = 0;\r
52 \r
53     NSTopicLL * iter = firstElement;\r
54 \r
55     while (iter)\r
56     {\r
57         cnt++;\r
58         iter = iter->next;\r
59     }\r
60 \r
61     return cnt;\r
62 }\r
63 \r
64 NSResult NSRegisterTopic(const char * topicName)\r
65 {\r
66     NS_LOG(DEBUG, "NSWriteTopicsToStorage()");\r
67 \r
68     NSCacheTopicData * data = (NSCacheTopicData *) OICMalloc(sizeof(NSCacheTopicData));\r
69     NS_VERIFY_NOT_NULL(data, NS_FAIL);\r
70     data->topicName = (char *) topicName;\r
71     data->state = NS_TOPIC_UNSUBSCRIBED;\r
72 \r
73     NSCacheElement * element = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
74     if (!element)\r
75     {\r
76         OICFree(data->topicName);\r
77         OICFree(data);\r
78         return NS_FAIL;\r
79     }\r
80     element->data = (void *) data;\r
81     element->next = NULL;\r
82 \r
83     if(NSProviderStorageWrite(registeredTopicList, element) != NS_OK)\r
84     {\r
85         NS_LOG(DEBUG, "fail to write cache");\r
86         return NS_FAIL;\r
87     }\r
88     NSSendTopicUpdation();\r
89 \r
90     NS_LOG(DEBUG, "NSWriteTopicsToStorage() NS_OK");\r
91     return NS_OK;\r
92 }\r
93 \r
94 NSResult NSUnregisterTopic(const char * topicName)\r
95 {\r
96     NS_LOG(DEBUG, "NSDeleteTopics()");\r
97     NSResult result = NS_OK;\r
98 \r
99     if (!topicName)\r
100     {\r
101         NS_LOG(ERROR, "topicName is NULL");\r
102         return NS_ERROR;\r
103     }\r
104 \r
105     result = NSProviderStorageDelete(registeredTopicList, topicName);\r
106     while (NSProviderStorageDelete(consumerTopicList, topicName) != NS_FAIL)\r
107     {\r
108     }\r
109 \r
110     if (result == NS_OK)\r
111     {\r
112         NSSendTopicUpdation();\r
113     }\r
114 \r
115     return result;\r
116 }\r
117 \r
118 NSResult NSSendTopicUpdation()\r
119 {\r
120     NS_LOG(DEBUG, "NSSendTopicUpdation - IN");\r
121 \r
122     OCRepPayload* payload = OCRepPayloadCreate();\r
123 \r
124     if (!payload)\r
125     {\r
126         NS_LOG(ERROR, "fail to create playload");\r
127         return NS_ERROR;\r
128     }\r
129 \r
130     OCResourceHandle rHandle = NULL;\r
131     if (NSPutMessageResource(NULL, &rHandle) != NS_OK)\r
132     {\r
133         NS_LOG(ERROR, "Fail to put message resource");\r
134         return NS_ERROR;\r
135     }\r
136 \r
137     OCRepPayloadSetUri(payload, NS_COLLECTION_MESSAGE_URI);\r
138     OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_TOPIC);\r
139     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
140 \r
141     OCObservationId obArray[255] =\r
142     { 0, };\r
143     int obCount = 0;\r
144 \r
145     NSCacheElement * it = consumerSubList->head;\r
146 \r
147     while (it)\r
148     {\r
149         NSCacheSubData * subData = (NSCacheSubData *) it->data;\r
150 \r
151         if (subData->isWhite)\r
152         {\r
153             if (subData->messageObId != 0)\r
154             {\r
155                 obArray[obCount++] = subData->messageObId;\r
156             }\r
157 \r
158 #if(defined WITH_CLOUD && defined RD_CLIENT)\r
159             if(subData->remote_messageObId != 0)\r
160             {\r
161                 obArray[obCount++] = subData->remote_messageObId;\r
162             }\r
163 #endif\r
164         }\r
165         it = it->next;\r
166     }\r
167 \r
168     if (!obCount)\r
169     {\r
170         NS_LOG(ERROR, "observer count is zero");\r
171         return NS_ERROR;\r
172     }\r
173 \r
174     if (OCNotifyListOfObservers(rHandle, obArray, obCount, payload, OC_HIGH_QOS) != OC_STACK_OK)\r
175     {\r
176         NS_LOG(ERROR, "fail to send topic updation");\r
177         OCRepPayloadDestroy(payload);\r
178         return NS_ERROR;\r
179 \r
180     }\r
181     OCRepPayloadDestroy(payload);\r
182 \r
183     NS_LOG(DEBUG, "NSSendTopicUpdation - OUT");\r
184     return NS_OK;\r
185 }\r
186 \r
187 NSResult NSSendTopicUpdationToConsumer(char *consumerId)\r
188 {\r
189     NS_LOG(DEBUG, "NSSendTopicUpdationToConsumer - IN");\r
190 \r
191     OCRepPayload* payload = OCRepPayloadCreate();\r
192 \r
193     if (!payload)\r
194     {\r
195         NS_LOG(ERROR, "fail to create playload");\r
196         return NS_ERROR;\r
197     }\r
198 \r
199     OCResourceHandle rHandle = NULL;\r
200     if (NSPutMessageResource(NULL, &rHandle) != NS_OK)\r
201     {\r
202         NS_LOG(ERROR, "Fail to put message resource");\r
203         return NS_ERROR;\r
204     }\r
205 \r
206     OCRepPayloadSetUri(payload, NS_COLLECTION_MESSAGE_URI);\r
207     OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_TOPIC);\r
208     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
209 \r
210     NSCacheElement * element = NSProviderStorageRead(consumerSubList, consumerId);\r
211 \r
212     if (element == NULL)\r
213     {\r
214         NS_LOG(ERROR, "element is NULL");\r
215         return NS_ERROR;\r
216     }\r
217 \r
218     NSCacheSubData * subData = (NSCacheSubData*) element->data;\r
219 \r
220     if (OCNotifyListOfObservers(rHandle, (OCObservationId*) &subData->messageObId, 1, payload,\r
221             OC_HIGH_QOS) != OC_STACK_OK)\r
222     {\r
223         NS_LOG(ERROR, "fail to send topic updation");\r
224         OCRepPayloadDestroy(payload);\r
225         return NS_ERROR;\r
226     }\r
227 \r
228     OCRepPayloadDestroy(payload);\r
229 \r
230     NS_LOG(DEBUG, "NSSendTopicUpdationToConsumer - OUT");\r
231     return NS_OK;\r
232 }\r
233 \r
234 NSResult NSSendTopicList(OCEntityHandlerRequest * entityHandlerRequest)\r
235 {\r
236     NS_LOG(DEBUG, "NSSendTopicList - IN");\r
237 \r
238     char * id = NSGetValueFromQuery(OICStrdup(entityHandlerRequest->query), NS_QUERY_CONSUMER_ID);\r
239     NSTopicLL * topics = NULL;\r
240 \r
241     if (!id)\r
242     {\r
243         NS_LOG(DEBUG, "Send registered topic list");\r
244         topics = NSProviderGetTopicsCacheData(registeredTopicList);\r
245     }\r
246     else\r
247     {\r
248         NS_LOG(DEBUG, "Send subscribed topic list to consumer");\r
249         topics = NSProviderGetConsumerTopicsCacheData(registeredTopicList, consumerTopicList, id);\r
250         if (!topics)\r
251         {\r
252             topics = NSProviderGetTopicsCacheData(registeredTopicList);\r
253         }\r
254     }\r
255 \r
256     // make response for the Get Request\r
257     OCEntityHandlerResponse response;\r
258     response.numSendVendorSpecificHeaderOptions = 0;\r
259     memset(response.sendVendorSpecificHeaderOptions, 0,\r
260             sizeof response.sendVendorSpecificHeaderOptions);\r
261     memset(response.resourceUri, 0, sizeof response.resourceUri);\r
262 \r
263     OCRepPayload* payload = OCRepPayloadCreate();\r
264     if (!payload)\r
265     {\r
266         NS_LOG(ERROR, "payload is NULL");\r
267         return NS_ERROR;\r
268     }\r
269 \r
270     OCRepPayloadSetUri(payload, NS_COLLECTION_TOPIC_URI);\r
271     if (id)\r
272     {\r
273         OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_CONSUMER_ID, id);\r
274     }\r
275     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
276 \r
277     if (topics)\r
278     {\r
279         NS_LOG(DEBUG, "topicList is NULL");\r
280         size_t dimensionSize = (size_t) NSProviderGetTopicListSize(topics);\r
281 \r
282         NS_LOG_V(DEBUG, "dimensionSize = %d", (int)dimensionSize);\r
283 \r
284         if (!dimensionSize)\r
285         {\r
286             return NS_ERROR;\r
287         }\r
288 \r
289         OCRepPayload** payloadTopicArray = (OCRepPayload **) OICMalloc(\r
290                 sizeof(OCRepPayload *) * dimensionSize);\r
291 \r
292         size_t dimensions[3] =\r
293         { dimensionSize, 0, 0 };\r
294 \r
295         for (int i = 0; i < (int) dimensionSize; i++)\r
296         {\r
297             NS_LOG_V(DEBUG, "topicName = %s", topics->topicName);\r
298             NS_LOG_V(DEBUG, "topicState = %d",(int) topics->state);\r
299 \r
300             payloadTopicArray[i] = OCRepPayloadCreate();\r
301             NS_VERIFY_NOT_NULL(payloadTopicArray[i], NS_ERROR);\r
302             OCRepPayloadSetPropString(payloadTopicArray[i], NS_ATTRIBUTE_TOPIC_NAME,\r
303                     topics->topicName);\r
304             OCRepPayloadSetPropInt(payloadTopicArray[i], NS_ATTRIBUTE_TOPIC_SELECTION,\r
305                     (int) topics->state);\r
306 \r
307             topics = topics->next;\r
308         }\r
309 \r
310         OCRepPayloadSetPropObjectArray(payload, NS_ATTRIBUTE_TOPIC_LIST,\r
311                 (const OCRepPayload**) (payloadTopicArray), dimensions);\r
312     }\r
313     else\r
314     {\r
315         size_t dimensions[3] =\r
316         { 0, 0, 0 };\r
317 \r
318         OCRepPayloadSetPropObjectArrayAsOwner(payload, NS_ATTRIBUTE_TOPIC_LIST,\r
319                 (OCRepPayload **) NULL, dimensions);\r
320     }\r
321 \r
322     char * reqInterface =\r
323             NSGetValueFromQuery(OICStrdup(entityHandlerRequest->query), NS_QUERY_INTERFACE);\r
324 \r
325     if (reqInterface && strcmp(reqInterface, NS_INTERFACE_BASELINE) == 0)\r
326     {\r
327         OCResourcePayloadAddStringLL(&payload->interfaces, NS_INTERFACE_BASELINE);\r
328         OCResourcePayloadAddStringLL(&payload->interfaces, NS_INTERFACE_READ);\r
329         OCResourcePayloadAddStringLL(&payload->types, NS_ROOT_TYPE);\r
330     }\r
331 \r
332     response.requestHandle = entityHandlerRequest->requestHandle;\r
333     response.resourceHandle = entityHandlerRequest->resource;\r
334     response.persistentBufferFlag = 0;\r
335     response.ehResult = OC_EH_OK;\r
336     response.payload = (OCPayload *) payload;\r
337 \r
338     if (OCDoResponse(&response) != OC_STACK_OK)\r
339     {\r
340         NS_LOG(ERROR, "Fail to response topic list");\r
341         return NS_ERROR;\r
342     }\r
343     OCRepPayloadDestroy(payload);\r
344 \r
345     NS_LOG(DEBUG, "NSSendTopicList - OUT");\r
346     return NS_OK;\r
347 }\r
348 \r
349 NSResult NSPostConsumerTopics(OCEntityHandlerRequest * entityHandlerRequest)\r
350 {\r
351     NS_LOG(DEBUG, "NSPostConsumerTopics() - IN");\r
352 \r
353     char * consumerId = NULL;\r
354     OCRepPayload * payload = (OCRepPayload *) entityHandlerRequest->payload;\r
355     OCRepPayloadGetPropString(payload, NS_ATTRIBUTE_CONSUMER_ID, &consumerId);\r
356 \r
357     if (!consumerId)\r
358     {\r
359         NS_LOG(DEBUG, "Invalid consumer ID");\r
360         return NS_FAIL;\r
361     }\r
362 \r
363     NS_LOG_V(DEBUG, "TOPIC consumer ID = %s", consumerId);\r
364 \r
365     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_CID;\r
366
367     while (NSProviderStorageDelete(consumerTopicList, consumerId) != NS_FAIL)\r
368     {\r
369     }\r
370     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_NAME;\r
371 \r
372     OCRepPayload ** topicListPayload = NULL;\r
373     OCRepPayloadValue * payloadValue = NULL;\r
374     payloadValue = NSPayloadFindValue(payload, NS_ATTRIBUTE_TOPIC_LIST);\r
375     size_t dimensionSize = calcDimTotal(payloadValue->arr.dimensions);\r
376     size_t dimensions[3] = { dimensionSize, 0, 0 };\r
377     OCRepPayloadGetPropObjectArray(payload, NS_ATTRIBUTE_TOPIC_LIST, &topicListPayload, dimensions);\r
378 \r
379     for (int i = 0; i < (int) dimensionSize; i++)\r
380     {\r
381         char * topicName = NULL;\r
382         int64_t topicState = 0;\r
383 \r
384         OCRepPayloadGetPropString(topicListPayload[i], NS_ATTRIBUTE_TOPIC_NAME, &topicName);\r
385         OCRepPayloadGetPropInt(topicListPayload[i], NS_ATTRIBUTE_TOPIC_SELECTION, &topicState);\r
386         NS_LOG_V(DEBUG, "Topic Name(state):  %s(%d)", topicName, (int)topicState);\r
387 \r
388         if (NS_TOPIC_SUBSCRIBED == (NSTopicState) topicState)\r
389         {\r
390             NSCacheTopicSubData * topicSubData = (NSCacheTopicSubData *) OICMalloc(\r
391                     sizeof(NSCacheTopicSubData));\r
392             NS_VERIFY_NOT_NULL(topicSubData, NS_FAIL);\r
393 \r
394             OICStrcpy(topicSubData->id, NS_UUID_STRING_SIZE, consumerId);\r
395             topicSubData->topicName = topicName;\r
396 \r
397             NSCacheElement * newObj = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
398 \r
399             if (!newObj)\r
400             {\r
401                 OICFree(topicSubData->topicName);\r
402                 OICFree(topicSubData);\r
403                 OICFree(consumerId);\r
404                 return NS_FAIL;\r
405             }\r
406 \r
407             newObj->data = (NSCacheData *) topicSubData;\r
408             newObj->next = NULL;\r
409 \r
410             NSProviderStorageWrite(consumerTopicList, newObj);
411         }\r
412     }\r
413     NSSendTopicUpdationToConsumer(consumerId);\r
414     OICFree(consumerId);\r
415     NS_LOG(DEBUG, "NSPostConsumerTopics() - OUT");\r
416     return NS_OK;\r
417 }\r
418 \r
419 void * NSTopicSchedule(void * ptr)\r
420 {\r
421     if (ptr == NULL)\r
422     {\r
423         NS_LOG(DEBUG, "Create NSTopicSchedule");\r
424     }\r
425 \r
426     while (NSIsRunning[TOPIC_SCHEDULER])\r
427     {\r
428         sem_wait(&NSSemaphore[TOPIC_SCHEDULER]);\r
429         pthread_mutex_lock(&NSMutex[TOPIC_SCHEDULER]);\r
430 \r
431         if (NSHeadMsg[TOPIC_SCHEDULER] != NULL)\r
432         {\r
433             NSTask *node = NSHeadMsg[TOPIC_SCHEDULER];\r
434             NSHeadMsg[TOPIC_SCHEDULER] = node->nextTask;\r
435 \r
436             switch (node->taskType)\r
437             {\r
438                 case TASK_SEND_TOPICS:\r
439                     NS_LOG(DEBUG, "CASE TASK_SEND_TOPICS : ");\r
440                     NSSendTopicList((OCEntityHandlerRequest*) node->taskData);\r
441                     NSFreeOCEntityHandlerRequest((OCEntityHandlerRequest*) node->taskData);\r
442                     break;\r
443                 case TASK_SUBSCRIBE_TOPIC:\r
444                 {\r
445                     NS_LOG(DEBUG, "CASE TASK_SUBSCRIBE_TOPIC : ");\r
446                     NSCacheElement * newObj = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
447                     if (newObj)\r
448                     {\r
449                         newObj->data = node->taskData;\r
450                         newObj->next = NULL;\r
451                         if (NSProviderStorageWrite(consumerTopicList, newObj) == NS_OK)\r
452                         {\r
453                             NSCacheTopicSubData * topicSubData =\r
454                                     (NSCacheTopicSubData *) node->taskData;\r
455                             NSSendTopicUpdationToConsumer(topicSubData->id);\r
456                         }\r
457                     }
458                 }\r
459                     break;\r
460                 case TASK_UNSUBSCRIBE_TOPIC:\r
461                 {\r
462                     NS_LOG(DEBUG, "CASE TASK_SUBSCRIBE_TOPIC : ");\r
463                     NSCacheTopicSubData * topicSubData = (NSCacheTopicSubData *) node->taskData;\r
464                     if (NSProviderDeleteConsumerTopic(consumerTopicList,\r
465                             (NSCacheTopicSubData *) node->taskData) == NS_OK)\r
466                     {\r
467                         NSSendTopicUpdationToConsumer(topicSubData->id);\r
468                     }\r
469                     OICFree(topicSubData->topicName);\r
470                     OICFree(topicSubData);\r
471                 }\r
472                     break;\r
473                 case TASK_REGISTER_TOPIC:\r
474                 {\r
475                     NS_LOG(DEBUG, "CASE TASK_ADD_TOPIC : ");\r
476                     NSTopicSyncResult * topicSyncResult = (NSTopicSyncResult *) node->taskData;\r
477 \r
478                     pthread_mutex_lock(topicSyncResult->mutex);\r
479                     topicSyncResult->result = NSRegisterTopic(\r
480                             (const char *) topicSyncResult->topicName);\r
481                     pthread_cond_signal(topicSyncResult->condition);\r
482                     pthread_mutex_unlock(topicSyncResult->mutex);\r
483                 }\r
484                     break;\r
485                 case TASK_UNREGISTER_TOPIC:\r
486                 {\r
487                     NS_LOG(DEBUG, "CASE_TASK_DELETE_TOPIC : ");\r
488                     NSTopicSyncResult * topicSyncResult = (NSTopicSyncResult *) node->taskData;\r
489                     pthread_mutex_lock(topicSyncResult->mutex);\r
490                     topicSyncResult->result = NSUnregisterTopic(\r
491                             (const char *) topicSyncResult->topicName);\r
492                     pthread_cond_signal(topicSyncResult->condition);\r
493                     pthread_mutex_unlock(topicSyncResult->mutex);\r
494                 }\r
495                     break;\r
496                 case TASK_POST_TOPIC:\r
497                 {\r
498                     NS_LOG(DEBUG, "TASK_POST_TOPIC : ");\r
499                     NSPostConsumerTopics((OCEntityHandlerRequest*) node->taskData);\r
500                     NSFreeOCEntityHandlerRequest((OCEntityHandlerRequest*) node->taskData);\r
501                 }\r
502                     break;\r
503                 case TASK_GET_TOPICS:\r
504                 {\r
505                     NS_LOG(DEBUG, "TASK_GET_TOPICS : ");\r
506                     NSTopicSync * topicSync = (NSTopicSync *) node->taskData;\r
507                     pthread_mutex_lock(topicSync->mutex);\r
508                     NSTopicLL * topics = NSProviderGetTopicsCacheData(registeredTopicList);\r
509                     topicSync->topics = topics;\r
510                     pthread_cond_signal(topicSync->condition);\r
511                     pthread_mutex_unlock(topicSync->mutex);\r
512                 }\r
513                     break;\r
514                 case TAST_GET_CONSUMER_TOPICS:\r
515                 {\r
516                     NS_LOG(DEBUG, "TASK_GET_CONSUMER_TOPICS : ");\r
517                     NSTopicSync * topicSync = (NSTopicSync *) node->taskData;\r
518                     pthread_mutex_lock(topicSync->mutex);\r
519                     NSTopicLL * topics = NSProviderGetConsumerTopicsCacheData(registeredTopicList,\r
520                             consumerTopicList, topicSync->consumerId);\r
521                     topicSync->topics = topics;\r
522                     pthread_cond_signal(topicSync->condition);\r
523                     pthread_mutex_unlock(topicSync->mutex);\r
524                 }\r
525                     break;\r
526                 default:\r
527                     break;\r
528             }\r
529 \r
530             OICFree(node);\r
531         }\r
532 \r
533         pthread_mutex_unlock(&NSMutex[TOPIC_SCHEDULER]);\r
534     }\r
535 \r
536     NS_LOG(DEBUG, "Destroy NSTopicSchedule");\r
537     return NULL;\r
538 }\r