1/* 2 * lws-api-test-lws_struct-json 3 * 4 * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5 * 6 * This file is made available under the Creative Commons CC0 1.0 7 * Universal Public Domain Dedication. 8 * 9 * lws_struct apis are used to serialize and deserialize your C structs and 10 * linked-lists in a standardized way that's very modest on memory but 11 * convenient and easy to maintain. 12 * 13 * The API test shows how to serialize and deserialize a struct with a linked- 14 * list of child structs in JSON using lws_struct APIs. 15 */ 16 17#include <libwebsockets.h> 18 19typedef struct { 20 lws_dll2_t list; 21 22 struct gpiod_line *line; 23 24 const char *name; 25 const char *wire; 26 27 int chip_idx; 28 int offset; 29 int safe; 30} sai_jig_gpio_t; 31 32typedef struct { 33 lws_dll2_t list; 34 sai_jig_gpio_t *gpio; /* null = wait ms */ 35 const char *gpio_name; 36 int value; 37} sai_jig_seq_item_t; 38 39typedef struct { 40 lws_dll2_t list; 41 lws_dll2_owner_t seq_owner; 42 const char *name; 43} sai_jig_sequence_t; 44 45typedef struct { 46 lws_dll2_t list; 47 lws_dll2_owner_t gpio_owner; 48 lws_dll2_owner_t seq_owner; 49 50 lws_sorted_usec_list_t sul; /* next step in ongoing seq */ 51 sai_jig_seq_item_t *current; /* next seq step */ 52 53 const char *name; 54 55 struct lws *wsi; 56} sai_jig_target_t; 57 58typedef struct { 59 lws_dll2_owner_t target_owner; 60 struct gpiod_chip *chip[16]; 61 struct lwsac *ac_conf; 62 int port; 63 const char *iface; 64 struct lws_context *ctx; 65} sai_jig_t; 66 67/* 68 * We read the JSON config using lws_struct... instrument the related structures 69 */ 70 71static const lws_struct_map_t lsm_sai_jig_gpio[] = { 72 LSM_UNSIGNED (sai_jig_gpio_t, chip_idx, "chip_idx"), 73 LSM_UNSIGNED (sai_jig_gpio_t, offset, "offset"), 74 LSM_UNSIGNED (sai_jig_gpio_t, safe, "safe"), 75 LSM_STRING_PTR (sai_jig_gpio_t, name, "name"), 76 LSM_STRING_PTR (sai_jig_gpio_t, wire, "wire"), 77}; 78 79static const lws_struct_map_t lsm_sai_jig_seq_item[] = { 80 LSM_STRING_PTR (sai_jig_seq_item_t, gpio_name, "gpio_name"), 81 LSM_UNSIGNED (sai_jig_seq_item_t, value, "value"), 82}; 83 84static const lws_struct_map_t lsm_sai_jig_sequence[] = { 85 LSM_STRING_PTR (sai_jig_sequence_t, name, "name"), 86 LSM_LIST (sai_jig_sequence_t, seq_owner, 87 sai_jig_seq_item_t, list, 88 NULL, lsm_sai_jig_seq_item, "seq"), 89}; 90 91static const lws_struct_map_t lsm_sai_jig_target[] = { 92 LSM_STRING_PTR (sai_jig_target_t, name, "name"), 93 LSM_LIST (sai_jig_target_t, gpio_owner, sai_jig_gpio_t, list, 94 NULL, lsm_sai_jig_gpio, "gpios"), 95 LSM_LIST (sai_jig_target_t, seq_owner, sai_jig_sequence_t, list, 96 NULL, lsm_sai_jig_sequence, "sequences"), 97}; 98 99static const lws_struct_map_t lsm_sai_jig[] = { 100 LSM_STRING_PTR (sai_jig_t, iface, "iface"), 101 LSM_UNSIGNED (sai_jig_t, port, "port"), 102 LSM_LIST (sai_jig_t, target_owner, sai_jig_target_t, list, 103 NULL, lsm_sai_jig_target, "targets"), 104}; 105 106static const lws_struct_map_t lsm_jig_schema[] = { 107 LSM_SCHEMA (sai_jig_t, NULL, lsm_sai_jig, "sai-jig"), 108}; 109 110static const char * const jig_conf = 111"{" 112 "\"schema\": \"sai-jig\"," 113 "\"port\": 44000," 114 "\"targets\": [" 115 "{" 116 "\"name\": \"linkit-7697-1\"," 117 "\"gpios\": [" 118 "{" 119 "\"chip_index\": 0," 120 "\"name\": \"nReset\"," 121 "\"offset\": 17," 122 "\"wire\": \"RST\"," 123 "\"safe\": 0" 124 "}, {" 125 "\"name\": \"usr\"," 126 "\"chip_index\": 0," 127 "\"offset\": 22," 128 "\"wire\": \"P6\"," 129 "\"safe\": 0" 130 "}" 131 "], \"sequences\": [" 132 "{" 133 "\"name\": \"reset\"," 134 "\"seq\": [" 135 "{ \"gpio_name\": \"nReset\", \"value\": 0 }," 136 "{ \"gpio_name\": \"usr\", \"value\": 0 }," 137 "{ \"value\": 300 }," 138 "{ \"gpio_name\": \"nReset\", \"value\": 1 }" 139 "]" 140 "}, {" 141 "\"name\": \"flash\"," 142 "\"seq\": [" 143 "{ \"gpio_name\": \"nReset\", \"value\": 0 }," 144 "{ \"gpio_name\": \"usr\", \"value\": 1 }," 145 "{ \"value\": 300 }," 146 "{ \"gpio_name\": \"nReset\", \"value\": 1 }," 147 "{ \"value\": 100 }," 148 "{ \"gpio_name\": \"usr\", \"value\": 0 }" 149 "]" 150 "}" 151 "]" 152 "}" 153 "]" 154"}"; 155 156 157 158extern int test2(void); 159 160/* 161 * in this example, the JSON is for one "builder" object, which may specify 162 * a child list "targets" of zero or more "target" objects. 163 */ 164 165static const char * const json_tests[] = { 166 "{" /* test 1 */ 167 "\"schema\":\"com-warmcat-sai-builder\"," 168 169 "\"hostname\":\"learn\"," 170 "\"nspawn_timeout\":1800," 171 "\"targets\":[" 172 "{" 173 "\"name\":\"target1\"," 174 "\"someflag\":true" 175 "}," 176 "{" 177 "\"name\":\"target2\"," 178 "\"someflag\":false" 179 "}" 180 "]" 181 "}", 182 "{" /* test 2 */ 183 "\"schema\":\"com-warmcat-sai-builder\"," 184 185 "\"hostname\":\"learn\"," 186 "\"targets\":[" 187 "{" 188 "\"name\":\"target1\"" 189 "}," 190 "{" 191 "\"name\":\"target2\"" 192 "}," 193 "{" 194 "\"name\":\"target3\"" 195 "}" 196 "]" 197 "}", "{" /* test 3 */ 198 "\"schema\":\"com-warmcat-sai-builder\"," 199 200 "\"hostname\":\"learn\"," 201 "\"nspawn_timeout\":1800," 202 "\"targets\":[" 203 "{" 204 "\"name\":\"target1\"," 205 "\"unrecognized\":\"xyz\"," 206 "\"child\": {" 207 "\"somename\": \"abc\"," 208 "\"junk\": { \"x\": \"y\" }" 209 "}" 210 "}," 211 "{" 212 "\"name\":\"target2\"" 213 "}" 214 "]" 215 "}", 216 "{" /* test 4 */ 217 "\"schema\":\"com-warmcat-sai-builder\"," 218 219 "\"hostname\":\"learn\"," 220 "\"nspawn_timeout\":1800" 221 "}", 222 "{" /* test 5 */ 223 "\"schema\":\"com-warmcat-sai-builder\"" 224 "}", 225 "{" /* test 6 ... check huge strings into smaller fixed char array */ 226 "\"schema\":\"com-warmcat-sai-builder\"," 227 "\"hostname\":\"" 228 "PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A" 229 "zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/" 230 "CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5" 231 "3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV" 232 "8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1" 233 "NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG" 234 "JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG" 235 "LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW" 236 "v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9" 237 "eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY" 238 "VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/" 239 "uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu" 240 "yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx" 241 "+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"" 242 "}", 243 "{" /* test 7 ... check huge strings into char * */ 244 "\"schema\":\"com-warmcat-sai-builder\"," 245 "\"targets\":[" 246 "{" 247 "\"name\":\"" 248 "PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A" 249 "zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/" 250 "CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5" 251 "3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV" 252 "8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1" 253 "NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG" 254 "JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG" 255 "LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW" 256 "v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9" 257 "eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY" 258 "VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/" 259 "uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu" 260 "yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx" 261 "+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"}]}" 262 "}", 263 "{" /* test 8 the "other" schema */ 264 "\"schema\":\"com-warmcat-sai-other\"," 265 "\"name\":\"somename\"" 266 "}", 267}; 268 269/* 270 * These are the expected outputs for each test, without pretty formatting. 271 * 272 * There are some differences to do with missing elements being rendered with 273 * default values. 274 */ 275 276static const char * const json_expected[] = { 277 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\"," 278 "\"nspawn_timeout\":1800,\"targets\":[{\"name\":\"target1\",\"someflag\":true}," 279 "{\"name\":\"target2\",\"someflag\":false}]}", 280 281 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\"," 282 "\"nspawn_timeout\":0,\"targets\":[{\"name\":\"target1\",\"someflag\":false}," 283 "{\"name\":\"target2\",\"someflag\":false},{\"name\":\"target3\",\"someflag\":false}]}", 284 285 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\"," 286 "\"nspawn_timeout\":1800,\"targets\":[{\"name\":\"target1\",\"someflag\":false," 287 "\"child\":{\"somename\":\"abc\"}},{\"name\":\"target2\",\"someflag\":false}]}", 288 289 "{\"schema\":\"com-warmcat-sai-builder\"," 290 "\"hostname\":\"learn\",\"nspawn_timeout\":1800}", 291 292 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"\"," 293 "\"nspawn_timeout\":0}", 294 295 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":" 296 "\"PYvtan6kqppjnS0KpYTCaiOLsJkc7Xe\"," 297 "\"nspawn_timeout\":0}", 298 299 "{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"\"," 300 "\"nspawn_timeout\":0,\"targets\":[{\"name\":\"PYvtan6kqppjnS0KpYTC" 301 "aiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6Azefz" 302 "oWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9" 303 "D1QKIWqg5RJ/CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6" 304 "bzhA+A/xAsFzSBnb3MHYWzGMprr53FAP1ISo5Ec9i+2ehV40sG6Q470sH3PG" 305 "QZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV8sq3ZgcxKNB7tNfN" 306 "7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1" 307 "NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEh" 308 "dZgxky2+g5hhlSIGJYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/" 309 "RrfOV+oV4R26IDq+KqUiJBENeo8/GXkGLUH/87iPyzXKEMavr6fkrK0vTGto" 310 "8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MWv+B/t1eZZ+1e" 311 "uLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZv" 312 "stK9eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6" 313 "O/grHnvJZm2vBkxuXgsYVkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0Wa" 314 "CqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/uZjjEGGLhJR1jPqA9D1Ej3Ch" 315 "V+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4R" 316 "IWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5v" 317 "METteZlx+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"" 318 ",\"someflag\":false}]}", 319 "{\"schema\":\"com-warmcat-sai-other\",\"name\":\"somename\"}" 320}; 321 322/* 323 * These annotate the members in the struct that will be serialized and 324 * deserialized with type and size information, as well as the name to use 325 * in the serialization format. 326 * 327 * Struct members that aren't annotated like this won't be serialized and 328 * when the struct is created during deserialiation, the will be set to 0 329 * or NULL. 330 */ 331 332/* child object */ 333 334typedef struct sai_child { 335 const char * somename; 336} sai_child_t; 337 338lws_struct_map_t lsm_child[] = { /* describes serializable members */ 339 LSM_STRING_PTR (sai_child_t, somename, "somename"), 340}; 341 342/* target object */ 343 344typedef struct sai_target { 345 struct lws_dll2 target_list; 346 sai_child_t * child; 347 348 const char * name; 349 char someflag; 350} sai_target_t; 351 352static const lws_struct_map_t lsm_target[] = { 353 LSM_STRING_PTR (sai_target_t, name, "name"), 354 LSM_BOOLEAN (sai_target_t, someflag, "someflag"), 355 LSM_CHILD_PTR (sai_target_t, child, sai_child_t, 356 NULL, lsm_child, "child"), 357}; 358 359/* the first kind of struct / schema we can receive */ 360 361/* builder object */ 362 363typedef struct sai_builder { 364 struct lws_dll2_owner targets; 365 366 char hostname[32]; 367 unsigned int nspawn_timeout; 368} sai_builder_t; 369 370static const lws_struct_map_t lsm_builder[] = { 371 LSM_CARRAY (sai_builder_t, hostname, "hostname"), 372 LSM_UNSIGNED (sai_builder_t, nspawn_timeout, "nspawn_timeout"), 373 LSM_LIST (sai_builder_t, targets, 374 sai_target_t, target_list, 375 NULL, lsm_target, "targets"), 376}; 377 378/* 379 * the second kind of struct / schema we can receive 380 */ 381 382typedef struct sai_other { 383 char name[32]; 384} sai_other_t; 385 386static const lws_struct_map_t lsm_other[] = { 387 LSM_CARRAY (sai_other_t, name, "name"), 388}; 389 390/* 391 * meta composed pointers test 392 * 393 * We serialize a struct that consists of members that point to other objects, 394 * we expect this kind of thing 395 * 396 * { 397 * "schema": "meta", 398 * "t": { ... }, 399 * "e": { ...} 400 * } 401 */ 402 403typedef struct meta { 404 sai_target_t *t; 405 sai_builder_t *b; 406} meta_t; 407 408static const lws_struct_map_t lsm_meta[] = { 409 LSM_CHILD_PTR (meta_t, t, sai_target_t, NULL, lsm_target, "t"), 410 LSM_CHILD_PTR (meta_t, b, sai_child_t, NULL, lsm_builder, "e"), 411}; 412 413static const lws_struct_map_t lsm_schema_meta[] = { 414 LSM_SCHEMA (meta_t, NULL, lsm_meta, "meta.schema"), 415}; 416 417/* 418 * Schema table 419 * 420 * Before we can understand the serialization top level format, we must read 421 * the schema, use the table below to create the right toplevel object for the 422 * schema name, and select the correct map tables to interpret the rest of the 423 * serialization. 424 * 425 * In this example there are two completely separate structs / schemas possible 426 * to receive, and we disambiguate and create the correct one using the schema 427 * JSON node. 428 * 429 * Therefore the schema table below is the starting point for the JSON 430 * deserialization. 431 */ 432 433static const lws_struct_map_t lsm_schema_map[] = { 434 LSM_SCHEMA (sai_builder_t, NULL, 435 lsm_builder, "com-warmcat-sai-builder"), 436 LSM_SCHEMA (sai_other_t, NULL, 437 lsm_other, "com-warmcat-sai-other"), 438}; 439 440typedef struct sai_cancel { 441 char task_uuid[65]; 442} sai_cancel_t; 443 444const lws_struct_map_t lsm_task_cancel[] = { 445 LSM_CARRAY (sai_cancel_t, task_uuid, "uuid"), 446}; 447 448static const lws_struct_map_t t2_map[] = { 449 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 450 "com.warmcat.sai.taskinfo"), 451 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 452 "com.warmcat.sai.eventinfo"), 453 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 454 /* shares struct */ "com.warmcat.sai.taskreset"), 455 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 456 /* shares struct */ "com.warmcat.sai.eventreset"), 457 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 458 /* shares struct */ "com.warmcat.sai.eventdelete"), 459 LSM_SCHEMA (sai_cancel_t, NULL, lsm_task_cancel, 460 "com.warmcat.sai.taskcan"), 461}; 462 463static const char *t2 = 464 "{\"schema\":\"com.warmcat.sai.taskcan\"," 465 "\"uuid\": \"071ab46ab4296e5de674c628fec17c55088254679f7714ad991f8c4873dca\"}\x01\x02\xff\xff\xff\xff"; 466 467typedef struct xlws_wifi_creds { 468 lws_dll2_t list; 469 char ssid[33]; 470 char passphrase[64]; 471 int alg; 472 char bssid[6]; 473} xlws_wifi_creds_t; 474 475typedef struct xlws_netdevs { 476 lws_dll2_owner_t owner_creds; 477} xlws_netdevs_t; 478 479static const lws_struct_map_t lsm_wifi_creds[] = { 480 LSM_CARRAY (xlws_wifi_creds_t, ssid, "ssid"), 481 LSM_CARRAY (xlws_wifi_creds_t, passphrase, "passphrase"), 482 LSM_UNSIGNED (xlws_wifi_creds_t, alg, "alg"), 483 LSM_STRING_PTR (xlws_wifi_creds_t, bssid, "bssid"), 484}; 485 486static const lws_struct_map_t lsm_netdev_credentials[] = { 487 LSM_LIST (xlws_netdevs_t, owner_creds, xlws_wifi_creds_t, list, 488 NULL, lsm_wifi_creds, "credentials"), 489}; 490 491static const lws_struct_map_t lsm_netdev_schema[] = { 492 LSM_SCHEMA (xlws_netdevs_t, NULL, lsm_netdev_credentials, 493 "com.warmcat.sai.taskinfo"), 494}; 495 496 497static int 498show_target(struct lws_dll2 *d, void *user) 499{ 500 sai_target_t *t = lws_container_of(d, sai_target_t, target_list); 501 502 lwsl_notice(" target.name '%s' (target %p)\n", t->name, t); 503 504 if (t->child) 505 lwsl_notice(" child %p, target.child.somename '%s'\n", 506 t->child, t->child->somename); 507 508 return 0; 509} 510 511 512int main(int argc, const char **argv) 513{ 514 int n, m, e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 515#if 1 516 lws_struct_serialize_t *ser; 517 uint8_t buf[4096]; 518 size_t written; 519#endif 520 struct lejp_ctx ctx; 521 lws_struct_args_t a; 522 sai_builder_t *b, mb; 523 sai_target_t mt; 524 sai_other_t *o; 525 const char *p; 526 meta_t meta; 527 528 if ((p = lws_cmdline_option(argc, argv, "-d"))) 529 logs = atoi(p); 530 531 lws_set_log_level(logs, NULL); 532 lwsl_user("LWS API selftest: lws_struct JSON\n"); 533 534 for (m = 0; m < (int)LWS_ARRAY_SIZE(json_tests); m++) { 535 536 /* 1. deserialize the canned JSON into structs */ 537 538 lwsl_notice("%s: ++++++++++++++++ test %d\n", __func__, m + 1); 539 540 memset(&a, 0, sizeof(a)); 541 a.map_st[0] = lsm_schema_map; 542 a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_map); 543 a.ac_block_size = 512; 544 545 lws_struct_json_init_parse(&ctx, NULL, &a); 546 n = lejp_parse(&ctx, (uint8_t *)json_tests[m], 547 (int)strlen(json_tests[m])); 548 if (n < 0) { 549 lwsl_err("%s: notification JSON decode failed '%s'\n", 550 __func__, lejp_error_to_string(n)); 551 e++; 552 goto done; 553 } 554 lwsac_info(a.ac); 555 556 if (m + 1 != 8) { 557 b = a.dest; 558 if (!b) { 559 lwsl_err("%s: didn't produce any output\n", __func__); 560 e++; 561 goto done; 562 } 563 564 if (a.top_schema_index) { 565 lwsl_err("%s: wrong top_schema_index\n", __func__); 566 e++; 567 goto done; 568 } 569 570 lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n", 571 b->hostname, b->nspawn_timeout, 572 b->targets.count); 573 574 lws_dll2_foreach_safe(&b->targets, NULL, show_target); 575 } else { 576 o = a.dest; 577 if (!o) { 578 lwsl_err("%s: didn't produce any output\n", __func__); 579 e++; 580 goto done; 581 } 582 583 if (a.top_schema_index != 1) { 584 lwsl_err("%s: wrong top_schema_index\n", __func__); 585 e++; 586 goto done; 587 } 588 589 lwsl_notice("other.name = '%s'\n", o->name); 590 } 591 592 /* 2. serialize the structs into JSON and confirm */ 593 594 lwsl_notice("%s: .... strarting serialization of test %d\n", 595 __func__, m + 1); 596 597 if (m + 1 != 8) { 598 ser = lws_struct_json_serialize_create(lsm_schema_map, 599 LWS_ARRAY_SIZE(lsm_schema_map), 600 0//LSSERJ_FLAG_PRETTY 601 , b); 602 } else { 603 ser = lws_struct_json_serialize_create(&lsm_schema_map[1], 604 1, 605 0//LSSERJ_FLAG_PRETTY 606 , o); 607 } 608 if (!ser) { 609 lwsl_err("%s: unable to init serialization\n", __func__); 610 goto bail; 611 } 612 613 do { 614 n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), 615 &written); 616 switch (n) { 617 case LSJS_RESULT_FINISH: 618 puts((const char *)buf); 619 break; 620 case LSJS_RESULT_CONTINUE: 621 case LSJS_RESULT_ERROR: 622 goto bail; 623 } 624 } while(n == LSJS_RESULT_CONTINUE); 625 626 if (strcmp(json_expected[m], (char *)buf)) { 627 lwsl_err("%s: test %d: expected %s\n", __func__, m + 1, 628 json_expected[m]); 629 e++; 630 goto done; 631 } 632 633 lws_struct_json_serialize_destroy(&ser); 634 635done: 636 lwsac_free(&a.ac); 637 } 638 639 if (e) 640 goto bail; 641 642 /* ad-hoc tests */ 643 644 memset(&meta, 0, sizeof(meta)); 645 memset(&mb, 0, sizeof(mb)); 646 memset(&mt, 0, sizeof(mt)); 647 648 meta.t = &mt; 649 meta.b = &mb; 650 651 meta.t->name = "mytargetname"; 652 lws_strncpy(meta.b->hostname, "myhostname", sizeof(meta.b->hostname)); 653 ser = lws_struct_json_serialize_create(lsm_schema_meta, 1, 0, 654 &meta); 655 if (!ser) { 656 lwsl_err("%s: failed to create json\n", __func__); 657 658 659 } 660 do { 661 n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), &written); 662 switch (n) { 663 case LSJS_RESULT_CONTINUE: 664 case LSJS_RESULT_FINISH: 665 puts((const char *)buf); 666 if (strcmp((const char *)buf, 667 "{\"schema\":\"meta.schema\"," 668 "\"t\":{\"name\":\"mytargetname\"," 669 "\"someflag\":false}," 670 "\"e\":{\"hostname\":\"myhostname\"," 671 "\"nspawn_timeout\":0}}")) { 672 lwsl_err("%s: meta test fail\n", __func__); 673 goto bail; 674 } 675 break; 676 case LSJS_RESULT_ERROR: 677 goto bail; 678 } 679 } while(n == LSJS_RESULT_CONTINUE); 680 681 lws_struct_json_serialize_destroy(&ser); 682 683 lwsl_notice("Test set 2\n"); 684 685 memset(&a, 0, sizeof(a)); 686 a.map_st[0] = t2_map; 687 a.map_entries_st[0] = LWS_ARRAY_SIZE(t2_map); 688 a.ac_block_size = 128; 689 690 lws_struct_json_init_parse(&ctx, NULL, &a); 691 m = lejp_parse(&ctx, (uint8_t *)t2, (int)strlen(t2)); 692 if (m < 0 || !a.dest) { 693 lwsl_notice("%s: notification JSON decode failed '%s'\n", 694 __func__, lejp_error_to_string(m)); 695 goto bail; 696 } 697 698 lwsl_notice("Test set 2: %d: %s\n", m, 699 ((sai_cancel_t *)a.dest)->task_uuid); 700 701 lwsac_free(&a.ac); 702 703 if (test2()) 704 goto bail; 705 706 { 707 lws_struct_serialize_t *js; 708 xlws_wifi_creds_t creds; 709 xlws_netdevs_t netdevs; 710 unsigned char *buf; 711 size_t w; 712 int n; 713 714 memset(&creds, 0, sizeof(creds)); 715 memset(&netdevs, 0, sizeof(netdevs)); 716 717 lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid)); 718 lws_strncpy(creds.passphrase, "yyy", sizeof(creds.passphrase)); 719 lws_dll2_add_tail(&creds.list, &netdevs.owner_creds); 720 721 buf = malloc(2048); /* length should be computed */ 722 723 js = lws_struct_json_serialize_create(lsm_netdev_schema, 724 LWS_ARRAY_SIZE(lsm_netdev_schema), 0, &netdevs); 725 if (!js) 726 goto bail; 727 728 n = (int)lws_struct_json_serialize(js, buf, 2048, &w); 729 lws_struct_json_serialize_destroy(&js); 730 if (n != LSJS_RESULT_FINISH) 731 goto bail; 732 if (strcmp("{\"schema\":\"com.warmcat.sai.taskinfo\",\"credentials\":[{\"ssid\":\"xxx\",\"passphrase\":\"yyy\",\"alg\":0}]}", (const char *)buf)) { 733 puts((const char *)buf); 734 goto bail; 735 } 736 free(buf); 737 } 738 739 { 740 struct x { lws_dll2_t list; const char *sz; }; 741 struct x x1, x2, *xp; 742 lws_dll2_owner_t o; 743 744 lws_dll2_owner_clear(&o); 745 memset(&x1, 0, sizeof(x1)); 746 memset(&x2, 0, sizeof(x2)); 747 748 x1.sz = "nope"; 749 x2.sz = "yes"; 750 751 lws_dll2_add_tail(&x1.list, &o); 752 lws_dll2_add_tail(&x2.list, &o); 753 754 xp = lws_dll2_search_sz_pl(&o, "yes", 3, struct x, list, sz); 755 if (xp != &x2) { 756 lwsl_err("%s: 1 xp %p\n", __func__, xp); 757 goto bail; 758 } 759 xp = lws_dll2_search_sz_pl(&o, "nope", 4, struct x, list, sz); 760 if (xp != &x1) { 761 lwsl_err("%s: 2 xp %p\n", __func__, xp); 762 goto bail; 763 } 764 xp = lws_dll2_search_sz_pl(&o, "wrong", 4, struct x, list, sz); 765 if (xp) { 766 lwsl_err("%s: 3 xp %p\n", __func__, xp); 767 goto bail; 768 } 769 } 770 771 { 772 lws_struct_args_t a; 773 struct lejp_ctx ctx; 774 int m; 775 776 memset(&a, 0, sizeof(a)); 777 a.map_st[0] = lsm_jig_schema; 778 a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_jig_schema); 779 a.ac_block_size = 512; 780 781 lws_struct_json_init_parse(&ctx, NULL, &a); 782 783 m = lejp_parse(&ctx, (uint8_t *)jig_conf, (int)strlen(jig_conf)); 784 785 if (m < 0 || !a.dest) { 786 lwsl_err("%s: line %d: JSON decode failed '%s'\n", 787 __func__, ctx.line, lejp_error_to_string(m)); 788 goto bail; 789 } 790 } 791 792 lwsl_user("Completed: PASS\n"); 793 794 return 0; 795 796bail: 797 798 lwsl_user("Completed: FAIL\n"); 799 800 return 1; 801} 802