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