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>
31 #include "icd-ioty-repr.h"
33 #include "icd-ioty-ocprocess.h"
35 static GMutex icd_csdk_mutex;
37 void icd_ioty_csdk_lock()
39 g_mutex_lock(&icd_csdk_mutex);
43 void icd_ioty_csdk_unlock()
45 g_mutex_unlock(&icd_csdk_mutex);
49 GThread* icd_ioty_init(const char *addr, unsigned short port)
55 OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
56 if (OC_STACK_OK != result) {
57 ERR("OCInit() Fail(%d)", result);
61 DBG("OCInit() Success");
63 thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
66 ERR("g_thread_try_new() Fail(%s)", error->message);
75 void icd_ioty_deinit(GThread *thread)
79 icd_ioty_ocprocess_stop();
80 g_thread_join(thread);
83 if (OC_STACK_OK != result)
84 ERR("OCStop() Fail(%d)", result);
88 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
89 const char* const* res_types, int ifaces, uint8_t properties)
94 OCResourceHandle handle;
95 const char *resInterface = NULL;
97 if (IOTCON_INTERFACE_DEFAULT & ifaces) {
98 resInterface = IC_INTERFACE_DEFAULT;
99 ifaces ^= IOTCON_INTERFACE_DEFAULT;
100 } else if (IOTCON_INTERFACE_LINK & ifaces) {
101 resInterface = IC_INTERFACE_LINK;
102 ifaces ^= IOTCON_INTERFACE_LINK;
103 } else if (IOTCON_INTERFACE_BATCH & ifaces) {
104 resInterface = IC_INTERFACE_BATCH;
105 ifaces ^= IOTCON_INTERFACE_BATCH;
106 } else if (IOTCON_INTERFACE_GROUP & ifaces) {
107 resInterface = IC_INTERFACE_GROUP;
108 ifaces ^= IOTCON_INTERFACE_GROUP;
110 ERR("Invalid interface type(%d)", ifaces);
114 icd_ioty_csdk_lock();
115 ret = OCCreateResource(&handle, res_types[0], resInterface, uri_path,
116 icd_ioty_ocprocess_req_handler, properties);
117 icd_ioty_csdk_unlock();
118 if (OC_STACK_OK != ret) {
119 ERR("OCCreateResource() Fail(%d)", ret);
123 for (i = 1; res_types[i]; i++)
124 icd_ioty_bind_type(handle, res_types[i]);
126 if (IOTCON_INTERFACE_DEFAULT & ifaces)
127 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_DEFAULT);
128 if (IOTCON_INTERFACE_LINK & ifaces)
129 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_LINK);
130 if (IOTCON_INTERFACE_BATCH & ifaces)
131 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_BATCH);
132 if (IOTCON_INTERFACE_GROUP & ifaces)
133 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_GROUP);
139 int icd_ioty_unregister_resource(OCResourceHandle resource_handle)
143 icd_ioty_csdk_lock();
144 ret = OCDeleteResource(resource_handle);
145 icd_ioty_csdk_unlock();
146 if (OC_STACK_OK != ret) {
147 ERR("OCDeleteResource() Fail(%d)", ret);
148 return IOTCON_ERROR_IOTIVITY;
151 return IOTCON_ERROR_NONE;
155 static int _ioty_convert_interface_flag(iotcon_interface_e src, const char **dest)
158 case IOTCON_INTERFACE_DEFAULT:
159 *dest = IC_INTERFACE_DEFAULT;
161 case IOTCON_INTERFACE_LINK:
162 *dest = IC_INTERFACE_LINK;
164 case IOTCON_INTERFACE_BATCH:
165 *dest = IC_INTERFACE_BATCH;
167 case IOTCON_INTERFACE_GROUP:
168 *dest = IC_INTERFACE_GROUP;
170 case IOTCON_INTERFACE_NONE:
172 ERR("Invalid interface(%d)", src);
173 return IOTCON_ERROR_INVALID_PARAMETER;
175 return IOTCON_ERROR_NONE;
179 int icd_ioty_bind_interface(OCResourceHandle resourceHandle, iotcon_interface_e iface)
182 OCStackResult result;
183 const char *resource_interface;
185 ret = _ioty_convert_interface_flag(iface, &resource_interface);
186 if (IOTCON_ERROR_NONE != ret) {
187 ERR("_ioty_convert_interface_flag(%d) Fail(%d)", iface, ret);
191 icd_ioty_csdk_lock();
192 result = OCBindResourceInterfaceToResource(resourceHandle, resource_interface);
193 icd_ioty_csdk_unlock();
194 if (OC_STACK_OK != result) {
195 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
196 return IOTCON_ERROR_IOTIVITY;
199 return IOTCON_ERROR_NONE;
202 int icd_ioty_bind_type(OCResourceHandle resource_handle, const char *resource_type)
206 icd_ioty_csdk_lock();
207 ret = OCBindResourceTypeToResource(resource_handle, resource_type);
208 icd_ioty_csdk_unlock();
209 if (OC_STACK_OK != ret) {
210 ERR("OCBindResourceTypeToResource() Fail(%d)", ret);
211 return IOTCON_ERROR_IOTIVITY;
214 return IOTCON_ERROR_NONE;
218 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
222 icd_ioty_csdk_lock();
223 ret = OCBindResource(parent, child);
224 icd_ioty_csdk_unlock();
225 if (OC_STACK_OK != ret) {
226 ERR("OCBindResource() Fail(%d)", ret);
227 return IOTCON_ERROR_IOTIVITY;
230 return IOTCON_ERROR_NONE;
234 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
238 icd_ioty_csdk_lock();
239 ret = OCUnBindResource(parent, child);
240 icd_ioty_csdk_unlock();
241 if (OC_STACK_OK != ret) {
242 ERR("OCUnBindResource() Fail(%d)", ret);
243 return IOTCON_ERROR_IOTIVITY;
246 return IOTCON_ERROR_NONE;
250 int icd_ioty_notify_list_of_observers(void *handle, GVariant *msg, GVariant *observers)
252 int i, error_code, obs_length;
253 char *repr_json = NULL;
254 GVariantIter obs_iter, msg_iter;
257 g_variant_iter_init(&obs_iter, observers);
258 obs_length = g_variant_iter_n_children(&obs_iter);
260 /* Variable-length Array */
261 OCObservationId obs_ids[obs_length];
263 for (i = 0; i < obs_length; i++)
264 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
266 g_variant_iter_init(&msg_iter, msg);
267 g_variant_iter_loop(&msg_iter, "(i&s)", &error_code, &repr_json);
268 /* TODO : How to use error_code. */
270 icd_ioty_csdk_lock();
271 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
272 ret = OCNotifyListOfObservers(handle, obs_ids, obs_length, repr_json, OC_HIGH_QOS);
273 icd_ioty_csdk_unlock();
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("OCNotifyListOfObservers() Fail(%d)", ret);
280 return IOTCON_ERROR_IOTIVITY;
283 return IOTCON_ERROR_NONE;
287 int icd_ioty_notify_all(void *handle)
291 icd_ioty_csdk_lock();
292 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
293 ret = OCNotifyAllObservers(handle, OC_HIGH_QOS);
294 icd_ioty_csdk_unlock();
296 if (OC_STACK_NO_OBSERVERS == ret) {
297 WARN("No Observers. Stop Notifying");
298 return IOTCON_ERROR_NONE;
299 } else if (OC_STACK_OK != ret) {
300 ERR("OCNotifyAllObservers() Fail(%d)", ret);
301 return IOTCON_ERROR_IOTIVITY;
304 return IOTCON_ERROR_NONE;
308 static int _ioty_get_header_options(GVariantIter *src, int src_size,
309 OCHeaderOption dest[], int dest_size)
313 unsigned short option_id;
315 RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
317 if (dest_size < src_size) {
318 ERR("Exceed Size(%d)", src_size);
319 return IOTCON_ERROR_INVALID_PARAMETER;
322 while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
323 dest[i].protocolID = OC_COAP_ID;
324 dest[i].optionID = option_id;
325 dest[i].optionLength = strlen(option_data) + 1;
326 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
330 return IOTCON_ERROR_NONE;
334 int icd_ioty_send_response(GVariant *resp)
336 int result, error_code, options_size;
337 int request_handle, resource_handle;
338 char *new_uri_path, *repr_json;
339 GVariantIter *options;
341 OCEntityHandlerResponse response = {0};
343 g_variant_get(resp, "(&sia(qs)i&sii)",
352 response.requestHandle = GINT_TO_POINTER(request_handle);
353 response.resourceHandle = GINT_TO_POINTER(resource_handle);
354 response.ehResult = (OCEntityHandlerResult)result;
356 if (OC_EH_RESOURCE_CREATED == response.ehResult)
357 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
359 options_size = g_variant_iter_n_children(options);
360 response.numSendVendorSpecificHeaderOptions = options_size;
362 if (0 != options_size) {
363 int ret= _ioty_get_header_options(options,
364 response.numSendVendorSpecificHeaderOptions,
365 response.sendVendorSpecificHeaderOptions,
366 sizeof(response.sendVendorSpecificHeaderOptions)
367 / sizeof(response.sendVendorSpecificHeaderOptions[0]));
369 if (IOTCON_ERROR_NONE != ret)
370 ERR("_ioty_get_header_options() Fail(%d)", ret);
372 g_variant_iter_free(options);
374 response.payload = repr_json;
375 response.payloadSize = strlen(response.payload) + 1;
377 /* related to block transfer */
378 response.persistentBufferFlag = 0;
380 icd_ioty_csdk_lock();
381 ret = OCDoResponse(&response);
382 icd_ioty_csdk_unlock();
384 if (OC_STACK_OK != ret) {
385 ERR("OCDoResponse() Fail(%d)", ret);
386 return IOTCON_ERROR_IOTIVITY;
389 return IOTCON_ERROR_NONE;
393 static void _ioty_free_signal_context(void *data)
395 icd_sig_ctx_s *context = data;
396 free(context->sender);
400 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
401 unsigned int signum, const char *sender)
404 OCStackResult result;
405 OCCallbackData cbdata = {0};
406 icd_sig_ctx_s *context;
407 char uri[PATH_MAX] = {0};
408 iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
410 if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
411 len = snprintf(uri, sizeof(uri), "%s", OC_MULTICAST_DISCOVERY_URI);
412 conn_type = IOTCON_CONNECTIVITY_ALL;
414 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
415 OC_MULTICAST_DISCOVERY_URI);
417 if (len <= 0 || sizeof(uri) <= len) {
418 ERR("snprintf() Fail(%d)", len);
419 return IOTCON_ERROR_UNKNOWN;
422 if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
423 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
425 context = calloc(1, sizeof(icd_sig_ctx_s));
426 if (NULL == context) {
427 ERR("calloc() Fail(%d)", errno);
428 return IOTCON_ERROR_OUT_OF_MEMORY;
431 context->sender = ic_utils_strdup(sender);
432 context->signum = signum;
434 cbdata.context = context;
435 cbdata.cb = icd_ioty_ocprocess_find_cb;
436 cbdata.cd = _ioty_free_signal_context;
438 icd_ioty_csdk_lock();
439 result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_LOW_QOS,
441 icd_ioty_csdk_unlock();
443 if (OC_STACK_OK != result) {
444 ERR("OCDoResource() Fail(%d)", result);
445 free(context->sender);
447 return IOTCON_ERROR_IOTIVITY;
450 return IOTCON_ERROR_NONE;
455 * returned string SHOULD be released by you
457 static char* _icd_ioty_resource_generate_uri(char *host, char *uri_path, GVariant *query)
460 bool loop_first = true;
462 GVariantIter *queryIter;
463 char uri_buf[PATH_MAX] = {0};
465 len = snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
467 /* remove suffix '/' */
468 if ('/' == uri_buf[strlen(uri_buf) - 1]) {
469 uri_buf[strlen(uri_buf) - 1] = '\0';
473 g_variant_get(query, "a(ss)", &queryIter);
475 while (g_variant_iter_loop(queryIter, "(&s&s)", &key, &value)) {
478 DBG("query exist. key(%s), value(%s)", key, value);
480 if (true == loop_first) {
481 query_len = snprintf(uri_buf + len, sizeof(uri_buf), "?%s=%s", key, value);
484 query_len = snprintf(uri_buf + len, sizeof(uri_buf), "&%s=%s", key, value);
489 g_variant_iter_free(queryIter);
491 return strdup(uri_buf);
495 int icd_ioty_get(GVariant *resource, GVariant *query, unsigned int signal_number,
499 int conn_type, options_size;
500 char *uri_path, *host, *uri;
501 OCStackResult result;
502 GVariantIter *options;
503 OCCallbackData cbdata = {0};
504 icd_sig_ctx_s *context;
505 int is_observable, ifaces, observe_handle;
506 OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
508 g_variant_get(resource, "(&s&sba(qs)iii)", &uri_path, &host, &is_observable, &options,
509 &ifaces, &observe_handle, &conn_type);
511 uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
513 ERR("_icd_ioty_resource_generate_uri() Fail");
514 g_variant_iter_free(options);
515 return IOTCON_ERROR_INVALID_PARAMETER;
518 context = calloc(1, sizeof(icd_sig_ctx_s));
519 if (NULL == context) {
520 ERR("calloc() Fail(%d)", errno);
521 g_variant_iter_free(options);
522 return IOTCON_ERROR_OUT_OF_MEMORY;
524 context->sender = ic_utils_strdup(sender);
525 context->signum = signal_number;
527 cbdata.context = context;
528 cbdata.cb = icd_ioty_ocprocess_get_cb;
529 cbdata.cd = _ioty_free_signal_context;
531 options_size = g_variant_iter_n_children(options);
532 if (0 != options_size) {
533 int ret = _ioty_get_header_options(options, options_size, oic_options,
534 sizeof(oic_options) / sizeof(oic_options[0]));
535 if (IOTCON_ERROR_NONE != ret) {
536 ERR("_ioty_get_header_options() Fail(%d)", ret);
537 free(context->sender);
540 g_variant_iter_free(options);
544 g_variant_iter_free(options);
546 icd_ioty_csdk_lock();
547 /* TODO : QoS is come from lib. And user can set QoS to client structure. */
548 result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_HIGH_QOS,
549 &cbdata, options_size?oic_options:NULL, options_size);
550 icd_ioty_csdk_unlock();
554 if (OC_STACK_OK != result) {
555 ERR("OCDoResource() Fail(%d)", result);
556 free(context->sender);
558 return IOTCON_ERROR_IOTIVITY;
561 return IOTCON_ERROR_NONE;
565 int icd_ioty_put(GVariant *resource, const char *repr, GVariant *query,
566 unsigned int signal_number, const char *sender)
568 // TODO : To be implemented
569 return IOTCON_ERROR_NONE;
573 int icd_ioty_post(GVariant *resource, const char *repr, GVariant *query,
574 unsigned int signal_number, const char *sender)
576 // TODO : To be implemented
577 return IOTCON_ERROR_NONE;
581 int icd_ioty_delete(GVariant *resource, unsigned int signal_number,
584 // TODO : To be implemented
585 return IOTCON_ERROR_NONE;
589 int icd_ioty_observer_start(GVariant *resource, int observe_type,
590 GVariant *query, unsigned int signal_number, const char *sender, int *observe_h)
592 // TODO : To be implemented
593 return IOTCON_ERROR_NONE;
597 int icd_ioty_observer_stop(void *observe_h)
599 // TODO : To be implemented
600 return IOTCON_ERROR_NONE;
604 #ifdef DEVICE_INFO_IMPL /* not implemented in iotivity 0.9.1 */
605 int icd_ioty_register_device_info(GVariant *value)
607 // TODO : To be implemented
608 return IOTCON_ERROR_NONE;
612 int icd_ioty_get_device_info(const char *host_address,
613 unsigned int signal_number, const char *sender)
615 // TODO : To be implemented
616 return IOTCON_ERROR_NONE;
621 int icd_ioty_register_platform_info(GVariant *value)
623 // TODO : To be implemented
624 return IOTCON_ERROR_NONE;
628 int icd_ioty_get_platform_info(const char *host_address, unsigned int signal_number,
631 // TODO : To be implemented
632 return IOTCON_ERROR_NONE;
636 iotcon_presence_h icd_ioty_subscribe_presence(const char *host_address,
637 const char *resource_type, unsigned int signal_number, const char *sender)
639 // TODO : To be implemented
644 int icd_ioty_unsubscribe_presence(iotcon_presence_h presence_handle)
646 // TODO : To be implemented
647 return IOTCON_ERROR_NONE;
651 int icd_ioty_start_presence(unsigned int time_to_live)
653 // TODO : To be implemented
654 return IOTCON_ERROR_NONE;
658 int icd_ioty_stop_presence()
660 // TODO : To be implemented
661 return IOTCON_ERROR_NONE;