Merge branch 'master' into notification-service
[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 \r
25 NSResult NSSendTopicUpdation();\r
26 \r
27 NSResult NSInitTopicList()\r
28 {\r
29     NS_LOG(DEBUG, "NSInitTopicList - IN");\r
30     consumerTopicList = NSStorageCreate();\r
31     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_NAME;\r
32 \r
33     registeredTopicList = NSStorageCreate();\r
34     registeredTopicList->cacheType = NS_PROVIDER_CACHE_REGISTER_TOPIC;\r
35 \r
36     NS_LOG(DEBUG, "NSInitTopicList - OUT");\r
37     return NS_OK;\r
38 }\r
39 \r
40 size_t NSProviderGetTopicListSize(NSTopicLL * firstElement)\r
41 {\r
42     if(!firstElement)\r
43     {\r
44         return 0;\r
45     }\r
46 \r
47     int cnt = 0;\r
48 \r
49     NSTopicLL * iter = firstElement;\r
50 \r
51     while(iter)\r
52     {\r
53         cnt++;\r
54         iter = iter->next;\r
55     }\r
56 \r
57     return cnt;\r
58 }\r
59 \r
60 NSResult NSAddTopics(const char * topicName)\r
61 {\r
62     NS_LOG(DEBUG, "NSWriteTopicsToStorage()");\r
63 \r
64     NSCacheTopicData * data = (NSCacheTopicData *)OICMalloc(sizeof(NSCacheTopicData));\r
65     data->topicName = (char *)topicName;\r
66     data->state = NS_TOPIC_UNSUBSCRIBED;\r
67 \r
68     NSCacheElement * element = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
69     element->data = (void *) data;\r
70     element->next = NULL;\r
71 \r
72     if(NSStorageWrite(registeredTopicList, element) != NS_OK)\r
73     {\r
74         NS_LOG(DEBUG, "fail to write cache");\r
75     }\r
76     NSSendTopicUpdation();\r
77 \r
78     NS_LOG(DEBUG, "NSWriteTopicsToStorage() NS_OK");\r
79     return NS_OK;\r
80 }\r
81 \r
82 NSResult NSDeleteTopics(const char * topicName)\r
83 {\r
84     NS_LOG(DEBUG, "NSDeleteTopics()");\r
85 \r
86     if(!topicName)\r
87     {\r
88         NS_LOG(ERROR, "topicName is NULL");\r
89         return NS_ERROR;\r
90     }\r
91 \r
92     NSStorageDelete(registeredTopicList, topicName);\r
93     while(NSStorageDelete(consumerTopicList, topicName) != NS_FAIL);\r
94     return NS_OK;\r
95 }\r
96 \r
97 NSResult NSSendTopicUpdation()\r
98 {\r
99     NS_LOG(DEBUG, "NSSendTopicUpdation - IN");\r
100 \r
101     OCRepPayload* payload = OCRepPayloadCreate();\r
102 \r
103     if (!payload)\r
104     {\r
105         NS_LOG(ERROR, "fail to create playload");\r
106         return NS_ERROR;\r
107     }\r
108 \r
109     OCResourceHandle rHandle = NULL;\r
110     if (NSPutMessageResource(NULL, &rHandle) != NS_OK)\r
111     {\r
112         NS_LOG(ERROR, "Fail to put message resource");\r
113         return NS_ERROR;\r
114     }\r
115 \r
116     OCRepPayloadSetUri(payload, NS_COLLECTION_MESSAGE_URI);\r
117     OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_TOPIC);\r
118     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
119 \r
120     OCObservationId obArray[255] = { 0, };\r
121     int obCount = 0;\r
122 \r
123     NSCacheElement * it = consumerSubList->head;\r
124 \r
125     while (it)\r
126     {\r
127         NSCacheSubData * subData = (NSCacheSubData *) it->data;\r
128 \r
129         if (subData->isWhite)\r
130         {\r
131             if(subData->messageObId != 0)\r
132             {\r
133                 obArray[obCount++] = subData->messageObId;\r
134             }\r
135 \r
136 #if(defined WITH_CLOUD && defined RD_CLIENT)\r
137             if(subData->remote_messageObId != 0)\r
138             {\r
139                 obArray[obCount++] = subData->remote_messageObId;\r
140             }\r
141 #endif\r
142         }\r
143         it = it->next;\r
144     }\r
145 \r
146     if(!obCount)\r
147     {\r
148         NS_LOG(ERROR, "observer count is zero");\r
149         return NS_ERROR;\r
150     }\r
151 \r
152     if (OCNotifyListOfObservers(rHandle, obArray, obCount, payload, OC_HIGH_QOS)\r
153             != OC_STACK_OK)\r
154     {\r
155         NS_LOG(ERROR, "fail to send topic updation");\r
156         OCRepPayloadDestroy(payload);\r
157         return NS_ERROR;\r
158 \r
159     }\r
160     OCRepPayloadDestroy(payload);\r
161 \r
162     NS_LOG(DEBUG, "NSSendTopicUpdation - OUT");\r
163     return NS_OK;\r
164 }\r
165 \r
166 NSResult NSSendTopicUpdationToConsumer(char *consumerId)\r
167 {\r
168     NS_LOG(DEBUG, "NSSendTopicUpdationToConsumer - IN");\r
169 \r
170     OCRepPayload* payload = OCRepPayloadCreate();\r
171 \r
172     if (!payload)\r
173     {\r
174         NS_LOG(ERROR, "fail to create playload");\r
175         return NS_ERROR;\r
176     }\r
177 \r
178     OCResourceHandle rHandle = NULL;\r
179     if (NSPutMessageResource(NULL, &rHandle) != NS_OK)\r
180     {\r
181         NS_LOG(ERROR, "Fail to put message resource");\r
182         return NS_ERROR;\r
183     }\r
184 \r
185     OCRepPayloadSetUri(payload, NS_COLLECTION_MESSAGE_URI);\r
186     OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_TOPIC);\r
187     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
188 \r
189     NSCacheElement * element = NSStorageRead(consumerSubList, consumerId);\r
190 \r
191     if(element == NULL)\r
192     {\r
193         NS_LOG(ERROR, "element is NULL");\r
194         return NS_ERROR;\r
195     }\r
196 \r
197     NSCacheSubData * subData = (NSCacheSubData*) element->data;\r
198 \r
199     if (OCNotifyListOfObservers(rHandle, (OCObservationId*)&subData->messageObId, 1, payload, OC_HIGH_QOS)\r
200             != OC_STACK_OK)\r
201     {\r
202         NS_LOG(ERROR, "fail to send topic updation");\r
203         OCRepPayloadDestroy(payload);\r
204         return NS_ERROR;\r
205 \r
206     }\r
207 \r
208     OCRepPayloadDestroy(payload);\r
209 \r
210     NS_LOG(DEBUG, "NSSendTopicUpdationToConsumer - OUT");\r
211     return NS_OK;\r
212 }\r
213 \r
214 NSResult NSSendTopicList(OCEntityHandlerRequest * entityHandlerRequest)\r
215 {\r
216     NS_LOG(DEBUG, "NSSendTopicList - IN");\r
217 \r
218     char * id = NSGetValueFromQuery(OICStrdup(entityHandlerRequest->query), NS_QUERY_CONSUMER_ID);\r
219     NSTopicLL * topics = NULL;\r
220 \r
221     if(!id)\r
222     {\r
223         NS_LOG(DEBUG, "Send registered topic list");\r
224         topics = NSProviderGetTopicsCacheData(registeredTopicList);\r
225     }\r
226     else\r
227     {\r
228         NS_LOG(DEBUG, "Send subscribed topic list to consumer");\r
229         topics = NSProviderGetConsumerTopicsCacheData(registeredTopicList, consumerTopicList, id);\r
230         if(!topics)\r
231         {\r
232             topics = NSProviderGetTopicsCacheData(registeredTopicList);\r
233         }\r
234     }\r
235 \r
236     if(!topics)\r
237     {\r
238         NS_LOG(DEBUG, "topicList is NULL");\r
239         return NS_ERROR;\r
240     }\r
241 \r
242     // make response for the Get Request\r
243     OCEntityHandlerResponse response;\r
244     response.numSendVendorSpecificHeaderOptions = 0;\r
245     memset(response.sendVendorSpecificHeaderOptions, 0,\r
246             sizeof response.sendVendorSpecificHeaderOptions);\r
247     memset(response.resourceUri, 0, sizeof response.resourceUri);\r
248 \r
249     OCRepPayload* payload = OCRepPayloadCreate();\r
250     if (!payload)\r
251     {\r
252         NS_LOG(ERROR, "payload is NULL");\r
253         return NS_ERROR;\r
254     }\r
255 \r
256     size_t dimensionSize = (size_t)NSProviderGetTopicListSize(topics);\r
257 \r
258     NS_LOG_V(DEBUG, "dimensionSize = %d", dimensionSize);\r
259 \r
260     if(!dimensionSize)\r
261     {\r
262         return NS_ERROR;\r
263     }\r
264 \r
265     OCRepPayload** payloadTopicArray = (OCRepPayload **) OICMalloc(\r
266             sizeof(OCRepPayload *) * dimensionSize);\r
267 \r
268     size_t dimensions[3] = {dimensionSize, 0, 0};\r
269 \r
270     for (int i = 0; i < (int)dimensionSize; i++)\r
271     {\r
272         NS_LOG_V(DEBUG, "topicName = %s", topics->topicName);\r
273         NS_LOG_V(DEBUG, "topicState = %d",(int) topics->state);\r
274 \r
275         payloadTopicArray[i] = OCRepPayloadCreate();\r
276         OCRepPayloadSetPropString(payloadTopicArray[i], NS_ATTRIBUTE_TOPIC_NAME, topics->topicName);\r
277         OCRepPayloadSetPropInt(payloadTopicArray[i], NS_ATTRIBUTE_TOPIC_SELECTION,\r
278                 (int)topics->state);\r
279 \r
280         topics = topics->next;\r
281     }\r
282 \r
283     OCRepPayloadSetUri(payload, NS_COLLECTION_TOPIC_URI);\r
284     if(id)\r
285     {\r
286         OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_CONSUMER_ID, id);\r
287     }\r
288     OCRepPayloadSetPropObjectArray(payload, NS_ATTRIBUTE_TOPIC_LIST,\r
289             (const OCRepPayload**)(payloadTopicArray), dimensions);\r
290 \r
291     response.requestHandle = entityHandlerRequest->requestHandle;\r
292     response.resourceHandle = entityHandlerRequest->resource;\r
293     response.persistentBufferFlag = 0;\r
294     response.ehResult = OC_EH_OK;\r
295     response.payload = (OCPayload *) payload;\r
296 \r
297     if (OCDoResponse(&response) != OC_STACK_OK)\r
298     {\r
299         NS_LOG(ERROR, "Fail to response topic list");\r
300         return NS_ERROR;\r
301     }\r
302     OCRepPayloadDestroy(payload);\r
303 \r
304     NS_LOG(DEBUG, "NSSendTopicList - OUT");\r
305     return NS_OK;\r
306 }\r
307 \r
308 NSResult NSPostConsumerTopics(OCEntityHandlerRequest * entityHandlerRequest)\r
309 {\r
310     NS_LOG(DEBUG, "NSPostConsumerTopics() - IN");\r
311 \r
312     char * consumerId = NULL;\r
313     OCRepPayload * payload = (OCRepPayload *) entityHandlerRequest->payload;\r
314     OCRepPayloadGetPropString(payload, NS_ATTRIBUTE_CONSUMER_ID, &consumerId);\r
315 \r
316     if(!consumerId)\r
317     {\r
318         NS_LOG(DEBUG, "Invalid consumer ID");\r
319         return NS_ERROR;\r
320     }\r
321 \r
322     NS_LOG_V(DEBUG, "TOPIC consumer ID = %s", consumerId);\r
323 \r
324     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_CID;\r
325     while(NSStorageDelete(consumerTopicList, consumerId) != NS_FAIL);\r
326     consumerTopicList->cacheType = NS_PROVIDER_CACHE_CONSUMER_TOPIC_NAME;\r
327 \r
328     OCRepPayload ** topicListPayload = NULL;\r
329     OCRepPayloadValue * payloadValue = NULL;\r
330     payloadValue = NSPayloadFindValue(payload, NS_ATTRIBUTE_TOPIC_LIST);\r
331     size_t dimensionSize = calcDimTotal(payloadValue->arr.dimensions);\r
332     size_t dimensions[3] = {dimensionSize, 0, 0};\r
333     OCRepPayloadGetPropObjectArray(payload, NS_ATTRIBUTE_TOPIC_LIST, & topicListPayload, dimensions);\r
334 \r
335     for(int i = 0; i <(int)dimensionSize; i++)\r
336     {\r
337         char * topicName = NULL;\r
338         int64_t topicState = 0;\r
339 \r
340         OCRepPayloadGetPropString(topicListPayload[i], NS_ATTRIBUTE_TOPIC_NAME, &topicName);\r
341         OCRepPayloadGetPropInt(topicListPayload[i], NS_ATTRIBUTE_TOPIC_SELECTION, &topicState);\r
342         NS_LOG_V(DEBUG, "Topic Name(state):  %s(%d)", topicName, (int)topicState);\r
343 \r
344         if(NS_TOPIC_SUBSCRIBED == (NSTopicState)topicState)\r
345         {\r
346             NSCacheTopicSubData * topicSubData = (NSCacheTopicSubData *)\r
347                     OICMalloc(sizeof(NSCacheTopicSubData));\r
348 \r
349             OICStrcpy(topicSubData->id, NS_UUID_STRING_SIZE, consumerId);\r
350             topicSubData->topicName = OICStrdup(topicName);\r
351 \r
352             NSCacheElement * newObj = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
353             newObj->data = (NSCacheData *) topicSubData;\r
354             newObj->next = NULL;\r
355             NSStorageWrite(consumerTopicList, newObj);\r
356         }\r
357     }\r
358 \r
359     NS_LOG(DEBUG, "NSPostConsumerTopics() - OUT");\r
360     return NS_OK;\r
361 }\r
362 \r
363 void * NSTopicSchedule(void * ptr)\r
364 {\r
365     if (ptr == NULL)\r
366     {\r
367         NS_LOG(DEBUG, "Create NSTopicSchedule");\r
368     }\r
369 \r
370     while (NSIsRunning[TOPIC_SCHEDULER])\r
371     {\r
372         sem_wait(&NSSemaphore[TOPIC_SCHEDULER]);\r
373         pthread_mutex_lock(&NSMutex[TOPIC_SCHEDULER]);\r
374 \r
375         if (NSHeadMsg[TOPIC_SCHEDULER] != NULL)\r
376         {\r
377             NSTask *node = NSHeadMsg[TOPIC_SCHEDULER];\r
378             NSHeadMsg[TOPIC_SCHEDULER] = node->nextTask;\r
379 \r
380             switch (node->taskType)\r
381             {\r
382                 case TASK_SEND_TOPICS:\r
383                     NS_LOG(DEBUG, "CASE TASK_SEND_TOPICS : ");\r
384                     NSSendTopicList((OCEntityHandlerRequest*) node->taskData);\r
385                     NSFreeOCEntityHandlerRequest((OCEntityHandlerRequest*) node->taskData);\r
386                     break;\r
387                 case TASK_SUBSCRIBE_TOPIC:\r
388                     NS_LOG(DEBUG, "CASE TASK_SUBSCRIBE_TOPIC : ");\r
389                     NSCacheElement * newObj = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
390                     newObj->data = node->taskData;\r
391                     newObj->next = NULL;\r
392                     NSStorageWrite(consumerTopicList, newObj);\r
393                     break;\r
394                 case TASK_UNSUBSCRIBE_TOPIC:\r
395                     NS_LOG(DEBUG, "CASE TASK_SUBSCRIBE_TOPIC : ");\r
396                     NSProviderDeleteConsumerTopic(consumerTopicList,\r
397                             (NSCacheTopicSubData *) node->taskData);\r
398                     NS_LOG(DEBUG, "CASE TASK_SUBSCRIBE_TOPIC AFter: ");\r
399                     break;\r
400                 case TASK_ADD_TOPIC:\r
401                 {\r
402                     NS_LOG(DEBUG, "CASE TASK_ADD_TOPIC : ");\r
403                     NSAddTopics((const char *) node->taskData);\r
404                 }\r
405                     break;\r
406                 case TASK_DELETE_TOPIC:\r
407                 {\r
408                     NS_LOG(DEBUG, "CASE_TASK_DELETE_TOPIC : ");\r
409                     NSDeleteTopics((const char *) node->taskData);\r
410                 }\r
411                     break;\r
412                 case TASK_POST_TOPIC:\r
413                 {\r
414                     NS_LOG(DEBUG, "TASK_POST_TOPIC : ");\r
415                     NSPostConsumerTopics((OCEntityHandlerRequest*) node->taskData);\r
416                     NSFreeOCEntityHandlerRequest((OCEntityHandlerRequest*) node->taskData);\r
417                 }\r
418                     break;\r
419                 default:\r
420                     break;\r
421             }\r
422 \r
423             OICFree(node);\r
424         }\r
425 \r
426         pthread_mutex_unlock(&NSMutex[TOPIC_SCHEDULER]);\r
427     }\r
428 \r
429     NS_LOG(DEBUG, "Destroy NSTopicSchedule");\r
430     return NULL;\r
431 }\r