2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <stdint.h> /* for uint8_t etc */
23 #include <json-glib/json-glib.h>
34 #include "icd-ioty-ocprocess.h"
36 static GMutex icd_csdk_mutex;
38 void icd_ioty_csdk_lock()
40 g_mutex_lock(&icd_csdk_mutex);
44 void icd_ioty_csdk_unlock()
46 g_mutex_unlock(&icd_csdk_mutex);
50 GThread* icd_ioty_init(const char *addr, unsigned short port)
56 OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
57 if (OC_STACK_OK != result) {
58 ERR("OCInit() Fail(%d)", result);
62 DBG("OCInit() Success");
64 thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
67 ERR("g_thread_try_new() Fail(%s)", error->message);
76 void icd_ioty_deinit(GThread *thread)
80 icd_ioty_ocprocess_stop();
81 g_thread_join(thread);
84 if (OC_STACK_OK != result)
85 ERR("OCStop() Fail(%d)", result);
89 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
90 const char* const* res_types, int ifaces, uint8_t properties)
95 OCResourceHandle handle;
96 const char *resInterface = NULL;
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;
111 ERR("Invalid interface type(%d)", ifaces);
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);
124 for (i = 1; res_types[i]; i++)
125 icd_ioty_bind_type(handle, res_types[i]);
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);
140 int icd_ioty_unregister_resource(OCResourceHandle resource_handle)
144 icd_ioty_csdk_lock();
145 ret = OCDeleteResource(resource_handle);
146 icd_ioty_csdk_unlock();
147 if (OC_STACK_OK != ret) {
148 ERR("OCDeleteResource() Fail(%d)", ret);
149 return IOTCON_ERROR_IOTIVITY;
152 return IOTCON_ERROR_NONE;
156 int icd_ioty_bind_interface(OCResourceHandle resourceHandle, iotcon_interface_e iface)
159 OCStackResult result;
160 char *resource_interface;
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);
168 icd_ioty_csdk_lock();
169 result = OCBindResourceInterfaceToResource(resourceHandle, resource_interface);
170 icd_ioty_csdk_unlock();
171 if (OC_STACK_OK != result) {
172 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
173 return IOTCON_ERROR_IOTIVITY;
176 return IOTCON_ERROR_NONE;
180 int icd_ioty_bind_type(OCResourceHandle resource_handle, const char *resource_type)
184 icd_ioty_csdk_lock();
185 ret = OCBindResourceTypeToResource(resource_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;
192 return IOTCON_ERROR_NONE;
196 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
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;
208 return IOTCON_ERROR_NONE;
212 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
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;
224 return IOTCON_ERROR_NONE;
228 int icd_ioty_notify_list_of_observers(void *handle, GVariant *msg, GVariant *observers)
230 int i, error_code, obs_length;
231 char *repr_json = NULL;
232 GVariantIter obs_iter, msg_iter;
235 g_variant_iter_init(&obs_iter, observers);
236 obs_length = g_variant_iter_n_children(&obs_iter);
238 /* Variable-length Array */
239 OCObservationId obs_ids[obs_length];
241 for (i = 0; i < obs_length; i++)
242 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
244 g_variant_iter_init(&msg_iter, msg);
245 g_variant_iter_loop(&msg_iter, "(i&s)", &error_code, &repr_json);
246 /* TODO : How to use error_code. */
248 icd_ioty_csdk_lock();
249 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
250 ret = OCNotifyListOfObservers(handle, obs_ids, obs_length, repr_json, OC_HIGH_QOS);
251 icd_ioty_csdk_unlock();
253 if (OC_STACK_NO_OBSERVERS == ret) {
254 WARN("No Observers. Stop Notifying");
255 return IOTCON_ERROR_NONE;
256 } else if (OC_STACK_OK != ret) {
257 ERR("OCNotifyListOfObservers() Fail(%d)", ret);
258 return IOTCON_ERROR_IOTIVITY;
261 return IOTCON_ERROR_NONE;
265 int icd_ioty_notify_all(void *handle)
269 icd_ioty_csdk_lock();
270 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
271 ret = OCNotifyAllObservers(handle, OC_HIGH_QOS);
272 icd_ioty_csdk_unlock();
274 if (OC_STACK_NO_OBSERVERS == ret) {
275 WARN("No Observers. Stop Notifying");
276 return IOTCON_ERROR_NONE;
277 } else if (OC_STACK_OK != ret) {
278 ERR("OCNotifyAllObservers() Fail(%d)", ret);
279 return IOTCON_ERROR_IOTIVITY;
282 return IOTCON_ERROR_NONE;
286 static int _ioty_get_header_options(GVariantIter *src, int src_size,
287 OCHeaderOption dest[], int dest_size)
291 unsigned short option_id;
293 RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
295 if (dest_size < src_size) {
296 ERR("Exceed Size(%d)", src_size);
297 return IOTCON_ERROR_INVALID_PARAMETER;
300 while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
301 dest[i].protocolID = OC_COAP_ID;
302 dest[i].optionID = option_id;
303 dest[i].optionLength = strlen(option_data) + 1;
304 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
308 return IOTCON_ERROR_NONE;
312 int icd_ioty_send_response(GVariant *resp)
314 int result, error_code, options_size;
315 int request_handle, resource_handle;
316 char *new_uri_path, *repr_json;
317 GVariantIter *options;
319 OCEntityHandlerResponse response = {0};
321 g_variant_get(resp, "(&sia(qs)i&sii)",
330 response.requestHandle = GINT_TO_POINTER(request_handle);
331 response.resourceHandle = GINT_TO_POINTER(resource_handle);
332 response.ehResult = (OCEntityHandlerResult)result;
334 if (OC_EH_RESOURCE_CREATED == response.ehResult)
335 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
337 options_size = g_variant_iter_n_children(options);
338 response.numSendVendorSpecificHeaderOptions = options_size;
340 if (0 != options_size) {
341 int ret= _ioty_get_header_options(options,
342 response.numSendVendorSpecificHeaderOptions,
343 response.sendVendorSpecificHeaderOptions,
344 sizeof(response.sendVendorSpecificHeaderOptions)
345 / sizeof(response.sendVendorSpecificHeaderOptions[0]));
347 if (IOTCON_ERROR_NONE != ret)
348 ERR("_ioty_get_header_options() Fail(%d)", ret);
350 g_variant_iter_free(options);
352 response.payload = repr_json;
353 response.payloadSize = strlen(response.payload) + 1;
355 /* related to block transfer */
356 response.persistentBufferFlag = 0;
358 icd_ioty_csdk_lock();
359 ret = OCDoResponse(&response);
360 icd_ioty_csdk_unlock();
362 if (OC_STACK_OK != ret) {
363 ERR("OCDoResponse() Fail(%d)", ret);
364 return IOTCON_ERROR_IOTIVITY;
367 return IOTCON_ERROR_NONE;
371 static void _ioty_free_signal_context(void *data)
373 icd_sig_ctx_s *context = data;
374 free(context->bus_name);
378 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
379 unsigned int signum, const char *bus_name)
382 OCStackResult result;
383 OCCallbackData cbdata = {0};
384 icd_sig_ctx_s *context;
385 char uri[PATH_MAX] = {0};
386 iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
388 if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
389 len = snprintf(uri, sizeof(uri), "%s", OC_MULTICAST_DISCOVERY_URI);
390 conn_type = IOTCON_CONNECTIVITY_ALL;
392 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
393 OC_MULTICAST_DISCOVERY_URI);
395 if (len <= 0 || sizeof(uri) <= len) {
396 ERR("snprintf() Fail(%d)", len);
397 return IOTCON_ERROR_UNKNOWN;
400 if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
401 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
403 context = calloc(1, sizeof(icd_sig_ctx_s));
404 if (NULL == context) {
405 ERR("calloc() Fail(%d)", errno);
406 return IOTCON_ERROR_OUT_OF_MEMORY;
409 context->bus_name = ic_utils_strdup(bus_name);
410 context->signum = signum;
412 cbdata.context = context;
413 cbdata.cb = icd_ioty_ocprocess_find_cb;
414 cbdata.cd = _ioty_free_signal_context;
416 icd_ioty_csdk_lock();
417 result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_LOW_QOS,
419 icd_ioty_csdk_unlock();
421 if (OC_STACK_OK != result) {
422 ERR("OCDoResource() Fail(%d)", result);
423 free(context->bus_name);
425 return IOTCON_ERROR_IOTIVITY;
428 return IOTCON_ERROR_NONE;
433 * returned string SHOULD be released by you
435 static char* _icd_ioty_resource_generate_uri(char *host, char *uri_path, GVariant *query)
438 bool loop_first = true;
440 GVariantIter query_iter;
441 char uri_buf[PATH_MAX] = {0};
443 len = snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
445 /* remove suffix '/' */
446 if ('/' == uri_buf[strlen(uri_buf) - 1]) {
447 uri_buf[strlen(uri_buf) - 1] = '\0';
451 g_variant_iter_init(&query_iter, query);
453 while (g_variant_iter_loop(&query_iter, "(&s&s)", &key, &value)) {
456 DBG("query exist. key(%s), value(%s)", key, value);
458 if (true == loop_first) {
459 query_len = snprintf(uri_buf + len, sizeof(uri_buf), "?%s=%s", key, value);
462 query_len = snprintf(uri_buf + len, sizeof(uri_buf), "&%s=%s", key, value);
468 return strdup(uri_buf);
472 void icd_ioty_complete(int type, GDBusMethodInvocation *invocation, GVariant *value)
476 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
479 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
482 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
484 case ICD_CRUD_DELETE:
485 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
491 void icd_ioty_complete_error(int type, GDBusMethodInvocation *invocation, int ret_val)
497 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
498 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
501 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
502 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
505 value = g_variant_new("(a(qs)si)", NULL, IC_STR_NULL, ret_val);
506 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
508 case ICD_CRUD_DELETE:
509 value = g_variant_new("(a(qs)i)", NULL, ret_val);
510 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
516 static gboolean _icd_ioty_crud(int type, icDbus *object, GDBusMethodInvocation *invocation,
517 GVariant *resource, GVariant *query, const char *repr)
520 OCStackResult result;
521 GVariantIter *options;
522 OCCallbackData cbdata = {0};
523 int conn_type, options_size;
524 char *uri_path, *host, *uri;
525 char uri_buf[PATH_MAX] = {0};
526 OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
527 OCHeaderOption *oic_options_ptr = NULL;
531 cbdata.cb = icd_ioty_ocprocess_get_cb;
532 rest_type = OC_REST_GET;
535 cbdata.cb = icd_ioty_ocprocess_put_cb;
536 rest_type = OC_REST_PUT;
539 cbdata.cb = icd_ioty_ocprocess_post_cb;
540 rest_type = OC_REST_POST;
542 case ICD_CRUD_DELETE:
543 cbdata.cb = icd_ioty_ocprocess_delete_cb;
544 rest_type = OC_REST_DELETE;
547 ERR("Invalid CRUD Type(%d)", type);
551 g_variant_get(resource, "(&s&sa(qs)i)", &uri_path, &host, &options, &conn_type);
557 uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
559 ERR("_icd_ioty_resource_generate_uri() Fail");
560 g_variant_iter_free(options);
561 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_INVALID_PARAMETER);
565 case ICD_CRUD_DELETE:
566 snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
567 uri = strdup(uri_buf);
571 cbdata.context = invocation;
573 options_size = g_variant_iter_n_children(options);
574 if (0 != options_size) {
575 int ret = _ioty_get_header_options(options, options_size, oic_options,
576 sizeof(oic_options) / sizeof(oic_options[0]));
577 if (IOTCON_ERROR_NONE != ret) {
578 ERR("_ioty_get_header_options() Fail(%d)", ret);
580 g_variant_iter_free(options);
581 icd_ioty_complete_error(type, invocation, ret);
584 oic_options_ptr = oic_options;
586 g_variant_iter_free(options);
588 icd_ioty_csdk_lock();
589 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
590 result = OCDoResource(NULL, rest_type, uri, NULL, repr, conn_type, OC_HIGH_QOS,
591 &cbdata, oic_options_ptr, options_size);
592 icd_ioty_csdk_unlock();
596 if (OC_STACK_OK != result) {
597 ERR("OCDoResource() Fail(%d)", result);
598 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_IOTIVITY);
605 gboolean icd_ioty_get(icDbus *object, GDBusMethodInvocation *invocation,
606 GVariant *resource, GVariant *query)
609 return _icd_ioty_crud(ICD_CRUD_GET, object, invocation, resource, query, NULL);
613 gboolean icd_ioty_put(icDbus *object, GDBusMethodInvocation *invocation,
614 GVariant *resource, const char *repr, GVariant *query)
617 return _icd_ioty_crud(ICD_CRUD_PUT, object, invocation, resource, query, repr);
621 gboolean icd_ioty_post(icDbus *object, GDBusMethodInvocation *invocation,
622 GVariant *resource, const char *repr, GVariant *query)
625 return _icd_ioty_crud(ICD_CRUD_POST, object, invocation, resource, query, repr);
629 gboolean icd_ioty_delete(icDbus *object, GDBusMethodInvocation *invocation,
633 return _icd_ioty_crud(ICD_CRUD_DELETE, object, invocation, resource, NULL, NULL);
637 int icd_ioty_observer_start(GVariant *resource, int observe_type,
638 GVariant *query, unsigned int signal_number, const char *bus_name, int *observe_h)
640 // TODO : To be implemented
641 return IOTCON_ERROR_NONE;
645 int icd_ioty_observer_stop(void *observe_h)
647 // TODO : To be implemented
648 return IOTCON_ERROR_NONE;
652 #ifdef DEVICE_INFO_IMPL /* not implemented in iotivity 0.9.1 */
653 int icd_ioty_register_device_info(GVariant *value)
655 // TODO : To be implemented
656 return IOTCON_ERROR_NONE;
660 int icd_ioty_get_device_info(const char *host_address,
661 unsigned int signal_number, const char *bus_name)
663 // TODO : To be implemented
664 return IOTCON_ERROR_NONE;
669 int icd_ioty_register_platform_info(GVariant *value)
671 // TODO : To be implemented
672 return IOTCON_ERROR_NONE;
676 int icd_ioty_get_platform_info(const char *host_address, unsigned int signal_number,
677 const char *bus_name)
679 // TODO : To be implemented
680 return IOTCON_ERROR_NONE;
684 OCDoHandle icd_ioty_subscribe_presence(const char *host_address,
685 const char *resource_type, unsigned int signal_number, const char *bus_name)
687 // TODO : To be implemented
692 int icd_ioty_unsubscribe_presence(OCDoHandle presence_handle)
694 // TODO : To be implemented
695 return IOTCON_ERROR_NONE;
699 int icd_ioty_start_presence(unsigned int time_to_live)
701 // TODO : To be implemented
702 return IOTCON_ERROR_NONE;
706 int icd_ioty_stop_presence()
708 // TODO : To be implemented
709 return IOTCON_ERROR_NONE;