apply Serverside functions related to resource
[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-utils.h"
30 #include "icd.h"
31 #include "icd-ioty-repr.h"
32 #include "icd-ioty.h"
33 #include "icd-ioty-ocprocess.h"
34
35 static GMutex icd_csdk_mutex;
36
37 void icd_ioty_csdk_lock()
38 {
39         g_mutex_lock(&icd_csdk_mutex);
40 }
41
42
43 void icd_ioty_csdk_unlock()
44 {
45         g_mutex_unlock(&icd_csdk_mutex);
46 }
47
48
49 GThread* icd_ioty_init(const char *addr, unsigned short port)
50 {
51         FN_CALL;
52         GError *error;
53         GThread *thread;
54
55         OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
56         if (OC_STACK_OK != result) {
57                 ERR("OCInit() Fail(%d)", result);
58                 return NULL;
59         }
60
61         DBG("OCInit() Success");
62
63         thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
64                         NULL, &error);
65         if (NULL == thread) {
66                 ERR("g_thread_try_new() Fail(%s)", error->message);
67                 g_error_free(error);
68                 return NULL;
69         }
70
71         return thread;
72 }
73
74
75 void icd_ioty_deinit(GThread *thread)
76 {
77         OCStackResult result;
78
79         icd_ioty_ocprocess_stop();
80         g_thread_join(thread);
81
82         result = OCStop();
83         if (OC_STACK_OK != result)
84                 ERR("OCStop() Fail(%d)", result);
85 }
86
87
88 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
89                 const char* const* res_types, int ifaces, uint8_t properties)
90 {
91         FN_CALL;
92         int i;
93         OCStackResult ret;
94         OCResourceHandle handle;
95         const char *resInterface = NULL;
96
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;
109         } else {
110                 ERR("Invalid interface type(%d)", ifaces);
111                 return NULL;
112         }
113
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);
120                 return NULL;
121         }
122
123         for (i = 1; res_types[i]; i++)
124                 icd_ioty_bind_type(handle, res_types[i]);
125
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);
134
135         return handle;
136 }
137
138
139 int icd_ioty_unregister_resource(OCResourceHandle resource_handle)
140 {
141         OCStackResult ret;
142
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;
149         }
150
151         return IOTCON_ERROR_NONE;
152 }
153
154
155 static int _ioty_convert_interface_flag(iotcon_interface_e src, const char **dest)
156 {
157         switch (src) {
158         case IOTCON_INTERFACE_DEFAULT:
159                 *dest = IC_INTERFACE_DEFAULT;
160                 break;
161         case IOTCON_INTERFACE_LINK:
162                 *dest = IC_INTERFACE_LINK;
163                 break;
164         case IOTCON_INTERFACE_BATCH:
165                 *dest = IC_INTERFACE_BATCH;
166                 break;
167         case IOTCON_INTERFACE_GROUP:
168                 *dest = IC_INTERFACE_GROUP;
169                 break;
170         case IOTCON_INTERFACE_NONE:
171         default:
172                 ERR("Invalid interface(%d)", src);
173                 return IOTCON_ERROR_INVALID_PARAMETER;
174         }
175         return IOTCON_ERROR_NONE;
176 }
177
178
179 int icd_ioty_bind_interface(OCResourceHandle resourceHandle, iotcon_interface_e iface)
180 {
181         int ret;
182         OCStackResult result;
183         const char *resource_interface;
184
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);
188                 return ret;
189         }
190
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;
197         }
198
199         return IOTCON_ERROR_NONE;
200 }
201
202 int icd_ioty_bind_type(OCResourceHandle resource_handle, const char *resource_type)
203 {
204         OCStackResult ret;
205
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;
212         }
213
214         return IOTCON_ERROR_NONE;
215 }
216
217
218 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
219 {
220         OCStackResult ret;
221
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;
228         }
229
230         return IOTCON_ERROR_NONE;
231 }
232
233
234 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
235 {
236         OCStackResult ret;
237
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;
244         }
245
246         return IOTCON_ERROR_NONE;
247 }
248
249
250 int icd_ioty_notify_list_of_observers(void *handle, GVariant *msg, GVariant *observers)
251 {
252         int i, error_code, obs_length;
253         char *repr_json = NULL;
254         GVariantIter obs_iter, msg_iter;
255         OCStackResult ret;
256
257         g_variant_iter_init(&obs_iter, observers);
258         obs_length = g_variant_iter_n_children(&obs_iter);
259
260         /* Variable-length Array */
261         OCObservationId obs_ids[obs_length];
262
263         for (i = 0; i < obs_length; i++)
264                 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
265
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. */
269
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();
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("OCNotifyListOfObservers() Fail(%d)", ret);
280                 return IOTCON_ERROR_IOTIVITY;
281         }
282
283         return IOTCON_ERROR_NONE;
284 }
285
286
287 int icd_ioty_notify_all(void *handle)
288 {
289         OCStackResult ret;
290
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();
295
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;
302         }
303
304         return IOTCON_ERROR_NONE;
305 }
306
307
308 static int _ioty_get_header_options(GVariantIter *src, int src_size,
309                 OCHeaderOption dest[], int dest_size)
310 {
311         int i = 0;
312         char *option_data;
313         unsigned short option_id;
314
315         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
316
317         if (dest_size < src_size) {
318                 ERR("Exceed Size(%d)", src_size);
319                 return IOTCON_ERROR_INVALID_PARAMETER;
320         }
321
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);
327                 i++;
328         }
329
330         return IOTCON_ERROR_NONE;
331 }
332
333
334 int icd_ioty_send_response(GVariant *resp)
335 {
336         int result, error_code, options_size;
337         int request_handle, resource_handle;
338         char *new_uri_path, *repr_json;
339         GVariantIter *options;
340         OCStackResult ret;
341         OCEntityHandlerResponse response = {0};
342
343         g_variant_get(resp, "(&sia(qs)i&sii)",
344                         &new_uri_path,
345                         &error_code,
346                         &options,
347                         &result,
348                         &repr_json,
349                         &request_handle,
350                         &resource_handle);
351
352         response.requestHandle = GINT_TO_POINTER(request_handle);
353         response.resourceHandle = GINT_TO_POINTER(resource_handle);
354         response.ehResult = (OCEntityHandlerResult)result;
355
356         if (OC_EH_RESOURCE_CREATED == response.ehResult)
357                 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
358
359         options_size = g_variant_iter_n_children(options);
360         response.numSendVendorSpecificHeaderOptions = options_size;
361
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]));
368
369                 if (IOTCON_ERROR_NONE != ret)
370                         ERR("_ioty_get_header_options() Fail(%d)", ret);
371         }
372         g_variant_iter_free(options);
373
374         response.payload = repr_json;
375         response.payloadSize = strlen(response.payload) + 1;
376
377         /* related to block transfer */
378         response.persistentBufferFlag = 0;
379
380         icd_ioty_csdk_lock();
381         ret = OCDoResponse(&response);
382         icd_ioty_csdk_unlock();
383
384         if (OC_STACK_OK != ret) {
385                 ERR("OCDoResponse() Fail(%d)", ret);
386                 return IOTCON_ERROR_IOTIVITY;
387         }
388
389         return IOTCON_ERROR_NONE;
390 }
391
392
393 static void _ioty_free_signal_context(void *data)
394 {
395         icd_sig_ctx_s *context = data;
396         free(context->sender);
397         free(context);
398 }
399
400 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
401                 unsigned int signum, const char *sender)
402 {
403         int len;
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;
409
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;
413         } else {
414                 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
415                                 OC_MULTICAST_DISCOVERY_URI);
416         }
417         if (len <= 0 || sizeof(uri) <= len) {
418                 ERR("snprintf() Fail(%d)", len);
419                 return IOTCON_ERROR_UNKNOWN;
420         }
421
422         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
423                 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
424
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;
429         }
430
431         context->sender = ic_utils_strdup(sender);
432         context->signum = signum;
433
434         cbdata.context = context;
435         cbdata.cb = icd_ioty_ocprocess_find_cb;
436         cbdata.cd = _ioty_free_signal_context;
437
438         icd_ioty_csdk_lock();
439         result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_LOW_QOS,
440                         &cbdata, NULL, 0);
441         icd_ioty_csdk_unlock();
442
443         if (OC_STACK_OK != result) {
444                 ERR("OCDoResource() Fail(%d)", result);
445                 free(context->sender);
446                 free(context);
447                 return IOTCON_ERROR_IOTIVITY;
448         }
449
450         return IOTCON_ERROR_NONE;
451 }
452
453
454 /*
455  * returned string SHOULD be released by you
456  */
457 static char* _icd_ioty_resource_generate_uri(char *host, char *uri_path, GVariant *query)
458 {
459         int len;
460         bool loop_first = true;
461         char *key, *value;
462         GVariantIter *queryIter;
463         char uri_buf[PATH_MAX] = {0};
464
465         len = snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
466
467         /* remove suffix '/' */
468         if ('/' == uri_buf[strlen(uri_buf) - 1]) {
469                 uri_buf[strlen(uri_buf) - 1] = '\0';
470                 len--;
471         }
472
473         g_variant_get(query, "a(ss)", &queryIter);
474
475         while (g_variant_iter_loop(queryIter, "(&s&s)", &key, &value)) {
476                 int query_len;
477
478                 DBG("query exist. key(%s), value(%s)", key, value);
479
480                 if (true == loop_first) {
481                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "?%s=%s", key, value);
482                         loop_first = false;
483                 } else {
484                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "&%s=%s", key, value);
485                 }
486
487                 len += query_len;
488         }
489         g_variant_iter_free(queryIter);
490
491         return strdup(uri_buf);
492 }
493
494
495 int icd_ioty_get(GVariant *resource, GVariant *query, unsigned int signal_number,
496                 const char *sender)
497 {
498         FN_CALL;
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];
507
508         g_variant_get(resource, "(&s&sba(qs)iii)", &uri_path, &host, &is_observable, &options,
509                         &ifaces, &observe_handle, &conn_type);
510
511         uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
512         if (NULL == uri) {
513                 ERR("_icd_ioty_resource_generate_uri() Fail");
514                 g_variant_iter_free(options);
515                 return IOTCON_ERROR_INVALID_PARAMETER;
516         }
517
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;
523         }
524         context->sender = ic_utils_strdup(sender);
525         context->signum = signal_number;
526
527         cbdata.context = context;
528         cbdata.cb = icd_ioty_ocprocess_get_cb;
529         cbdata.cd = _ioty_free_signal_context;
530
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);
538                         free(context);
539                         free(uri);
540                         g_variant_iter_free(options);
541                         return ret;
542                 }
543         }
544         g_variant_iter_free(options);
545
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();
551
552         free(uri);
553
554         if (OC_STACK_OK != result) {
555                 ERR("OCDoResource() Fail(%d)", result);
556                 free(context->sender);
557                 free(context);
558                 return IOTCON_ERROR_IOTIVITY;
559         }
560
561         return IOTCON_ERROR_NONE;
562 }
563
564
565 int icd_ioty_put(GVariant *resource, const char *repr, GVariant *query,
566                 unsigned int signal_number, const char *sender)
567 {
568         // TODO : To be implemented
569         return IOTCON_ERROR_NONE;
570 }
571
572
573 int icd_ioty_post(GVariant *resource, const char *repr, GVariant *query,
574                 unsigned int signal_number, const char *sender)
575 {
576         // TODO : To be implemented
577         return IOTCON_ERROR_NONE;
578 }
579
580
581 int icd_ioty_delete(GVariant *resource, unsigned int signal_number,
582                 const char *sender)
583 {
584         // TODO : To be implemented
585         return IOTCON_ERROR_NONE;
586 }
587
588
589 int icd_ioty_observer_start(GVariant *resource, int observe_type,
590                 GVariant *query, unsigned int signal_number, const char *sender, int *observe_h)
591 {
592         // TODO : To be implemented
593         return IOTCON_ERROR_NONE;
594 }
595
596
597 int icd_ioty_observer_stop(void *observe_h)
598 {
599         // TODO : To be implemented
600         return IOTCON_ERROR_NONE;
601 }
602
603
604 #ifdef DEVICE_INFO_IMPL /* not implemented in iotivity 0.9.1 */
605 int icd_ioty_register_device_info(GVariant *value)
606 {
607         // TODO : To be implemented
608         return IOTCON_ERROR_NONE;
609 }
610
611
612 int icd_ioty_get_device_info(const char *host_address,
613                 unsigned int signal_number, const char *sender)
614 {
615         // TODO : To be implemented
616         return IOTCON_ERROR_NONE;
617 }
618 #endif
619
620
621 int icd_ioty_register_platform_info(GVariant *value)
622 {
623         // TODO : To be implemented
624         return IOTCON_ERROR_NONE;
625 }
626
627
628 int icd_ioty_get_platform_info(const char *host_address, unsigned int signal_number,
629                 const char *sender)
630 {
631         // TODO : To be implemented
632         return IOTCON_ERROR_NONE;
633 }
634
635
636 iotcon_presence_h icd_ioty_subscribe_presence(const char *host_address,
637                 const char *resource_type, unsigned int signal_number, const char *sender)
638 {
639         // TODO : To be implemented
640         return NULL;
641 }
642
643
644 int icd_ioty_unsubscribe_presence(iotcon_presence_h presence_handle)
645 {
646         // TODO : To be implemented
647         return IOTCON_ERROR_NONE;
648 }
649
650
651 int icd_ioty_start_presence(unsigned int time_to_live)
652 {
653         // TODO : To be implemented
654         return IOTCON_ERROR_NONE;
655 }
656
657
658 int icd_ioty_stop_presence()
659 {
660         // TODO : To be implemented
661         return IOTCON_ERROR_NONE;
662 }