Allow various connectivity(IPv4, IPv6, BT_EDR)
[platform/core/iot/iotcon.git] / daemon / icd-ioty-ocprocess.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 <stdlib.h>
18 #include <unistd.h> /* for usleep() */
19 #include <glib.h>
20
21 #include <ocstack.h>
22 #include <octypes.h>
23 #include <ocpayload.h>
24
25 #include "iotcon.h"
26 #include "ic-utils.h"
27 #include "icd.h"
28 #include "icd-payload.h"
29 #include "icd-dbus.h"
30 #include "icd-ioty.h"
31 #include "icd-ioty-type.h"
32 #include "icd-ioty-ocprocess.h"
33
34 static int icd_ioty_alive;
35
36 typedef int (*_ocprocess_cb)(void *user_data);
37
38 struct icd_ioty_worker
39 {
40         void *ctx;
41         _ocprocess_cb cb;
42 };
43
44
45 struct icd_req_context {
46         unsigned int signal_number;
47         char *bus_name;
48         int types;
49         int observe_id;
50         int observe_action;
51         OCRequestHandle request_h;
52         OCResourceHandle resource_h;
53         GVariant *payload;
54         GVariantBuilder *options;
55         GVariantBuilder *query;
56         OCDevAddr *dev_addr;
57 };
58
59
60 struct icd_find_context {
61         unsigned int signal_number;
62         char *bus_name;
63         int conn_type;
64         GVariant **payload;
65 };
66
67
68 struct icd_crud_context {
69         int res;
70         int crud_type;
71         GVariant *payload;
72         GVariantBuilder *options;
73         GDBusMethodInvocation *invocation;
74 };
75
76
77 struct icd_info_context {
78         unsigned int signal_number;
79         int info_type;
80         char *bus_name;
81         GVariant *payload;
82 };
83
84
85 struct icd_tizen_info_context {
86         OCRequestHandle request_h;
87         OCResourceHandle resource_h;
88         GDBusMethodInvocation *invocation;
89 };
90
91
92 struct icd_observe_context {
93         unsigned int signal_number;
94         int res;
95         int seqnum;
96         char *bus_name;
97         GVariant *payload;
98         GVariantBuilder *options;
99 };
100
101
102 struct icd_presence_context {
103         unsigned int signal_number;
104         char *bus_name;
105         int result;
106         unsigned int nonce;
107         OCDevAddr *dev_addr;
108         iotcon_presence_trigger_e trigger;
109         char *resource_type;
110 };
111
112
113 void icd_ioty_ocprocess_stop()
114 {
115         icd_ioty_alive = 0;
116 }
117
118
119 static void* _ocprocess_worker_thread(void *data)
120 {
121         int ret;
122         struct icd_ioty_worker *worker = data;
123
124         if (NULL == data) {
125                 ERR("worker is NULL");
126                 return NULL;
127         }
128
129         ret = worker->cb(worker->ctx);
130         if (IOTCON_ERROR_NONE != ret)
131                 ERR("cb() Fail(%d)", ret);
132
133         /* worker was allocated from _ocprocess_worker_start() */
134         free(worker);
135
136         /* GCC warning happen if use g_thread_exit() */
137         return NULL;
138 }
139
140
141 static int _ocprocess_worker_start(_ocprocess_cb cb, void *ctx)
142 {
143         GError *error;
144         GThread *thread;
145         struct icd_ioty_worker *worker;
146
147         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
148
149         worker = calloc(1, sizeof(struct icd_ioty_worker));
150         if (NULL == worker) {
151                 ERR("calloc() Fail(%d)", errno);
152                 return IOTCON_ERROR_OUT_OF_MEMORY;
153         }
154
155         worker->cb = cb;
156         worker->ctx = ctx;
157
158         /* TODO : consider thread pool mechanism */
159         thread = g_thread_try_new("worker_thread", _ocprocess_worker_thread, worker, &error);
160         if (NULL == thread) {
161                 ERR("g_thread_try_new() Fail(%s)", error->message);
162                 g_error_free(error);
163                 free(worker);
164                 return IOTCON_ERROR_SYSTEM;
165         }
166
167         /* DO NOT join thread. It was already detached by calling g_thread_unref() */
168         g_thread_unref(thread);
169
170         /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
171
172         return IOTCON_ERROR_NONE;
173 }
174
175
176 static int _ocprocess_response_signal(const char *dest, const char *signal_prefix,
177                 unsigned int signal_number, GVariant *value)
178 {
179         int ret;
180         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
181
182         ret = snprintf(signal_name, sizeof(signal_name), "%s_%u", signal_prefix, signal_number);
183         if (ret <= 0 || sizeof(signal_name) <= ret) {
184                 ERR("snprintf() Fail(%d)", ret);
185                 return IOTCON_ERROR_IO_ERROR;
186         }
187
188         ret = icd_dbus_emit_signal(dest, signal_name, value);
189         if (IOTCON_ERROR_NONE != ret) {
190                 ERR("icd_dbus_emit_signal() Fail(%d)", ret);
191                 return ret;
192         }
193
194         return IOTCON_ERROR_NONE;
195 }
196
197
198 static inline GVariantBuilder* _ocprocess_parse_header_options(
199                 OCHeaderOption *oic_option, int option_size)
200 {
201         int i;
202         GVariantBuilder *options;
203
204         options = g_variant_builder_new(G_VARIANT_TYPE("a(qs)"));
205         for (i = 0; i < option_size; i++) {
206                 g_variant_builder_add(options, "(qs)", oic_option[i].optionID,
207                                 oic_option[i].optionData);
208         }
209
210         return options;
211 }
212
213 static int _ioty_oic_action_to_ioty_action(int oic_action)
214 {
215         int action;
216
217         switch (oic_action) {
218         case OC_OBSERVE_REGISTER:
219                 action = IOTCON_OBSERVE_REGISTER;
220                 break;
221         case OC_OBSERVE_DEREGISTER:
222                 action = IOTCON_OBSERVE_DEREGISTER;
223                 break;
224         case OC_OBSERVE_NO_OPTION:
225         default:
226                 ERR("Invalid action (%d)", oic_action);
227                 action = IOTCON_OBSERVE_NO_OPTION;
228         }
229         return action;
230 }
231
232
233 static void _icd_req_context_free(struct icd_req_context *ctx)
234 {
235         free(ctx->bus_name);
236         if (ctx->payload)
237                 g_variant_unref(ctx->payload);
238         g_variant_builder_unref(ctx->options);
239         g_variant_builder_unref(ctx->query);
240         free(ctx->dev_addr);
241         free(ctx);
242 }
243
244
245 static int _worker_req_handler(void *context)
246 {
247         GVariant *value;
248         char *host_address;
249         int ret, conn_type, action;
250         GVariantBuilder payload_builder;
251         struct icd_req_context *ctx = context;
252
253         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
254
255         g_variant_builder_init(&payload_builder, G_VARIANT_TYPE("av"));
256         if (ctx->payload) {
257                 g_variant_builder_add(&payload_builder, "v", ctx->payload);
258                 ctx->payload = NULL;
259         }
260
261         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
262         if (IOTCON_ERROR_NONE != ret) {
263                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
264                 g_variant_builder_clear(&payload_builder);
265                 _icd_req_context_free(ctx);
266                 return ret;
267         }
268
269         action = _ioty_oic_action_to_ioty_action(ctx->observe_action);
270
271         value = g_variant_new("(siia(qs)a(ss)iiavxx)",
272                         host_address,
273                         conn_type,
274                         ctx->types,
275                         ctx->options,
276                         ctx->query,
277                         action,
278                         ctx->observe_id,
279                         &payload_builder,
280                         ICD_POINTER_TO_INT64(ctx->request_h),
281                         ICD_POINTER_TO_INT64(ctx->resource_h));
282
283         free(host_address);
284
285         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_REQUEST_HANDLER,
286                         ctx->signal_number, value);
287         if (IOTCON_ERROR_NONE != ret)
288                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
289
290         _icd_req_context_free(ctx);
291
292         return ret;
293 }
294
295
296 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
297                 OCEntityHandlerRequest *request, void *user_data)
298 {
299         FN_CALL;
300         int ret;
301         unsigned int signal_number;
302         char *query_str, *query_key, *query_value;
303         char *token, *save_ptr1, *save_ptr2;
304         char *bus_name = NULL;
305         struct icd_req_context *req_ctx;
306         OCDevAddr *dev_addr;
307
308         RETV_IF(NULL == request, OC_EH_ERROR);
309
310         req_ctx = calloc(1, sizeof(struct icd_req_context));
311         if (NULL == req_ctx) {
312                 ERR("calloc() Fail(%d)", errno);
313                 return OC_EH_ERROR;
314         }
315
316         /* handle */
317         req_ctx->request_h = request->requestHandle;
318         req_ctx->resource_h = request->resource;
319
320         ret = icd_dbus_client_list_get_info(req_ctx->resource_h, &signal_number, &bus_name);
321         if (IOTCON_ERROR_NONE != ret) {
322                 ERR("icd_dbus_client_list_get_info() Fail(%d)", ret);
323                 free(req_ctx);
324                 return OC_EH_ERROR;
325         }
326
327         /* signal number & bus_name */
328         req_ctx->signal_number = signal_number;
329         req_ctx->bus_name = bus_name;
330
331         dev_addr = calloc(1, sizeof(OCDevAddr));
332         if (NULL == dev_addr) {
333                 ERR("calloc() Fail(%d)", errno);
334                 free(req_ctx);
335                 return OC_EH_ERROR;
336         }
337         memcpy(dev_addr, &request->devAddr, sizeof(OCDevAddr));
338         req_ctx->dev_addr = dev_addr;
339
340         /* request type */
341         if (OC_REQUEST_FLAG & flag) {
342                 switch (request->method) {
343                 case OC_REST_GET:
344                         req_ctx->types = IOTCON_REQUEST_GET;
345                         req_ctx->payload = NULL;
346
347                         if (OC_OBSERVE_FLAG & flag) {
348                                 req_ctx->types |= IOTCON_REQUEST_OBSERVE;
349                                 /* observation info*/
350                                 req_ctx->observe_id = request->obsInfo.obsId;
351                                 req_ctx->observe_action = request->obsInfo.action;
352                         }
353                         break;
354                 case OC_REST_PUT:
355                         req_ctx->types = IOTCON_REQUEST_PUT;
356                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
357                         break;
358                 case OC_REST_POST:
359                         req_ctx->types = IOTCON_REQUEST_POST;
360                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
361                         break;
362                 case OC_REST_DELETE:
363                         req_ctx->types = IOTCON_REQUEST_DELETE;
364                         req_ctx->payload = NULL;
365                         break;
366                 default:
367                         free(req_ctx->bus_name);
368                         free(req_ctx);
369                         return OC_EH_ERROR;
370                 }
371         }
372
373         /* header options */
374         req_ctx->options = _ocprocess_parse_header_options(
375                         request->rcvdVendorSpecificHeaderOptions,
376                         request->numRcvdVendorSpecificHeaderOptions);
377
378         /* query */
379         req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
380         query_str = request->query;
381         while ((token = strtok_r(query_str, "&;", &save_ptr1))) {
382                 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
383                         token = NULL;
384                         query_value = strtok_r(token, "=", &save_ptr2);
385                         if (NULL == query_value)
386                                 break;
387
388                         g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
389                 }
390                 query_str = NULL;
391         }
392
393         ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
394         if (IOTCON_ERROR_NONE != ret) {
395                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
396                 _icd_req_context_free(req_ctx);
397                 return OC_EH_ERROR;
398         }
399
400         /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
401
402         return OC_EH_OK;
403 }
404
405
406 gpointer icd_ioty_ocprocess_thread(gpointer data)
407 {
408         FN_CALL;
409         OCStackResult result;
410
411         icd_ioty_alive = 1;
412         while (icd_ioty_alive) {
413                 icd_ioty_csdk_lock();
414                 result = OCProcess();
415                 icd_ioty_csdk_unlock();
416                 if (OC_STACK_OK != result) {
417                         ERR("OCProcess() Fail(%d)", result);
418                         break;
419                 }
420
421                 /* TODO : SHOULD revise time or usleep */
422                 usleep(10);
423         }
424
425         return NULL;
426 }
427
428
429 static int _worker_find_cb(void *context)
430 {
431         GVariant *value;
432         int i, ret;
433         struct icd_find_context *ctx = context;
434
435         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
436
437         for (i = 0; ctx->payload[i]; i++) {
438                 value = g_variant_new("(vi)", ctx->payload[i], ctx->conn_type);
439                 /* TODO : If one device has multi resources, it comes as bulk data.
440                  * To reduce the number of emit_signal, let's send signal only one time for one device.
441                  * for ex, client list. */
442                 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
443                                 ctx->signal_number, value);
444                 if (IOTCON_ERROR_NONE != ret) {
445                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
446                         g_variant_unref(value);
447                         return ret;
448                 }
449         }
450
451         /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
452         free(ctx->bus_name);
453         free(ctx);
454
455         return ret;
456 }
457
458
459 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
460                 OCClientResponse *resp)
461 {
462         int ret;
463         struct icd_find_context *find_ctx;
464         icd_sig_ctx_s *sig_context = ctx;
465
466         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
467         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
468         if (NULL == resp->payload)
469                 /* normal case : payload COULD be NULL */
470                 return OC_STACK_KEEP_TRANSACTION;
471         RETVM_IF(PAYLOAD_TYPE_DISCOVERY != resp->payload->type,
472                         OC_STACK_KEEP_TRANSACTION, "Invalid payload type(%d)", resp->payload->type);
473
474         find_ctx = calloc(1, sizeof(struct icd_find_context));
475         if (NULL == find_ctx) {
476                 ERR("calloc() Fail(%d)", errno);
477                 return OC_STACK_KEEP_TRANSACTION;
478         }
479
480         find_ctx->signal_number = sig_context->signal_number;
481         find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
482         find_ctx->payload = icd_payload_res_to_gvariant(resp->payload, &resp->devAddr);
483         find_ctx->conn_type = icd_ioty_transport_flag_to_conn_type(resp->devAddr.adapter,
484                         resp->devAddr.flags);
485
486         ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
487         if (IOTCON_ERROR_NONE != ret) {
488                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
489                 free(find_ctx->bus_name);
490                 ic_utils_gvariant_array_free(find_ctx->payload);
491                 free(find_ctx);
492                 return OC_STACK_KEEP_TRANSACTION;
493         }
494
495         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
496         /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
497
498         return OC_STACK_KEEP_TRANSACTION;
499 }
500
501
502 static int _worker_crud_cb(void *context)
503 {
504         GVariant *value;
505         struct icd_crud_context *ctx = context;
506
507         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
508
509         if (ICD_CRUD_DELETE == ctx->crud_type)
510                 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
511         else
512                 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
513         icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
514
515         /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
516         g_variant_builder_unref(ctx->options);
517         free(ctx);
518
519         return IOTCON_ERROR_NONE;
520 }
521
522
523 static int _worker_info_cb(void *context)
524 {
525         int ret;
526         const char *signal_prefix = NULL;
527         struct icd_info_context *ctx = context;
528
529         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
530
531         if (ICD_DEVICE_INFO == ctx->info_type)
532                 signal_prefix = IC_DBUS_SIGNAL_DEVICE;
533         else if (ICD_PLATFORM_INFO == ctx->info_type)
534                 signal_prefix = IC_DBUS_SIGNAL_PLATFORM;
535
536         ret = _ocprocess_response_signal(ctx->bus_name, signal_prefix, ctx->signal_number,
537                         ctx->payload);
538         if (IOTCON_ERROR_NONE != ret)
539                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
540
541         /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
542         free(ctx->bus_name);
543         free(ctx);
544
545         return ret;
546 }
547
548
549 static int _ocprocess_worker(_ocprocess_cb cb, int type, OCPayload *payload, int res,
550                 GVariantBuilder *options, void *ctx)
551 {
552         int ret;
553         struct icd_crud_context *crud_ctx;
554
555         crud_ctx = calloc(1, sizeof(struct icd_crud_context));
556         if (NULL == crud_ctx) {
557                 ERR("calloc() Fail(%d)", errno);
558                 return IOTCON_ERROR_OUT_OF_MEMORY;
559         }
560
561         crud_ctx->crud_type = type;
562         crud_ctx->payload = icd_payload_to_gvariant(payload);
563         crud_ctx->res = res;
564         crud_ctx->options = options;
565         crud_ctx->invocation = ctx;
566
567         ret = _ocprocess_worker_start(cb, crud_ctx);
568         if (IOTCON_ERROR_NONE != ret) {
569                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
570                 if (crud_ctx->payload)
571                         g_variant_unref(crud_ctx->payload);
572                 g_variant_builder_unref(crud_ctx->options);
573                 free(crud_ctx);
574         }
575
576         /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
577
578         return ret;
579 }
580
581 static int _ocprocess_parse_oic_result(OCStackResult result)
582 {
583         int res;
584
585         switch (result) {
586         case OC_STACK_OK:
587                 res = IOTCON_RESPONSE_RESULT_OK;
588                 break;
589         case OC_STACK_RESOURCE_CREATED:
590                 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
591                 break;
592         case OC_STACK_RESOURCE_DELETED:
593                 res = IOTCON_RESPONSE_RESULT_RESOURCE_DELETED;
594                 break;
595         case OC_STACK_UNAUTHORIZED_REQ:
596                 res = IOTCON_RESPONSE_RESULT_FORBIDDEN;
597                 break;
598         default:
599                 WARN("response error(%d)", result);
600                 res = IOTCON_RESPONSE_RESULT_ERROR;
601                 break;
602         }
603
604         return res;
605 }
606
607
608 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
609                 OCClientResponse *resp)
610 {
611         FN_CALL;
612         int ret, res;
613         GVariantBuilder *options;
614
615         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
616
617         if (NULL == resp->payload) {
618                 ERR("payload is empty");
619                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
620                 return OC_STACK_DELETE_TRANSACTION;
621         }
622
623         res = _ocprocess_parse_oic_result(resp->result);
624
625         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
626                         resp->numRcvdVendorSpecificHeaderOptions);
627
628         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
629                         options, ctx);
630         if (IOTCON_ERROR_NONE != ret) {
631                 ERR("_ocprocess_worker() Fail(%d)", ret);
632                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
633                 return OC_STACK_DELETE_TRANSACTION;
634         }
635
636         return OC_STACK_DELETE_TRANSACTION;
637 }
638
639
640 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
641                 OCClientResponse *resp)
642 {
643         FN_CALL;
644         int ret, res;
645         GVariantBuilder *options;
646
647         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
648
649         if (NULL == resp->payload) {
650                 ERR("payload is empty");
651                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
652                 return OC_STACK_DELETE_TRANSACTION;
653         }
654
655         res = _ocprocess_parse_oic_result(resp->result);
656
657         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
658                         resp->numRcvdVendorSpecificHeaderOptions);
659
660         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
661                         options, ctx);
662         if (IOTCON_ERROR_NONE != ret) {
663                 ERR("_ocprocess_worker() Fail(%d)", ret);
664                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
665                 return OC_STACK_DELETE_TRANSACTION;
666         }
667
668         return OC_STACK_DELETE_TRANSACTION;
669 }
670
671
672 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
673                 OCClientResponse *resp)
674 {
675         FN_CALL;
676         int ret, res;
677         GVariantBuilder *options;
678
679         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
680
681         if (NULL == resp->payload) {
682                 ERR("payload is empty");
683                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
684                 return OC_STACK_DELETE_TRANSACTION;
685         }
686
687         res = _ocprocess_parse_oic_result(resp->result);
688
689         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
690                         resp->numRcvdVendorSpecificHeaderOptions);
691
692         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
693                         options, ctx);
694         if (IOTCON_ERROR_NONE != ret) {
695                 ERR("_ocprocess_worker() Fail(%d)", ret);
696                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
697                 return OC_STACK_DELETE_TRANSACTION;
698         }
699
700         return OC_STACK_DELETE_TRANSACTION;
701 }
702
703
704 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
705                 OCClientResponse *resp)
706 {
707         FN_CALL;
708         int ret, res;
709         GVariantBuilder *options;
710
711         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
712
713         if (NULL == resp->payload) {
714                 ERR("payload is empty");
715                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
716                 return OC_STACK_DELETE_TRANSACTION;
717         }
718
719         res = _ocprocess_parse_oic_result(resp->result);
720
721         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
722                         resp->numRcvdVendorSpecificHeaderOptions);
723
724         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
725         if (IOTCON_ERROR_NONE != ret) {
726                 ERR("_ocprocess_worker() Fail(%d)", ret);
727                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
728                 return OC_STACK_DELETE_TRANSACTION;
729         }
730
731         return OC_STACK_DELETE_TRANSACTION;
732 }
733
734
735 static int _worker_observe_cb(void *context)
736 {
737         int ret;
738         GVariant *value;
739         struct icd_observe_context *ctx = context;
740
741         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
742
743         value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
744                         ctx->seqnum);
745
746         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE,
747                         ctx->signal_number, value);
748         if (IOTCON_ERROR_NONE != ret)
749                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
750
751         /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
752         free(ctx->bus_name);
753         g_variant_builder_unref(ctx->options);
754         free(ctx);
755
756         return ret;
757 }
758
759
760 static void _observe_cb_response_error(const char *dest,
761                 unsigned int signal_number, int ret_val)
762 {
763         int ret;
764         GVariant *value;
765         GVariant *payload;
766         GVariantBuilder options;
767
768         g_variant_builder_init(&options, G_VARIANT_TYPE("a(qs)"));
769         payload = icd_payload_representation_empty_gvariant();
770
771         value = g_variant_new("(a(qs)vii)", &options, payload, ret_val, 0);
772
773         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signal_number, value);
774         if (IOTCON_ERROR_NONE != ret)
775                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
776 }
777
778
779 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx,
780                 OCDoHandle handle, OCClientResponse *resp)
781 {
782         int ret, res;
783         GVariantBuilder *options;
784         struct icd_observe_context *observe_ctx;
785         icd_sig_ctx_s *sig_context = ctx;
786
787         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
788
789         if (NULL == resp->payload) {
790                 ERR("payload is empty");
791                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
792                                 IOTCON_ERROR_IOTIVITY);
793                 return OC_STACK_KEEP_TRANSACTION;
794         }
795
796         observe_ctx = calloc(1, sizeof(struct icd_observe_context));
797         if (NULL == observe_ctx) {
798                 ERR("calloc() Fail(%d)", errno);
799                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
800                                 IOTCON_ERROR_OUT_OF_MEMORY);
801                 return OC_STACK_KEEP_TRANSACTION;
802         }
803
804         res = _ocprocess_parse_oic_result(resp->result);
805
806         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
807                         resp->numRcvdVendorSpecificHeaderOptions);
808
809         observe_ctx->payload = icd_payload_to_gvariant(resp->payload);
810         observe_ctx->signal_number = sig_context->signal_number;
811         observe_ctx->res = res;
812         observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
813         observe_ctx->options = options;
814
815         ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
816         if (IOTCON_ERROR_NONE != ret) {
817                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
818                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
819                 free(observe_ctx->bus_name);
820                 if (observe_ctx->payload)
821                         g_variant_unref(observe_ctx->payload);
822                 g_variant_builder_unref(observe_ctx->options);
823                 free(observe_ctx);
824                 return OC_STACK_KEEP_TRANSACTION;
825         }
826
827         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
828         /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
829
830         return OC_STACK_KEEP_TRANSACTION;
831 }
832
833
834 static int _worker_presence_cb(void *context)
835 {
836         GVariant *value;
837         int ret, conn_type;
838         char *host_address;
839         struct icd_presence_context *ctx = context;
840
841         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
842
843         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
844         if (IOTCON_ERROR_NONE != ret) {
845                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
846                 free(ctx->resource_type);
847                 free(ctx->bus_name);
848                 free(ctx->dev_addr);
849                 free(ctx);
850                 return ret;
851         }
852
853         value = g_variant_new("(iusiis)", ctx->result, ctx->nonce, host_address, conn_type,
854                         ctx->trigger, ic_utils_dbus_encode_str(ctx->resource_type));
855
856         free(host_address);
857
858         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_PRESENCE,
859                         ctx->signal_number, value);
860         if (IOTCON_ERROR_NONE != ret)
861                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
862
863         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
864         free(ctx->resource_type);
865         free(ctx->bus_name);
866         free(ctx->dev_addr);
867         free(ctx);
868
869         return ret;
870 }
871
872
873 static void _presence_cb_response_error(const char *dest, unsigned int signal_number,
874                 int ret_val)
875 {
876         FN_CALL;
877         int ret;
878         GVariant *value;
879
880         value = g_variant_new("(iusiis)", ret_val, 0, IC_STR_NULL, IOTCON_CONNECTIVITY_ALL,
881                         IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED, IC_STR_NULL);
882
883         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_PRESENCE, signal_number, value);
884         if (IOTCON_ERROR_NONE != ret)
885                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
886 }
887
888
889 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
890                 iotcon_presence_trigger_e *dest)
891 {
892         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
893
894         switch (src) {
895         case OC_PRESENCE_TRIGGER_CREATE:
896                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED;
897                 break;
898         case OC_PRESENCE_TRIGGER_CHANGE:
899                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_UPDATED;
900                 break;
901         case OC_PRESENCE_TRIGGER_DELETE:
902                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_DESTROYED;
903                 break;
904         default:
905                 ERR("Invalid trigger(%d)", src);
906                 return IOTCON_ERROR_INVALID_PARAMETER;
907         }
908
909         return IOTCON_ERROR_NONE;
910 }
911
912
913 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
914                 OCClientResponse *resp)
915 {
916         FN_CALL;
917         int ret;
918         OCDevAddr *dev_addr;
919         OCPresencePayload *payload;
920         icd_sig_ctx_s *sig_context = ctx;
921         struct icd_presence_context *presence_ctx;
922
923         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
924         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
925
926         presence_ctx = calloc(1, sizeof(struct icd_presence_context));
927         if (NULL == presence_ctx) {
928                 ERR("calloc() Fail(%d)", errno);
929                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
930                                 IOTCON_ERROR_OUT_OF_MEMORY);
931                 return OC_STACK_KEEP_TRANSACTION;
932         }
933
934         dev_addr = calloc(1, sizeof(OCDevAddr));
935         if (NULL == dev_addr) {
936                 ERR("calloc() Fail(%d)", errno);
937                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
938                                 IOTCON_ERROR_OUT_OF_MEMORY);
939                 free(presence_ctx);
940                 return OC_STACK_KEEP_TRANSACTION;
941         }
942         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
943
944         payload = (OCPresencePayload*)resp->payload;
945
946         switch (resp->result) {
947         case OC_STACK_OK:
948                 presence_ctx->result = IOTCON_PRESENCE_OK;
949                 ret = _presence_trigger_to_ioty_trigger(payload->trigger, &presence_ctx->trigger);
950                 if (IOTCON_ERROR_NONE != ret) {
951                         ERR("_presence_trigger_to_ioty_trigger() Fail(%d)", ret);
952                         _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
953                                         ret);
954                         free(presence_ctx);
955                         return OC_STACK_KEEP_TRANSACTION;
956                 }
957                 break;
958         case OC_STACK_PRESENCE_STOPPED:
959                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
960                 break;
961         case OC_STACK_PRESENCE_TIMEOUT:
962                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
963                 break;
964         case OC_STACK_ERROR:
965         default:
966                 DBG("Presence error(%d)", resp->result);
967                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
968         }
969
970         presence_ctx->signal_number = sig_context->signal_number;
971         presence_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
972         presence_ctx->nonce = resp->sequenceNumber;
973         presence_ctx->dev_addr = dev_addr;
974
975         if (payload->resourceType)
976                 presence_ctx->resource_type = strdup(payload->resourceType);
977
978         ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
979         if (IOTCON_ERROR_NONE != ret) {
980                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
981                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
982                 free(presence_ctx->resource_type);
983                 free(presence_ctx->bus_name);
984                 free(presence_ctx->dev_addr);
985                 free(presence_ctx);
986                 return OC_STACK_KEEP_TRANSACTION;
987         }
988
989         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
990         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
991
992         return OC_STACK_KEEP_TRANSACTION;
993 }
994
995
996 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
997                 OCClientResponse *resp)
998 {
999         int ret;
1000         int info_type;
1001         struct icd_info_context *info_ctx;
1002         icd_sig_ctx_s *sig_context = ctx;
1003
1004         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1005         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1006         RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
1007
1008         if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
1009                 info_type = ICD_DEVICE_INFO;
1010         else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
1011                 info_type = ICD_PLATFORM_INFO;
1012         else
1013                 return OC_STACK_KEEP_TRANSACTION;
1014
1015         info_ctx = calloc(1, sizeof(struct icd_info_context));
1016         if (NULL == info_ctx) {
1017                 ERR("calloc() Fail(%d)", errno);
1018                 return OC_STACK_KEEP_TRANSACTION;
1019         }
1020
1021         info_ctx->info_type = info_type;
1022         info_ctx->payload = icd_payload_to_gvariant(resp->payload);
1023         info_ctx->signal_number = sig_context->signal_number;
1024         info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1025
1026         ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
1027         if (IOTCON_ERROR_NONE != ret) {
1028                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1029                 free(info_ctx->bus_name);
1030                 if (info_ctx->payload)
1031                         g_variant_unref(info_ctx->payload);
1032                 free(info_ctx);
1033                 return OC_STACK_KEEP_TRANSACTION;
1034         }
1035
1036         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1037         /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
1038
1039         return OC_STACK_KEEP_TRANSACTION;
1040 }
1041
1042
1043 static int _worker_tizen_info_handler(void *context)
1044 {
1045         int ret;
1046         char *device_name;
1047         char *tizen_device_id;
1048         OCStackResult result;
1049         OCRepPayload *payload;
1050         OCEntityHandlerResponse response = {0};
1051         struct icd_tizen_info_context *ctx = context;
1052
1053         response.requestHandle = ctx->request_h;
1054         response.resourceHandle = ctx->resource_h;
1055         response.ehResult = OC_EH_OK;
1056
1057         /* Get Tizen Info */
1058         ret = icd_ioty_tizen_info_get_property(&device_name, &tizen_device_id);
1059         if (IOTCON_ERROR_NONE != ret) {
1060                 ERR("icd_ioty_tizen_info_get_property() Fail(%d)", ret);
1061                 response.ehResult = OC_EH_ERROR;
1062         }
1063
1064         /* payload */
1065         payload = OCRepPayloadCreate();
1066         OCRepPayloadSetUri(payload, ICD_IOTY_TIZEN_INFO_URI);
1067         OCRepPayloadAddResourceType(payload, ICD_IOTY_TIZEN_INFO_TYPE);
1068         OCRepPayloadAddInterface(payload, IC_INTERFACE_DEFAULT);
1069
1070         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_DEVICE_NAME,
1071                         ic_utils_dbus_encode_str(device_name));
1072         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_TIZEN_DEVICE_ID,
1073                         ic_utils_dbus_encode_str(tizen_device_id));
1074         response.payload = (OCPayload*)payload;
1075
1076         icd_ioty_csdk_lock();
1077         result = OCDoResponse(&response);
1078         icd_ioty_csdk_unlock();
1079
1080         if (OC_STACK_OK != result) {
1081                 ERR("OCDoResponse() Fail(%d)", result);
1082                 free(ctx);
1083                 return IOTCON_ERROR_IOTIVITY;
1084         }
1085
1086         free(ctx);
1087         return IOTCON_ERROR_NONE;
1088 }
1089
1090
1091 OCEntityHandlerResult icd_ioty_ocprocess_tizen_info_handler(OCEntityHandlerFlag flag,
1092                 OCEntityHandlerRequest *request, void *user_data)
1093 {
1094         int ret;
1095         struct icd_tizen_info_context *tizen_info_ctx;
1096
1097         if ((0 == (OC_REQUEST_FLAG & flag)) || (OC_REST_GET != request->method)) {
1098                 ERR("Prohibited Action");
1099                 return OC_EH_FORBIDDEN;
1100         }
1101
1102         tizen_info_ctx = calloc(1, sizeof(struct icd_tizen_info_context));
1103         if (NULL == tizen_info_ctx) {
1104                 ERR("calloc() Fail(%d)", errno);
1105                 return OC_EH_ERROR;
1106         }
1107
1108         tizen_info_ctx->request_h = request->requestHandle;
1109         tizen_info_ctx->resource_h = request->resource;
1110
1111         ret = _ocprocess_worker_start(_worker_tizen_info_handler, tizen_info_ctx);
1112         if (IOTCON_ERROR_NONE != ret) {
1113                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1114                 free(tizen_info_ctx);
1115                 return OC_EH_ERROR;
1116         }
1117
1118         return OC_EH_OK;
1119 }
1120
1121
1122 OCStackApplicationResult icd_ioty_ocprocess_get_tizen_info_cb(void *ctx,
1123                 OCDoHandle handle, OCClientResponse *resp)
1124 {
1125         int res;
1126         char *device_name;
1127         char *tizen_device_id;
1128         GVariant *tizen_info;
1129         OCRepPayload *payload;
1130         OCRepPayloadValue *val;
1131
1132         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1133
1134         if (NULL == resp->payload) {
1135                 ERR("payload is empty");
1136                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1137                 return OC_STACK_DELETE_TRANSACTION;
1138         }
1139
1140         payload = (OCRepPayload*)resp->payload;
1141         val = payload->values;
1142         if (NULL == val) {
1143                 ERR("Invalid payload");
1144                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1145                 return OC_STACK_DELETE_TRANSACTION;
1146         }
1147         device_name = val->str;
1148
1149         val = val->next;
1150         if (NULL == val) {
1151                 ERR("Invalid Payload");
1152                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1153                 return OC_STACK_DELETE_TRANSACTION;
1154         }
1155
1156         tizen_device_id = val->str;
1157
1158         if (OC_STACK_OK == resp->result)
1159                 res = IOTCON_RESPONSE_RESULT_OK;
1160         else
1161                 res = IOTCON_RESPONSE_RESULT_ERROR;
1162
1163         tizen_info = g_variant_new("(ssi)", device_name, tizen_device_id, res);
1164
1165         icd_ioty_complete(ICD_TIZEN_INFO, ctx, tizen_info);
1166
1167         return OC_STACK_DELETE_TRANSACTION;
1168 }