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