revise
[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
24 #include <octypes.h>
25 #include <ocstack.h>
26
27 #include "iotcon.h"
28 #include "ic-dbus.h"
29 #include "ic-utils.h"
30 #include "icd.h"
31 #include "icd-payload.h"
32 #include "icd-dbus.h"
33 #include "icd-ioty.h"
34 #include "icd-ioty-type.h"
35 #include "icd-ioty-ocprocess.h"
36
37 static GMutex icd_csdk_mutex;
38
39 void icd_ioty_csdk_lock()
40 {
41         g_mutex_lock(&icd_csdk_mutex);
42 }
43
44
45 void icd_ioty_csdk_unlock()
46 {
47         g_mutex_unlock(&icd_csdk_mutex);
48 }
49
50
51 GThread* icd_ioty_init(const char *addr, unsigned short port)
52 {
53         FN_CALL;
54         GError *error;
55         GThread *thread;
56
57         OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
58         if (OC_STACK_OK != result) {
59                 ERR("OCInit() Fail(%d)", result);
60                 return NULL;
61         }
62
63         DBG("OCInit() Success");
64
65         thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
66                         NULL, &error);
67         if (NULL == thread) {
68                 ERR("g_thread_try_new() Fail(%s)", error->message);
69                 g_error_free(error);
70                 return NULL;
71         }
72
73         return thread;
74 }
75
76
77 void icd_ioty_deinit(GThread *thread)
78 {
79         OCStackResult result;
80
81         icd_ioty_ocprocess_stop();
82         g_thread_join(thread);
83
84         result = OCStop();
85         if (OC_STACK_OK != result)
86                 ERR("OCStop() Fail(%d)", result);
87 }
88
89
90 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
91                 const char* const* res_types, int ifaces, uint8_t properties)
92 {
93         FN_CALL;
94         int i;
95         OCStackResult ret;
96         OCResourceHandle handle;
97         const char *res_iface = NULL;
98
99         if (IOTCON_INTERFACE_DEFAULT & ifaces) {
100                 res_iface = IC_INTERFACE_DEFAULT;
101                 ifaces ^= IOTCON_INTERFACE_DEFAULT;
102         } else if (IOTCON_INTERFACE_LINK & ifaces) {
103                 res_iface = IC_INTERFACE_LINK;
104                 ifaces ^= IOTCON_INTERFACE_LINK;
105         } else if (IOTCON_INTERFACE_BATCH & ifaces) {
106                 res_iface = IC_INTERFACE_BATCH;
107                 ifaces ^= IOTCON_INTERFACE_BATCH;
108         } else if (IOTCON_INTERFACE_GROUP & ifaces) {
109                 res_iface = IC_INTERFACE_GROUP;
110                 ifaces ^= IOTCON_INTERFACE_GROUP;
111         } else {
112                 ERR("Invalid interface type(%d)", ifaces);
113                 return NULL;
114         }
115
116         /* Secure option is not supported yet. */
117         properties = (properties & OC_SECURE)? (properties ^ OC_SECURE):properties;
118
119         icd_ioty_csdk_lock();
120         ret = OCCreateResource(&handle, res_types[0], res_iface, uri_path,
121                         icd_ioty_ocprocess_req_handler, NULL, properties);
122         icd_ioty_csdk_unlock();
123         if (OC_STACK_OK != ret) {
124                 ERR("OCCreateResource() Fail(%d)", ret);
125                 return NULL;
126         }
127
128         for (i = 1; res_types[i]; i++)
129                 icd_ioty_bind_type(handle, res_types[i]);
130
131         if (IOTCON_INTERFACE_DEFAULT & ifaces)
132                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_DEFAULT);
133         if (IOTCON_INTERFACE_LINK & ifaces)
134                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_LINK);
135         if (IOTCON_INTERFACE_BATCH & ifaces)
136                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_BATCH);
137         if (IOTCON_INTERFACE_GROUP & ifaces)
138                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_GROUP);
139
140         return handle;
141 }
142
143
144 int icd_ioty_unregister_resource(OCResourceHandle handle)
145 {
146         OCStackResult ret;
147
148         icd_ioty_csdk_lock();
149         ret = OCDeleteResource(handle);
150         icd_ioty_csdk_unlock();
151         if (OC_STACK_OK != ret) {
152                 ERR("OCDeleteResource() Fail(%d)", ret);
153                 return IOTCON_ERROR_IOTIVITY;
154         }
155
156         return IOTCON_ERROR_NONE;
157 }
158
159
160 int icd_ioty_bind_interface(OCResourceHandle handle, iotcon_interface_e iface)
161 {
162         int ret;
163         OCStackResult result;
164         char *resource_interface;
165
166         ret = ic_utils_convert_interface_flag(iface, &resource_interface);
167         if (IOTCON_ERROR_NONE != ret) {
168                 ERR("ic_utils_convert_interface_flag(%d) Fail(%d)", iface, ret);
169                 return ret;
170         }
171
172         icd_ioty_csdk_lock();
173         result = OCBindResourceInterfaceToResource(handle, resource_interface);
174         icd_ioty_csdk_unlock();
175         if (OC_STACK_OK != result) {
176                 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
177                 return IOTCON_ERROR_IOTIVITY;
178         }
179
180         return IOTCON_ERROR_NONE;
181 }
182
183
184 int icd_ioty_bind_type(OCResourceHandle handle, const char *resource_type)
185 {
186         OCStackResult ret;
187
188         icd_ioty_csdk_lock();
189         ret = OCBindResourceTypeToResource(handle, resource_type);
190         icd_ioty_csdk_unlock();
191         if (OC_STACK_OK != ret) {
192                 ERR("OCBindResourceTypeToResource() Fail(%d)", ret);
193                 return IOTCON_ERROR_IOTIVITY;
194         }
195
196         return IOTCON_ERROR_NONE;
197 }
198
199
200 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
201 {
202         OCStackResult ret;
203
204         icd_ioty_csdk_lock();
205         ret = OCBindResource(parent, child);
206         icd_ioty_csdk_unlock();
207         if (OC_STACK_OK != ret) {
208                 ERR("OCBindResource() Fail(%d)", ret);
209                 return IOTCON_ERROR_IOTIVITY;
210         }
211
212         return IOTCON_ERROR_NONE;
213 }
214
215
216 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
217 {
218         OCStackResult ret;
219
220         icd_ioty_csdk_lock();
221         ret = OCUnBindResource(parent, child);
222         icd_ioty_csdk_unlock();
223         if (OC_STACK_OK != ret) {
224                 ERR("OCUnBindResource() Fail(%d)", ret);
225                 return IOTCON_ERROR_IOTIVITY;
226         }
227
228         return IOTCON_ERROR_NONE;
229 }
230
231
232 int icd_ioty_notify_list_of_observers(OCResourceHandle handle, GVariant *msg,
233                 GVariant *observers)
234 {
235         int i, error_code, obs_length;
236         GVariant *repr_gvar;
237         GVariantIter obs_iter, msg_iter;
238         OCStackResult ret;
239         OCRepPayload *payload;
240
241         g_variant_iter_init(&obs_iter, observers);
242         obs_length = g_variant_iter_n_children(&obs_iter);
243
244         /* Variable-length Array */
245         OCObservationId obs_ids[obs_length];
246
247         for (i = 0; i < obs_length; i++)
248                 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
249
250         g_variant_iter_init(&msg_iter, msg);
251         g_variant_iter_loop(&msg_iter, "(iv)", &error_code, &repr_gvar);
252         /* TODO : How to use error_code. */
253
254         payload = icd_payload_representation_from_gvariant(repr_gvar);
255
256         icd_ioty_csdk_lock();
257         /* TODO : QoS is come from lib. */
258         ret = OCNotifyListOfObservers(handle, obs_ids, obs_length, payload, OC_LOW_QOS);
259         icd_ioty_csdk_unlock();
260
261         if (OC_STACK_NO_OBSERVERS == ret) {
262                 WARN("No Observers. Stop Notifying");
263                 return IOTCON_ERROR_NONE;
264         } else if (OC_STACK_OK != ret) {
265                 ERR("OCNotifyListOfObservers() Fail(%d)", ret);
266                 return IOTCON_ERROR_IOTIVITY;
267         }
268
269         return IOTCON_ERROR_NONE;
270 }
271
272
273 int icd_ioty_notify_all(OCResourceHandle handle)
274 {
275         OCStackResult ret;
276
277         icd_ioty_csdk_lock();
278         /* TODO : QoS is come from lib. */
279         ret = OCNotifyAllObservers(handle, OC_LOW_QOS);
280         icd_ioty_csdk_unlock();
281
282         if (OC_STACK_NO_OBSERVERS == ret) {
283                 WARN("No Observers. Stop Notifying");
284                 return IOTCON_ERROR_NONE;
285         } else if (OC_STACK_OK != ret) {
286                 ERR("OCNotifyAllObservers() Fail(%d)", ret);
287                 return IOTCON_ERROR_IOTIVITY;
288         }
289
290         return IOTCON_ERROR_NONE;
291 }
292
293
294 static int _ioty_get_header_options(GVariantIter *src, int src_size,
295                 OCHeaderOption dest[], int dest_size)
296 {
297         int i = 0;
298         char *option_data;
299         unsigned short option_id;
300
301         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
302
303         if (dest_size < src_size) {
304                 ERR("Exceed Size(%d)", src_size);
305                 return IOTCON_ERROR_INVALID_PARAMETER;
306         }
307
308         while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
309                 dest[i].protocolID = OC_COAP_ID;
310                 dest[i].optionID = option_id;
311                 dest[i].optionLength = strlen(option_data) + 1;
312                 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
313                 i++;
314         }
315
316         return IOTCON_ERROR_NONE;
317 }
318
319
320 int icd_ioty_send_response(GVariant *resp)
321 {
322         char *new_uri_path;
323         GVariant *repr_gvar;
324         GVariantIter *options;
325         OCStackResult ret;
326         OCEntityHandlerResponse response = {0};
327         int result, error_code, options_size;
328         int64_t request_handle, resource_handle;
329
330         g_variant_get(resp, "(&sia(qs)ivxx)",
331                         &new_uri_path,
332                         &error_code,
333                         &options,
334                         &result,
335                         &repr_gvar,
336                         &request_handle,
337                         &resource_handle);
338
339         response.requestHandle = ICD_INT64_TO_POINTER(request_handle);
340         response.resourceHandle = ICD_INT64_TO_POINTER(resource_handle);
341         response.ehResult = (OCEntityHandlerResult)result;
342
343         if (OC_EH_RESOURCE_CREATED == response.ehResult)
344                 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
345
346         options_size = g_variant_iter_n_children(options);
347         response.numSendVendorSpecificHeaderOptions = options_size;
348
349         if (0 != options_size) {
350                 int ret= _ioty_get_header_options(options,
351                                 response.numSendVendorSpecificHeaderOptions,
352                                 response.sendVendorSpecificHeaderOptions,
353                                 sizeof(response.sendVendorSpecificHeaderOptions)
354                                 / sizeof(response.sendVendorSpecificHeaderOptions[0]));
355
356                 if (IOTCON_ERROR_NONE != ret)
357                         ERR("_ioty_get_header_options() Fail(%d)", ret);
358         }
359         g_variant_iter_free(options);
360
361         response.payload = (OCPayload*)icd_payload_representation_from_gvariant(repr_gvar);
362
363         /* related to block transfer */
364         response.persistentBufferFlag = 0;
365
366         icd_ioty_csdk_lock();
367         ret = OCDoResponse(&response);
368         icd_ioty_csdk_unlock();
369
370         if (OC_STACK_OK != ret) {
371                 ERR("OCDoResponse() Fail(%d)", ret);
372                 return IOTCON_ERROR_IOTIVITY;
373         }
374
375         return IOTCON_ERROR_NONE;
376 }
377
378
379 static void _ioty_free_signal_context(void *data)
380 {
381         icd_sig_ctx_s *context = data;
382         free(context->bus_name);
383         free(context);
384 }
385
386
387 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
388                 unsigned int signum, const char *bus_name)
389 {
390         int len;
391         OCStackResult result;
392         icd_sig_ctx_s *context;
393         char uri[PATH_MAX] = {0};
394         OCCallbackData cbdata = {0};
395         OCConnectivityType oic_conn_type;
396         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
397
398         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
399                 len = snprintf(uri, sizeof(uri), "%s", OC_RSRVD_WELL_KNOWN_URI);
400         } else {
401                 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
402                                 OC_RSRVD_WELL_KNOWN_URI);
403         }
404         if (len <= 0 || sizeof(uri) <= len) {
405                 ERR("snprintf() Fail(%d)", len);
406                 return IOTCON_ERROR_IO_ERROR;
407         }
408
409         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
410                 snprintf(uri + len, sizeof(uri) - len, "?rt=%s", resource_type);
411
412         context = calloc(1, sizeof(icd_sig_ctx_s));
413         if (NULL == context) {
414                 ERR("calloc() Fail(%d)", errno);
415                 return IOTCON_ERROR_OUT_OF_MEMORY;
416         }
417
418         context->bus_name = ic_utils_strdup(bus_name);
419         context->signum = signum;
420
421         cbdata.context = context;
422         cbdata.cb = icd_ioty_ocprocess_find_cb;
423         cbdata.cd = _ioty_free_signal_context;
424
425         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
426
427         icd_ioty_csdk_lock();
428         /* TODO : QoS is come from lib. */
429         result = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL, oic_conn_type,
430                         OC_LOW_QOS, &cbdata, NULL, 0);
431         icd_ioty_csdk_unlock();
432
433         if (OC_STACK_OK != result) {
434                 ERR("OCDoResource() Fail(%d)", result);
435                 free(context->bus_name);
436                 free(context);
437                 return IOTCON_ERROR_IOTIVITY;
438         }
439
440         return IOTCON_ERROR_NONE;
441 }
442
443
444 /*
445  * returned string SHOULD be released by you
446  */
447 static char* _icd_ioty_resource_generate_uri(char *uri_path, GVariant *query)
448 {
449         int len;
450         bool loop_first = true;
451         char *key, *value;
452         GVariantIter query_iter;
453         char uri_buf[PATH_MAX] = {0};
454
455         len = snprintf(uri_buf, sizeof(uri_buf), "%s", uri_path);
456
457         /* remove suffix '/' */
458         if ('/' == uri_buf[strlen(uri_buf) - 1]) {
459                 uri_buf[strlen(uri_buf) - 1] = '\0';
460                 len--;
461         }
462
463         g_variant_iter_init(&query_iter, query);
464
465         while (g_variant_iter_loop(&query_iter, "(&s&s)", &key, &value)) {
466                 int query_len;
467
468                 DBG("query exist. key(%s), value(%s)", key, value);
469
470                 if (true == loop_first) {
471                         query_len = snprintf(uri_buf + len, sizeof(uri_buf) - len, "?%s=%s", key, value);
472                         loop_first = false;
473                 } else {
474                         query_len = snprintf(uri_buf + len, sizeof(uri_buf) - len, "&%s=%s", key, value);
475                 }
476
477                 len += query_len;
478         }
479
480         return strdup(uri_buf);
481 }
482
483
484 void icd_ioty_complete(int type, GDBusMethodInvocation *invocation, GVariant *value)
485 {
486         switch(type) {
487         case ICD_CRUD_GET:
488                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
489                 break;
490         case ICD_CRUD_PUT:
491                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
492                 break;
493         case ICD_CRUD_POST:
494                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
495                 break;
496         case ICD_CRUD_DELETE:
497                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
498                 break;
499         }
500 }
501
502
503 void icd_ioty_complete_error(int type, GDBusMethodInvocation *invocation, int ret_val)
504 {
505         GVariant *value;
506
507         switch (type) {
508         case ICD_CRUD_GET:
509                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
510                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
511                 break;
512         case ICD_CRUD_PUT:
513                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
514                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
515                 break;
516         case ICD_CRUD_POST:
517                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
518                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
519                 break;
520         case ICD_CRUD_DELETE:
521                 value = g_variant_new("(a(qs)i)", NULL, ret_val);
522                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
523                 break;
524         }
525 }
526
527
528 static gboolean _icd_ioty_crud(int type, icDbus *object, GDBusMethodInvocation *invocation,
529                 GVariant *resource, GVariant *query, GVariant *repr)
530 {
531         bool is_secure;
532         OCMethod rest_type;
533         OCStackResult result;
534         GVariantIter *options;
535         OCCallbackData cbdata = {0};
536         int conn_type, options_size;
537         char *uri_path, *host, *uri, *dev_host, *ptr = NULL;
538         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
539         OCHeaderOption *oic_options_ptr = NULL;
540         OCPayload *payload = NULL;
541         OCConnectivityType oic_conn_type;
542         OCDevAddr dev_addr = {0};
543
544         switch (type) {
545         case ICD_CRUD_GET:
546                 cbdata.cb = icd_ioty_ocprocess_get_cb;
547                 rest_type = OC_REST_GET;
548                 break;
549         case ICD_CRUD_PUT:
550                 cbdata.cb = icd_ioty_ocprocess_put_cb;
551                 rest_type = OC_REST_PUT;
552                 break;
553         case ICD_CRUD_POST:
554                 cbdata.cb = icd_ioty_ocprocess_post_cb;
555                 rest_type = OC_REST_POST;
556                 break;
557         case ICD_CRUD_DELETE:
558                 cbdata.cb = icd_ioty_ocprocess_delete_cb;
559                 rest_type = OC_REST_DELETE;
560                 break;
561         default:
562                 ERR("Invalid CRUD Type(%d)", type);
563                 return FALSE;
564         }
565
566         g_variant_get(resource, "(&s&sba(qs)i)", &uri_path, &host, &is_secure, &options,
567                         &conn_type);
568
569         switch (type) {
570         case ICD_CRUD_GET:
571         case ICD_CRUD_PUT:
572         case ICD_CRUD_POST:
573                 uri = _icd_ioty_resource_generate_uri(uri_path, query);
574                 if (NULL == uri) {
575                         ERR("_icd_ioty_resource_generate_uri() Fail");
576                         g_variant_iter_free(options);
577                         icd_ioty_complete_error(type, invocation, IOTCON_ERROR_INVALID_PARAMETER);
578                         return TRUE;
579                 }
580                 break;
581         case ICD_CRUD_DELETE:
582                 uri = strdup(uri_path);
583                 break;
584         }
585
586         cbdata.context = invocation;
587
588         options_size = g_variant_iter_n_children(options);
589         if (0 != options_size) {
590                 int ret = _ioty_get_header_options(options, options_size, oic_options,
591                                 sizeof(oic_options) / sizeof(oic_options[0]));
592                 if (IOTCON_ERROR_NONE != ret) {
593                         ERR("_ioty_get_header_options() Fail(%d)", ret);
594                         free(uri);
595                         g_variant_iter_free(options);
596                         icd_ioty_complete_error(type, invocation, ret);
597                         return TRUE;
598                 }
599                 oic_options_ptr = oic_options;
600         }
601         g_variant_iter_free(options);
602
603         if (repr)
604                 payload = (OCPayload*)icd_payload_representation_from_gvariant(repr);
605
606         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
607
608         icd_ioty_conn_type_to_oic_transport_type(conn_type, &dev_addr.adapter,
609                         &dev_addr.flags);
610
611         switch (conn_type) {
612         case IOTCON_CONNECTIVITY_IPV4:
613                 dev_host = strtok_r(host, ":", &ptr);
614                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
615                 dev_addr.port = atoi(strtok_r(NULL, ":", &ptr));
616                 break;
617         case IOTCON_CONNECTIVITY_IPV6:
618                 dev_host = strtok_r(host, "]", &ptr);
619                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
620                 dev_addr.port = atoi(strtok_r(NULL, "]", &ptr));
621                 break;
622         default:
623                 ERR("Invalid Connectivitiy Type");
624                 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_IOTIVITY);
625                 free(uri);
626                 return TRUE;
627         }
628
629         icd_ioty_csdk_lock();
630         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
631         result = OCDoResource(NULL, rest_type, uri, &dev_addr, payload, oic_conn_type,
632                         OC_LOW_QOS, &cbdata, oic_options_ptr, options_size);
633         icd_ioty_csdk_unlock();
634
635         free(uri);
636
637         if (OC_STACK_OK != result) {
638                 ERR("OCDoResource() Fail(%d)", result);
639                 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_IOTIVITY);
640                 return TRUE;
641         }
642
643         return TRUE;
644 }
645
646 gboolean icd_ioty_get(icDbus *object, GDBusMethodInvocation *invocation,
647                 GVariant *resource, GVariant *query)
648 {
649         return _icd_ioty_crud(ICD_CRUD_GET, object, invocation, resource, query, NULL);
650 }
651
652
653 gboolean icd_ioty_put(icDbus *object, GDBusMethodInvocation *invocation,
654                 GVariant *resource, GVariant *repr, GVariant *query)
655 {
656         return _icd_ioty_crud(ICD_CRUD_PUT, object, invocation, resource, query, repr);
657 }
658
659
660 gboolean icd_ioty_post(icDbus *object, GDBusMethodInvocation *invocation,
661                 GVariant *resource, GVariant *repr, GVariant *query)
662 {
663         return _icd_ioty_crud(ICD_CRUD_POST, object, invocation, resource, query, repr);
664 }
665
666
667 gboolean icd_ioty_delete(icDbus *object, GDBusMethodInvocation *invocation,
668                 GVariant *resource)
669 {
670         return _icd_ioty_crud(ICD_CRUD_DELETE, object, invocation, resource, NULL, NULL);
671 }
672
673
674 OCDoHandle icd_ioty_observer_start(GVariant *resource, int observe_type, GVariant *query,
675                 unsigned int signal_number, const char *bus_name)
676 {
677         bool is_secure;
678         OCMethod method;
679         OCDoHandle handle;
680         OCStackResult result;
681         GVariantIter *options;
682         icd_sig_ctx_s *context;
683         OCCallbackData cbdata = {0};
684         int conn_type, options_size;
685         char *uri_path, *host, *uri, *dev_host, *ptr = NULL;
686         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
687         OCHeaderOption *oic_options_ptr = NULL;
688         OCConnectivityType oic_conn_type;
689         OCDevAddr dev_addr = {0};
690
691         g_variant_get(resource, "(&s&sba(qs)i)", &uri_path, &host, &is_secure, &options,
692                         &conn_type);
693
694         uri = _icd_ioty_resource_generate_uri(uri_path, query);
695         if (NULL == uri) {
696                 ERR("_icd_ioty_resource_generate_uri() Fail");
697                 g_variant_iter_free(options);
698                 return NULL;
699         }
700
701         if (IOTCON_OBSERVE == observe_type)
702                 method = OC_REST_OBSERVE;
703         else if (IOTCON_OBSERVE_ALL == observe_type)
704                 method = OC_REST_OBSERVE_ALL;
705         else
706                 method = OC_REST_OBSERVE_ALL;
707
708         context = calloc(1, sizeof(icd_sig_ctx_s));
709         if (NULL == context) {
710                 ERR("calloc() Fail(%d)", errno);
711                 return NULL;
712         }
713         context->bus_name = ic_utils_strdup(bus_name);
714         context->signum = signal_number;
715
716         cbdata.context = context;
717         cbdata.cb = icd_ioty_ocprocess_observe_cb;
718         cbdata.cd = _ioty_free_signal_context;
719
720         options_size = g_variant_iter_n_children(options);
721         if (0 != options_size) {
722                 int ret = _ioty_get_header_options(options, options_size, oic_options,
723                                 sizeof(oic_options) / sizeof(oic_options[0]));
724                 if (IOTCON_ERROR_NONE != ret) {
725                         ERR("_ioty_get_header_options() Fail(%d)", ret);
726                         free(context->bus_name);
727                         free(context);
728                         free(uri);
729                         g_variant_iter_free(options);
730                         return NULL;
731                 }
732                 oic_options_ptr = oic_options;
733         }
734         g_variant_iter_free(options);
735
736         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
737
738         icd_ioty_conn_type_to_oic_transport_type(conn_type, &dev_addr.adapter,
739                         &dev_addr.flags);
740
741         switch (conn_type) {
742         case IOTCON_CONNECTIVITY_IPV4:
743                 dev_host = strtok_r(host, ":", &ptr);
744                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
745                 dev_addr.port = atoi(strtok_r(NULL, ":", &ptr));
746                 break;
747         case IOTCON_CONNECTIVITY_IPV6:
748                 dev_host = strtok_r(host, "]", &ptr);
749                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
750                 dev_addr.port = atoi(strtok_r(NULL, "]", &ptr));
751                 break;
752         default:
753                 ERR("Invalid Connectivitiy Type");
754                 free(context->bus_name);
755                 free(context);
756                 free(uri);
757                 return NULL;
758         }
759
760         icd_ioty_csdk_lock();
761         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
762         result = OCDoResource(&handle, method, uri, &dev_addr, NULL, oic_conn_type,
763                         OC_LOW_QOS, &cbdata, oic_options_ptr, options_size);
764         icd_ioty_csdk_unlock();
765         free(uri);
766         if (OC_STACK_OK != result) {
767                 ERR("OCDoResource() Fail(%d)", result);
768                 free(context->bus_name);
769                 free(context);
770                 return NULL;
771         }
772
773         return handle;
774 }
775
776
777 int icd_ioty_observer_stop(OCDoHandle handle, GVariant *options)
778 {
779         int options_size;
780         OCStackResult ret;
781         GVariantIter options_iter;
782         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
783         OCHeaderOption *oic_options_ptr = NULL;
784
785         g_variant_iter_init(&options_iter, options);
786
787         options_size = g_variant_iter_n_children(&options_iter);
788         if (0 != options_size) {
789                 int ret = _ioty_get_header_options(&options_iter, options_size, oic_options,
790                                 sizeof(oic_options) / sizeof(oic_options[0]));
791                 if (IOTCON_ERROR_NONE != ret) {
792                         ERR("_ioty_get_header_options() Fail(%d)", ret);
793                         return ret;
794                 }
795                 oic_options_ptr = oic_options;
796         }
797
798         icd_ioty_csdk_lock();
799         ret = OCCancel(handle, OC_HIGH_QOS, oic_options_ptr, options_size);
800         icd_ioty_csdk_unlock();
801         if (OC_STACK_OK != ret) {
802                 ERR("OCCancel() Fail(%d)", ret);
803                 return IOTCON_ERROR_IOTIVITY;
804         }
805
806         return IOTCON_ERROR_NONE;
807 }
808
809
810 int icd_ioty_register_device_info(GVariant *value)
811 {
812         OCStackResult result;
813         OCDeviceInfo device_info = {0};
814
815         g_variant_get(value, "(&s)", &device_info.deviceName);
816
817         icd_ioty_csdk_lock();
818         result = OCSetDeviceInfo(device_info);
819         icd_ioty_csdk_unlock();
820
821         if (OC_STACK_OK != result) {
822                 ERR("OCSetDeviceInfo() Fail(%d)", result);
823                 return IOTCON_ERROR_IOTIVITY;
824         }
825
826         return IOTCON_ERROR_NONE;
827 }
828
829
830 int icd_ioty_register_platform_info(GVariant *value)
831 {
832         OCStackResult result;
833         OCPlatformInfo platform_info = {0};
834
835         g_variant_get(value, "(&s&s&s&s&s&s&s&s&s&s&s)",
836                         &platform_info.platformID,
837                         &platform_info.manufacturerName,
838                         &platform_info.manufacturerUrl,
839                         &platform_info.modelNumber,
840                         &platform_info.dateOfManufacture,
841                         &platform_info.platformVersion,
842                         &platform_info.operatingSystemVersion,
843                         &platform_info.hardwareVersion,
844                         &platform_info.firmwareVersion,
845                         &platform_info.supportUrl,
846                         &platform_info.systemTime);
847
848         icd_ioty_csdk_lock();
849         result = OCSetPlatformInfo(platform_info);
850         icd_ioty_csdk_unlock();
851
852         if (OC_STACK_OK != result) {
853                 ERR("OCSetPlatformInfo() Fail(%d)", result);
854                 return IOTCON_ERROR_IOTIVITY;
855         }
856
857         return IOTCON_ERROR_NONE;
858 }
859
860
861 int icd_ioty_get_info(int type, const char *host_address, unsigned int signal_number,
862                 const char *bus_name)
863 {
864         OCStackResult result;
865         icd_sig_ctx_s *context;
866         OCCallbackData cbdata = {0};
867         char uri[PATH_MAX] = {0};
868         char *uri_path = NULL;
869         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
870         OCConnectivityType oic_conn_type;
871
872         if (ICD_DEVICE_INFO == type)
873                 uri_path = OC_RSRVD_DEVICE_URI;
874         else if (ICD_PLATFORM_INFO == type)
875                 uri_path = OC_RSRVD_PLATFORM_URI;
876         else
877                 return IOTCON_ERROR_INVALID_PARAMETER;
878
879         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address))
880                 snprintf(uri, sizeof(uri), "%s", uri_path);
881         else
882                 snprintf(uri, sizeof(uri), "%s%s", host_address, uri_path);
883
884         context = calloc(1, sizeof(icd_sig_ctx_s));
885         if (NULL == context) {
886                 ERR("calloc() Fail(%d)", errno);
887                 return IOTCON_ERROR_OUT_OF_MEMORY;
888         }
889         context->bus_name = ic_utils_strdup(bus_name);
890         context->signum = signal_number;
891
892         cbdata.context = context;
893         cbdata.cb = icd_ioty_ocprocess_info_cb;
894         cbdata.cd = _ioty_free_signal_context;
895
896         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
897
898         icd_ioty_csdk_lock();
899         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
900         result = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL, oic_conn_type,
901                         OC_LOW_QOS, &cbdata, NULL, 0);
902         icd_ioty_csdk_unlock();
903
904         if (OC_STACK_OK != result) {
905                 ERR("OCDoResource() Fail(%d)", result);
906                 free(context->bus_name);
907                 free(context);
908                 return IOTCON_ERROR_IOTIVITY;
909         }
910
911         return IOTCON_ERROR_NONE;
912 }
913
914
915 OCDoHandle icd_ioty_subscribe_presence(const char *host_address,
916                 const char *resource_type, unsigned int signal_number, const char *bus_name)
917 {
918         int len;
919         OCDoHandle handle;
920         OCStackResult result;
921         char uri[PATH_MAX] = {0};
922         OCCallbackData cbdata = {0};
923         icd_sig_ctx_s *context;
924
925         len = snprintf(uri, sizeof(uri), "%s%s", host_address, OC_RSRVD_PRESENCE_URI);
926         if (len <= 0 || sizeof(uri) <= len) {
927                 ERR("snprintf() Fail(%d)", len);
928                 return NULL;
929         }
930
931         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
932                 snprintf(uri + len, sizeof(uri) - len, "?rt=%s", resource_type);
933
934         context = calloc(1, sizeof(icd_sig_ctx_s));
935         if (NULL == context) {
936                 ERR("calloc() Fail(%d)", errno);
937                 return NULL;
938         }
939         context->bus_name = ic_utils_strdup(bus_name);
940         context->signum = signal_number;
941
942         cbdata.context = context;
943         cbdata.cb = icd_ioty_ocprocess_presence_cb;
944         cbdata.cd = _ioty_free_signal_context;
945
946         /* In case of IPV4 or IPV6, connectivity type is CT_ADAPTER_IP in iotivity 0.9.2 */
947         icd_ioty_csdk_lock();
948         result = OCDoResource(&handle, OC_REST_PRESENCE, uri, NULL, NULL, CT_ADAPTER_IP,
949                         OC_LOW_QOS, &cbdata, NULL, 0);
950         icd_ioty_csdk_unlock();
951
952         if (OC_STACK_OK != result) {
953                 ERR("OCDoResource() Fail(%d)", result);
954                 free(context->bus_name);
955                 free(context);
956                 return NULL;
957         }
958         return handle;
959 }
960
961
962 int icd_ioty_unsubscribe_presence(OCDoHandle handle)
963 {
964         OCStackResult ret;
965
966         icd_ioty_csdk_lock();
967         ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);
968         icd_ioty_csdk_unlock();
969         if (OC_STACK_OK != ret) {
970                 ERR("OCCancel() Fail(%d)", ret);
971                 return IOTCON_ERROR_IOTIVITY;
972         }
973
974         return IOTCON_ERROR_NONE;
975 }
976
977
978 int icd_ioty_start_presence(unsigned int time_to_live)
979 {
980         OCStackResult ret;
981
982         icd_ioty_csdk_lock();
983         ret = OCStartPresence(time_to_live);
984         icd_ioty_csdk_unlock();
985         if (OC_STACK_OK != ret) {
986                 ERR("OCStartPresence() Fail(%d)", ret);
987                 return IOTCON_ERROR_IOTIVITY;
988         }
989
990         return IOTCON_ERROR_NONE;
991 }
992
993
994 int icd_ioty_stop_presence()
995 {
996         OCStackResult ret;
997
998         icd_ioty_csdk_lock();
999         ret = OCStopPresence();
1000         icd_ioty_csdk_unlock();
1001         if (OC_STACK_OK != ret) {
1002                 ERR("OCStopPresence() Fail(%d)", ret);
1003                 return IOTCON_ERROR_IOTIVITY;
1004         }
1005
1006         return IOTCON_ERROR_NONE;
1007 }