trilogy_w_prepared_statements 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +80 -0
  4. data/Rakefile +22 -0
  5. data/ext/trilogy-ruby/cast.c +277 -0
  6. data/ext/trilogy-ruby/cext.c +1048 -0
  7. data/ext/trilogy-ruby/extconf.rb +17 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +281 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +165 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +760 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +44 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +1014 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +216 -0
  17. data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
  18. data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
  19. data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
  20. data/ext/trilogy-ruby/inc/trilogy.h +8 -0
  21. data/ext/trilogy-ruby/src/blocking.c +358 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +236 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +903 -0
  26. data/ext/trilogy-ruby/src/error.c +17 -0
  27. data/ext/trilogy-ruby/src/packet_parser.c +140 -0
  28. data/ext/trilogy-ruby/src/protocol.c +1175 -0
  29. data/ext/trilogy-ruby/src/reader.c +282 -0
  30. data/ext/trilogy-ruby/src/socket.c +623 -0
  31. data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
  32. data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
  33. data/ext/trilogy-ruby/trilogy-ruby.h +37 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +107 -0
@@ -0,0 +1,1175 @@
1
+ #include <openssl/evp.h>
2
+
3
+ #include "trilogy/builder.h"
4
+ #include "trilogy/error.h"
5
+ #include "trilogy/packet_parser.h"
6
+ #include "trilogy/protocol.h"
7
+ #include "trilogy/reader.h"
8
+
9
+ #define TRILOGY_CMD_QUIT 0x01
10
+ #define TRILOGY_CMD_CHANGE_DB 0x02
11
+ #define TRILOGY_CMD_QUERY 0x03
12
+ #define TRILOGY_CMD_PING 0x0e
13
+
14
+ #define TRILOGY_CMD_STMT_PREPARE 0x16
15
+ #define TRILOGY_CMD_STMT_EXECUTE 0x17
16
+ #define TRILOGY_CMD_STMT_SEND_LONG_DATA 0x18
17
+ #define TRILOGY_CMD_STMT_CLOSE 0x19
18
+ #define TRILOGY_CMD_STMT_RESET 0x1a
19
+
20
+ #define SCRAMBLE_LEN 20
21
+
22
+ static size_t min(size_t a, size_t b)
23
+ {
24
+ if (a < b) {
25
+ return a;
26
+ } else {
27
+ return b;
28
+ }
29
+ }
30
+
31
+ #define CHECKED(expr) \
32
+ if ((rc = (expr)) < 0) { \
33
+ goto fail; \
34
+ }
35
+
36
+ int trilogy_parse_ok_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_ok_packet_t *out_packet)
37
+ {
38
+ int rc;
39
+
40
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
41
+
42
+ // skip packet type
43
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
44
+
45
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->affected_rows));
46
+
47
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->last_insert_id));
48
+
49
+ out_packet->status_flags = 0;
50
+ out_packet->warning_count = 0;
51
+ out_packet->txn_status_flags = 0;
52
+ out_packet->session_status = NULL;
53
+ out_packet->session_status_len = 0;
54
+ out_packet->session_state_changes = NULL;
55
+ out_packet->session_state_changes_len = 0;
56
+ out_packet->info = NULL;
57
+ out_packet->info_len = 0;
58
+ out_packet->last_gtid_len = 0;
59
+
60
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
61
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
62
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
63
+ } else if (capabilities & TRILOGY_CAPABILITIES_TRANSACTIONS) {
64
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->txn_status_flags));
65
+ }
66
+
67
+ if (capabilities & TRILOGY_CAPABILITIES_SESSION_TRACK && !trilogy_reader_eof(&reader)) {
68
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_status_len,
69
+ (const void **)&out_packet->session_status));
70
+
71
+ if (out_packet->status_flags & TRILOGY_SERVER_STATUS_SESSION_STATE_CHANGED) {
72
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_state_changes_len,
73
+ (const void **)&out_packet->session_state_changes));
74
+
75
+ TRILOGY_SESSION_TRACK_TYPE_t type = 0;
76
+ const char *state_info = NULL;
77
+ size_t state_info_len = 0;
78
+
79
+ trilogy_reader_t state_reader = TRILOGY_READER((const uint8_t *)out_packet->session_state_changes,
80
+ out_packet->session_state_changes_len);
81
+
82
+ while (!trilogy_reader_eof(&state_reader)) {
83
+ CHECKED(trilogy_reader_get_uint8(&state_reader, (uint8_t *)&type));
84
+ CHECKED(trilogy_reader_get_lenenc_buffer(&state_reader, &state_info_len, (const void **)&state_info));
85
+
86
+ switch (type) {
87
+ case TRILOGY_SESSION_TRACK_GTIDS: {
88
+ trilogy_reader_t gtid_reader = TRILOGY_READER((const uint8_t *)state_info, state_info_len);
89
+ // There's a type with value TRILOGY_SESSION_TRACK_GTIDS tag
90
+ // at the beginning here we can ignore since we already had
91
+ // the type one level higher as well.
92
+ CHECKED(trilogy_reader_get_uint8(&gtid_reader, NULL));
93
+ CHECKED(trilogy_reader_get_lenenc_buffer(&gtid_reader, &out_packet->last_gtid_len,
94
+ (const void **)&out_packet->last_gtid));
95
+ if (out_packet->last_gtid_len > TRILOGY_MAX_LAST_GTID_LEN) {
96
+ return TRILOGY_PROTOCOL_VIOLATION;
97
+ }
98
+ break;
99
+ }
100
+ default:
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ } else {
106
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->info_len, (const void **)&out_packet->info));
107
+ }
108
+
109
+ return trilogy_reader_finish(&reader);
110
+
111
+ fail:
112
+ return rc;
113
+ }
114
+
115
+ int trilogy_parse_eof_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_eof_packet_t *out_packet)
116
+ {
117
+ int rc;
118
+
119
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
120
+
121
+ // skip packet type
122
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
123
+
124
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
125
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
126
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
127
+ } else {
128
+ out_packet->status_flags = 0;
129
+ out_packet->warning_count = 0;
130
+ }
131
+
132
+ return trilogy_reader_finish(&reader);
133
+
134
+ fail:
135
+ return rc;
136
+ }
137
+
138
+ int trilogy_parse_err_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_err_packet_t *out_packet)
139
+ {
140
+ int rc;
141
+
142
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
143
+
144
+ // skip packet type
145
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
146
+
147
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->error_code));
148
+
149
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
150
+ CHECKED(trilogy_reader_get_uint8(&reader, out_packet->sql_state_marker));
151
+ CHECKED(trilogy_reader_copy_buffer(&reader, 5, out_packet->sql_state));
152
+ } else {
153
+ memset(out_packet->sql_state_marker, 0, sizeof out_packet->sql_state_marker);
154
+ memset(out_packet->sql_state, 0, sizeof out_packet->sql_state);
155
+ }
156
+
157
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->error_message_len,
158
+ (const void **)&out_packet->error_message));
159
+
160
+ return trilogy_reader_finish(&reader);
161
+
162
+ fail:
163
+ return rc;
164
+ }
165
+
166
+ int trilogy_parse_auth_switch_request_packet(const uint8_t *buff, size_t len, uint32_t capabilities,
167
+ trilogy_auth_switch_request_packet_t *out_packet)
168
+ {
169
+ int rc;
170
+
171
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
172
+
173
+ // skip packet type
174
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
175
+
176
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
177
+ const char *auth_plugin;
178
+ size_t auth_plugin_len;
179
+
180
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
181
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
182
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
183
+ }
184
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
185
+
186
+ const char *auth_data;
187
+ size_t auth_data_len;
188
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &auth_data_len, (const void **)&auth_data));
189
+ if (auth_data_len > 21) {
190
+ auth_data_len = 21;
191
+ }
192
+ memcpy(out_packet->scramble, auth_data, auth_data_len);
193
+ } else {
194
+ return TRILOGY_PROTOCOL_VIOLATION;
195
+ }
196
+
197
+ return trilogy_reader_finish(&reader);
198
+
199
+ fail:
200
+ return rc;
201
+ }
202
+
203
+ int trilogy_parse_handshake_packet(const uint8_t *buff, size_t len, trilogy_handshake_t *out_packet)
204
+ {
205
+ int rc;
206
+
207
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
208
+
209
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->proto_version));
210
+ if (out_packet->proto_version != 0xa) {
211
+ // incompatible protocol version
212
+ return TRILOGY_PROTOCOL_VIOLATION;
213
+ }
214
+
215
+ const char *server_version;
216
+ size_t server_version_len;
217
+
218
+ CHECKED(trilogy_reader_get_string(&reader, &server_version, &server_version_len));
219
+ server_version_len = min(server_version_len, sizeof(out_packet->server_version) - 1);
220
+ memcpy(out_packet->server_version, server_version, server_version_len);
221
+ out_packet->server_version[server_version_len] = '\0';
222
+
223
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->conn_id));
224
+
225
+ CHECKED(trilogy_reader_copy_buffer(&reader, 8, out_packet->scramble));
226
+
227
+ // this should be a NULL filler
228
+ uint8_t filler = 0;
229
+ CHECKED(trilogy_reader_get_uint8(&reader, &filler));
230
+ if (filler != '\0') {
231
+ // corrupt handshake packet
232
+ return TRILOGY_PROTOCOL_VIOLATION;
233
+ }
234
+
235
+ // lower two bytes of capabilities flags
236
+ uint16_t caps_part = 0;
237
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
238
+ out_packet->capabilities = caps_part;
239
+
240
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41)) {
241
+ // incompatible protocol version
242
+ return TRILOGY_PROTOCOL_VIOLATION;
243
+ }
244
+
245
+ uint8_t server_charset;
246
+ CHECKED(trilogy_reader_get_uint8(&reader, &server_charset));
247
+
248
+ out_packet->server_charset = server_charset;
249
+
250
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->server_status));
251
+
252
+ // upper 16 bits of capabilities flags
253
+
254
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
255
+ out_packet->capabilities |= ((uint32_t)caps_part << 16);
256
+
257
+ uint8_t auth_data_len = 0;
258
+ CHECKED(trilogy_reader_get_uint8(&reader, &auth_data_len));
259
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH)) {
260
+ // this should be a NULL filler
261
+ if (auth_data_len != '\0') {
262
+ // corrupt handshake packet
263
+ return TRILOGY_PROTOCOL_VIOLATION;
264
+ }
265
+ }
266
+
267
+ // This space is reserved. It should be all NULL bytes but some tools or
268
+ // future versions of MySQL-compatible clients may use it. This library
269
+ // opts to skip the validation as some servers don't respect the protocol.
270
+ CHECKED(trilogy_reader_get_buffer(&reader, 10, NULL));
271
+
272
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_SECURE_CONNECTION && auth_data_len > 8) {
273
+ uint8_t remaining_auth_data_len = auth_data_len - 8;
274
+
275
+ // The auth plugins we support all provide exactly 21 bytes of
276
+ // auth_data. Reject any other values for auth_data_len.
277
+ if (SCRAMBLE_LEN + 1 != auth_data_len) {
278
+ return TRILOGY_PROTOCOL_VIOLATION;
279
+ }
280
+
281
+ CHECKED(trilogy_reader_copy_buffer(&reader, remaining_auth_data_len, out_packet->scramble + 8));
282
+ } else {
283
+ // only support 4.1 protocol or newer with secure connection
284
+ return TRILOGY_PROTOCOL_VIOLATION;
285
+ }
286
+
287
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
288
+ const char *auth_plugin;
289
+ size_t auth_plugin_len;
290
+
291
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
292
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
293
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
294
+ }
295
+
296
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
297
+ }
298
+
299
+ return trilogy_reader_finish(&reader);
300
+
301
+ fail:
302
+ return rc;
303
+ }
304
+
305
+ int trilogy_parse_result_packet(const uint8_t *buff, size_t len, trilogy_result_packet_t *out_packet)
306
+ {
307
+ int rc = 0;
308
+
309
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
310
+
311
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->column_count));
312
+
313
+ return trilogy_reader_finish(&reader);
314
+
315
+ fail:
316
+ return rc;
317
+ }
318
+
319
+ int trilogy_parse_row_packet(const uint8_t *buff, size_t len, uint64_t column_count, trilogy_value_t *out_values)
320
+ {
321
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
322
+
323
+ for (uint64_t i = 0; i < column_count; i++) {
324
+ void *data = NULL;
325
+ size_t data_len = 0;
326
+
327
+ int rc = trilogy_reader_get_lenenc_buffer(&reader, &data_len, (const void **)&data);
328
+
329
+ switch (rc) {
330
+ case TRILOGY_OK:
331
+ out_values[i].is_null = false;
332
+ out_values[i].data = data;
333
+ out_values[i].data_len = data_len;
334
+ break;
335
+
336
+ case TRILOGY_NULL_VALUE:
337
+ out_values[i].is_null = true;
338
+ out_values[i].data_len = 0;
339
+ break;
340
+
341
+ default:
342
+ return rc;
343
+ }
344
+ }
345
+
346
+ return trilogy_reader_finish(&reader);
347
+ }
348
+
349
+ int trilogy_parse_column_packet(const uint8_t *buff, size_t len, bool field_list, trilogy_column_packet_t *out_packet)
350
+ {
351
+ int rc;
352
+
353
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
354
+
355
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->catalog_len, (const void **)&out_packet->catalog));
356
+
357
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->schema_len, (const void **)&out_packet->schema));
358
+
359
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->table_len, (const void **)&out_packet->table));
360
+
361
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_table_len,
362
+ (const void **)&out_packet->original_table));
363
+
364
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->name_len, (const void **)&out_packet->name));
365
+
366
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_name_len,
367
+ (const void **)&out_packet->original_name));
368
+
369
+ // skip length of fixed length field until we have something to use it for
370
+ CHECKED(trilogy_reader_get_lenenc(&reader, NULL));
371
+
372
+ uint16_t charset;
373
+ CHECKED(trilogy_reader_get_uint16(&reader, &charset));
374
+
375
+ out_packet->charset = charset;
376
+
377
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->len));
378
+
379
+ uint8_t type;
380
+ CHECKED(trilogy_reader_get_uint8(&reader, &type));
381
+ out_packet->type = type;
382
+
383
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->flags));
384
+
385
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->decimals));
386
+
387
+ // skip NULL filler
388
+ CHECKED(trilogy_reader_get_uint16(&reader, NULL));
389
+
390
+ out_packet->default_value_len = 0;
391
+
392
+ if (field_list) {
393
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->default_value_len,
394
+ (const void **)&out_packet->default_value));
395
+ }
396
+
397
+ return trilogy_reader_finish(&reader);
398
+
399
+ fail:
400
+ return rc;
401
+ }
402
+
403
+ int trilogy_parse_stmt_ok_packet(const uint8_t *buff, size_t len, trilogy_stmt_ok_packet_t *out_packet)
404
+ {
405
+ int rc;
406
+
407
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
408
+
409
+ // skip packet type
410
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
411
+
412
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->id));
413
+
414
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->column_count));
415
+
416
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->parameter_count));
417
+
418
+ uint8_t filler;
419
+
420
+ CHECKED(trilogy_reader_get_uint8(&reader, &filler));
421
+
422
+ if (filler != 0) {
423
+ return TRILOGY_PROTOCOL_VIOLATION;
424
+ }
425
+
426
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
427
+
428
+ return trilogy_reader_finish(&reader);
429
+
430
+ fail:
431
+ return rc;
432
+ }
433
+
434
+ static void trilogy_pack_scramble_native_hash(const char *scramble, const char *password, size_t password_len,
435
+ uint8_t *buffer, unsigned int *buffer_len)
436
+ {
437
+ EVP_MD_CTX *ctx;
438
+ const EVP_MD *alg;
439
+ unsigned int hash_size_tmp1;
440
+ unsigned int hash_size_tmp2;
441
+ unsigned int x;
442
+
443
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
444
+ ctx = EVP_MD_CTX_new();
445
+ #else
446
+ ctx = EVP_MD_CTX_create();
447
+ EVP_MD_CTX_init(ctx);
448
+ #endif
449
+ alg = EVP_sha1();
450
+ hash_size_tmp1 = 0;
451
+ hash_size_tmp2 = 0;
452
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
453
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
454
+
455
+ /* First hash the password. */
456
+ EVP_DigestInit_ex(ctx, alg, NULL);
457
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
458
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
459
+
460
+ /* Second, hash the password hash. */
461
+ EVP_DigestInit_ex(ctx, alg, NULL);
462
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
463
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
464
+
465
+ /* Third, hash the scramble and the double password hash. */
466
+ EVP_DigestInit_ex(ctx, alg, NULL);
467
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
468
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
469
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
470
+
471
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
472
+ EVP_MD_CTX_free(ctx);
473
+ #else
474
+ EVP_MD_CTX_destroy(ctx);
475
+ #endif
476
+
477
+ /* Fourth, xor the last hash against the first password hash. */
478
+ for (x = 0; x < *buffer_len; x++) {
479
+ buffer[x] = buffer[x] ^ hash_tmp1[x];
480
+ }
481
+ }
482
+
483
+ static void trilogy_pack_scramble_sha2_hash(const char *scramble, const char *password, size_t password_len,
484
+ uint8_t *buffer, unsigned int *buffer_len)
485
+ {
486
+ EVP_MD_CTX *ctx;
487
+ const EVP_MD *alg;
488
+ unsigned int hash_size_tmp1;
489
+ unsigned int hash_size_tmp2;
490
+ unsigned int x;
491
+
492
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
493
+ ctx = EVP_MD_CTX_new();
494
+ #else
495
+ ctx = EVP_MD_CTX_create();
496
+ EVP_MD_CTX_init(ctx);
497
+ #endif
498
+ alg = EVP_sha256();
499
+ hash_size_tmp1 = 0;
500
+ hash_size_tmp2 = 0;
501
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
502
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
503
+
504
+ /* First hash the password. */
505
+ EVP_DigestInit_ex(ctx, alg, NULL);
506
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
507
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
508
+
509
+ /* Second, hash the password hash. */
510
+ EVP_DigestInit_ex(ctx, alg, NULL);
511
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
512
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
513
+
514
+ /* Third, hash the scramble and the double password hash. */
515
+ EVP_DigestInit_ex(ctx, alg, NULL);
516
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
517
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
518
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
519
+
520
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
521
+ EVP_MD_CTX_free(ctx);
522
+ #else
523
+ EVP_MD_CTX_destroy(ctx);
524
+ #endif
525
+
526
+ /* Fourth, xor the first and last hash. */
527
+ for (x = 0; x < *buffer_len; x++) {
528
+ buffer[x] = hash_tmp1[x] ^ buffer[x];
529
+ }
530
+ }
531
+
532
+ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
533
+ const char *database, const char *auth_plugin, const char *scramble,
534
+ TRILOGY_CAPABILITIES_t flags)
535
+ {
536
+ int rc = TRILOGY_OK;
537
+
538
+ const char *default_auth_plugin = "mysql_native_password";
539
+
540
+ uint32_t capabilities = flags;
541
+ // Add the default set of capabilities for this client
542
+ capabilities |= TRILOGY_CAPABILITIES_CLIENT;
543
+
544
+ uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
545
+
546
+ uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
547
+
548
+ unsigned int auth_response_len = 0;
549
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
550
+
551
+ if (database) {
552
+ capabilities |= TRILOGY_CAPABILITIES_CONNECT_WITH_DB;
553
+ }
554
+
555
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
556
+
557
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
558
+
559
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
560
+
561
+ static const char zeroes[23] = {0};
562
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
563
+
564
+ if (user) {
565
+ CHECKED(trilogy_builder_write_string(builder, user));
566
+ } else {
567
+ CHECKED(trilogy_builder_write_string(builder, "root"));
568
+ }
569
+
570
+ if (pass_len > 0) {
571
+ // Fallback to te default unless we have SHA2 requested
572
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
573
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
574
+ } else {
575
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
576
+ auth_plugin = default_auth_plugin;
577
+ }
578
+ }
579
+
580
+ // auth data len
581
+ CHECKED(trilogy_builder_write_uint8(builder, (uint8_t)auth_response_len));
582
+
583
+ if (auth_response_len > 0) {
584
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
585
+ }
586
+
587
+ if (database) {
588
+ CHECKED(trilogy_builder_write_string(builder, database));
589
+ }
590
+
591
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
592
+ CHECKED(trilogy_builder_write_string(builder, auth_plugin));
593
+ }
594
+
595
+ trilogy_builder_finalize(builder);
596
+
597
+ return TRILOGY_OK;
598
+
599
+ fail:
600
+ return rc;
601
+ }
602
+
603
+ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const char *pass, size_t pass_len,
604
+ const char *auth_plugin, const char *scramble)
605
+ {
606
+ int rc = TRILOGY_OK;
607
+ unsigned int auth_response_len = 0;
608
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
609
+
610
+ if (pass_len > 0) {
611
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
612
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
613
+ } else {
614
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
615
+ }
616
+ }
617
+
618
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
619
+ trilogy_builder_finalize(builder);
620
+
621
+ return TRILOGY_OK;
622
+ fail:
623
+ return rc;
624
+ }
625
+
626
+ int trilogy_build_ping_packet(trilogy_builder_t *builder)
627
+ {
628
+ int rc = TRILOGY_OK;
629
+
630
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_PING));
631
+
632
+ trilogy_builder_finalize(builder);
633
+
634
+ return TRILOGY_OK;
635
+
636
+ fail:
637
+ return rc;
638
+ }
639
+
640
+ int trilogy_build_query_packet(trilogy_builder_t *builder, const char *sql, size_t sql_len)
641
+ {
642
+ int rc = TRILOGY_OK;
643
+
644
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUERY));
645
+
646
+ CHECKED(trilogy_builder_write_buffer(builder, sql, sql_len));
647
+
648
+ trilogy_builder_finalize(builder);
649
+
650
+ return TRILOGY_OK;
651
+
652
+ fail:
653
+ return rc;
654
+ }
655
+
656
+ int trilogy_build_change_db_packet(trilogy_builder_t *builder, const char *name, size_t name_len)
657
+ {
658
+ int rc = TRILOGY_OK;
659
+
660
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_CHANGE_DB));
661
+
662
+ CHECKED(trilogy_builder_write_buffer(builder, name, name_len));
663
+
664
+ trilogy_builder_finalize(builder);
665
+
666
+ return TRILOGY_OK;
667
+
668
+ fail:
669
+ return rc;
670
+ }
671
+
672
+ int trilogy_build_quit_packet(trilogy_builder_t *builder)
673
+ {
674
+ int rc = TRILOGY_OK;
675
+
676
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUIT));
677
+
678
+ trilogy_builder_finalize(builder);
679
+
680
+ return TRILOGY_OK;
681
+
682
+ fail:
683
+ return rc;
684
+ }
685
+
686
+ int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags)
687
+ {
688
+ static const char zeroes[23] = {0};
689
+
690
+ const uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
691
+ const uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
692
+ const uint32_t capabilities = flags | TRILOGY_CAPABILITIES_CLIENT | TRILOGY_CAPABILITIES_SSL;
693
+
694
+ int rc = TRILOGY_OK;
695
+
696
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
697
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
698
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
699
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
700
+ trilogy_builder_finalize(builder);
701
+
702
+ return TRILOGY_OK;
703
+
704
+ fail:
705
+ return rc;
706
+ }
707
+
708
+ int trilogy_build_stmt_prepare_packet(trilogy_builder_t *builder, const char *sql, size_t sql_len)
709
+ {
710
+ int rc = TRILOGY_OK;
711
+
712
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_PREPARE));
713
+
714
+ CHECKED(trilogy_builder_write_buffer(builder, sql, sql_len));
715
+
716
+ trilogy_builder_finalize(builder);
717
+
718
+ return TRILOGY_OK;
719
+
720
+ fail:
721
+ return rc;
722
+ }
723
+
724
+ int trilogy_build_stmt_execute_packet(trilogy_builder_t *builder, uint32_t stmt_id, uint8_t flags,
725
+ trilogy_binary_value_t *binds, uint16_t num_binds)
726
+ {
727
+ int rc = TRILOGY_OK;
728
+
729
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_EXECUTE));
730
+
731
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
732
+
733
+ CHECKED(trilogy_builder_write_uint8(builder, flags));
734
+
735
+ // apparently, iteration-count is always 1
736
+ CHECKED(trilogy_builder_write_uint32(builder, 1));
737
+
738
+ int i;
739
+
740
+ if (num_binds > 0) {
741
+ if (binds == NULL) {
742
+ return TRILOGY_PROTOCOL_VIOLATION;
743
+ }
744
+
745
+ uint8_t current_bits = 0;
746
+
747
+ for (i = 0; i < num_binds; i++) {
748
+ if (binds[i].is_null) {
749
+ current_bits |= 1 << (i % 8);
750
+ }
751
+
752
+ // If we hit a byte boundary, write the bits we have so far and continue
753
+ if ((i % 8) == 7) {
754
+ CHECKED(trilogy_builder_write_uint8(builder, current_bits))
755
+
756
+ current_bits = 0;
757
+ }
758
+ }
759
+
760
+ // If there would have been any remainder bits, finally write those as well
761
+ if (num_binds % 8) {
762
+ CHECKED(trilogy_builder_write_uint8(builder, current_bits))
763
+ }
764
+
765
+ // new params bound flag
766
+ CHECKED(trilogy_builder_write_uint8(builder, 0x1));
767
+
768
+ for (i = 0; i < num_binds; i++) {
769
+ CHECKED(trilogy_builder_write_uint8(builder, binds[i].type));
770
+
771
+ if (binds[i].is_unsigned) {
772
+ CHECKED(trilogy_builder_write_uint8(builder, 0x80));
773
+ } else {
774
+ CHECKED(trilogy_builder_write_uint8(builder, 0x00));
775
+ }
776
+ }
777
+
778
+ for (i = 0; i < num_binds; i++) {
779
+ trilogy_binary_value_t val = binds[i];
780
+
781
+ switch (val.type) {
782
+ case TRILOGY_TYPE_TINY:
783
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.uint8));
784
+
785
+ break;
786
+ case TRILOGY_TYPE_SHORT:
787
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.uint16));
788
+
789
+ break;
790
+ case TRILOGY_TYPE_INT24:
791
+ case TRILOGY_TYPE_LONG:
792
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.uint32));
793
+
794
+ break;
795
+ case TRILOGY_TYPE_LONGLONG:
796
+ CHECKED(trilogy_builder_write_uint64(builder, val.as.uint64));
797
+
798
+ break;
799
+ case TRILOGY_TYPE_FLOAT:
800
+ CHECKED(trilogy_builder_write_float(builder, val.as.flt));
801
+
802
+ break;
803
+ case TRILOGY_TYPE_DOUBLE:
804
+ CHECKED(trilogy_builder_write_double(builder, val.as.dbl));
805
+
806
+ break;
807
+ case TRILOGY_TYPE_YEAR:
808
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.year));
809
+
810
+ break;
811
+ case TRILOGY_TYPE_TIME: {
812
+ uint8_t field_len = 0;
813
+
814
+ if (val.as.time.micro_seconds) {
815
+ field_len = 12;
816
+ } else if (val.as.time.hour || val.as.time.minute || val.as.time.second) {
817
+ field_len = 8;
818
+ } else {
819
+ field_len = 0;
820
+ }
821
+
822
+ CHECKED(trilogy_builder_write_uint8(builder, field_len));
823
+
824
+ if (field_len > 0) {
825
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.is_negative));
826
+
827
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.time.days));
828
+
829
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.hour));
830
+
831
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.minute));
832
+
833
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.second));
834
+
835
+ if (field_len > 8) {
836
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.time.micro_seconds));
837
+ }
838
+ }
839
+
840
+ break;
841
+ }
842
+ case TRILOGY_TYPE_DATE:
843
+ case TRILOGY_TYPE_DATETIME:
844
+ case TRILOGY_TYPE_TIMESTAMP: {
845
+ uint8_t field_len = 0;
846
+
847
+ if (val.as.date.datetime.micro_seconds) {
848
+ field_len = 11;
849
+ } else if (val.as.date.datetime.hour || val.as.date.datetime.minute || val.as.date.datetime.second) {
850
+ field_len = 7;
851
+ } else if (val.as.date.year || val.as.date.month || val.as.date.day) {
852
+ field_len = 4;
853
+ } else {
854
+ field_len = 0;
855
+ }
856
+
857
+ CHECKED(trilogy_builder_write_uint8(builder, field_len));
858
+
859
+ if (field_len > 0) {
860
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.date.year));
861
+
862
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.month));
863
+
864
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.day));
865
+
866
+ if (field_len > 4) {
867
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.hour));
868
+
869
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.minute));
870
+
871
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.second));
872
+
873
+ if (field_len > 7) {
874
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.date.datetime.micro_seconds));
875
+ }
876
+ }
877
+ }
878
+
879
+ break;
880
+ }
881
+ case TRILOGY_TYPE_DECIMAL:
882
+ case TRILOGY_TYPE_VARCHAR:
883
+ case TRILOGY_TYPE_BIT:
884
+ case TRILOGY_TYPE_NEWDECIMAL:
885
+ case TRILOGY_TYPE_ENUM:
886
+ case TRILOGY_TYPE_SET:
887
+ case TRILOGY_TYPE_TINY_BLOB:
888
+ case TRILOGY_TYPE_BLOB:
889
+ case TRILOGY_TYPE_MEDIUM_BLOB:
890
+ case TRILOGY_TYPE_LONG_BLOB:
891
+ case TRILOGY_TYPE_VAR_STRING:
892
+ case TRILOGY_TYPE_STRING:
893
+ case TRILOGY_TYPE_GEOMETRY:
894
+ CHECKED(trilogy_builder_write_lenenc_buffer(builder, val.as.str.data, val.as.str.len));
895
+
896
+ break;
897
+ case TRILOGY_TYPE_NULL:
898
+ // already handled by the null bitmap
899
+ break;
900
+ default:
901
+ return TRILOGY_UNKNOWN_TYPE;
902
+ }
903
+ }
904
+ }
905
+
906
+ trilogy_builder_finalize(builder);
907
+
908
+ return TRILOGY_OK;
909
+
910
+ fail:
911
+ return rc;
912
+ }
913
+
914
+ int trilogy_build_stmt_bind_data_packet(trilogy_builder_t *builder, uint32_t stmt_id, uint16_t param_id, uint8_t *data,
915
+ size_t data_len)
916
+ {
917
+ int rc = TRILOGY_OK;
918
+
919
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_SEND_LONG_DATA));
920
+
921
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
922
+
923
+ CHECKED(trilogy_builder_write_uint16(builder, param_id));
924
+
925
+ CHECKED(trilogy_builder_write_buffer(builder, data, data_len));
926
+
927
+ trilogy_builder_finalize(builder);
928
+
929
+ return TRILOGY_OK;
930
+
931
+ fail:
932
+ return rc;
933
+ }
934
+
935
+ int trilogy_build_stmt_reset_packet(trilogy_builder_t *builder, uint32_t stmt_id)
936
+ {
937
+ int rc = TRILOGY_OK;
938
+
939
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_RESET));
940
+
941
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
942
+
943
+ trilogy_builder_finalize(builder);
944
+
945
+ return TRILOGY_OK;
946
+
947
+ fail:
948
+ return rc;
949
+ }
950
+
951
+ int trilogy_build_stmt_close_packet(trilogy_builder_t *builder, uint32_t stmt_id)
952
+ {
953
+ int rc = TRILOGY_OK;
954
+
955
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_CLOSE));
956
+
957
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
958
+
959
+ trilogy_builder_finalize(builder);
960
+
961
+ return TRILOGY_OK;
962
+
963
+ fail:
964
+ return rc;
965
+ }
966
+
967
+ static inline int is_null(uint8_t *null_bitmap, uint64_t bitmap_len, uint64_t column_offset, bool *col_is_null)
968
+ {
969
+ if (column_offset > (bitmap_len * 8) - 1) {
970
+ return TRILOGY_PROTOCOL_VIOLATION;
971
+ }
972
+
973
+ column_offset += 2;
974
+
975
+ uint64_t byte_offset = column_offset / 8;
976
+
977
+ // for the binary protocol result row packet, we need to offset the bit check
978
+ // by 2
979
+ *col_is_null = (null_bitmap[byte_offset] & (1 << (column_offset % 8))) != 0;
980
+
981
+ return TRILOGY_OK;
982
+ }
983
+
984
+ int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_column_packet_t *columns,
985
+ uint64_t column_count, trilogy_binary_value_t *out_values)
986
+ {
987
+ int rc;
988
+
989
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
990
+
991
+ // skip packet header
992
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
993
+
994
+ uint8_t *null_bitmap = NULL;
995
+ uint64_t bitmap_len = (column_count + 7 + 2) / 8;
996
+
997
+ CHECKED(trilogy_reader_get_buffer(&reader, bitmap_len, (const void **)&null_bitmap));
998
+
999
+ for (uint64_t i = 0; i < column_count; i++) {
1000
+ CHECKED(is_null(null_bitmap, bitmap_len, i, &out_values[i].is_null));
1001
+ if (out_values[i].is_null) {
1002
+ out_values[i].type = TRILOGY_TYPE_NULL;
1003
+ } else {
1004
+ out_values[i].is_null = false;
1005
+
1006
+ out_values[i].type = columns[i].type;
1007
+
1008
+ if (columns[i].flags & TRILOGY_COLUMN_FLAG_UNSIGNED) {
1009
+ out_values[i].is_unsigned = true;
1010
+ }
1011
+
1012
+ switch (columns[i].type) {
1013
+ case TRILOGY_TYPE_STRING:
1014
+ case TRILOGY_TYPE_VARCHAR:
1015
+ case TRILOGY_TYPE_VAR_STRING:
1016
+ case TRILOGY_TYPE_ENUM:
1017
+ case TRILOGY_TYPE_SET:
1018
+ case TRILOGY_TYPE_LONG_BLOB:
1019
+ case TRILOGY_TYPE_MEDIUM_BLOB:
1020
+ case TRILOGY_TYPE_BLOB:
1021
+ case TRILOGY_TYPE_TINY_BLOB:
1022
+ case TRILOGY_TYPE_GEOMETRY:
1023
+ case TRILOGY_TYPE_BIT:
1024
+ case TRILOGY_TYPE_DECIMAL:
1025
+ case TRILOGY_TYPE_NEWDECIMAL:
1026
+ case TRILOGY_TYPE_JSON:
1027
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_values[i].as.str.len,
1028
+ (const void **)&out_values[i].as.str.data));
1029
+
1030
+ break;
1031
+ case TRILOGY_TYPE_LONGLONG:
1032
+ CHECKED(trilogy_reader_get_uint64(&reader, &out_values[i].as.uint64));
1033
+
1034
+ break;
1035
+ case TRILOGY_TYPE_DOUBLE:
1036
+ CHECKED(trilogy_reader_get_double(&reader, &out_values[i].as.dbl));
1037
+
1038
+ break;
1039
+ case TRILOGY_TYPE_LONG:
1040
+ case TRILOGY_TYPE_INT24:
1041
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.uint32));
1042
+
1043
+ break;
1044
+ case TRILOGY_TYPE_FLOAT:
1045
+ CHECKED(trilogy_reader_get_float(&reader, &out_values[i].as.flt));
1046
+
1047
+ break;
1048
+ case TRILOGY_TYPE_SHORT:
1049
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.uint16));
1050
+
1051
+ break;
1052
+ case TRILOGY_TYPE_YEAR:
1053
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.year));
1054
+
1055
+ break;
1056
+ case TRILOGY_TYPE_TINY:
1057
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.uint8));
1058
+
1059
+ break;
1060
+ case TRILOGY_TYPE_DATE:
1061
+ case TRILOGY_TYPE_DATETIME:
1062
+ case TRILOGY_TYPE_TIMESTAMP: {
1063
+ uint8_t time_len;
1064
+
1065
+ CHECKED(trilogy_reader_get_uint8(&reader, &time_len));
1066
+
1067
+ out_values[i].as.date.year = 0;
1068
+ out_values[i].as.date.month = 0;
1069
+ out_values[i].as.date.day = 0;
1070
+ out_values[i].as.date.datetime.hour = 0;
1071
+ out_values[i].as.date.datetime.minute = 0;
1072
+ out_values[i].as.date.datetime.second = 0;
1073
+ out_values[i].as.date.datetime.micro_seconds = 0;
1074
+
1075
+ switch (time_len) {
1076
+ case 0:
1077
+ break;
1078
+ case 4:
1079
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1080
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1081
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1082
+
1083
+ break;
1084
+ case 7:
1085
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1086
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1087
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1088
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.hour));
1089
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.minute));
1090
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.second));
1091
+
1092
+ break;
1093
+ case 11:
1094
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1095
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1096
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1097
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.hour));
1098
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.minute));
1099
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.second));
1100
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.date.datetime.micro_seconds));
1101
+
1102
+ break;
1103
+ default:
1104
+ return TRILOGY_PROTOCOL_VIOLATION;
1105
+ }
1106
+
1107
+ break;
1108
+ }
1109
+ case TRILOGY_TYPE_TIME: {
1110
+ uint8_t time_len;
1111
+
1112
+ CHECKED(trilogy_reader_get_uint8(&reader, &time_len));
1113
+
1114
+ out_values[i].as.time.is_negative = false;
1115
+ out_values[i].as.time.days = 0;
1116
+ out_values[i].as.time.hour = 0;
1117
+ out_values[i].as.time.minute = 0;
1118
+ out_values[i].as.time.second = 0;
1119
+ out_values[i].as.time.micro_seconds = 0;
1120
+
1121
+ switch (time_len) {
1122
+ case 0:
1123
+ break;
1124
+ case 8: {
1125
+ uint8_t is_negative;
1126
+
1127
+ CHECKED(trilogy_reader_get_uint8(&reader, &is_negative));
1128
+
1129
+ out_values[i].as.time.is_negative = is_negative == 1;
1130
+
1131
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.days));
1132
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.hour));
1133
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.minute));
1134
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.second));
1135
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.micro_seconds));
1136
+
1137
+ break;
1138
+ }
1139
+ case 12: {
1140
+ uint8_t is_negative;
1141
+
1142
+ CHECKED(trilogy_reader_get_uint8(&reader, &is_negative));
1143
+
1144
+ out_values[i].as.time.is_negative = is_negative == 1;
1145
+
1146
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.days));
1147
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.hour));
1148
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.minute));
1149
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.second));
1150
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.micro_seconds));
1151
+
1152
+ break;
1153
+ }
1154
+ default:
1155
+ return TRILOGY_PROTOCOL_VIOLATION;
1156
+ }
1157
+
1158
+ break;
1159
+ }
1160
+ case TRILOGY_TYPE_NULL:
1161
+ default:
1162
+ // we cover TRILOGY_TYPE_NULL here because we should never hit this case
1163
+ // explicitly as it should be covered in the null bitmap
1164
+ return TRILOGY_UNKNOWN_TYPE;
1165
+ }
1166
+ }
1167
+ }
1168
+
1169
+ return trilogy_reader_finish(&reader);
1170
+
1171
+ fail:
1172
+ return rc;
1173
+ }
1174
+
1175
+ #undef CHECKED