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