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