Merge notification service from master branch
[platform/upstream/iotivity.git] / service / notification / src / provider / NSProviderSubscription.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 "NSProviderSubscription.h"\r
22 \r
23 NSResult NSInitSubscriptionList()\r
24 {\r
25     NS_LOG(DEBUG, "NSInitSubscriptionList - IN");\r
26 \r
27     consumerSubList = NSProviderStorageCreate();\r
28     NS_VERIFY_NOT_NULL(consumerSubList, NS_FAIL);\r
29     consumerSubList->cacheType = NS_PROVIDER_CACHE_SUBSCRIBER;\r
30 \r
31     NS_LOG(DEBUG, "NSInitSubscriptionList - OUT");\r
32     return NS_OK;\r
33 }\r
34 \r
35 NSResult NSSetSubscriptionAccessPolicy(bool policy)\r
36 {\r
37     NS_LOG(DEBUG, "NSSetSubscriptionAcceptPolicy - IN");\r
38 \r
39     if (policy == NS_POLICY_PROVIDER)\r
40     {\r
41         NS_LOG(DEBUG, "Place Provider as a subscription accepter");\r
42     }\r
43     else if (policy == NS_POLICY_CONSUMER)\r
44     {\r
45         NS_LOG(DEBUG, "Place Consumer as a subscription accepter");\r
46     }\r
47 \r
48     NSSetPolicy(policy);\r
49 \r
50     NS_LOG(DEBUG, "NSSetSubscriptionAcceptPolicy - OUT");\r
51     return NS_OK;\r
52 }\r
53 \r
54 NSResult NSSendAccessPolicyResponse(OCEntityHandlerRequest *entityHandlerRequest)\r
55 {\r
56     NS_LOG(DEBUG, "NSSendAccessPolicyResponse - IN");\r
57 \r
58     // put notification resource\r
59     OCResourceHandle notificationResourceHandle = NULL;\r
60     if (NSPutNotificationResource(NSGetPolicy(), &notificationResourceHandle)\r
61             != NS_OK)\r
62     {\r
63         NS_LOG(ERROR, "Fail to put notification resource");\r
64         return NS_ERROR;\r
65     }\r
66 \r
67     // make response for the Get Request\r
68     OCEntityHandlerResponse response;\r
69     response.numSendVendorSpecificHeaderOptions = 0;\r
70     memset(response.sendVendorSpecificHeaderOptions, 0,\r
71             sizeof response.sendVendorSpecificHeaderOptions);\r
72     memset(response.resourceUri, 0, sizeof response.resourceUri);\r
73 \r
74     OCRepPayload* payload = OCRepPayloadCreate();\r
75     if (!payload)\r
76     {\r
77         NS_LOG(ERROR, "payload is NULL");\r
78         return NS_ERROR;\r
79     }\r
80 \r
81     NS_LOG_V(DEBUG, "NS Provider ID: %s", NSGetProviderInfo()->providerId);\r
82 \r
83     OCRepPayloadSetUri(payload, NS_ROOT_URI);\r
84     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
85     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_VERSION, VERSION);\r
86     OCRepPayloadSetPropBool(payload, NS_ATTRIBUTE_POLICY, NSGetPolicy());\r
87     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_MESSAGE, NS_COLLECTION_MESSAGE_URI);\r
88     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_SYNC, NS_COLLECTION_SYNC_URI);\r
89     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_TOPIC, NS_COLLECTION_TOPIC_URI);\r
90 \r
91     response.requestHandle = entityHandlerRequest->requestHandle;\r
92     response.resourceHandle = entityHandlerRequest->resource;\r
93     response.persistentBufferFlag = 0;\r
94     response.ehResult = OC_EH_OK;\r
95     response.payload = (OCPayload *) payload;\r
96 \r
97     // Send Response\r
98     if (OCDoResponse(&response) != OC_STACK_OK)\r
99     {\r
100         NS_LOG(ERROR, "Fail to AccessPolicy send response");\r
101         return NS_ERROR;\r
102     }\r
103     OCRepPayloadDestroy(payload);\r
104     NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
105 \r
106     NS_LOG(DEBUG, "NSSendAccessPolicyResponse - OUT");\r
107     return NS_OK;\r
108 }\r
109 \r
110 void NSHandleSubscription(OCEntityHandlerRequest *entityHandlerRequest, NSResourceType resourceType)\r
111 {\r
112     NS_LOG(DEBUG, "NSHandleSubscription - IN");\r
113 \r
114     char * id = NSGetValueFromQuery(OICStrdup(entityHandlerRequest->query), NS_QUERY_CONSUMER_ID);\r
115 \r
116     if(!id)\r
117     {\r
118         NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
119         NS_LOG(ERROR, "Invalid ConsumerID");\r
120         return;\r
121     }\r
122 \r
123     NS_LOG_V(DEBUG, "consumerId = %s", id);\r
124     if (resourceType == NS_RESOURCE_MESSAGE)\r
125     {\r
126         NS_LOG(DEBUG, "resourceType == NS_RESOURCE_MESSAGE");\r
127         NSCacheElement * element = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
128         NSCacheSubData * subData = (NSCacheSubData *) OICMalloc(sizeof(NSCacheSubData));\r
129 \r
130         OICStrcpy(subData->id, UUID_STRING_SIZE, id);\r
131         NS_LOG_V(DEBUG, "SubList ID = [%s]", subData->id);\r
132 \r
133         NS_LOG_V(DEBUG, "Consumer Address: %s", entityHandlerRequest->devAddr.addr);\r
134 \r
135         subData->remote_messageObId = subData->messageObId = 0;\r
136 \r
137         bool iSRemoteServer = false;\r
138 \r
139 #if(defined WITH_CLOUD && defined RD_CLIENT)\r
140         iSRemoteServer = NSIsRemoteServerAddress(entityHandlerRequest->devAddr.addr);\r
141         if(iSRemoteServer)\r
142         {\r
143             NS_LOG(DEBUG, "Requested by remote server");\r
144             subData->remote_messageObId = entityHandlerRequest->obsInfo.obsId;\r
145             NS_LOG_V(DEBUG, "SubList message observation ID = [%d]", subData->remote_messageObId);\r
146         }\r
147 #endif\r
148 \r
149         if(!iSRemoteServer)\r
150         {\r
151             NS_LOG(DEBUG, "Requested by local consumer");\r
152             subData->messageObId = entityHandlerRequest->obsInfo.obsId;\r
153             NS_LOG_V(DEBUG, "SubList message observation ID = [%d]", subData->messageObId);\r
154         }\r
155 \r
156         subData->isWhite = false;\r
157         subData->remote_syncObId = 0;\r
158         subData->syncObId = 0;\r
159 \r
160         element->data = (void*) subData;\r
161         element->next = NULL;\r
162 \r
163         if (NSProviderStorageWrite(consumerSubList, element) != NS_OK)\r
164         {\r
165             NS_LOG(DEBUG, "fail to write cache");\r
166         }\r
167 \r
168         bool currPolicy = NSGetPolicy();\r
169         NSAskAcceptanceToUser(entityHandlerRequest);\r
170 \r
171         if (currPolicy == NS_POLICY_PROVIDER)\r
172         {\r
173             NS_LOG(DEBUG, "NSGetSubscriptionAccepter == NS_ACCEPTER_PROVIDER");\r
174         }\r
175         else if (currPolicy == NS_POLICY_CONSUMER)\r
176         {\r
177             NS_LOG(DEBUG, "NSGetSubscriptionAccepter == NS_ACCEPTER_CONSUMER");\r
178             NSSendConsumerSubResponse(NSCopyOCEntityHandlerRequest(entityHandlerRequest));\r
179         }\r
180     }\r
181     else if (resourceType == NS_RESOURCE_SYNC)\r
182     {\r
183         NS_LOG(DEBUG, "resourceType == NS_RESOURCE_SYNC");\r
184         NSCacheElement * element = (NSCacheElement *) OICMalloc(sizeof(NSCacheElement));\r
185         NSCacheSubData * subData = (NSCacheSubData *) OICMalloc(sizeof(NSCacheSubData));\r
186 \r
187         OICStrcpy(subData->id, UUID_STRING_SIZE, id);\r
188         NS_LOG_V(DEBUG, "SubList ID = [%s]", subData->id);\r
189 \r
190         NS_LOG_V(DEBUG, "Consumer Address: %s", entityHandlerRequest->devAddr.addr);\r
191 \r
192         subData->remote_syncObId = subData->syncObId = 0;\r
193         bool isRemoteServer = false;\r
194 \r
195 #if(defined WITH_CLOUD && defined RD_CLIENT)\r
196         isRemoteServer = NSIsRemoteServerAddress(entityHandlerRequest->devAddr.addr);\r
197         if(isRemoteServer)\r
198         {\r
199             NS_LOG(DEBUG, "Requested by remote server");\r
200             subData->remote_syncObId = entityHandlerRequest->obsInfo.obsId;\r
201             NS_LOG_V(DEBUG, "SubList sync observation ID = [%d]", subData->remote_syncObId);\r
202         }\r
203 #endif\r
204 \r
205         if(!isRemoteServer)\r
206         {\r
207             NS_LOG(DEBUG, "Requested by local consumer");\r
208             subData->syncObId = entityHandlerRequest->obsInfo.obsId;\r
209             NS_LOG_V(DEBUG, "SubList sync observation ID = [%d]", subData->syncObId);\r
210         }\r
211 \r
212         subData->isWhite = false;\r
213         subData->messageObId = 0;\r
214         subData->remote_messageObId = 0;\r
215 \r
216         element->data = (void*) subData;\r
217         element->next = NULL;\r
218 \r
219         if (NSProviderStorageWrite(consumerSubList, element) != NS_OK)\r
220         {\r
221             NS_LOG(ERROR, "Fail to write cache");\r
222         }\r
223 \r
224         NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
225     }\r
226 \r
227     NS_LOG(DEBUG, "NSHandleSubscription - OUT");\r
228 }\r
229 \r
230 void NSHandleUnsubscription(OCEntityHandlerRequest *entityHandlerRequest)\r
231 {\r
232     NS_LOG(DEBUG, "NSHandleUnsubscription - IN");\r
233 \r
234     consumerSubList->cacheType = NS_PROVIDER_CACHE_SUBSCRIBER_OBSERVE_ID;\r
235 \r
236     while(NSProviderStorageDelete(consumerSubList, (char *)\r
237             &(entityHandlerRequest->obsInfo.obsId)) != NS_FAIL);\r
238     consumerSubList->cacheType = NS_PROVIDER_CACHE_SUBSCRIBER;\r
239 \r
240     NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
241 \r
242     NS_LOG(DEBUG, "NSHandleUnsubscription - OUT");\r
243 }\r
244 \r
245 void NSAskAcceptanceToUser(OCEntityHandlerRequest *entityHandlerRequest)\r
246 {\r
247     NS_LOG(DEBUG, "NSAskAcceptanceToUser - IN");\r
248 \r
249     NSPushQueue(CALLBACK_RESPONSE_SCHEDULER, TASK_CB_SUBSCRIPTION, entityHandlerRequest);\r
250 \r
251     NS_LOG(DEBUG, "NSAskAcceptanceToUser - OUT");\r
252 }\r
253 \r
254 NSResult NSSendResponse(const char * id, bool accepted)\r
255 {\r
256     NS_LOG(DEBUG, "NSSendResponse - IN");\r
257 \r
258     OCRepPayload* payload = OCRepPayloadCreate();\r
259     if (!payload)\r
260     {\r
261         NS_LOG(ERROR, "fail to create playload");\r
262         return NS_ERROR;\r
263     }\r
264 \r
265     OCResourceHandle rHandle = NULL;\r
266     if (NSPutMessageResource(NULL, &rHandle) != NS_OK)\r
267     {\r
268         NS_LOG(ERROR, "Fail to put notification resource");\r
269         return NS_ERROR;\r
270     }\r
271 \r
272     OCRepPayloadSetUri(payload, NS_COLLECTION_MESSAGE_URI);\r
273     (accepted) ? OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_ALLOW)\r
274         : OCRepPayloadSetPropInt(payload, NS_ATTRIBUTE_MESSAGE_ID, NS_DENY);\r
275     OCRepPayloadSetPropString(payload, NS_ATTRIBUTE_PROVIDER_ID, NSGetProviderInfo()->providerId);\r
276 \r
277     NSCacheElement * element = NSProviderStorageRead(consumerSubList, id);\r
278 \r
279     if(element == NULL)\r
280     {\r
281         NS_LOG(ERROR, "element is NULL");\r
282         return NS_ERROR;\r
283     }\r
284     NSCacheSubData * subData = (NSCacheSubData*) element->data;\r
285 \r
286     if (OCNotifyListOfObservers(rHandle, (OCObservationId*)&subData->messageObId, 1,\r
287             payload, OC_LOW_QOS) != OC_STACK_OK)\r
288     {\r
289         NS_LOG(ERROR, "fail to send Acceptance");\r
290         OCRepPayloadDestroy(payload);\r
291         return NS_ERROR;\r
292 \r
293     }\r
294     OCRepPayloadDestroy(payload);\r
295 \r
296     NS_LOG(DEBUG, "NSSendResponse - OUT");\r
297     return NS_OK;\r
298 }\r
299 \r
300 NSResult NSSendConsumerSubResponse(OCEntityHandlerRequest * entityHandlerRequest)\r
301 {\r
302     NS_LOG(DEBUG, "NSSendSubscriptionResponse - IN");\r
303 \r
304     if (!entityHandlerRequest)\r
305     {\r
306         NS_LOG(ERROR, "Invalid request pointer");\r
307         return OC_EH_ERROR;\r
308     }\r
309 \r
310     char * id = NSGetValueFromQuery(OICStrdup(entityHandlerRequest->query), NS_QUERY_CONSUMER_ID);\r
311 \r
312     if(!id)\r
313     {\r
314         NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
315         NS_LOG(ERROR, "Invalid ConsumerID");\r
316         return NS_ERROR;\r
317     }\r
318 \r
319     NSCacheUpdateSubScriptionState(consumerSubList, id, true);\r
320     NSSendResponse(id, true);\r
321     NSFreeOCEntityHandlerRequest(entityHandlerRequest);\r
322     NS_LOG(DEBUG, "NSSendSubscriptionResponse - OUT");\r
323     return NS_OK;\r
324 }\r
325 \r
326 void * NSSubScriptionSchedule(void *ptr)\r
327 {\r
328     if (ptr == NULL)\r
329     {\r
330         NS_LOG(DEBUG, "Create NSSubScriptionSchedule");\r
331     }\r
332 \r
333     while (NSIsRunning[SUBSCRIPTION_SCHEDULER])\r
334     {\r
335         sem_wait(&NSSemaphore[SUBSCRIPTION_SCHEDULER]);\r
336         pthread_mutex_lock(&NSMutex[SUBSCRIPTION_SCHEDULER]);\r
337 \r
338         if (NSHeadMsg[SUBSCRIPTION_SCHEDULER] != NULL)\r
339         {\r
340             NSTask *node = NSHeadMsg[SUBSCRIPTION_SCHEDULER];\r
341             NSHeadMsg[SUBSCRIPTION_SCHEDULER] = node->nextTask;\r
342 \r
343             switch (node->taskType)\r
344             {\r
345                 case TASK_SEND_POLICY:\r
346                     NS_LOG(DEBUG, "CASE TASK_SEND_POLICY : ");\r
347                     NSSendAccessPolicyResponse((OCEntityHandlerRequest*) node->taskData);\r
348                     break;\r
349 \r
350                 case TASK_RECV_SUBSCRIPTION:\r
351                     NS_LOG(DEBUG, "CASE TASK_RECV_SUBSCRIPTION : ");\r
352                     NSHandleSubscription((OCEntityHandlerRequest*) node->taskData,\r
353                             NS_RESOURCE_MESSAGE);\r
354                     break;\r
355 \r
356                 case TASK_RECV_UNSUBSCRIPTION:\r
357                     NS_LOG(DEBUG, "CASE TASK_RECV_UNSUBSCRIPTION : ");\r
358                     NSHandleUnsubscription((OCEntityHandlerRequest*) node->taskData);\r
359                     break;\r
360 \r
361                 case TASK_SEND_ALLOW:\r
362                 {\r
363                     NS_LOG(DEBUG, "CASE TASK_SEND_ALLOW : ");\r
364                     char * consumerId = (char *) node->taskData;\r
365 \r
366                     NSCacheUpdateSubScriptionState(consumerSubList, consumerId, true);\r
367                     NSSendResponse(consumerId, true);\r
368                     OICFree(consumerId);\r
369                     break;\r
370                 }\r
371                 case TASK_SEND_DENY:\r
372                 {\r
373                     NS_LOG(DEBUG, "CASE TASK_SEND_DENY : ");\r
374                     char * consumerId = (char *) node->taskData;\r
375 \r
376                     NSCacheUpdateSubScriptionState(consumerSubList, consumerId, false);\r
377                     NSSendResponse(consumerId, false);\r
378                     OICFree(consumerId);\r
379 \r
380                     break;\r
381                 }\r
382                 case TASK_SYNC_SUBSCRIPTION:\r
383                     NS_LOG(DEBUG, "CASE TASK_SYNC_SUBSCRIPTION : ");\r
384                     NSHandleSubscription((OCEntityHandlerRequest*) node->taskData,\r
385                             NS_RESOURCE_SYNC);\r
386                     break;\r
387                 default:\r
388                     break;\r
389 \r
390             }\r
391             OICFree(node);\r
392         }\r
393 \r
394         pthread_mutex_unlock(&NSMutex[SUBSCRIPTION_SCHEDULER]);\r
395 \r
396     }\r
397     NS_LOG(INFO, "Destroy NSSubScriptionSchedule");\r
398     return NULL;\r
399 }\r