HomePort
rest_json.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Aalborg University. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  * conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  * of conditions and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Aalborg University ''AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Aalborg University OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  */
27 
28 #include "rest_json.h"
29 #include "hpd/common/hpd_jansson.h"
31 #include <string.h>
32 
33 #define REST_JSON_RETURN_JSON_ERROR(CONTEXT) HPD_LOG_RETURN(context, HPD_E_UNKNOWN, "Json error")
34 
35 static hpd_error_t rest_json_add(json_t *parent, const char *key, const char *val, const hpd_module_t *context)
36 {
37  json_t *json;
38  if (!(json = json_string(val)))
40  if (json_object_set_new(parent, key, json)) {
41  json_decref(json);
43  }
44  return HPD_E_SUCCESS;
45 }
46 
47 static hpd_error_t rest_json_add_attr(json_t *parent, hpd_pair_t *pair, const hpd_module_t *context)
48 {
49  hpd_error_t rc;
50 
51  // Get key and value
52  const char *key, *val;
53  if ((rc = hpd_pair_get(pair, &key, &val))) return rc;
54 
55  return rest_json_add(parent, key, val, context);
56 }
57 
59 {
60  hpd_error_t rc;
61 
62  // Create object
63  json_t *json;
64  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
65 
66  // Add id
67  const char *id;
68  if ((rc = hpd_parameter_get_id(parameter, &id))) goto error;
69  if ((rc = rest_json_add(json, HPD_REST_KEY_ID, id, context))) goto error;
70 
71  // Add attributes
72  hpd_pair_t *pair;
73  hpd_parameter_foreach_attr(rc, pair, parameter)
74  if ((rc = rest_json_add_attr(json, pair, context))) goto error;
75  if (rc) goto error;
76 
77  // Add to parent
78  if (json_array_append_new(parent, json)) {
79  json_decref(json);
81  }
82 
83  return HPD_E_SUCCESS;
84 
85  error:
86  json_decref(json);
87  return rc;
88 }
89 
91 {
92  hpd_error_t rc;
93 
94  // Create array
95  json_t *json;
96  if (!(json = json_array())) REST_JSON_RETURN_JSON_ERROR(context);
97 
98  // Add parameters
99  hpd_parameter_id_t *parameter;
100  hpd_service_foreach_parameter(rc, parameter, service) {
101  if ((rc = rest_json_add_parameter(json, parameter, context))) goto error;
102  }
103  if (rc) goto error;
104 
105  // Add to parent
106  if (json_object_set_new(parent, HPD_REST_KEY_PARAMETER, json)) {
107  json_decref(json);
109  }
110  return HPD_E_SUCCESS;
111 
112  error:
113  json_decref(json);
114  return rc;
115 }
116 
117 static hpd_error_t rest_json_add_service(json_t *parent, hpd_service_id_t *service, hpd_rest_t *rest, const hpd_module_t *context)
118 {
119  hpd_error_t rc;
120 
121  // Create object
122  json_t *json;
123  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
124 
125  // Add id
126  const char *id;
127  if ((rc = hpd_service_get_id(service, &id))) goto error;
128  if ((rc = rest_json_add(json, HPD_REST_KEY_ID, id, context))) goto error;
129 
130  // Add url
131  char *url;
132  if ((rc = hpd_rest_url_create(rest, service, &url))) goto error;
133  if ((rc = rest_json_add(json, HPD_REST_KEY_URI, url, context))) {
134  free(url);
135  goto error;
136  }
137  free(url);
138 
139  // Add actions
140  hpd_action_t *action;
141  hpd_service_foreach_action(rc, action, service) {
142  hpd_method_t method;
143  if ((rc = hpd_action_get_method(action, &method))) goto error;
144  switch (method) {
145  case HPD_M_NONE:break;
146  case HPD_M_GET:
147  if ((rc = rest_json_add(json, HPD_REST_KEY_GET, HPD_REST_VAL_TRUE, context))) goto error;
148  break;
149  case HPD_M_PUT:
150  if ((rc = rest_json_add(json, HPD_REST_KEY_PUT, HPD_REST_VAL_TRUE, context))) goto error;
151  break;
152  case HPD_M_COUNT:break;
153  }
154  }
155  if (rc) goto error;
156 
157  // Add attributes
158  hpd_pair_t *pair;
159  hpd_service_foreach_attr(rc, pair, service)
160  if ((rc = rest_json_add_attr(json, pair, context))) goto error;
161  if (rc) goto error;
162 
163  // Add parameters
164  if ((rc = rest_json_add_parameters(json, service, context))) goto error;
165 
166  // Add to parent
167  if (json_array_append_new(parent, json)) {
168  json_decref(json);
170  }
171 
172  return HPD_E_SUCCESS;
173 
174  error:
175  json_decref(json);
176  return rc;
177 }
178 
179 static hpd_error_t rest_json_add_services(json_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
180 {
181  hpd_error_t rc;
182 
183  // Create array
184  json_t *json;
185  if (!(json = json_array())) REST_JSON_RETURN_JSON_ERROR(context);
186 
187  // Add services
188  hpd_service_id_t *service;
189  hpd_device_foreach_service(rc, service, device) {
190  if ((rc = rest_json_add_service(json, service, rest, context))) goto error;
191  }
192  if (rc) goto error;
193 
194  // Add to parent
195  if (json_object_set_new(parent, HPD_REST_KEY_SERVICE, json)) {
196  json_decref(json);
198  }
199  return HPD_E_SUCCESS;
200 
201  error:
202  json_decref(json);
203  return rc;
204 }
205 
206 static hpd_error_t rest_json_add_device(json_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
207 {
208  hpd_error_t rc;
209 
210  // Create object
211  json_t *json;
212  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
213 
214  // Add id
215  const char *id;
216  if ((rc = hpd_device_get_id(device, &id))) goto error;
217  if ((rc = rest_json_add(json, HPD_REST_KEY_ID, id, context))) goto error;
218 
219  // Add attributes
220  hpd_pair_t *pair;
221  hpd_device_foreach_attr(rc, pair, device)
222  if ((rc = rest_json_add_attr(json, pair, context))) goto error;
223  if (rc) goto error;
224 
225  // Add services
226  if ((rc = rest_json_add_services(json, device, rest, context))) goto error;
227 
228  // Add to parent
229  if (json_array_append_new(parent, json)) {
230  json_decref(json);
232  }
233 
234  return HPD_E_SUCCESS;
235 
236  error:
237  json_decref(json);
238  return rc;
239 }
240 
241 static hpd_error_t rest_json_add_devices(json_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
242 {
243  hpd_error_t rc;
244 
245  // Create array
246  json_t *json;
247  if (!(json = json_array())) REST_JSON_RETURN_JSON_ERROR(context);
248 
249  // Add devices
250  hpd_device_id_t *device;
251  hpd_adapter_foreach_device(rc, device, adapter) {
252  if ((rc = rest_json_add_device(json, device, rest, context))) goto error;
253  }
254  if (rc) goto error;
255 
256  // Add to parent
257  if (json_object_set_new(parent, HPD_REST_KEY_DEVICE, json)) {
258  json_decref(json);
260  }
261 
262  return HPD_E_SUCCESS;
263 
264  error:
265  json_decref(json);
266  return rc;
267 }
268 
269 static hpd_error_t rest_json_add_adapter(json_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
270 {
271  hpd_error_t rc;
272 
273  // Create object
274  json_t *json;
275  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
276 
277  // Add id
278  const char *id;
279  if ((rc = hpd_adapter_get_id(adapter, &id))) goto error;
280  if ((rc = rest_json_add(json, HPD_REST_KEY_ID, id, context))) goto error;
281 
282  // Add attributes
283  hpd_pair_t *pair;
284  hpd_adapter_foreach_attr(rc, pair, adapter) {
285  if ((rc = rest_json_add_attr(json, pair, context))) goto error;
286  }
287  if (rc) goto error;
288 
289  // Add devices
290  if ((rc = rest_json_add_devices(json, adapter, rest, context))) goto error;
291 
292  // Add to parent
293  if (json_array_append_new(parent, json)) {
294  json_decref(json);
296  }
297 
298  return HPD_E_SUCCESS;
299 
300  error:
301  json_decref(json);
302  return rc;
303 }
304 
306 {
307  hpd_error_t rc;
308 
309  // Create array
310  json_t *json;
311  if (!(json = json_array())) REST_JSON_RETURN_JSON_ERROR(context);
312 
313  // Add adapters
314  hpd_adapter_id_t *adapter;
315  hpd_foreach_adapter(rc, adapter, hpd) {
316  if ((rc = rest_json_add_adapter(json, adapter, rest, context))) goto error;
317  }
318  if (rc) goto error;
319 
320  // Add to parent
321  if (json_object_set_new(parent, HPD_REST_KEY_ADAPTER, json)) {
322  json_decref(json);
324  }
325 
326  return HPD_E_SUCCESS;
327 
328  error:
329  json_decref(json);
330  return rc;
331 }
332 
334 {
335  hpd_error_t rc;
336 
337  // Create object
338  json_t *json;
339  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
340 
341  // Add encoded charset
342 #ifdef CURL_ICONV_CODESET_OF_HOST
343  curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
344  if (curl_ver->features & CURL_VERSION_CONV && curl_ver->iconv_ver_num != 0)
345  if ((rc = rest_json_add(json, HPD_REST_KEY_URL_ENCODED_CHARSET, CURL_ICONV_CODESET_OF_HOST, context))) goto error;
346  else
347  if ((rc = rest_json_add(json, HPD_REST_KEY_URL_ENCODED_CHARSET, HPD_REST_VAL_ASCII, context))) goto error;
348 #else
349  if ((rc = rest_json_add(json, HPD_REST_KEY_URL_ENCODED_CHARSET, HPD_REST_VAL_ASCII, context))) goto error;
350 #endif
351 
352  // Add adapters
353  if ((rc = rest_json_add_adapters(json, hpd, rest, context))) goto error;
354 
355  // Add to parent
356  if (json_object_set_new(parent, HPD_REST_KEY_CONFIGURATION, json)) {
357  json_decref(json);
359  }
360 
361  return HPD_E_SUCCESS;
362 
363  error:
364  json_decref(json);
365  return rc;
366 }
367 
369 {
370  hpd_error_t rc;
371 
372  json_t *json;
373  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
374 
375  if ((rc = rest_json_add_configuration(json, hpd, rest, context))) goto error;
376 
377  if (!((*out) = json_dumps(json, 0))) {
378  json_decref(json);
380  }
381 
382  json_decref(json);
383  return HPD_E_SUCCESS;
384 
385  error:
386  json_decref(json);
387  return rc;
388 }
389 
391 {
392  hpd_error_t rc;
393 
394  json_t *json;
395  if (!(json = json_object())) REST_JSON_RETURN_JSON_ERROR(context);
396 
397  // Add timestamp
398  char timestamp[21];
399  if ((rc = hpd_rest_get_timestamp(context, timestamp))) goto error;
400  if ((rc = rest_json_add(json, HPD_REST_KEY_TIMESTAMP, timestamp, context))) goto error;
401 
402  // Add value
403  if ((rc = rest_json_add(json, HPD_REST_KEY_VALUE, value, context))) goto error;
404 
405  if (!((*out) = json_dumps(json, 0))) {
406  json_decref(json);
408  }
409 
410  json_decref(json);
411  return HPD_E_SUCCESS;
412 
413  error:
414  json_decref(json);
415  return rc;
416 }
417 
418 hpd_error_t hpd_rest_json_parse_value(const char *in, const hpd_module_t *context, char **out)
419 {
420  // Load json
421  json_t *json = NULL;
422  json_error_t *error = NULL;
423  if (!(json = json_loads(in, 0, error))) {
424  HPD_LOG_RETURN(context, HPD_E_ARGUMENT, "Json parsing error: %s", error->text);
425  }
426 
427  // Get value
428  json_t *value;
429  if (!json_is_object(json) || !(value = json_object_get(json, HPD_REST_KEY_VALUE))) {
430  json_decref(json);
431  HPD_LOG_RETURN(context, HPD_E_ARGUMENT, "Json parsing error");
432  }
433 
434  // Allocate a copy
435  (*out) = malloc((json_string_length(value)+1)*sizeof(char));
436  if (!(*out)) {
437  json_decref(json);
438  HPD_LOG_RETURN_E_ALLOC(context);
439  }
440  strcpy((*out), json_string_value(value));
441 
442  json_decref(json);
443  return HPD_E_SUCCESS;
444 }
445 
446 
static const char *const HPD_REST_KEY_CONFIGURATION
Definition: rest_intern.h:49
hpd_error_t hpd_rest_json_get_configuration(hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context, char **out)
Definition: rest_json.c:368
static hpd_error_t rest_json_add_adapter(json_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:269
hpd_error_t hpd_rest_json_get_value(char *value, const hpd_module_t *context, char **out)
Definition: rest_json.c:390
#define hpd_device_foreach_service(RC, SERVICE, DEVICE)
#define HPD_LOG_RETURN(CONTEXT, E, FMT,...)
static const char *const HPD_REST_KEY_VALUE
Definition: rest_intern.h:48
static hpd_error_t rest_json_add_service(json_t *parent, hpd_service_id_t *service, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:117
static const char *const HPD_REST_VAL_ASCII
Definition: rest_intern.h:53
#define hpd_service_foreach_parameter(RC, PARAMETER, SERVICE)
#define REST_JSON_RETURN_JSON_ERROR(CONTEXT)
Definition: rest_json.c:33
data value
Definition: map.c:34
static const char *const HPD_REST_KEY_PARAMETER
Definition: rest_intern.h:43
static hpd_error_t rest_json_add_devices(json_t *parent, hpd_adapter_id_t *adapter, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:241
char * url
free(data.url)
#define hpd_parameter_foreach_attr(RC, PAIR, ID)
const hpd_module_t * context
Definition: rest.c:57
static const char *const HPD_REST_KEY_URL_ENCODED_CHARSET
Definition: rest_intern.h:46
hpd_error_t hpd_rest_get_timestamp(const hpd_module_t *context, char *str)
Definition: rest.c:115
#define hpd_service_foreach_attr(RC, PAIR, ID)
static const char *const HPD_REST_KEY_DEVICE
Definition: rest_intern.h:45
#define hpd_device_foreach_attr(RC, PAIR, ID)
hpd_error_t hpd_adapter_get_id(const hpd_adapter_id_t *aid, const char **id)
[id_t functions]
hpd_error_t hpd_parameter_get_id(const hpd_parameter_id_t *pid, const char **id)
[hpd_service_t functions]
static const char *const HPD_REST_KEY_ID
Definition: rest_intern.h:39
hpd_error_t hpd_device_get_id(const hpd_device_id_t *did, const char **id)
[hpd_adapter_t functions]
#define hpd_adapter_foreach_device(RC, DEVICE, ADAPTER)
data key
#define hpd_service_foreach_action(RC, ACTION, ID)
[hpd_parameter_t functions]
static const char *const HPD_REST_KEY_GET
Definition: rest_intern.h:41
hpd_error_t hpd_service_get_id(const hpd_service_id_t *sid, const char **id)
[hpd_device_t functions]
static hpd_error_t rest_json_add_adapters(json_t *parent, hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:305
static const char *const HPD_REST_KEY_SERVICE
Definition: rest_intern.h:44
enum hpd_error hpd_error_t
Definition: hpd_types.h:167
static hpd_error_t rest_json_add_parameters(json_t *parent, hpd_service_id_t *service, const hpd_module_t *context)
Definition: rest_json.c:90
#define HPD_LOG_RETURN_E_ALLOC(CONTEXT)
static hpd_error_t rest_json_add(json_t *parent, const char *key, const char *val, const hpd_module_t *context)
Definition: rest_json.c:35
static const char *const HPD_REST_KEY_PUT
Definition: rest_intern.h:42
static hpd_error_t rest_json_add_attr(json_t *parent, hpd_pair_t *pair, const hpd_module_t *context)
Definition: rest_json.c:47
static const char *const HPD_REST_VAL_TRUE
Definition: rest_intern.h:52
static hpd_error_t rest_json_add_services(json_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:179
Definition: daemon.h:50
static const char *const HPD_REST_KEY_ADAPTER
Definition: rest_intern.h:47
static hpd_error_t rest_json_add_device(json_t *parent, hpd_device_id_t *device, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:206
static hpd_error_t rest_json_add_configuration(json_t *parent, hpd_t *hpd, hpd_rest_t *rest, const hpd_module_t *context)
Definition: rest_json.c:333
Definition: rest.c:53
static const char *const HPD_REST_KEY_URI
Definition: rest_intern.h:40
hpd_error_t hpd_rest_url_create(hpd_rest_t *rest, hpd_service_id_t *service, char **url)
Definition: rest.c:124
hpd_error_t hpd_action_get_method(const hpd_action_t *action, hpd_method_t *method)
[model foreach loops]
#define json_string_length(JSON)
Definition: hpd_jansson.h:36
#define hpd_foreach_adapter(RC, ADAPTER, HPD)
[Browsing functions]
hpd_error_t hpd_pair_get(const hpd_pair_t *pair, const char **key, const char **value)
Definition: map.c:229
enum hpd_method hpd_method_t
[hpd_log_level_t]
Definition: hpd_types.h:166
hpd_error_t hpd_rest_json_parse_value(const char *in, const hpd_module_t *context, char **out)
Definition: rest_json.c:418
static const char *const HPD_REST_KEY_TIMESTAMP
Definition: rest_intern.h:50
#define hpd_adapter_foreach_attr(RC, PAIR, ID)
static hpd_error_t rest_json_add_parameter(json_t *parent, hpd_parameter_id_t *parameter, const hpd_module_t *context)
Definition: rest_json.c:58