apply observe,presence functions
[platform/core/iot/iotcon.git] / daemon / icd-ioty.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h> /* for uint8_t etc */
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <glib.h>
23 #include <json-glib/json-glib.h>
24
25 #include <octypes.h>
26 #include <ocstack.h>
27
28 #include "iotcon.h"
29 #include "ic-dbus.h"
30 #include "ic-utils.h"
31 #include "icd.h"
32 #include "icd-dbus.h"
33 #include "icd-ioty.h"
34 #include "icd-ioty-ocprocess.h"
35
36 static GMutex icd_csdk_mutex;
37
38 void icd_ioty_csdk_lock()
39 {
40         g_mutex_lock(&icd_csdk_mutex);
41 }
42
43
44 void icd_ioty_csdk_unlock()
45 {
46         g_mutex_unlock(&icd_csdk_mutex);
47 }
48
49
50 GThread* icd_ioty_init(const char *addr, unsigned short port)
51 {
52         FN_CALL;
53         GError *error;
54         GThread *thread;
55
56         OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
57         if (OC_STACK_OK != result) {
58                 ERR("OCInit() Fail(%d)", result);
59                 return NULL;
60         }
61
62         DBG("OCInit() Success");
63
64         thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
65                         NULL, &error);
66         if (NULL == thread) {
67                 ERR("g_thread_try_new() Fail(%s)", error->message);
68                 g_error_free(error);
69                 return NULL;
70         }
71
72         return thread;
73 }
74
75
76 void icd_ioty_deinit(GThread *thread)
77 {
78         OCStackResult result;
79
80         icd_ioty_ocprocess_stop();
81         g_thread_join(thread);
82
83         result = OCStop();
84         if (OC_STACK_OK != result)
85                 ERR("OCStop() Fail(%d)", result);
86 }
87
88
89 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
90                 const char* const* res_types, int ifaces, uint8_t properties)
91 {
92         FN_CALL;
93         int i;
94         OCStackResult ret;
95         OCResourceHandle handle;
96         const char *resInterface = NULL;
97
98         if (IOTCON_INTERFACE_DEFAULT & ifaces) {
99                 resInterface = IC_INTERFACE_DEFAULT;
100                 ifaces ^= IOTCON_INTERFACE_DEFAULT;
101         } else if (IOTCON_INTERFACE_LINK & ifaces) {
102                 resInterface = IC_INTERFACE_LINK;
103                 ifaces ^= IOTCON_INTERFACE_LINK;
104         } else if (IOTCON_INTERFACE_BATCH & ifaces) {
105                 resInterface = IC_INTERFACE_BATCH;
106                 ifaces ^= IOTCON_INTERFACE_BATCH;
107         } else if (IOTCON_INTERFACE_GROUP & ifaces) {
108                 resInterface = IC_INTERFACE_GROUP;
109                 ifaces ^= IOTCON_INTERFACE_GROUP;
110         } else {
111                 ERR("Invalid interface type(%d)", ifaces);
112                 return NULL;
113         }
114
115         icd_ioty_csdk_lock();
116         ret = OCCreateResource(&handle, res_types[0], resInterface, uri_path,
117                         icd_ioty_ocprocess_req_handler, properties);
118         icd_ioty_csdk_unlock();
119         if (OC_STACK_OK != ret) {
120                 ERR("OCCreateResource() Fail(%d)", ret);
121                 return NULL;
122         }
123
124         for (i = 1; res_types[i]; i++)
125                 icd_ioty_bind_type(handle, res_types[i]);
126
127         if (IOTCON_INTERFACE_DEFAULT & ifaces)
128                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_DEFAULT);
129         if (IOTCON_INTERFACE_LINK & ifaces)
130                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_LINK);
131         if (IOTCON_INTERFACE_BATCH & ifaces)
132                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_BATCH);
133         if (IOTCON_INTERFACE_GROUP & ifaces)
134                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_GROUP);
135
136         return handle;
137 }
138
139
140 int icd_ioty_unregister_resource(OCResourceHandle handle)
141 {
142         OCStackResult ret;
143
144         icd_ioty_csdk_lock();
145         ret = OCDeleteResource(handle);
146         icd_ioty_csdk_unlock();
147         if (OC_STACK_OK != ret) {
148                 ERR("OCDeleteResource() Fail(%d)", ret);
149                 return IOTCON_ERROR_IOTIVITY;
150         }
151
152         return IOTCON_ERROR_NONE;
153 }
154
155
156 int icd_ioty_bind_interface(OCResourceHandle handle, iotcon_interface_e iface)
157 {
158         int ret;
159         OCStackResult result;
160         char *resource_interface;
161
162         ret = ic_utils_convert_interface_flag(iface, &resource_interface);
163         if (IOTCON_ERROR_NONE != ret) {
164                 ERR("ic_utils_convert_interface_flag(%d) Fail(%d)", iface, ret);
165                 return ret;
166         }
167
168         icd_ioty_csdk_lock();
169         result = OCBindResourceInterfaceToResource(handle, resource_interface);
170         icd_ioty_csdk_unlock();
171         if (OC_STACK_OK != result) {
172                 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
173                 return IOTCON_ERROR_IOTIVITY;
174         }
175
176         return IOTCON_ERROR_NONE;
177 }
178
179
180 int icd_ioty_bind_type(OCResourceHandle handle, const char *resource_type)
181 {
182         OCStackResult ret;
183
184         icd_ioty_csdk_lock();
185         ret = OCBindResourceTypeToResource(handle, resource_type);
186         icd_ioty_csdk_unlock();
187         if (OC_STACK_OK != ret) {
188                 ERR("OCBindResourceTypeToResource() Fail(%d)", ret);
189                 return IOTCON_ERROR_IOTIVITY;
190         }
191
192         return IOTCON_ERROR_NONE;
193 }
194
195
196 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
197 {
198         OCStackResult ret;
199
200         icd_ioty_csdk_lock();
201         ret = OCBindResource(parent, child);
202         icd_ioty_csdk_unlock();
203         if (OC_STACK_OK != ret) {
204                 ERR("OCBindResource() Fail(%d)", ret);
205                 return IOTCON_ERROR_IOTIVITY;
206         }
207
208         return IOTCON_ERROR_NONE;
209 }
210
211
212 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
213 {
214         OCStackResult ret;
215
216         icd_ioty_csdk_lock();
217         ret = OCUnBindResource(parent, child);
218         icd_ioty_csdk_unlock();
219         if (OC_STACK_OK != ret) {
220                 ERR("OCUnBindResource() Fail(%d)", ret);
221                 return IOTCON_ERROR_IOTIVITY;
222         }
223
224         return IOTCON_ERROR_NONE;
225 }
226
227
228 int icd_ioty_notify_list_of_observers(OCResourceHandle handle, GVariant *msg,
229                 GVariant *observers)
230 {
231         int i, error_code, obs_length;
232         char *repr_json = NULL;
233         GVariantIter obs_iter, msg_iter;
234         OCStackResult ret;
235
236         g_variant_iter_init(&obs_iter, observers);
237         obs_length = g_variant_iter_n_children(&obs_iter);
238
239         /* Variable-length Array */
240         OCObservationId obs_ids[obs_length];
241
242         for (i = 0; i < obs_length; i++)
243                 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
244
245         g_variant_iter_init(&msg_iter, msg);
246         g_variant_iter_loop(&msg_iter, "(i&s)", &error_code, &repr_json);
247         /* TODO : How to use error_code. */
248
249         icd_ioty_csdk_lock();
250         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
251         ret = OCNotifyListOfObservers(handle, obs_ids, obs_length, repr_json, OC_HIGH_QOS);
252         icd_ioty_csdk_unlock();
253
254         if (OC_STACK_NO_OBSERVERS == ret) {
255                 WARN("No Observers. Stop Notifying");
256                 return IOTCON_ERROR_NONE;
257         } else if (OC_STACK_OK != ret) {
258                 ERR("OCNotifyListOfObservers() Fail(%d)", ret);
259                 return IOTCON_ERROR_IOTIVITY;
260         }
261
262         return IOTCON_ERROR_NONE;
263 }
264
265
266 int icd_ioty_notify_all(OCResourceHandle handle)
267 {
268         OCStackResult ret;
269
270         icd_ioty_csdk_lock();
271         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
272         ret = OCNotifyAllObservers(handle, OC_HIGH_QOS);
273         icd_ioty_csdk_unlock();
274
275         if (OC_STACK_NO_OBSERVERS == ret) {
276                 WARN("No Observers. Stop Notifying");
277                 return IOTCON_ERROR_NONE;
278         } else if (OC_STACK_OK != ret) {
279                 ERR("OCNotifyAllObservers() Fail(%d)", ret);
280                 return IOTCON_ERROR_IOTIVITY;
281         }
282
283         return IOTCON_ERROR_NONE;
284 }
285
286
287 static int _ioty_get_header_options(GVariantIter *src, int src_size,
288                 OCHeaderOption dest[], int dest_size)
289 {
290         int i = 0;
291         char *option_data;
292         unsigned short option_id;
293
294         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
295
296         if (dest_size < src_size) {
297                 ERR("Exceed Size(%d)", src_size);
298                 return IOTCON_ERROR_INVALID_PARAMETER;
299         }
300
301         while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
302                 dest[i].protocolID = OC_COAP_ID;
303                 dest[i].optionID = option_id;
304                 dest[i].optionLength = strlen(option_data) + 1;
305                 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
306                 i++;
307         }
308
309         return IOTCON_ERROR_NONE;
310 }
311
312
313 int icd_ioty_send_response(GVariant *resp)
314 {
315         int result, error_code, options_size;
316         int request_handle, resource_handle;
317         char *new_uri_path, *repr_json;
318         GVariantIter *options;
319         OCStackResult ret;
320         OCEntityHandlerResponse response = {0};
321
322         g_variant_get(resp, "(&sia(qs)i&sii)",
323                         &new_uri_path,
324                         &error_code,
325                         &options,
326                         &result,
327                         &repr_json,
328                         &request_handle,
329                         &resource_handle);
330
331         response.requestHandle = GINT_TO_POINTER(request_handle);
332         response.resourceHandle = GINT_TO_POINTER(resource_handle);
333         response.ehResult = (OCEntityHandlerResult)result;
334
335         if (OC_EH_RESOURCE_CREATED == response.ehResult)
336                 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
337
338         options_size = g_variant_iter_n_children(options);
339         response.numSendVendorSpecificHeaderOptions = options_size;
340
341         if (0 != options_size) {
342                 int ret= _ioty_get_header_options(options,
343                                 response.numSendVendorSpecificHeaderOptions,
344                                 response.sendVendorSpecificHeaderOptions,
345                                 sizeof(response.sendVendorSpecificHeaderOptions)
346                                 / sizeof(response.sendVendorSpecificHeaderOptions[0]));
347
348                 if (IOTCON_ERROR_NONE != ret)
349                         ERR("_ioty_get_header_options() Fail(%d)", ret);
350         }
351         g_variant_iter_free(options);
352
353         response.payload = repr_json;
354         response.payloadSize = strlen(response.payload) + 1;
355
356         /* related to block transfer */
357         response.persistentBufferFlag = 0;
358
359         icd_ioty_csdk_lock();
360         ret = OCDoResponse(&response);
361         icd_ioty_csdk_unlock();
362
363         if (OC_STACK_OK != ret) {
364                 ERR("OCDoResponse() Fail(%d)", ret);
365                 return IOTCON_ERROR_IOTIVITY;
366         }
367
368         return IOTCON_ERROR_NONE;
369 }
370
371
372 static void _ioty_free_signal_context(void *data)
373 {
374         icd_sig_ctx_s *context = data;
375         free(context->bus_name);
376         free(context);
377 }
378
379 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
380                 unsigned int signum, const char *bus_name)
381 {
382         int len;
383         OCStackResult result;
384         OCCallbackData cbdata = {0};
385         icd_sig_ctx_s *context;
386         char uri[PATH_MAX] = {0};
387         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
388
389         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
390                 len = snprintf(uri, sizeof(uri), "%s", OC_MULTICAST_DISCOVERY_URI);
391                 conn_type = IOTCON_CONNECTIVITY_ALL;
392         } else {
393                 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
394                                 OC_MULTICAST_DISCOVERY_URI);
395         }
396         if (len <= 0 || sizeof(uri) <= len) {
397                 ERR("snprintf() Fail(%d)", len);
398                 return IOTCON_ERROR_UNKNOWN;
399         }
400
401         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
402                 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
403
404         context = calloc(1, sizeof(icd_sig_ctx_s));
405         if (NULL == context) {
406                 ERR("calloc() Fail(%d)", errno);
407                 return IOTCON_ERROR_OUT_OF_MEMORY;
408         }
409
410         context->bus_name = ic_utils_strdup(bus_name);
411         context->signum = signum;
412
413         cbdata.context = context;
414         cbdata.cb = icd_ioty_ocprocess_find_cb;
415         cbdata.cd = _ioty_free_signal_context;
416
417         icd_ioty_csdk_lock();
418         result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_LOW_QOS,
419                         &cbdata, NULL, 0);
420         icd_ioty_csdk_unlock();
421
422         if (OC_STACK_OK != result) {
423                 ERR("OCDoResource() Fail(%d)", result);
424                 free(context->bus_name);
425                 free(context);
426                 return IOTCON_ERROR_IOTIVITY;
427         }
428
429         return IOTCON_ERROR_NONE;
430 }
431
432
433 /*
434  * returned string SHOULD be released by you
435  */
436 static char* _icd_ioty_resource_generate_uri(char *host, char *uri_path, GVariant *query)
437 {
438         int len;
439         bool loop_first = true;
440         char *key, *value;
441         GVariantIter query_iter;
442         char uri_buf[PATH_MAX] = {0};
443
444         len = snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
445
446         /* remove suffix '/' */
447         if ('/' == uri_buf[strlen(uri_buf) - 1]) {
448                 uri_buf[strlen(uri_buf) - 1] = '\0';
449                 len--;
450         }
451
452         g_variant_iter_init(&query_iter, query);
453
454         while (g_variant_iter_loop(&query_iter, "(&s&s)", &key, &value)) {
455                 int query_len;
456
457                 DBG("query exist. key(%s), value(%s)", key, value);
458
459                 if (true == loop_first) {
460                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "?%s=%s", key, value);
461                         loop_first = false;
462                 } else {
463                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "&%s=%s", key, value);
464                 }
465
466                 len += query_len;
467         }
468
469         return strdup(uri_buf);
470 }
471
472
473 void icd_ioty_complete(int type, GDBusMethodInvocation *invocation, GVariant *value)
474 {
475         switch(type) {
476         case ICD_CRUD_GET:
477                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
478                 break;
479         case ICD_CRUD_PUT:
480                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
481                 break;
482         case ICD_CRUD_POST:
483                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
484                 break;
485         case ICD_CRUD_DELETE:
486                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
487                 break;
488         }
489 }
490
491
492 void icd_ioty_complete_error(int type, GDBusMethodInvocation *invocation, int ret_val)
493 {
494         GVariant *value;
495
496         switch (type) {
497         case ICD_CRUD_GET:
498                 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
499                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
500                 break;
501         case ICD_CRUD_PUT:
502                 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
503                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
504                 break;
505         case ICD_CRUD_POST:
506                 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
507                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
508                 break;
509         case ICD_CRUD_DELETE:
510                 value = g_variant_new("(a(qs)i)", NULL, ret_val);
511                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
512                 break;
513         }
514 }
515
516
517 static gboolean _icd_ioty_crud(int type, icDbus *object, GDBusMethodInvocation *invocation,
518                 GVariant *resource, GVariant *query, const char *repr)
519 {
520         OCMethod rest_type;
521         OCStackResult result;
522         GVariantIter *options;
523         OCCallbackData cbdata = {0};
524         int conn_type, options_size;
525         char *uri_path, *host, *uri;
526         char uri_buf[PATH_MAX] = {0};
527         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
528         OCHeaderOption *oic_options_ptr = NULL;
529
530         switch (type) {
531         case ICD_CRUD_GET:
532                 cbdata.cb = icd_ioty_ocprocess_get_cb;
533                 rest_type = OC_REST_GET;
534                 break;
535         case ICD_CRUD_PUT:
536                 cbdata.cb = icd_ioty_ocprocess_put_cb;
537                 rest_type = OC_REST_PUT;
538                 break;
539         case ICD_CRUD_POST:
540                 cbdata.cb = icd_ioty_ocprocess_post_cb;
541                 rest_type = OC_REST_POST;
542                 break;
543         case ICD_CRUD_DELETE:
544                 cbdata.cb = icd_ioty_ocprocess_delete_cb;
545                 rest_type = OC_REST_DELETE;
546                 break;
547         default:
548                 ERR("Invalid CRUD Type(%d)", type);
549                 return FALSE;
550         }
551
552         g_variant_get(resource, "(&s&sa(qs)i)", &uri_path, &host, &options, &conn_type);
553
554         switch (type) {
555         case ICD_CRUD_GET:
556         case ICD_CRUD_PUT:
557         case ICD_CRUD_POST:
558                 uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
559                 if (NULL == uri) {
560                         ERR("_icd_ioty_resource_generate_uri() Fail");
561                         g_variant_iter_free(options);
562                         icd_ioty_complete_error(type, invocation, IOTCON_ERROR_INVALID_PARAMETER);
563                         return TRUE;
564                 }
565                 break;
566         case ICD_CRUD_DELETE:
567                 snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
568                 uri = strdup(uri_buf);
569                 break;
570         }
571
572         cbdata.context = invocation;
573
574         options_size = g_variant_iter_n_children(options);
575         if (0 != options_size) {
576                 int ret = _ioty_get_header_options(options, options_size, oic_options,
577                                 sizeof(oic_options) / sizeof(oic_options[0]));
578                 if (IOTCON_ERROR_NONE != ret) {
579                         ERR("_ioty_get_header_options() Fail(%d)", ret);
580                         free(uri);
581                         g_variant_iter_free(options);
582                         icd_ioty_complete_error(type, invocation, ret);
583                         return TRUE;
584                 }
585                 oic_options_ptr = oic_options;
586         }
587         g_variant_iter_free(options);
588
589         icd_ioty_csdk_lock();
590         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
591         result = OCDoResource(NULL, rest_type, uri, NULL, repr, conn_type, OC_HIGH_QOS,
592                         &cbdata, oic_options_ptr, options_size);
593         icd_ioty_csdk_unlock();
594
595         free(uri);
596
597         if (OC_STACK_OK != result) {
598                 ERR("OCDoResource() Fail(%d)", result);
599                 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_IOTIVITY);
600                 return TRUE;
601         }
602
603         return TRUE;
604 }
605
606 gboolean icd_ioty_get(icDbus *object, GDBusMethodInvocation *invocation,
607                 GVariant *resource, GVariant *query)
608 {
609         FN_CALL;
610         return _icd_ioty_crud(ICD_CRUD_GET, object, invocation, resource, query, NULL);
611 }
612
613
614 gboolean icd_ioty_put(icDbus *object, GDBusMethodInvocation *invocation,
615                 GVariant *resource, const char *repr, GVariant *query)
616 {
617         FN_CALL;
618         return _icd_ioty_crud(ICD_CRUD_PUT, object, invocation, resource, query, repr);
619 }
620
621
622 gboolean icd_ioty_post(icDbus *object, GDBusMethodInvocation *invocation,
623                 GVariant *resource, const char *repr, GVariant *query)
624 {
625         FN_CALL;
626         return _icd_ioty_crud(ICD_CRUD_POST, object, invocation, resource, query, repr);
627 }
628
629
630 gboolean icd_ioty_delete(icDbus *object, GDBusMethodInvocation *invocation,
631                 GVariant *resource)
632 {
633         FN_CALL;
634         return _icd_ioty_crud(ICD_CRUD_DELETE, object, invocation, resource, NULL, NULL);
635 }
636
637
638 OCDoHandle icd_ioty_observer_start(GVariant *resource, int observe_type, GVariant *query,
639                 unsigned int signal_number, const char *bus_name)
640 {
641         OCMethod method;
642         OCDoHandle handle;
643         OCStackResult result;
644         GVariantIter *options;
645         icd_sig_ctx_s *context;
646         OCCallbackData cbdata = {0};
647         int conn_type, options_size;
648         char *uri_path, *host, *uri;
649         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
650         OCHeaderOption *oic_options_ptr = NULL;
651
652         g_variant_get(resource, "(&s&sa(qs)i)", &uri_path, &host, &options, &conn_type);
653
654         uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
655         if (NULL == uri) {
656                 ERR("_icd_ioty_resource_generate_uri() Fail");
657                 g_variant_iter_free(options);
658                 return NULL;
659         }
660
661         if (IOTCON_OBSERVE == observe_type)
662                 method = OC_REST_OBSERVE;
663         else if (IOTCON_OBSERVE_ALL == observe_type)
664                 method = OC_REST_OBSERVE_ALL;
665         else
666                 method = OC_REST_OBSERVE_ALL;
667
668         context = calloc(1, sizeof(icd_sig_ctx_s));
669         if (NULL == context) {
670                 ERR("calloc() Fail(%d)", errno);
671                 return NULL;
672         }
673         context->bus_name = ic_utils_strdup(bus_name);
674         context->signum = signal_number;
675
676         cbdata.context = context;
677         cbdata.cb = icd_ioty_ocprocess_observe_cb;
678         cbdata.cd = _ioty_free_signal_context;
679
680         options_size = g_variant_iter_n_children(options);
681         if (0 != options_size) {
682                 int ret = _ioty_get_header_options(options, options_size, oic_options,
683                                 sizeof(oic_options) / sizeof(oic_options[0]));
684                 if (IOTCON_ERROR_NONE != ret) {
685                         ERR("_ioty_get_header_options() Fail(%d)", ret);
686                         free(context->bus_name);
687                         free(context);
688                         free(uri);
689                         g_variant_iter_free(options);
690                         return NULL;
691                 }
692                 oic_options_ptr = oic_options;
693         }
694         g_variant_iter_free(options);
695
696         icd_ioty_csdk_lock();
697         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
698         result = OCDoResource(&handle, method, uri, NULL, NULL, conn_type, OC_HIGH_QOS,
699                         &cbdata, oic_options_ptr, options_size);
700         icd_ioty_csdk_unlock();
701         free(uri);
702         if (OC_STACK_OK != result) {
703                 ERR("OCDoResource() Fail(%d)", result);
704                 free(context->bus_name);
705                 free(context);
706                 return NULL;
707         }
708
709         return handle;
710 }
711
712
713 int icd_ioty_observer_stop(OCDoHandle handle, GVariant *options)
714 {
715         int options_size;
716         OCStackResult ret;
717         GVariantIter options_iter;
718         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
719         OCHeaderOption *oic_options_ptr = NULL;
720
721         g_variant_iter_init(&options_iter, options);
722
723         options_size = g_variant_iter_n_children(&options_iter);
724         if (0 != options_size) {
725                 int ret = _ioty_get_header_options(&options_iter, options_size, oic_options,
726                                 sizeof(oic_options) / sizeof(oic_options[0]));
727                 if (IOTCON_ERROR_NONE != ret) {
728                         ERR("_ioty_get_header_options() Fail(%d)", ret);
729                         return ret;
730                 }
731                 oic_options_ptr = oic_options;
732         }
733
734         icd_ioty_csdk_lock();
735         ret = OCCancel(handle, OC_HIGH_QOS, oic_options_ptr, options_size);
736         icd_ioty_csdk_unlock();
737         if (OC_STACK_OK != ret) {
738                 ERR("OCCancel() Fail(%d)", ret);
739                 return IOTCON_ERROR_IOTIVITY;
740         }
741
742         return IOTCON_ERROR_NONE;
743 }
744
745
746 #ifdef DEVICE_INFO_IMPL /* not implemented in iotivity 0.9.1 */
747 int icd_ioty_register_device_info(GVariant *value)
748 {
749         // TODO : To be implemented
750         return IOTCON_ERROR_NONE;
751 }
752
753
754 int icd_ioty_get_device_info(const char *host_address,
755                 unsigned int signal_number, const char *bus_name)
756 {
757         // TODO : To be implemented
758         return IOTCON_ERROR_NONE;
759 }
760 #endif
761
762
763 int icd_ioty_register_platform_info(GVariant *value)
764 {
765         // TODO : To be implemented
766         return IOTCON_ERROR_NONE;
767 }
768
769
770 int icd_ioty_get_platform_info(const char *host_address, unsigned int signal_number,
771                 const char *bus_name)
772 {
773         // TODO : To be implemented
774         return IOTCON_ERROR_NONE;
775 }
776
777
778 OCDoHandle icd_ioty_subscribe_presence(const char *host_address,
779                 const char *resource_type, unsigned int signal_number, const char *bus_name)
780 {
781         int len;
782         OCDoHandle handle;
783         OCStackResult result;
784         char uri[PATH_MAX] = {0};
785         OCCallbackData cbdata = {0};
786         icd_sig_ctx_s *context;
787         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
788
789         len = snprintf(uri, sizeof(uri), "%s%s", host_address, OC_PRESENCE_URI);
790         if (len <= 0 || sizeof(uri) <= len) {
791                 ERR("snprintf() Fail(%d)", len);
792                 return NULL;
793         }
794
795         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
796                 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
797
798         context = calloc(1, sizeof(icd_sig_ctx_s));
799         if (NULL == context) {
800                 ERR("calloc() Fail(%d)", errno);
801                 return NULL;
802         }
803         context->bus_name = ic_utils_strdup(bus_name);
804         context->signum = signal_number;
805
806         cbdata.context = context;
807         cbdata.cb = icd_ioty_ocprocess_presence_cb;
808         cbdata.cd = _ioty_free_signal_context;
809
810         /* TODO : OC_ALL has wrong behaviour in iotivity version 0.9.1.
811          * Therefore, OC_IPV4 SHOULD be changed to OC_ALL later.
812          */
813         icd_ioty_csdk_lock();
814         result = OCDoResource(&handle, OC_REST_PRESENCE, uri, NULL, NULL, conn_type,
815                         OC_LOW_QOS, &cbdata, NULL, 0);
816         icd_ioty_csdk_unlock();
817
818         if (OC_STACK_OK != result) {
819                 ERR("OCDoResource() Fail(%d)", result);
820                 free(context->bus_name);
821                 free(context);
822                 return NULL;
823         }
824         return handle;
825 }
826
827
828 int icd_ioty_unsubscribe_presence(OCDoHandle handle)
829 {
830         OCStackResult ret;
831
832         icd_ioty_csdk_lock();
833         ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);
834         icd_ioty_csdk_unlock();
835         if (OC_STACK_OK != ret) {
836                 ERR("OCCancel() Fail(%d)", ret);
837                 return IOTCON_ERROR_IOTIVITY;
838         }
839
840         return IOTCON_ERROR_NONE;
841 }
842
843
844 int icd_ioty_start_presence(unsigned int time_to_live)
845 {
846         OCStackResult ret;
847
848         icd_ioty_csdk_lock();
849         ret = OCStartPresence(time_to_live);
850         icd_ioty_csdk_unlock();
851         if (OC_STACK_OK != ret) {
852                 ERR("OCStartPresence() Fail(%d)", ret);
853                 return IOTCON_ERROR_IOTIVITY;
854         }
855
856         return IOTCON_ERROR_NONE;
857 }
858
859
860 int icd_ioty_stop_presence()
861 {
862         OCStackResult ret;
863
864         icd_ioty_csdk_lock();
865         ret = OCStopPresence();
866         icd_ioty_csdk_unlock();
867         if (OC_STACK_OK != ret) {
868                 ERR("OCStopPresence() Fail(%d)", ret);
869                 return IOTCON_ERROR_IOTIVITY;
870         }
871
872         return IOTCON_ERROR_NONE;
873 }