1/* 2 * lws-api-test-lws_struct-sqlite 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 teststruct { 20 lws_dll2_t list; /* not directly serialized */ 21 22 char str1[32]; 23 const char *str2; 24 uint8_t u8; 25 uint16_t u16; 26 uint32_t u32; 27 uint64_t u64; 28 int32_t s32; 29} teststruct_t; 30 31/* 32 * These are the members that we will serialize and deserialize, not every 33 * member in the struct (eg, the dll2 list member) 34 */ 35 36static const lws_struct_map_t lsm_teststruct[] = { 37 LSM_CARRAY (teststruct_t, str1, "str1"), 38 LSM_STRING_PTR (teststruct_t, str2, "str2"), 39 LSM_UNSIGNED (teststruct_t, u8, "u8"), 40 LSM_UNSIGNED (teststruct_t, u16, "u16"), 41 LSM_UNSIGNED (teststruct_t, u32, "u32"), 42 LSM_UNSIGNED (teststruct_t, u64, "u64"), 43 LSM_SIGNED (teststruct_t, s32, "s32"), 44}; 45 46static const lws_struct_map_t lsm_schema_apitest[] = { 47 LSM_SCHEMA_DLL2 (teststruct_t, list, NULL, lsm_teststruct, "apitest") 48}; 49 50static const char *test_string = 51 "No one would have believed in the last years of the nineteenth " 52 "century that this world was being watched keenly and closely by " 53 "intelligences greater than man's and yet as mortal as his own; that as " 54 "men busied themselves about their various concerns they were " 55 "scrutinised and studied, perhaps almost as narrowly as a man with a " 56 "microscope might scrutinise the transient creatures that swarm and " 57 "multiply in a drop of water. With infinite complacency men went to " 58 "and fro over this globe about their little affairs, serene in their " 59 "assurance of their empire over matter. It is possible that the " 60 "infusoria under the microscope do the same. No one gave a thought to " 61 "the older worlds of space as sources of human danger, or thought of " 62 "them only to dismiss the idea of life upon them as impossible or " 63 "improbable. It is curious to recall some of the mental habits of " 64 "those departed days. At most terrestrial men fancied there might be " 65 "other men upon Mars, perhaps inferior to themselves and ready to " 66 "welcome a missionary enterprise. Yet across the gulf of space, minds " 67 "that are to our minds as ours are to those of the beasts that perish, " 68 "intellects vast and cool and unsympathetic, regarded this earth with " 69 "envious eyes, and slowly and surely drew their plans against us. And " 70 "early in the twentieth century came the great disillusionment. "; 71 72int main(int argc, const char **argv) 73{ 74 int e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 75 struct lws_context_creation_info info; 76 struct lws_context *context; 77 struct lwsac *ac = NULL; 78 lws_dll2_owner_t resown; 79 teststruct_t ts, *pts; 80 const char *p; 81 sqlite3 *db; 82 83 if ((p = lws_cmdline_option(argc, argv, "-d"))) 84 logs = atoi(p); 85 86 lws_set_log_level(logs, NULL); 87 lwsl_user("LWS API selftest: lws_struct SQLite\n"); 88 89 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 90#if defined(LWS_WITH_NETWORK) 91 info.port = CONTEXT_PORT_NO_LISTEN; 92#endif 93 context = lws_create_context(&info); 94 if (!context) { 95 lwsl_err("lws init failed\n"); 96 return 1; 97 } 98 99 100 unlink("_lws_apitest.sq3"); 101 102 if (lws_struct_sq3_open(context, "_lws_apitest.sq3", 1, &db)) { 103 lwsl_err("%s: failed to open table\n", __func__); 104 goto bail; 105 } 106 107 /* 1. populate the struct */ 108 109 memset(&ts, 0, sizeof(ts)); 110 111 lws_strncpy(ts.str1, "hello", sizeof(ts.str1)); 112 ts.str2 = test_string; 113 ts.u8 = 1; 114 ts.u16 = 512, 115 ts.u32 = 0x55aa1234; /* 1437209140, */ 116 ts.u64 = 0x34abcdef01ull; 117 ts.s32 = -1; 118 119 /* add our struct to the dll2 owner list */ 120 121 lws_dll2_owner_clear(&resown); 122 lws_dll2_add_head(&ts.list, &resown); 123 124 /* gratuitously create the table */ 125 126 if (lws_struct_sq3_create_table(db, lsm_schema_apitest)) { 127 lwsl_err("%s: Create table failed\n", __func__); 128 e++; 129 goto done; 130 } 131 132 /* serialize the items on the dll2 owner */ 133 134 if (lws_struct_sq3_serialize(db, lsm_schema_apitest, &resown, 0)) { 135 lwsl_err("%s: Serialize failed\n", __func__); 136 e++; 137 goto done; 138 } 139 140 /* resown should be cleared by deserialize, ac is already NULL */ 141 142 lws_dll2_owner_clear(&resown); /* make sure old resown data is gone */ 143 144 if (lws_struct_sq3_deserialize(db, NULL, NULL, lsm_schema_apitest, 145 &resown, &ac, 0, 1)) { 146 lwsl_err("%s: Deserialize failed\n", __func__); 147 e++; 148 goto done; 149 } 150 151 /* we should have 1 entry in resown now (created into the ac) */ 152 153 if (resown.count != 1) { 154 lwsl_err("%s: Expected 1 result got %d\n", __func__, 155 resown.count); 156 e++; 157 goto done; 158 } 159 160 /* 161 * Convert the pointer to the embedded lws_dll2 into a pointer 162 * to the actual struct with the correct type 163 */ 164 165 pts = lws_container_of(lws_dll2_get_head(&resown), 166 teststruct_t, list); 167 168 if (strcmp(pts->str1, "hello") || 169 strcmp(pts->str2, test_string) || 170 pts->u8 != 1 || 171 pts->u16 != 512 || 172 pts->u32 != 0x55aa1234 || 173 pts->u64 != 0x34abcdef01ull || 174 pts->s32 != -1) { 175 lwsl_err("%s: unexpected deser values: %s\n", __func__, pts->str1); 176 lwsl_err("%s: %s\n", __func__, pts->str2); 177 lwsl_err("%s: %u %u %u 0x%llx %d\n", __func__, pts->u8, pts->u16, 178 pts->u32, (unsigned long long)pts->u64, pts->s32); 179 180 e++; 181 goto done; 182 } 183 184done: 185 lwsac_free(&ac); 186 lws_struct_sq3_close(&db); 187 188 189 if (e) 190 goto bail; 191 192 lws_context_destroy(context); 193 194 lwsl_user("Completed: PASS\n"); 195 196 return 0; 197 198bail: 199 lws_context_destroy(context); 200 201 lwsl_user("Completed: FAIL\n"); 202 203 return 1; 204} 205