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